From a0c27ec444c85326efe3bacf3205dfecbd66451d Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期二, 22 四月 2025 09:28:39 +0800 Subject: [PATCH] #新增 1. 新增出库单明细 2. 编码规则bug修改 --- rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx | 189 +++ rsf-admin/src/page/system/serialRule/SerialRuleEdit.jsx | 7 rsf-admin/src/page/orders/outStock/OutOrderItemCreate.jsx | 204 +++ rsf-admin/src/page/orders/outStock/AsnWareModal.jsx | 249 ++++ rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java | 174 +++ rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java | 6 rsf-admin/src/page/system/serialRule/SerialRuleItemList.jsx | 4 rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx | 184 +++ rsf-admin/src/page/orders/outStock/OutOrderItemEdit.jsx | 195 +++ rsf-admin/src/page/orders/outStock/PrintModal.jsx | 310 +++++ rsf-admin/src/page/orders/outStock/OutOrderEdit.jsx | 150 ++ rsf-admin/src/page/orders/outStock/asnOrder.css | 5 rsf-admin/src/page/orders/outStock/AsnOrderModal.jsx | 643 ++++++++++++ rsf-admin/src/page/orders/outStock/index.jsx | 18 rsf-admin/src/i18n/zh.js | 37 rsf-admin/src/page/orders/outStock/AsnOrderPanel.jsx | 239 ++++ rsf-admin/src/page/orders/outStock/OutOrderList.jsx | 263 +++++ rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutOrderItemController.java | 185 +++ rsf-admin/src/i18n/en.js | 1 rsf-admin/src/page/ResourceContent.js | 4 rsf-admin/.env | 2 21 files changed, 3,062 insertions(+), 7 deletions(-) diff --git a/rsf-admin/.env b/rsf-admin/.env index a8ce658..ccb3f34 100644 --- a/rsf-admin/.env +++ b/rsf-admin/.env @@ -1,3 +1,3 @@ -VITE_BASE_IP=192.168.4.24 +VITE_BASE_IP=192.168.4.25 # 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 2840e89..625d37a 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -170,6 +170,7 @@ logs: 'Logs', permissions: 'Permissions', delivery: 'Delivery', + outStock: 'Out Stock', }, table: { field: { diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 82b3d55..7454779 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -171,6 +171,7 @@ logs: '鏃ュ織', permissions: '鏉冮檺绠$悊', delivery: 'DO鍗�', + outStock: '鍑哄簱鍗�', }, table: { @@ -531,6 +532,20 @@ ntyStatus: "涓婃姤鐘舵��", exceStatus: '鍗曟嵁鐘舵��' }, + outStock: { + code: "鍑哄簱鍗曞彿", + poCode: "骞冲彴鍗曞彿", + poId: "PO鏍囪瘑", + type: "绫诲瀷", + wkType: "涓氬姟绫诲瀷", + anfme: "鏁伴噺", + qty: "宸插嚭搴撴暟閲�", + logisNo: "鐗╂祦鍗曞彿", + arrTime: "棰勮鍒拌揪鏃堕棿", + rleStatus: "閲婃斁鐘舵��", + ntyStatus: "涓婃姤鐘舵��", + exceStatus: '鍗曟嵁鐘舵��' + }, asnOrderItem: { asnId: "涓诲崟鏍囪瘑", asnCode: "涓诲崟缂栫爜", @@ -554,6 +569,28 @@ prodTime: "鐢熶骇鏃ユ湡", platItemId: '琛屽彿' }, + outStockItem: { + asnId: "涓诲崟鏍囪瘑", + asnCode: "鍗曞彿", + poDetlId: "骞冲彴鏄庣粏ID", + matnrId: "鐗╂枡鏍囪瘑", + maktx: "鐗╂枡鍚嶇О", + matnrCode: "鐗╂枡缂栫爜", + anfme: "璁″垝鍑哄簱鏁�", + stockUnit: "搴撳瓨鍗曚綅", + purQty: "涓嬪崟鏁伴噺", + purUnit: "鍗曚綅", + qty: "瀹屾垚鏁伴噺", + splrBatch: "渚涘簲鍟嗘壒娆�", + splrCode: "渚涘簲鍟嗙紪鐮�", + splrName: "渚涘簲鍟嗗悕绉�", + qrcode: "浜岀淮鐮�", + barcode: "鏉″舰鐮�", + packName: "鍖呰", + ntyStatus: "鎶ユ鐘舵��", + prodTime: "鐢熶骇鏃ユ湡", + platItemId: '琛屽彿' + }, asnOrderLog: { code: "缂栫爜", poCode: "PO缂栫爜", diff --git a/rsf-admin/src/page/ResourceContent.js b/rsf-admin/src/page/ResourceContent.js index 256cf8a..5dd2787 100644 --- a/rsf-admin/src/page/ResourceContent.js +++ b/rsf-admin/src/page/ResourceContent.js @@ -42,6 +42,8 @@ import taskLog from './histories/taskLog'; import stock from './orders/stock'; import delivery from './orders/delivery'; +import outStock from './orders/outStock'; + const ResourceContent = (node) => { switch (node.component) { @@ -121,6 +123,8 @@ return stock; case 'delivery': return delivery; + case 'outStock': + return outStock; default: return { list: ListGuesser, 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/AsnOrderPanel.jsx b/rsf-admin/src/page/orders/outStock/AsnOrderPanel.jsx new file mode 100644 index 0000000..4649e7f --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/AsnOrderPanel.jsx @@ -0,0 +1,239 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { Box, Card, CardContent, Grid, Typography, Button, TextField, Tooltip, Paper, TableContainer, Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material'; +import { + useTranslate, + useRecordContext, + useNotify, + useRefresh, + useListContext, +} from 'react-admin'; +import PanelTypography from "../../components/PanelTypography"; +import * as Common from '@/utils/common' +import { styled } from "@mui/material/styles"; +import request from '@/utils/request'; +import debounce from 'lodash/debounce'; +import { DataGrid } from '@mui/x-data-grid'; +import PrintModal from './PrintModal'; +import PrintIcon from '@mui/icons-material/Print'; +const AsnOrderPanel = ({ billReload }) => { + const record = useRecordContext(); + if (!record) return null; + const translate = useTranslate(); + const notify = useNotify(); + const [rows, setRows] = useState([]); + const [maktx, setMaktx] = useState(''); + const asnId = record.id; + + useEffect(() => { + debouncedHttp({ maktx }); + }, [asnId, maktx]); + + const http = async (parmas) => { + const res = await request.post('/asnOrderItem/page', { ...parmas, asnId }); + if (res?.data?.code === 200) { + setRows(res.data.data.records) + } else { + notify(res.data.msg); + } + } + + + useEffect(() => { + billReload.current = http + }, []); + + + const debouncedHttp = useMemo(() => debounce(http, 300), []); + + const columns = [ + { + field: 'asnId', + headerName: translate('table.field.asnOrderItem.asnId') + }, + { + field: 'asnCode', + headerName: translate('table.field.asnOrderItem.asnCode'), + width: 150, + }, + // { + // field: 'poDetlId', + // headerName: translate('table.field.asnOrderItem.poDetlId') + // }, + { + field: 'poCode', + headerName: translate('table.field.asnOrderItem.poDetlCode') + }, + { + field: 'matnrCode', + headerName: translate('table.field.asnOrderItem.matnrCode'), + width: 150, + }, + { + field: 'maktx', + headerName: translate('table.field.asnOrderItem.maktx'), + width: 200, + }, + { + field: 'anfme', + headerName: translate('table.field.asnOrderItem.purQty') + }, + { + field: 'stockUnit', + headerName: translate('table.field.asnOrderItem.stockUnit') + }, + // { + // field: 'purQty', + // headerName: translate('table.field.asnOrderItem.purQty') + // }, + { + field: 'purUnit', + headerName: translate('table.field.asnOrderItem.purUnit') + }, + { + field: 'qty', + headerName: translate('table.field.asnOrderItem.qty') + }, + { + field: 'splrBatch', + headerName: translate('table.field.asnOrderItem.splrBatch') + }, + { + field: 'splrCode', + headerName: translate('table.field.asnOrderItem.splrCode') + }, + { + field: 'splrName', + headerName: translate('table.field.asnOrderItem.splrName') + }, + { + field: 'trackCode', + headerName: translate('table.field.asnOrderItem.barcode'), + width: 150 + }, + { + field: 'prodTime', + headerName: translate('table.field.asnOrderItem.prodTime') + }, + { + field: 'packName', + headerName: translate('table.field.asnOrderItem.packName') + }, + { + field: 'action', + headerName: '鎿嶄綔', + width: 70, + lockPosition: 'left', + renderCell: (params) => ( + <PrintButton rows={[params.row.id]} /> + ), + + },] + + const [selectedRows, setSelectedRows] = useState([]); + + const handleSelectionChange = (ids) => { + setSelectedRows(ids) + + }; + const maktxChange = (value) => { + setMaktx(value) + } + + + return ( + <Box sx={{ + position: 'relative', + padding: '5px 10px' + }}> + <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px', alignItems: 'center' }}> + <TextField value={maktx} onChange={(e) => maktxChange(e.target.value)} label="鎼滅储鐗╂枡" sx={{ width: '300px' }} size="small" /> + + <div style={{ display: 'flex', gap: '10px' }}> + <PrintsButton rows={selectedRows} /> + </div> + </div> + + + <DataGrid + sx={{ width: 'calc(100vw - 280px)' }} + size="small" + rows={rows} + columns={columns} + disableRowSelectionOnClick + checkboxSelection + onRowSelectionModelChange={handleSelectionChange} + selectionModel={selectedRows} + disableColumnMenu={true} + disableColumnSorting + disableMultipleColumnsSorting + columnHeaderHeight={40} + rowHeight={42} + initialState={{ + pagination: { + paginationModel: { + pageSize: 10, + }, + }, + }} + pageSizeOptions={[10, 25, 50]} + /> + </Box > + + ); +}; + +export default AsnOrderPanel; + +const PrintsButton = ({ rows }) => { + const record = useRecordContext(); + const { resource, selectedIds } = useListContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const translate = useTranslate(); + + const [createDialog, setCreateDialog] = useState(false); + + const modalChange = () => { + if (rows?.length === 0) { + notify('璇烽�夋嫨鐗╂枡'); + return; + } else { + setCreateDialog(true) + } + + } + + return ( + <> + <Button size="small" color="secondary" onClick={modalChange} startIcon={<PrintIcon />}>{translate("toolbar.batchPrint")}</Button> + + <PrintModal + open={createDialog} + setOpen={setCreateDialog} + rows={rows} + /> + </> + ) +} + +const PrintButton = ({ rows }) => { + const record = useRecordContext(); + + const notify = useNotify(); + const refresh = useRefresh(); + + const [createDialog, setCreateDialog] = useState(false); + const translate = useTranslate(); + + return ( + <> + <Button size="small" color="secondary" onClick={() => setCreateDialog(true)} startIcon={<PrintIcon />}>{translate("toolbar.print")}</Button> + + <PrintModal + open={createDialog} + setOpen={setCreateDialog} + rows={rows} + /> + </> + ) +} 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 new file mode 100644 index 0000000..28cd69d --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderCreate.jsx @@ -0,0 +1,184 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + CreateBase, + useTranslate, + TextInput, + NumberInput, + BooleanInput, + DateInput, + SaveButton, + SelectInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + Toolbar, + required, + useDataProvider, + useNotify, + Form, + useCreateController, +} from 'react-admin'; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Stack, + Grid, + Box, +} from '@mui/material'; +import DialogCloseButton from "../components/DialogCloseButton"; +import StatusSelectInput from "../components/StatusSelectInput"; +import MemoInput from "../components/MemoInput"; + +const OutOrderCreate = (props) => { + const { open, setOpen } = props; + + const translate = useTranslate(); + const notify = useNotify(); + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const handleSuccess = async (data) => { + setOpen(false); + notify('common.response.success'); + }; + + const handleError = async (error) => { + notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); + }; + + return ( + <> + <CreateBase + record={{}} + transform={(data) => { + return data; + }} + mutationOptions={{ onSuccess: handleSuccess, onError: handleError }} + > + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + fullWidth + disableRestoreFocus + maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' + > + <Form> + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }} + > + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Grid container rowSpacing={2} columnSpacing={2}> + {/* <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrder.code" + source="code" + parse={v => v} + autoFocus + /> + </Grid> */} + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrder.poCode" + source="poCode" + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.asnOrder.poId" + source="poId" + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrder.type" + source="type" + parse={v => v} + validate={required()} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrder.wkType" + source="wkType" + parse={v => v} + validate={required()} + /> + </Grid> + {/* <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.asnOrder.anfme" + source="anfme" + validate={required()} + /> + </Grid> */} + {/* <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.asnOrder.qty" + source="qty" + validate={required()} + /> + </Grid> */} + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrder.logisNo" + source="logisNo" + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <DateInput + label="table.field.asnOrder.arrTime" + source="arrTime" + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <SelectInput + label="table.field.asnOrder.rleStatus" + source="rleStatus" + choices={[ + { id: 0, name: ' 姝e父' }, + { id: 1, name: ' 宸查噴鏀�' }, + ]} + /> + </Grid> + + <Grid item xs={6} display="flex" gap={1}> + <StatusSelectInput /> + </Grid> + <Grid item xs={12} display="flex" gap={1}> + <Stack direction="column" spacing={1} width={'100%'}> + <MemoInput /> + </Stack> + </Grid> + </Grid> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }} > + <SaveButton /> + </Toolbar> + </DialogActions> + </Form> + </Dialog> + </CreateBase> + </> + ) +} + +export default OutOrderCreate; diff --git a/rsf-admin/src/page/orders/outStock/OutOrderEdit.jsx b/rsf-admin/src/page/orders/outStock/OutOrderEdit.jsx new file mode 100644 index 0000000..ddfa812 --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderEdit.jsx @@ -0,0 +1,150 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + Edit, + SimpleForm, + useTranslate, + TextInput, + DateInput, + SelectInput, + AutocompleteInput, + SaveButton, + Toolbar, + required, + DeleteButton, +} from 'react-admin'; +import { useWatch, useFormContext } from "react-hook-form"; +import { Stack, Grid, Box, Typography } from '@mui/material'; +import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting'; +import EditBaseAside from "../../components/EditBaseAside"; +import CustomerTopToolBar from "../../components/EditTopToolBar"; +import AsnOrderItemList from "./AsnOrderItemList"; + +const FormToolbar = () => { + const { getValues } = useFormContext(); + + return ( + <Toolbar sx={{ justifyContent: 'end' }}> + <></> + {/* <SaveButton /> + <DeleteButton mutationMode="optimistic" /> */} + </Toolbar> + ) +} + +const OutOrderEdit = () => { + const translate = useTranslate(); + const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_order_type')) || []; + const business = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_business_type')) || []; + + return ( + <> + <Edit + redirect="list" + mutationMode={EDIT_MODE} + actions={<CustomerTopToolBar />} + aside={<EditBaseAside />} + > + <SimpleForm + shouldUnregister + warnWhenUnsavedChanges + toolbar={<FormToolbar />} + mode="onTouched" + defaultValues={{}} + > + <Grid container width={{ xs: '100%', xl: '100%' }} rowSpacing={3} columnSpacing={3} + sx={{ + "& .MuiFormLabel-root.MuiInputLabel-root.Mui-disabled": { + bgcolor: 'white', + WebkitTextFillColor: "rgba(0, 0, 0)" + }, + + "& .MuiInputBase-input.MuiFilledInput-input.Mui-disabled": { + bgcolor: 'white', + WebkitTextFillColor: "rgba(0, 0, 0)" + }, + "& .MuiFilledInput-root.MuiInputBase-sizeSmall": { + bgcolor: 'white', + } + }} + > + <Grid item xs={24} md={12} > + <Typography variant="h6" gutterBottom> + {translate('common.edit.title.main')} + </Typography> + <Stack direction='row' gap={2}> + <TextInput + label="table.field.asnOrder.code" + source="code" + readOnly + parse={v => v} + /> + <TextInput + label="table.field.asnOrder.poCode" + source="poCode" + readOnly + parse={v => v} + /> + <AutocompleteInput + choices={dicts} + optionText="label" + label="table.field.asnOrder.type" + source="type" + optionValue="value" + parse={v => v} + readOnly + /> + <AutocompleteInput + choices={business} + optionText="label" + label="table.field.asnOrder.wkType" + source="wkType" + optionValue="value" + parse={v => v} + readOnly + /> + </Stack> + <Stack direction='row' gap={2}> + <TextInput + label="table.field.asnOrder.logisNo" + source="logisNo" + readOnly + parse={v => v} + /> + <TextInput + label="table.field.asnOrder.anfme" + source="anfme" + readOnly + parse={v => v} + /> + <TextInput + label="table.field.asnOrder.qty" + source="qty" + readOnly + parse={v => v} + /> + <DateInput + label="table.field.asnOrder.arrTime" + source="arrTime" + readOnly + /> + <SelectInput + label="table.field.asnOrder.rleStatus" + source="rleStatus" + readOnly + choices={[ + { id: 0, name: ' 姝e父' }, + { id: 1, name: ' 宸查噴鏀�' }, + ]} + validate={required()} + /> + </Stack> + </Grid> + </Grid> + </SimpleForm> + </Edit > + <AsnOrderItemList /> + </> + ) +} + +export default OutOrderEdit; diff --git a/rsf-admin/src/page/orders/outStock/OutOrderItemCreate.jsx b/rsf-admin/src/page/orders/outStock/OutOrderItemCreate.jsx new file mode 100644 index 0000000..e9a378d --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderItemCreate.jsx @@ -0,0 +1,204 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + CreateBase, + useTranslate, + TextInput, + NumberInput, + BooleanInput, + DateInput, + SaveButton, + SelectInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + Toolbar, + required, + useDataProvider, + useNotify, + Form, + useCreateController, +} from 'react-admin'; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Stack, + Grid, + Box, +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import StatusSelectInput from "../../components/StatusSelectInput"; +import MemoInput from "../../components/MemoInput"; + +const OutOrderItemCreate = (props) => { + const { open, setOpen, record } = props; + const translate = useTranslate(); + const notify = useNotify(); + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const handleSuccess = async (data) => { + setOpen(false); + notify('common.response.success'); + }; + + const handleError = async (error) => { + notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); + }; + + return ( + <> + <CreateBase + resource="asnOrderItem" + record={{}} + transform={(data) => { + return data; + }} + mutationOptions={{ onSuccess: handleSuccess, onError: handleError }} + > + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + fullWidth + disableRestoreFocus + maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' + > + <Form> + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }} + > + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Grid> + <Grid item xs={6} display="flex" gap={2}> + <NumberInput + label="table.field.asnOrderItem.asnId" + source="asnId" + readOnly + hidden + defaultValue={record?.id} + /> + <TextInput + label="table.field.asnOrderItem.asnCode" + source="asnCode" + readOnly + defaultValue={record?.code} + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={2}> + <TextInput + label="table.field.asnOrderItem.poDetlId" + source="poDetlId" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.poDetlCode" + source="poDetlCode" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.matnrId" + source="matnrId" + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrderItem.maktx" + source="maktx" + parse={v => v} + /> + <NumberInput + label="table.field.asnOrderItem.anfme" + source="anfme" + validate={required()} + /> + <TextInput + label="table.field.asnOrderItem.stockUnit" + source="stockUnit" + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <NumberInput + label="table.field.asnOrderItem.purQty" + source="purQty" + validate={required()} + /> + <TextInput + label="table.field.asnOrderItem.purUnit" + source="purUnit" + parse={v => v} + /> + <NumberInput + label="table.field.asnOrderItem.qty" + source="qty" + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrderItem.splrCode" + source="splrCode" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.splrName" + source="splrName" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.qrcode" + source="qrcode" + parse={v => v} + /> + </Grid> + <Grid item xs={6} display="flex" gap={1}> + <TextInput + label="table.field.asnOrderItem.barcode" + source="barcode" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.packName" + source="packName" + parse={v => v} + /> + </Grid> + + <Grid item xs={6} display="flex" gap={1}> + <StatusSelectInput /> + </Grid> + <Grid item xs={12} display="flex" gap={1}> + <Stack direction="column" spacing={1} width={'100%'}> + <MemoInput /> + </Stack> + </Grid> + </Grid> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }} > + <SaveButton /> + </Toolbar> + </DialogActions> + </Form> + </Dialog> + </CreateBase> + </> + ) +} + +export default OutOrderItemCreate; diff --git a/rsf-admin/src/page/orders/outStock/OutOrderItemEdit.jsx b/rsf-admin/src/page/orders/outStock/OutOrderItemEdit.jsx new file mode 100644 index 0000000..800b76b --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderItemEdit.jsx @@ -0,0 +1,195 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + Edit, + SimpleForm, + FormDataConsumer, + useTranslate, + TextInput, + NumberInput, + BooleanInput, + DateInput, + SelectInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + SaveButton, + Toolbar, + Labeled, + NumberField, + required, + Form, + useRecordContext, + useGetOne, + DeleteButton, + EditBase, + ReferenceField, +} from 'react-admin'; +import { useWatch, useFormContext } from "react-hook-form"; +import { Stack, Grid, Box, Typography, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material'; +import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting'; +import DialogCloseButton from "../../components/DialogCloseButton"; +import EditBaseAside from "../../components/EditBaseAside"; +import CustomerTopToolBar from "../../components/EditTopToolBar"; +import MemoInput from "../../components/MemoInput"; +import StatusSelectInput from "../../components/StatusSelectInput"; + +const FormToolbar = () => { + const { getValues } = useFormContext(); + + return ( + <Toolbar sx={{ justifyContent: 'end' }}> + <SaveButton /> + <DeleteButton mutationMode="optimistic" /> + </Toolbar> + ) +} + +const OutOrderItemEdit = (props) => { + const { open, setOpen, record } = props; + const translate = useTranslate(); + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + const { data, isPending, } = useGetOne('asnOrderItem', { id: record?.id }); + if (data == null || data == undefined) { return } + + return ( + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + fullWidth + disableRestoreFocus + maxWidth="md" + > + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }} + > + {translate('update.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <EditBase + id={record?.id} + resource="asnOrderItem" + mutationMode={EDIT_MODE} + actions={<CustomerTopToolBar />} + > + <Form + shouldUnregister + warnWhenUnsavedChanges + mode="onTouched" + defaultValues={{}} + > + <Grid container width={{ xs: '100%', xl: '100%' }}> + <Grid item xs={24} md={14}> + <Stack direction='row' gap={2}> + <NumberInput + label="table.field.asnOrderItem.asnId" + source="asnId" + readOnly + /> + <TextInput + label="table.field.asnOrderItem.asnCode" + source="asnCode" + readOnly + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.poDetlId" + source="poDetlId" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.poDetlCode" + source="poDetlCode" + parse={v => v} + /> + </Stack> + <Stack direction='row' gap={2}> + <TextInput + label="table.field.asnOrderItem.matnrId" + source="matnrId" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.maktx" + source="maktx" + parse={v => v} + /> + <NumberInput + label="table.field.asnOrderItem.anfme" + source="anfme" + validate={required()} + /> + <TextInput + label="table.field.asnOrderItem.stockUnit" + source="stockUnit" + parse={v => v} + /> + </Stack> + <Stack direction='row' gap={2}> + <NumberInput + label="table.field.asnOrderItem.purQty" + source="purQty" + validate={required()} + /> + <TextInput + label="table.field.asnOrderItem.purUnit" + source="purUnit" + parse={v => v} + /> + <NumberInput + label="table.field.asnOrderItem.qty" + source="qty" + readOnly + /> + <ReferenceInput source="splrName" label="table.field.asnOrderItem.splrName" reference="companys" filter={{type: 'supplier'}}> + <AutocompleteInput optionText="name" label="table.field.asnOrderItem.splrName" /> + </ReferenceInput> + </Stack> + <Stack direction='row' gap={2}> + <TextInput + label="table.field.asnOrderItem.qrcode" + source="qrcode" + parse={v => v} + /> + <TextInput + label="table.field.asnOrderItem.barcode" + source="trackCode" + parse={v => v} + readOnly + /> + <TextInput + label="table.field.asnOrderItem.packName" + source="packName" + parse={v => v} + /> + </Stack> + </Grid> + </Grid> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Toolbar sx={{ width: '100%', justifyContent: 'end' }} > + <SaveButton type="button" mutationOptions={{ + onSuccess: () => { + setOpen(false) + } + }} /> + </Toolbar> + </DialogActions> + </Form> + </EditBase > + </DialogContent> + </Dialog> + ) +} + +export default OutOrderItemEdit; diff --git a/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx b/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx new file mode 100644 index 0000000..4d73b97 --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx @@ -0,0 +1,189 @@ +import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; +import { useNavigate, useLocation } 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, + Button, + useEditContext, + useGetRecordId, + useGetOne +} from 'react-admin'; +import { Box, Typography, Card, Stack, Dialog, DialogActions, DialogTitle } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import OutOrderItemCreate from "./OutOrderItemCreate"; +import EmptyData from "../../components/EmptyData"; +import MyCreateButton from "../../components/MyCreateButton"; +import MyExportButton from '../../components/MyExportButton'; +import PageDrawer from "../../components/PageDrawer"; +import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting'; +import OutOrderItemEdit from "./OutOrderItemEdit"; +import ImportButton from "../../components/ImportButton"; + +const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ + '& .css-1vooibu-MuiSvgIcon-root': { + height: '.9em', + + }, + '& .RaDatagrid-row': { + cursor: 'auto' + }, + '& .column-name': { + }, + '& .opt': { + width: 200 + }, +})); + +const filters = [ + <SearchInput source="condition" alwaysOn />, + <NumberInput source="asnId" label="table.field.asnOrderItem.asnId" />, + <TextInput source="asnCode" label="table.field.asnOrderItem.asnCode" />, + <TextInput source="poDetlId" label="table.field.asnOrderItem.poDetlId" />, + <TextInput source="poDetlCode" label="table.field.asnOrderItem.poDetlCode" />, + <TextInput source="matnrId" label="table.field.asnOrderItem.matnrId" />, + <TextInput source="maktx" label="table.field.asnOrderItem.maktx" />, + <NumberInput source="anfme" label="table.field.asnOrderItem.anfme" />, + <TextInput source="stockUnit" label="table.field.asnOrderItem.stockUnit" />, + <NumberInput source="purQty" label="table.field.asnOrderItem.purQty" />, + <TextInput source="purUnit" label="table.field.asnOrderItem.purUnit" />, + <NumberInput source="qty" label="table.field.asnOrderItem.qty" />, + <TextInput source="splrCode" label="table.field.asnOrderItem.splrCode" />, + <TextInput source="splrName" label="table.field.asnOrderItem.splrName" />, + <TextInput source="qrcode" label="table.field.asnOrderItem.qrcode" />, + <TextInput source="trackCode" label="table.field.asnOrderItem.barcode" />, + <TextInput source="packName" label="table.field.asnOrderItem.packName" />, + <TextInput label="common.field.memo" source="memo" />, + <SelectInput + label="common.field.status" + source="status" + choices={[ + { id: '1', name: 'common.enums.statusTrue' }, + { id: '0', name: 'common.enums.statusFalse' }, + ]} + resettable + />, +] + +const OutOrderItemList = () => { + const translate = useTranslate(); + const [createDialog, setCreateDialog] = useState(false); + const [editDialog, setEditDialog] = useState(false); + const [drawerVal, setDrawerVal] = useState(false); + const [select, setSelect] = useState({}); + const asnId = useGetRecordId(); + const { data: dicts, isPending, error } = useGetOne('asnOrder', { id: asnId }); + + return ( + <> + <Box display="flex"> + <List + resource="asnOrderItem" + sx={{ + flexGrow: 1, + transition: (theme) => + theme.transitions.create(['all'], { + duration: theme.transitions.duration.enteringScreen, + }), + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + }} + title={"menu.asnOrderItem"} + empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} + filter={{ asnId: asnId, deleted: 0 }} + filters={filters} + sort={{ field: "create_time", order: "desc" }} + actions={( + <TopToolbar> + <FilterButton /> + <MyCreateButton onClick={() => { setCreateDialog(true) }} /> + <SelectColumnsButton preferenceKey='asnOrderItem' /> + {/* <MyExportButton /> */} + </TopToolbar> + )} + perPage={DEFAULT_ITEM_PAGE_SIZE} + > + <StyledDatagrid + preferenceKey='asnOrderItem' + bulkActionButtons={false} + rowClick={(id, resource, record) => { + setSelect(record) + setEditDialog(true) + }} + omit={['id', 'createTime', 'createBy', 'memo', 'poDetlId', 'matnrId', 'asnId']} + > + <NumberField source="id" /> + <NumberField source="asnId" label="table.field.asnOrderItem.asnId" /> + <TextField source="asnCode" label="table.field.asnOrderItem.asnCode" /> + <TextField source="poDetlId" label="table.field.asnOrderItem.poDetlId" /> + <TextField source="poDetlCode" label="table.field.asnOrderItem.poDetlCode" /> + <TextField source="matnrId" label="table.field.asnOrderItem.matnrId" /> + <TextField source="matnrCode" label="table.field.asnOrderItem.matnrCode" /> + <TextField source="maktx" label="table.field.asnOrderItem.maktx" /> + <NumberField source="anfme" label="table.field.asnOrderItem.anfme" /> + <TextField source="stockUnit" label="table.field.asnOrderItem.stockUnit" /> + <NumberField source="purQty" label="table.field.asnOrderItem.purQty" /> + <TextField source="purUnit" label="table.field.asnOrderItem.purUnit" /> + <NumberField source="qty" label="table.field.asnOrderItem.qty" /> + <TextField source="splrCode" label="table.field.asnOrderItem.splrCode" /> + <TextField source="splrName" label="table.field.asnOrderItem.splrName" /> + <TextField source="qrcode" label="table.field.asnOrderItem.qrcode" /> + <TextField source="trackCode" label="table.field.asnOrderItem.barcode" /> + <TextField source="packName" label="table.field.asnOrderItem.packName" /> + <TextField source="updateBy$" label="common.field.updateBy" /> + <DateField source="updateTime" label="common.field.updateTime" showTime /> + <TextField source="createBy$" label="common.field.createBy" /> + <DateField source="createTime" label="common.field.createTime" showTime /> + <BooleanField source="status$" label="common.field.status" sortable={false} /> + <TextField source="memo" label="common.field.memo" sortable={false} /> + </StyledDatagrid> + </List> + <OutOrderItemCreate + open={createDialog} + setOpen={setCreateDialog} + record={dicts} + /> + <OutOrderItemEdit + open={editDialog} + setOpen={setEditDialog} + record={select} + /> + <PageDrawer + title='AsnOrderItem Detail' + drawerVal={drawerVal} + setDrawerVal={setDrawerVal} + > + </PageDrawer> + </Box> + </> + ) +} +OutOrderItemList.Context = React.createContext() + +export default OutOrderItemList; diff --git a/rsf-admin/src/page/orders/outStock/OutOrderList.jsx b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx new file mode 100644 index 0000000..f5b9dd5 --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx @@ -0,0 +1,263 @@ +import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; +import { useLocation, useNavigate } from 'react-router-dom'; +import { + List, + DatagridConfigurable, + SearchInput, + TopToolbar, + SelectColumnsButton, + EditButton, + FilterButton, + CreateButton, + ExportButton, + BulkDeleteButton, + useDataProvider, + WrapperField, + useRecordContext, + useTranslate, + useNotify, + useRefresh, + useListContext, + FunctionField, + TextField, + NumberField, + DateField, + BooleanField, + ReferenceField, + TextInput, + DateTimeInput, + DateInput, + SelectInput, + NumberInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + DeleteButton, + Button, + useRedirect, + useUnselectAll, +} from 'react-admin'; +import { Box, Typography, Card, Stack } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import AsnOrderModal from "./AsnOrderModal"; +import EmptyData from "../../components/EmptyData"; +import MyCreateButton from "../../components/MyCreateButton"; +import MyExportButton from '../../components/MyExportButton'; +import BillStatusField from '../../components/BillStatusField'; +import ConfirmButton from '../../components/ConfirmButton'; +import PageDrawer from "../../components/PageDrawer"; +import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; +import ConstructionIcon from "@mui/icons-material/Construction"; +import EditIcon from '@mui/icons-material/Edit'; +import TaskIcon from '@mui/icons-material/Task'; +import CloseIcon from '@mui/icons-material/Close'; +import request from '@/utils/request'; +import DictionarySelect from "../../components/DictionarySelect"; +import ExitToAppIcon from '@mui/icons-material/ExitToApp'; +import ImportButton from "../../components/ImportButton"; +import DetailsIcon from '@mui/icons-material/Details'; + +const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ + '& .css-1vooibu-MuiSvgIcon-root': { + height: '.9em' + }, + '& .RaDatagrid-row': { + cursor: 'auto' + }, + '& .column-name': { + }, + '& .opt': { + width: 220 + }, + '& .wkType': { + width: 110 + }, + '& .status': { + width: 90 + }, +})); + +const filters = [ + <SearchInput source="condition" alwaysOn />, + <TextInput source="code" label="table.field.asnOrder.code" />, + <TextInput source="poCode" label="table.field.asnOrder.poCode" />, + <NumberInput source="poId" label="table.field.asnOrder.poId" />, + <TextInput source="type" label="table.field.asnOrder.type" />, + <ReferenceInput source="wkType" reference="dictData" filter={{ dictTypeCode: 'sys_business_type' }} label="table.field.asnOrder.wkType"> + <AutocompleteInput label="table.field.asnOrder.wkType" optionValue="value" /> + </ReferenceInput>, + <NumberInput source="anfme" label="table.field.asnOrder.anfme" />, + <NumberInput source="qty" label="table.field.asnOrder.qty" />, + <TextInput source="logisNo" label="table.field.asnOrder.logisNo" />, + <DateInput source="arrTime" label="table.field.asnOrder.arrTime" />, + <SelectInput source="rleStatus" label="table.field.asnOrder.rleStatus" + choices={[ + { id: 0, name: ' 姝e父' }, + { id: 1, name: ' 宸查噴鏀�' }, + ]} + />, + + <TextInput label="common.field.memo" source="memo" />, + <DictionarySelect + label='table.field.asnOrder.exceStatus' + name="exceStatus" + dictTypeCode="sys_asn_exce_status" + alwaysOn + />, + +] + +const OutOrderList = (props) => { + const translate = useTranslate(); + const [createDialog, setCreateDialog] = useState(false); + const [drawerVal, setDrawerVal] = useState(false); + const [modalType, setmodalType] = useState(0); + const [select, setSelect] = useState(0); + const billReload = useRef(); + const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_business_type')) || []; + return ( + <Box display="flex"> + <List + resource="outStock" + storeKey='outStock' + sx={{ + flexGrow: 1, + transition: (theme) => + theme.transitions.create(['all'], { + duration: theme.transitions.duration.enteringScreen, + }), + marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, + }} + title={"menu.outStock"} + empty={<EmptyData onClick={() => { setCreateDialog(true); setmodalType(0) }} />} + filters={filters} + filter={{deleted: 0, type: 'out'}} + sort={{ field: "create_time", order: "desc" }} + actions={( + <TopToolbar> + <FilterButton /> + <MyCreateButton onClick={() => { setCreateDialog(true); setmodalType(0) }} /> + <SelectColumnsButton preferenceKey='outStock' /> + <ImportButton value={'asnOrderItem'} /> + <MyExportButton /> + </TopToolbar> + )} + perPage={DEFAULT_PAGE_SIZE} + > + <StyledDatagrid + sx={{ width: '100%' }} + preferenceKey='outStock' + bulkActionButtons={ + <> + <MyExportButton /> + {/* <BtnBulkExport></BtnBulkExport> */} + <BulkDeleteButton mutationMode={OPERATE_MODE} + /> + </>} + rowClick={false} + expandSingle={true} + omit={['id', 'createTime', 'createBy', 'memo', 'poId', 'rleStatus$']} + > + <NumberField source="id" /> + <TextField source="code" label="table.field.outStock.code" /> + <TextField source="poCode" label="table.field.outStock.poCode" /> + <NumberField source="poId" label="table.field.outStock.poId" /> + <TextField source="type$" label="table.field.outStock.type" /> + <TextField cellClassName="wkType" source="wkType$" label="table.field.outStock.wkType" /> + <NumberField source="anfme" label="table.field.outStock.anfme" /> + <NumberField source="qty" label="table.field.outStock.qty" /> + <TextField source="logisNo" label="table.field.outStock.logisNo" /> + <TextField source="rleStatus$" label="table.field.outStock.rleStatus" sortable={false} /> + <TextField source="updateBy$" label="common.field.updateBy" /> + <DateField source="updateTime" label="common.field.updateTime" showTime /> + <TextField source="createBy$" label="common.field.createBy" /> + <DateField source="createTime" label="common.field.createTime" showTime /> + <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" > + <EditButton label="toolbar.detail" icon={(<DetailsIcon />)}></EditButton> + <MyButton setCreateDialog={setCreateDialog} setmodalType={setmodalType} /> + {/* <CompleteButton /> */} + </WrapperField> + </StyledDatagrid> + </List> + <AsnOrderModal + open={createDialog} + setOpen={setCreateDialog} + asnId={modalType} + billReload={billReload} + /> + <PageDrawer + title='AsnOrder Detail' + drawerVal={drawerVal} + setDrawerVal={setDrawerVal} + > + </PageDrawer> + </Box > + ) +} +export default OutOrderList; + +const MyButton = ({ setCreateDialog, setmodalType }) => { + const record = useRecordContext(); + const handleEditClick = (btn) => { + btn.stopPropagation(); + const id = record.id; + setmodalType(id); + setCreateDialog(true); + + }; + return ( + <Button + color="primary" + startIcon={<EditIcon />} + onClick={(btn) => handleEditClick(btn)} + sx={{ ml: 1 }} + label={'ra.action.edit'} + > + </Button> + ) +} + +const CompleteButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const requestComplete = async () => { + const { data: { code, data, msg } } = await request.post(`/asnOrder/complete/${record.id}`); + + if (code === 200) { + notify(msg); + refresh() + } else { + notify(msg); + } + } + + return ( + record.exceStatus === 1 && (record.anfme === record.qty ? <Button onClick={requestComplete} label={"toolbar.complete"} color="success"> + <TaskIcon /> + </Button> : <ConfirmButton label={"toolbar.complete"} color="success" data={'褰撳墠鏀惰揣鏁伴噺灏忎簬璁″垝鏁伴噺锛屾槸鍚︾‘璁ゅ畬鎴�'} startIcon={<TaskIcon />} onConfirm={requestComplete} />) + + ) +} + +const CloseButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const requestClose = async () => { + const { data: { code, data, msg } } = await request.post(`/asnOrder/close/${record.id}`); + + if (code === 200) { + notify(msg); + refresh() + } else { + notify(msg); + } + } + + return ( + <ConfirmButton label={"toolbar.close"} color="error" data={'纭鏄惁鍏抽棴锛�'} startIcon={<CloseIcon />} onConfirm={requestClose} /> + ) +} diff --git a/rsf-admin/src/page/orders/outStock/PrintModal.jsx b/rsf-admin/src/page/orders/outStock/PrintModal.jsx new file mode 100644 index 0000000..2ad47fd --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/PrintModal.jsx @@ -0,0 +1,310 @@ +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, + Radio, + RadioGroup, + FormControlLabel, + FormControl, + FormLabel, + TableRow, + TableCell, + Tooltip, + IconButton, + styled + + +} from '@mui/material'; +import DialogCloseButton from "@/page/components/DialogCloseButton"; +import DictionarySelect from "@/page/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 "@/page/components/StatusSelectInput"; + +import { useReactToPrint } from "react-to-print"; +import jsbarcode from 'jsbarcode' +import { el } from "date-fns/locale"; + +const PrintModal = ({ open, setOpen, rows }) => { + const refresh = useRefresh(); + const translate = useTranslate(); + const notify = useNotify(); + const contentRef = useRef(null); + const reactToPrintFn = useReactToPrint({ contentRef }); + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const [value, setValue] = useState('temp1'); + + const handleChange = (event) => { + setValue(event.target.value); + }; + + const handlePrint = () => { + // handleClose() + reactToPrintFn() + }; + + return ( + <Dialog open={open} maxWidth="sm" fullWidth> + <DialogCloseButton onClose={handleClose} /> + <DialogTitle>{translate('toolbar.print')}</DialogTitle> + <DialogContent > + <FormControl > + <RadioGroup + row + aria-labelledby="demo-controlled-radio-buttons-group" + name="controlled-radio-buttons-group" + value={value} + onChange={handleChange} + size="small" + sx={{ justifyContent: 'center' }} + > + <FormControlLabel value="temp1" control={<Radio />} label="妯℃澘1" size="small" /> + </RadioGroup> + </FormControl> + + <Box> + <div style={{ textAlign: 'center', display: 'flex', justifyContent: 'center' }}> + <table + className="contain" + style={{ + overflow: 'hidden', + fontSize: 'small', + tableLayout: 'fixed', + width: '280px', + borderCollapse: 'collapse', // 鍚堝苟杈规 + border: '1px solid black' // 璁剧疆琛ㄦ牸鏁翠綋杈规 + }} + > + <tbody> + <tr style={{ height: '74px' }}> + <td + align="center" + colSpan={3} + style={{ border: '1px solid black' }} // 璁剧疆鍗曞厓鏍艰竟妗� + > + 鍟嗗搧缂栫爜 + </td> + <td + align="center" + className="barcode" + colSpan={9} + style={{ border: '1px solid black' }} + > + <img className="template-code" src={'/img/barcode.jpeg'} style={{ width: '90%' }} alt="Barcode" /> + <div style={{ letterSpacing: '2px', marginTop: '1px', textAlign: 'center' }}> + <span>{'xxxxxx'}</span> + </div> + </td> + </tr> + <tr style={{ height: '74px' }}> + <td + align="center" + colSpan={3} + style={{ border: '1px solid black' }} + > + 鍟嗗搧 + </td> + <td + align="center" + colSpan={5} + style={{ + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + border: '1px solid black' + }} + > + {'xxxxxxxx'} + </td> + <td + align="center" + colSpan={2} + style={{ border: '1px solid black' }} + > + 澶囨敞 + </td> + <td + align="center" + colSpan={2} + style={{ border: '1px solid black' }} + > + {'xx'} + </td> + </tr> + </tbody> + </table> + </div> + <style>{` + @media print { + .print-content { + display: block!important; + } + }`} </style> + <div ref={contentRef} className="print-content" style={{ textAlign: 'center', display: 'none' }}> + <PrintTemp key={'bb'} rows={rows} /> + </div> + </Box> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}> + <Button onClick={handlePrint} variant="contained" startIcon={<SaveIcon />}> + {translate('toolbar.confirm')} + </Button> + </Box> + </DialogActions> + </Dialog > + ); +} + +export default PrintModal; + +const PrintTemp = ({ rows }) => { + const notify = useNotify(); + const [data, setData] = useState([]); + const http = async () => { + const res = await request.post(`/asnOrderItem/many/${rows?.join()}`); + if (res?.data?.code === 200) { + let val = res.data.data.map((el => { + return { + barcode: '/img/barcode.jpeg', + code: el.trackCode, + name: el.maktx, + memo: el.memo || '' + } + })) + setData(val) + setTimeout(() => { + val.forEach((el) => { + jsbarcode(`#barcode${el.code}`, el.code, { height: 30 }); + }); + }, 10); + + } else { + notify(res.data.msg); + } + } + + useEffect(() => { + if (rows?.length > 0) { + http(); + } + + }, [rows]); + + + return ( + <> + {data.map((item, index) => ( + <table + key={index} + className="contain" + style={{ + overflow: 'hidden', + fontSize: 'small', + tableLayout: 'fixed', + width: '520px', + borderCollapse: 'collapse', + borderSpacing: 0, + margin: '0 auto', + marginTop: '10px', + }} + > + <tbody> + <tr style={{ height: '74px' }}> + <td align="center" colSpan={3} style={{ border: '1px solid black' }} > + 鍟嗗搧缂栫爜 + </td> + <td + align="center" + className="barcode" + colSpan={9} + style={{ border: '1px solid black' }} + > + <img id={"barcode" + item.code} style={{ width: '70%', verticalAlign: 'middle' }} /> + {/* <img className="template-code" src={item.barcode} style={{ width: '90%', verticalAlign: 'middle' }} alt="Barcode" /> */} + {/* <div style={{ letterSpacing: '2px', marginTop: '1px', textAlign: 'center' }}> + <span>{item.code}</span> + </div> */} + </td> + </tr> + <tr style={{ height: '74px' }}> + <td + align="center" + colSpan={3} + style={{ border: '1px solid black' }} + > + 鍟嗗搧 + </td> + <td + align="center" + colSpan={5} + style={{ + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + border: '1px solid black' + }} + > + {item.name} + </td> + <td + align="center" + colSpan={2} + style={{ border: '1px solid black' }} + > + 澶囨敞 + </td> + <td + align="center" + colSpan={2} + style={{ border: '1px solid black' }} + > + {item.memo} + </td> + </tr> + </tbody> + </table> + ))} + + </> + ) +} + + diff --git a/rsf-admin/src/page/orders/outStock/asnOrder.css b/rsf-admin/src/page/orders/outStock/asnOrder.css new file mode 100644 index 0000000..0df941e --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/asnOrder.css @@ -0,0 +1,5 @@ + +.custom { + color: rgb(0, 195, 255) !important; + } + diff --git a/rsf-admin/src/page/orders/outStock/index.jsx b/rsf-admin/src/page/orders/outStock/index.jsx new file mode 100644 index 0000000..d710162 --- /dev/null +++ b/rsf-admin/src/page/orders/outStock/index.jsx @@ -0,0 +1,18 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + ListGuesser, + EditGuesser, + ShowGuesser, +} from "react-admin"; + +import OutOrderList from "./OutOrderList"; +import OutOrderEdit from "./OutOrderEdit"; + +export default { + list: OutOrderList, + edit: OutOrderEdit, + show: ShowGuesser, + recordRepresentation: (record) => { + return `${record.name}` + } +}; diff --git a/rsf-admin/src/page/system/serialRule/SerialRuleEdit.jsx b/rsf-admin/src/page/system/serialRule/SerialRuleEdit.jsx index c343e76..e950bb9 100644 --- a/rsf-admin/src/page/system/serialRule/SerialRuleEdit.jsx +++ b/rsf-admin/src/page/system/serialRule/SerialRuleEdit.jsx @@ -61,8 +61,8 @@ defaultValues={{}} // validate={(values) => { }} > - <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}> - <Grid item xs={12} md={8}> + <Grid container width={{ xs: '100%', xl: '90%' }} rowSpacing={3} columnSpacing={3}> + <Grid item xs={16} md={10}> <Typography variant="h6" gutterBottom> {translate('common.edit.title.main')} </Typography> @@ -109,9 +109,8 @@ parse={v => v} /> </Stack> - </Grid> - <Grid item xs={12} md={4}> + <Grid item xs={8} md={2}> <Typography variant="h6" gutterBottom> {translate('common.edit.title.common')} </Typography> diff --git a/rsf-admin/src/page/system/serialRule/SerialRuleItemList.jsx b/rsf-admin/src/page/system/serialRule/SerialRuleItemList.jsx index e2bfea6..a4a436d 100644 --- a/rsf-admin/src/page/system/serialRule/SerialRuleItemList.jsx +++ b/rsf-admin/src/page/system/serialRule/SerialRuleItemList.jsx @@ -142,7 +142,7 @@ setSelect(record) setEditDialog(true) }} - omit={["id", "createTime", "createBy", "memo"]} + omit={["id", "ruleId", "createTime", "createBy", "memo"]} > <NumberField source="id" /> <NumberField @@ -196,7 +196,7 @@ /> <WrapperField cellClassName="opt" label="common.field.opt"> <Button onClick={() => { - setSelect(record) + // setSelect(record) setEditDialog(true) }} label={'ra.action.edit'} > </Button> diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutOrderItemController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutOrderItemController.java new file mode 100644 index 0000000..80939f3 --- /dev/null +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutOrderItemController.java @@ -0,0 +1,185 @@ +package com.vincent.rsf.server.manager.controller; + + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.vincent.rsf.framework.common.Cools; +import com.vincent.rsf.framework.common.R; +import com.vincent.rsf.framework.exception.CoolException; +import com.vincent.rsf.server.common.annotation.OperationLog; +import com.vincent.rsf.server.common.domain.BaseParam; +import com.vincent.rsf.server.common.domain.KeyValVo; +import com.vincent.rsf.server.common.domain.PageParam; +import com.vincent.rsf.server.common.utils.ExcelUtil; +import com.vincent.rsf.server.manager.entity.AsnOrderItem; +import com.vincent.rsf.server.manager.entity.Companys; +import com.vincent.rsf.server.manager.entity.excel.AsnOrderTemplate; +import com.vincent.rsf.server.manager.enums.CompanysType; +import com.vincent.rsf.server.manager.service.AsnOrderItemService; +import com.vincent.rsf.server.manager.service.CompanysService; +import com.vincent.rsf.server.system.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +@Api(tags = "鍑哄簱鍗曟槑缁�") +@RestController +public class OutOrderItemController extends BaseController { + + @Autowired + private AsnOrderItemService asnOrderItemService; + + @Autowired + private CompanysService companysService; + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @ApiOperation("鍒嗛〉鑾峰彇鍒楄〃") + @PostMapping("/outOrderItem/page") + public R page(@RequestBody Map<String, Object> map) { + BaseParam baseParam = buildParam(map, BaseParam.class); + PageParam<AsnOrderItem, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrderItem.class); + return R.ok().add(asnOrderItemService.listByAsnId(pageParam, pageParam.buildWrapper(true))); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @PostMapping("/outOrderItem/list") + public R list(@RequestBody Map<String, Object> map) { + return R.ok().add(asnOrderItemService.list()); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @PostMapping({"/outOrderItem/many/{ids}", "/outOrderItems/many/{ids}"}) + public R many(@PathVariable Long[] ids) { + return R.ok().add(asnOrderItemService.listByIds(Arrays.asList(ids))); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @GetMapping("/outOrderItem/{id}") + public R get(@PathVariable("id") Long id) { + return R.ok().add(asnOrderItemService.getById(id)); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:save')") + @OperationLog("Create 鍑哄簱鍗曟槑缁�") + @PostMapping("/outOrderItem/save") + public R save(@RequestBody Map<String, Object> params) { + if (Objects.isNull(params)) { + throw new CoolException("淇℃伅涓嶈兘涓虹┖锛侊紒"); + } + params.put("createBy", getLoginUserId()); + params.put("updateBy", getLoginUserId()); + + if (!asnOrderItemService.fieldsSave(params)) { + return R.error("Save Fail"); + } + return R.ok("Save Success"); + } + + + @PreAuthorize("hasAuthority('manager:outOrderItem:update')") + @OperationLog("Update 鍑哄簱鍗曟槑缁�") + @PostMapping("/outOrderItem/update") + public R update(@RequestBody AsnOrderItem asnOrderItem) { + asnOrderItem.setUpdateBy(getLoginUserId()); + asnOrderItem.setUpdateTime(new Date()); + if (!Objects.isNull(asnOrderItem.getSplrName()) && StringUtils.isNotBlank(asnOrderItem.getSplrName())) { + Companys companys = companysService.getOne(new LambdaQueryWrapper<Companys>() + .eq(Companys::getType, CompanysType.COMPANYS_TYPE_SUPPLIER.val) + .eq(Companys::getId, asnOrderItem.getSplrName())); + if (!Objects.isNull(companys)) { + asnOrderItem.setSplrCode(companys.getCode()).setSplrName(companys.getName()); + } + } + if (!asnOrderItemService.updateById(asnOrderItem)) { + return R.error("Update Fail"); + } + return R.ok("Update Success").add(asnOrderItem); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:remove')") + @OperationLog("Delete 鍑哄簱鍗曟槑缁�") + @PostMapping("/outOrderItem/remove/{ids}") + public R remove(@PathVariable Long[] ids) { + if (!asnOrderItemService.removeByIds(Arrays.asList(ids))) { + return R.error("Delete Fail"); + } + return R.ok("Delete Success").add(ids); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @PostMapping("/outOrderItem/query") + public R query(@RequestParam(required = false) String condition) { + List<KeyValVo> vos = new ArrayList<>(); + LambdaQueryWrapper<AsnOrderItem> wrapper = new LambdaQueryWrapper<>(); + if (!Cools.isEmpty(condition)) { + wrapper.like(AsnOrderItem::getId, condition); + } + asnOrderItemService.page(new Page<>(1, 30), wrapper).getRecords().forEach( + item -> vos.add(new KeyValVo(item.getId(), item.getId())) + ); + return R.ok().add(vos); + } + + @PreAuthorize("hasAuthority('manager:outOrderItem:list')") + @PostMapping("/outOrderItem/export") + @ApiOperation("瀵煎嚭鍑哄簱鍗曟槑缁�") + public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { + List<AsnOrderItem> orderItems = new ArrayList<>(); + if (!Objects.isNull(map.get("ids"))) { + List<Long> ids = JSONArray.parseArray(JSONObject.toJSONString(map.get("ids")), Long.class); + if (!ids.isEmpty()) { + orderItems = asnOrderItemService.list(new LambdaQueryWrapper<AsnOrderItem>() + .in(AsnOrderItem::getId, ids) + .eq(AsnOrderItem::getStatus, 1)); + } else { + orderItems = asnOrderItemService.list(new LambdaQueryWrapper<>()); + } + } else { + orderItems = asnOrderItemService.list(new LambdaQueryWrapper<>()); + } + + ExcelUtil.build(ExcelUtil.create(orderItems, AsnOrderItem.class, true), response); + } + + /** + * ASN鍗曟嵁鏄庣粏瀵煎叆 + * @param file + * @return + */ + @PostMapping("/outOrderItem/import") + @ApiOperation("ASN瀵煎叆鎺ュ彛") + @PreAuthorize("hasAuthority('manager:outOrderItem:update')") + public R importExcel(@RequestParam(value = "file") MultipartFile file, @RequestParam String asnId) throws Exception { + if (Objects.isNull(file)) { + R.error("鏂囦欢涓嶈兘涓虹┖锛侊紒"); + } + HashMap<String, Object> hashMap = new HashMap<>(); + return asnOrderItemService.excelImport(file, hashMap, getLoginUserId()); + } + + /** + * @author Ryan + * @description 涓嬭浇妯℃澘 + * @param + * @return + * @time 2025/4/18 08:17 + */ + @PostMapping("/outOrderItem/template/download") + @ApiOperation("涓嬭浇鏀惰揣鍗曟ā鏉�") + @PreAuthorize("hasAuthority('manager:outOrderItem:update')") + public void downloadTemplate(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { + AsnOrderTemplate template = ExcelUtil.mockData(AsnOrderTemplate.class); + List<AsnOrderTemplate> list = Arrays.asList(template); + ExcelUtil.build(ExcelUtil.create(list, AsnOrderTemplate.class, true), response); + } + +} 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 new file mode 100644 index 0000000..73618e0 --- /dev/null +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java @@ -0,0 +1,174 @@ +package com.vincent.rsf.server.manager.controller; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.vincent.rsf.framework.common.Cools; +import com.vincent.rsf.framework.common.R; +import com.vincent.rsf.server.api.entity.enums.OrderType; +import com.vincent.rsf.server.api.entity.enums.OrderWorkType; +import com.vincent.rsf.server.common.annotation.OperationLog; +import com.vincent.rsf.server.common.domain.BaseParam; +import com.vincent.rsf.server.common.domain.KeyValVo; +import com.vincent.rsf.server.common.domain.PageParam; +import com.vincent.rsf.server.common.utils.ExcelUtil; +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; +import com.vincent.rsf.server.manager.enums.AsnExceStatus; +import com.vincent.rsf.server.manager.service.AsnOrderItemService; +import com.vincent.rsf.server.manager.service.AsnOrderService; +import com.vincent.rsf.server.system.constant.SerialRuleCode; +import com.vincent.rsf.server.system.controller.BaseController; +import com.vincent.rsf.server.system.utils.SerialRuleUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +@RestController +@Api(tags = "鍑哄簱鍗曟嵁") +public class OutStockController extends BaseController { + + @Autowired + private AsnOrderService asnOrderService; + @Autowired + private AsnOrderItemService asnOrderItemService; + + @PreAuthorize("hasAuthority('manager:outStock:list')") + @PostMapping("/outStock/page") + public R page(@RequestBody Map<String, Object> map) { + BaseParam baseParam = buildParam(map, BaseParam.class); + PageParam<AsnOrder, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrder.class); + return R.ok().add(asnOrderService.page(pageParam, pageParam.buildWrapper(true))); + } + + @PreAuthorize("hasAuthority('manager:outStock:list')") + @PostMapping("/outStock/list") + public R list(@RequestBody Map<String, Object> map) { + return R.ok().add(asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getType, OrderType.ORDER_OUT.type))); + } + + @PreAuthorize("hasAuthority('manager:outStock:list')") + @PostMapping({"/outStock/many/{ids}", "/asnOrders/many/{ids}"}) + public R many(@PathVariable Long[] ids) { + return R.ok().add(asnOrderService.listByIds(Arrays.asList(ids))); + } + + @PreAuthorize("hasAuthority('manager:asnOrder:list')") + @OperationLog("琛ㄥ崟鏌ヨ") + @GetMapping("/outStock/{id}") + public R get(@PathVariable("id") Long id) { + return R.ok().add(asnOrderService.getById(id)); + } + + @PreAuthorize("hasAuthority('manager:outStock:save')") + @OperationLog("Create 鍑哄簱鍗曟嵁") + @PostMapping("/outStock/save") + @ApiOperation("淇濆瓨") + public R save(@RequestBody AsnOrder asnOrder) { + asnOrder.setCreateBy(getLoginUserId()) + .setUpdateBy(getLoginUserId()); + if (!Objects.isNull(asnOrder.getCode())) { + String code = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_OUT_STOCK_CODE, asnOrder); + asnOrder.setCode(code); + } + if (!asnOrderService.save(asnOrder)) { + return R.error("Save Fail"); + } + return R.ok("Save Success").add(asnOrder); + } + + @PreAuthorize("hasAuthority('manager:outStock:update')") + @OperationLog("Update 锛涘嚭搴撳崟鎹�") + @PostMapping("/outStock/update") + @ApiOperation("鏇存柊") + public R update(@RequestBody AsnOrder asnOrder) { + asnOrder.setType(OrderType.ORDER_OUT.type) + .setUpdateBy(getLoginUserId()) + .setUpdateTime(new Date()); + if (!asnOrderService.updateById(asnOrder)) { + return R.error("Update Fail"); + } + return R.ok("Update Success").add(asnOrder); + } + + @PreAuthorize("hasAuthority('manager:outStock:remove')") + @OperationLog("Delete 鍑哄簱鍗曟嵁") + @PostMapping("/outStock/remove/{ids}") + public R remove(@PathVariable Long[] ids) { + if (!asnOrderService.removeByIds(Arrays.asList(ids))) { + return R.error("Delete Fail"); + } + return R.ok("Delete Success").add(ids); + } + + @PreAuthorize("hasAuthority('manager:outStock:list')") + @PostMapping("/outStock/query") + @ApiOperation("鏌ヨ") + public R query(@RequestParam(required = false) String condition) { + List<KeyValVo> vos = new ArrayList<>(); + LambdaQueryWrapper<AsnOrder> wrapper = new LambdaQueryWrapper<>(); + if (!Cools.isEmpty(condition)) { + wrapper.like(AsnOrder::getCode, condition); + } + asnOrderService.page(new Page<>(1, 30), wrapper).getRecords().forEach( + item -> vos.add(new KeyValVo(item.getId(), item.getCode())) + ); + return R.ok().add(vos); + } + + @PreAuthorize("hasAuthority('manager:outStock:list')") + @PostMapping("/outStock/export") + @ApiOperation("瀵煎嚭") + public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { + List<AsnOrder> orders = new ArrayList<>(); + if (!Objects.isNull(map.get("ids"))) { + List<Long> ids = JSONArray.parseArray(JSONObject.toJSONString(map.get("ids")), Long.class); + if (!ids.isEmpty()) { + orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, ids)); + } else { + orders = asnOrderService.list(new LambdaQueryWrapper<>()); + } + } else { + orders = asnOrderService.list(); + } + List<AsnOrderTemplate> orderTemplates = new ArrayList<>(); + for (AsnOrder order : orders) { + List<AsnOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<AsnOrderItem>().eq(AsnOrderItem::getAsnId, order.getId())); + for (AsnOrderItem item : orderItems) { + if (Objects.isNull(item)) { + continue; + } + AsnOrderTemplate template = new AsnOrderTemplate(); + template.setCode(order.getCode()) + .setType(OrderType.getValType(order.getType())) + .setWkType(OrderWorkType.getWorkDesc(order.getWkType())) + .setExceStatus(AsnExceStatus.getExceStatus(order.getExceStatus())) + .setAnfme(item.getAnfme() + "") + .setMaktx(item.getMaktx()) + .setMemo(item.getMemo()) + .setMatnrCode(item.getMatnrCode()) + .setPoCode(item.getPoCode()) + .setSplrName(item.getSplrName()) + .setPoId(order.getPoId() + "") + .setTrackCode(item.getTrackCode()) + .setBarcode(item.getBarcode()) + .setPackName(item.getPackName()) + .setPlatItemId(item.getPlatItemId()) + .setSplrBatch(item.getSplrBatch()) + .setSplrCode(item.getSplrCode()) + .setStockUnit(item.getStockUnit()) + .setPurQty(item.getPurQty() + "") + .setPurUnit(item.getPurUnit()); + orderTemplates.add(template); + } + } + ExcelUtil.build(ExcelUtil.create(orderTemplates, AsnOrderTemplate.class), response); + } +} diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java index 9d2adf7..d0ad509 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java @@ -63,4 +63,10 @@ * DO鍗曟嵁缂栫爜瑙勫垯 */ public final static String SYS_DELIVERY_RULE_CODE = "sys_delivery_rule_code"; + + /** + * 鍑哄簱鍗曟嵁鍙� + */ + public final static String SYS_OUT_STOCK_CODE = "sys_out_stock_code"; + } -- Gitblit v1.9.1