|  |  | 
 |  |  | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; | 
 |  |  | import { useNavigate } from 'react-router-dom'; | 
 |  |  | import React from 'react'; | 
 |  |  | import { | 
 |  |  |     List, | 
 |  |  |     DatagridConfigurable, | 
 |  |  |     SearchInput, | 
 |  |  |     TopToolbar, | 
 |  |  |     SelectColumnsButton, | 
 |  |  |     EditButton, | 
 |  |  |     FilterButton, | 
 |  |  |     CreateButton, | 
 |  |  |     ExportButton, | 
 |  |  |     BulkDeleteButton, | 
 |  |  |     WrapperField, | 
 |  |  |     useRecordContext, | 
 |  |  |     Title, | 
 |  |  |     useTranslate, | 
 |  |  |     useNotify, | 
 |  |  |     useListContext, | 
 |  |  |     FunctionField, | 
 |  |  |     TextField, | 
 |  |  |     NumberField, | 
 |  |  |     DateField, | 
 |  |  |     BooleanField, | 
 |  |  |     ReferenceField, | 
 |  |  |     TextInput, | 
 |  |  |     DateTimeInput, | 
 |  |  |     DateInput, | 
 |  |  |     SelectInput, | 
 |  |  |     NumberInput, | 
 |  |  |     ReferenceInput, | 
 |  |  |     ReferenceArrayInput, | 
 |  |  |     AutocompleteInput, | 
 |  |  |     DeleteButton, | 
 |  |  |     useRedirect, | 
 |  |  |     useRefresh, | 
 |  |  |     useDelete, | 
 |  |  | } from 'react-admin'; | 
 |  |  | import { Box, Typography, Card, Stack } from '@mui/material'; | 
 |  |  | import { styled } from '@mui/material/styles'; | 
 |  |  | import MatnrGroupCreate from "./MatnrGroupCreate"; | 
 |  |  | import MatnrGroupPanel from "./MatnrGroupPanel"; | 
 |  |  | import EmptyData from "@/page/components/EmptyData"; | 
 |  |  | import MyCreateButton from "@/page/components/MyCreateButton"; | 
 |  |  | import MyExportButton from '@/page/components/MyExportButton'; | 
 |  |  | import PageDrawer from "@/page/components/PageDrawer"; | 
 |  |  | import MyField from "@/page/components/MyField"; | 
 |  |  | import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; | 
 |  |  | import * as Common from '@/utils/common'; | 
 |  |  | import { | 
 |  |  |     Box, | 
 |  |  |     Collapse, | 
 |  |  |     IconButton, | 
 |  |  |     Table, | 
 |  |  |     TableBody, | 
 |  |  |     TableCell, | 
 |  |  |     TableContainer, | 
 |  |  |     TableHead, | 
 |  |  |     TableRow, | 
 |  |  |     Paper, | 
 |  |  |     Card, | 
 |  |  |     Typography, | 
 |  |  |     TextField, | 
 |  |  |     Tooltip, | 
 |  |  |     Button, | 
 |  |  |     Chip, | 
 |  |  |     LinearProgress, | 
 |  |  | } from '@mui/material'; | 
 |  |  | import { Add, Edit, Delete } from '@mui/icons-material'; | 
 |  |  | import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; | 
 |  |  | import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; | 
 |  |  | import RefreshIcon from '@mui/icons-material/Refresh'; | 
 |  |  | import request from '@/utils/request'; | 
 |  |  | import MatnrGroupEdit from "./MatnrGroupEdit"; | 
 |  |  | import * as Icons from '@mui/icons-material'; | 
 |  |  |  | 
 |  |  | const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ | 
 |  |  |     '& .css-1vooibu-MuiSvgIcon-root': { | 
 |  |  |         height: '.9em' | 
 |  |  | const RESOURCE = 'matnrGroup'; | 
 |  |  | const TITLE = 'menu.matnrGroup'; | 
 |  |  |  | 
 |  |  | const columns = [ | 
 |  |  |     { | 
 |  |  |         id: 'name', | 
 |  |  |         label: 'table.field.matnrGroup.name', | 
 |  |  |         minWidth: 200, | 
 |  |  |     }, | 
 |  |  |     '& .RaDatagrid-row': { | 
 |  |  |         cursor: 'auto' | 
 |  |  |     { | 
 |  |  |         id: 'code', | 
 |  |  |         label: 'table.field.matnrGroup.code', | 
 |  |  |         minWidth: 80, | 
 |  |  |     }, | 
 |  |  |     '& .column-name': { | 
 |  |  |     }, | 
 |  |  |     '& .opt': { | 
 |  |  |         width: 200 | 
 |  |  |     }, | 
 |  |  |     { | 
 |  |  |         id: 'parentId', | 
 |  |  |         label: 'table.field.matnrGroup.parentId', | 
 |  |  |         minWidth: 100, | 
 |  |  |     } | 
 |  |  | ]; | 
 |  |  |  | 
 |  |  | const getIconComponent = (iconStr) => { | 
 |  |  |     return Icons[iconStr] || null; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const StyledTableRow = styled(TableRow)(({ theme }) => ({ | 
 |  |  |     '& .MuiButtonBase-root': { | 
 |  |  |         padding: '0px 8px' | 
 |  |  |     } | 
 |  |  | })); | 
 |  |  |  | 
 |  |  | const filters = [ | 
 |  |  |     <SearchInput source="condition" alwaysOn />, | 
 |  |  |     <DateInput label='common.time.after' source="timeStart" alwaysOn />, | 
 |  |  |     <DateInput label='common.time.before' source="timeEnd" alwaysOn />, | 
 |  |  | const StyledTableCell = styled(TableCell)(({ theme }) => ({ | 
 |  |  |     overflow: 'hidden', | 
 |  |  |     textOverflow: 'ellipsis', | 
 |  |  |     whiteSpace: 'nowrap', | 
 |  |  |     maxWidth: 600, | 
 |  |  | })); | 
 |  |  |  | 
 |  |  |     <TextInput source="name" label="table.field.matnrGroup.name" />, | 
 |  |  |     <TextInput source="code" label="table.field.matnrGroup.code" />, | 
 |  |  |     <NumberInput source="parentId" label="table.field.matnrGroup.parentId" />, | 
 |  |  | const TreeTableRow = (props) => { | 
 |  |  |     const { row, depth = 0, openNodes, setOpenNodes, onEdit, onDelete } = props; | 
 |  |  |     const translate = useTranslate(); | 
 |  |  |  | 
 |  |  |     <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 toggleNode = (id) => { | 
 |  |  |         setOpenNodes(prevState => ({ ...prevState, [id]: !prevState[id] })); | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     const isOpen = openNodes[row.id] || false; | 
 |  |  |  | 
 |  |  |     return ( | 
 |  |  |         <React.Fragment> | 
 |  |  |             <StyledTableRow hover tabIndex={-1} key={row.id}> | 
 |  |  |                 <StyledTableCell sx={{ padding: 0 }}> | 
 |  |  |                     {row.children && ( | 
 |  |  |                         <IconButton | 
 |  |  |                             aria-label="expand row" | 
 |  |  |                             size="small" | 
 |  |  |                             onClick={() => toggleNode(row.id)} | 
 |  |  |                         > | 
 |  |  |                             {isOpen ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />} | 
 |  |  |                         </IconButton> | 
 |  |  |                     )} | 
 |  |  |                 </StyledTableCell> | 
 |  |  |                 {columns.map((column, idx) => { | 
 |  |  |                     if (column.id !== 'actions') { | 
 |  |  |                         let value = row[column.id]; | 
 |  |  |                         if (column.id === 'name' && row['type'] === 0) { | 
 |  |  |                             value = translate(value); | 
 |  |  |                         } | 
 |  |  |                         return ( | 
 |  |  |                             <StyledTableCell | 
 |  |  |                                 key={column.id} | 
 |  |  |                                 align={column.align || 'left'} | 
 |  |  |                                 style={{ | 
 |  |  |                                     paddingLeft: idx === 0 && (depth * 16 + 16), | 
 |  |  |                                     opacity: column.id === 'icon' && .6 | 
 |  |  |                                 }} | 
 |  |  |                                 onClick={() => toggleNode(row.id)} | 
 |  |  |                             > | 
 |  |  |                                 {column.format ? column.format(value) : value} | 
 |  |  |                             </StyledTableCell> | 
 |  |  |                         ) | 
 |  |  |                     } | 
 |  |  |                 })} | 
 |  |  |                 <StyledTableCell> | 
 |  |  |                     <Tooltip title="Edit"> | 
 |  |  |                         <IconButton onClick={() => onEdit(row)}> | 
 |  |  |                             <Edit /> | 
 |  |  |                         </IconButton> | 
 |  |  |                     </Tooltip> | 
 |  |  |                     <Tooltip title="Delete"> | 
 |  |  |                         <IconButton onClick={() => onDelete(row)}> | 
 |  |  |                             <Delete /> | 
 |  |  |                         </IconButton> | 
 |  |  |                     </Tooltip> | 
 |  |  |                 </StyledTableCell> | 
 |  |  |             </StyledTableRow> | 
 |  |  |             {row.children && isOpen && ( | 
 |  |  |                 row.children.map((child) => ( | 
 |  |  |                     <TreeTableRow | 
 |  |  |                         key={child.id} | 
 |  |  |                         row={child} | 
 |  |  |                         depth={depth + 1} | 
 |  |  |                         onEdit={onEdit} | 
 |  |  |                         onDelete={onDelete} | 
 |  |  |                         openNodes={openNodes} | 
 |  |  |                         setOpenNodes={setOpenNodes} | 
 |  |  |                     /> | 
 |  |  |                 )) | 
 |  |  |             )} | 
 |  |  |         </React.Fragment> | 
 |  |  |     ); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const MatnrGroupList = () => { | 
 |  |  |     const translate = useTranslate(); | 
 |  |  |     const notify = useNotify(); | 
 |  |  |     const redirect = useRedirect(); | 
 |  |  |     const refresh = useRefresh(); | 
 |  |  |     const [deleteOne] = useDelete(); | 
 |  |  |  | 
 |  |  |     const [createDialog, setCreateDialog] = useState(false); | 
 |  |  |     const [drawerVal, setDrawerVal] = useState(false); | 
 |  |  |     const [treeData, setTreeData] = React.useState(null); | 
 |  |  |     const [filter, setFilter] = React.useState(""); | 
 |  |  |     const [createDialog, setCreateDialog] = React.useState(false); | 
 |  |  |     const [editRecord, setEditRecord] = React.useState(null); | 
 |  |  |     const [openNodes, setOpenNodes] = React.useState({}); | 
 |  |  |     const [expandAll, setExpandAll] = React.useState(true); | 
 |  |  |  | 
 |  |  |     const http = async () => { | 
 |  |  |         const res = await request.post(RESOURCE + '/tree', { | 
 |  |  |             condition: filter | 
 |  |  |         }); | 
 |  |  |         if (res?.data?.code === 200) { | 
 |  |  |             setTreeData(res.data.data); | 
 |  |  |         } else { | 
 |  |  |             notify(res.data.msg); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     React.useEffect(() => { | 
 |  |  |         http(); | 
 |  |  |     }, [filter]); | 
 |  |  |  | 
 |  |  |     const handleRefresh = () => { | 
 |  |  |         http(); | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     const handleAdd = () => { | 
 |  |  |         setEditRecord(null); | 
 |  |  |         setCreateDialog(true); | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     const handleEdit = (node) => { | 
 |  |  |         setEditRecord(node); | 
 |  |  |         setCreateDialog(true); | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     const handleDelete = (node) => { | 
 |  |  |         if (window.confirm(translate('ra.message.delete_content'))) { | 
 |  |  |             deleteOne( | 
 |  |  |                 RESOURCE, | 
 |  |  |                 { id: node.id }, | 
 |  |  |                 { | 
 |  |  |                     onSuccess: () => { | 
 |  |  |                         handleRefresh(); | 
 |  |  |                         notify('Department deleted successfully', { type: 'info', messageArgs: { _: 'Department deleted successfully' } }); | 
 |  |  |                     }, | 
 |  |  |                     onError: (error) => { | 
 |  |  |                         notify(`Error: ${error.message}`, { type: 'warning', messageArgs: { _: `Error: ${error.message}` } }); | 
 |  |  |                     }, | 
 |  |  |                 } | 
 |  |  |             ); | 
 |  |  |         } | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     const toggleExpandAll = () => { | 
 |  |  |         setExpandAll(prevExpandAll => { | 
 |  |  |             const newExpandAll = !prevExpandAll; | 
 |  |  |             const newOpenNodes = {}; | 
 |  |  |             const updateOpenNodes = (nodes) => { | 
 |  |  |                 nodes.forEach(node => { | 
 |  |  |                     newOpenNodes[node.id] = newExpandAll; | 
 |  |  |                     if (node.children) { | 
 |  |  |                         updateOpenNodes(node.children); | 
 |  |  |                     } | 
 |  |  |                 }); | 
 |  |  |             }; | 
 |  |  |             updateOpenNodes(treeData); | 
 |  |  |             setOpenNodes(newOpenNodes); | 
 |  |  |             return newExpandAll; | 
 |  |  |         }); | 
 |  |  |     }; | 
 |  |  |  | 
 |  |  |     // 初始化 openNodes 以展开所有节点 | 
 |  |  |     React.useEffect(() => { | 
 |  |  |         if (treeData) { | 
 |  |  |             const newOpenNodes = {}; | 
 |  |  |             const updateOpenNodes = (nodes) => { | 
 |  |  |                 nodes.forEach(node => { | 
 |  |  |                     newOpenNodes[node.id] = true; | 
 |  |  |                     if (node.children) { | 
 |  |  |                         updateOpenNodes(node.children); | 
 |  |  |                     } | 
 |  |  |                 }); | 
 |  |  |             }; | 
 |  |  |             updateOpenNodes(treeData); | 
 |  |  |             setOpenNodes(newOpenNodes); | 
 |  |  |         } | 
 |  |  |     }, [treeData]); | 
 |  |  |  | 
 |  |  |     return ( | 
 |  |  |         <Box display="flex"> | 
 |  |  |             <List | 
 |  |  |                 sx={{ | 
 |  |  |                     flexGrow: 1, | 
 |  |  |                     transition: (theme) => | 
 |  |  |                         theme.transitions.create(['all'], { | 
 |  |  |                             duration: theme.transitions.duration.enteringScreen, | 
 |  |  |                         }), | 
 |  |  |                     marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, | 
 |  |  |                 }} | 
 |  |  |                 title={"menu.matnrGroup"} | 
 |  |  |                 empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} | 
 |  |  |                 filters={filters} | 
 |  |  |                 sort={{ field: "create_time", order: "desc" }} | 
 |  |  |                 actions={( | 
 |  |  |                     <TopToolbar> | 
 |  |  |                         <FilterButton /> | 
 |  |  |                         <MyCreateButton onClick={() => { setCreateDialog(true) }} /> | 
 |  |  |                         <SelectColumnsButton preferenceKey='matnrGroup' /> | 
 |  |  |                         <MyExportButton /> | 
 |  |  |                     </TopToolbar> | 
 |  |  |                 )} | 
 |  |  |                 perPage={DEFAULT_PAGE_SIZE} | 
 |  |  |             > | 
 |  |  |                 <StyledDatagrid | 
 |  |  |                     preferenceKey='matnrGroup' | 
 |  |  |                     bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} | 
 |  |  |                     rowClick={(id, resource, record) => false} | 
 |  |  |                     expand={() => <MatnrGroupPanel />} | 
 |  |  |                     expandSingle={true} | 
 |  |  |                     omit={['id', 'createTime', 'createBy', 'memo']} | 
 |  |  |                 > | 
 |  |  |                     <NumberField source="id" /> | 
 |  |  |                     <TextField source="name" label="table.field.matnrGroup.name" /> | 
 |  |  |                     <TextField source="code" label="table.field.matnrGroup.code" /> | 
 |  |  |                     <NumberField source="parentId" label="table.field.matnrGroup.parentId" /> | 
 |  |  |  | 
 |  |  |                     <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}> | 
 |  |  |                         <TextField source="nickname" /> | 
 |  |  |                     </ReferenceField> | 
 |  |  |                     <DateField source="updateTime" label="common.field.updateTime" showTime /> | 
 |  |  |                     <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}> | 
 |  |  |                         <TextField source="nickname" /> | 
 |  |  |                     </ReferenceField> | 
 |  |  |                     <DateField source="createTime" label="common.field.createTime" showTime /> | 
 |  |  |                     <BooleanField source="statusBool" label="common.field.status" sortable={false} /> | 
 |  |  |                     <TextField source="memo" label="common.field.memo" sortable={false} /> | 
 |  |  |                     <WrapperField cellClassName="opt" label="common.field.opt"> | 
 |  |  |                         <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> | 
 |  |  |                         <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> | 
 |  |  |                     </WrapperField> | 
 |  |  |                 </StyledDatagrid> | 
 |  |  |             </List> | 
 |  |  |             <MatnrGroupCreate | 
 |  |  |         <div> | 
 |  |  |             <MatnrGroupEdit | 
 |  |  |                 editRecord={editRecord} | 
 |  |  |                 open={createDialog} | 
 |  |  |                 setOpen={setCreateDialog} | 
 |  |  |                 callback={() => { | 
 |  |  |                     handleRefresh(); | 
 |  |  |                 }} | 
 |  |  |                 resource={RESOURCE} | 
 |  |  |             /> | 
 |  |  |             <PageDrawer | 
 |  |  |                 title='MatnrGroup Detail' | 
 |  |  |                 drawerVal={drawerVal} | 
 |  |  |                 setDrawerVal={setDrawerVal} | 
 |  |  |             > | 
 |  |  |             </PageDrawer> | 
 |  |  |         </Box> | 
 |  |  |     ) | 
 |  |  |             <Title title={TITLE} /> | 
 |  |  |             <Box sx={{ mt: 2, mr: 3, mb: 1, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> | 
 |  |  |                 <Box width={300} > | 
 |  |  |                     <Button | 
 |  |  |                         variant="outlined" | 
 |  |  |                         color="primary" | 
 |  |  |                         startIcon={expandAll ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />} | 
 |  |  |                         onClick={toggleExpandAll} | 
 |  |  |                         sx={{ ml: 1 }} | 
 |  |  |                     > | 
 |  |  |                         {expandAll ? translate('common.action.collapseAll') : translate('common.action.expandAll')} | 
 |  |  |                     </Button> | 
 |  |  |                     {/* <TextField | 
 |  |  |                         label="Search" | 
 |  |  |                         value={filter} | 
 |  |  |                         onChange={({ target }) => { | 
 |  |  |                             setFilter(target.value) | 
 |  |  |                         }} | 
 |  |  |                         variant="filled" | 
 |  |  |                         size="small" | 
 |  |  |                         margin="dense" | 
 |  |  |                         fullWidth | 
 |  |  |                     /> */} | 
 |  |  |                 </Box> | 
 |  |  |                 <Box> | 
 |  |  |                     <Button | 
 |  |  |                         variant="outlined" | 
 |  |  |                         color="primary" | 
 |  |  |                         startIcon={<RefreshIcon />} | 
 |  |  |                         onClick={handleRefresh} | 
 |  |  |                         sx={{ ml: 1 }} | 
 |  |  |                     > | 
 |  |  |                         {translate('ra.action.refresh')} | 
 |  |  |                     </Button> | 
 |  |  |                     <Button | 
 |  |  |                         variant="outlined" | 
 |  |  |                         color="primary" | 
 |  |  |                         startIcon={<Add />} | 
 |  |  |                         onClick={handleAdd} | 
 |  |  |                         sx={{ ml: 1 }} | 
 |  |  |                     > | 
 |  |  |                         {translate('ra.action.add')} | 
 |  |  |                     </Button> | 
 |  |  |                 </Box> | 
 |  |  |             </Box> | 
 |  |  |             <Card sx={{ | 
 |  |  |                 position: 'relative', | 
 |  |  |             }}> | 
 |  |  |                 {!treeData && ( | 
 |  |  |                     <LinearProgress | 
 |  |  |                         sx={{ | 
 |  |  |                             height: "3px", | 
 |  |  |                             position: 'absolute', | 
 |  |  |                             top: 0, | 
 |  |  |                             left: 0, | 
 |  |  |                             right: 0, | 
 |  |  |                         }} | 
 |  |  |                     /> | 
 |  |  |                 )} | 
 |  |  |                 <TableContainer component={Paper}> | 
 |  |  |                     <Table size="small"> | 
 |  |  |                         <TableHead> | 
 |  |  |                             <TableRow> | 
 |  |  |                                 <StyledTableCell sx={{ padding: 0, width: 60 }} /> | 
 |  |  |                                 {columns.map((column, idx) => ( | 
 |  |  |                                     <StyledTableCell | 
 |  |  |                                         key={idx} | 
 |  |  |                                         align={column.align || 'left'} | 
 |  |  |                                         style={{ | 
 |  |  |                                             minWidth: column.minWidth | 
 |  |  |                                         }} | 
 |  |  |                                     > | 
 |  |  |                                         {translate(column.label)} | 
 |  |  |                                     </StyledTableCell> | 
 |  |  |                                 ))} | 
 |  |  |                             </TableRow> | 
 |  |  |                         </TableHead> | 
 |  |  |                         <TableBody> | 
 |  |  |                             {treeData && treeData.length > 0 && ( | 
 |  |  |                                 treeData.map((row) => ( | 
 |  |  |                                     <TreeTableRow | 
 |  |  |                                         key={row.id} | 
 |  |  |                                         row={row} | 
 |  |  |                                         onEdit={handleEdit} | 
 |  |  |                                         onDelete={handleDelete} | 
 |  |  |                                         openNodes={openNodes} | 
 |  |  |                                         setOpenNodes={setOpenNodes} | 
 |  |  |                                     /> | 
 |  |  |                                 )) | 
 |  |  |                             )} | 
 |  |  |                         </TableBody> | 
 |  |  |                     </Table> | 
 |  |  |                 </TableContainer> | 
 |  |  |             </Card> | 
 |  |  |         </div> | 
 |  |  |     ); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | export default MatnrGroupList; | 
 |  |  | export default MatnrGroupList; |