在Angular Material或Highcharts中实现多层嵌套可折叠表格
实现多层嵌套折叠员工报表方案
一、数据重构:平级转树形结构
原始的EmpNTID(员工ID)、RMNTID(上级ID)平级数据无法直接支持嵌套渲染,必须先转成树形结构,每个节点包含自身信息和下属数组。
重构代码示例(TypeScript)
// 定义原始员工数据结构 interface RawEmployee { empNTID: string; rmNTID: string; name: string; // 其他业务字段(如部门、职位等) } // 定义树形节点结构 interface EmployeeTreeNode extends RawEmployee { children: EmployeeTreeNode[]; } // 从平级数据构建树形结构 function buildEmployeeTree(rawData: RawEmployee[], rootEmpNTID: string): EmployeeTreeNode { // 用Map快速查找节点 const nodeMap = new Map<string, EmployeeTreeNode>(); // 先将所有员工转为树形节点,存入Map rawData.forEach(emp => { nodeMap.set(emp.empNTID, { ...emp, children: [] }); }); // 遍历数据,将每个员工挂载到对应上级的children数组中 rawData.forEach(emp => { if (emp.rmNTID && nodeMap.has(emp.rmNTID)) { nodeMap.get(emp.rmNTID)!.children.push(nodeMap.get(emp.empNTID)!); } }); // 返回根节点(即Carmen对应的EmpNTID) return nodeMap.get(rootEmpNTID)!; }
二、Angular Material 实现多层折叠表格/层级列表
优先用Angular Material的mat-expansion-panel结合递归组件实现,天然支持多层嵌套折叠,完全符合需求。
1. 创建递归子组件(employee-tree-node.component)
这个组件负责渲染单个员工节点,同时递归渲染其下属:
组件模板(employee-tree-node.component.html)
<mat-expansion-panel [expanded]="false"> <mat-expansion-panel-header> <mat-panel-title> {{ node.name }} ({{ node.empNTID }}) </mat-panel-title> <mat-panel-description> {{ node.position }} | {{ node.department }} </mat-panel-description> </mat-expansion-panel-header> <!-- 显示当前员工的详细信息(表格行形式) --> <div class="employee-details"> <table mat-table [dataSource]="[node]" class="mat-elevation-z1"> <ng-container matColumnDef="empNTID"> <th mat-header-cell *matHeaderCellDef>员工ID</th> <td mat-cell *matCellDef="let emp">{{ emp.empNTID }}</td> </ng-container> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef>姓名</th> <td mat-cell *matCellDef="let emp">{{ emp.name }}</td> </ng-container> <ng-container matColumnDef="department"> <th mat-header-cell *matHeaderCellDef>部门</th> <td mat-cell *matCellDef="let emp">{{ emp.department }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> </div> <!-- 递归渲染下属节点 --> <app-employee-tree-node *ngFor="let child of node.children" [node]="child"> </app-employee-tree-node> </mat-expansion-panel>
组件类(employee-tree-node.component.ts)
import { Component, Input } from '@angular/core'; import { EmployeeTreeNode } from '../models/employee.model'; @Component({ selector: 'app-employee-tree-node', templateUrl: './employee-tree-node.component.html', styleUrls: ['./employee-tree-node.component.scss'] }) export class EmployeeTreeNodeComponent { @Input() node!: EmployeeTreeNode; displayedColumns: string[] = ['empNTID', 'name', 'department']; }
2. 父组件调用(根组件)
在父组件中加载原始数据,构建树形结构后,渲染根节点(Carmen):
父组件模板(app.component.html)
<div class="container"> <h2>层级员工报表</h2> <app-employee-tree-node [node]="rootEmployee"></app-employee-tree-node> </div>
父组件类(app.component.ts)
import { Component, OnInit } from '@angular/core'; import { RawEmployee, EmployeeTreeNode, buildEmployeeTree } from './models/employee.model'; // 假设从API获取数据,这里用模拟数据示例 const mockRawData: RawEmployee[] = [ { empNTID: 'Carmen001', rmNTID: null, name: 'Carmen', department: '总部', position: 'CEO' }, { empNTID: 'Bob001', rmNTID: 'Carmen001', name: 'Bob', department: '研发部', position: '研发经理' }, { empNTID: 'Alice001', rmNTID: 'Bob001', name: 'Alice', department: '研发部', position: '前端开发' }, // 更多员工数据... ]; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { rootEmployee!: EmployeeTreeNode; ngOnInit(): void { // 构建树形结构,传入Carmen的EmpNTID this.rootEmployee = buildEmployeeTree(mockRawData, 'Carmen001'); } }
三、关于Highcharts的说明
Highcharts核心是图表组件,并不擅长实现嵌套表格的折叠功能,不符合你“表格形式呈现”的需求,因此不建议用Highcharts实现该功能。
四、关键注意事项
- 确保原始数据中顶层员工(Carmen)的
RMNTID为null或唯一标识(如空字符串),避免构建树形结构时出错。 - 如果员工数量较多,可考虑添加懒加载:点击展开时再请求该员工的下属数据,而非一次性构建完整树形结构。
内容的提问来源于stack exchange,提问作者FlyFish
相关产品推荐
相关产品推荐

