From 48ad97c8a8afa2c9333bd00545dbc54bb4f0870a Mon Sep 17 00:00:00 2001
From: zjj <3272660260@qq.com>
Date: 星期五, 23 五月 2025 09:28:03 +0800
Subject: [PATCH] #盘点出库

---
 rsf-admin/src/page/outWork/checkOutBound/CheckOutBoundList.jsx |  358 +++++++++++++++++++++++++++++++++++++++++++++++++++
 rsf-admin/src/page/outWork/components/StaSelect.jsx            |    0 
 rsf-admin/src/page/outWork/outBound/OutBoundList.jsx           |    4 
 rsf-admin/src/i18n/zh.js                                       |    3 
 rsf-admin/src/page/ResourceContent.js                          |    3 
 rsf-admin/src/page/outWork/checkOutBound/index.jsx             |   18 ++
 rsf-admin/src/page/outWork/components/locItemInfoModal.jsx     |    0 
 7 files changed, 383 insertions(+), 3 deletions(-)

diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index 74875e8..d206f30 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -215,10 +215,11 @@
             outBound: {
                 stockWithdrawal: '鎻愬彇搴撳瓨',
                 withdrawal:'鎻愬彇',
-                outSta: '鍑哄簱绔�',
+                outSta: '鍑哄簱/鎷f枡绔�',
                 outQty: '鍑哄簱鏁伴噺',
                 anfme: '鏁伴噺',
                 createTask: '鐢熸垚浠诲姟',
+                checkSta: '鐩樼偣绔�'
                 
             },
             basContainer: {
diff --git a/rsf-admin/src/page/ResourceContent.js b/rsf-admin/src/page/ResourceContent.js
index 9636298..f324b18 100644
--- a/rsf-admin/src/page/ResourceContent.js
+++ b/rsf-admin/src/page/ResourceContent.js
@@ -50,6 +50,7 @@
 import warehouseStock from './statistics/stockManage';
 import basContainer from './basicInfo/basContainer';
 import outBound from "./outWork/outBound";
+import checkOutBound from "./outWork/checkOutBound";
 
 const ResourceContent = (node) => {
     switch (node.component) {
@@ -145,6 +146,8 @@
             return basContainer;
         case 'outBound':
             return outBound;
+        case 'checkOutBound':
+            return checkOutBound;
         default:
             return {
                 list: ListGuesser,
diff --git a/rsf-admin/src/page/outWork/checkOutBound/CheckOutBoundList.jsx b/rsf-admin/src/page/outWork/checkOutBound/CheckOutBoundList.jsx
new file mode 100644
index 0000000..a290e9c
--- /dev/null
+++ b/rsf-admin/src/page/outWork/checkOutBound/CheckOutBoundList.jsx
@@ -0,0 +1,358 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { useWatch, useFormContext } from "react-hook-form";
+import {
+    CreateBase,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SaveButton,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    Toolbar,
+    required,
+    useDataProvider,
+    useNotify,
+    Form,
+    useCreateController,
+    useListContext,
+    useRefresh,
+    Edit,
+    useRedirect,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    Grid,
+    TextField,
+    Box,
+    Button,
+    Paper,
+    TableContainer,
+    Table,
+    TableHead,
+    TableBody,
+    TableRow,
+    TableCell,
+    Tooltip,
+    IconButton,
+    styled,
+    Select,
+    MenuItem,
+    Typography,
+    Card,
+} from '@mui/material';
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import ConfirmButton from "../../components/ConfirmButton";
+import TreeSelectInput from "@/page/components/TreeSelectInput";
+import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
+import DictSelect from "../../components/DictSelect";
+import AddIcon from '@mui/icons-material/Add';
+import DeleteIcon from '@mui/icons-material/Delete';
+import request from '@/utils/request';
+import LocItemInfoModal from "../components/locItemInfoModal";
+import { Delete } from '@mui/icons-material';
+import _, { set } from 'lodash';
+import StaSelect from "../components/StaSelect";
+import { redirect } from "react-router";
+import { number } from "prop-types";
+
+const CheckOutBoundList = () => {
+
+    const [createDialog, setCreateDialog] = useState(false);
+    const [tabelData, setTableData] = useState([]);
+    const [selectedRows, setSelectedRows] = useState([]);
+    const [sta, setSta] = useState("");
+    const notify = useNotify();
+    const tableRef = useRef();
+    tableRef.current = useGridApiRef();
+    const translate = useTranslate();
+
+    const handleDeleteItem = () => {
+        const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId));
+        setTableData(newTableData);
+    }
+
+    // 娣诲姞涓�涓鐞嗘柊鏁版嵁鐨勫嚱鏁帮紝璁剧疆outQty榛樿鍊�
+    const handleSetData = (newData) => {
+        // 涓烘柊娣诲姞鐨勬暟鎹缃畂utQty榛樿鍊间负anfme鐨勫��
+        const dataWithDefaultQty = newData.map(item => ({
+            ...item,
+            outQty: item.outQty || item.anfme // 濡傛灉outQty宸插瓨鍦ㄥ垯淇濈暀锛屽惁鍒欎娇鐢╝nfme鐨勫��
+        }));
+        setTableData([...tabelData, ...dataWithDefaultQty]);
+    };
+
+
+
+    return (
+        <>
+            <Card sx={{ p: 2, mb: 2, mt: 2 }}>
+                <Grid container spacing={2}>
+                    <Grid item xs={12}>
+                        <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
+                            <Typography variant="h6">
+                                {translate('table.field.outBound.stockWithdrawal')}
+                            </Typography>
+                            <Stack direction='row' spacing={2}>
+                                <Button
+                                    variant="contained"
+                                    color="primary"
+                                    startIcon={<AddIcon />}
+                                    onClick={() => setCreateDialog(true)}
+                                >
+                                    {translate('table.field.outBound.withdrawal')}
+                                </Button>
+                            </Stack>
+                        </Box>
+                    </Grid>
+                </Grid>
+            </Card>
+            <Card sx={{ p: 2, mb: 2 }}>
+                <Form>
+                    <Grid container spacing={2}>
+                        <Grid item xs={12}>
+                            <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
+                                <Typography variant="h6" >
+                                    {translate('table.field.outBound.checkSta')}
+                                </Typography>
+                                <Stack direction='row' spacing={2} minWidth={200}>
+                                    <StaSelect
+                                        source="sta"
+                                        label={translate("table.field.outBound.checkSta")}
+                                        onChange={(e) => {
+                                            setSta(e.target.value);
+                                            console.log("绔欑偣宸查�夋嫨:", e.target.value);
+                                        }}
+                                        size="small"
+                                        type="[107]"
+                                    />
+                                </Stack>
+                                <Stack direction='row' spacing={2} minWidth={200}>
+                                    <SubmitButton
+                                        sta={sta}
+                                        data={tabelData}
+                                        setTableData={setTableData}
+                                    />
+                                </Stack>
+                            </Box>
+                        </Grid>
+                    </Grid>
+                </Form>
+            </Card>
+            <Card sx={{ mb: 2 }}>
+                <Box sx={{}}>
+                    <ModalTable tabelData={tabelData} setTableData={setTableData} selectedRows={selectedRows} setSelectedRows={setSelectedRows} tableRef={tableRef}></ModalTable>
+                </Box>
+            </Card>
+            <LocItemInfoModal
+                open={createDialog}
+                setOpen={setCreateDialog}
+                data={tabelData}
+                setData={handleSetData}
+            />
+
+        </>
+    )
+}
+
+export default CheckOutBoundList;
+
+const SubmitButton = (props) => {
+    const translate = useTranslate();
+    const notify = useNotify();
+    const redirect = useRedirect();
+    const refresh = useRefresh();
+    const { sta, data, setTableData } = props;
+    const check = () => {
+        if (sta === "" || sta === undefined || sta === null) {
+            notify("璇烽�夋嫨绔欑偣");
+            return;
+        }
+        if (data.length === 0) {
+            notify("璇烽�夋嫨鐗╂枡");
+            return;
+        }
+        http(sta, data);
+    }
+    const http = async (sta, items) => {
+        console.log(items);
+
+        const filter = items.filter(item => (item.outQty + item.workQty) > item.anfme);
+        if (filter.length > 0) {
+            notify(translate('toolbar.request.error.out_stock_qty'))
+            return
+        }
+        const { data: { code, data, msg } } = await request.post(`/locItem/generate/task`, { siteNo: sta, items: items });
+        if (code === 200) {
+            notify(msg);
+            refresh()
+            setTableData([])
+            redirect("/task")
+        } else {
+            notify(msg);
+        }
+    }
+    return (
+        <ConfirmButton
+            variant="contained"
+            color="primary"
+            onConfirm={check}
+            label={"table.field.outBound.createTask"}
+        >
+        </ConfirmButton>
+    )
+
+}
+
+const ModalTable = ({ tabelData, setTableData, selectedRows, setSelectedRows, tableRef }) => {
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const [columns, setColumns] = useState([
+        {
+            field: 'outQty',
+            headerName: translate('table.field.outBound.outQty') + "*",
+            width: 100,
+            type: 'number',
+            editable: true,
+            headerClassName: "custom",
+        },
+        {
+            field: 'anfme',
+            headerName: translate('table.field.locItem.anfme'),
+            type: 'number',
+            width: 100,
+            editable: false,
+        },
+        {
+            field: 'workQty',
+            headerName: translate('table.field.locItem.workQty'),
+            width: 100,
+            type: 'number',
+            editable: false,
+        },
+        {
+            field: 'matnrCode',
+            headerName: translate('table.field.locItem.matnrCode'),
+            width: 130,
+            editable: false,
+        },
+        {
+            field: 'maktx',
+            headerName: translate('table.field.locItem.maktx'),
+            width: 250,
+            editable: false,
+        },
+        {
+            field: 'batch',
+            headerName: translate('table.field.locItem.batch'),
+            width: 250,
+            editable: false,
+        },
+    ])
+
+    const action = {
+        field: 'action',
+        headerName: '鎿嶄綔',
+        width: 70,
+        lockPosition: 'left',
+        renderCell: (params) => (
+            <Tooltip title="Delete">
+                <IconButton onClick={() => handleDelete(params.row)}>
+                    <Delete />
+                </IconButton>
+            </Tooltip>
+        ),
+
+    }
+
+    let cdata = useRef([]);
+
+    useEffect(() => {
+        getDynamicFields();
+    }, []);
+
+    useEffect(() => {
+        cdata.current = tabelData
+    }, [tabelData]);
+
+    const getDynamicFields = async () => {
+        const {
+            data: { code, data, msg },
+        } = await request.get("/fields/enable/list");
+        if (code === 200) {
+            const cols = data.map(el => ({
+                field: el.fields,
+                headerName: el.fieldsAlise,
+                minWidth: 100,
+                flex: 1,
+                editable: false
+            }))
+            setColumns([...columns, ...cols, action])
+        } else {
+            notify(msg);
+        }
+    }
+
+
+    const handleDelete = (row) => {
+        const newData = _.filter(cdata.current, (item) => item.id !== row.id);
+        setTableData(newData);
+    };
+
+
+    const processRowUpdate = (newRow, oldRow) => {
+        const rows = tabelData.map((r) =>
+            r.id === newRow.id ? { ...newRow } : r
+        )
+        setTableData(rows)
+        return newRow;
+    };
+
+    const handleSelectionChange = (ids) => {
+        setSelectedRows(ids)
+    };
+
+    tableRef.current = useGridApiRef();
+
+    return (
+        <div style={{ height: 500, width: '100%' }}>
+            <DataGrid
+                apiRef={tableRef}
+                rows={tabelData}
+                columns={columns}
+                disableRowSelectionOnClick
+                getRowId={(row) => row.matnrId ? row.matnrId : row.id}
+                disableColumnFilter
+                disableColumnSelector
+                disableColumnSorting
+                disableMultipleColumnsSorting
+                processRowUpdate={processRowUpdate}
+                initialState={{
+                    pagination: {
+                        paginationModel: {
+                            pageSize: 25,
+                        },
+                    },
+                }}
+                pageSizeOptions={[10, 25, 50, 100]}
+                editMode="row"
+                checkboxSelection
+                onRowSelectionModelChange={handleSelectionChange}
+                selectionModel={selectedRows}
+                sx={{
+                    '& .MuiDataGrid-cell input': {
+                        border: '1px solid #ccc'
+                    },
+                }}
+            />
+        </div>
+    );
+};
diff --git a/rsf-admin/src/page/outWork/checkOutBound/index.jsx b/rsf-admin/src/page/outWork/checkOutBound/index.jsx
new file mode 100644
index 0000000..c99b807
--- /dev/null
+++ b/rsf-admin/src/page/outWork/checkOutBound/index.jsx
@@ -0,0 +1,18 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    ListGuesser,
+    EditGuesser,
+    ShowGuesser,
+} from "react-admin";
+
+import CheckOutBoundList from "./CheckOutBoundList";
+
+
+export default {
+    list: CheckOutBoundList,
+    edit: EditGuesser,
+    show: ShowGuesser,
+    recordRepresentation: (record) => {
+        return `${record.id}`
+    }
+};
diff --git a/rsf-admin/src/page/outWork/outBound/StaSelect.jsx b/rsf-admin/src/page/outWork/components/StaSelect.jsx
similarity index 100%
rename from rsf-admin/src/page/outWork/outBound/StaSelect.jsx
rename to rsf-admin/src/page/outWork/components/StaSelect.jsx
diff --git a/rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx b/rsf-admin/src/page/outWork/components/locItemInfoModal.jsx
similarity index 100%
rename from rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx
rename to rsf-admin/src/page/outWork/components/locItemInfoModal.jsx
diff --git a/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx b/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
index e7bf5b2..9b9a2e3 100644
--- a/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
+++ b/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
@@ -56,10 +56,10 @@
 import AddIcon from '@mui/icons-material/Add';
 import DeleteIcon from '@mui/icons-material/Delete';
 import request from '@/utils/request';
-import LocItemInfoModal from "./locItemInfoModal";
+import LocItemInfoModal from "../components/locItemInfoModal";
 import { Delete } from '@mui/icons-material';
 import _, { set } from 'lodash';
-import StaSelect from "./StaSelect";
+import StaSelect from "../components/StaSelect";
 import { redirect } from "react-router";
 import { number } from "prop-types";
 

--
Gitblit v1.9.1