如何在Angular中垂直填充表格?基于NG Zorro实现MITRE矩阵展示
需求与问题
我需要在前端用表格展示MITRE矩阵,后端返回的数据包含每个战术下的工单数量等信息,要求表格按列垂直填充(即一列对应一个技术,该列从上到下依次显示该技术下的所有战术),但目前用NG Zorro写的代码只能填充单列,无法实现多列垂直布局。
后端返回的核心数据结构如下:
"tableData": [ { "technique": "Reconnaissance", "tactics": [ {"tactic": "Active Scanning", "id": "T1595", "total_tickets": 14}, {"tactic": "Gather Victim Host Information", "id": "T1592", "total_tickets": 0}, {"tactic": "Gather Victim Identity Information", "id": "T1589", "total_tickets": 0}, {"tactic": "Gather Victim Network Information", "id": "T1590", "total_tickets": 0}, {"tactic": "Gather Victim Org Information", "id": "T1591", "total_tickets": 2}, {"tactic": "Phishing for Information", "id": "T1598", "total_tickets": 1}, {"tactic": "Search Closed Sources", "id": "T1597", "total_tickets": 0}, {"tactic": "Search Open Technical Databases", "id": "T1596", "total_tickets": 0}, {"tactic": "Search Open Websites/Domains", "id": "T1593", "total_tickets": 0}, {"tactic": "Search Victim-Owned Websites", "id": "T1594", "total_tickets": 1} ] }, { "technique": "Resource Development", "tactics": [ {"tactic": "Acquire Infrastructure", "id": "T1583", "total_tickets": 1}, {"tactic": "Compromise Accounts", "id": "T1586", "total_tickets": 1}, {"tactic": "Compromise Infrastructure", "id": "T1584", "total_tickets": 5}, {"tactic": "Develop Capabilities", "id": "T1587", "total_tickets": 4}, {"tactic": "Establish Accounts", "id": "T1585", "total_tickets": 0}, {"tactic": "Obtain Capabilities", "id": "T1588", "total_tickets": 2}, {"tactic": "Stage Capabilities", "id": "T1608", "total_tickets": 0} ] }, { "technique": "Initial Access", "tactics": [ {"tactic": "Drive-by Compromise", "id": "T1189", "total_tickets": 1}, {"tactic": "Exploit Public-Facing Application", "id": "T1190", "total_tickets": 2}, {"tactic": "External Remote Services", "id": "T1133", "total_tickets": 0}, {"tactic": "Hardware Additions", "id": "T1200", "total_tickets": 0}, {"tactic": "Phishing", "id": "T1566", "total_tickets": 2}, {"tactic": "Replication Through Removable Media", "id": "T1091", "total_tickets": 1}, {"tactic": "Supply Chain Compromise", "id": "T1195", "total_tickets": 0}, {"tactic": "Trusted Relationship", "id": "T1199", "total_tickets": 0}, {"tactic": "Valid Accounts", "id": "T1078", "total_tickets": 8} ] } ]
当前使用NG Zorro的表格代码(仅能填充单列):
<div class="simple-card"> <div class="table-header flex between wrap"> <div class="card-title"> <span *ngIf="isLoading">Cargando...</span> <span *ngIf="!isLoading">{{totalData || 0}} {{title || ''}}</span> </div> </div> <div class="table-container"> <nz-table #basicTable [nzShowPagination]="false" [nzTotal]="totalData" [nzLoading]="isLoading" [nzBordered]="true" [nzData]="data"> <thead> <tr> <th *ngFor="let technique of basicTable.data">{{technique.technique}}</th> </tr> </thead> <tbody> <ng-container *ngFor="let techniqueObject of basicTable.data"> <tr *ngFor="let tacticObject of techniqueObject.tactics"> <td>{{tacticObject.tactic}}: {{tacticObject.total_tickets}}</td> </tr> </ng-container> </tbody> </nz-table> </div> </div>
解决方案
要实现按列垂直填充,需要先转换数据结构,再修改模板渲染逻辑:
1. 组件内转换数据
首先找到所有技术中战术数量的最大值,生成对应行数的数组,每行包含对应位置的各技术战术数据(战术数量不足的技术补空结构)。
在组件的TypeScript代码中添加数据转换逻辑:
// 假设后端返回的数据存储在tableData变量中 transformedData: any[] = []; ngOnInit(): void { // 提取所有技术的战术列表 const tacticsLists = this.tableData.map(item => item.tactics); // 计算最长战术列表长度,确定表格总行数 const maxRows = Math.max(...tacticsLists.map(list => list.length)); // 构建转换后的数据:每行对应表格的一行,每行元素对应各列的战术数据 for (let i = 0; i < maxRows; i++) { const row = this.tableData.map(tech => { return tech.tactics[i] || { tactic: '', total_tickets: 0 }; }); this.transformedData.push(row); } }
2. 修改NG Zorro表格模板
将表格数据源替换为转换后的transformedData,调整表头和表体的渲染逻辑:
<div class="simple-card"> <div class="table-header flex between wrap"> <div class="card-title"> <span *ngIf="isLoading">加载中...</span> <span *ngIf="!isLoading">{{totalData || 0}} {{title || ''}}</span> </div> </div> <div class="table-container"> <nz-table #basicTable [nzShowPagination]="false" [nzTotal]="totalData" [nzLoading]="isLoading" [nzBordered]="true" [nzData]="transformedData"> <thead> <tr> <!-- 表头直接使用原数据中的技术名称 --> <th *ngFor="let tech of tableData">{{tech.technique}}</th> </tr> </thead> <tbody> <!-- 每行渲染对应列的战术信息 --> <tr *ngFor="let row of basicTable.data"> <td *ngFor="let tactic of row"> <span *ngIf="tactic.tactic">{{tactic.tactic}}: {{tactic.total_tickets}}</span> </td> </tr> </tbody> </nz-table> </div> </div>
说明
- 数据转换后,
transformedData的每一项对应表格的一行,每行元素对应各列的战术数据,确保每列垂直填充对应技术的所有战术。 - 对于战术数量较少的技术,空白位置会显示空内容,可根据需求自定义占位文本。
- 表头直接绑定原
tableData的技术名称,保证列数与技术的对应关系正确。
内容的提问来源于stack exchange,提问作者Jair León
相关产品推荐
相关产品推荐

