From f695b59337121fb6c93251e73bdfb3fc8e847cc8 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期五, 25 七月 2025 17:07:09 +0800
Subject: [PATCH] 调拔单功能优化

---
 rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java                 |    3 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java        |   32 +
 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java                   |   25 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java        |    6 
 rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java               |    3 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java              |    6 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java                |   31 +
 rsf-admin/src/page/orders/transfer/TransferCreate.jsx                                             |  451 ++++++++++----
 rsf-admin/src/page/orders/transfer/TransferList.jsx                                               |   52 -
 /dev/null                                                                                         |  203 -------
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java |   24 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java     |   91 +++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java                      |   36 
 rsf-admin/src/page/orders/transfer/ManualCreate.jsx                                               |  469 ++++++++++++++++
 rsf-admin/src/i18n/zh.js                                                                          |    1 
 rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx                                         |  300 ++++++++++
 rsf-admin/src/i18n/en.js                                                                          |    1 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java                      |    2 
 18 files changed, 1,351 insertions(+), 385 deletions(-)

diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index bd7b5ab..8551425 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -1270,6 +1270,7 @@
         quality: "quality",
         complete: "complete",
         allComfirm: 'All Comfirm',
+        createTransfer: 'Create Transfer Order',
         verifyComfirm: 'Verify Comfirm',
         close: "close",
         asnCreate: "Create By Order",
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index fdcbf80..4b086a3 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -1282,6 +1282,7 @@
         quality: "璐ㄦ",
         complete: "瀹岀粨",
         close: "鍏抽棴",
+        createTransfer: '鍒涘缓璋冩嫈鍗�',
         asnCreate: "閫氳繃鍗曟嵁鍒涘缓",
         poCreate: "閫氳繃PO鍗曞垱寤�",
         orderPrint: '鎵撳嵃鍗曟嵁',
