| import React from 'react'; | 
| import { | 
|     Title, | 
|     useTranslate, | 
|     useNotify, | 
|     useRedirect, | 
|     useRefresh, | 
|     useDelete, | 
| } from 'react-admin'; | 
| import { styled } from '@mui/material/styles'; | 
| 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 RESOURCE = 'matnrGroup'; | 
| const TITLE = 'menu.matnrGroup'; | 
|   | 
| const columns = [ | 
|   | 
|     { | 
|         id: 'code', | 
|         label: 'table.field.matnrGroup.code', | 
|         minWidth: 80, | 
|     }, | 
|     { | 
|         id: 'name', | 
|         label: 'table.field.matnrGroup.name', | 
|         Width: 100, | 
|     }, | 
|     { | 
|         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 StyledTableCell = styled(TableCell)(({ theme }) => ({ | 
|     overflow: 'hidden', | 
|     textOverflow: 'ellipsis', | 
|     whiteSpace: 'nowrap', | 
|     maxWidth: 600, | 
| })); | 
|   | 
| const TreeTableRow = (props) => { | 
|     const { row, depth = 0, openNodes, setOpenNodes, onEdit, onDelete } = props; | 
|     const translate = useTranslate(); | 
|   | 
|     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 [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 ( | 
|         <div> | 
|             <MatnrGroupEdit | 
|                 editRecord={editRecord} | 
|                 open={createDialog} | 
|                 setOpen={setCreateDialog} | 
|                 callback={() => { | 
|                     handleRefresh(); | 
|                 }} | 
|                 resource={RESOURCE} | 
|             /> | 
|             <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="搜索名称" | 
|                         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; |