Excel 导出不是只能铺数据:我用吾码 V8 做了一张带公式的审批单

📅 发布时间:2026/8/5 2:56:33
Excel 导出不是只能铺数据:我用吾码 V8 做了一张带公式的审批单 项目里有一类 Excel 需求第一次听起来并不复杂把审批单导出来。真正开始做才发现它和普通列表导出不是一回事。表头不止一层标题要横跨整行审批意见左右分栏金额要自动汇总还要控制 A3 横向打印。继续往ExcelData ExcelHeader里塞条件最后通常会得到一段很难维护的“表格导出特例”。吾码 V8 的V8.Office.ExportExcel现在有另一条路径ExcelLayout。它不是围绕“字段”组织工作簿而是按A1、A1:K15这样的 Excel 区域描述值、公式、合并和样式。我拿官方高级示例做了一次实际请求也拆开返回的 xlsx 检查了内部结构确认这条路线确实适合审批单、套打表和复杂报表。列表导出和自由布局解决的不是同一个问题普通业务列表的核心是“字段到列”的映射名称列多宽、金额用什么格式、是否冻结表头。此时ExcelData ExcelHeader很顺手因为数据天然就是一行一条记录。审批单的核心却是“这个区域长什么样”A1:K1放单据编号并合并A2:K2放大标题A3:K3是明细表头D10、F10放汇总公式A11:F11和G11:J11分别放申请人、主管意见A1:K15是固定打印区域。如果先把这种版式强行转换成字段列表代码会一直在和数据模型较劲。ExcelLayout直接使用 Excel 自己的坐标体系反而更接近需求原稿。从源码也能看出两种模式不是同一段代码的参数差异。ExportExcel发现 Sheet 中存在ExcelLayout后会进入WriteExportExcelLayoutSheet先解析每个 Range把样式、值、公式和数据类型累计到单元格状态再创建真实单元格、合并区域、行列尺寸和打印选项。这里有个我很喜欢的实现细节同一单元格的样式不是后写入就整块替换而是进行属性合并。所以可以先给A1:K15统一画细网格再对标题、合计和外框做小范围覆盖。V8 代码会短很多也不用为每个单元格重复写边框。一个可以直接改成自己业务的最小版本下面这段接口引擎代码刻意只保留审批单最关键的结构。复制后改标题、明细数据和审批意见就能得到自己的版本。functioncell(list,range,value,style,merge,dataType){varitem{Range:range};if(value!nulltypeofvalue!undefined)item.Valuevalue;if(style)item.Stylestyle;if(mergetrue)item.Mergetrue;if(dataType)item.DataTypedataType;list.push(item);}functionformula(list,range,expression,style){list.push({Range:range,Formula:expression,Style:style});}varcells[];vargrid{FontName:Microsoft YaHei,FontSize:10,VerticalAlignment:Center,BorderStyle:Thin,BorderColor:7F8C9A,WrapText:true};varcenter{HorizontalAlignment:Center,VerticalAlignment:Center};varmoney{HorizontalAlignment:Right,NumberFormat:#,##0.00};// 先处理整块网格再覆盖局部样式cell(cells,A1:H9,null,grid);cell(cells,A1:H1,设备报废申请单,{Bold:true,FontSize:18,HorizontalAlignment:Center,BorderTopStyle:Medium,BorderTopColor:34495E},true);varheaders[序号,设备编号,设备名称,数量,单价,金额,原因,责任部门];for(vari0;iheaders.length;i){cell(cells,String.fromCharCode(65i)2,headers[i],{Bold:true,BackgroundColor:EEF2F7,HorizontalAlignment:Center});}varrows[[1,EQ-24001,工业网关,2,1200,null,主板损坏,生产部],[2,EQ-24009,扫码终端,1,860,null,无法启动,仓储部]];for(varr0;rrows.length;r){varexcelRowr3;for(varc0;crows[r].length;c){varstylec3c5?money:center;cell(cells,String.fromCharCode(65c)excelRow,rows[r][c],style);}formula(cells,FexcelRow,DexcelRow*EexcelRow,money);}cell(cells,A6:E6,合计,{Bold:true,HorizontalAlignment:Right},true);formula(cells,F6,SUM(F3:F5),{Bold:true,NumberFormat:#,##0.00});cell(cells,A7:D7,申请人张三已电子签,{Bold:true},true);cell(cells,E7:H7,主管意见同意已电子签,{Bold:true},true);cell(cells,A8:H9,说明设备处置完成后原始审批记录交财务归档。,{WrapText:true},true);varresultV8.Office.ExportExcel({OsClient:V8.OsClient,ExcelSheets:[{SheetName:设备报废申请,ExcelLayout:{Cells:cells,Columns:[{Column:A,Width:8},{Column:B,Width:18},{Column:C,Width:24},{Column:D,Width:10},{Column:E,Width:12},{Column:F,Width:14},{Column:G,Width:22},{Column:H,Width:16}],Rows:[{Row:1,Height:42},{Row:2,Height:30},{Row:8,Height:32},{Row:9,Height:32}]},ExcelOptions:{ShowGridLines:false,FreezeRows:2,PrintOrientation:Landscape,PaperSize:A4,FitToWidth:1,PrintArea:A1:H9,ShowPageNumber:true}}]});if(result.Code!1)returnresult;return{Code:1,Data:{FileName:设备报废申请单.xlsx,ContentType:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,FileByteBase64:System.Convert.ToBase64String(result.Data)}};这段代码有三个容易忽略的点。其一公式单元格不要再写死结果。数量和单价是数字金额使用D3*E3合计使用SUM(F3:F5)后续改明细时计算关系仍然存在。其二接口引擎必须开启“响应文件”。ExportExcel返回的是字节数组只有在 HTTP 返回边界才转换为 Base64如果只是内部继续处理没有必要来回编码。其三打印参数应和实际区域一起设计。只设置横向而不设置PrintArea、FitToWidth打开文件看着正常打印时仍可能多出空白页。我实际验证到了哪一步2026 年 8 月 4 日我直接请求了吾码官网文档给出的高级示例接口GET https://api.itdos.com/apiengine/export-excel-advanced-demo--OsClient--iTdos--接口返回 HTTP 200Content-Type是标准 xlsx 类型文件大小为 15,539 字节文件头为50 4B 03 04。随后我按 OOXML 的 ZIP 结构读取工作簿共有 5 个 Sheet“盘盈亏报废申请”包含 11 个合并区域D10、E10、F10分别保存求和、平均和求和公式冻结窗格落在A4页面方向为横向。这能证明线上接口已经生成了带公式、合并、冻结和打印配置的真实工作簿而不只是源码里存在几个尚未执行的方法。边界也要说清楚本次没有在不同版本的 Microsoft Excel、WPS、LibreOffice 上逐一做像素级渲染对比因此我不会声称所有客户端的分页结果完全一致。真正用于套打时仍应该拿目标打印机和客户使用的 Office 软件做一次纸张验收。几个踩坑点比参数表更重要Range不要写成整列或夸张的大区域。高级布局会为覆盖区域创建真实单元格实际只用到A1:K15就不要为了省事给A:K整列套样式。合并区域不能交叉。A7:D7与E7:H7可以并排但两块部分重叠会在生成阶段报错。复杂模板最好先在纸上或 Excel 中把坐标划清楚再翻译成 V8 配置。样式应按“公共底色 → 局部覆盖”组织。先画网格再处理标题、表头、合计和外框比在每个业务单元格里复制一长串字体与边框配置更容易维护。列表和自由布局也不必二选一。一个工作簿的第一张 Sheet 可以用ExcelLayout放审批单第二张 Sheet 继续用ExcelData ExcelHeader放完整明细。对实际项目来说这往往比把所有信息硬塞进一张复杂表更清楚。我的判断很简单需求如果围绕“字段和记录”继续用标准表格导出需求如果围绕“区域和版式”尽早切到ExcelLayout。选对抽象以后复杂 Excel 反而不再复杂。参考资料吾码官方文档V8 函数列表 - 后端Microi.Office 的 ExcelLayout 实现源码