From bfc43ca0e4683c1c0322a6cad5d5be2bc07decc3 Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期四, 24 七月 2025 15:00:44 +0800 Subject: [PATCH] 新增调拔单功能 盘点功能优化 --- rsf-admin/src/page/orders/outStock/OutStockPublic.jsx | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 438 insertions(+), 4 deletions(-) diff --git a/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx b/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx index 6a4a626..0dc8ff5 100644 --- a/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx +++ b/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx @@ -1,3 +1,4 @@ +import { Box, Card, Grid, LinearProgress, Select, MenuItem, ListItemText } from "@mui/material"; import React, { useState, useRef, useEffect, useMemo } from "react"; import { List, @@ -12,7 +13,6 @@ ExportButton, BulkDeleteButton, WrapperField, - Toolbar, useRecordContext, useTranslate, useNotify, @@ -33,19 +33,453 @@ AutocompleteInput, DeleteButton, SimpleForm, + required, Form, - SaveButton, useRefresh, - useGetList, + useRedirect, + useRecordSelection, } from 'react-admin'; +import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE, DEFAULT_ITEM_PAGE_SIZE, DEFAULT_TYPE } from '@/config/setting'; +import { styled } from '@mui/material/styles'; +import { DataGrid, useGridApiContext, GridActionsCellItem, useGridApiRef } from '@mui/x-data-grid'; +import request from '@/utils/request'; +import ConfirmationNumberOutlinedIcon from '@mui/icons-material/ConfirmationNumberOutlined'; +import CloseSharpIcon from '@mui/icons-material/CloseSharp'; +import ConfirmButton from '../../components/ConfirmButton'; +import { Delete, Edit, Add } from '@mui/icons-material'; +import OutStockSiteDialog from "./OutStockSiteDialog"; + +const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ + '& .css-1vooibu-MuiSvgIcon-root': { + height: '.9em' + }, + '& .RaDatagrid-row': { + cursor: 'auto' + }, + '& .column-maktx': { + width: 200 + }, + + mt: '60px' + // '& .RaBulkActionsToolbar-toolbar': { + // display: 'none' + // } + +})); const OutStockPublic = (props) => { + const { record, open, setOpen, setManualDialog } = props; + const notify = useNotify(); + const gridRef = useGridApiRef(); + const [rows, setRows] = useState([]); + const [fetchRows, setFetchRows] = useState([]); + const translate = useTranslate(); + const [rowSelectedIds, setRowSelectedIds] = useState([]); + const [selectedMatnr, setSelectedMatnr] = useState([]); + const [selectedIds, setSelectedIds] = useState([]); + const [formData, setFormData] = useState({ orderId: record?.id, waveId: DEFAULT_TYPE }); + const [dialog, setDialog] = useState(false); + const [selectedValue, setSelectedValue] = useState({}); + + useEffect(() => { + if (selectedMatnr.length < 1) { + setRows(fetchRows) + } else { + const mas = fetchRows.filter(item => selectedMatnr.includes(item.matnrCode)); + setRows(mas) + } + }, [selectedMatnr]) + + + const ComfirmButton = () => { + const { data } = useListContext(); + const [selectedIds, selectionModifiers] = useRecordSelection(); + + const handleRowClick = () => { + console.log(selectedIds); + + const ids = data.filter(item => selectedIds.includes(item.id)).map(item => item.id); + setRowSelectedIds(ids); + const mas = data.filter(item => selectedIds.includes(item.id)).map(item => item.matnrCode); + //璁剧疆搴撲綅淇℃伅绛涢�夋潯浠� + setSelectedMatnr(mas); + } + + return ( + <Button label="toolbar.confirm" size="medium" onClick={handleRowClick} /> + ) + }; + + const handleClickOpen = () => { + setDialog(true); + }; + + const handleClose = (value) => { + setDialog(false); + setSelectedValue(value); + if (selectedIds.length == 0) { + const newRows = rows.map(item => { + return { + ...item, + siteNo: value?.site + } + }) + setRows(newRows); + } else { + const newRows = rows.map(item => { + return selectedIds.includes(item?.id) ? { + ...item, + siteNo: value?.site + } : item + }) + setRows(newRows); + } + }; + + useEffect(() => { + getWaveRule() + }, [open]) + + const getWaveRule = async () => { + if (formData.waveId == null && formData.waveId == undefined) { + return + } + const { data: { code, data, msg } } = await request.post('/outStock/order/getOutTaskItems', { ...formData }); + if (code === 200) { + // setRows(data) + setFetchRows(data) + } else { + notify(msg); + } + } + + const handleChange = (value, name) => { + setFormData((prevData) => ({ + ...prevData, + [name]: value + })); + }; + return ( <> - + <Box> + <Grid sx={{ display: "flex" }} container rowSpacing={2} columnSpacing={2}> + <Grid item xl={5.7} gap={2} > + <Card> + <Form> + <ReferenceInput + source="type" + reference="waveRule" + > + <AutocompleteInput + label="table.field.waveRule.type" + onChange={(e) => handleChange(e, 'waveId')} + defaultValue={15} + value={formData.type} + validate={required()} + /> + </ReferenceInput> + </Form> + <List + resource="outStockItem" + storeKey='outStockItem' + sx={{ + flexGrow: 1, + transition: (theme) => + theme.transitions.create(['all'], { + duration: theme.transitions.duration.enteringScreen, + }), + }} + title={"menu.outStockItem"} + empty={false} + filter={{ orderId: record?.id, deleted: 0 }} + sort={{ field: "create_time", order: "desc" }} + actions={false} + pagination={false} + perPage={DEFAULT_ITEM_PAGE_SIZE} + > + <LinearProgress + sx={{ height: "2px", position: 'absolute', top: 0, left: 0, right: 0, }} + /> + <StyledDatagrid + storeKey={"outStockPublic"} + preferenceKey='outStockItem' + bulkActionButtons={<> + <ComfirmButton /> + </>} + omit={['id', 'splrName', 'qty', 'poCode',]} + > + <NumberField source="id" /> + <TextField source="asnCode" label="table.field.outStockItem.orderCode" /> + <TextField source="poCode" label="table.field.outStockItem.poCode" /> + <TextField source="matnrCode" label="table.field.outStockItem.matnrCode" /> + <TextField source="maktx" label="table.field.outStockItem.maktx" /> + <NumberField source="anfme" label="table.field.outStockItem.anfme" /> + <NumberField source="workQty" label="table.field.outStockItem.workQty" /> + <NumberField source="qty" label="table.field.outStockItem.qty" /> + <TextField source="stockUnit" label="table.field.outStockItem.stockUnit" /> + <TextField source="splrName" label="table.field.outStockItem.splrName" /> + </StyledDatagrid> + </List> + </Card> + </Grid> + <Grid item xl={6.3} gap={2}> + <Card sx={{ minHeight: 1050, height: 'calc(100% - 10px)', width: '100%' }}> + <Box> + <PreviewTable + rows={rows} + gridRef={gridRef} + setRows={setRows} + record={record} + formData={formData} + selectedIds={selectedIds} + setDialog={setDialog} + setSelectedIds={setSelectedIds} + /> + </Box> + <Box sx={{ textAlign: 'center' }}> + <CloseButton setOpen={setOpen} /> + <SubmitButton selectedIds={selectedIds} setSelectedIds={setSelectedIds} gridRef={gridRef} record={record} /> + </Box> + </Card> + </Grid> + </Grid> + <Grid> + <OutStockSiteDialog + selectedValue={selectedValue} + open={dialog} + onClose={handleClose} + /> + </Grid> + </Box> </> ); } +const PreviewTable = ({ rows, gridRef, setRows, record, selectedIds, setSelectedIds, setDialog, formData }) => { + gridRef.current = useGridApiRef(); + const translate = useTranslate(); + + useEffect(() => { + if (selectedIds.length > 0) { + console.log(selectedIds); + } + }, [selectedIds]) + + const baseColumns = [ + // { field: 'id', headerName: 'ID', width: 40 }, + { field: 'locCode', headerName: '搴撲綅', width: 110 }, + { field: 'barcode', headerName: '瀹瑰櫒', width: 120 }, + { field: 'matnrCode', headerName: '鐗╂枡缂栫爜', width: 120 }, + { field: 'batch', headerName: '鎵规', width: 90 }, + { field: 'unit', headerName: '鍗曚綅', width: 60 }, + { field: 'outQty', headerName: '鍑哄簱鏁伴噺', width: 110, }, + { + field: 'anfme', headerName: '搴撳瓨鏁伴噺', width: 110, + renderCell: (params) => ( + <OutStockAnfme value={params.value} /> + ) + }, + { + field: 'siteNo', + headerName: '鍑哄簱鍙�', + width: 90, + type: 'singleSelect', + editable: true, + renderCell: (params) => ( + <OutStockSiteNo value={params.value} /> + ), + renderEditCell: (params) => ( + <OutStockSite {...params} /> + ), + }, + ] + + const optAction = { + field: 'actions', + type: 'actions', + headerName: translate('common.field.opt'), + with: 120, + getActions: (params) => [ + <GridActionsCellItem + icon={<Delete />} + label="Delete" + onClick={() => handleDelete(params.row, rows, setRows)} + />, + ] + } + + const columns = (formData.waveId == 15 || formData.waveId == 16) ? [...baseColumns] : [...baseColumns, optAction]; + + /** + * 鍒犻櫎浜嬩欢 + * @param {*} params + */ + const handleDelete = (params, rows, setRows) => { + const outRows = rows.filter(row => { + return row.id !== params.id + }) + setRows(outRows) + } + + const OutStockAnfme = React.memo(function OutStockAnfme(props) { + const { value } = props; + return ( + value > 0 ? + <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> + <span>{value}</span> + </Box> + : + <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> + <span style={{ color: 'red' }}>{translate('common.edit.title.insuffInventory')}</span> + </Box> + ); + }); + + const OutStockSiteNo = React.memo(function OutStockSiteNo(props) { + const { value } = props; + if (!value) { + return null; + } + return ( + <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> + <span>{value}</span> + </Box> + ); + }); + + const CustomToolBar = () => { + const selectSiteNo = () => { + setDialog(true) + } + return ( + <Box sx={{ + p: 1, + display: 'flex', + justifyContent: 'flex-end', + borderTop: '1px solid rgba(224, 224, 224, 1)' + }}> + <Button + onClick={selectSiteNo} + variant="outlined" + label="toolbar.modiftySite" + size="medium" + sx={{ mr: 1 }} /> + </Box> + ); + } + + const OutStockSite = (params) => { + const { id, field, siteNo, row: { staNos } } = params; + const apiRef = useGridApiContext(); + const handleChange = async (event) => { + await apiRef.current.setEditCellValue( + { id, field, value: event.target.value }, + event, + ); + apiRef.current.stopCellEditMode({ id, field }); + }; + + const handleClose = (event, reason) => { + if (reason === 'backdropClick') { + apiRef.current.stopCellEditMode({ id, field }); + } + }; + + return ( + <Select + value={siteNo} + onChange={handleChange} + MenuProps={{ + onClose: handleClose, + }} + sx={{ + height: '100%', + '& .MuiSelect-select': { + display: 'flex', + alignItems: 'center', + pl: 1, + }, + }} + autoFocus + fullWidth + open + > + {staNos.map((option) => { + return ( + <MenuItem + key={option} + value={option.staNo} + > + <ListItemText sx={{ overflow: 'hidden' }} primary={option.staNo} /> + </MenuItem> + ); + })} + </Select > + ) + } + + return ( + <DataGrid + storeKey={"locItemPreview"} + rows={rows} + columns={columns} + slots={{ toolbar: CustomToolBar }} + apiRef={gridRef} + checkboxSelection + disableRowSelectionOnClick + hideFooterPagination={true} // 闅愯棌鍒嗛〉鎺т欢 + hideFooter={false} + onRowSelectionModelChange={(ids) => { + setSelectedIds(ids) + }} + /> + ) +} + + +//鎻愪氦鎸夐挳 +const SubmitButton = ({ selectedIds, setSelectedIds, gridRef, record }) => { + const notify = useNotify(); + const refresh = useRefresh(); + const redirect = useRedirect(); + const submit = async () => { + const items = gridRef.current?.getSortedRows(); + const { data: { code, data, msg } } = await request.post('/outStock/generate/tasks', { items, outId: record?.id }); + if (code == 200) { + refresh(); + redirect("/task") + } else { + notify(msg); + } + } + return ( + <ConfirmButton + label="toolbar.allComfirm" + variant="contained" + size="medium" + onConfirm={submit} + /> + ) +} + +//鍏抽棴鎸夐挳 +const CloseButton = ({ setOpen }) => { + const close = () => { + setOpen(false) + } + return ( + <Button + label="toolbar.close" + variant="outlined" + size="medium" + onClick={close} + startIcon={<CloseSharpIcon />} + sx={{ margin: '3.5em' }} /> + ) +} + export default OutStockPublic; + + -- Gitblit v1.9.1