chen.lin
1 天以前 9e84e0199af37546a5fe76befdf004fae84ca921
站点初始化,批量增加
1个文件已添加
1个文件已修改
381 ■■■■■ 已修改文件
rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx
New file
@@ -0,0 +1,363 @@
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;
rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx
@@ -35,8 +35,10 @@
} from 'react-admin';
import { Box, Typography, Card, Stack, Button } from '@mui/material';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
import { styled } from '@mui/material/styles';
import BasStationCreate from "./BasStationCreate";
import BasStationInitModal from "./BasStationInitModal";
import BasStationPanel from "./BasStationPanel";
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
@@ -125,6 +127,7 @@
    const [areaFieldDialog, setAreaFieldDialog] = useState(false);
    const [areaFieldDialog2, setAreaFieldDialog2] = useState(false);
    const [copyRecord, setCopyRecord] = useState(null);
    const [initDialogOpen, setInitDialogOpen] = useState(false);
    return (
        <Box display="flex">
            <List
@@ -144,6 +147,16 @@
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <Button
                          variant="text"
                          color="primary"
                          size="small"
                          startIcon={<PlaylistAddIcon />}
                          onClick={() => setInitDialogOpen(true)}
                          sx={{ ml: 1 }}
                        >
                          {translate('toolbar.siteInit')}
                        </Button>
                        <SelectColumnsButton preferenceKey='basStation' />
                        <MyExportButton />
                    </TopToolbar>
@@ -238,7 +251,10 @@
                copyRecord={copyRecord}
                onClose={() => setCopyRecord(null)}
            />
            <BasStationInitModal
              open={initDialogOpen}
              setOpen={setInitDialogOpen}
            />
            <PageDrawer
                title='BasStation Detail'
                drawerVal={drawerVal}