客户系统做了个考勤统计统计表可以统计考勤数据,现在客户要结算工资了想把上个月的考勤数据导出来处理(是的这关乎到钱钱所以还是挺重要的💸💸)。但是这个考勤统计统计表是个虚拟报表没有物理表直接存储数据,所以直接用吾码低代码平台自带的导出方法无法导出数据😶🌫️😶🌫️,这就需要另写一个接口获取到数据并转成excel文件来导出。
参考✨✨开源低代码平台-Microi吾码-自定义导出Excel-CSDN博客✨✨
最开始我是打算用前端post方法把这个虚拟报表的数据源接口的代码跑一遍,但是这个方法试过之后报错,提示无法拿到token,请教过后发现前端点击导出按钮事件是无法把token传到接口引擎,有两种解决方法:
1. 直接在接口里写死一个token,但是在程序中写死不太好()
2. 把获取数据源的方法直接用后端DataSourceEngine方法,这个接口引擎本身就是后端,没必要再拐弯用前端的方法拿数据,可以直接用后端的方法来获取数据(这才是程序员正常的逻辑,是我能力不佳经验不足了只想着用前端的方法了🥲🥲),到这就体现出我们吾码低代码平台的优势了:前后端直接打通,可以用调用前端方法也可以直接调用后端方法接口,自如调用畅通无阻。
var res = V8.DataSourceEngine.Run({ ModuleEngineKey: ModuleEngineKey, DataSourceKey: DataSourceId, _Where : whereArray,// 查询条件 OsClient: 'crm', }); // 解析返回的数据并只返回 Data 部分 var dataList = res.Data;
3. 因为系统前端看到数据的是支持查询的,现在获取到数据源之后就可以考虑如何把查询条件传进去接口来实现导出的数据也是符合前端查询条件的。但是传入接口的参数和数据源接收到的查询参数是不一样的,数据源查询的参数格式是这样的:
而导出接口传进来的参数格式是这样的:
一个是JSON一个是FormData,所以需要处理一下才可以把符合形式的参数传入数据源接口进行筛选,代码如下:
// V8.Param._Where 是包含所有查询条件的对象 for (let key in V8.Param) { // 检查键是否以 "_Where[" 开头并包含 "][Name]" if (key.startsWith("_Where[") && key.endsWith("][Name]")) { // 提取当前索引 let index = key.match(/\d+/)[0]; // 构造参数对象 let param = { Name: V8.Param[`_Where[${index}][Name]`], Value: V8.Param[`_Where[${index}][Value]`] || [], Type: V8.Param[`_Where[${index}][Type]`], FormEngineKey: V8.Param[`_Where[${index}][FormEngineKey]`] }; // 将参数添加到 whereArray 数组中 whereArray.push(param); } }
这个我最开始也是想用前端post方法来获取,也是token的问题,可以直接通过平台GetTableData方法获取,这里menu表里的DiyTableId 和 where条件里的FormEngineKey 和 Field表里的TableId都是前端可以拿到的TableId,他们都是同☝️个东西(刚开始看的时候差点没给我看迷糊,这个小玩意在每个表都有不同的名字呢☝️😀),查询表头代码关键如下:
var result = V8.FormEngine.GetTableData({ FormEngineKey: 'diy_field', _Where: [{ Name : 'TableId', Value : TableId, Type : '=' }]})
因为查询出来的数据很多都是无用的id类数据,最后呈现出来的只需要真正有数字的数据,所以需要将这些无用的字段剔除掉,同时为了方便用户查看数据,我还把字段顺序调整成和前端查看到的顺序一样。代码如下:
// 定义目标顺序 var targetOrder = ["Name", "ShijianD", "workDays", "normalDays", "missShangban", "missXiaban", "totalLateTime", "totalEarlyTime", "NianJia", "BingJia", "ShiJia"]; // 调整 biaotou 顺序 biaotou = biaotou .filter(header => targetOrder.includes(header.Name)) // 保留在目标顺序中的字段 .sort((a, b) => targetOrder.indexOf(a.Name) - targetOrder.indexOf(b.Name)); // 按目标顺序排序 var Header = biaotou; // 调整 dataList 顺序并删除多余字段 var DataList = dataList.map(row => { var orderedRow = {}; targetOrder.forEach(field => { if (row.hasOwnProperty(field)) { orderedRow[field] = row[field]; // 保留字段的原始值 } }); orderedRow.Component = "Text"; // 为每条记录添加 "Component" 属性,这个数据如果是图片属性就是“ImgUpload” return orderedRow; });
把数据源和表头数据都传入 V8.Office.ExportExcel ,这部分代码直接复制过来就可以啦,代码在这篇里👉开源低代码平台-Microi吾码-自定义导出Excel-CSDN博客
我自己加了一个参数可以根据时间段自定义文件名,如果没有需要也可以不加。完整代码放在下面啦~
如果觉得这篇文章有用的话就三连一下吧!🥰🥰祝您一天都顺利程序不报错🧚♀️🧚♀️
var TableId = V8.Param.TableId;//表Id var ModuleEngineKey = V8.Param.ModuleEngineKey;//模块Id var DataSourceId = V8.Db.FromSql(`select DataSourceId from Diy_Table where Id = '${TableId}'`).ToScalar();//数据源Id,获取表头用到 var TableName = V8.Db.FromSql(`select Name from Diy_Table where Id = '${TableId}'`).ToScalar();//表名,获取表头用到 //大家用的时候不考虑通用的话可以直接等于赋值,不用再通过查表传参获取这些Id,有点麻烦 // 动态提取 _Where 参数并组装成数组 var whereArray = []; var index = 0; // V8.Param._Where 是包含所有查询条件的对象 for (let key in V8.Param) { // 检查键是否以 "_Where[" 开头并包含 "][Name]" if (key.startsWith("_Where[") && key.endsWith("][Name]")) { // 提取当前索引 let index = key.match(/\d+/)[0]; // 构造参数对象 let param = { Name: V8.Param[`_Where[${index}][Name]`], Value: V8.Param[`_Where[${index}][Value]`] || [], Type: V8.Param[`_Where[${index}][Type]`], FormEngineKey: V8.Param[`_Where[${index}][FormEngineKey]`] }; // 将参数添加到 whereArray 数组中 whereArray.push(param); } } /**---------------获取数据源--------------*/ try { var res = V8.DataSourceEngine.Run({ ModuleEngineKey: ModuleEngineKey, DataSourceKey: DataSourceId, _Where : whereArray, OsClient: 'crm', }); // 解析返回的数据并只返回 Data 部分 var dataList = res.Data; } catch (e) { V8.Result = { Code: 0, Data: null, Msg: '获取数据源请求错误:' + res }; return; } /**----------------获取表头---------------*/ try { var result = V8.FormEngine.GetTableData({ FormEngineKey: 'diy_field', _Where: [{ Name : 'TableId', Value : TableId, Type : '=' }] }) // 解析返回的数据并只提取 Name 和 Label 字段 var biaotou = result.Data .filter(field => field.Visible === 1) // 只需要把显示出来的数据导出来就可以了,那些id类的字段不需要一起导出来,所以过滤出 Visible = 1 的字段 .map(field => ({ Name: field.Name,// 这个是英文字段名,这个用于匹配数据源和表头用 Label: field.Label,// 这个是中文字段名,这个是真正要给客户看到的 Component : 'Text' })); } catch (e) { V8.Result = { Code: 0, Data: null, Msg: '获取表头请求错误:' + result }; return; } /**----------------调整dataList字段顺序并删除多余字段---------------*/ // 定义目标顺序,为了导出的数据便于查看,我把字段顺序改成和用户看到的顺序一样了 var targetOrder = ["Name", "ShijianD", "workDays", "normalDays", "missShangban", "missXiaban", "totalLateTime", "totalEarlyTime", "NianJia", "BingJia", "ShiJia"]; // 调整 biaotou 顺序 biaotou = biaotou .filter(header => targetOrder.includes(header.Name)) // 保留在目标顺序中的字段 .sort((a, b) => targetOrder.indexOf(a.Name) - targetOrder.indexOf(b.Name)); // 按目标顺序排序 var Header = biaotou; // 调整 dataList 顺序并删除多余字段 var DataList = dataList.map(row => { var orderedRow = {}; targetOrder.forEach(field => { if (row.hasOwnProperty(field)) { orderedRow[field] = row[field]; // 保留字段的原始值 } }); orderedRow.Component = "Text"; // 为每条记录添加 "Component" 属性 return orderedRow; }); // 导出excel。注:ExportExcel()方法的源码公开在【Microi.Office】插件源码中。 var excelResult = V8.Office.ExportExcel({ OsClient : V8.OsClient, ExcelData : DataList,//传入数据源 ExcelHeader : Header,//传入表头 }); if(excelResult.Code != 1){ V8.Result = excelResult; return; } var excelByte = excelResult.Data; // 从 dataList 中获取 ShijianD 值 var reportPeriod = DataList[0].ShijianD || ""; //返回文件流。注意:接口引擎必须开启【响应文件】 V8.Result = { Code : 1, Data : { FileName : `${reportPeriod}考勤统计表.xls`, ContentType : 'application/vnd.ms-excel', FileByteBase64 : System.Convert.ToBase64String(excelByte) } };