From c01d9b053852b12e7d3ced66367babb4d499b14b Mon Sep 17 00:00:00 2001
From: vincentlu <t1341870251@gmail.com>
Date: 星期四, 26 二月 2026 11:44:15 +0800
Subject: [PATCH] #

---
 zy-acs-flow/src/page/guarantee/CronField.jsx                     |  150 ++++++++++
 zy-acs-flow/src/page/userLogin/UserLoginList.jsx                 |    2 
 zy-acs-flow/src/page/action/ActionList.jsx                       |    2 
 zy-acs-flow/src/page/loc/LocList.jsx                             |    2 
 zy-acs-flow/src/page/guarantee/GuaranteeList.jsx                 |   59 +++-
 zy-acs-flow/src/page/jam/JamList.jsx                             |    2 
 zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx             |    2 
 zy-acs-flow/src/page/agvSts/AgvStsList.jsx                       |    2 
 zy-acs-flow/src/page/code/CodeList.jsx                           |    2 
 zy-acs-flow/src/page/config/ConfigList.jsx                       |    2 
 zy-acs-flow/src/page/actionSts/ActionStsList.jsx                 |    2 
 zy-acs-flow/src/page/role/RoleList.jsx                           |    4 
 zy-acs-flow/src/page/busSts/BusStsList.jsx                       |    2 
 zy-acs-flow/src/page/guarantee/ScopeField.jsx                    |   70 +++++
 zy-acs-flow/src/page/user/UserList.jsx                           |    2 
 zy-acs-flow/src/page/locSts/LocStsList.jsx                       |    2 
 zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx     |    2 
 zy-acs-flow/src/page/travel/TravelList.jsx                       |    2 
 zy-acs-flow/src/page/bus/BusList.jsx                             |    2 
 zy-acs-flow/src/page/guarantee/cronUtils.js                      |  168 ++++++++++++
 zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx                 |   70 ++--
 zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx                |   18 +
 zy-acs-flow/src/i18n/zh.js                                       |   40 ++
 zy-acs-flow/src/page/codeGap/CodeGapList.jsx                     |    2 
 zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx                 |    2 
 zy-acs-flow/src/page/tenant/TenantList.jsx                       |    2 
 zy-acs-flow/src/i18n/en.js                                       |   40 ++
 zy-acs-flow/src/page/funcSta/FuncStaList.jsx                     |    2 
 zy-acs-flow/src/page/zone/ZoneList.jsx                           |    2 
 zy-acs-flow/src/page/lane/LaneList.jsx                           |    2 
 zy-acs-flow/src/page/task/TaskList.jsx                           |    2 
 zy-acs-flow/src/page/guarantee/guaranteeConstants.js             |   63 ++++
 zy-acs-flow/src/page/staType/StaTypeList.jsx                     |    2 
 zy-acs-flow/src/page/segment/SegmentList.jsx                     |    2 
 zy-acs-flow/src/page/staReserve/StaReserveList.jsx               |    2 
 zy-acs-flow/src/page/actionType/ActionTypeList.jsx               |    2 
 zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx |    2 
 zy-acs-flow/src/page/agv/AgvList.jsx                             |    2 
 zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx               |   67 ++--
 zy-acs-flow/src/page/sta/StaList.jsx                             |    2 
 zy-acs-flow/src/page/staSts/StaStsList.jsx                       |    2 
 zy-acs-flow/src/page/agvModel/AgvModelList.jsx                   |    2 
 zy-acs-flow/src/page/route/RouteList.jsx                         |    2 
 zy-acs-flow/src/page/host/HostList.jsx                           |    2 
 zy-acs-flow/src/page/locType/LocTypeList.jsx                     |    2 
 zy-acs-flow/src/page/mission/MissionResend.jsx                   |    4 
 zy-acs-flow/src/page/mission/MissionShow.jsx                     |    2 
 zy-acs-flow/src/page/area/AreaList.jsx                           |    2 
 zy-acs-flow/src/page/taskType/TaskTypeList.jsx                   |    2 
 zy-acs-flow/src/page/taskSts/TaskStsList.jsx                     |    2 
 50 files changed, 698 insertions(+), 131 deletions(-)

diff --git a/zy-acs-flow/src/i18n/en.js b/zy-acs-flow/src/i18n/en.js
index 2fd3b41..ed46a89 100644
--- a/zy-acs-flow/src/i18n/en.js
+++ b/zy-acs-flow/src/i18n/en.js
@@ -708,6 +708,46 @@
                 },
             },
         },
+        guarantee: {
+            scope: {
+                helper: 'Select the scope for this plan; defaults to global coverage',
+                global: 'Global',
+                model: 'By model',
+                area: 'By area',
+                biz: 'By business type',
+                agv: 'Specific vehicles',
+                globalHelper: 'Applies to all vehicles',
+                globalTip: 'Select a scope type to limit the plan',
+            },
+            schedule: {
+                label: 'Capacity window',
+                type: 'Frequency',
+                daily: 'Daily',
+                weekly: 'Weekly',
+                monthly: 'Monthly',
+                time: 'Execution time',
+                weeklyLabel: 'Weekdays',
+                monthlyLabel: 'Days of month',
+                monthHelper: 'Select at least one day',
+                monthDay: 'Day %{day}',
+                preview: 'Cron expression',
+                descriptionPrefix: 'Runs as %{desc}',
+                description: {
+                    daily: 'every day at %{time}',
+                    weekly: 'every week on %{days} at %{time}',
+                    monthly: 'every month on %{days} at %{time}',
+                },
+            },
+            week: {
+                mon: 'Mon',
+                tue: 'Tue',
+                wed: 'Wed',
+                thu: 'Thu',
+                fri: 'Fri',
+                sat: 'Sat',
+                sun: 'Sun',
+            },
+        },
         sta: {
             depthHint: 'Set depth to 0 to keep the default value.',
             enums: {
diff --git a/zy-acs-flow/src/i18n/zh.js b/zy-acs-flow/src/i18n/zh.js
index c0d2ad1..3f31d4a 100644
--- a/zy-acs-flow/src/i18n/zh.js
+++ b/zy-acs-flow/src/i18n/zh.js
@@ -708,6 +708,46 @@
                 },
             },
         },
