From 031e36213941ad3430da2b0429701e742f09f5d8 Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期二, 18 三月 2025 11:14:20 +0800 Subject: [PATCH] Merge branch 'front' into devlop --- rsf-admin/src/page/asnOrder/AsnOrderList.jsx | 36 + rsf-admin/src/page/components/BatchButton.jsx | 31 + rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx | 58 ++- rsf-admin/src/page/components/TooltipField.jsx | 28 + rsf-admin/src/page/basicInfo/whMat/WhMatList.jsx | 2 rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx | 21 + rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx | 2 rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx | 4 rsf-admin/src/page/basicInfo/loc/InitButton.jsx | 74 ++++ rsf-admin/src/page/basicInfo/loc/LocList.jsx | 44 ++ rsf-admin/src/page/basicInfo/loc/InitModal.jsx | 241 +++++++++++++++ rsf-admin/src/page/basicInfo/loc/LocCreate.jsx | 46 ++ rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx | 10 rsf-admin/src/page/components/BatchModal.jsx | 65 ++++ rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx | 4 rsf-admin/src/page/components/DictionarySelect.jsx | 45 ++ rsf-admin/src/i18n/zh.js | 20 + rsf-admin/src/page/basicInfo/loc/LocEdit.jsx | 41 + rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx | 115 +++++-- rsf-admin/src/i18n/en.js | 14 rsf-admin/.env | 4 rsf-admin/src/page/asnOrder/AsnOrderModal.jsx | 2 22 files changed, 799 insertions(+), 108 deletions(-) diff --git a/rsf-admin/.env b/rsf-admin/.env index ebc08a7..9669b2c 100644 --- a/rsf-admin/.env +++ b/rsf-admin/.env @@ -1,3 +1,3 @@ -VITE_BASE_IP=localhost -# 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 4596053..602630c 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -68,6 +68,7 @@ deprecate: 'Deprecate', resend: 'RESEND', selected: 'selected', + batch: 'batch' }, msg: { confirm: { @@ -143,6 +144,13 @@ fields: 'Extend Fields', fieldsItem: 'Extend Fields Items', warehouseAreasItem: 'WarehouseAreasItem', + endBay: "endBay", + endLev: "endLev", + endRow: "endRow", + locType: "locType", + startBay: "startBay", + startLev: "startLev", + startRow: "startRow", }, table: { field: { @@ -334,6 +342,9 @@ barcode: "Barcode", unit: "Unit", size: "Size", + length: "length", + width: "width", + height: "height", row: "Row", col: "Col", lev: "Lev", @@ -596,6 +607,9 @@ inspection: "Inspection", creatcode: "creatcode", print: "print", + enable: 'enable', + unenable: 'unenable', + locInit: 'loc init' }, }; diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 8c533da..889ea39 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -68,6 +68,7 @@ deprecate: '搴熷純', resend: '閲嶅彂', selected: '椤归�変腑', + batch: '鎵归噺缂栬緫' }, msg: { confirm: { @@ -121,7 +122,7 @@ userLogin: '鐧诲綍鏃ュ織', customer: '瀹㈡埛琛�', shipper: '璐т富淇℃伅', - matnr: '鐗╂枡琛�', + matnr: '鐗╂枡鏁版嵁', matnrGroup: '鐗╂枡鍒嗙粍', warehouse: '浠撳簱淇℃伅', warehouseAreas: '浠撳簱搴撳尯', @@ -280,7 +281,7 @@ matnrGroup: { name: "鍚嶇О", code: "缂栫爜", - parentId: "鐖剁被鏍囪瘑", + parentId: "涓婄骇鏍囪瘑", }, warehouse: { name: "浠撳簱鍚嶇О", @@ -326,13 +327,16 @@ warehouseId: "浠撳簱", areaId: "搴撳尯", code: "缂栫爜", - type: "绫诲瀷", + type: "搴撲綅绫诲瀷", name: "鍚嶇О", flagLogic: "铏氭嫙搴撲綅", fucAtrrs: "鍔熻兘灞炴��", barcode: "瀹瑰櫒鐮�", unit: "鍗曚綅", size: "闀�/瀹�/楂�", + length: "闀�", + width: "瀹�", + height: "楂�", row: "鎺�", col: "鍒�", lev: "灞�", @@ -341,6 +345,13 @@ maxPack: "鏈�澶у寘瑁呮暟", flagLabelMange: "鏍囩绠$悊", locAttrs: "灞炴��", + endBay: "缁堟鍒�", + endLev: "缁堟灞�", + endRow: "缁堟鎺�", + locType: "瀹界獎绫诲瀷", + startBay: "璧峰鍒�", + startLev: "璧峰灞�", + startRow: "璧峰鎺�", }, container: { @@ -598,6 +609,9 @@ inspection: "鎶ユ", creatcode: "鐢熸垚鏉$爜", print: "鎵撳嵃", + enable: '鍚敤', + unenable: '绂佺敤', + locInit: '聽搴撲綅鍒濆鍖�' }, }; diff --git a/rsf-admin/src/page/asnOrder/AsnOrderList.jsx b/rsf-admin/src/page/asnOrder/AsnOrderList.jsx index 96dbf12..095bde5 100644 --- a/rsf-admin/src/page/asnOrder/AsnOrderList.jsx +++ b/rsf-admin/src/page/asnOrder/AsnOrderList.jsx @@ -109,7 +109,32 @@ const inspection = () => { }; - const print = () => { }; + + const print = () => { + const imageUrls = ['https://www.baidu.com/img/flexible/logo/pc/result@2.png',] + const iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + document.body.appendChild(iframe); + + const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; + iframeDoc.open(); + iframeDoc.write('<html><head><title>Print Images</title></head><body>'); + + // 灏嗗浘鐗囨彃鍏ュ埌 iframe 涓� + imageUrls.forEach((imageUrl) => { + iframeDoc.write(`<img src="${imageUrl}" style="margin: 10px;">`); + }); + + iframeDoc.write('</body></html>'); + iframeDoc.close(); + + // 绛夊緟鍥剧墖鍔犺浇瀹屾垚鍚庤Е鍙戞墦鍗� + iframe.contentWindow.onload = () => { + iframe.contentWindow.print(); + // 鎵撳嵃瀹屾垚鍚庣Щ闄� iframe + document.body.removeChild(iframe); + }; + }; return ( @@ -151,14 +176,7 @@ omit={['id', 'createTime', 'createBy', 'memo']} > <NumberField source="id" /> - <MyField - source="code" - label="table.field.asnOrder.code" - onClick={(event, record, val) => { - event.stopPropagation(); - assign(record); - }} - /> + <TextField source="code" label="table.field.asnOrder.code" /> <TextField source="poCode" label="table.field.asnOrder.poCode" /> <NumberField source="poId" label="table.field.asnOrder.poId" /> <TextField source="type" label="table.field.asnOrder.type" /> diff --git a/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx b/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx index 2942d22..1b23e74 100644 --- a/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx +++ b/rsf-admin/src/page/asnOrder/AsnOrderModal.jsx @@ -183,7 +183,7 @@ onBlur={requestSetHead} variant="outlined" size="small" - validate={required()} + required /> </Grid> diff --git a/rsf-admin/src/page/basicInfo/loc/InitButton.jsx b/rsf-admin/src/page/basicInfo/loc/InitButton.jsx new file mode 100644 index 0000000..e3dd2e3 --- /dev/null +++ b/rsf-admin/src/page/basicInfo/loc/InitButton.jsx @@ -0,0 +1,74 @@ +import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; +import { useNavigate } from 'react-router-dom'; +import { + List, + DatagridConfigurable, + SearchInput, + TopToolbar, + SelectColumnsButton, + EditButton, + FilterButton, + CreateButton, + ExportButton, + BulkDeleteButton, + WrapperField, + useRecordContext, + useTranslate, + useNotify, + useListContext, + FunctionField, + TextField, + NumberField, + DateField, + BooleanField, + ReferenceField, + TextInput, + DateTimeInput, + DateInput, + SelectInput, + NumberInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + DeleteButton, + useRefresh, + Button +} from 'react-admin'; +import { Box, Typography, Card, Stack } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import InitModal from "./InitModal"; +import LocPanel from "./LocPanel"; +import EmptyData from "../../components/EmptyData"; +import MyCreateButton from "../../components/MyCreateButton"; +import MyExportButton from '../../components/MyExportButton'; +import BatchButton from '../../components/BatchButton'; +import PageDrawer from "../../components/PageDrawer"; +import MyField from "../../components/MyField"; +import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; +import * as Common from '@/utils/common'; +import DashboardIcon from '@mui/icons-material/Dashboard'; +import request from '@/utils/request'; +import CabinIcon from '@mui/icons-material/Cabin'; + +const InitButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + + const [createDialog, setCreateDialog] = useState(false); + // console.log(record) + + return (<> + <Button onClick={() => setCreateDialog(true)} label={"toolbar.locInit"}> + <CabinIcon /> + </Button> + <InitModal + open={createDialog} + setOpen={setCreateDialog} + /> + </> + + ) +} + +export default InitButton; \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/loc/InitModal.jsx b/rsf-admin/src/page/basicInfo/loc/InitModal.jsx new file mode 100644 index 0000000..ed84903 --- /dev/null +++ b/rsf-admin/src/page/basicInfo/loc/InitModal.jsx @@ -0,0 +1,241 @@ +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'; + + + + +const InitModal = ({ open, setOpen }) => { + const refresh = useRefresh(); + const translate = useTranslate(); + + + const notify = useNotify(); + + const [formData, setFormData] = useState({ + "areaId": undefined, + "endBay": undefined, + "endLev": undefined, + "endRow": undefined, + "locType": "", + "startBay": undefined, + "startLev": undefined, + "startRow": undefined, + "type": "" + }); + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const handleReset = (e) => { + e.preventDefault(); + }; + + const handleChange = (value, name) => { + setFormData((prevData) => ({ + ...prevData, + [name]: ['locType', 'type'].includes(name) ? value : +value + })); + }; + + const handleSubmit = async () => { + const res = await request.post(`/loc/init`, formData); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + } else { + notify(res.data.msg); + } + } + + + return ( + <Dialog open={open} maxWidth="md" fullWidth> + <DialogCloseButton onClose={handleClose} /> + <DialogTitle>{translate('toolbar.locInit')}</DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form> + + <Grid container spacing={2}> + <Grid item xs={4}> + <ReferenceInput + source="areaId" + reference="warehouseAreas" + > + <AutocompleteInput + label="table.field.loc.areaId" + optionText="name" + onChange={(value) => handleChange(value, 'areaId')} + value={formData.areaId} + validate={[required()]} + filterToQuery={(val) => ({ name: val })} + /> + </ReferenceInput> + + </Grid> + + <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')} + size="small" + validate={[required()]} + dictTypeCode="sys_loc_type" + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.startBay")} + name="startBay" + value={formData.startBay} + onChange={(e) => handleChange(e.target.value, 'startBay')} + size="small" + type="number" + required + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.startLev")} + name="startLev" + value={formData.startLev} + onChange={(e) => handleChange(e.target.value, 'startLev')} + size="small" + type="number" + required + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.startRow")} + name="startRow" + value={formData.startRow} + onChange={(e) => handleChange(e.target.value, 'startRow')} + size="small" + type="number" + required + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.endBay")} + name="endBay" + value={formData.endBay} + onChange={(e) => handleChange(e.target.value, 'endBay')} + size="small" + type="number" + required + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.endLev")} + name="endLev" + value={formData.endLev} + onChange={(e) => handleChange(e.target.value, 'endLev')} + size="small" + type="number" + required + /> + </Grid> + + <Grid item xs={4}> + <TextField + label={translate("table.field.loc.endRow")} + name="endRow" + value={formData.endRow} + onChange={(e) => handleChange(e.target.value, 'endRow')} + size="small" + type="number" + required + /> + </Grid> + + </Grid> + </Form> + </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 />}> + 纭 + </Button> + </Box> + </DialogActions> + </Dialog> + ); +} + +export default InitModal; \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx b/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx index 831412b..0602179 100644 --- a/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx +++ b/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx @@ -119,20 +119,27 @@ /> </Grid> <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.loc.type" + <ReferenceInput source="type" - parse={v => v} - validate={required()} - /> + reference="dictData" + filter={{ dictTypeCode: 'sys_loc_type' }} + > + <AutocompleteInput + label="table.field.loc.type" + optionText="label" + optionValue="value" + parse={v => v} + validate={[required()]} + /> + </ReferenceInput> </Grid> - <Grid item xs={6} display="flex" gap={1}> + {/* <Grid item xs={6} display="flex" gap={1}> <TextInput label="table.field.loc.name" source="name" parse={v => v} /> - </Grid> + </Grid> */} <Grid item xs={6} display="flex" gap={1}> <NumberInput label="table.field.loc.flagLogic" @@ -153,24 +160,41 @@ parse={v => v} /> </Grid> - <Grid item xs={6} display="flex" gap={1}> + {/* <Grid item xs={6} display="flex" gap={1}> <TextInput label="table.field.loc.unit" source="unit" parse={v => v} /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> + </Grid> */} + {/* <Grid item xs={6} display="flex" gap={1}> <TextInput label="table.field.loc.size" source="size" parse={v => v} /> + </Grid> */} + <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.loc.length" + source="length" + validate={required()} + /> + <NumberInput + label="table.field.loc.width" + source="width" + validate={required()} + /> + <NumberInput + label="table.field.loc.height" + source="height" + validate={required()} + /> </Grid> <Grid item xs={6} display="flex" gap={1}> <NumberInput label="table.field.loc.row" - source="lrow" + source="row" validate={required()} /> <NumberInput diff --git a/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx b/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx index c8c7fcb..3ea6793 100644 --- a/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx +++ b/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx @@ -66,7 +66,7 @@ <Grid container rowSpacing={2} columnSpacing={2}> <Grid item xs={6} display="flex" gap={1}> <ReferenceInput - source="warehouseId$" + source="warehouseId" reference="warehouse" > <AutocompleteInput @@ -99,12 +99,19 @@ /> </Grid> <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.loc.type" + <ReferenceInput source="type" - parse={v => v} - validate={required()} - /> + reference="dictData" + filter={{ dictTypeCode: 'sys_loc_type' }} + > + <AutocompleteInput + label="table.field.loc.type" + optionText="label" + optionValue="value" + parse={v => v} + validate={[required()]} + /> + </ReferenceInput> </Grid> <Grid item xs={6} display="flex" gap={1}> <TextInput @@ -141,10 +148,24 @@ /> </Grid> <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.loc.size" - source="size" - parse={v => v} + <NumberInput + label="table.field.loc.length" + source="length" + validate={required()} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.loc.width" + source="width" + validate={required()} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.loc.height" + source="height" + validate={required()} /> </Grid> <Grid item xs={6} display="flex" gap={1}> diff --git a/rsf-admin/src/page/basicInfo/loc/LocList.jsx b/rsf-admin/src/page/basicInfo/loc/LocList.jsx index 1980da5..fbbecc9 100644 --- a/rsf-admin/src/page/basicInfo/loc/LocList.jsx +++ b/rsf-admin/src/page/basicInfo/loc/LocList.jsx @@ -31,6 +31,8 @@ ReferenceArrayInput, AutocompleteInput, DeleteButton, + useRefresh, + Button } from 'react-admin'; import { Box, Typography, Card, Stack } from '@mui/material'; import { styled } from '@mui/material/styles'; @@ -39,10 +41,13 @@ import EmptyData from "../../components/EmptyData"; import MyCreateButton from "../../components/MyCreateButton"; import MyExportButton from '../../components/MyExportButton'; +import InitButton from './InitButton'; import PageDrawer from "../../components/PageDrawer"; import MyField from "../../components/MyField"; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; import * as Common from '@/utils/common'; +import DashboardIcon from '@mui/icons-material/Dashboard'; +import request from '@/utils/request'; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -60,8 +65,6 @@ const filters = [ <SearchInput source="condition" alwaysOn />, - <DateInput label='common.time.after' source="timeStart" alwaysOn />, - <DateInput label='common.time.before' source="timeEnd" alwaysOn />, <NumberField source="warehouseId$" label="table.field.loc.warehouseId" />, <NumberField source="areaId$" label="table.field.loc.areaId" />, @@ -100,6 +103,7 @@ const [createDialog, setCreateDialog] = useState(false); const [drawerVal, setDrawerVal] = useState(false); + return ( <Box display="flex"> <List @@ -109,7 +113,7 @@ theme.transitions.create(['all'], { duration: theme.transitions.duration.enteringScreen, }), - marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} title={"menu.loc"} empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} @@ -118,6 +122,7 @@ actions={( <TopToolbar> <FilterButton /> + <InitButton /> <MyCreateButton onClick={() => { setCreateDialog(true) }} /> <SelectColumnsButton preferenceKey='loc' /> <MyExportButton /> @@ -143,7 +148,9 @@ <TextField source="fucAtrrs" label="table.field.loc.fucAtrrs" /> <TextField source="barcode" label="table.field.loc.barcode" /> <TextField source="unit" label="table.field.loc.unit" /> - <TextField source="size" label="table.field.loc.size" /> + <TextField source="size" label="table.field.loc.length" /> + <TextField source="size" label="table.field.loc.width" /> + <TextField source="size" label="table.field.loc.height" /> <NumberField source="lrow" label="table.field.loc.row" /> <NumberField source="col" label="table.field.loc.col" /> <NumberField source="lev" label="table.field.loc.lev" /> @@ -164,7 +171,8 @@ <TextField source="memo" label="common.field.memo" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt"> <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> - <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> + {/* <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> */} + <EnableButton /> </WrapperField> </StyledDatagrid> </List> @@ -183,3 +191,29 @@ } export default LocList; + +const EnableButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const enable = async () => { + const res = await request.post('/loc/update', { + ...record, + status: +!record.status + }); + if (res?.data?.code === 200) { + refresh() + } else { + notify(res.data.msg); + } + } + return ( + record.status === 1 ? + (<Button onClick={enable} label={"toolbar.unenable"}> + <DashboardIcon /> + </Button>) : (<Button onClick={enable} label={"toolbar.enable"}> + <DashboardIcon /> + </Button>) + + ) +} diff --git a/rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx b/rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx index 47b56d9..98b87e4 100644 --- a/rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx +++ b/rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx @@ -94,7 +94,7 @@ // if (!values.shipperId) errors.shipperId = translate('form.matnr.shipper'); // if (!values.groupId) errors.groupId = translate('form.matnr.groupId'); // if (!values.code) errors.code = translate('form.matnr.code'); - + // return errors; // }; diff --git a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx b/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx index e2e4c63..901038b 100644 --- a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx +++ b/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx @@ -31,8 +31,11 @@ ReferenceArrayInput, AutocompleteInput, DeleteButton, + useRefresh, + Button + } from 'react-admin'; -import { Box, Typography, Card, Stack,LinearProgress } from '@mui/material'; +import { Box, Typography, Card, Stack, LinearProgress, Tooltip } from '@mui/material'; import { styled } from '@mui/material/styles'; import MatnrCreate from "./MatnrCreate"; import MatnrPanel from "./MatnrPanel"; @@ -40,33 +43,52 @@ import MyCreateButton from "@/page/components/MyCreateButton"; import MyExportButton from '@/page/components/MyExportButton'; import PageDrawer from "@/page/components/PageDrawer"; -import MyField from "@/page/components/MyField"; +import TooltipField from "@/page/components/TooltipField"; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; import * as Common from '@/utils/common'; import ImportButton from "../../components/ImportButton"; import MatListAside from './MatnrListAside'; +import { display, height } from "@mui/system"; +import DashboardIcon from '@mui/icons-material/Dashboard'; +import request from '@/utils/request'; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { height: '.9em' }, + '& .RaDatagrid-row': { cursor: 'auto' + }, + '& .RaList-content': { + width: '200px' + }, + '& .RaList-main': { + minHeight: '80vh' }, '& .column-name': { }, '& .opt': { width: 200 }, + '& .name': { + width: '100px', + + }, + '& .name .MuiTypography-root': { + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + display: 'block', + width: '100px', + } })); const filters = [ <SearchInput source="condition" alwaysOn />, - <DateInput label='common.time.after' source="timeStart" alwaysOn />, - <DateInput label='common.time.before' source="timeEnd" alwaysOn />, - <TextInput source="name" label="table.field.matnr.name" />, - <TextInput source="code" label="table.field.matnr.code" />, + <TextInput source="name" label="table.field.matnr.name" alwaysOn />, + <TextInput source="code" label="table.field.matnr.code" alwaysOn />, <ReferenceInput source="shipperId$" label="table.field.matnr.shipperId" reference="shipper"> <AutocompleteInput label="table.field.matnr.shipperId" optionText="name" filterToQuery={(val) => ({ name: val })} /> </ReferenceInput>, @@ -90,14 +112,14 @@ <SelectInput source="stockLeval" label="table.field.matnr.stockLevel" choices={[ { id: 0, name: ' A' }, - { id: 1, name: ' B' }, - { id: 2, name: 'C' }, + { id: 1, name: ' B' }, + { id: 2, name: 'C' }, ]} />, <SelectInput source="isLabelMange" label="table.field.matnr.isLabelMange" choices={[ { id: 0, name: ' 鍚�' }, - { id: 1, name: ' 鏄�' }, + { id: 1, name: ' 鏄�' }, ]} />, <NumberInput source="safeQty" label="table.field.matnr.safeQty" />, @@ -125,31 +147,33 @@ const { isLoading } = useListContext(); return ( - <Box sx={{ position: 'relative' }}> - {isLoading && ( - <LinearProgress - sx={{ - height: "2px", - position: 'absolute', - top: 0, - left: 0, - right: 0, - }} - /> - )} - <StyledDatagrid + <Box sx={{ position: 'relative', minHeight: "40vh", }}> + {isLoading && ( + <LinearProgress + sx={{ + height: "2px", + position: 'absolute', + top: 0, + left: 0, + right: 0, + }} + /> + )} + + <StyledDatagrid preferenceKey='matnr' bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} rowClick={(id, resource, record) => false} expand={() => <MatnrPanel />} expandSingle={true} - omit={['id','shipperId','platCode','spec','model','weight','color','size','describle' - ,'nromNum','unit','purchaseUnit','stockUnit','stockLeval','isLabelMange','safeQty' - ,'minQty','maxQty','stagn','valid','validWarn','flagCheck','updateTime', 'updateBy' - , 'createTime', 'createBy', 'memo']} + omit={['id', 'shipperId', 'platCode', 'spec', 'model', 'weight', 'color', 'size', 'describle' + , 'nromNum', 'unit', 'purchaseUnit', 'stockUnit', 'stockLeval', 'isLabelMange', 'safeQty' + , 'minQty', 'maxQty', 'stagn', 'valid', 'validWarn', 'flagCheck', 'updateTime', 'updateBy' + , 'createTime', 'createBy', 'memo', 'rglarId', 'groupId', 'stockLevel', 'isLabelMange']} > <NumberField source="id" /> - <TextField source="name" label="table.field.matnr.name" /> + + <TooltipField source="name" label="table.field.matnr.name" cellClassName="name" /> <TextField source="code" label="table.field.matnr.code" /> <ReferenceField source="shipperId" label="table.field.matnr.shipperId" reference="shipper" link={false} sortable={false}> <TextField source="name" /> @@ -193,12 +217,13 @@ <TextField source="memo" label="common.field.memo" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt"> <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> - <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> + {/* <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> */} + <EnableButton /> </WrapperField> </StyledDatagrid> </Box> ); - + } const MatnrList = () => { @@ -217,7 +242,7 @@ theme.transitions.create(['all'], { duration: theme.transitions.duration.enteringScreen, }), - marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} title={"menu.matnr"} empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} @@ -235,7 +260,7 @@ </TopToolbar> )} perPage={DEFAULT_PAGE_SIZE} - aside={ <MatListAside /> } + aside={<MatListAside />} > <MatnrListContent /> </List> @@ -255,4 +280,30 @@ MatnrList.Context = React.createContext() -export default MatnrList; \ No newline at end of file +export default MatnrList; + +const EnableButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const enable = async () => { + const res = await request.post('/loc/update', { + ...record, + status: +!record.status + }); + if (res?.data?.code === 200) { + refresh() + } else { + notify(res.data.msg); + } + } + return ( + record.status === 1 ? + (<Button onClick={enable} label={"toolbar.unenable"}> + <DashboardIcon /> + </Button>) : (<Button onClick={enable} label={"toolbar.enable"}> + <DashboardIcon /> + </Button>) + + ) +} \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx b/rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx index 9f5617b..e20ce92 100644 --- a/rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx +++ b/rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx @@ -11,14 +11,27 @@ import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; import { TreeItem2 } from "@mui/x-tree-view/TreeItem2"; - const MatListAside = () => { const theme = useTheme(); const notify = useNotify(); const { setFilters } = useListContext(); // 鑾峰彇鍒楄〃涓婁笅鏂� const [selectedOption, setSelectedOption] = useState(null); const [treeData, setTreeData] = useState([]); - const trees = [] + // 鐢ㄤ簬绠$悊灞曞紑椤圭殑鐘舵�� + const [expandedItems, setExpandedItems] = useState([]); + + // 閫掑綊鏀堕泦鎵�鏈夎妭鐐圭殑 id + const collectAllNodeIds = (nodes) => { + let allIds = []; + nodes.forEach((node) => { + allIds.push(node.id.toString()); + if (node.children && Array.isArray(node.children)) { + allIds = allIds.concat(collectAllNodeIds(node.children)); + } + }); + return allIds; + }; + const haveChildren = (item) => { // 濡傛灉 item 鏄竴涓暟缁勶紝閬嶅巻鏁扮粍涓殑姣忎釜鍏冪礌 if (Array.isArray(item)) { @@ -40,13 +53,16 @@ return item; }; + useEffect(() => { request.post('/matnrGroup/tree') .then(res => { if (res?.data?.code === 200) { let data = res.data.data; - let items = haveChildren(data) - setTreeData(items) + let items = haveChildren(data); + setTreeData(items); + // 褰撴爲鏁版嵁鏇存柊鏃讹紝鏇存柊灞曞紑椤圭姸鎬� + setExpandedItems(collectAllNodeIds(items)); } else { notify(res.data.msg); } @@ -54,12 +70,7 @@ .catch(error => { notify('Error fetching tree data'); }); - - - }, []); - - const treeData1 = [ { @@ -68,8 +79,12 @@ editable: true, children: [ { - id: 'grid-community', label: '@mui/x-data-grid', editable: true, children: [ - { id: 'grid-community22', label: '@mui/x-data-grid', editable: true },] + id: 'grid-community', + label: '@mui/x-data-grid', + editable: true, + children: [ + { id: 'grid-community22', label: '@mui/x-data-grid', editable: true }, + ], }, { id: 'grid-pro', label: '@mui/x-data-grid-pro', editable: true }, { id: 'grid-premium', label: '@mui/x-data-grid-premium', editable: true }, @@ -95,15 +110,16 @@ children: [{ id: 'tree-view-community1', label: '@mui/x-tree-view' }], }, ]; + const handleNodeSelect = (event, nodeId) => { console.log('Selected Node ID:', nodeId); setFilters({ groupId: nodeId }); // 鍦ㄨ繖閲屽彲浠ユ牴鎹� nodeId 鏇存柊涓诲唴瀹瑰尯鍩� }; + const handleSearch = () => { console.log('Search Input:', selectedOption); }; - const CustomCheckbox = React.forwardRef(function CustomCheckbox(props, ref) { return <input type="checkbox" ref={ref} {...props} />; @@ -121,33 +137,35 @@ ); }); - return ( <Card sx={{ - display: { xs: 'none', md: 'block', }, order: -1, mr: 2, mt: 8, alignSelf: 'flex-start', border: theme.palette.mode === 'light' && '1px solid #e0e0e3', - width: 250 + width: 250, + minWidth: 150, + height: `calc(100% - 120px)`, }} > <CardContent> <SavedQueriesList icon={<BookmarkIcon />} /> <FilterLiveSearch source="condition" /> <RichTreeView - defaultExpandedItems={['grid', 'pickers']} + // 浣跨敤 expandedItems 鎺у埗灞曞紑鐘舵�� + expandedItems={expandedItems} + // 澶勭悊灞曞紑椤圭姸鎬佺殑鍙樺寲 + onExpandedItemsChange={(newExpandedItems) => setExpandedItems(newExpandedItems)} expansionTrigger="iconContainer" items={treeData} slots={CustomTreeItem} onItemClick={handleNodeSelect} // 鐩戝惉鑺傜偣鐐瑰嚮浜嬩欢 - /> </CardContent> </Card> - ) -} + ); +}; -export default MatListAside; +export default MatListAside; \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx b/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx index 8436018..92c89df 100644 --- a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx +++ b/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx @@ -160,7 +160,7 @@ const [createDialog, setCreateDialog] = React.useState(false); const [editRecord, setEditRecord] = React.useState(null); const [openNodes, setOpenNodes] = React.useState({}); - const [expandAll, setExpandAll] = React.useState(false); + const [expandAll, setExpandAll] = React.useState(true); const http = async () => { const res = await request.post(RESOURCE + '/tree', { @@ -226,6 +226,23 @@ return newExpandAll; }); }; + + // 鍒濆鍖� openNodes 浠ュ睍寮�鎵�鏈夎妭鐐� + React.useEffect(() => { + if (treeData) { + const newOpenNodes = {}; + const updateOpenNodes = (nodes) => { + nodes.forEach(node => { + newOpenNodes[node.id] = true; + if (node.children) { + updateOpenNodes(node.children); + } + }); + }; + updateOpenNodes(treeData); + setOpenNodes(newOpenNodes); + } + }, [treeData]); return ( <div> @@ -336,4 +353,4 @@ ); } -export default MatnrGroupList; +export default MatnrGroupList; \ No newline at end of file diff --git a/rsf-admin/src/page/basicInfo/whMat/WhMatList.jsx b/rsf-admin/src/page/basicInfo/whMat/WhMatList.jsx index 16631c9..d0b4c7c 100644 --- a/rsf-admin/src/page/basicInfo/whMat/WhMatList.jsx +++ b/rsf-admin/src/page/basicInfo/whMat/WhMatList.jsx @@ -145,7 +145,7 @@ const getMatnrList = async () => { const { data: { code, data, msg }, - } = await request.post("/matnr/list", {}).then(); + } = await request.post("/matnr/list", {}); if (code === 200) { console.log(data); } else { diff --git a/rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx b/rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx index f7546dc..a32c132 100644 --- a/rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx +++ b/rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx @@ -180,7 +180,7 @@ <Checkbox key={row.id} checked={row.checked} - // onChange={() => { row.checked = !row.checked; }} + // onChange={() => { row.checked = !row.checked; }} /> </StyledTableCell> {columns.map((column, idx) => { @@ -626,7 +626,7 @@ </TableBody> </Table> </TableContainer> - <WhTable data={treeDatas} /> + {/* <WhTable data={treeDatas} /> */} </> ); }; diff --git a/rsf-admin/src/page/components/BatchButton.jsx b/rsf-admin/src/page/components/BatchButton.jsx new file mode 100644 index 0000000..5a46f8d --- /dev/null +++ b/rsf-admin/src/page/components/BatchButton.jsx @@ -0,0 +1,31 @@ +import EditIcon from '@mui/icons-material/Edit'; +import { useState } from 'react'; +import { Button, useListContext } from 'react-admin'; +import BatchModal from './BatchModal'; + +const ImportButton = (props) => { + const [modalOpen, setModalOpen] = useState(false); + const { selectedIds } = useListContext(); + console.log(selectedIds) + const handleOpenModal = () => { + setModalOpen(true); + }; + + const handleCloseModal = () => { + setModalOpen(false); + }; + + return ( + <> + <Button + startIcon={<EditIcon />} + label="common.action.batch" + onClick={handleOpenModal} + /> + + <BatchModal open={modalOpen} onClose={handleCloseModal} {...props} /> + </> + ); +}; + +export default ImportButton; \ No newline at end of file diff --git a/rsf-admin/src/page/components/BatchModal.jsx b/rsf-admin/src/page/components/BatchModal.jsx new file mode 100644 index 0000000..e2107c7 --- /dev/null +++ b/rsf-admin/src/page/components/BatchModal.jsx @@ -0,0 +1,65 @@ +import { useEffect, useState, createContext, useContext } from 'react'; +import { Box, CircularProgress, Stack, Typography } from '@mui/material'; +import Alert from '@mui/material/Alert'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import MuiLink from '@mui/material/Link'; +import { + Button, + FileField, + FileInput, + Form, + Toolbar, + useRefresh, + useTranslate, + useNotify +} from 'react-admin'; +import { Link } from 'react-router-dom'; +import DialogCloseButton from './DialogCloseButton'; +import { usePapaParse } from './usePapaParse'; +import MatnrList from '../basicInfo/matnr/MatnrList'; +import request from '@/utils/request' +import SaveIcon from '@mui/icons-material/Save'; + +const ImportModal = ({ open, onClose, importTemp, useCodeImport, onceBatch = 10, value, parmas = {} }) => { + const refresh = useRefresh(); + const translate = useTranslate(); + + + const notify = useNotify(); + + + + const handleClose = () => { + onClose(); + }; + + const handleReset = (e) => { + e.preventDefault(); + }; + + const handleSubmit = () => { + }; + + + return ( + <Dialog open={open} maxWidth="md" fullWidth> + <DialogCloseButton onClose={handleClose} /> + <DialogTitle>{translate('common.action.batch')}</DialogTitle> + <DialogContent> + <div>1</div> + </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 />}> + 纭 + </Button> + </Box> + </DialogActions> + </Dialog> + ); +} + +export default ImportModal; \ No newline at end of file diff --git a/rsf-admin/src/page/components/DictionarySelect.jsx b/rsf-admin/src/page/components/DictionarySelect.jsx new file mode 100644 index 0000000..43dc811 --- /dev/null +++ b/rsf-admin/src/page/components/DictionarySelect.jsx @@ -0,0 +1,45 @@ +import EditIcon from '@mui/icons-material/Edit'; +import { useState, useEffect } from 'react'; +import { + Button, useListContext, SelectInput, + required, + useTranslate, useNotify +} from 'react-admin'; +import request from '@/utils/request'; + +const DictionarySelect = (props) => { + const { dictTypeCode, name, ...parmas } = props; + const { selectedIds } = useListContext(); + const translate = useTranslate(); + const notify = useNotify(); + const [list, setList] = useState([]) + + useEffect(() => { + http() + }, [dictTypeCode]); + + const http = async () => { + const res = await request.post('/dictData/page', { dictTypeCode }); + if (res?.data?.code === 200) { + + setList(res.data.data.records.map((item) => { + return { + id: item.value, + name: item.value + } + })) + } else { + notify(res.data.msg); + } + } + + return ( + <SelectInput + source={name} + choices={list} + {...parmas} + /> + ); +}; + +export default DictionarySelect; \ No newline at end of file diff --git a/rsf-admin/src/page/components/TooltipField.jsx b/rsf-admin/src/page/components/TooltipField.jsx new file mode 100644 index 0000000..8eb6937 --- /dev/null +++ b/rsf-admin/src/page/components/TooltipField.jsx @@ -0,0 +1,28 @@ +import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; +import { + useRecordContext, +} from 'react-admin'; +import { Box, Typography, Card, Stack, Tooltip } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; + +const MyField = ({ source, onClick }) => { + const record = useRecordContext(); + const theme = useTheme(); + + return record ? ( + <Box + + > + <Typography + variant="body2" + > + <Tooltip title={record[source]} placement="top"> + <span>{record[source]}</span> + </Tooltip> + + </Typography > + </Box> + ) : null; +} + +export default MyField; \ No newline at end of file diff --git a/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx b/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx index f8a68f3..8a95d66 100644 --- a/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx +++ b/rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx @@ -60,8 +60,6 @@ const filters = [ <SearchInput source="condition" alwaysOn />, - <DateInput label='common.time.after' source="timeStart" alwaysOn />, - <DateInput label='common.time.before' source="timeEnd" alwaysOn />, <TextInput source="uuid" label="table.field.warehouseAreas.uuid" />, <TextInput source="name" label="table.field.warehouseAreas.name" />, @@ -73,19 +71,19 @@ <SelectInput source="flagMinus" label="table.field.warehouseAreas.flagMinus" choices={[ { id: 0, name: '鍚�' }, - { id: 1, name: '鏄�' }, + { id: 1, name: '鏄�' }, ]} />, <SelectInput source="flagLabelMange" label="table.field.warehouseAreas.flagLabelMange" choices={[ { id: 0, name: ' 鍚�' }, - { id: 1, name: ' 鏄�' }, + { id: 1, name: ' 鏄�' }, ]} />, <SelectInput source="flagMix" label="table.field.warehouseAreas.flagMix" choices={[ { id: 0, name: '鍚�' }, - { id: 1, name: '鏄�' }, + { id: 1, name: '鏄�' }, ]} />, @@ -116,7 +114,7 @@ theme.transitions.create(['all'], { duration: theme.transitions.duration.enteringScreen, }), - marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} title={"menu.warehouseAreas"} empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} diff --git a/rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx b/rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx index 65fc752..9b03b48 100644 --- a/rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx +++ b/rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx @@ -60,8 +60,6 @@ const filters = [ <SearchInput source="condition" alwaysOn />, - <DateInput label='common.time.after' source="timeStart" alwaysOn />, - <DateInput label='common.time.before' source="timeEnd" alwaysOn />, <NumberInput source="areaId" label="table.field.warehouseAreasItem.areaId" />, <TextInput source="areaName" label="table.field.warehouseAreasItem.areaName" />, @@ -109,7 +107,7 @@ theme.transitions.create(['all'], { duration: theme.transitions.duration.enteringScreen, }), - marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} title={"menu.warehouseAreasItem"} empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} -- Gitblit v1.9.1