| New file |
| | |
| | | import React, { useState, useEffect } from "react"; |
| | | import { useTranslate, useNotify, useRefresh } from 'react-admin'; |
| | | import { |
| | | Dialog, |
| | | DialogActions, |
| | | DialogContent, |
| | | DialogTitle, |
| | | Box, |
| | | Button, |
| | | IconButton, |
| | | Table, |
| | | TableBody, |
| | | TableCell, |
| | | TableContainer, |
| | | TableHead, |
| | | TableRow, |
| | | Paper, |
| | | Grid, |
| | | TextField, |
| | | MenuItem, |
| | | Select, |
| | | FormControl, |
| | | InputLabel, |
| | | } from '@mui/material'; |
| | | import DialogCloseButton from "../../components/DialogCloseButton"; |
| | | import AddIcon from '@mui/icons-material/Add'; |
| | | import DeleteIcon from '@mui/icons-material/Delete'; |
| | | import SaveIcon from '@mui/icons-material/Save'; |
| | | import request from '@/utils/request'; |
| | | |
| | | const defaultPair = () => ({ stationName: '', stationId: '' }); |
| | | |
| | | const BasStationInitModal = ({ open, setOpen }) => { |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | const refresh = useRefresh(); |
| | | |
| | | const [pairs, setPairs] = useState([defaultPair()]); |
| | | const [common, setCommon] = useState({ |
| | | type: 0, |
| | | useStatus: '', |
| | | areaIds: [], |
| | | containerTypes: [], |
| | | inAble: 0, |
| | | outAble: 0, |
| | | }); |
| | | const [loading, setLoading] = useState(false); |
| | | |
| | | const [useStatusOptions, setUseStatusOptions] = useState([]); |
| | | const [areaOptions, setAreaOptions] = useState([]); |
| | | const [containerTypeOptions, setContainerTypeOptions] = useState([]); |
| | | |
| | | useEffect(() => { |
| | | if (!open) return; |
| | | request.post('/dictData/page', { dictTypeCode: 'sys_sta_use_stas', current: 1, pageSize: 100 }) |
| | | .then((res) => { |
| | | if (res?.data?.code === 200 && res?.data?.data?.records) { |
| | | setUseStatusOptions(res.data.data.records.map((item) => ({ |
| | | value: item.value, |
| | | label: item.label ?? item.value, |
| | | }))); |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | }, [open]); |
| | | |
| | | useEffect(() => { |
| | | if (!open) return; |
| | | request.post('/warehouseAreas/list', {}) |
| | | .then((res) => { |
| | | if (res?.data?.code === 200 && res?.data?.data) { |
| | | const list = Array.isArray(res.data.data) ? res.data.data : (res.data.data?.records || []); |
| | | setAreaOptions(list.map((item) => ({ id: item.id, name: item.name ?? item.id }))); |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | }, [open]); |
| | | |
| | | useEffect(() => { |
| | | if (!open) return; |
| | | request.post('/dictData/page', { dictTypeCode: 'sys_container_type', current: 1, pageSize: 100 }) |
| | | .then((res) => { |
| | | if (res?.data?.code === 200 && res?.data?.data?.records) { |
| | | setContainerTypeOptions(res.data.data.records.map((item) => ({ |
| | | id: item.id, |
| | | label: item.label ?? item.value ?? item.id, |
| | | }))); |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | }, [open]); |
| | | |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | setPairs([defaultPair()]); |
| | | } |
| | | }; |
| | | |
| | | const addRow = () => setPairs((prev) => [...prev, defaultPair()]); |
| | | const removeRow = (index) => { |
| | | if (pairs.length <= 1) return; |
| | | setPairs((prev) => prev.filter((_, i) => i !== index)); |
| | | }; |
| | | const changePair = (index, field, value) => { |
| | | setPairs((prev) => prev.map((p, i) => (i === index ? { ...p, [field]: value } : p))); |
| | | }; |
| | | |
| | | const handleSubmit = async () => { |
| | | const toSave = pairs.filter( |
| | | (p) => (p.stationName || '').trim() && (p.stationId || '').trim() |
| | | ); |
| | | if (toSave.length === 0) { |
| | | notify('请至少填写一组站点名称和站点编码', { type: 'error' }); |
| | | return; |
| | | } |
| | | if (!(common.areaIds?.length)) { |
| | | notify('请选择可跨库区', { type: 'error' }); |
| | | return; |
| | | } |
| | | if (!(common.containerTypes?.length)) { |
| | | notify('请选择容器类型', { type: 'error' }); |
| | | return; |
| | | } |
| | | |
| | | setLoading(true); |
| | | let success = 0; |
| | | let fail = 0; |
| | | for (const p of toSave) { |
| | | const body = { |
| | | stationName: (p.stationName || '').trim(), |
| | | stationId: (p.stationId || '').trim(), |
| | | type: common.type, |
| | | useStatus: common.useStatus || undefined, |
| | | areaIds: common.areaIds, |
| | | containerTypes: common.containerTypes, |
| | | inAble: common.inAble, |
| | | outAble: common.outAble, |
| | | }; |
| | | try { |
| | | const res = await request.post('/basStation/save', body); |
| | | if (res?.data?.code === 200) success++; |
| | | else { |
| | | fail++; |
| | | notify(res?.data?.msg || '保存失败', { type: 'error' }); |
| | | } |
| | | } catch (e) { |
| | | fail++; |
| | | notify(e?.message || '保存失败', { type: 'error' }); |
| | | } |
| | | } |
| | | setLoading(false); |
| | | if (success > 0) { |
| | | notify(`成功保存 ${success} 条${fail > 0 ? `,失败 ${fail} 条` : ''}`); |
| | | setOpen(false); |
| | | refresh(); |
| | | } |
| | | }; |
| | | |
| | | return ( |
| | | <Dialog |
| | | open={open} |
| | | onClose={handleClose} |
| | | aria-labelledby="form-dialog-title" |
| | | fullWidth |
| | | disableRestoreFocus |
| | | maxWidth="md" |
| | | > |
| | | <DialogTitle |
| | | id="form-dialog-title" |
| | | sx={{ |
| | | position: 'sticky', |
| | | top: 0, |
| | | backgroundColor: 'background.paper', |
| | | zIndex: 1000, |
| | | }} |
| | | > |
| | | {translate('toolbar.siteInit')} |
| | | <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> |
| | | <DialogCloseButton onClose={handleClose} /> |
| | | </Box> |
| | | </DialogTitle> |
| | | <DialogContent sx={{ mt: 2 }}> |
| | | <Grid container rowSpacing={2} columnSpacing={2}> |
| | | <Grid item xs={12}> |
| | | <TableContainer component={Paper} variant="outlined"> |
| | | <Table size="small"> |
| | | <TableHead> |
| | | <TableRow> |
| | | <TableCell>{translate('table.field.basStation.stationName')}</TableCell> |
| | | <TableCell>{translate('table.field.basStation.stationId')}</TableCell> |
| | | <TableCell width={80}>操作</TableCell> |
| | | </TableRow> |
| | | </TableHead> |
| | | <TableBody> |
| | | {pairs.map((p, index) => ( |
| | | <TableRow key={index}> |
| | | <TableCell> |
| | | <TextField |
| | | size="small" |
| | | fullWidth |
| | | placeholder={translate('table.field.basStation.stationName')} |
| | | value={p.stationName || ''} |
| | | onChange={(e) => changePair(index, 'stationName', e.target.value)} |
| | | /> |
| | | </TableCell> |
| | | <TableCell> |
| | | <TextField |
| | | size="small" |
| | | fullWidth |
| | | placeholder={translate('table.field.basStation.stationId')} |
| | | value={p.stationId || ''} |
| | | onChange={(e) => changePair(index, 'stationId', e.target.value)} |
| | | /> |
| | | </TableCell> |
| | | <TableCell> |
| | | <IconButton |
| | | size="small" |
| | | onClick={() => removeRow(index)} |
| | | disabled={pairs.length <= 1} |
| | | > |
| | | <DeleteIcon fontSize="small" /> |
| | | </IconButton> |
| | | </TableCell> |
| | | </TableRow> |
| | | ))} |
| | | </TableBody> |
| | | </Table> |
| | | </TableContainer> |
| | | <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }}> |
| | | <span>{translate('table.field.basStation.stationName')} / {translate('table.field.basStation.stationId')}(必填)</span> |
| | | <Button size="small" startIcon={<AddIcon />} onClick={addRow}> |
| | | 新增一行 |
| | | </Button> |
| | | </Box> |
| | | |
| | | </Grid> |
| | | |
| | | {/* 以下与新增页顺序、含义完全一致 */} |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.type')}</InputLabel> |
| | | <Select |
| | | label={translate('table.field.basStation.type')} |
| | | value={common.type} |
| | | onChange={(e) => setCommon((c) => ({ ...c, type: e.target.value }))} |
| | | > |
| | | <MenuItem value={0}>智能站点</MenuItem> |
| | | <MenuItem value={1}>普通站点</MenuItem> |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.useStatus')}</InputLabel> |
| | | <Select |
| | | label={translate('table.field.basStation.useStatus')} |
| | | value={common.useStatus ?? ''} |
| | | onChange={(e) => setCommon((c) => ({ ...c, useStatus: e.target.value }))} |
| | | > |
| | | <MenuItem value="">请选择</MenuItem> |
| | | {useStatusOptions.map((opt) => ( |
| | | <MenuItem key={opt.value} value={opt.value}> |
| | | {opt.label} |
| | | </MenuItem> |
| | | ))} |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.crossZoneArea')}</InputLabel> |
| | | <Select |
| | | multiple |
| | | label={translate('table.field.basStation.crossZoneArea')} |
| | | value={common.areaIds ?? []} |
| | | onChange={(e) => setCommon((c) => ({ ...c, areaIds: e.target.value }))} |
| | | renderValue={(selected) => |
| | | (selected || []) |
| | | .map((id) => areaOptions.find((a) => a.id === id)?.name ?? id) |
| | | .join(', ') |
| | | } |
| | | > |
| | | {areaOptions.map((opt) => ( |
| | | <MenuItem key={opt.id} value={opt.id}> |
| | | {opt.name} |
| | | </MenuItem> |
| | | ))} |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.containerType')}</InputLabel> |
| | | <Select |
| | | multiple |
| | | label={translate('table.field.basStation.containerType')} |
| | | value={common.containerTypes ?? []} |
| | | onChange={(e) => setCommon((c) => ({ ...c, containerTypes: e.target.value }))} |
| | | renderValue={(selected) => |
| | | (selected || []) |
| | | .map((id) => containerTypeOptions.find((c) => c.id === id)?.label ?? id) |
| | | .join(', ') |
| | | } |
| | | > |
| | | {containerTypeOptions.map((opt) => ( |
| | | <MenuItem key={opt.id} value={opt.id}> |
| | | {opt.label} |
| | | </MenuItem> |
| | | ))} |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.inAble')}</InputLabel> |
| | | <Select |
| | | label={translate('table.field.basStation.inAble')} |
| | | value={common.inAble} |
| | | onChange={(e) => setCommon((c) => ({ ...c, inAble: e.target.value }))} |
| | | > |
| | | <MenuItem value={0}>否</MenuItem> |
| | | <MenuItem value={1}>是</MenuItem> |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <FormControl fullWidth size="small"> |
| | | <InputLabel>{translate('table.field.basStation.outAble')}</InputLabel> |
| | | <Select |
| | | label={translate('table.field.basStation.outAble')} |
| | | value={common.outAble} |
| | | onChange={(e) => setCommon((c) => ({ ...c, outAble: e.target.value }))} |
| | | > |
| | | <MenuItem value={0}>否</MenuItem> |
| | | <MenuItem value={1}>是</MenuItem> |
| | | </Select> |
| | | </FormControl> |
| | | </Grid> |
| | | </Grid> |
| | | </DialogContent> |
| | | <DialogActions |
| | | sx={{ |
| | | position: 'sticky', |
| | | bottom: 0, |
| | | backgroundColor: 'background.paper', |
| | | zIndex: 1000, |
| | | }} |
| | | > |
| | | <Button |
| | | disabled={loading} |
| | | variant="contained" |
| | | startIcon={<SaveIcon />} |
| | | onClick={handleSubmit} |
| | | > |
| | | {loading ? '保存中...' : translate('ra.action.save')} |
| | | </Button> |
| | | </DialogActions> |
| | | </Dialog> |
| | | ); |
| | | }; |
| | | |
| | | export default BasStationInitModal; |