#
vincentlu
1 天以前 c01d9b053852b12e7d3ced66367babb4d499b14b
#
4个文件已添加
46个文件已修改
829 ■■■■ 已修改文件
zy-acs-flow/src/i18n/en.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/i18n/zh.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/action/ActionList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/actionSts/ActionStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/actionType/ActionTypeList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/agv/AgvList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/agvDetail/AgvDetailList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/agvModel/AgvModelList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/agvSts/AgvStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/area/AreaList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/bus/BusList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/busSts/BusStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/code/CodeList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/codeGap/CodeGapList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/config/ConfigList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/funcSta/FuncStaList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/CronField.jsx 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/GuaranteeCreate.jsx 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/GuaranteeEdit.jsx 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/GuaranteeList.jsx 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/GuaranteePanel.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/ScopeField.jsx 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/cronUtils.js 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/guarantee/guaranteeConstants.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/host/HostList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/jam/JamList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/lane/LaneList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/loc/LocList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/locSts/LocStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/locType/LocTypeList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/mission/MissionResend.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/mission/MissionShow.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/operationRecord/OperationRecordList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/role/RoleList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/route/RouteList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/segment/SegmentList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/sta/StaList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/staReserve/StaReserveList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/staSts/StaStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/staType/StaTypeList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/task/TaskList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/taskSts/TaskStsList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/taskType/TaskTypeList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/tenant/TenantList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/travel/TravelList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/user/UserList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/userLogin/UserLoginList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/vehFaultRec/VehFaultRecList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/page/zone/ZoneList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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: {
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: {
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
zy-acs-flow/src/page/guarantee/CronField.jsx
New file
@@ -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;
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>
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;
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" />
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}>
zy-acs-flow/src/page/guarantee/ScopeField.jsx
New file
@@ -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;
zy-acs-flow/src/page/guarantee/cronUtils.js
New file
@@ -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}`;
    }
};
zy-acs-flow/src/page/guarantee/guaranteeConstants.js
New file
@@ -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;
};
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) }} />}
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 />}
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) }} />}
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 />}
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) }} />}
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) }} />}
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) }} />}
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) {
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>
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) }} />}
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([]);
                }}
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) }} />}
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 />}
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) }} />}
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 />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}
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) }} />}