| import React, { useState } from "react"; | 
| import { | 
|   Table, | 
|   TableBody, | 
|   TableCell, | 
|   TableHead, | 
|   TableRow, | 
|   IconButton, | 
|   Checkbox, | 
| } from "@mui/material"; | 
| import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; | 
| import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; | 
|   | 
| // 递归收集所有节点的 ID | 
| const collectAllNodeIds = (nodes) => { | 
|   let allIds = []; | 
|   nodes.forEach((node) => { | 
|     allIds.push(node.id); | 
|     if (node.children) { | 
|       allIds = allIds.concat(collectAllNodeIds(node.children)); | 
|     } | 
|   }); | 
|   return allIds; | 
| }; | 
|   | 
| // 递归收集某个节点及其所有子节点的 ID | 
| const collectNodeAndChildrenIds = (node) => { | 
|   let ids = [node.id]; | 
|   if (node.children) { | 
|     node.children.forEach((child) => { | 
|       ids = ids.concat(collectNodeAndChildrenIds(child)); | 
|     }); | 
|   } | 
|   return ids; | 
| }; | 
|   | 
| // 检查某个节点的所有子节点是否都被选中 | 
| const areAllChildrenSelected = (node, selectedNodeIds) => { | 
|   const childrenIds = collectAllNodeIds(node.children || []); | 
|   return childrenIds.every((id) => selectedNodeIds.includes(id)); | 
| }; | 
|   | 
| // 递归渲染树状表格行 | 
| const renderTreeRows = ( | 
|   nodes, | 
|   level = 0, | 
|   openNodes, | 
|   setOpenNodes, | 
|   selectedNodeIds, | 
|   setSelectedNodeIds, | 
| ) => { | 
|   return nodes.map((node) => { | 
|     const isOpen = openNodes.includes(node.id); | 
|     const toggleOpen = () => { | 
|       if (isOpen) { | 
|         setOpenNodes(openNodes.filter((id) => id !== node.id)); | 
|       } else { | 
|         setOpenNodes([...openNodes, node.id]); | 
|       } | 
|     }; | 
|   | 
|     const allChildrenIds = collectNodeAndChildrenIds(node); | 
|     const allChildrenSelected = allChildrenIds.every((id) => | 
|       selectedNodeIds.includes(id), | 
|     ); | 
|     const someChildrenSelected = | 
|       allChildrenIds.some((id) => selectedNodeIds.includes(id)) && | 
|       !allChildrenSelected; | 
|   | 
|     const handleCheckboxChange = () => { | 
|       let newSelectedNodeIds = [...selectedNodeIds]; | 
|       if (allChildrenSelected) { | 
|         allChildrenIds.forEach((id) => { | 
|           newSelectedNodeIds = newSelectedNodeIds.filter( | 
|             (selectedId) => selectedId !== id, | 
|           ); | 
|         }); | 
|       } else { | 
|         allChildrenIds.forEach((id) => { | 
|           if (!newSelectedNodeIds.includes(id)) { | 
|             newSelectedNodeIds.push(id); | 
|           } | 
|         }); | 
|       } | 
|       setSelectedNodeIds(newSelectedNodeIds); | 
|     }; | 
|   | 
|     return ( | 
|       <React.Fragment key={node.id}> | 
|         <TableRow size="small"> | 
|           <TableCell padding="none" width={20}> | 
|             {node.children && ( | 
|               <IconButton size="small" onClick={toggleOpen}> | 
|                 {isOpen ? ( | 
|                   <KeyboardArrowDownIcon fontSize="small" /> | 
|                 ) : ( | 
|                   <KeyboardArrowRightIcon fontSize="small" /> | 
|                 )} | 
|               </IconButton> | 
|             )} | 
|           </TableCell> | 
|           <TableCell width={20} style={{ paddingLeft: 20 * level }}> | 
|             <Checkbox | 
|               size="small" | 
|               checked={allChildrenSelected} | 
|               indeterminate={someChildrenSelected} | 
|               onChange={handleCheckboxChange} | 
|             /> | 
|           </TableCell> | 
|           <TableCell>{node.matnrCode}</TableCell> | 
|           <TableCell>{node.fullName || node.matnrName}</TableCell> | 
|           <TableCell>{node.matnrGroupId}</TableCell> | 
|           <TableCell>{node.specification || "-"}</TableCell> | 
|           <TableCell>{node.color || "-"}</TableCell> | 
|           <TableCell>{node.size || "-"}</TableCell> | 
|           <TableCell>{node.minWeight || "-"}</TableCell> | 
|           <TableCell>{node.maxWeight || "-"}</TableCell> | 
|         </TableRow> | 
|         {isOpen && | 
|           node.children && | 
|           renderTreeRows( | 
|             node.children, | 
|             level + 1, | 
|             openNodes, | 
|             setOpenNodes, | 
|             selectedNodeIds, | 
|             setSelectedNodeIds, | 
|           )} | 
|       </React.Fragment> | 
|     ); | 
|   }); | 
| }; | 
|   | 
| const TreeTable = ({ data }) => { | 
|   const [openNodes, setOpenNodes] = useState([]); | 
|   const [selectedNodeIds, setSelectedNodeIds] = useState([]); | 
|   const allNodeIds = collectAllNodeIds(data); | 
|   | 
|   const handleSelectAll = (event) => { | 
|     if (event.target.checked) { | 
|       setSelectedNodeIds(allNodeIds); | 
|     } else { | 
|       setSelectedNodeIds([]); | 
|     } | 
|   }; | 
|   | 
|   const isAllSelected = selectedNodeIds.length === allNodeIds.length; | 
|   | 
|   return ( | 
|     <Table size="small" style={{ backgroundColor: "#121317" }}> | 
|       <TableHead> | 
|         <TableRow size="small"> | 
|           <TableCell width={20}></TableCell> | 
|           <TableCell width={20}> | 
|             <Checkbox | 
|               size="small" | 
|               checked={isAllSelected} | 
|               indeterminate={ | 
|                 selectedNodeIds.length > 0 && | 
|                 selectedNodeIds.length < allNodeIds.length | 
|               } | 
|               onChange={handleSelectAll} | 
|             /> | 
|           </TableCell> | 
|           <TableCell>物料编码</TableCell> | 
|           <TableCell>物料名称</TableCell> | 
|           <TableCell>物料分组</TableCell> | 
|           <TableCell>规格</TableCell> | 
|           <TableCell>颜色</TableCell> | 
|           <TableCell>尺寸</TableCell> | 
|           <TableCell>最小重量</TableCell> | 
|           <TableCell>最大重量</TableCell> | 
|         </TableRow> | 
|       </TableHead> | 
|       <TableBody> | 
|         {renderTreeRows( | 
|           data, | 
|           0, | 
|           openNodes, | 
|           setOpenNodes, | 
|           selectedNodeIds, | 
|           setSelectedNodeIds, | 
|         )} | 
|       </TableBody> | 
|     </Table> | 
|   ); | 
| }; | 
|   | 
| export default TreeTable; |