From c3bd7262ff89c7594ec368f76ea910e6212769af Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期二, 29 四月 2025 13:53:03 +0800 Subject: [PATCH] 1. 出库单新增修改优化 --- rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java | 49 + rsf-admin/src/page/orders/outStock/AsnWareModal.jsx | 249 ++++++++ rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java | 4 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java | 40 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java | 4 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java | 25 rsf-server/src/main/java/com/vincent/rsf/server/common/interceptor/severlet/CustomParameterFilter.java | 2 rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx | 83 - rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx | 613 +++++++++++++++++++++ rsf-admin/src/page/components/DictSelect.jsx | 1 rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx | 1 rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx | 7 rsf-admin/src/page/orders/outStock/AsnOrderModal.jsx | 643 ++++++++++++++++++++++ rsf-admin/src/i18n/zh.js | 1 rsf-admin/src/page/orders/outStock/OutOrderList.jsx | 15 rsf-admin/src/i18n/en.js | 1 16 files changed, 1,656 insertions(+), 82 deletions(-) diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js index 37cd4e3..596f515 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -56,6 +56,7 @@ expand: 'Expand', expandAll: 'Expand All', collapse: 'Collapse', + newAddMats: 'New Mats', collapseAll: 'Collapse All', scope: 'Assign', import: { diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 8f6d2d3..0c681ce 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -56,6 +56,7 @@ expand: '灞曞紑', expandAll: '鍏ㄩ儴灞曞紑', collapse: '鎶樺彔', + newAddMats: '鏂板鐗╂枡', collapseAll: '鍏ㄩ儴鎶樺彔', scope: '鏉冮檺', inputPlaceholder: '绔欑偣鍙~澶氫釜锛屼腑闂翠互鑻辨枃閫楀彿鍖哄垎锛�,锛�', diff --git a/rsf-admin/src/page/components/DictSelect.jsx b/rsf-admin/src/page/components/DictSelect.jsx index 72c9d76..d42a8ee 100644 --- a/rsf-admin/src/page/components/DictSelect.jsx +++ b/rsf-admin/src/page/components/DictSelect.jsx @@ -44,6 +44,7 @@ <Select labelId="demo-select-small-label" value={validValue} + variant="filled" onChange={handleChange} size='small' > diff --git a/rsf-admin/src/page/orders/outStock/AsnOrderModal.jsx b/rsf-admin/src/page/orders/outStock/AsnOrderModal.jsx new file mode 100644 index 0000000..6c2dc38 --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/AsnOrderModal.jsx @@ -0,0 +1,643 @@ +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, + useListContext, + useRefresh, +} 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 + + +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import StatusSelectInput from "../../components/StatusSelectInput"; +import ConfirmButton from "../../components/ConfirmButton"; +import AsnWareModal from "./AsnWareModal"; +import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form"; +import SaveIcon from '@mui/icons-material/Save'; +import request from '@/utils/request'; +import { Add, Edit, Delete } from '@mui/icons-material'; +import _, { set } from 'lodash'; +import { DataGrid, useGridApiRef } from '@mui/x-data-grid'; +import DictionarySelect from "../../components/DictionarySelect"; +import DictSelect from "../../components/DictSelect"; +import "./asnOrder.css"; + +const AsnOrderModal = (props) => { + const { open, setOpen, asnId, billReload } = props; + + const translate = useTranslate(); + const notify = useNotify(); + const refresh = useRefresh(); + const [disabled, setDisabled] = useState(false) + + const [createDialog, setCreateDialog] = useState(false); + + const tableRef = useRef(); + + useEffect(() => { + if (open && asnId !== 0) { + requestGetHead() + requestGetBody() + } + setDisabled(false) + }, [open]) + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + refresh(); + setFormData({ type: '', wkType: '' }) + setTableData([]) + } + }; + + const [formData, setFormData] = useState({ + type: '', + wkType: '', + poCode: '', + logisNo: '', + arrTime: '' + }); + + const [tabelData, setTableData] = useState([]); + + + const handleChange = (value, name) => { + setFormData((prevData) => ({ + ...prevData, + [name]: value + })); + console.log(formData); + }; + + const resetData = () => { + setFormData({ + type: '', + wkType: '', + poCode: '', + logisNo: '', + arrTime: '' + }) + setTableData([]) + } + + const setFinally = () => { + const rows = tableRef.current.state.editRows; + for (const key in rows) { + const find = tabelData.find(item => item.matnrId === +key); + find.anfme = rows[key].anfme.value; + } + setTableData([...tabelData]); + } + + const handleSubmit = async () => { + setFinally() + setDisabled(true) + + if (asnId === 0) { + const parmas = { + "orders": formData, + "items": tabelData, + } + + const res = await request.post(`/asnOrder/items/save`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + billReload?.current() + resetData() + } else { + notify(res.data.msg); + } + } else { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/asnOrder/items/update`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + billReload?.current() + resetData() + } else { + notify(res.data.msg); + } + } + setDisabled(false) + + }; + + + const handleDelete = async () => { + const res = await request.post(`/asnOrder/remove/${asnId}`); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + } else { + notify(res.data.msg); + } + }; + + const requestGetHead = async () => { + const res = await request.get(`/asnOrder/${asnId}`); + if (res?.data?.code === 200) { + setFormData(res.data.data) + } else { + notify(res.data.msg); + } + } + + const requestGetBody = async () => { + const res = await request.post(`/asnOrderItem/page`, { asnId }); + if (res?.data?.code === 200) { + setTableData(res.data.data.records) + } else { + notify(res.data.msg); + } + } + + const [selectedRows, setSelectedRows] = useState([]); + + + + const handleDeleteItem = () => { + const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId)); + setTableData(newTableData); + } + + return ( + <> + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + aria-hidden + fullWidth + disableRestoreFocus + maxWidth="lg" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' + > + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }}> + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form defaultValues={formData}> + <Grid container spacing={2}> + <Grid item md={3}> + <DictSelect + label={translate("table.field.asnOrder.type")} + value={formData.type} + onChange={(e) => handleChange(e.target.value, 'type')} + dictTypeCode="sys_order_type" + required + /> + </Grid> + <Grid item md={3}> + <DictSelect + label={translate("table.field.asnOrder.wkType")} + value={formData.wkType} + onChange={(e) => handleChange(e.target.value, 'wkType')} + dictTypeCode="sys_business_type" + required + /> + </Grid> + <Grid item md={3}> + <TextField + label={translate("table.field.asnOrder.poCode")} + value={formData.poCode} + onChange={(e) => handleChange(e.target.value, 'poCode')} + /> + </Grid> + <Grid item md={3}> + <TextField + label={translate("table.field.asnOrder.logisNo")} + value={formData.logisNo} + onChange={(e) => handleChange(e.target.value, 'logisNo')} + /> + </Grid> + + <Grid item md={3}> + {/* <TextField + label={translate("table.field.asnOrder.arrTime")} + value={formData.arrTime} + onChange={(e) => handleChange(e.target.value, 'arrTime')} + /> */} + <DateInput + source="arrTime" + label="table.field.asnOrder.arrTime" + value={formData.arrTime} + onChange={(e) => handleChange(e.target.value, 'arrTime')} + /> + + </Grid> + </Grid> + </Form> + </Box> + + <Box sx={{ mt: 2 }}> + <Stack direction="row" spacing={2}> + <Button variant="contained" onClick={() => setCreateDialog(true)}>鏂板鐗╂枡</Button> + {/* {asnId !== '' && <ConfirmButton label={'鍒犻櫎'} variant="outlined" color="error" onConfirm={handleDelete} />} */} + <ConfirmButton label={'鍒犻櫎'} variant="outlined" color="error" onConfirm={handleDeleteItem} /> + </Stack> + </Box> + <Box sx={{ mt: 2 }}> + <AsnOrderModalTable tabelData={tabelData} setTableData={setTableData} asnId={asnId} selectedRows={selectedRows} setSelectedRows={setSelectedRows} tableRef={tableRef}></AsnOrderModalTable> + </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> + + <AsnWareModal + open={createDialog} + setOpen={setCreateDialog} + data={tabelData} + setData={setTableData} + /> + </> + ) +} + +export default AsnOrderModal; + +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) + console.log(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) + console.log(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 AsnOrderModalTable = ({ tabelData, setTableData, asnId, selectedRows, setSelectedRows, tableRef }) => { + const translate = useTranslate(); + const notify = useNotify(); + + const [columns, setColumns] = useState([ + + { + field: 'maktx', + headerName: translate('table.field.asnOrderItem.maktx'), + width: 250, + editable: false, + }, + { + field: 'matnrCode', + headerName: translate('table.field.asnOrderItem.matnrCode'), + width: 130, + editable: false, + }, + { + field: 'anfme', + headerName: translate('table.field.asnOrderItem.anfme')+"*", + type: 'number', + minWidth: 100, + flex: 1, + editable: true, + valueFormatter: (val) => val < 0 ? 0 : val, + headerClassName: "custom", + }, + { + field: 'splrCode', + headerName: translate('table.field.asnOrderItem.splrCode')+"*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrCodeEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrName', + headerName: translate('table.field.asnOrderItem.splrName')+"*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrNameEditCell {...params} /> + ), + headerClassName: "custom", + }, + // { + // field: 'packName', + // headerName: translate('table.field.asnOrderItem.packName'), + // minWidth: 100, + // flex: 1, + // editable: true, + // }, + // { + // field: 'poDetlId', + // headerName: translate('table.field.asnOrderItem.poDetlId'), + // minWidth: 100, + // flex: 1, + // }, + { + field: 'poCode', + headerName: translate('table.field.asnOrderItem.poDetlCode')+"*", + minWidth: 100, + flex: 1, + editable: true, + headerClassName: "custom", + }, + + { + field: 'stockUnit', + headerName: translate('table.field.asnOrderItem.stockUnit'), + minWidth: 100, + flex: 1, + editable: false, + }, + // { + // field: 'purQty', + // headerName: translate('table.field.asnOrderItem.purQty'), + // minWidth: 100, + // flex: 1, + // editable: true, + // }, + { + field: 'purUnit', + headerName: translate('table.field.asnOrderItem.purUnit'), + minWidth: 100, + flex: 1, + 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.matnrId !== row.matnrId); + setTableData(newData); + }; + + + const processRowUpdate = (newRow, oldRow) => { + const rows = tabelData.map((r) => + r.matnrId === newRow.matnrId ? { ...newRow } : r + ) + setTableData(rows) + // setTableData((prevData) => + // prevData.map((r) => + // r.matnrId === newRow.matnrId ? { ...newRow } : r + // ) + + // ); + + 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} + 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/orders/outStock/AsnWareModal.jsx b/rsf-admin/src/page/orders/outStock/AsnWareModal.jsx new file mode 100644 index 0000000..8f3788b --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/AsnWareModal.jsx @@ -0,0 +1,249 @@ +import React, { useState, useEffect } from "react"; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Stack, + Grid, + TextField, + Box, + Button, + Paper, + styled +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import { useTranslate, useNotify, useRefresh } from 'react-admin'; +import request from '@/utils/request'; +import { DataGrid } from '@mui/x-data-grid'; +import SaveIcon from '@mui/icons-material/Save'; +import TreeSelectInput from "@/page/components/TreeSelectInput"; +const AsnWareModal = (props) => { + const { open, setOpen, data, setData } = props; + + const translate = useTranslate(); + const notify = useNotify(); + const refresh = useRefresh(); + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const [formData, setFormData] = useState({}); + const [tableData, setTableData] = useState([]); + const [dyFields, setDyFields] = useState([]); + const [selectedRows, setSelectedRows] = useState([]); + + 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: 1, + pageSize: 100, + orderBy: "create_time desc" + }); + if (res?.data?.code === 200) { + setTableData(res.data.data.records); + } 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 + }}> + 閫夋嫨鐗╂枡 + <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={4}> + <TextField + label={translate('table.field.matnr.name')} + name="name" + value={formData.name} + onChange={handleChange} + size="small" + /> + </Grid> + <Grid item md={4}> + <TextField + label={translate('table.field.matnr.code')} + name="code" + value={formData.code} + onChange={handleChange} + size="small" + /> + </Grid> + <Grid item md={4}> + <TreeSelectInput + label="table.field.matnr.groupId" + value={formData.groupId} + resource={'matnrGroup'} + source="groupId" + name="groupId" + onChange={handleChange} + /> + </Grid> + </Grid> + </Box> + <Box sx={{ mt: 2 }}> + <Stack direction="row" spacing={2}> + <Button variant="contained" onClick={handleSearch}>鎼滅储</Button> + </Stack> + </Box> + <Box sx={{ mt: 2, height: 400, width: '100%' }}> + <AsnWareModalTable + tableData={tableData} + setTableData={setTableData} + 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: 'space-between' }}> + <Button onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}> + {translate('toolbar.confirm')} + </Button> + </Box> + </DialogActions> + </Dialog> + ); +}; + +export default AsnWareModal; + +const AsnWareModalTable = ({ tableData, setTableData, selectedRows, setSelectedRows, dyFields, setDyFields }) => { + const translate = useTranslate(); + const notify = useNotify(); + + const [columns, setColumns] = useState([ + // { field: 'id', headerName: 'ID', width: 100 }, + { 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(() => { + 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] || ''; + }, + })) + setDyFields(data) + setColumns([...columns, ...cols]) + } else { + notify(msg); + } + } + + return ( + <div style={{ height: 400, width: '100%' }}> + <DataGrid + size="small" + rows={tableData} + columns={columns} + checkboxSelection + onRowSelectionModelChange={handleSelectionChange} + selectionModel={selectedRows} + disableColumnMenu={true} + disableColumnSorting + disableMultipleColumnsSorting + /> + </div> + ); +}; \ No newline at end of file diff --git a/rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx b/rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx index 25a8314..40fba47 100644 --- a/rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx +++ b/rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx @@ -27,6 +27,8 @@ useList, ListContextProvider, useListContext, + Button, + useRecordContext, } from 'react-admin'; import { Dialog, @@ -43,7 +45,8 @@ import StatusSelectInput from "../../components/StatusSelectInput"; import OutOrderItemList from "./OutOrderItemList"; import MemoInput from "../../components/MemoInput"; - +import AddIcon from '@mui/icons-material/Add'; +import SelectMatnrModal from "./SelectMatnrModal"; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -67,6 +70,7 @@ const translate = useTranslate(); const notify = useNotify(); const [drawerVal, setDrawerVal] = useState(false); + const [matCreate, setMatCreate] = useState(false); const handleClose = (event, reason) => { if (reason !== "backdropClick") { @@ -120,7 +124,7 @@ </DialogTitle> <DialogContent sx={{ mt: 2 }}> <> - <Grid container rowSpacing={2} columnSpacing={2}> + <Grid container> <Grid item xs={12} display="flex" gap={1}> <TextInput label="table.field.asnOrder.poCode" @@ -154,12 +158,13 @@ source="anfme" validate={required()} /> + + </Grid> + <Grid item xs={12} display="flex" gap={1}> <NumberInput label="table.field.asnOrder.qty" source="qty" /> - </Grid> - <Grid item xs={12} display="flex" gap={1}> <TextInput label="table.field.asnOrder.logisNo" source="logisNo" @@ -179,64 +184,15 @@ /> </Grid> </Grid> + <SelectMatnrModal open={matCreate} setOpen={setMatCreate} /> <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> <Toolbar sx={{ width: '100%', justifyContent: 'end' }} > + <AddOutOrderButton setMatCreate={setMatCreate} /> <SaveButton /> </Toolbar> </DialogActions> - <Box> - <ListContextProvider - // resource="waveItem脧" - value={listContext} - sx={{ - flexGrow: 1, - transition: (theme) => - theme.transitions.create(['all'], { - duration: theme.transitions.duration.enteringScreen, - }), - marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, - }} - title={"menu.waveItem"} - empty={false} - sort={{ field: "create_time", order: "desc" }} - filters={false} - actions={( - <TopToolbar> - <SelectColumnsButton preferenceKey='waveItem' /> - </TopToolbar> - )} - perPage={DEFAULT_PAGE_SIZE} - > - <StyledDatagrid - preferenceKey='waveItem' - bulkActionButtons={false} - rowClick={(id, resource, record) => false} - expand={false} - expandSingle={false} - omit={['id', 'createTime', 'matnrId', 'waveId', 'batch', 'orderItemId', 'unit', 'batch', 'trackCode', 'fieldsIndex', 'createBy', 'memo']} - > - <NumberField source="id" /> - <NumberField source="waveId" label="table.field.waveItem.waveId" /> - <TextField source="waveCode" label="table.field.waveItem.waveCode" /> - <TextField source="orderCode" label="table.field.waveItem.orderCode" /> - <NumberField source="matnrId" label="table.field.waveItem.matnrId" /> - <TextField source="matnrCode" label="table.field.waveItem.matnrCode" /> - <TextField source="batch" label="table.field.waveItem.batch" /> - <TextField source="splrBatch" label="table.field.waveItem.splrBatch" /> - <NumberField source="orderItemId" label="table.field.waveItem.orderItemId" /> - <TextField source="unit" label="table.field.waveItem.unit" /> - <TextField source="trackCode" label="table.field.waveItem.trackCode" /> - <TextField source="fieldsIndex" label="table.field.waveItem.fieldsIndex" /> - <NumberField source="anfme" label="table.field.waveItem.anfme" /> - <NumberField source="workQty" label="table.field.waveItem.workQty" /> - <NumberField source="qty" label="table.field.waveItem.qty" /> - <NumberField source="stockQty" label="table.field.waveItem.stockQty" /> - <WrapperField cellClassName="opt" label="table.field.waveItem.stockLocs"> - {/* <TagsField /> */} - </WrapperField> - </StyledDatagrid> - </ListContextProvider> + </Box> </> </DialogContent> @@ -248,3 +204,18 @@ } export default OutOrderCreate; + + +const AddOutOrderButton = (setMatCreate) => { + const record = useRecordContext(); + const addMats = (event) => { + event.stopPropagation(); + setMatCreate(true) + } + + return ( + <Button label={"common.action.newAddMats"} onClick={addMats} variant="contained" sx={{ padding: '0.6em', marginRight: '1em' }}> + <AddIcon /> + </Button> + ); +} diff --git a/rsf-admin/src/page/orders/outStock/OutOrderList.jsx b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx index 23ed27e..2b181eb 100644 --- a/rsf-admin/src/page/orders/outStock/OutOrderList.jsx +++ b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx @@ -56,6 +56,7 @@ import AddIcon from '@mui/icons-material/Add'; import OutOrderModal from "./OutOrderModal"; import PublicIcon from '@mui/icons-material/Public'; +import SelectMatnrModal from "./SelectMatnrModal"; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -139,7 +140,7 @@ <TopToolbar> <FilterButton /> <CreateByOrderButton setCreateDialog={setCreateDialog} /> - <MyCreateButton onClick={() => { setManualDialog(true) }} /> + <MyCreateButton onClick={() => { setManualDialog(true); setmodalType(0) }} /> <SelectColumnsButton preferenceKey='outStock' /> <ImportButton value={'asnOrderItem'} /> {/* <MyExportButton /> */} @@ -173,12 +174,19 @@ <BillStatusField cellClassName="status" source="exceStatus" label="table.field.outStock.exceStatus" /> <TextField source="memo" label="common.field.memo" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt" > + <MyButton setCreateDialog={setManualDialog} setmodalType={setmodalType} /> <EditButton label="toolbar.detail" icon={(<DetailsIcon />)}></EditButton> <CancelButton /> </WrapperField> </StyledDatagrid> </List> - <OutOrderCreate + {/* <OutOrderCreate + open={manualDialog} + setOpen={setManualDialog} + /> */} + <SelectMatnrModal + asnId={modalType} + billReload={billReload} open={manualDialog} setOpen={setManualDialog} /> @@ -190,8 +198,7 @@ title='AsnOrder Detail' drawerVal={drawerVal} setDrawerVal={setDrawerVal} - > - </PageDrawer> + /> </Box > ) } diff --git a/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx b/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx new file mode 100644 index 0000000..7e0652b --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx @@ -0,0 +1,613 @@ +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, + useListContext, + useRefresh, +} 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 +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import StatusSelectInput from "../../components/StatusSelectInput"; +import ConfirmButton from "../../components/ConfirmButton"; +import AsnWareModal from "./AsnWareModal"; +import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form"; +import SaveIcon from '@mui/icons-material/Save'; +import request from '@/utils/request'; +import { Add, Edit, Delete } from '@mui/icons-material'; +import _, { set } from 'lodash'; +import { DataGrid, useGridApiRef } from '@mui/x-data-grid'; +import DictionarySelect from "../../components/DictionarySelect"; +import DictSelect from "../../components/DictSelect"; +import "./asnOrder.css"; + +const SelectMatnrModal = (props) => { + const { open, setOpen, asnId, billReload } = props; + + const translate = useTranslate(); + const notify = useNotify(); + const refresh = useRefresh(); + const [disabled, setDisabled] = useState(false) + + const [createDialog, setCreateDialog] = useState(false); + + const tableRef = useRef(); + + useEffect(() => { + if (open && asnId !== 0) { + requestGetHead() + requestGetBody() + } + setDisabled(false) + }, [open]) + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + refresh(); + setFormData({ type: '', wkType: '' }) + setTableData([]) + } + }; + + const [formData, setFormData] = useState({ + type: '', + wkType: '', + poCode: '', + logisNo: '', + arrTime: '' + }); + + const [tabelData, setTableData] = useState([]); + + const handleChange = (value, name) => { + setFormData((prevData) => ({ + ...prevData, + [name]: value + })); + console.log(formData); + }; + + const resetData = () => { + setFormData({ + type: '', + wkType: '', + poCode: '', + logisNo: '', + arrTime: '' + }) + setTableData([]) + } + + const setFinally = () => { + const rows = tableRef.current.state.editRows; + for (const key in rows) { + const find = tabelData.find(item => item.matnrId === +key); + find.anfme = rows[key].anfme.value; + } + setTableData([...tabelData]); + } + + const handleSubmit = async () => { + setFinally() + setDisabled(true) + + if (asnId === 0) { + const parmas = { + "orders": formData, + "items": tabelData, + } + + const res = await request.post(`/asnOrder/items/save`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + billReload?.current() + resetData() + } else { + notify(res.data.msg); + } + } else { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/asnOrder/items/update`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + billReload?.current() + resetData() + } else { + notify(res.data.msg); + } + } + setDisabled(false) + + }; + + + const handleDelete = async () => { + const res = await request.post(`/asnOrder/remove/${asnId}`); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + } else { + notify(res.data.msg); + } + }; + + const requestGetHead = async () => { + const res = await request.get(`/asnOrder/${asnId}`); + if (res?.data?.code === 200) { + setFormData(res.data.data) + } else { + notify(res.data.msg); + } + } + + const requestGetBody = async () => { + const res = await request.post(`/asnOrderItem/page`, { asnId }); + if (res?.data?.code === 200) { + setTableData(res.data.data.records) + } else { + notify(res.data.msg); + } + } + + const [selectedRows, setSelectedRows] = useState([]); + + const handleDeleteItem = () => { + const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId)); + setTableData(newTableData); + } + + return ( + <> + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + aria-hidden + fullWidth + disableRestoreFocus + maxWidth="lg" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' + > + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }}> + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form defaultValues={formData}> + <Grid container spacing={2}> + {/* <Grid item md={2}> + <DictSelect + label={translate("table.field.asnOrder.type")} + value={formData.type} + onChange={(e) => handleChange(e.target.value, 'type')} + dictTypeCode="sys_order_type" + required + /> + </Grid> */} + <Grid item md={2}> + <DictSelect + label={translate("table.field.asnOrder.wkType")} + value={formData.wkType} + variant="filled" + onChange={(e) => handleChange(e.target.value, 'wkType')} + dictTypeCode="sys_business_type" + required + /> + </Grid> + <Grid item md={2}> + <TextField + label={translate("table.field.asnOrder.poCode")} + value={formData.poCode} + variant="filled" + size='small' + onChange={(e) => handleChange(e.target.value, 'poCode')} + /> + </Grid> + <Grid item md={2}> + <TextField + label={translate("table.field.asnOrder.logisNo")} + value={formData.logisNo} + variant="filled" + size='small' + onChange={(e) => handleChange(e.target.value, 'logisNo')} + /> + </Grid> + <Grid item md={2}> + <DateInput + source="arrTime" + label="table.field.asnOrder.arrTime" + size='small' + variant="filled" + value={formData.arrTime} + onChange={(e) => handleChange(e.target.value, 'arrTime')} + /> + </Grid> + </Grid> + </Form> + </Box> + + <Box sx={{ mt: 2 }}> + <Stack direction="row" spacing={2}> + <Button variant="contained" onClick={() => setCreateDialog(true)}>鏂板鐗╂枡</Button> + {/* {asnId !== '' && <ConfirmButton label={'鍒犻櫎'} variant="outlined" color="error" onConfirm={handleDelete} />} */} + <ConfirmButton label={'鍒犻櫎'} variant="outlined" color="error" onConfirm={handleDeleteItem} /> + </Stack> + </Box> + <Box sx={{ mt: 2 }}> + <AsnOrderModalTable tabelData={tabelData} setTableData={setTableData} asnId={asnId} selectedRows={selectedRows} setSelectedRows={setSelectedRows} tableRef={tableRef}></AsnOrderModalTable> + </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> + <AsnWareModal + open={createDialog} + setOpen={setCreateDialog} + data={tabelData} + setData={setTableData} + /> + </> + ) +} + +export default SelectMatnrModal; + +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) + console.log(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) + console.log(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 AsnOrderModalTable = ({ tabelData, setTableData, asnId, selectedRows, setSelectedRows, tableRef }) => { + const translate = useTranslate(); + const notify = useNotify(); + + const [columns, setColumns] = useState([ + { + field: 'maktx', + headerName: translate('table.field.asnOrderItem.maktx'), + width: 250, + editable: false, + }, + { + field: 'matnrCode', + headerName: translate('table.field.asnOrderItem.matnrCode'), + width: 130, + editable: false, + }, + { + field: 'anfme', + headerName: translate('table.field.asnOrderItem.anfme') + "*", + type: 'number', + minWidth: 100, + flex: 1, + editable: true, + valueFormatter: (val) => val < 0 ? 0 : val, + headerClassName: "custom", + }, + { + field: 'splrCode', + headerName: translate('table.field.asnOrderItem.splrCode') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrCodeEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrName', + headerName: translate('table.field.asnOrderItem.splrName') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrNameEditCell {...params} /> + ), + headerClassName: "custom", + }, + // { + // field: 'packName', + // headerName: translate('table.field.asnOrderItem.packName'), + // minWidth: 100, + // flex: 1, + // editable: true, + // }, + // { + // field: 'poDetlId', + // headerName: translate('table.field.asnOrderItem.poDetlId'), + // minWidth: 100, + // flex: 1, + // }, + { + field: 'poCode', + headerName: translate('table.field.asnOrderItem.poDetlCode') + "*", + minWidth: 100, + flex: 1, + editable: true, + headerClassName: "custom", + }, + + { + field: 'stockUnit', + headerName: translate('table.field.asnOrderItem.stockUnit'), + minWidth: 100, + flex: 1, + editable: false, + }, + // { + // field: 'purQty', + // headerName: translate('table.field.asnOrderItem.purQty'), + // minWidth: 100, + // flex: 1, + // editable: true, + // }, + { + field: 'purUnit', + headerName: translate('table.field.asnOrderItem.purUnit'), + minWidth: 100, + flex: 1, + 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.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} + 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/orders/wave/ItemToTaskModal.jsx b/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx index 2f81a39..d37edc4 100644 --- a/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx +++ b/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx @@ -150,7 +150,7 @@ </DialogContent> <DialogActions> <Toolbar sx={{ width: '100%', justifyContent: 'end' }} > - <GenerateTaskButton record={[record?.id]} dataSource={data} /> + <GenerateTaskButton record={record?.id} dataSource={data} /> </Toolbar> </DialogActions> </Dialog> @@ -165,7 +165,10 @@ const notify = useNotify(); const redirect = useRedirect(); const generateTask = async () => { - const res = await request.post(`/wave/public/task`, { wave: record, waveItem: dataSource }); + const params = {wave: record, waveItem: dataSource} + console.log('---------->'); + console.log(record); + const res = await request.post(`/wave/public/task`, { wave: record?.record, waveItem: record?.dataSource }); if (res?.data?.code === 200) { notify(res.data.msg); redirect("/task") diff --git a/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx b/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx index 86a989a..cf5d60c 100644 --- a/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx +++ b/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx @@ -116,7 +116,6 @@ const translate = useTranslate(); const [createDialog, setCreateDialog] = useState(false); const [drawerVal, setDrawerVal] = useState(false); - const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_ware_areas_type')) || []; return ( <Box display="flex"> diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/interceptor/severlet/CustomParameterFilter.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/interceptor/severlet/CustomParameterFilter.java index 56b1756..ddef2aa 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/common/interceptor/severlet/CustomParameterFilter.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/interceptor/severlet/CustomParameterFilter.java @@ -8,7 +8,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; -@Component +//@Component public class CustomParameterFilter extends OncePerRequestFilter { @Override diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java index 2efff1c..058422e 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java @@ -13,6 +13,7 @@ import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.server.common.utils.ExcelUtil; +import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams; import com.vincent.rsf.server.manager.entity.AsnOrder; import com.vincent.rsf.server.manager.entity.AsnOrderItem; import com.vincent.rsf.server.manager.entity.excel.AsnOrderTemplate; @@ -214,4 +215,28 @@ List<Long> ids = (List<Long>) params.get("ids"); return outStockService.generateWaves(ids); } + + @PostMapping("/outStock/items/save") + @ApiOperation("淇濆瓨涓诲崟鍙婃槑缁�") + @PreAuthorize("hasAuthority('manager:outStock:save')") + public R orderAndItem(@RequestBody AsnOrderAndItemsParams params) throws Exception { + if (Objects.isNull(params)) { + return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒"); + } + return outStockService.saveOrderAndItems(params, getLoginUserId()); + } + + @ApiOperation("鍗曟嵁淇℃伅淇敼") + @PostMapping("/outStock/items/update") + @PreAuthorize("hasAuthority('manager:outStock:update')") + public R orderAndrItemUpdate(@RequestBody AsnOrderAndItemsParams params) throws Exception { + if (Objects.isNull(params)) { + return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒"); + } + return outStockService.updateOrderItem(params, getLoginUserId()); + } + + + + } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java index aa19574..919b81a 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java @@ -126,4 +126,8 @@ } } + + + + } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java index 22fcc64..71a70bd 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java @@ -16,4 +16,8 @@ R genOutStock(List<Long> ids); R generateWaves(List<Long> ids); + + R saveOrderAndItems(AsnOrderAndItemsParams params, Long loginUserId); + + R updateOrderItem(AsnOrderAndItemsParams params, Long loginUserId); } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java index ddc4991..20dc185 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java @@ -310,6 +310,55 @@ } /** + * @author Ryan + * @description 淇濆瓨鍑哄簱涓诲崟鍙婃槑缁� + * @param + * @return + * @time 2025/4/29 13:47 + */ + @Override + public R saveOrderAndItems(AsnOrderAndItemsParams params, Long loginUserId) { + if (Objects.isNull(params.getOrders())) { + throw new CoolException("涓诲崟淇℃伅涓嶈兘涓虹┖"); + } + AsnOrder orders = params.getOrders(); + if (Objects.isNull(orders)) { + throw new CoolException("鍗曟嵁涓嶈兘涓虹┖锛侊紒"); + } + String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_OUT_STOCK_CODE, orders); + if (Objects.isNull(ruleCode) || StringUtils.isBlank(ruleCode)) { + throw new CoolException("缂栫爜瑙勫垯閿欒锛氳妫�鏌ャ�孲YS_OUT_STOCK_CODE銆嶆槸鍚﹁缃纭紒锛�"); + } + orders.setCode(ruleCode) + .setUpdateBy(loginUserId) + .setCreateBy(loginUserId); + if (!this.save(orders)) { + throw new CoolException("涓诲崟淇濆瓨澶辫触锛侊紒"); + } + if (params.getItems().isEmpty()) { + throw new CoolException("鏀惰揣閫氱煡鍗曟槑缁嗕笉鑳戒负瀵掗鑺傦紒锛�"); + } + +// svaeOrUpdateOrderItem(params,loginUserId); + + + + return null; + } + + /** + * @author Ryan + * @description 淇敼涓诲崟鍙婃槑缁� + * @param + * @return + * @time 2025/4/29 13:47 + */ + @Override + public R updateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) { + return null; + } + + /** * @param * @param wave * @return diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java index f070e5f..73b2acd 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java @@ -1,6 +1,7 @@ package com.vincent.rsf.server.manager.service.impl; import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -17,6 +18,7 @@ import com.vincent.rsf.server.manager.utils.OptimalAlgorithmUtil; import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.utils.SerialRuleUtils; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +28,7 @@ import java.util.*; import java.util.stream.Collectors; +@Slf4j @Service("waveService") public class WaveServiceImpl extends ServiceImpl<WaveMapper, Wave> implements WaveService { @@ -59,39 +62,40 @@ if (Objects.isNull(itemParams) || itemParams.isEmpty()) { throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒"); } - Wave wave = (Wave) map.get("wave"); - Wave waves = this.getById(new LambdaQueryWrapper<Wave>().in(Wave::getId, wave.getId())); + List<WaveItem> items = JSONArray.parseArray(JSONArray.toJSONString(itemParams), WaveItem.class); + String waveId = map.get("wave").toString(); + Wave waves = this.getById(Long.parseLong(waveId)); if (Objects.isNull(waves)) { throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦紒锛�"); } - List<Long> list = itemParams.stream().map(WaveItem::getWaveId).collect(Collectors.toList()); - List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>().in(WaveItem::getWaveId, list)); +// List<Long> list = itemParams.stream().map(WaveItem::getWaveId).collect(Collectors.toList()); + List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>().eq(WaveItem::getWaveId, waves.getId())); if (waveItems.isEmpty()) { throw new CoolException("娉㈡鏄庣粏涓嶅瓨鍦紒锛�"); } /**鐢熸垚鍑哄簱浠诲姟*/ try { - generateOutTask(itemParams, loginUserId, wave); + generateOutTask(items, loginUserId, waves); } catch (Exception e) { - throw new CoolException("搴撲綅鑾峰彇澶辫触锛侊紒锛�"); + log.error(e.getMessage()); + throw new CoolException("鍑哄簱浠诲姟鐢熸垚澶辫触锛侊紒锛�"); } //TODO 1. 鏍规嵁娉㈡鏄庣粏鐢熸垚鍑哄簱浠诲姟 // 2. 鏍规嵁鐗╂枡SKU瀵绘壘绗﹀悎鐗╂枡搴撲綅 {1. 鏍规嵁鐗╂枡缂栫爜锛屾壒娆★紝鍔ㄦ�佸瓧娈� 鏌ヨ绗﹀悎鐨勫簱浣嶏紝鍐嶆牴鎹簱浣嶄腑鐗╂枡鐨勬暟閲忛�夋嫨鏈�閫傚悎鐨勫簱浣� 2. 鍒ゆ柇褰撳墠璁㈠崟鏄叏鎷栧嚭搴撹繕鏄嫞鏂欏叆搴搣 // 3. 淇敼涓诲崟銆佹尝娆℃墽琛屾暟閲� // 4. 鍒ゆ柇鍏ㄤ粨鍑哄簱鎴栨嫞鏂欏嚭搴� List<Long> orderIds = waveItems.stream().map(WaveItem::getOrderId).collect(Collectors.toList()); - - List<AsnOrder> orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, orderIds)); +// List<AsnOrder> orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, orderIds)); /**淇敼鍑哄簱鍗曠姸鎬�*/ - if (!asnOrderService.update(new LambdaQueryWrapper<AsnOrder>() - .eq(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) - .in(AsnOrder::getId, orders))) { + if (!asnOrderService.update(new LambdaUpdateWrapper<AsnOrder>() + .set(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) + .in(AsnOrder::getId, orderIds))) { throw new CoolException("鍑哄簱鍗曟嵁鐘舵�佷慨鏀瑰け璐ワ紒锛�"); } - /**淇敼娉㈡鍗曟嵁鎵ц鐘舵��*/ - if (!this.update(new LambdaUpdateWrapper<Wave>().set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK).eq(Wave::getId, wave.getId()))) { - throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�"); - } +// /**淇敼娉㈡鍗曟嵁鎵ц鐘舵��*/ +// if (!this.update(new LambdaUpdateWrapper<Wave>().set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK).eq(Wave::getId, waves.getId()))) { +// throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�"); +// } return R.ok(); } @@ -113,7 +117,7 @@ if (locItems.isEmpty()) { continue; } - List<Long> list = locItems.stream().map(LocItem::getId).collect(Collectors.toList()); + List<Long> list = locItems.stream().map(LocItem::getLocId).collect(Collectors.toList()); /**鏍规嵁渚涘簲鍟嗘壒娆★紝鐗╂枡鐮侊紝 鍔ㄦ�佸瓧娈垫煡璇㈡寚瀹氱殑鐗╂枡搴撳瓨淇℃伅*/ List<LocItem> items = locItemService.list(new LambdaQueryWrapper<LocItem>() .eq(LocItem::getSplrBatch, param.getSplrBatch()) @@ -185,7 +189,7 @@ /**淇敼娉㈡鎵ц鏁伴噺*/ taskItems.forEach(item -> { boolean update = waveItemService.update(new LambdaUpdateWrapper<WaveItem>() - .eq(WaveItem::getWaveId, item.getSource()) + .eq(WaveItem::getId, item.getSource()) .set(WaveItem::getWorkQty, item.getAnfme())); if (!update) { throw new CoolException("娉㈡鎵ц鏁伴噺淇敼澶辫触锛侊紒"); @@ -195,7 +199,7 @@ List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>().eq(WaveItem::getWaveId, wave.getId())); double sum = waveItems.stream().mapToDouble(WaveItem::getWorkQty).sum(); /**娉㈡涓诲崟淇℃伅淇敼*/ - if (!update(new LambdaUpdateWrapper<Wave>() + if (!this.update(new LambdaUpdateWrapper<Wave>() .eq(Wave::getId, wave.getId()) .set(Wave::getWorkQty, sum) .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val))) { -- Gitblit v1.9.1