verou
2025-03-14 6c19e2c3af7e24700c65d47830687a9a1750fb59
feat:选择物料
2个文件已添加
4个文件已修改
668 ■■■■■ 已修改文件
rsf-admin/.env 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrder/AsnOrderList.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrder/AsnOrderModal.jsx 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrder/AsnOrderPanel.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrder/AsnWareModal.jsx 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/vite.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/.env
@@ -1,2 +1,2 @@
VITE_BASE_IP=192.168.4.24
VITE_BASE_IP=47.76.147.249
VITE_BASE_PORT=8080
rsf-admin/src/page/asnOrder/AsnOrderList.jsx
@@ -35,7 +35,7 @@
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import AsnOrderCreate from "./AsnOrderCreate";
import AsnOrderModal from "./AsnOrderModal";
import AsnOrderPanel from "./AsnOrderPanel";
import EmptyData from "../components/EmptyData";
import MyCreateButton from "../components/MyCreateButton";
@@ -46,6 +46,7 @@
import * as Common from '@/utils/common';
import ConstructionIcon from "@mui/icons-material/Construction";
import FileDownloadIcon from '@mui/icons-material/FileDownload';
import EditIcon from '@mui/icons-material/Edit';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
@@ -179,12 +180,20 @@
            <Button label="toolbar.print" onClick={print}>
              <FileDownloadIcon />
            </Button>
            <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
            {/* <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> */}
            <Button
              color="primary"
              startIcon={<EditIcon />}
              onClick={() => { setCreateDialog(true) }}
              sx={{ ml: 1 }}
              label={'ra.action.edit'}
            >
            </Button>
            <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
          </WrapperField>
        </StyledDatagrid>
      </List>
      <AsnOrderCreate
      <AsnOrderModal
        open={createDialog}
        setOpen={setCreateDialog}
      />
