From 9e84e0199af37546a5fe76befdf004fae84ca921 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期三, 25 二月 2026 13:36:34 +0800
Subject: [PATCH] 站点初始化,批量增加
---
rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx | 18 ++
rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 380 insertions(+), 1 deletions(-)
diff --git a/rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx b/rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx
new file mode 100644
index 0000000..865aa26
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/basStation/BasStationInitModal.jsx
@@ -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;
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx b/rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx
index eb4489a..49be844 100644
--- a/rsf-admin/src/page/basicInfo/basStation/BasStationList.jsx
+++ b/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}
--
Gitblit v1.9.1