如何在ASP.NET MVC中导出5层级jqGrid的全部数据至Excel?
解决jqGrid多层级数据完整导出到Excel的问题
我明白你现在的痛点——用jqGrid 5.3.0做的5层级嵌套网格,自带的exportToExcel只能导出当前展开的那一层数据,没法一次性把所有层级的子网格数据都导进Excel。结合你给出的2层级实现代码,我给你分享两个最实用的解决方案:
方案一:手动递归收集所有层级数据,后端生成Excel(推荐)
这个方案的核心是先通过前端JavaScript递归遍历主网格和所有子网格,把所有行数据收集到一个统一的数组里,再传给后端用Excel库生成完整的Excel文件。这种方式完全可控,适合复杂的多层级场景。
步骤1:编写前端递归收集数据的函数
你可以基于现有的子网格ID命名规则(比如GR{parentRowID}_table),写一个递归函数遍历所有层级:
// 收集所有层级的网格数据 function collectAllGridData() { const allData = []; // 先收集主网格的所有行 const mainGridRows = $("#jqGrid").jqGrid('getRowData'); mainGridRows.forEach(mainRow => { // 标记当前行的层级,方便Excel里区分 mainRow.level = 1; allData.push(mainRow); // 递归收集当前行的子网格数据 collectSubGridData(mainRow.ArchiveChecklistMainId_fk, 2, allData); }); return allData; } // 递归收集子网格数据 function collectSubGridData(parentId, currentLevel, allData) { // 根据父ID找到对应的子网格实例 const childGridSelector = `#GR${parentId}_table`; const childGrid = $(childGridSelector); if (childGrid.length === 0) return; // 获取子网格的所有行数据 const childRows = childGrid.jqGrid('getRowData'); childRows.forEach(childRow => { childRow.level = currentLevel; childRow.parentId = parentId; // 记录父ID,方便关联 allData.push(childRow); // 继续递归收集下一级子网格(这里假设第三层级的主键是Coding_Id,根据你的实际结构调整) collectSubGridData(childRow.Coding_Id, currentLevel + 1, allData); }); }
步骤2:前端触发导出请求
添加一个导出按钮,点击时调用收集函数,把数据传给后端:
// 绑定导出按钮点击事件 $("#exportAllBtn").click(function() { const allGridData = collectAllGridData(); $.ajax({ url: '@Url.Action("ExportAllGridData", "Report")', type: 'POST', contentType: 'application/json', data: JSON.stringify(allGridData), xhrFields: { responseType: 'blob' // 接收二进制文件 }, success: function(blob) { // 创建下载链接并触发下载 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `GridFullData_${new Date().toISOString().slice(0,10)}.xlsx`; document.body.appendChild(a); a.click(); // 清理资源 window.URL.revokeObjectURL(url); document.body.removeChild(a); } }); });
步骤3:后端用EPPlus生成Excel
在ASP.NET MVC后端安装EPPlus库(NuGet搜索EPPlus),然后编写导出接口:
using OfficeOpenXml; using System.IO; using System.Web.Mvc; public class ReportController : Controller { [HttpPost] public ActionResult ExportAllGridData(dynamic[] gridData) { // 初始化Excel包 using var package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("Full Grid Data"); // 设置表头(根据你的网格列名调整,这里合并主/子网格的列) var headers = new[] { "层级", "Transmittal No", "主题", "日期", "延迟数", "编码", "版本" }; for (int i = 0; i < headers.Length; i++) { worksheet.Cells[1, i + 1].Value = headers[i]; worksheet.Cells[1, i + 1].Style.Font.Bold = true; } // 填充数据行 int rowIndex = 2; foreach (var row in gridData) { worksheet.Cells[rowIndex, 1].Value = row.level; // 主网格列 worksheet.Cells[rowIndex, 2].Value = row.trans_ref_no ?? string.Empty; worksheet.Cells[rowIndex, 3].Value = row.ChkMain_Subject ?? string.Empty; worksheet.Cells[rowIndex, 4].Value = row.trans_date ?? string.Empty; worksheet.Cells[rowIndex, 5].Value = row.sum_delay_count ?? string.Empty; // 子网格列 worksheet.Cells[rowIndex, 6].Value = row.comp_code ?? string.Empty; worksheet.Cells[rowIndex, 7].Value = row.revision ?? string.Empty; // 给不同层级设置缩进,增强可读性 if (row.level > 1) { worksheet.Cells[rowIndex, 2].Style.Indent = row.level - 1; } rowIndex++; } // 自动调整列宽 worksheet.Cells.AutoFitColumns(); // 生成文件流并返回 var stream = new MemoryStream(); package.SaveAs(stream); stream.Position = 0; return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "FullGridData.xlsx"); } }
方案二:扩展jqGrid的exportToExcel方法
如果你想复用jqGrid自带的导出逻辑,可以修改或扩展exportToExcel方法,让它递归遍历子网格。不过这个方法需要熟悉jqGrid的源码实现,适合有一定源码基础的开发者:
- 找到jqGrid中
exportToExcel的实现部分(通常在grid.export.js文件里) - 在收集当前网格行数据的代码后,添加递归逻辑,遍历当前行的子网格,收集子行数据并添加到导出列表中
- 注意处理子网格列和主网格列的合并,避免表头重复
注意事项
- 确保所有子网格的数据都已加载:如果你的子网格是动态加载(
loadonce: false),需要在收集数据前先展开所有子网格,确保数据已加载到本地 - 层级标识:在Excel里可以用缩进、背景色或字体样式区分不同层级,提高可读性
- 列名兼容:如果不同层级的网格列名不同,需要在后端处理列的映射和填充
内容的提问来源于stack exchange,提问作者Saman
相关产品推荐
相关产品推荐

