node(koa2+ejs) 通过 node-xlsx xlsx-style xlsx 生成带有格式的 excel

近日收到一个任务,使用程序自动生成考勤报表,条件是单元格格式必须与模板完全一致,行高、列宽,字体样式等,于是就尝试用node搞一个,遇见了一些坑,不过都趟过去了,接下来一步步展示

首先上效果图


微信截图_20210414104933.png

源码地址: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中,在使用中直接引用就好;

微信截图_20210414123537.png

这里修改源码为:

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

微信截图_20210414132323.png

最后配置上系统截图


微信截图_20210414133208.png

目前提供的源码只支持导出excel,读取的代码并不复杂,会在下一篇文章体现出来,如有代码遗漏,还请同学们告知。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容