diff --git a/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx b/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx
new file mode 100644
index 0000000..ef7023d
--- /dev/null
+++ b/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx
@@ -0,0 +1,300 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    Edit,
+    SimpleForm,
+    FormDataConsumer,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    SaveButton,
+    Toolbar,
+    Labeled,
+    NumberField,
+    useNotify,
+    useRefresh,
+    required,
+    useRecordContext,
+    DeleteButton,
+} from 'react-admin';
+import { Stack, Grid, Box, Typography, Dialog, DialogTitle, DialogContent, TextField, Button, DialogActions } from '@mui/material';
+import DialogCloseButton from "../../components/DialogCloseButton.jsx";
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import StatusSelectInput from "../../components/StatusSelectInput";
+import CustomerTopToolBar from "../../components/EditTopToolBar";
+import TreeSelectInput from "@/page/components/TreeSelectInput";
+import EditBaseAside from "../../components/EditBaseAside";
+import MemoInput from "../../components/MemoInput";
+import SaveIcon from '@mui/icons-material/Save';
+import { DataGrid } from '@mui/x-data-grid';
+import * as Common from '@/utils/common';
+import request from '@/utils/request';
+
+
+const CreateBySelectMats = (props) => {
+    const { open, setOpen, data, setData } = props;
+
+    const [page, setPage] = useState(0);
+    const [rowCount, setRowCount] = useState(0);
+    const [formData, setFormData] = useState({});
+    const [tableData, setTableData] = useState([]);
+    const [dyFields, setDyFields] = useState([]);
+    const [pageSize, setPageSize] = useState(25);
+    const [selectedRows, setSelectedRows] = useState([]);
+
+    const translate = useTranslate();
+    const notify = useNotify();
+    const refresh = useRefresh();
+
+
+
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+
+    const handleChange = (e) => {
+        const { name, value } = e.target;
+        setFormData(() => ({
+            [name]: value
+        }));
+    };
+
+    const reset = () => {
+        setFormData({
+            name: '',
+            code: '',
+            groupId: 0
+        })
+    }
+
+    const handleSubmit = () => {
+        const hasarr = data.map(el => +el.matnrId)
+        const selectedData = selectedRows.filter(item => !hasarr.includes(item)).map(id => (tableData.find(row => row.id === id)));
+        const value = selectedData.map((el => {
+            const dynamicFields = dyFields.reduce((acc, item) => {
+                acc[item.fields] = el['extendFields']?.[item.fields] || '';
+                return acc;
+            }, {});
+            return {
+                matnrId: el.id,
+                maktx: el.name,
+                matnrCode: el.code,
+                stockUnit: el.stockUnit || '',
+                purUnit: el.purchaseUnit || '',
+                ...dynamicFields
+            }
+        }))
+        setData([...data, ...value]);
+        setOpen(false);
+        reset();
+    };
+
+    const getData = async () => {
+        const res = await request.post(`/matnr/page`, {
+            ...formData,
+            current: page,
+            pageSize: pageSize,
+            orderBy: "create_time desc"
+        });
+        if (res?.data?.code === 200) {
+            const {data} = res.data;
+            setTableData(data?.records);
+            setRowCount(data?.total)
+
+            console.log(rowCount);
+            console.log(data);
+            
+            
+        } else {
+            notify(res.data.msg);
+        }
+    };
+
+    useEffect(() => {
+        getData();
+    }, [open]);
+
+    const handleSearch = () => {
+        getData()
+    };
+
+    return (
+        <Dialog
+            open={open}
+            onClose={handleClose}
+            aria-labelledby="form-dialog-title"
+            fullWidth
+            disableRestoreFocus
+            maxWidth="lg"
+        >
+            <DialogTitle id="form-dialog-title" sx={{
+                position: 'sticky',
+                top: 0,
+                backgroundColor: 'background.paper',
+                zIndex: 1000
+            }}>
+                {translate("common.action.newAddMats")}
+                <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 md={3}>
+                            <TextField
+                                label={translate('table.field.matnr.name')}
+                                name="name"
+                                value={formData.name}
+                                onChange={handleChange}
+                                size="small"
+                            />
+                        </Grid>
+                        <Grid item md={3}>
+                            <TextField
+                                label={translate('table.field.matnr.code')}
+                                name="code"
+                                value={formData.code}
+                                onChange={handleChange}
+                                size="small"
+                            />
+                        </Grid>
+                        <Grid item md={3}>
+                            <TreeSelectInput
+                                label="table.field.matnr.groupId"
+                                value={formData.groupId}
+                                resource={'matnrGroup'}
+                                source="groupId"
+                                name="groupId"
+                                onChange={handleChange}
+                            />
+                        </Grid>
+                        <Grid item md={2} sx={{ margin: 'auto' }}>
+                            <Button variant="contained" onClick={handleSearch}>{translate('toolbar.query')}</Button>
+                        </Grid>
+                    </Grid>
+                </Box>
+
+                <Box sx={{ mt: 2, height: 400, width: '100%' }}>
+                    <SelectMatsTableView
+                        tableData={tableData}
+                        setTableData={setTableData}
+                        page={page}
+                        rowCount={rowCount}
+                        pageSize={pageSize}
+                        setPage={setPage}
+                        setPageSize={setPageSize}
+                        dyFields={dyFields}
+                        setDyFields={setDyFields}
+                        selectedRows={selectedRows}
+                        setSelectedRows={setSelectedRows}
+                    />
+                </Box>
+            </DialogContent>
+            <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                <Box sx={{ width: '100%', display: 'flex', justifyContent: 'flex-end' }}>
+                    <Button onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
+                        {translate('toolbar.confirm')}
+                    </Button>
+                </Box>
+            </DialogActions>
+        </Dialog>
+    );
+}
+
+export default CreateBySelectMats;
+
+
+const SelectMatsTableView = ({ tableData, page, pageSize,setPage, setPageSize, rowCount, setTableData, selectedRows, setSelectedRows, dyFields, setDyFields }) => {
+    const translate = useTranslate();
+
+    const notify = useNotify();
+    const [extendColumns, setExtendColumns] = useState([]);
+
+    const [columns, setColumns] = useState([
+        { field: 'name', headerName: translate('table.field.matnr.name'), width: 300 },
+        { field: 'code', headerName: translate('table.field.matnr.code'), width: 200 },
+        { field: 'groupId$', headerName: translate('table.field.matnr.groupId'), width: 100 },
+        { field: 'spec', headerName: translate('table.field.matnr.spec'), width: 100 },
+        { field: 'model', headerName: translate('table.field.matnr.model'), width: 100 },
+        { field: 'weight', headerName: translate('table.field.matnr.weight'), width: 100 },
+        { field: 'describle', headerName: translate('table.field.matnr.describle'), width: 100 },
+        { field: 'nromNum', headerName: translate('table.field.matnr.nromNum'), width: 100 },
+        { field: 'unit', headerName: translate('table.field.matnr.unit'), width: 100 },
+        { field: 'purchaseUnit', headerName: translate('table.field.matnr.purUnit'), width: 100 },
+        { field: 'stockUnit', headerName: translate('table.field.matnr.stockUnit'), width: 100 },
+        { field: 'stockLeval$', headerName: translate('table.field.matnr.stockLevel'), width: 100, sortable: false },
+    ])
+
+    const handleSelectionChange = (ids) => {
+        setSelectedRows(ids)
+    };
+
+    useEffect(() => {
+        if (extendColumns == undefined || extendColumns.length < 1) {
+            getDynamicFields();
+        }
+    }, []);
+
+    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: el.unique,
+                valueGetter: (value, row) => {
+                    return row.extendFields?.[el.fields] || '';
+                },
+            }))
+            setExtendColumns(cols);
+            setDyFields(data)
+            setColumns([...columns, ...cols])
+        } else {
+            notify(msg);
+        }
+    }
+
+    return (
+        <div style={{ height: 400, width: '100%' }}>
+            <DataGrid
+                size="small"
+                rows={tableData}
+                page={page}
+                pageSize={pageSize}
+                columns={columns}
+                pagination
+                checkboxSelection
+                rowCount={rowCount}
+                onRowSelectionModelChange={handleSelectionChange}
+                onPageChange={(newPage) => setPage(newPage)}
+                onPageSizeChange={(newPageSize) => setPageSize(newPageSize)}
+                selectionModel={selectedRows}
+                paginationMode="server"
+                disableColumnMenu={true}
+                initialState={{
+                    pagination: {
+                        paginationModel: {
+                            pageSize: 25,
+                        },
+                    },
+                }}
+                pageSizeOptions={[15, 25, 50, 100]}
+                disableColumnSorting
+                disableMultipleColumnsSorting
+            />
+        </div>
+    );
+};
diff --git a/rsf-admin/src/page/orders/transfer/ManualCreate.jsx b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx
new file mode 100644
index 0000000..5251ed0
--- /dev/null
+++ b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx
@@ -0,0 +1,469 @@
+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,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    TextField,
+    IconButton,
+    MenuItem,
+    Tooltip,
+    Select,
+    Button,
+    Stack,
+    Grid,
+    Box,
+} from '@mui/material';
+import DialogCloseButton from "../../components/DialogCloseButton.jsx";
+import ConfirmationNumberIcon from '@mui/icons-material/ConfirmationNumber';
+import CreateBySelectMats from "./CreateBySelectMats.jsx";
+import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
+import { Add, Edit, Delete } from '@mui/icons-material';
+import ConfirmButton from "../../components/ConfirmButton";
+import DictSelect from "../../components/DictSelect";
+import { minHeight, padding } from "@mui/system";
+import SaveIcon from '@mui/icons-material/Save';
+import request from '@/utils/request';
+
+const ManualCreate = (props) => {
+    const { open, setOpen, orderId } = props;
+    const tableRef = useRef();
+    const notify = useNotify();
+    const translate = useTranslate();
+    const [tabelData, setTableData] = useState([]);
+    const [disabled, setDisabled] = useState(false);
+    const [selectedRows, setSelectedRows] = useState([]);
+    const [createDialog, setCreateDialog] = useState(false);
+    const [formData, setFormData] = useState({});
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+    const handleSubmit = async () => {
+        setFinally()
+        setDisabled(true)
+
+        if (asnId === 0) {
+            const parmas = {
+                "orders": formData,
+                "items": tabelData,
+            }
+            const res = await request.post(`/outStock/items/save`, parmas);
+            if (res?.data?.code === 200) {
+                setOpen(false);
+                refresh();
+                resetData()
+            } else {
+                notify(res.data.msg);
+            }
+        } else {
+            const parmas = {
+                "orders": formData,
+                "items": tabelData,
+            }
+            const res = await request.post(`/outStock/items/update`, parmas);
+            if (res?.data?.code === 200) {
+                setOpen(false);
+                refresh();
+                resetData()
+            } else {
+                notify(res.data.msg);
+            }
+        }
+        setDisabled(false)
+
+    };
+
+    const handleSuccess = async (data) => {
+        setOpen(false);
+        notify('common.response.success');
+    };
+
+    const handleDeleteItem = () => {
+        const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId));
+        setTableData(newTableData);
+    }
+
+    const handleError = async (error) => {
+        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
+    };
+
+    return (
+        <>
+            <Box sx={{ padding: 1 }}>
+                <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
+                    <Form defaultValues={formData}>
+                        <Grid container spacing={2}>
+                            <Grid item md={2}>
+                                <DictSelect
+                                    label={translate("table.field.transfer.type")}
+                                    value={formData.wkType}
+                                    variant="filled"
+                                    group='2'
+                                    onChange={(e) => handleChange(e.target.value, 'wkType')}
+                                    dictTypeCode="sys_business_type"
+                                    required
+                                />
+                            </Grid>
+                            <Grid item md={2}>
+                                <ReferenceInput reference="warehouseAreas" source="name">
+                                    <AutocompleteInput optionText="name" label="table.field.transfer.orgAreaName" />
+                                </ReferenceInput>
+                            </Grid>
+                            <Grid item md={2}>
+                                <ReferenceInput reference="warehouseAreas" source="name">
+                                    <AutocompleteInput optionText="name" label="table.field.transfer.orgAreaName" />
+                                </ReferenceInput>
+                            </Grid>
+                        </Grid>
+                    </Form>
+                </Box>
+                <Box sx={{ mt: 2 }}>
+                    <Stack direction="row" spacing={2} sx={{ justifyContent: "flex-end" }}>
+                        <Button variant="contained" onClick={() => setCreateDialog(true)} >
+                            {translate('common.action.newAddMats')}
+                        </Button>
+                        <ConfirmButton label={"toolbar.delete"} variant="outlined" color="error" onConfirm={handleDeleteItem} />
+                    </Stack>
+                </Box>
+                <Box sx={{ mt: 2 }}>
+                    <TransferTableView
+                        tabelData={tabelData}
+                        setTableData={setTableData}
+                        asnId={orderId}
+                        selectedRows={selectedRows}
+                        setSelectedRows={setSelectedRows}
+                        tableRef={tableRef}>
+                    </TransferTableView>
+                </Box>
+                <Toolbar sx={{ width: '100%', justifyContent: 'flex-end', bgcolor: 'white' }}  >
+                    <Button disabled={disabled} onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
+                        {translate('toolbar.confirm')}
+                    </Button>
+                </Toolbar>
+                <CreateBySelectMats
+                    open={createDialog}
+                    setOpen={setCreateDialog}
+                    data={tabelData}
+                    setData={setTableData}
+                />
+            </Box>
+        </>
+    )
+}
+
+const SelectInputSplrNameEditCell = (params) => {
+    const [formData, setFormData] = useState([{}])
+    useEffect(() => {
+        getOptions();
+    }, []);
+    const getOptions = async () => {
+        const parmas = {
+            "type": "supplier"
+        }
+        const {
+            data: { code, data, msg },
+        } = await request.post("companys/page", parmas);
+        if (code === 200) {
+            setFormData(data.records)
+        } else {
+            notify(msg);
+        }
+    }
+
+    return (
+        <Select
+            value={params.value}
+            onChange={(e) => {
+                params.api.setEditCellValue({
+                    id: params.id,
+                    field: params.field,
+                    value: e.target.value,
+                })
+                // 鎵惧埌閫変腑鐨勪緵搴斿晢璁板綍
+                const selectedSupplier = formData.find(supplier => supplier.name === e.target.value);
+
+                // 濡傛灉鎵惧埌瀵瑰簲鐨勪緵搴斿晢璁板綍锛屽悓鏃舵洿鏂皊plrCode瀛楁
+                if (selectedSupplier) {
+                    params.api.setEditCellValue({
+                        id: params.id,
+                        field: 'splrCode',
+                        value: selectedSupplier.id,
+                    });
+                }
+            }}
+            fullWidth
+        >
+            {formData.map(e => {
+                return (
+                    <MenuItem value={e.name} children={e.name} key={e.id} />
+                );
+
+            })}
+
+        </Select>
+    );
+};
+
+const SelectInputSplrCodeEditCell = (params) => {
+    const [formData, setFormData] = useState([{}])
+    useEffect(() => {
+        getOptions();
+    }, []);
+    const getOptions = async () => {
+        const parmas = {
+            "type": "supplier"
+        }
+        const {
+            data: { code, data, msg },
+        } = await request.post("companys/page", parmas);
+        if (code === 200) {
+            setFormData(data.records)
+        } else {
+            notify(msg);
+        }
+    }
+
+    return (
+        <Select
+            value={params.value}
+            onChange={(e) => {
+                params.api.setEditCellValue({
+                    id: params.id,
+                    field: params.field,
+                    value: e.target.value,
+                })
+                const selectedSupplier = formData.find(supplier => supplier.id === e.target.value);
+
+                // 濡傛灉鎵惧埌瀵瑰簲鐨勪緵搴斿晢璁板綍锛屽悓鏃舵洿鏂皊plrCode瀛楁
+                if (selectedSupplier) {
+                    params.api.setEditCellValue({
+                        id: params.id,
+                        field: 'splrName',
+                        value: selectedSupplier.name,
+                    });
+                }
+            }}
+            fullWidth
+
+        >
+            {formData.map(e => {
+                return (
+                    <MenuItem value={e.id} children={e.name} key={e.id} />
+                );
+
+            })}
+
+        </Select>
+    );
+};
+
+
+
+const TransferTableView = ({ tabelData, setTableData, orderId, selectedRows, setSelectedRows, tableRef }) => {
+    const translate = useTranslate();
+    const notify = useNotify();
+    const [extendColumns, setExtendColumns] = useState([]);
+    const [columns, setColumns] = useState([
+        {
+            field: 'maktx',
+            headerName: translate('table.field.outStockItem.maktx'),
+            width: 250,
+            editable: false,
+        },
+        {
+            field: 'matnrCode',
+            headerName: translate('table.field.outStockItem.matnrCode'),
+            width: 130,
+            editable: false,
+        },
+        {
+            field: 'anfme',
+            headerName: translate('table.field.outStockItem.anfme') + "*",
+            type: 'number',
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            valueFormatter: (val) => val < 0 ? 0 : val,
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrCode',
+            headerName: translate('table.field.outStockItem.splrCode') + "*",
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            renderEditCell: (params) => (
+                <SelectInputSplrCodeEditCell {...params} />
+            ),
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrName',
+            headerName: translate('table.field.outStockItem.splrName') + "*",
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            renderEditCell: (params) => (
+                <SelectInputSplrNameEditCell {...params} />
+            ),
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrBatch',
+            headerName: translate('table.field.outStockItem.splrBatch'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+        {
+            field: 'poCode',
+            headerName: translate('table.field.outStockItem.poDetlCode'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+        {
+            field: 'stockUnit',
+            headerName: translate('table.field.outStockItem.stockUnit'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+    ])
+
+    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(() => {
+        if (extendColumns == undefined || extendColumns.length < 1) {
+            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])
+            setExtendColumns(cols);
+        } else {
+            notify(msg);
+        }
+    }
+
+
+    const handleDelete = (row) => {
+        const newData = _.filter(cdata.current, (item) => item.matnrId !== row.matnrId);
+        setTableData(newData);
+    };
+
+
+    const processRowUpdate = (newRow, oldRow) => {
+        const rows = tabelData.map((r) =>
+            r.matnrId === newRow.matnrId ? { ...newRow } : r
+        )
+        setTableData(rows)
+        return newRow;
+    };
+
+    const handleSelectionChange = (ids) => {
+        setSelectedRows(ids)
+    };
+
+    tableRef.current = useGridApiRef();
+
+    return (
+        <Box>
+            <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={[15, 25, 50, 100]}
+                editMode="row"
+                checkboxSelection
+                onRowSelectionModelChange={handleSelectionChange}
+                selectionModel={selectedRows}
+                sx={{
+                    height: 610,
+                    '& .MuiDataGrid-cell input': {
+                        border: '1px solid #ccc'
+                    },
+                }}
+            />
+            {/* <Box sx={{
+                padding: 2,
+                position: 'absolute',
+                right: 1
+            }}>
+                <Button variant="contained" onClick={() => handleSubmit()} startIcon={<SaveIcon/>} >
+                    {translate('toolbar.confirm')}
+                </Button>
+            </Box> */}
+        </Box>
+    );
+};
+
+
+export default ManualCreate;
diff --git a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
index 19a4edf..a6a754e 100644
--- a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
+++ b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
@@ -23,19 +23,30 @@
     DialogActions,
     DialogContent,
     DialogTitle,
+    TextField,
+    Button,
     Stack,
     Grid,
     Box,
 } from '@mui/material';
 import DialogCloseButton from "../../components/DialogCloseButton.jsx";
-import StatusSelectInput from "../../components/StatusSelectInput.jsx";
-import MemoInput from "../../components/MemoInput.jsx";
+import CreateBySelectMats from "./CreateBySelectMats.jsx";
+import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
+import ConfirmButton from "../../components/ConfirmButton";
+import DictSelect from "../../components/DictSelect";
+import SaveIcon from '@mui/icons-material/Save';
+import request from '@/utils/request';
 
 const TransferCreate = (props) => {
-    const { open, setOpen } = props;
-
-    const translate = useTranslate();
+    const { open, setOpen, orderId } = props;
+    const tableRef = useRef();
     const notify = useNotify();
+    const translate = useTranslate();
+    const [tabelData, setTableData] = useState([]);
+    const [disabled, setDisabled] = useState(false)
+    const [selectedRows, setSelectedRows] = useState([]);
+    const [createDialog, setCreateDialog] = useState(false);
+    const [formData, setFormData] = useState({});
 
     const handleClose = (event, reason) => {
         if (reason !== "backdropClick") {
@@ -43,10 +54,50 @@
         }
     };
 
+    const handleSubmit = async () => {
+        setFinally()
+        setDisabled(true)
+
+        if (asnId === 0) {
+            const parmas = {
+                "orders": formData,
+                "items": tabelData,
+            }
+            const res = await request.post(`/outStock/items/save`, parmas);
+            if (res?.data?.code === 200) {
+                setOpen(false);
+                refresh();
+                resetData()
+            } else {
+                notify(res.data.msg);
+            }
+        } else {
+            const parmas = {
+                "orders": formData,
+                "items": tabelData,
+            }
+            const res = await request.post(`/outStock/items/update`, parmas);
+            if (res?.data?.code === 200) {
+                setOpen(false);
+                refresh();
+                resetData()
+            } else {
+                notify(res.data.msg);
+            }
+        }
+        setDisabled(false)
+
+    };
+
     const handleSuccess = async (data) => {
         setOpen(false);
         notify('common.response.success');
     };
+
+    const handleDeleteItem = () => {
+        const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId));
+        setTableData(newTableData);
+    }
 
     const handleError = async (error) => {
         notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
@@ -54,146 +105,280 @@
 
     return (
         <>
-            <CreateBase
-                record={{}}
-                transform={(data) => {
-                    return data;
-                }}
-                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+            <Dialog
+                open={open}
+                onClose={handleClose}
+                aria-labelledby="form-dialog-title"
+                aria-hidden
+                fullWidth
+                disableRestoreFocus
+                maxWidth="xl"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
             >
-                <Dialog
-                    open={open}
-                    onClose={handleClose}
-                    aria-labelledby="form-dialog-title"
-                    fullWidth
-                    disableRestoreFocus
-                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
-                >
-                    <Form>
-                        <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 }}>
-                            <Grid container rowSpacing={2} columnSpacing={2}>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.transfer.code"
-                                        source="code"
-                                        parse={v => v}
-                                        autoFocus
+                <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 sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
+                        <Form defaultValues={formData}>
+                            <Grid container spacing={2}>
+                                <Grid item md={2}>
+                                    <DictSelect
+                                        label={translate("table.field.outStock.wkType")}
+                                        value={formData.wkType}
+                                        variant="filled"
+                                        group='2'
+                                        onChange={(e) => handleChange(e.target.value, 'wkType')}
+                                        dictTypeCode="sys_business_type"
+                                        required
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
-                                        label="table.field.transfer.type"
-                                        source="type"
+                                <Grid item md={2}>
+                                    <TextField
+                                        label={translate("table.field.outStock.poCode")}
+                                        value={formData.poCode}
+                                        variant="filled"
+                                        size='small'
+                                        onChange={(e) => handleChange(e.target.value, 'poCode')}
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <SelectInput
-                                        label="table.field.transfer.source"
-                                        source="source"
-                                        choices={[
-                                            { id: 1, name: 'ERP绯荤粺' },
-                                            { id:  2, name: 'WMS绯荤粺鐢熸垚' },
-                                            { id:  3, name: 'EXCEL瀵煎叆 ' },
-                                            { id:  4, name: 'QMS绯荤粺' },
-                                        ]}
+                                <Grid item md={2}>
+                                    <TextField
+                                        label={translate("table.field.outStock.logisNo")}
+                                        value={formData.logisNo}
+                                        variant="filled"
+                                        size='small'
+                                        onChange={(e) => handleChange(e.target.value, 'logisNo')}
                                     />
                                 </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <SelectInput
-                                        label="table.field.transfer.exceStatus"
-                                        source="exceStatus"
-                                        choices={[
-                                            { id: 0, name: '鏈墽琛�' },
-                                            { id:  1, name: '鎵ц涓�' },
-                                            { id:  2, name: '鎵ц瀹屾垚' },
-                                        ]}
+                                <Grid item md={2}>
+                                    <DateInput
+                                        source="arrTime"
+                                        label="table.field.outStock.arrTime"
+                                        size='small'
+                                        variant="filled"
+                                        value={formData.arrTime}
+                                        onChange={(e) => handleChange(e.target.value, 'arrTime')}
                                     />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
-                                        label="table.field.transfer.orgWareId"
-                                        source="orgWareId"
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.transfer.orgWareName"
-                                        source="orgWareName"
-                                        parse={v => v}
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
-                                        label="table.field.transfer.tarWareId"
-                                        source="tarWareId"
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.transfer.tarWareName"
-                                        source="tarWareName"
-                                        parse={v => v}
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
-                                        label="table.field.transfer.orgAreaId"
-                                        source="orgAreaId"
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.transfer.orgAreaName"
-                                        source="orgAreaName"
-                                        parse={v => v}
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
-                                        label="table.field.transfer.tarAreaId"
-                                        source="tarAreaId"
-                                    />
-                                </Grid>
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <TextInput
-                                        label="table.field.transfer.tarAreaName"
-                                        source="tarAreaName"
-                                        parse={v => v}
-                                    />
-                                </Grid>
-
-                                <Grid item xs={6} display="flex" gap={1}>
-                                    <StatusSelectInput />
-                                </Grid>
-                                <Grid item xs={12} display="flex" gap={1}>
-                                    <Stack direction="column" spacing={1} width={'100%'}>
-                                        <MemoInput />
-                                    </Stack>
                                 </Grid>
                             </Grid>
-                        </DialogContent>
-                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
-                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
-                                <SaveButton />
-                            </Toolbar>
-                        </DialogActions>
-                    </Form>
-                </Dialog>
-            </CreateBase>
+                        </Form>
+                    </Box>
+
+                    <Box sx={{ mt: 2 }}>
+                        <Stack direction="row" spacing={2}>
+                            <Button variant="contained" onClick={() => setCreateDialog(true)} >
+                                {translate('common.action.newAddMats')}
+                            </Button>
+                            <ConfirmButton label={"toolbar.delete"} variant="outlined" color="error" onConfirm={handleDeleteItem} />
+                        </Stack>
+                    </Box>
+                    <Box sx={{ mt: 2 }}>
+                        <TransferTableView
+                            tabelData={tabelData}
+                            setTableData={setTableData}
+                            asnId={orderId}
+                            selectedRows={selectedRows}
+                            setSelectedRows={setSelectedRows}
+                            tableRef={tableRef}>
+                        </TransferTableView>
+                    </Box>
+                </DialogContent>
+                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                    <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
+                        <Button disabled={disabled} onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
+                            {translate('toolbar.confirm')}
+                        </Button>
+                    </Toolbar>
+                </DialogActions>
+            </Dialog>
+            <CreateBySelectMats
+                open={createDialog}
+                setOpen={setCreateDialog}
+                data={tabelData}
+                setData={setTableData}
+            />
         </>
     )
 }
 
+const TransferTableView = ({ tabelData, setTableData, orderId, selectedRows, setSelectedRows, tableRef }) => {
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const [columns, setColumns] = useState([
+        {
+            field: 'maktx',
+            headerName: translate('table.field.outStockItem.maktx'),
+            width: 250,
+            editable: false,
+        },
+        {
+            field: 'matnrCode',
+            headerName: translate('table.field.outStockItem.matnrCode'),
+            width: 130,
+            editable: false,
+        },
+        {
+            field: 'anfme',
+            headerName: translate('table.field.outStockItem.anfme') + "*",
+            type: 'number',
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            valueFormatter: (val) => val < 0 ? 0 : val,
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrCode',
+            headerName: translate('table.field.outStockItem.splrCode') + "*",
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            renderEditCell: (params) => (
+                <SelectInputSplrCodeEditCell {...params} />
+            ),
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrName',
+            headerName: translate('table.field.outStockItem.splrName') + "*",
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+            renderEditCell: (params) => (
+                <SelectInputSplrNameEditCell {...params} />
+            ),
+            headerClassName: "custom",
+        },
+        {
+            field: 'splrBatch',
+            headerName: translate('table.field.outStockItem.splrBatch'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+        {
+            field: 'poCode',
+            headerName: translate('table.field.outStockItem.poDetlCode'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+        {
+            field: 'stockUnit',
+            headerName: translate('table.field.outStockItem.stockUnit'),
+            minWidth: 100,
+            flex: 1,
+            editable: true,
+        },
+    ])
+
+    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.matnrId !== row.matnrId);
+        setTableData(newData);
+    };
+
+
+    const processRowUpdate = (newRow, oldRow) => {
+        const rows = tabelData.map((r) =>
+            r.matnrId === newRow.matnrId ? { ...newRow } : r
+        )
+        setTableData(rows)
+        return newRow;
+    };
+
+    const handleSelectionChange = (ids) => {
+        setSelectedRows(ids)
+    };
+
+    tableRef.current = useGridApiRef();
+
+    return (
+        <div style={{ height: 400, 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={[15, 25, 50, 100]}
+                editMode="row"
+                checkboxSelection
+                onRowSelectionModelChange={handleSelectionChange}
+                selectionModel={selectedRows}
+                sx={{
+                    '& .MuiDataGrid-cell input': {
+                        border: '1px solid #ccc'
+                    },
+                }}
+            />
+        </div>
+    );
+};
+
 export default TransferCreate;
diff --git a/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx b/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx
deleted file mode 100644
index 3bde7c2..0000000
--- a/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx
+++ /dev/null
@@ -1,203 +0,0 @@
-import React, { useState, useRef, useEffect, useMemo } from "react";
-import {
-    Edit,
-    SimpleForm,
-    FormDataConsumer,
-    useTranslate,
-    TextInput,
-    NumberInput,
-    BooleanInput,
-    DateInput,
-    SelectInput,
-    ReferenceInput,
-    ReferenceArrayInput,
-    AutocompleteInput,
-    SaveButton,
-    Toolbar,
-    Labeled,
-    NumberField,
-    required,
-    useRecordContext,
-    DeleteButton,
-} from 'react-admin';
-import { useWatch, useFormContext } from "react-hook-form";
-import { Stack, Grid, Box, Typography } from '@mui/material';
-import * as Common from '@/utils/common';
-import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
-import EditBaseAside from "../../components/EditBaseAside";
-import CustomerTopToolBar from "../../components/EditTopToolBar";
-import MemoInput from "../../components/MemoInput";
-import StatusSelectInput from "../../components/StatusSelectInput";
-
-const FormToolbar = () => {
-    const { getValues } = useFormContext();
-
-    return (
-        <Toolbar sx={{ justifyContent: 'space-between' }}>
-            <SaveButton />
-            <DeleteButton mutationMode="optimistic" />
-        </Toolbar>
-    )
-}
-
-const TransferItemEdit = () => {
-    const translate = useTranslate();
-
-    return (
-        <Edit
-            redirect="list"
-            mutationMode={EDIT_MODE}
-            actions={<CustomerTopToolBar />}
-            aside={<EditBaseAside />}
-        >
-            <SimpleForm
-                shouldUnregister
-                warnWhenUnsavedChanges
-                toolbar={<FormToolbar />}
-                mode="onTouched"
-                defaultValues={{}}
-            // validate={(values) => { }}
-            >
-                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
-                    <Grid item xs={12} md={8}>
-                        <Typography variant="h6" gutterBottom>
-                            {translate('common.edit.title.main')}
-                        </Typography>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.transferId"
-                                source="transferId"
-                                autoFocus
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.transferCode"
-                                source="transferCode"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.matnrId"
-                                source="matnrId"
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.maktx"
-                                source="maktx"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.matnrCode"
-                                source="matnrCode"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.unit"
-                                source="unit"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.anfme"
-                                source="anfme"
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.qty"
-                                source="qty"
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.workQty"
-                                source="workQty"
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.batch"
-                                source="batch"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <NumberInput
-                                label="table.field.transferItem.splrId"
-                                source="splrId"
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.spec"
-                                source="spec"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.model"
-                                source="model"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.fieldsIndex"
-                                source="fieldsIndex"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.platItemId"
-                                source="platItemId"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.platOrderCode"
-                                source="platOrderCode"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.platWorkCode"
-                                source="platWorkCode"
-                                parse={v => v}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            <TextInput
-                                label="table.field.transferItem.projectCode"
-                                source="projectCode"
-                                parse={v => v}
-                            />
-                        </Stack>
-
-                    </Grid>
-                    <Grid item xs={12} md={4}>
-                        <Typography variant="h6" gutterBottom>
-                            {translate('common.edit.title.common')}
-                        </Typography>
-                        <StatusSelectInput />
-                        <Box mt="2em" />
-                        <MemoInput />
-                    </Grid>
-                </Grid>
-            </SimpleForm>
-        </Edit >
-    )
-}
-
-export default TransferItemEdit;
diff --git a/rsf-admin/src/page/orders/transfer/TransferList.jsx b/rsf-admin/src/page/orders/transfer/TransferList.jsx
index 790702b..3e6b4fa 100644
--- a/rsf-admin/src/page/orders/transfer/TransferList.jsx
+++ b/rsf-admin/src/page/orders/transfer/TransferList.jsx
@@ -33,16 +33,19 @@
     DeleteButton,
 } from 'react-admin';
 import { Box, Typography, Card, Stack } from '@mui/material';
-import { styled } from '@mui/material/styles';
-import TransferCreate from "./TransferCreate.jsx";
-import TransferPanel from "./TransferPanel.jsx";
-import EmptyData from "../../components/EmptyData.jsx";
+import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting.js';
+
 import MyCreateButton from "../../components/MyCreateButton.jsx";
 import MyExportButton from '../../components/MyExportButton.jsx';
+import PageEditDrawer from "../../components/PageEditDrawer";
 import PageDrawer from "../../components/PageDrawer.jsx";
+import EmptyData from "../../components/EmptyData.jsx";
 import MyField from "../../components/MyField.jsx";
-import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting.js';
+import TransferCreate from "./TransferCreate.jsx";
+import { styled } from '@mui/material/styles';
+import TransferPanel from "./TransferPanel.jsx";
 import * as Common from '@/utils/common.js';
+import ManualCreate from "./ManualCreate.jsx";
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
     '& .css-1vooibu-MuiSvgIcon-root': {
@@ -62,22 +65,21 @@
     <SearchInput source="condition" alwaysOn />,
     <DateInput label='common.time.after' source="timeStart" alwaysOn />,
     <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
-
     <TextInput source="code" label="table.field.transfer.code" />,
     <NumberInput source="type" label="table.field.transfer.type" />,
     <SelectInput source="source" label="table.field.transfer.source"
         choices={[
             { id: 1, name: 'ERP绯荤粺' },
-            { id:  2, name: 'WMS绯荤粺鐢熸垚' },
-            { id:  3, name: 'EXCEL瀵煎叆 ' },
-            { id:  4, name: 'QMS绯荤粺' },
+            { id: 2, name: 'WMS绯荤粺鐢熸垚' },
+            { id: 3, name: 'EXCEL瀵煎叆 ' },
+            { id: 4, name: 'QMS绯荤粺' },
         ]}
     />,
     <SelectInput source="exceStatus" label="table.field.transfer.exceStatus"
         choices={[
             { id: 0, name: '鏈墽琛�' },
-            { id:  1, name: '鎵ц涓�' },
-            { id:  2, name: '鎵ц瀹屾垚' },
+            { id: 1, name: '鎵ц涓�' },
+            { id: 2, name: '鎵ц瀹屾垚' },
         ]}
     />,
     <NumberInput source="orgWareId" label="table.field.transfer.orgWareId" />,
@@ -88,7 +90,6 @@
     <TextInput source="orgAreaName" label="table.field.transfer.orgAreaName" />,
     <NumberInput source="tarAreaId" label="table.field.transfer.tarAreaId" />,
     <TextInput source="tarAreaName" label="table.field.transfer.tarAreaName" />,
-
     <TextInput label="common.field.memo" source="memo" />,
     <SelectInput
         label="common.field.status"
@@ -103,7 +104,6 @@
 
 const TransferList = () => {
     const translate = useTranslate();
-
     const [createDialog, setCreateDialog] = useState(false);
     const [drawerVal, setDrawerVal] = useState(false);
 
@@ -138,7 +138,7 @@
                     rowClick={(id, resource, record) => false}
                     expand={() => <TransferPanel />}
                     expandSingle={true}
-                    omit={['id', 'createTime', 'createBy', 'memo']}
+                    omit={['id', 'createTime', 'createBy$', 'memo']}
                 >
                     <NumberField source="id" />
                     <TextField source="code" label="table.field.transfer.code" />
@@ -153,14 +153,9 @@
                     <TextField source="orgAreaName" label="table.field.transfer.orgAreaName" />
                     <NumberField source="tarAreaId" label="table.field.transfer.tarAreaId" />
                     <TextField source="tarAreaName" label="table.field.transfer.tarAreaName" />
-
-                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
-                        <TextField source="nickname" />
-                    </ReferenceField>
+                    <TextField source="updateBy$" label="common.field.updateBy" />
                     <DateField source="updateTime" label="common.field.updateTime" showTime />
-                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
-                        <TextField source="nickname" />
-                    </ReferenceField>
+                    <TextField source="createBy$" label="common.field.createBy" />
                     <DateField source="createTime" label="common.field.createTime" showTime />
                     <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                     <TextField source="memo" label="common.field.memo" sortable={false} />
@@ -170,16 +165,13 @@
                     </WrapperField>
                 </StyledDatagrid>
             </List>
-            <TransferCreate
-                open={createDialog}
-                setOpen={setCreateDialog}
-            />
-            <PageDrawer
-                title='Transfer Detail'
-                drawerVal={drawerVal}
-                setDrawerVal={setDrawerVal}
+            <PageEditDrawer
+                title={"toolbar.createTransfer"}
+                drawerVal={createDialog}
+                setDrawerVal={setCreateDialog}
             >
-            </PageDrawer>
+                <ManualCreate />
+            </PageEditDrawer>
         </Box>
     )
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java
index cf5f8c2..9767a12 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java
@@ -9,10 +9,14 @@
 import com.vincent.rsf.server.common.domain.BaseParam;
 import com.vincent.rsf.server.common.domain.KeyValVo;
 import com.vincent.rsf.server.common.domain.PageParam;
+import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams;
+import com.vincent.rsf.server.manager.controller.params.TransferItemParams;
 import com.vincent.rsf.server.manager.entity.Transfer;
 import com.vincent.rsf.server.manager.entity.excel.CheckOrderTemplate;
 import com.vincent.rsf.server.manager.service.TransferService;
+import com.vincent.rsf.server.system.constant.SerialRuleCode;
 import com.vincent.rsf.server.system.controller.BaseController;
+import com.vincent.rsf.server.system.utils.SerialRuleUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -63,6 +67,12 @@
         transfer.setCreateTime(new Date());
         transfer.setUpdateBy(getLoginUserId());
         transfer.setUpdateTime(new Date());
+
+        if (Objects.isNull(transfer.getCode())) {
+            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TRANSFER_ORDER_CODE, transfer);
+            transfer.setCode(ruleCode);
+        }
+
         if (!transferService.save(transfer)) {
             return R.error("Save Fail");
         }
@@ -105,6 +115,28 @@
         return R.ok().add(vos);
     }
 
+    @PostMapping("/transfer/items/save")
+    @ApiOperation("淇濆瓨涓诲崟鍙婃槑缁�")
+    @PreAuthorize("hasAuthority('manager:transfer:save')")
+    public R saveOutStock(@RequestBody TransferItemParams params) throws Exception {
+        if (Objects.isNull(params)) {
+            return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
+        }
+        return transferService.saveTransfer(params, getLoginUserId());
+    }
+
+    @ApiOperation("鍗曟嵁淇℃伅淇敼")
+    @PostMapping("/transfer/items/update")
+    @PreAuthorize("hasAuthority('manager:outStock:update')")
+    public R orderAndrItemUpdate(@RequestBody TransferItemParams params) throws Exception {
+        if (Objects.isNull(params)) {
+            return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
+        }
+        return transferService.updateTransfer(params, getLoginUserId());
+    }
+
+
+
     /**
      * @author Ryan
      * @description 涓嬭浇妯℃澘
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java
new file mode 100644
index 0000000..0a06795
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java
@@ -0,0 +1,24 @@
+package com.vincent.rsf.server.manager.controller.params;
+
+import com.vincent.rsf.server.manager.entity.Transfer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@Accessors(chain = true)
+@ApiModel(value = "TransferItemParams", description = "璋冩嫈鍗曞弬鏁�")
+public class TransferItemParams implements Serializable {
+
+    @ApiModelProperty("璋冩嫈鍗�")
+    private Transfer transfer;
+
+    @ApiModelProperty("璋冩嫈鍗曟槑缁�")
+    private List<Map<String, Object>>  items;
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java
index 154ab5b..1d64745 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java
@@ -3,6 +3,13 @@
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.vincent.rsf.server.manager.enums.OrderType;
+import com.vincent.rsf.server.system.constant.DictTypeCode;
+import com.vincent.rsf.server.system.entity.DictData;
+import com.vincent.rsf.server.system.service.DictDataService;
+import lombok.experimental.Accessors;
 import org.springframework.format.annotation.DateTimeFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -20,8 +27,10 @@
 import com.vincent.rsf.server.system.entity.User;
 import java.io.Serializable;
 import java.util.Date;
+import java.util.Objects;
 
 @Data
+@Accessors(chain = true)
 @TableName("man_transfer")
 public class Transfer implements Serializable {
 
@@ -56,7 +65,7 @@
      * 鎵ц鐘舵��: 0: 鏈墽琛�   1: 鎵ц涓�   2: 鎵ц瀹屾垚  
      */
     @ApiModelProperty(value= "鎵ц鐘舵��: 0: 鏈墽琛�   1: 鎵ц涓�   2: 鎵ц瀹屾垚  ")
-    private Integer exceStatus;
+    private Short exceStatus;
 
     /**
      * 婧愪粨搴揑D
@@ -159,7 +168,7 @@
 
     public Transfer() {}
 
-    public Transfer(String code,Integer type,Integer source,Integer exceStatus,Long orgWareId,String orgWareName,Long tarWareId,String tarWareName,Long orgAreaId,String orgAreaName,Long tarAreaId,String tarAreaName,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
+    public Transfer(String code,Integer type,Integer source,Short exceStatus,Long orgWareId,String orgWareName,Long tarWareId,String tarWareName,Long orgAreaId,String orgAreaName,Long tarAreaId,String tarAreaName,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
         this.code = code;
         this.type = type;
         this.source = source;
@@ -221,20 +230,21 @@
         }
     }
 
-    public String getExceStatus$(){
-        if (null == this.exceStatus){ return null; }
-        switch (this.exceStatus){
-            case 0:
-                return "鏈墽琛�";
-            case  1:
-                return "鎵ц涓�";
-            case  2:
-                return "鎵ц瀹屾垚";
-            default:
-                return String.valueOf(this.exceStatus);
+    public String getExceStatus$() {
+        if (Cools.isEmpty(this.exceStatus)){
+            return "";
         }
+        DictDataService dictDataService = SpringUtils.getBean(DictDataService.class);
+        DictData dictData = dictDataService.getOne(new LambdaQueryWrapper<DictData>()
+                .eq(DictData::getDictTypeCode, DictTypeCode.SYS_ORDER_SOURCE)
+                .eq(DictData::getValue, this.exceStatus));
+        if (Objects.isNull(dictData)) {
+            return null;
+        }
+        return dictData.getLabel();
     }
 
+
     public String getStatus$(){
         if (null == this.status){ return null; }
         switch (this.status){
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java
index 6fb3726..f9381c9 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java
@@ -16,10 +16,37 @@
     ;
 
     OrderSourceType(String val, String desc) {
-        this.val = Short.parseShort(val);
+        this.val = Integer.parseInt(val);
         this.desc = desc;
     }
 
-    public Short val;
+    public Integer val;
     public String desc;
+
+
+    public static Integer getSourceVal(String desc) {
+        if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_ERP.desc)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_ERP.val;
+        } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.desc)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val;
+        } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.desc)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.val;
+        } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_QMS.desc)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_QMS.val;
+        }
+        return null;
+    }
+
+    public static String getSourceDesc(Integer val) {
+        if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_ERP.val)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_ERP.desc;
+        } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.desc;
+        } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.val)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.desc;
+        } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_QMS.val)) {
+            return OrderSourceType.ORDER_SOURCE_TYPE_QMS.desc;
+        }
+        return null;
+    }
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java
index 583ebdf..15a0a35 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java
@@ -12,7 +12,7 @@
     ORDER_OUT("out", "鍑哄簱鍗�"),
     ORDER_IN("in", "鍏ュ簱鍗�"),
     ORDER_CHECK("check", "鐩樼偣鍗�");
-    ;
+
 
     OrderType(String type, String desc) {
         this.type = type;
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java
new file mode 100644
index 0000000..c23e0f3
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java
@@ -0,0 +1,25 @@
+package com.vincent.rsf.server.manager.enums;
+
+/**
+ * @author Ryan
+ * @date 2025/7/25
+ * @description: 璋冩嫈绫诲瀷
+ * @version 1.0
+ */
+public enum TransferType {
+
+    //璋冩嫈绫诲瀷
+    TRANSFER_TYPE_WAREHOUSE("1" ,"璺ㄤ粨璋冩嫈"),
+    TRANSFER_TYPE_AREAS("2", "璺ㄥ尯璋冩嫈"),
+    TRANSFER_TYPE_LOCAL("0", "鏈湴璋冩嫈");
+
+    private Integer val;
+
+    private String desc;
+
+    TransferType(String val, String desc) {
+        this.val = Integer.parseInt(val);
+        this.desc = desc;
+    }
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java
index 47d4f27..640cd5f 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java
@@ -1,8 +1,14 @@
 package com.vincent.rsf.server.manager.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.server.manager.controller.params.TransferItemParams;
 import com.vincent.rsf.server.manager.entity.Transfer;
 
 public interface TransferService extends IService<Transfer> {
 
+    R saveTransfer(TransferItemParams params, Long loginUserId);
+
+    R updateTransfer(TransferItemParams params, Long loginUserId);
 }
+
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java
index d0eb7ca..bcf2413 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java
@@ -115,15 +115,15 @@
             if (null != group){
                 pageParam.getWhere().getMap().remove("groupId");
                 if(!group.getCode().equals("01")){
-                    List<MatnrGroup> matnrGroups = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>().eq(MatnrGroup::getParentId, Long.parseLong(groupId.toString())).select(MatnrGroup::getId));
+                    List<MatnrGroup> matnrGroups = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>()
+                            .eq(MatnrGroup::getParentId, Long.parseLong(groupId.toString()))
+                            .select(MatnrGroup::getId));
                     if (!matnrGroups.isEmpty()) {
                         longs = matnrGroups.stream().map(MatnrGroup::getId).collect(Collectors.toList());
 
                     }
                     longs.add(group.getId());
                 }
-
-
             }
         }
         QueryWrapper<Matnr> queryWrapper = pageParam.buildWrapper(true);
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java
index b4b3026..fa85fe3 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java
@@ -1,12 +1,103 @@
 package com.vincent.rsf.server.manager.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.framework.exception.CoolException;
+import com.vincent.rsf.server.manager.controller.params.TransferItemParams;
+import com.vincent.rsf.server.manager.entity.WkOrder;
+import com.vincent.rsf.server.manager.entity.WkOrderItem;
+import com.vincent.rsf.server.manager.enums.AsnExceStatus;
+import com.vincent.rsf.server.manager.enums.CheckExceStatus;
+import com.vincent.rsf.server.manager.enums.OrderSourceType;
+import com.vincent.rsf.server.manager.enums.OrderType;
 import com.vincent.rsf.server.manager.mapper.TransferMapper;
 import com.vincent.rsf.server.manager.entity.Transfer;
 import com.vincent.rsf.server.manager.service.TransferService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.vincent.rsf.server.system.constant.SerialRuleCode;
+import com.vincent.rsf.server.system.utils.SerialRuleUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Objects;
 
 @Service("transferService")
 public class TransferServiceImpl extends ServiceImpl<TransferMapper, Transfer> implements TransferService {
 
+    /**
+     * @author Ryan
+     * @date 2025/7/25
+     * @description: 淇濆瓨璋冩嫈鍗曞強鏄庣粏
+     * @version 1.0
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R saveTransfer(TransferItemParams params, Long loginUserId) {
+        if (Objects.isNull(params.getTransfer())) {
+            throw new CoolException("涓诲崟淇℃伅涓嶈兘涓虹┖");
+        }
+        Transfer transfer = params.getTransfer();
+        if (StringUtils.isBlank(transfer.getType() + "")) {
+            throw new CoolException("涓氬姟绫诲瀷涓嶈兘涓虹┖锛侊紒");
+        }
+
+        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TRANSFER_ORDER_CODE, transfer);
+        if (StringUtils.isBlank(ruleCode)) {
+            throw new CoolException("缂栫爜瑙勫垯閿欒锛氳妫�鏌ャ�孲YS_TRANSFER_ORDER_CODE銆嶆槸鍚﹁缃纭紒锛�");
+        }
+        transfer.setCode(ruleCode)
+                .setExceStatus(CheckExceStatus.CHECK_ORDER_STATUS_UN_EXCE.val)
+                .setSource(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val)
+                .setUpdateBy(loginUserId)
+                .setCreateBy(loginUserId);
+        if (!this.save(transfer)) {
+            throw new CoolException("涓诲崟淇濆瓨澶辫触锛侊紒");
+        }
+        if (params.getItems().isEmpty()) {
+            throw new CoolException("鏀惰揣閫氱煡鍗曟槑缁嗕笉鑳戒负绌猴紒锛�");
+        }
+        params.setTransfer(transfer);
+        try {
+            svaeOrUpdateOrderItem(params, loginUserId);
+        } catch (Exception e) {
+            throw new CoolException(e.getMessage());
+        }
+        return R.ok();
+    }
+
+
+    private void svaeOrUpdateOrderItem(TransferItemParams params, Long loginUserId) {
+//        Transfer orders = params.getTransfer();
+//        params.getItems().forEach(item -> {
+//            item.put("orderId", orders.getId());
+//            item.put("orderCode", orders.getCode());
+//            item.put("poCode", orders.getPoCode());
+//            item.put("createBy", loginUserId);
+//            item.put("updateBy", loginUserId);
+//            if (!asnOrderItemService.fieldsSave(item, loginUserId)) {
+//                throw new CoolException("鏄庣粏淇濆瓨澶辫触锛侊紒");
+//            }
+//        });
+//        List<WkOrderItem> orderItems = checkOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>()
+//                .eq(WkOrderItem::getOrderId, params.getOrders().getId()));
+//        Double sum = orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum();
+//        orders.setAnfme(sum);
+//        if (!this.updateById(orders)) {
+//            throw new CoolException("璁″垝鏀惰揣鏁伴噺淇敼澶辫触锛侊紒");
+//        }
+    }
+
+
+    /**
+     * @author Ryan
+     * @date 2025/7/25
+     * @description: 璋冩嫈鍗曞強鏄庣粏淇敼
+     * @version 1.0
+     */
+    @Override
+    public R updateTransfer(TransferItemParams params, Long loginUserId) {
+        return null;
+    }
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java
index 40e8b46..43d2e0e 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java
@@ -91,4 +91,7 @@
     public final static String SYS_CHECK_DIFF_REASON =  "sys_check_diff_reason";
     /**鐩樼偣绫诲瀷*/
     public final static String SYS_CHECK_TYPE = "sys_check_type";
+
+    /**鍗曟嵁鏉ユ簮*/
+    public final static String SYS_ORDER_SOURCE = "sys_order_source";
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java
index c0e28de..6361b89 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java
@@ -88,5 +88,8 @@
     /**鐩樼偣鍗曞彿*/
     public final static String SYS_CHECK_RULE_CODE = "sys_check_rule_code";
 
+    /**璋冩嫈鍗曠紪鐮佽鍒�*/
+    public final static String SYS_TRANSFER_ORDER_CODE = "sys_transfer_order_code";
+
 
 }

--
Gitblit v1.9.1