+        guarantee: {
+            scope: {
+                helper: '閫夋嫨浣滅敤鑼冨洿锛岄粯璁や负鍏ㄥ眬鐢熸晥',
+                global: '鍏ㄥ眬',
+                model: '鎸夎溅鍨�',
+                area: '鎸夊尯鍩�',
+                biz: '鎸変笟鍔$被鍨�',
+                agv: '鎸囧畾杞﹁締',
+                globalHelper: '鍏ㄥ眬閫傜敤',
+                globalTip: '濡傞渶闄愬畾锛岃鍏堥�夋嫨浣滅敤鑼冨洿',
+            },
+            schedule: {
+                label: '淇濋殰鏃堕棿閰嶇疆',
+                type: '鎵ц棰戠巼',
+                daily: '姣忓ぉ',
+                weekly: '姣忓懆',
+                monthly: '姣忔湀',
+                time: '鎵ц鏃堕棿',
+                weeklyLabel: '鎵ц鏄熸湡',
+                monthlyLabel: '鎵ц鏃�',
+                monthHelper: '鑷冲皯閫夋嫨涓�涓棩鏈�',
+                monthDay: '%{day} 鏃�',
+                preview: 'Cron 琛ㄨ揪寮�',
+                descriptionPrefix: '绯荤粺灏嗗湪 %{desc} 瑙﹀彂',
+                description: {
+                    daily: '姣忓ぉ %{time}',
+                    weekly: '姣忓懆 %{days} %{time}',
+                    monthly: '姣忔湀 %{days} %{time}',
+                },
+            },
+            week: {
+                mon: '鍛ㄤ竴',
+                tue: '鍛ㄤ簩',
+                wed: '鍛ㄤ笁',
+                thu: '鍛ㄥ洓',
+                fri: '鍛ㄤ簲',
+                sat: '鍛ㄥ叚',
+                sun: '鍛ㄦ棩',
+            },
+        },
         sta: {
             depthHint: '娣卞害璁剧疆涓� 0 琛ㄧず娌跨敤榛樿鍊笺��',
             enums: {
diff --git a/zy-acs-flow/src/page/action/ActionList.jsx b/zy-acs-flow/src/page/action/ActionList.jsx
index aa0c286..8c77c3e 100644
--- a/zy-acs-flow/src/page/action/ActionList.jsx
+++ b/zy-acs-flow/src/page/action/ActionList.jsx
@@ -122,7 +122,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.action"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/actionSts/ActionStsList.jsx b/zy-acs-flow/src/page/actionSts/ActionStsList.jsx
index 7985600..c472f53 100644
--- a/zy-acs-flow/src/page/actionSts/ActionStsList.jsx
+++ b/zy-acs-flow/src/page/actionSts/ActionStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.actionSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/actionType/ActionTypeList.jsx b/zy-acs-flow/src/page/actionType/ActionTypeList.jsx
index 8e60509..0a3dd57 100644
--- a/zy-acs-flow/src/page/actionType/ActionTypeList.jsx
+++ b/zy-acs-flow/src/page/actionType/ActionTypeList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.actionType"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/agv/AgvList.jsx b/zy-acs-flow/src/page/agv/AgvList.jsx
index b0855da..56da0da 100644
--- a/zy-acs-flow/src/page/agv/AgvList.jsx
+++ b/zy-acs-flow/src/page/agv/AgvList.jsx
@@ -168,7 +168,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.agv"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx b/zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx
index b18562f..6889492 100644
--- a/zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx
+++ b/zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx
@@ -119,7 +119,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.agvDetail"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/agvModel/AgvModelList.jsx b/zy-acs-flow/src/page/agvModel/AgvModelList.jsx
index ab519aa..8297181 100644
--- a/zy-acs-flow/src/page/agvModel/AgvModelList.jsx
+++ b/zy-acs-flow/src/page/agvModel/AgvModelList.jsx
@@ -111,7 +111,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.agvModel"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/agvSts/AgvStsList.jsx b/zy-acs-flow/src/page/agvSts/AgvStsList.jsx
index aadf665..e58a09e 100644
--- a/zy-acs-flow/src/page/agvSts/AgvStsList.jsx
+++ b/zy-acs-flow/src/page/agvSts/AgvStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.agvSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/area/AreaList.jsx b/zy-acs-flow/src/page/area/AreaList.jsx
index 55ca554..02d5d4c 100644
--- a/zy-acs-flow/src/page/area/AreaList.jsx
+++ b/zy-acs-flow/src/page/area/AreaList.jsx
@@ -105,7 +105,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.area"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/bus/BusList.jsx b/zy-acs-flow/src/page/bus/BusList.jsx
index d411899..cf96b29 100644
--- a/zy-acs-flow/src/page/bus/BusList.jsx
+++ b/zy-acs-flow/src/page/bus/BusList.jsx
@@ -128,7 +128,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.bus"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/busSts/BusStsList.jsx b/zy-acs-flow/src/page/busSts/BusStsList.jsx
index 244f1bd..fbfa3a4 100644
--- a/zy-acs-flow/src/page/busSts/BusStsList.jsx
+++ b/zy-acs-flow/src/page/busSts/BusStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.busSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/code/CodeList.jsx b/zy-acs-flow/src/page/code/CodeList.jsx
index 797ea44..1f45bad 100644
--- a/zy-acs-flow/src/page/code/CodeList.jsx
+++ b/zy-acs-flow/src/page/code/CodeList.jsx
@@ -117,7 +117,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.code"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/codeGap/CodeGapList.jsx b/zy-acs-flow/src/page/codeGap/CodeGapList.jsx
index d665dfe..2ff4f3c 100644
--- a/zy-acs-flow/src/page/codeGap/CodeGapList.jsx
+++ b/zy-acs-flow/src/page/codeGap/CodeGapList.jsx
@@ -96,7 +96,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.codeGap"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/config/ConfigList.jsx b/zy-acs-flow/src/page/config/ConfigList.jsx
index 41850e9..c27a826 100644
--- a/zy-acs-flow/src/page/config/ConfigList.jsx
+++ b/zy-acs-flow/src/page/config/ConfigList.jsx
@@ -100,7 +100,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.config"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/funcSta/FuncStaList.jsx b/zy-acs-flow/src/page/funcSta/FuncStaList.jsx
index 8dff6cf..cfd649e 100644
--- a/zy-acs-flow/src/page/funcSta/FuncStaList.jsx
+++ b/zy-acs-flow/src/page/funcSta/FuncStaList.jsx
@@ -131,7 +131,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.funcSta"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/guarantee/CronField.jsx b/zy-acs-flow/src/page/guarantee/CronField.jsx
new file mode 100644
index 0000000..5517dc4
--- /dev/null
+++ b/zy-acs-flow/src/page/guarantee/CronField.jsx
@@ -0,0 +1,150 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { useInput, useTranslate } from 'react-admin';
+import {
+    Box,
+    FormControl,
+    InputLabel,
+    MenuItem,
+    Select,
+    Stack,
+    TextField,
+    ToggleButton,
+    ToggleButtonGroup,
+    Typography,
+    Chip,
+} from '@mui/material';
+import Autocomplete from '@mui/material/Autocomplete';
+import {
+    DEFAULT_CRON_EXPRESSION,
+    DEFAULT_SCHEDULE_STATE,
+    MONTH_DAY_OPTIONS,
+    SCHEDULE_MODES,
+    WEEK_DAYS,
+    buildCronExpression,
+    describeCronExpression,
+    getWeekdayLabel,
+    parseCronExpression,
+} from './cronUtils';
+
+const CronField = ({ source = 'cronExpr', ...rest }) => {
+    const translate = useTranslate();
+    const { field } = useInput({ source, defaultValue: DEFAULT_CRON_EXPRESSION, ...rest });
+    const [state, setState] = useState(() => parseCronExpression(field.value || DEFAULT_CRON_EXPRESSION));
+
+    useEffect(() => {
+        setState(parseCronExpression(field.value || DEFAULT_CRON_EXPRESSION));
+    }, [field.value]);
+
+    useEffect(() => {
+        const cron = buildCronExpression(state);
+        if (cron !== field.value) {
+            field.onChange(cron);
+        }
+    }, [state, field]);
+
+    const handleModeChange = (event) => {
+        const mode = event.target.value;
+        setState((prev) => ({
+            ...prev,
+            mode,
+            weekDays: mode === SCHEDULE_MODES.WEEKLY ? prev.weekDays || DEFAULT_SCHEDULE_STATE.weekDays : prev.weekDays,
+            monthDays: mode === SCHEDULE_MODES.MONTHLY ? prev.monthDays || DEFAULT_SCHEDULE_STATE.monthDays : prev.monthDays,
+        }));
+    };
+
+    const handleTimeChange = (event) => {
+        const newTime = event.target.value;
+        setState((prev) => ({ ...prev, time: newTime }));
+    };
+
+    const handleWeekDaysChange = (_, newDays) => {
+        if (!newDays.length) {
+            return;
+        }
+        setState((prev) => ({ ...prev, weekDays: newDays }));
+    };
+
+    const handleMonthDaysChange = (_, newDays) => {
+        if (!newDays.length) {
+            newDays = DEFAULT_SCHEDULE_STATE.monthDays;
+        }
+        setState((prev) => ({ ...prev, monthDays: newDays }));
+    };
+
+    const cronExpression = useMemo(() => buildCronExpression(state), [state]);
+    const description = useMemo(() => describeCronExpression(cronExpression, translate), [cronExpression, translate]);
+
+    return (
+        <Stack spacing={2} sx={{ width: '100%' }}>
+            <Typography variant="subtitle1">{translate('page.guarantee.schedule.label')}</Typography>
+            <FormControl fullWidth>
+                <InputLabel>{translate('page.guarantee.schedule.type')}</InputLabel>
+                <Select
+                    label={translate('page.guarantee.schedule.type')}
+                    value={state.mode || SCHEDULE_MODES.DAILY}
+                    onChange={handleModeChange}
+                >
+                    <MenuItem value={SCHEDULE_MODES.DAILY}>{translate('page.guarantee.schedule.daily')}</MenuItem>
+                    <MenuItem value={SCHEDULE_MODES.WEEKLY}>{translate('page.guarantee.schedule.weekly')}</MenuItem>
+                    <MenuItem value={SCHEDULE_MODES.MONTHLY}>{translate('page.guarantee.schedule.monthly')}</MenuItem>
+                </Select>
+            </FormControl>
+            <TextField
+                label={translate('page.guarantee.schedule.time')}
+                type="time"
+                value={state.time || DEFAULT_SCHEDULE_STATE.time}
+                onChange={handleTimeChange}
+                inputProps={{ step: 300 }}
+            />
+            {state.mode === SCHEDULE_MODES.WEEKLY && (
+                <Box>
+                    <Typography variant="body2" gutterBottom>
+                        {translate('page.guarantee.schedule.weeklyLabel')}
+                    </Typography>
+                    <ToggleButtonGroup value={state.weekDays || []} onChange={handleWeekDaysChange} size="small">
+                        {WEEK_DAYS.map((day) => (
+                            <ToggleButton key={day} value={day} aria-label={day} sx={{ textTransform: 'none' }}>
+                                {getWeekdayLabel(day, translate)}
+                            </ToggleButton>
+                        ))}
+                    </ToggleButtonGroup>
+                </Box>
+            )}
+            {state.mode === SCHEDULE_MODES.MONTHLY && (
+                <Autocomplete
+                    multiple
+                    options={MONTH_DAY_OPTIONS}
+                    value={state.monthDays || []}
+                    onChange={handleMonthDaysChange}
+                    renderTags={(value, getTagProps) =>
+                        value.map((option, index) => (
+                            <Chip
+                                variant="outlined"
+                                label={translate('page.guarantee.schedule.monthDay', { day: option })}
+                                {...getTagProps({ index })}
+                                key={`month-day-${option}`}
+                            />
+                        ))
+                    }
+                    renderInput={(params) => (
+                        <TextField
+                            {...params}
+                            label={translate('page.guarantee.schedule.monthlyLabel')}
+                            helperText={translate('page.guarantee.schedule.monthHelper')}
+                        />
+                    )}
+                />
+            )}
+            <TextField
+                label={translate('page.guarantee.schedule.preview')}
+                value={cronExpression}
+                InputProps={{ readOnly: true }}
+            />
+            <Typography variant="caption" color="text.secondary">
+                {translate('page.guarantee.schedule.descriptionPrefix', { desc: description })}
+            </Typography>
+        </Stack>
+    );
+};
+
+export default CronField;
diff --git a/zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx b/zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx
index 7b28c4d..16239fa 100644
--- a/zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx
+++ b/zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx
@@ -4,19 +4,11 @@
     useTranslate,
     TextInput,
     NumberInput,
-    BooleanInput,
-    DateInput,
     SaveButton,
-    SelectInput,
-    ReferenceInput,
-    ReferenceArrayInput,
-    AutocompleteInput,
     Toolbar,
     required,
-    useDataProvider,
     useNotify,
     Form,
-    useCreateController,
 } from 'react-admin';
 import {
     Dialog,
@@ -30,12 +22,25 @@
 import DialogCloseButton from "../components/DialogCloseButton";
 import StatusSelectInput from "../components/StatusSelectInput";
 import MemoInput from "../components/MemoInput";
+import ScopeField from "./ScopeField";
+import CronField from "./CronField";
+import { DEFAULT_CRON_EXPRESSION } from "./cronUtils";
+import { DEFAULT_SCOPE_TYPE } from "./guaranteeConstants";
 
 const GuaranteeCreate = (props) => {
     const { open, setOpen } = props;
 
     const translate = useTranslate();
     const notify = useNotify();
+
+    const defaultRecord = {
+        scopeType: DEFAULT_SCOPE_TYPE,
+        cronExpr: DEFAULT_CRON_EXPRESSION,
+        requiredCount: 10,
+        minSoc: 50,
+        leadTime: 60,
+        status: 1,
+    };
 
     const handleClose = (event, reason) => {
         if (reason !== "backdropClick") {
@@ -55,9 +60,13 @@
     return (
         <>
             <CreateBase
-                record={{}}
+                record={defaultRecord}
                 transform={(data) => {
-                    return data;
+                    return {
+                        ...data,
+                        cronExpr: (data.cronExpr || '').trim(),
+                        scopeValue: data.scopeType === DEFAULT_SCOPE_TYPE ? null : data.scopeValue,
+                    };
                 }}
                 mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
             >
@@ -97,45 +106,39 @@
                                         label="table.field.guarantee.name"
                                         source="name"
                                         parse={v => v}
+                                        validate={[required()]}
+                                        fullWidth
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.guarantee.scopeType"
-                                        source="scopeType"
-                                        parse={v => v}
-                                    />
+                                <Grid item xs={12}>
+                                    <ScopeField />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.guarantee.scopeValue"
-                                        source="scopeValue"
-                                        parse={v => v}
-                                    />
+                                <Grid item xs={12}>
+                                    <CronField />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.guarantee.cronExpr"
-                                        source="cronExpr"
-                                        parse={v => v}
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
+                                <Grid item xs={4} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.guarantee.requiredCount"
                                         source="requiredCount"
+                                        validate={[required()]}
+                                        min={1}
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
+                                <Grid item xs={4} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.guarantee.minSoc"
                                         source="minSoc"
+                                        validate={[required()]}
+                                        min={1}
+                                        max={100}
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
+                                <Grid item xs={4} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.guarantee.leadTime"
                                         source="leadTime"
+                                        validate={[required()]}
+                                        min={1}
                                     />
                                 </Grid>
 
diff --git a/zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx b/zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx
index 4580c59..aae03b9 100644
--- a/zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx
+++ b/zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx
@@ -2,36 +2,25 @@
 import {
     Edit,
     SimpleForm,
-    FormDataConsumer,
     useTranslate,
     TextInput,
     NumberInput,
-    BooleanInput,
-    DateInput,
-    SelectInput,
-    ReferenceInput,
-    ReferenceArrayInput,
-    AutocompleteInput,
     SaveButton,
     Toolbar,
-    Labeled,
-    NumberField,
     required,
-    useRecordContext,
     DeleteButton,
 } from 'react-admin';
-import { useWatch, useFormContext } from "react-hook-form";
 import { Stack, Grid, Box, Typography } from '@mui/material';
-import * as Common from '@/utils/common';
-import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import { EDIT_MODE } from '@/config/setting';
 import EditBaseAside from "../components/EditBaseAside";
 import CustomerTopToolBar from "../components/EditTopToolBar";
 import MemoInput from "../components/MemoInput";
 import StatusSelectInput from "../components/StatusSelectInput";
+import ScopeField from "./ScopeField";
+import CronField from "./CronField";
+import { DEFAULT_SCOPE_TYPE } from "./guaranteeConstants";
 
 const FormToolbar = () => {
-    const { getValues } = useFormContext();
-
     return (
         <Toolbar sx={{ justifyContent: 'space-between' }}>
             <SaveButton />
@@ -76,45 +65,36 @@
                                 label="table.field.guarantee.name"
                                 source="name"
                                 parse={v => v}
+                                validate={[required()]}
                             />
                         </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.guarantee.scopeType"
-                                source="scopeType"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.guarantee.scopeValue"
-                                source="scopeValue"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.guarantee.cronExpr"
-                                source="cronExpr"
-                                parse={v => v}
-                            />
-                        </Stack>
+                        <ScopeField />
+                        <Box mt={2}>
+                            <CronField />
+                        </Box>
                         <Stack direction='row' gap={2}>
                             <NumberInput
                                 label="table.field.guarantee.requiredCount"
                                 source="requiredCount"
+                                validate={[required()]}
+                                min={1}
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
                             <NumberInput
                                 label="table.field.guarantee.minSoc"
                                 source="minSoc"
+                                validate={[required()]}
+                                min={1}
+                                max={100}
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
                             <NumberInput
                                 label="table.field.guarantee.leadTime"
                                 source="leadTime"
+                                validate={[required()]}
+                                min={1}
                             />
                         </Stack>
 
@@ -133,4 +113,20 @@
     )
 }
 
-export default GuaranteeEdit;
+const GuaranteeEditWrapper = () => (
+    <Edit
+        redirect="list"
+        mutationMode={EDIT_MODE}
+        actions={<CustomerTopToolBar />}
+        aside={<EditBaseAside />}
+        transform={(data) => ({
+            ...data,
+            cronExpr: (data.cronExpr || '').trim(),
+            scopeValue: data.scopeType === DEFAULT_SCOPE_TYPE ? null : data.scopeValue,
+        })}
+    >
+        <GuaranteeEdit />
+    </Edit>
+);
+
+export default GuaranteeEditWrapper;
diff --git a/zy-acs-flow/src/page/guarantee/GuaranteeList.jsx b/zy-acs-flow/src/page/guarantee/GuaranteeList.jsx
index 576e125..cd953e2 100644
--- a/zy-acs-flow/src/page/guarantee/GuaranteeList.jsx
+++ b/zy-acs-flow/src/page/guarantee/GuaranteeList.jsx
@@ -1,21 +1,14 @@
-import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
-import { useNavigate } from 'react-router-dom';
+import React, { useState, useCallback } from "react";
 import {
     List,
     DatagridConfigurable,
     SearchInput,
     TopToolbar,
     SelectColumnsButton,
-    EditButton,
     FilterButton,
-    CreateButton,
-    ExportButton,
     BulkDeleteButton,
     WrapperField,
-    useRecordContext,
     useTranslate,
-    useNotify,
-    useListContext,
     FunctionField,
     TextField,
     NumberField,
@@ -27,10 +20,8 @@
     DateInput,
     SelectInput,
     NumberInput,
-    ReferenceInput,
-    ReferenceArrayInput,
-    AutocompleteInput,
     DeleteButton,
+    EditButton,
 } from 'react-admin';
 import { Box, Typography, Card, Stack } from '@mui/material';
 import { styled } from '@mui/material/styles';
@@ -40,9 +31,10 @@
 import MyCreateButton from "../components/MyCreateButton";
 import MyExportButton from '../components/MyExportButton';
 import PageDrawer from "../components/PageDrawer";
-import MyField from "../components/MyField";
 import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
 import * as Common from '@/utils/common';
+import { describeCronExpression } from "./cronUtils";
+import { DEFAULT_SCOPE_TYPE, SCOPE_FILTER_CHOICES, getScopeLabel } from "./guaranteeConstants";
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
     '& .css-1vooibu-MuiSvgIcon-root': {
@@ -65,7 +57,14 @@
 
     <TextInput source="uuid" label="table.field.guarantee.uuid" />,
     <TextInput source="name" label="table.field.guarantee.name" />,
-    <TextInput source="scopeType" label="table.field.guarantee.scopeType" />,
+    <SelectInput
+        source="scopeType"
+        label="table.field.guarantee.scopeType"
+        choices={SCOPE_FILTER_CHOICES}
+        translateChoice
+        allowEmpty
+        resettable
+    />,
     <TextInput source="scopeValue" label="table.field.guarantee.scopeValue" />,
     <TextInput source="cronExpr" label="table.field.guarantee.cronExpr" />,
     <NumberInput source="requiredCount" label="table.field.guarantee.requiredCount" />,
@@ -90,6 +89,32 @@
     const [createDialog, setCreateDialog] = useState(false);
     const [drawerVal, setDrawerVal] = useState(false);
 
+    const renderScopeType = useCallback((record) => {
+        if (!record) {
+            return '';
+        }
+        return getScopeLabel(record.scopeType, translate);
+    }, [translate]);
+
+    const renderScopeValue = useCallback((record) => {
+        if (!record) {
+            return '';
+        }
+        if (!record.scopeValue) {
+            return record.scopeType === DEFAULT_SCOPE_TYPE
+                ? translate('page.guarantee.scope.globalHelper')
+                : translate('common.enums.na');
+        }
+        return record.scopeValue;
+    }, [translate]);
+
+    const renderCron = useCallback((record) => {
+        if (!record || !record.cronExpr) {
+            return translate('common.enums.na');
+        }
+        return describeCronExpression(record.cronExpr, translate);
+    }, [translate]);
+
     return (
         <Box display="flex">
             <List
@@ -99,7 +124,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.guarantee"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -126,9 +151,9 @@
                     <NumberField source="id" />
                     <TextField source="uuid" label="table.field.guarantee.uuid" />
                     <TextField source="name" label="table.field.guarantee.name" />
-                    <TextField source="scopeType" label="table.field.guarantee.scopeType" />
-                    <TextField source="scopeValue" label="table.field.guarantee.scopeValue" />
-                    <TextField source="cronExpr" label="table.field.guarantee.cronExpr" />
+                    <FunctionField label="table.field.guarantee.scopeType" render={renderScopeType} />
+                    <FunctionField label="table.field.guarantee.scopeValue" render={renderScopeValue} />
+                    <FunctionField label="table.field.guarantee.cronExpr" render={renderCron} />
                     <NumberField source="requiredCount" label="table.field.guarantee.requiredCount" />
                     <NumberField source="minSoc" label="table.field.guarantee.minSoc" />
                     <NumberField source="leadTime" label="table.field.guarantee.leadTime" />
diff --git a/zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx b/zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx
index 300213c..8c95403 100644
--- a/zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx
+++ b/zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx
@@ -6,11 +6,23 @@
 } from 'react-admin';
 import PanelTypography from "../components/PanelTypography";
 import * as Common from '@/utils/common'
+import { describeCronExpression } from "./cronUtils";
+import { DEFAULT_SCOPE_TYPE, getScopeLabel } from "./guaranteeConstants";
 
 const GuaranteePanel = () => {
     const record = useRecordContext();
     if (!record) return null;
     const translate = useTranslate();
+    const scopeTypeLabel = getScopeLabel(record.scopeType, translate);
+    const scopeValueLabel = record.scopeValue
+        ? record.scopeValue
+        : record.scopeType === DEFAULT_SCOPE_TYPE
+            ? translate('page.guarantee.scope.globalHelper')
+            : translate('common.enums.na');
+    const cronDesc = record.cronExpr
+        ? `${describeCronExpression(record.cronExpr, translate)} (${record.cronExpr})`
+        : translate('common.enums.na');
+
     return (
         <>
             <Card sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: 'auto' }}>
@@ -55,19 +67,19 @@
                         <Grid item xs={6}>
                             <PanelTypography
                                 title="table.field.guarantee.scopeType" 
-                                property={record.scopeType}
+                                property={scopeTypeLabel}
                             />
                         </Grid>
                         <Grid item xs={6}>
                             <PanelTypography
                                 title="table.field.guarantee.scopeValue" 
-                                property={record.scopeValue}
+                                property={scopeValueLabel}
                             />
                         </Grid>
                         <Grid item xs={6}>
                             <PanelTypography
                                 title="table.field.guarantee.cronExpr" 
-                                property={record.cronExpr}
+                                property={cronDesc}
                             />
                         </Grid>
                         <Grid item xs={6}>
diff --git a/zy-acs-flow/src/page/guarantee/ScopeField.jsx b/zy-acs-flow/src/page/guarantee/ScopeField.jsx
new file mode 100644
index 0000000..0b89c90
--- /dev/null
+++ b/zy-acs-flow/src/page/guarantee/ScopeField.jsx
@@ -0,0 +1,70 @@
+import React from 'react';
+import { Stack, TextField } from '@mui/material';
+import {
+    AutocompleteInput,
+    FormDataConsumer,
+    ReferenceInput,
+    SelectInput,
+    required,
+    useTranslate,
+} from 'react-admin';
+import { REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import { DEFAULT_SCOPE_TYPE, SCOPE_OPTIONS, getScopeConfig } from './guaranteeConstants';
+
+const ScopeField = () => {
+    const translate = useTranslate();
+
+    return (
+        <Stack spacing={2} sx={{ width: '100%' }}>
+            <SelectInput
+                label="table.field.guarantee.scopeType"
+                source="scopeType"
+                choices={SCOPE_OPTIONS}
+                optionText={(choice) => translate(choice.labelKey)}
+                optionValue="id"
+                translateChoice={false}
+                defaultValue={DEFAULT_SCOPE_TYPE}
+                helperText={translate('page.guarantee.scope.helper')}
+            />
+            <FormDataConsumer>
+                {({ formData, ...rest }) => {
+                    const currentType = formData.scopeType || DEFAULT_SCOPE_TYPE;
+                    const config = getScopeConfig(currentType);
+
+                    if (config.valueType === 'reference') {
+                        return (
+                            <ReferenceInput
+                                key={currentType}
+                                source="scopeValue"
+                                reference={config.reference}
+                                perPage={REFERENCE_INPUT_PAGESIZE}
+                                {...rest}
+                            >
+                                <AutocompleteInput
+                                    label="table.field.guarantee.scopeValue"
+                                    optionText={config.optionText}
+                                    optionValue={config.optionValue || 'id'}
+                                    filterToQuery={config.filterToQuery}
+                                    validate={[required()]}
+                                    fullWidth
+                                />
+                            </ReferenceInput>
+                        );
+                    }
+
+                    return (
+                        <TextField
+                            label={translate('table.field.guarantee.scopeValue')}
+                            value={translate('page.guarantee.scope.globalHelper')}
+                            helperText={translate('page.guarantee.scope.globalTip')}
+                            disabled
+                            fullWidth
+                        />
+                    );
+                }}
+            </FormDataConsumer>
+        </Stack>
+    );
+};
+
+export default ScopeField;
diff --git a/zy-acs-flow/src/page/guarantee/cronUtils.js b/zy-acs-flow/src/page/guarantee/cronUtils.js
new file mode 100644
index 0000000..29b8120
--- /dev/null
+++ b/zy-acs-flow/src/page/guarantee/cronUtils.js
@@ -0,0 +1,168 @@
+export const SCHEDULE_MODES = {
+    DAILY: 'DAILY',
+    WEEKLY: 'WEEKLY',
+    MONTHLY: 'MONTHLY',
+};
+
+export const WEEK_DAYS = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'];
+export const MONTH_DAY_OPTIONS = Array.from({ length: 31 }, (_, idx) => idx + 1);
+
+const DEFAULT_TIME = '10:00';
+const pad = (value) => value.toString().padStart(2, '0');
+
+const sanitizeWeekDays = (days) => {
+    if (!Array.isArray(days) || days.length === 0) {
+        return ['MON'];
+    }
+    const unique = [...new Set(days.filter((day) => WEEK_DAYS.includes(day)))];
+    return unique.length ? unique : ['MON'];
+};
+
+const sanitizeMonthDays = (days) => {
+    if (!Array.isArray(days) || days.length === 0) {
+        return [1];
+    }
+    const unique = [...new Set(days.map((day) => Number(day)).filter((day) => day >= 1 && day <= 31))];
+    return unique.length ? unique : [1];
+};
+
+const sanitizeTime = (time = DEFAULT_TIME) => {
+    if (typeof time !== 'string') {
+        return DEFAULT_TIME;
+    }
+    const [hour = '10', minute = '00'] = time.split(':');
+    const parsedHour = Math.min(23, Math.max(0, parseInt(hour, 10) || 0));
+    const parsedMinute = Math.min(59, Math.max(0, parseInt(minute, 10) || 0));
+    return `${pad(parsedHour)}:${pad(parsedMinute)}`;
+};
+
+export const DEFAULT_SCHEDULE_STATE = {
+    mode: SCHEDULE_MODES.DAILY,
+    time: DEFAULT_TIME,
+    weekDays: ['MON'],
+    monthDays: [1],
+};
+
+export const buildCronExpression = (state = DEFAULT_SCHEDULE_STATE) => {
+    const mode = state?.mode || SCHEDULE_MODES.DAILY;
+    const time = sanitizeTime(state?.time);
+    const [hour, minute] = time.split(':');
+
+    if (mode === SCHEDULE_MODES.WEEKLY) {
+        const days = sanitizeWeekDays(state?.weekDays).join(',');
+        return `0 ${minute} ${hour} ? * ${days}`;
+    }
+
+    if (mode === SCHEDULE_MODES.MONTHLY) {
+        const days = sanitizeMonthDays(state?.monthDays).sort((a, b) => a - b).join(',');
+        return `0 ${minute} ${hour} ${days} * ?`;
+    }
+
+    return `0 ${minute} ${hour} * * ?`;
+};
+
+export const DEFAULT_CRON_EXPRESSION = buildCronExpression(DEFAULT_SCHEDULE_STATE);
+
+const createParsedState = () => ({
+    ...DEFAULT_SCHEDULE_STATE,
+    valid: false,
+});
+
+export const parseCronExpression = (expr) => {
+    const state = createParsedState();
+    if (!expr || typeof expr !== 'string') {
+        return state;
+    }
+    const tokens = expr.trim().split(/\s+/);
+    if (tokens.length < 6) {
+        return state;
+    }
+    const [, minute, hour, dayOfMonth, , dayOfWeek] = tokens;
+    const time = sanitizeTime(`${hour}:${minute}`);
+
+    if (dayOfMonth === '*' && dayOfWeek === '?') {
+        return {
+            ...state,
+            valid: true,
+            mode: SCHEDULE_MODES.DAILY,
+            time,
+        };
+    }
+
+    if (dayOfMonth === '?' && dayOfWeek && dayOfWeek !== '?') {
+        const weekDays = dayOfWeek.split(',').filter((day) => WEEK_DAYS.includes(day));
+        return {
+            ...state,
+            valid: true,
+            mode: SCHEDULE_MODES.WEEKLY,
+            time,
+            weekDays: sanitizeWeekDays(weekDays),
+        };
+    }
+
+    if (dayOfMonth && dayOfMonth !== '*' && dayOfWeek === '?') {
+        const monthDays = dayOfMonth
+            .split(',')
+            .map((day) => parseInt(day, 10))
+            .filter((day) => !Number.isNaN(day));
+        return {
+            ...state,
+            valid: true,
+            mode: SCHEDULE_MODES.MONTHLY,
+            time,
+            monthDays: sanitizeMonthDays(monthDays),
+        };
+    }
+
+    return state;
+};
+
+export const getWeekdayLabel = (day, translate) => {
+    const key = `page.guarantee.week.${day?.toLowerCase?.()}`;
+    return translate ? translate(key) : day;
+};
+
+const formatWeekdays = (days, translate) => {
+    const normalized = sanitizeWeekDays(days);
+    return normalized.map((day) => getWeekdayLabel(day, translate)).join(' / ');
+};
+
+const formatMonthDays = (days, translate) => {
+    const normalized = sanitizeMonthDays(days).sort((a, b) => a - b);
+    return normalized
+        .map((day) => (translate ? translate('page.guarantee.schedule.monthDay', { day }) : `${day}`))
+        .join(' / ');
+};
+
+export const describeCronExpression = (expr, translate) => {
+    if (!expr) {
+        return '';
+    }
+    const parsed = parseCronExpression(expr);
+    const time = parsed.time || DEFAULT_TIME;
+
+    if (!parsed.valid) {
+        return expr;
+    }
+
+    switch (parsed.mode) {
+        case SCHEDULE_MODES.WEEKLY:
+            return translate
+                ? translate('page.guarantee.schedule.description.weekly', {
+                    days: formatWeekdays(parsed.weekDays, translate),
+                    time,
+                })
+                : `Weekly ${formatWeekdays(parsed.weekDays)} ${time}`;
+        case SCHEDULE_MODES.MONTHLY:
+            return translate
+                ? translate('page.guarantee.schedule.description.monthly', {
+                    days: formatMonthDays(parsed.monthDays, translate),
+                    time,
+                })
+                : `Monthly ${formatMonthDays(parsed.monthDays)} ${time}`;
+        default:
+            return translate
+                ? translate('page.guarantee.schedule.description.daily', { time })
+                : `Daily ${time}`;
+    }
+};
diff --git a/zy-acs-flow/src/page/guarantee/guaranteeConstants.js b/zy-acs-flow/src/page/guarantee/guaranteeConstants.js
new file mode 100644
index 0000000..fbc0aba
--- /dev/null
+++ b/zy-acs-flow/src/page/guarantee/guaranteeConstants.js
@@ -0,0 +1,63 @@
+const buildFilter = (field) => (value) => ({ [field]: value });
+
+export const SCOPE_CONFIGS = {
+    GLOBAL: {
+        id: 'GLOBAL',
+        labelKey: 'page.guarantee.scope.global',
+        valueType: 'none',
+    },
+    MODEL: {
+        id: 'MODEL',
+        labelKey: 'page.guarantee.scope.model',
+        valueType: 'reference',
+        reference: 'agvModel',
+        optionText: 'name',
+        optionValue: 'id',
+        filterToQuery: buildFilter('name'),
+    },
+    AREA: {
+        id: 'AREA',
+        labelKey: 'page.guarantee.scope.area',
+        valueType: 'reference',
+        reference: 'area',
+        optionText: 'name',
+        optionValue: 'id',
+        filterToQuery: buildFilter('name'),
+    },
+    BIZ: {
+        id: 'BIZ',
+        labelKey: 'page.guarantee.scope.biz',
+        valueType: 'reference',
+        reference: 'taskType',
+        optionText: 'name',
+        optionValue: 'id',
+        filterToQuery: buildFilter('name'),
+    },
+    AGV: {
+        id: 'AGV',
+        labelKey: 'page.guarantee.scope.agv',
+        valueType: 'reference',
+        reference: 'agv',
+        optionText: 'uuid',
+        optionValue: 'id',
+        filterToQuery: buildFilter('uuid'),
+    },
+};
+
+export const DEFAULT_SCOPE_TYPE = SCOPE_CONFIGS.GLOBAL.id;
+
+export const SCOPE_OPTIONS = Object.values(SCOPE_CONFIGS);
+
+export const SCOPE_FILTER_CHOICES = SCOPE_OPTIONS.map(({ id, labelKey }) => ({
+    id,
+    name: labelKey,
+}));
+
+export const getScopeConfig = (scopeType) => SCOPE_CONFIGS[scopeType] || SCOPE_CONFIGS.GLOBAL;
+
+export const getScopeLabelKey = (scopeType) => getScopeConfig(scopeType).labelKey;
+
+export const getScopeLabel = (scopeType, translate) => {
+    const key = getScopeLabelKey(scopeType);
+    return translate ? translate(key) : key;
+};
diff --git a/zy-acs-flow/src/page/host/HostList.jsx b/zy-acs-flow/src/page/host/HostList.jsx
index ac9be3d..6bad995 100644
--- a/zy-acs-flow/src/page/host/HostList.jsx
+++ b/zy-acs-flow/src/page/host/HostList.jsx
@@ -82,7 +82,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.host"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx
index 8d6e450..016e5cf 100644
--- a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx
+++ b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx
@@ -106,7 +106,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.integrationRecord"}
                 empty={<EmptyDataLoader />}
diff --git a/zy-acs-flow/src/page/jam/JamList.jsx b/zy-acs-flow/src/page/jam/JamList.jsx
index 212cfb0..c2a12ab 100644
--- a/zy-acs-flow/src/page/jam/JamList.jsx
+++ b/zy-acs-flow/src/page/jam/JamList.jsx
@@ -147,7 +147,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.jam"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/lane/LaneList.jsx b/zy-acs-flow/src/page/lane/LaneList.jsx
index 8fc152c..0b47a33 100644
--- a/zy-acs-flow/src/page/lane/LaneList.jsx
+++ b/zy-acs-flow/src/page/lane/LaneList.jsx
@@ -112,7 +112,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.lane"}
                 empty={<EmptyDataLoader />}
diff --git a/zy-acs-flow/src/page/loc/LocList.jsx b/zy-acs-flow/src/page/loc/LocList.jsx
index 657c561..ecff579 100644
--- a/zy-acs-flow/src/page/loc/LocList.jsx
+++ b/zy-acs-flow/src/page/loc/LocList.jsx
@@ -132,7 +132,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.loc"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/locSts/LocStsList.jsx b/zy-acs-flow/src/page/locSts/LocStsList.jsx
index e72434b..0bf9f4b 100644
--- a/zy-acs-flow/src/page/locSts/LocStsList.jsx
+++ b/zy-acs-flow/src/page/locSts/LocStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.locSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/locType/LocTypeList.jsx b/zy-acs-flow/src/page/locType/LocTypeList.jsx
index 34b50b7..eeea2f3 100644
--- a/zy-acs-flow/src/page/locType/LocTypeList.jsx
+++ b/zy-acs-flow/src/page/locType/LocTypeList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.locType"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/mission/MissionResend.jsx b/zy-acs-flow/src/page/mission/MissionResend.jsx
index 85823b3..a8ad383 100644
--- a/zy-acs-flow/src/page/mission/MissionResend.jsx
+++ b/zy-acs-flow/src/page/mission/MissionResend.jsx
@@ -57,7 +57,7 @@
             }}
         >
             <DialogContent sx={{ padding: 0 }}>
-                {!!id ? (
+                {id ? (
                     <ShowBase id={id}>
                         <MissionResendContent handleClose={handleClose} />
                     </ShowBase>
@@ -231,7 +231,7 @@
     };
 
     const resendSubmit = () => {
-        if (!!selected?.length) {
+        if (selected?.length) {
             request.post("/mission/resend", selected.map(id => ({ id }))).then(res => {
                 const { code, msg, data } = res.data;
                 if (code === 200) {
diff --git a/zy-acs-flow/src/page/mission/MissionShow.jsx b/zy-acs-flow/src/page/mission/MissionShow.jsx
index 4ccffc4..c78511e 100644
--- a/zy-acs-flow/src/page/mission/MissionShow.jsx
+++ b/zy-acs-flow/src/page/mission/MissionShow.jsx
@@ -53,7 +53,7 @@
             }}
         >
             <DialogContent sx={{ padding: 0 }}>
-                {!!id ? (
+                {id ? (
                     <ShowBase id={id}>
                         <MissionShowContent handleClose={handleClose} />
                     </ShowBase>
diff --git a/zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx b/zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx
index 940424a..8c2d42a 100644
--- a/zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx
+++ b/zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx
@@ -122,7 +122,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.operation"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/role/RoleList.jsx b/zy-acs-flow/src/page/role/RoleList.jsx
index d03ab60..6c43310 100644
--- a/zy-acs-flow/src/page/role/RoleList.jsx
+++ b/zy-acs-flow/src/page/role/RoleList.jsx
@@ -112,7 +112,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.role"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -163,7 +163,7 @@
             <PageDrawer
                 drawerVal={drawerVal}
                 setDrawerVal={setDrawerVal}
-                title={!!drawerVal ? `Scope by ${drawerVal.code || drawerVal.name}` : 'Role Detail'}
+                title={drawerVal ? `Scope by ${drawerVal.code || drawerVal.name}` : 'Role Detail'}
                 closeCallback={() => {
                     setMenuIds([]);
                 }}
diff --git a/zy-acs-flow/src/page/route/RouteList.jsx b/zy-acs-flow/src/page/route/RouteList.jsx
index 6175fa1..e8e7b6d 100644
--- a/zy-acs-flow/src/page/route/RouteList.jsx
+++ b/zy-acs-flow/src/page/route/RouteList.jsx
@@ -113,7 +113,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.route"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/segment/SegmentList.jsx b/zy-acs-flow/src/page/segment/SegmentList.jsx
index 43b51fd..0537618 100644
--- a/zy-acs-flow/src/page/segment/SegmentList.jsx
+++ b/zy-acs-flow/src/page/segment/SegmentList.jsx
@@ -108,7 +108,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.segment"}
                 empty={<EmptyData />}
diff --git a/zy-acs-flow/src/page/sta/StaList.jsx b/zy-acs-flow/src/page/sta/StaList.jsx
index 6d91a9a..3991595 100644
--- a/zy-acs-flow/src/page/sta/StaList.jsx
+++ b/zy-acs-flow/src/page/sta/StaList.jsx
@@ -111,7 +111,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.sta"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/staReserve/StaReserveList.jsx b/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
index a4948d6..102d53e 100644
--- a/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
+++ b/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
@@ -128,7 +128,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.staReserve"}
                 empty={<EmptyDataLoader />}
diff --git a/zy-acs-flow/src/page/staSts/StaStsList.jsx b/zy-acs-flow/src/page/staSts/StaStsList.jsx
index 80d676b..e61db0b 100644
--- a/zy-acs-flow/src/page/staSts/StaStsList.jsx
+++ b/zy-acs-flow/src/page/staSts/StaStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.staSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/staType/StaTypeList.jsx b/zy-acs-flow/src/page/staType/StaTypeList.jsx
index 3a2f665..d459e0e 100644
--- a/zy-acs-flow/src/page/staType/StaTypeList.jsx
+++ b/zy-acs-flow/src/page/staType/StaTypeList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.staType"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/task/TaskList.jsx b/zy-acs-flow/src/page/task/TaskList.jsx
index 09e7397..bf8aa94 100644
--- a/zy-acs-flow/src/page/task/TaskList.jsx
+++ b/zy-acs-flow/src/page/task/TaskList.jsx
@@ -371,7 +371,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.task"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/taskSts/TaskStsList.jsx b/zy-acs-flow/src/page/taskSts/TaskStsList.jsx
index ccda9d0..61ea519 100644
--- a/zy-acs-flow/src/page/taskSts/TaskStsList.jsx
+++ b/zy-acs-flow/src/page/taskSts/TaskStsList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.taskSts"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/taskType/TaskTypeList.jsx b/zy-acs-flow/src/page/taskType/TaskTypeList.jsx
index 0aa9053..9bbcfad 100644
--- a/zy-acs-flow/src/page/taskType/TaskTypeList.jsx
+++ b/zy-acs-flow/src/page/taskType/TaskTypeList.jsx
@@ -91,7 +91,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.taskType"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/tenant/TenantList.jsx b/zy-acs-flow/src/page/tenant/TenantList.jsx
index 3470c93..ed914b3 100644
--- a/zy-acs-flow/src/page/tenant/TenantList.jsx
+++ b/zy-acs-flow/src/page/tenant/TenantList.jsx
@@ -86,7 +86,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.tenant"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/travel/TravelList.jsx b/zy-acs-flow/src/page/travel/TravelList.jsx
index 04b27f2..f97986a 100644
--- a/zy-acs-flow/src/page/travel/TravelList.jsx
+++ b/zy-acs-flow/src/page/travel/TravelList.jsx
@@ -120,7 +120,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.travel"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/user/UserList.jsx b/zy-acs-flow/src/page/user/UserList.jsx
index 63f81bd..fab2f71 100644
--- a/zy-acs-flow/src/page/user/UserList.jsx
+++ b/zy-acs-flow/src/page/user/UserList.jsx
@@ -127,7 +127,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.user"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/userLogin/UserLoginList.jsx b/zy-acs-flow/src/page/userLogin/UserLoginList.jsx
index bfa653c..f0621ab 100644
--- a/zy-acs-flow/src/page/userLogin/UserLoginList.jsx
+++ b/zy-acs-flow/src/page/userLogin/UserLoginList.jsx
@@ -100,7 +100,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.userLogin"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx b/zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx
index b40f636..99fde60 100644
--- a/zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx
+++ b/zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx
@@ -104,7 +104,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.vehFaultRec"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
diff --git a/zy-acs-flow/src/page/zone/ZoneList.jsx b/zy-acs-flow/src/page/zone/ZoneList.jsx
index 904ff2f..b5ba9f8 100644
--- a/zy-acs-flow/src/page/zone/ZoneList.jsx
+++ b/zy-acs-flow/src/page/zone/ZoneList.jsx
@@ -93,7 +93,7 @@
                         theme.transitions.create(['all'], {
                             duration: theme.transitions.duration.enteringScreen,
                         }),
-                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.zone"}
                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}

--
Gitblit v1.9.1