import React, { useState, useRef, useEffect } from "react";
|
import {
|
Grid, Card, Typography, Button, Checkbox, Tooltip,
|
IconButton,
|
} from '@mui/material';
|
import { useTranslate, useRecordContext, useNotify } from 'react-admin';
|
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
|
import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
|
import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
|
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
|
import AddIcon from '@mui/icons-material/Add';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
import BindMatnrModal from './BindMatnrModal';
|
import BindLocModal from './BindLocModal';
|
import ConfirmModal from "@/page/components/ConfirmModal";
|
import { DataGrid } from '@mui/x-data-grid';
|
import request from '@/utils/request';
|
|
const LocAreaMatPanel = () => {
|
const record = useRecordContext();
|
if (!record) return null;
|
const translate = useTranslate();
|
const notify = useNotify();
|
|
const columns = [
|
{ field: 'id', headerName: 'ID', width: 100 },
|
{ field: 'areaId$', headerName: translate('table.field.locAreaMatRela.areaId'), width: 100 },
|
{ field: 'matnrId$', headerName: translate('table.field.locAreaMatRela.matnrId'), width: 100 },
|
{ field: 'groupId$', headerName: translate('table.field.locAreaMatRela.groupId'), width: 100 },
|
{ field: 'locTypeId$', headerName: translate('table.field.locAreaMatRela.locTypeId'), width: 100 },
|
{ field: 'locId$', headerName: translate('table.field.locAreaMatRela.locId'), width: 100 },
|
{
|
field: 'action',
|
headerName: '操作',
|
minWidth: 100,
|
sticky: 'left',
|
flex: 1,
|
renderCell: (params) => (
|
<Tooltip title="Delete">
|
<IconButton onClick={(e) => handleDelete(params.row, e)}>
|
<DeleteIcon />
|
</IconButton>
|
</Tooltip>
|
),
|
},
|
];
|
|
const handleDelete = async (row, e) => {
|
e.stopPropagation()
|
const { data: { code, data, msg } } = await request.post(`/locAreaMatRela/remove/${row.id}`);
|
|
if (code === 200) {
|
reload()
|
notify(msg);
|
} else {
|
notify(msg);
|
}
|
|
}
|
|
const [parmas, setParmas] = useState({
|
areaMatId: record.id,
|
});
|
|
const [tableData, setTableData] = useState([]);
|
const [matnrTree, setMatnrTree] = useState([]);
|
const [locTree, setLocTree] = useState([]);
|
|
useEffect(() => {
|
reload()
|
}, [parmas])
|
|
const reload = () => {
|
requestTable()
|
requestMatnr()
|
requestLocType()
|
}
|
|
const requestTable = async () => {
|
const { data: { code, data, msg } } = await request.post(`/locAreaMatRela/page`, parmas);
|
|
if (code === 200) {
|
setTableData(data.records || [])
|
} else {
|
notify(msg);
|
}
|
}
|
|
const requestMatnr = async () => {
|
const { data: { code, data, msg } } = await request.get(`/locAreaMatRela/groups/${record.id}`);
|
|
if (code === 200) {
|
setMatnrTree(data || [])
|
} else {
|
notify(msg);
|
}
|
}
|
|
const requestLocType = async () => {
|
const { data: { code, data, msg } } = await request.get(`/locAreaMatRela/locType/${record.id}`);
|
|
if (code === 200) {
|
setLocTree(data || [])
|
} else {
|
notify(msg);
|
}
|
}
|
|
|
return (
|
<Grid container spacing={2}>
|
{/* 物料分组 */}
|
<Grid item xs={2}>
|
<MatnrTree matnrTree={matnrTree} setParmas={setParmas} reload={reload} />
|
</Grid>
|
|
{/* 库位类型 */}
|
<Grid item xs={2}>
|
<LocTree locTree={locTree} setParmas={setParmas} reload={reload} />
|
</Grid>
|
|
{/* 其他内容 */}
|
<Grid item xs={8}>
|
<DataGrid
|
size="small"
|
rows={tableData}
|
columns={columns}
|
checkboxSelection
|
disableColumnMenu={true}
|
disableColumnSorting
|
disableMultipleColumnsSorting
|
columnBufferPx={100}
|
/>
|
</Grid>
|
</Grid>
|
);
|
};
|
|
export default LocAreaMatPanel;
|
|
|
const MatnrTree = ({ matnrTree, setParmas, reload }) => {
|
|
const record = useRecordContext();
|
const notify = useNotify();
|
|
function getItemDescendantsIds(item) {
|
const ids = [];
|
item.children?.forEach((child) => {
|
ids.push(child.id);
|
ids.push(...getItemDescendantsIds(child));
|
});
|
|
return ids;
|
}
|
|
const [selectedItems, setSelectedItems] = useState([]);
|
const toggledItemRef = useRef({});
|
const apiRef = useTreeViewApiRef();
|
|
const handleItemSelectionToggle = (event, itemId, isSelected) => {
|
event.stopPropagation()
|
event.preventDefault();
|
toggledItemRef.current[itemId] = isSelected;
|
};
|
|
const handleSelectedItemsChange = (event, newSelectedItems) => {
|
event.stopPropagation()
|
event.preventDefault();
|
setSelectedItems(newSelectedItems);
|
|
const itemsToSelect = [];
|
const itemsToUnSelect = {};
|
Object.entries(toggledItemRef.current).forEach(([itemId, isSelected]) => {
|
const item = apiRef.current.getItem(itemId);
|
if (isSelected) {
|
itemsToSelect.push(...getItemDescendantsIds(item));
|
} else {
|
getItemDescendantsIds(item).forEach((descendantId) => {
|
itemsToUnSelect[descendantId] = true;
|
});
|
}
|
});
|
|
const newSelectedItemsWithChildren = Array.from(
|
new Set(
|
[...newSelectedItems, ...itemsToSelect].filter(
|
(itemId) => !itemsToUnSelect[itemId],
|
),
|
),
|
);
|
|
setSelectedItems(newSelectedItemsWithChildren);
|
|
toggledItemRef.current = {};
|
};
|
|
const [addDialog, setAddDialog] = useState(false);
|
const [delectDialog, setDelectDialog] = useState(false);
|
|
|
const handleDelete = () => {
|
if (selectedItems.length > 0) {
|
setDelectDialog(true)
|
} else {
|
notify('请选择物料分组');
|
}
|
|
};
|
|
const contirmDelete = async () => {
|
const parmas = {
|
aeaMatId: record.id,
|
groupId: selectedItems
|
}
|
|
const res = await request.post(`/locAreaMatRela/group/remove/`, parmas);
|
if (res?.data?.code === 200) {
|
reload()
|
notify(res.data.msg);
|
|
} else {
|
notify(res.data.msg);
|
}
|
|
};
|
|
const handleAdd = () => {
|
setAddDialog(true)
|
|
};
|
|
const handleNodeSelect = (event, nodeId) => {
|
event.stopPropagation()
|
};
|
|
return (
|
<Card sx={{ p: 1 }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '3px', marginBottom: '3px', borderBottom: '1px dashed #d4d4d4' }}>
|
<div style={{ fontSize: '17px' }}>物料分组</div>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '3px' }}>
|
<AddIcon color={'info'} sx={{ cursor: 'pointer' }} onClick={() => handleAdd()} />
|
|
<DeleteIcon color={'warning'} sx={{ cursor: 'pointer' }} onClick={() => handleDelete()} />
|
</div>
|
</div>
|
|
<RichTreeView
|
expansionTrigger="iconContainer"
|
checkboxSelection
|
multiSelect
|
items={matnrTree}
|
apiRef={apiRef}
|
selectedItems={selectedItems}
|
getItemId={(item) => item.id}
|
getItemLabel={(item) => item.name}
|
defaultExpandedItems={['grid']}
|
onSelectedItemsChange={handleSelectedItemsChange}
|
onItemSelectionToggle={handleItemSelectionToggle}
|
onItemClick={handleNodeSelect}
|
/>
|
|
<BindMatnrModal
|
open={addDialog}
|
setOpen={setAddDialog}
|
selectedItems={selectedItems}
|
reload={reload}
|
/>
|
|
<ConfirmModal
|
open={delectDialog}
|
setOpen={setDelectDialog}
|
onConfirm={contirmDelete}
|
/>
|
</Card>
|
)
|
}
|
|
const LocTree = ({ locTree, setParmas, reload }) => {
|
|
const record = useRecordContext();
|
const notify = useNotify();
|
|
function getItemDescendantsIds(item) {
|
const ids = [];
|
item.children?.forEach((child) => {
|
ids.push(child.id);
|
ids.push(...getItemDescendantsIds(child));
|
});
|
|
return ids;
|
}
|
|
const [selectedItems, setSelectedItems] = useState([]);
|
const toggledItemRef = useRef({});
|
const apiRef = useTreeViewApiRef();
|
|
const handleItemSelectionToggle = (event, itemId, isSelected) => {
|
toggledItemRef.current[itemId] = isSelected;
|
};
|
|
const handleSelectedItemsChange = (event, newSelectedItems) => {
|
setSelectedItems(newSelectedItems);
|
|
const itemsToSelect = [];
|
const itemsToUnSelect = {};
|
Object.entries(toggledItemRef.current).forEach(([itemId, isSelected]) => {
|
const item = apiRef.current.getItem(itemId);
|
if (isSelected) {
|
itemsToSelect.push(...getItemDescendantsIds(item));
|
} else {
|
getItemDescendantsIds(item).forEach((descendantId) => {
|
itemsToUnSelect[descendantId] = true;
|
});
|
}
|
});
|
|
const newSelectedItemsWithChildren = Array.from(
|
new Set(
|
[...newSelectedItems, ...itemsToSelect].filter(
|
(itemId) => !itemsToUnSelect[itemId],
|
),
|
),
|
);
|
|
setSelectedItems(newSelectedItemsWithChildren);
|
|
toggledItemRef.current = {};
|
};
|
|
const [addDialog, setAddDialog] = useState(false);
|
const [delectDialog, setDelectDialog] = useState(false);
|
|
|
const handleDelete = () => {
|
if (selectedItems.length > 0) {
|
setDelectDialog(true)
|
} else {
|
notify('请选择库位类型');
|
}
|
|
};
|
|
const contirmDelete = async () => {
|
const parmas = {
|
areaMatId: record.id,
|
typeId: selectedItems
|
}
|
|
const res = await request.post(`/locAreaMatRela/locType/remove/`, parmas);
|
if (res?.data?.code === 200) {
|
reload()
|
notify(res.data.msg);
|
|
} else {
|
notify(res.data.msg);
|
}
|
|
};
|
|
const handleAdd = () => {
|
setAddDialog(true)
|
|
};
|
|
const handleNodeSelect = (event, nodeId) => {
|
// event.preventDefault();
|
console.log(nodeId)
|
};
|
|
return (
|
<Card sx={{ p: 1 }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '3px', marginBottom: '3px', borderBottom: '1px dashed #d4d4d4' }}>
|
<div style={{ fontSize: '17px' }}>库位类型</div>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '3px' }}>
|
<AddIcon color={'info'} sx={{ cursor: 'pointer' }} onClick={() => handleAdd()} />
|
|
<DeleteIcon color={'warning'} sx={{ cursor: 'pointer' }} onClick={() => handleDelete()} />
|
</div>
|
</div>
|
|
<RichTreeView
|
expansionTrigger="iconContainer"
|
checkboxSelection
|
multiSelect
|
items={locTree}
|
apiRef={apiRef}
|
selectedItems={selectedItems}
|
getItemId={(item) => item.id}
|
getItemLabel={(item) => item.name}
|
defaultExpandedItems={['grid']}
|
onSelectedItemsChange={handleSelectedItemsChange}
|
onItemSelectionToggle={handleItemSelectionToggle}
|
onItemClick={handleNodeSelect}
|
/>
|
|
<BindLocModal
|
open={addDialog}
|
setOpen={setAddDialog}
|
selectedItems={selectedItems}
|
reload={reload}
|
/>
|
|
<ConfirmModal
|
open={delectDialog}
|
setOpen={setDelectDialog}
|
onConfirm={contirmDelete}
|
/>
|
</Card>
|
)
|
}
|