@@ -194,7 +203,7 @@
        setDrawerVal={setDrawerVal}
      >
      </PageDrawer>
    </Box>
    </Box >
  )
}
export default AsnOrderList;
rsf-admin/src/page/asnOrder/AsnOrderModal.jsx
New file
@@ -0,0 +1,300 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useRefresh,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    styled
} from '@mui/material';
import DialogCloseButton from "../components/DialogCloseButton";
import StatusSelectInput from "../components/StatusSelectInput";
import ConfirmButton from "../components/ConfirmButton";
import AsnWareModal from "./AsnWareModal";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
const AsnOrderModal = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const [createDialog, setCreateDialog] = useState(false);
    const asnId = ''
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const [formData, setFormData] = useState({
        type: '',
        wkType: ''
    });
    const [tabelData, setTableData] = useState([]);
    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
    };
    const handleSubmit = () => {
        console.log(formData);
    };
    const handleDelete = async () => {
        const res = await request.post(`/asnOrder/remove/${asnId}`, {});
        if (res?.data?.code === 200) {
            setOpen(false);
            refresh();
        } else {
            notify(res.data.msg);
        }
    };
    return (
        <>
            <Dialog
                open={open}
                onClose={handleClose}
                aria-labelledby="form-dialog-title"
                fullWidth
                disableRestoreFocus
                maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
            >
                <DialogTitle id="form-dialog-title" sx={{
                    position: 'sticky',
                    top: 0,
                    backgroundColor: 'background.paper',
                    zIndex: 1000
                }}>
                    {translate('create.title')}
                    <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                        <DialogCloseButton onClose={handleClose} />
                    </Box>
                </DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <TextField
                                    label={translate('table.field.asnOrder.type')}
                                    name="type"
                                    value={formData.type}
                                    onChange={handleChange}
                                    variant="outlined"
                                    size="small"
                                />
                            </Grid>
                            <Grid item xs={4}>
                                <TextField
                                    label={translate('table.field.asnOrder.wkType')}
                                    name="wkType"
                                    value={formData.wkType}
                                    onChange={handleChange}
                                    variant="outlined"
                                    size="small"
                                />
                            </Grid>
                        </Grid>
                    </Box>
                    <Box sx={{ mt: 2 }}>
                        <Stack direction="row" spacing={2}>
                            <Button variant="contained" onClick={() => setCreateDialog(true)}>新增物料</Button>
                            {asnId !== '' && <ConfirmButton label={'删除'} variant="outlined" color="error" onConfirm={handleDelete} />}
                        </Stack>
                    </Box>
                    <Box sx={{ mt: 2 }}>
                        <AsnOrderModalTable tabelData={tabelData} setTableData={setTableData} ></AsnOrderModalTable>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                        <Button onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
                            确认
                        </Button>
                    </Toolbar>
                </DialogActions>
            </Dialog>
            <AsnWareModal
                open={createDialog}
                setOpen={setCreateDialog}
            />
        </>
    )
}
export default AsnOrderModal;
const AsnOrderModalTable = ({ tabelData, setTableData }) => {
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const columns = [
        {
            id: 'matnrId',
            label: 'table.field.asnOrderItem.matnrId',
            minWidth: 100,
        },
        {
            id: 'matnk',
            label: 'table.field.asnOrderItem.matnk',
            minWidth: 100,
        },
        {
            id: 'poDetlId',
            label: 'table.field.asnOrderItem.poDetlId',
            minWidth: 100,
        },
        {
            id: 'poDetlCode',
            label: 'table.field.asnOrderItem.poDetlCode',
            minWidth: 100,
        },
        {
            id: 'anfme',
            label: 'table.field.asnOrderItem.anfme',
            minWidth: 100,
        },
        {
            id: 'stockUnit',
            label: 'table.field.asnOrderItem.stockUnit',
            minWidth: 100,
        },
        {
            id: 'purQty',
            label: 'table.field.asnOrderItem.purQty',
            minWidth: 100,
        },
        {
            id: 'purUnit',
            label: 'table.field.asnOrderItem.purUnit',
            minWidth: 100,
        },
        {
            id: 'splrCode',
            label: 'table.field.asnOrderItem.splrCode',
            minWidth: 100,
        },
        {
            id: 'splrName',
            label: 'table.field.asnOrderItem.splrName',
            minWidth: 100,
        },
        {
            id: 'qrcode',
            label: 'table.field.asnOrderItem.qrcode',
            minWidth: 100,
        },
        {
            id: 'barcode',
            label: 'table.field.asnOrderItem.barcode',
            minWidth: 100,
        },
        {
            id: 'packName',
            label: 'table.field.asnOrderItem.packName',
            minWidth: 100,
        }]
    const StyledTableRow = styled(TableRow)(({ theme }) => ({
        "& .MuiButtonBase-root.": {
            padding: "0px 0px",
        },
    }));
    const StyledTableCell = styled(TableCell)(({ theme }) => ({
        "& .MuiButtonBase-root": {
            padding: "0px 0px",
        },
        overflow: "hidden",
        textOverflow: "ellipsis",
        whiteSpace: "nowrap",
        maxWidth: 600,
    }));
    return (
        <TableContainer component={Paper} >
            <Table size="small" >
                <TableHead>
                    <StyledTableRow key={'head'}>
                        {columns.map((column) => {
                            const value = column.label;
                            return (
                                <StyledTableCell
                                    key={column.id}
                                    align={column.align || "left"}
                                >
                                    {column.format ? column.format(value) : translate(value)}
                                </StyledTableCell>
                            );
                        })}
                    </StyledTableRow>
                </TableHead>
                <TableBody>
                    {tabelData.map((row) => (
                        <StyledTableRow key={row.id || Math.random()}>
                            {columns.map((column) => (
                                <StyledTableCell key={column.id} >
                                    {row[column.id]}
                                </StyledTableCell>
                            ))}
                        </StyledTableRow>
                    ))}
                </TableBody>
            </Table>
        </TableContainer>
    )
}
rsf-admin/src/page/asnOrder/AsnOrderPanel.jsx
@@ -30,11 +30,6 @@
        }
    }
    const StyledTable = styled(TableRow)(({ theme }) => ({
        "& .MuiButtonBase-root.": {
            padding: "0px 0px",
        },
    }));
    const StyledTableRow = styled(TableRow)(({ theme }) => ({
        "& .MuiButtonBase-root.": {
rsf-admin/src/page/asnOrder/AsnWareModal.jsx
New file
@@ -0,0 +1,340 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useRefresh,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Checkbox,
    styled
} from '@mui/material';
import DialogCloseButton from "../components/DialogCloseButton";
import StatusSelectInput from "../components/StatusSelectInput";
import ConfirmButton from "../components/ConfirmButton";
import MemoInput from "../components/MemoInput";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
const AsnWareModal = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const asnId = ''
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const [formData, setFormData] = useState({
        type: '',
        wkType: ''
    });
    const [tabelData, setTableData] = useState([{ id: 1 }, { id: 2 }]);
    const [selectedRows, setSelectedRows] = useState([]);
    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
    };
    const handleSubmit = () => {
        console.log(formData);
    };
    const handleSearch = () => {
    };
    return (
        <Dialog
            open={open}
            onClose={handleClose}
            aria-labelledby="form-dialog-title"
            fullWidth
            disableRestoreFocus
            maxWidth="lg"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
        >
            <DialogTitle id="form-dialog-title" sx={{
                position: 'sticky',
                top: 0,
                backgroundColor: 'background.paper',
                zIndex: 1000
            }}>
                选择物料
                <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                    <DialogCloseButton onClose={handleClose} />
                </Box>
            </DialogTitle>
            <DialogContent sx={{ mt: 2 }}>
                <Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                    <Grid container spacing={2}>
                        <Grid item xs={4}>
                            <TextField
                                label={translate('table.field.asnOrder.type')}
                                name="type"
                                value={formData.type}
                                onChange={handleChange}
                                variant="outlined"
                                size="small"
                            />
                        </Grid>
                        <Grid item xs={4}>
                            <TextField
                                label={translate('table.field.asnOrder.wkType')}
                                name="wkType"
                                value={formData.wkType}
                                onChange={handleChange}
                                variant="outlined"
                                size="small"
                            />
                        </Grid>
                    </Grid>
                </Box>
                <Box sx={{ mt: 2 }}>
                    <Stack direction="row" spacing={2}>
                        <Button variant="contained" onClick={handleSearch}>搜索</Button>
                    </Stack>
                </Box>
                <Box sx={{ mt: 2 }}>
                    <AsnWareModalTable tabelData={tabelData} setTableData={setTableData} selectedRows={selectedRows}
                        setSelectedRows={setSelectedRows}></AsnWareModalTable>
                </Box>
            </DialogContent>
            <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                    <Button onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
                        确认
                    </Button>
                </Toolbar>
            </DialogActions>
        </Dialog>
    )
}
export default AsnWareModal;
const AsnWareModalTable = ({ tabelData, setTableData }) => {
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const [selected, setSelected] = React.useState([]);
    const columns = [
        {
            id: 'id',
            label: 'ID',
            minWidth: 100
        },
        {
            id: 'name',
            label: 'table.field.matnr.name',
            minWidth: 100
        },
        {
            id: 'code',
            label: 'table.field.matnr.code',
            minWidth: 100
        },
        {
            id: 'spec',
            label: 'table.field.matnr.spec',
            minWidth: 100
        },
        {
            id: 'model',
            label: 'table.field.matnr.model',
            minWidth: 100
        },
        {
            id: 'weight',
            label: 'table.field.matnr.weight',
            minWidth: 100
        },
        {
            id: 'color',
            label: 'table.field.matnr.color',
            minWidth: 100
        },
        {
            id: 'size',
            label: 'table.field.matnr.size',
            minWidth: 100
        },
        {
            id: 'describle',
            label: 'table.field.matnr.describle',
            minWidth: 100
        },
        {
            id: 'nromNum',
            label: 'table.field.matnr.nromNum',
            minWidth: 100
        },
        {
            id: 'unit',
            label: 'table.field.matnr.unit',
            minWidth: 100
        },
        {
            id: 'purchaseUnit',
            label: 'table.field.matnr.purUnit',
            minWidth: 100
        },
        {
            id: 'stockUnit',
            label: 'table.field.matnr.stockUnit',
            minWidth: 100
        },
        {
            id: 'stockLeval$',
            label: 'table.field.matnr.stockLevel',
            minWidth: 100,
            sortable: false
        },
    ];
    const StyledTableRow = styled(TableRow)(({ theme }) => ({
        "& .MuiButtonBase-root.": {
            padding: "0px 0px",
        },
    }));
    const StyledTableCell = styled(TableCell)(({ theme }) => ({
        "& .MuiButtonBase-root": {
            padding: "0px 0px",
        },
        overflow: "hidden",
        textOverflow: "ellipsis",
        whiteSpace: "nowrap",
        maxWidth: 600,
    }));
    const handleClick = (event, id) => {
        const selectedIndex = selected.indexOf(id);
        let newSelected = [];
        if (selectedIndex === -1) {
            newSelected = newSelected.concat(selected, id);
        } else if (selectedIndex === 0) {
            newSelected = newSelected.concat(selected.slice(1));
        } else if (selectedIndex === selected.length - 1) {
            newSelected = newSelected.concat(selected.slice(0, -1));
        } else if (selectedIndex > 0) {
            newSelected = newSelected.concat(
                selected.slice(0, selectedIndex),
                selected.slice(selectedIndex + 1),
            );
        }
        setSelected(newSelected);
    };
    // const handleSelectAllClick = (event) => {
    //     if (event.target.checked) {
    //         const newSelected = tabelData.map((n) => n.id);
    //         setSelected(newSelected);
    //         return;
    //     }
    //     setSelected([]);
    // };
    return (
        <TableContainer component={Paper} >
            <Table size="small" >
                <TableHead>
                    <StyledTableRow key={'head'}>
                        <TableCell padding="checkbox">
                            <Checkbox
                                color="primary"
                            />
                        </TableCell>
                        {columns.map((column) => {
                            const value = column.label;
                            return (
                                <StyledTableCell
                                    key={column.id}
                                    align={column.align || "left"}
                                >
                                    {column.format ? column.format(value) : translate(value)}
                                </StyledTableCell>
                            );
                        })}
                    </StyledTableRow>
                </TableHead>
                <TableBody>
                    {tabelData.map((row) => {
                        const isItemSelected = selected.includes(row.id);
                        return (<StyledTableRow key={row.id || Math.random()} aria-checked={isItemSelected} selected={isItemSelected} onClick={(event) => handleClick(event, row.id)}>
                            <TableCell padding="checkbox">
                                <Checkbox
                                    color="primary"
                                    checked={isItemSelected}
                                />
                            </TableCell>
                            {columns.map((column) => (
                                <StyledTableCell key={column.id} >
                                    {row[column.id]}
                                </StyledTableCell>
                            ))}
                        </StyledTableRow>)
                    })}
                </TableBody>
            </Table>
        </TableContainer>
    )
}
rsf-admin/vite.config.js
@@ -20,6 +20,10 @@
        '/rsf-server': {
          target: `http://${env.VITE_BASE_IP}:${env.VITE_BASE_PORT}`,
          changeOrigin: true,
          bypass: (req, res, options) => {
            const proxyUrl = `${options.target}${req.url}`;
            res.setHeader('x-rel-url', proxyUrl);
          }
          // rewrite: (path) => path.replace(/^\/api/, ''),
        },
        '/ws': {