近日收到一个任务,使用程序自动生成考勤报表,条件是单元格格式必须与模板完全一致,行高、列宽,字体样式等,于是就尝试用node搞一个,遇见了一些坑,不过都趟过去了,接下来一步步展示
首先上效果图
源码地址:https://github.com/jianghaifei/nodeWriteExcel.git
一、框架搭建:
使用的是 node(koa2) + ejs 框架,前后端不分离,框架是次要的,主要还是生成 excel 模块才是重点;
配置 bin 里面的 www 文件可以修改服务端口,目前默认是3000;
在 app.js 中可以配置自己的中间件;
项目代码下载后,先执行 npm install
然后测我环境运营项目可以执行 npm run dev
二、页面引用关系
app.js 注册路由,路由文件在 routes 里面,前后端路由地址都在 write.js 文件中,数据操作在 controller 中;
三、引入生成 excel 相关的插件
安装 node-xlsx 执行命令:npm install node-xlsx
目前只需要引入这一个插件就可以,实际上还需要 xlsx-style xlsx 这两个插件,但是这两个并不完善,需要我们自行修改源码,才能达到使用需求,所以这里就不需要安装,我将源码直接放在public/node-xlsx-c中,在使用中直接引用就好;
这里修改源码为:
1、index.js 中,将第 12 行引用修改为
var _xlsx = _interopRequireDefault(require("./xlsx"));
var _bufferFrom = _interopRequireDefault(require("buffer-from"));
var _helpers = require("./helpers");
var _workbook = _interopRequireDefault(require("./workbook"));
目的是为了引入 xlsx-style ,因为 xlsx-style 也需要修改,所以引入 xlsx.js 文件;修改的目的是为了让单元格样式生效,如 字体颜色,边框,局中等;
2、修改 hepler.js,在136行增加如下代码
if (options['!rows']) {
workSheet['!rows'] = options['!rows'];
}
目的是让opts里的rows能够被添加至workSheet当中
然后再修改在xlsx-style里的xlsx.js write_ws_xml_data 方法,添加设置行高的代码,在10608行
var DEF_PPI = 96,
PPI = DEF_PPI;
function px2pt(px) {
return (px * 96) / PPI;
}
function write_ws_xml_data(ws, opts, idx, wb) {
var o = [],
r = [],
range = safe_decode_range(ws["!ref"]),
cell,
ref,
rr = "",
cols = [],
R,
C,
rows = ws["!rows"];
for (C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for (R = range.s.r; R <= range.e.r; ++R) {
r = [];
rr = encode_row(R);
for (C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
if (ws[ref] === undefined) continue;
if (
(cell = write_ws_xml_cell(
ws[ref],
ref,
ws,
opts,
idx,
wb
)) != null
)
r.push(cell);
}
if (r.length > 0) {
params = { r: rr };
if (rows && rows[R]) {
row = rows[R];
if (row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) {
params.ht = height;
params.customHeight = 1;
}
if (row.level) {
params.outlineLevel = row.level;
}
}
o[o.length] = writextag("row", r.join(""), params);
}
}
if (rows)
for (; R < rows.length; ++R) {
if (rows && rows[R]) {
params = { r: R + 1 };
row = rows[R];
if (row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) {
params.ht = height;
params.customHeight = 1;
}
if (row.level) {
params.outlineLevel = row.level;
}
o[o.length] = writextag("row", "", params);
}
}
return o.join("");
}
需要修改源码的部分就结束了,直接引入
const nodeXlsx = require('../public/node-xlsx-c'); // 引入二次封装好的 xlsx-style xlsx
四、关键的导出代码如下:
// 定义表格数据,列宽,行高,单元格合并
let newdata = [],colArray=[],rowArray=[],range=[];
// 表头样式
const headerStyle = {
font: {
name: '宋体',
bold: true,
sz: '20',
},
alignment: {
horizontal: 'center',
vertical: 'center',
},
};
// 添加表头数据
newdata.push(
[
{
v: '考 勤 记 录 表',
s: headerStyle,
},
],[]
)
// 设定列宽
colArray.push({ wch: 3.91 });
// 设置行高
rowArray.push({ hpx: 15.6 });
// 设置单元格合并
range.push({
s: { c: 0, r: lie },
e: { c: weekarry.length - 1, r: lie },
});
// 文件名称
let name = `${query.title} ${month + 1}月打卡记录`;
// 配置属性,分别为 列宽/行高/单元格合并
const options = {
'!cols': colArray,
'!rows': rowArray,
'!merges': range,
};
// 创建二进制流
const buffer = nodeXlsx.build([{ name: 'sheet1', data: newdata }], options);
// 生成文件
fs.writeFileSync('./public/excelnew/' + name + '.xls', buffer, 'binary');
五、参数配置介绍
原文地址:https://www.npmjs.com/package/xlsx-style
最后配置上系统截图
目前提供的源码只支持导出excel,读取的代码并不复杂,会在下一篇文章体现出来,如有代码遗漏,还请同学们告知。