From baa5bdca332564deef950002f2cc0d4d061cf3fa Mon Sep 17 00:00:00 2001 From: verou <857149855@qq.com> Date: 星期二, 18 三月 2025 14:25:26 +0800 Subject: [PATCH] feat:物料批量操作 --- rsf-admin/src/page/basicInfo/loc/InitModal.jsx | 14 +- rsf-admin/src/page/basicInfo/loc/BatchModal.jsx | 67 +++++++---- rsf-admin/src/page/basicInfo/matnr/BatchModal.jsx | 151 +++++++++++++++++++++++++ rsf-admin/src/page/components/DictionarySelect.jsx | 3 rsf-admin/src/page/components/StatusSelectInput.jsx | 7 rsf-admin/src/i18n/zh.js | 1 rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx | 27 ++++ rsf-admin/src/i18n/en.js | 1 rsf-admin/.env | 4 rsf-admin/src/page/basicInfo/loc/LocList.jsx | 38 ----- rsf-admin/src/page/asnOrder/AsnOrderModal.jsx | 22 +- 11 files changed, 250 insertions(+), 85 deletions(-) diff --git a/rsf-admin/.env b/rsf-admin/.env index 9669b2c..a8ce658 100644 --- a/rsf-admin/.env +++ b/rsf-admin/.env @@ -1,3 +1,3 @@ -# VITE_BASE_IP=192.168.4.24 -VITE_BASE_IP=47.76.147.249 +VITE_BASE_IP=192.168.4.24 +# VITE_BASE_IP=47.76.147.249 VITE_BASE_PORT=8080 diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js index f0994e2..f338b7e 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -353,6 +353,7 @@ maxPack: "MaxPack", flagLabelMange: "FlagLabelMange", locAttrs: "LocAttrs", + useStatus: 'useStatus' }, container: { code: "Code", diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 0b3480c..3b6756e 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -352,6 +352,7 @@ startBay: "璧峰鍒�", startLev: "璧峰灞�", startRow: "璧峰鎺�", + useStatus: '搴撲綅鐘舵��' }, container: { diff --git a/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx b/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx index 1b23e74..01da591 100644 --- a/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx +++ b/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx @@ -53,6 +53,7 @@ import { Add, Edit, Delete } from '@mui/icons-material'; import _ from 'lodash'; import { DataGrid } from '@mui/x-data-grid'; +import DictionarySelect from "../components/DictionarySelect"; const AsnOrderModal = (props) => { const { open, setOpen, asnId } = props; @@ -84,8 +85,8 @@ const [tabelData, setTableData] = useState([]); - const handleChange = (e) => { - const { name, value } = e.target; + + const handleChange = (value, name) => { setFormData((prevData) => ({ ...prevData, [name]: value @@ -171,20 +172,19 @@ </Box> </DialogTitle> <DialogContent sx={{ mt: 2 }}> - <Box component="form" sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> - <form> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form> <Grid container spacing={2}> <Grid item xs={4}> - <TextField - label={translate('table.field.asnOrder.type')} + <DictionarySelect + label={translate("table.field.asnOrder.type")} name="type" value={formData.type} - onChange={handleChange} - onBlur={requestSetHead} - variant="outlined" + onChange={(e) => handleChange(+e.target.value, 'type')} size="small" - required + dictTypeCode="sys_bill_type" /> + </Grid> {/* <Grid item xs={4}> @@ -198,7 +198,7 @@ /> </Grid> */} </Grid> - </form> + </Form> </Box> <Box sx={{ mt: 2 }}> diff --git a/rsf-admin/src/page/basicInfo/loc/BatchModal.jsx b/rsf-admin/src/page/basicInfo/loc/BatchModal.jsx index 5e9cfb7..a3448a2 100644 --- a/rsf-admin/src/page/basicInfo/loc/BatchModal.jsx +++ b/rsf-admin/src/page/basicInfo/loc/BatchModal.jsx @@ -50,7 +50,7 @@ import { Add, Edit, Delete } from '@mui/icons-material'; import _ from 'lodash'; import { DataGrid } from '@mui/x-data-grid'; - +import StatusSelectInput from "../../components/StatusSelectInput"; @@ -62,16 +62,28 @@ const notify = useNotify(); const [formData, setFormData] = useState({ - "areaId": undefined, - "locType": "", - "type": "" + "areaId": null, + "type": null, + 'status': null }); + + const { selectedIds } = useListContext(); const handleClose = (event, reason) => { if (reason !== "backdropClick") { setOpen(false); + reset() + refresh(); } }; + + const reset = () => { + setFormData({ + "areaId": null, + "type": null, + 'status': null + }) + } const handleReset = (e) => { e.preventDefault(); @@ -80,20 +92,34 @@ const handleChange = (value, name) => { setFormData((prevData) => ({ ...prevData, - [name]: ['locType', 'type'].includes(name) ? value : +value + [name]: value })); }; + const removeEmptyKeys = (obj) => { + return _.pickBy(obj, (value) => { + if (_.isObject(value)) { + const newObj = removeEmptyKeys(value); + return !_.isEmpty(newObj); + } + return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value)); + }); + } + const handleSubmit = async () => { - const res = await request.post(`/loc/init`, formData); + const parmas = { + id: selectedIds, + loc: removeEmptyKeys(formData) + } + + const res = await request.post(`/loc/modify`, parmas); if (res?.data?.code === 200) { - setOpen(false); - refresh(); + handleClose() + } else { notify(res.data.msg); } } - return ( <Dialog open={open} maxWidth="md" fullWidth> @@ -113,7 +139,6 @@ optionText="name" onChange={(value) => handleChange(value, 'areaId')} value={formData.areaId} - validate={[required()]} filterToQuery={(val) => ({ name: val })} /> </ReferenceInput> @@ -122,28 +147,22 @@ <Grid item xs={4}> <DictionarySelect - label={translate("table.field.loc.locType")} - name="locType" - value={formData.locType} - onChange={(e) => handleChange(e.target.value, 'locType')} - size="small" - validate={[required()]} - dictTypeCode="sys_width_type" - /> - </Grid> - - <Grid item xs={4}> - <DictionarySelect label={translate("table.field.loc.type")} name="type" value={formData.type} - onChange={(e) => handleChange(e.target.value, 'type')} + onChange={(e) => handleChange(+e.target.value, 'type')} size="small" - validate={[required()]} dictTypeCode="sys_loc_type" /> </Grid> + <Grid item xs={4}> + <StatusSelectInput + onChange={(e) => handleChange(e.target.value, 'status')} + defaultValue={''} + require={false} + /> + </Grid> </Grid> diff --git a/rsf-admin/src/page/basicInfo/loc/InitModal.jsx b/rsf-admin/src/page/basicInfo/loc/InitModal.jsx index f0c4c48..15156ca 100644 --- a/rsf-admin/src/page/basicInfo/loc/InitModal.jsx +++ b/rsf-admin/src/page/basicInfo/loc/InitModal.jsx @@ -86,7 +86,7 @@ const handleChange = (value, name) => { setFormData((prevData) => ({ ...prevData, - [name]: ['locType', 'type'].includes(name) ? value : +value + [name]: value })); }; @@ -155,7 +155,7 @@ label={translate("table.field.loc.startBay")} name="startBay" value={formData.startBay} - onChange={(e) => handleChange(e.target.value, 'startBay')} + onChange={(e) => handleChange(+e.target.value, 'startBay')} size="small" type="number" validate={[required()]} @@ -167,7 +167,7 @@ label={translate("table.field.loc.startLev")} name="startLev" value={formData.startLev} - onChange={(e) => handleChange(e.target.value, 'startLev')} + onChange={(e) => handleChange(+e.target.value, 'startLev')} size="small" type="number" validate={[required()]} @@ -179,7 +179,7 @@ label={translate("table.field.loc.startRow")} name="startRow" value={formData.startRow} - onChange={(e) => handleChange(e.target.value, 'startRow')} + onChange={(e) => handleChange(+e.target.value, 'startRow')} size="small" type="number" validate={[required()]} @@ -191,7 +191,7 @@ label={translate("table.field.loc.endBay")} name="endBay" value={formData.endBay} - onChange={(e) => handleChange(e.target.value, 'endBay')} + onChange={(e) => handleChange(+e.target.value, 'endBay')} size="small" type="number" validate={[required()]} @@ -203,7 +203,7 @@ label={translate("table.field.loc.endLev")} name="endLev" value={formData.endLev} - onChange={(e) => handleChange(e.target.value, 'endLev')} + onChange={(e) => handleChange(+e.target.value, 'endLev')} size="small" type="number" validate={[required()]} @@ -215,7 +215,7 @@ label={translate("table.field.loc.endRow")} name="endRow" value={formData.endRow} - onChange={(e) => handleChange(e.target.value, 'endRow')} + onChange={(e) => handleChange(+e.target.value, 'endRow')} size="small" type="number" validate={[required()]} diff --git a/rsf-admin/src/page/basicInfo/loc/LocList.jsx b/rsf-admin/src/page/basicInfo/loc/LocList.jsx index b9b2578..c64bbb7 100644 --- a/rsf-admin/src/page/basicInfo/loc/LocList.jsx +++ b/rsf-admin/src/page/basicInfo/loc/LocList.jsx @@ -142,7 +142,7 @@ } rowClick={() => false} expand={() => <LocPanel />} - omit={['id', 'createTime', 'createBy', 'memo']} + omit={['id', 'createTime', 'createBy', 'memo', 'updateTime', 'updateBy']} > <NumberField source="id" /> <NumberField source="warehouseId$" label="table.field.loc.warehouseId" /> @@ -228,8 +228,7 @@ const record = useRecordContext(); const notify = useNotify(); const refresh = useRefresh(); - const { selectedIds } = useListContext(); - console.log(selectedIds) + const [createDialog, setCreateDialog] = useState(false); @@ -246,35 +245,4 @@ </> ) -} -const CustomBulkActionButton = () => { - const { selectedIds } = useListContext(); - const notify = useNotify(); - const refresh = useRefresh(); - - const handleCustomBulkAction = async () => { - if (selectedIds.length === 0) { - notify('璇烽�夋嫨瑕佹搷浣滅殑璁板綍'); - return; - } - // 杩欓噷鍐欏叿浣撶殑鎵归噺鎿嶄綔閫昏緫锛屼緥濡傚悜鏈嶅姟鍣ㄥ彂閫佽姹� - try { - const res = await request.post('/loc/bulk-action', { ids: selectedIds }); - if (res?.data?.code === 200) { - refresh(); - notify('鎵归噺鎿嶄綔鎴愬姛'); - } else { - notify(res.data.msg); - } - } catch (error) { - notify('鎵归噺鎿嶄綔澶辫触锛岃绋嶅悗閲嶈瘯'); - } - }; - - return ( - <Button onClick={handleCustomBulkAction} label="鑷畾涔夋壒閲忔搷浣�"> - {/* 鍙互娣诲姞鑷畾涔夊浘鏍� */} - <EditIcon /> - </Button> - ); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/matnr/BatchModal.jsx b/rsf-admin/src/page/basicInfo/matnr/BatchModal.jsx new file mode 100644 index 0000000..c185cbf --- /dev/null +++ b/rsf-admin/src/page/basicInfo/matnr/BatchModal.jsx @@ -0,0 +1,151 @@ +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, + Grid, + TextField, + Box, + Button, + Paper, + TableContainer, + Table, + TableHead, + TableBody, + TableRow, + TableCell, + Tooltip, + IconButton, + styled + + +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import DictionarySelect from "../../components/DictionarySelect"; +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 _ from 'lodash'; +import { DataGrid } from '@mui/x-data-grid'; +import StatusSelectInput from "../../components/StatusSelectInput"; + + + +const InitModal = ({ open, setOpen }) => { + const refresh = useRefresh(); + const translate = useTranslate(); + + + const notify = useNotify(); + + const [formData, setFormData] = useState({ + 'status': null + }); + + const { selectedIds } = useListContext(); + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + reset() + refresh(); + } + }; + + const reset = () => { + setFormData({ + 'status': null + }) + } + + const handleReset = (e) => { + e.preventDefault(); + }; + + const handleChange = (value, name) => { + setFormData((prevData) => ({ + ...prevData, + [name]: ['locType', 'type'].includes(name) ? value : +value + })); + }; + + const removeEmptyKeys = (obj) => { + return _.pickBy(obj, (value) => { + if (_.isObject(value)) { + const newObj = removeEmptyKeys(value); + return !_.isEmpty(newObj); + } + return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value)); + }); + } + + const handleSubmit = async () => { + const parmas = { + id: selectedIds, + matnr: removeEmptyKeys(formData) + } + + const res = await request.post(`/matnr/modify`, parmas); + if (res?.data?.code === 200) { + handleClose() + + } else { + notify(res.data.msg); + } + } + + return ( + <Dialog open={open} maxWidth="md" fullWidth> + <Form onSubmit={handleSubmit}> + <DialogCloseButton onClose={handleClose} /> + <DialogTitle>{translate('toolbar.batch')}</DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Grid container spacing={2}> + <Grid item xs={4}> + <StatusSelectInput + onChange={(e) => handleChange(e.target.value, 'status')} + defaultValue={''} + require={false} + /> + </Grid> + </Grid> + + </Box> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}> + <Button type="submit" variant="contained" startIcon={<SaveIcon />}> + 纭 + </Button> + </Box> + </DialogActions> + </Form> + </Dialog> + ); +} + +export default InitModal; \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx b/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx index 4182da5..90889d9 100644 --- a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx +++ b/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx @@ -50,7 +50,9 @@ import MatListAside from './MatnrListAside'; import { display, height } from "@mui/system"; import DashboardIcon from '@mui/icons-material/Dashboard'; +import EditIcon from '@mui/icons-material/Edit'; import request from '@/utils/request'; +import BatchModal from './BatchModal'; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -162,7 +164,7 @@ <StyledDatagrid preferenceKey='matnr' - bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} + bulkActionButtons={<> <BatchButton /><BulkDeleteButton mutationMode={OPERATE_MODE} /></>} rowClick={(id, resource, record) => false} expand={() => <MatnrPanel />} expandSingle={true} @@ -304,4 +306,27 @@ </Button>) ) +} + +const BatchButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + + + const [createDialog, setCreateDialog] = useState(false); + + return ( + <> + <Button onClick={() => setCreateDialog(true)} label={"toolbar.batch"}> + <EditIcon /> + </Button> + + <BatchModal + open={createDialog} + setOpen={setCreateDialog} + /> + </> + + ) } \ No newline at end of file diff --git a/rsf-admin/src/page/components/DictionarySelect.jsx b/rsf-admin/src/page/components/DictionarySelect.jsx index 43dc811..2523c5d 100644 --- a/rsf-admin/src/page/components/DictionarySelect.jsx +++ b/rsf-admin/src/page/components/DictionarySelect.jsx @@ -9,7 +9,6 @@ const DictionarySelect = (props) => { const { dictTypeCode, name, ...parmas } = props; - const { selectedIds } = useListContext(); const translate = useTranslate(); const notify = useNotify(); const [list, setList] = useState([]) @@ -25,7 +24,7 @@ setList(res.data.data.records.map((item) => { return { id: item.value, - name: item.value + name: item.label } })) } else { diff --git a/rsf-admin/src/page/components/StatusSelectInput.jsx b/rsf-admin/src/page/components/StatusSelectInput.jsx index 46f787c..11031ca 100644 --- a/rsf-admin/src/page/components/StatusSelectInput.jsx +++ b/rsf-admin/src/page/components/StatusSelectInput.jsx @@ -5,20 +5,21 @@ } from 'react-admin'; const StatusSelectInput = (props) => { + const { require = true, defaultValue = 1, ...rest } = props const translate = useTranslate(); return ( <SelectInput label={translate('common.field.status')} source="status" - validate={[required()]} + validate={[require && required()]} choices={[ { id: '1', name: 'common.enums.statusTrue' }, { id: '0', name: 'common.enums.statusFalse' }, ]} - defaultValue={1} + defaultValue={defaultValue} helperText={false} - {...props} + {...rest} /> ) } -- Gitblit v1.9.1