美文网首页
node-xlsx 数据转换

node-xlsx 数据转换

作者: achar | 来源:发表于2017-05-10 22:31 被阅读0次

    node-xlsx 数据转换

    公司要将打开记录导入到OA系统中,虽然都是Excel格式,但是因为其数据展示格式不一样,因此需要做一个转换然后才能导入Oa系统中。
    https://github.com/acharzuo/oa_excel_convert

    需求分析

    将打卡机导出的excel转换为oa系统可识别的格式
    这个打开记录是得力考勤机导出的,oa系统使用的是然之,有需要的朋友可以直接去github上下载完整代码。

    需求

    打卡机导出的文件04月汇总表.xls(整体查看)

    打卡机导出的文件

    打卡机导出的文件(放大图)


    打卡机导出的文件(放大图)
    oa考勤导入excel格式oa_attend.xlsx oa考勤导入excel格式`oa_attend.xlsx`
    oa字段说明
    https://www.ranzhico.com/book/ranzhi/83.html#16 oa字段说明

    功能分析

    打卡机文件与OA导入文件对应规则

    | 打卡机单元格 | OA导入单元格 | 名称 | 说明 |
    |---|---|
    | | A:A | 编号 | 顺序号 |
    | K5 | B:B | 用户 | 每人一行;打卡记录姓名与OA姓名不一致,需要准换;
    | C3 | C:C 整列 | 日期(年月) | 需要文字分割转换为日期 |
    | 4:4 整行 | C:C 整列 | 日期(日) | |
    | 6:6 整行 | D:D 整列 | 签到 | 每人一行;单元格中第一个为签到时间|
    | 6:6 整行 | E:E 整列 | 签退 | 每人一行;单元格中最后一个为签退时间|
    | | F:F 整列 | 状态 | 默认normal,见状态分析 |
    || G:G | IP | 默认: "127.0.0.1" |
    || H:H | 设备 | 默认: "得力打卡机01" |
    || I:I | 签到时间 | 默认: "00:00:00" |
    || J:J | 签退时间 | 默认: "00:00:00" |
    || K:K | 原因 | 默认: "" |
    || L:L | 描述 | 默认: "" |
    || M:M | 补录状态 | 默认: "" |
    || N:N | 审核人 | 默认: "" |
    || O:O | 审核时间 | 默认: "0/0/0000 00:00:00" |

    状态分析

    工作时间为:8:50 到 18:00

    | 状态名称 | 状态字 | 成立条件 | 说明 |
    |---|----|--|
    | 正常 | normal | 签到<= 8:50 && >= 18:00 | |
    | 迟到 | late | 签到> 8:50 && 签到< 18:00 && 签退 >=18:00 | |
    | 早退 | early | 签到<= 8:50 && 签退>8:50 && 签退<=18:00 ||
    | 迟到+早退| both | 签到 > 8:50 && 签退 < 18:00 && 签到 != 签退 | |

    技术选型

    原生的直接可以使用vba实现,但是考虑到团队成员的知识储备,在nodejs上会更熟悉,方便将来的维护,遂选用Nodejs,在其体系下做excel转换。

    node-xlsx

    https://github.com/mgcrea/node-xlsx
    进行简单的读写测试通过

    var xlsx = require('node-xlsx'); 
    var fs = require('fs'); 
    // 读取文件 
    const workSheetsFromBuffer = xlsx.parse(fs.readFileSync(${__dirname}/04月汇总表.xls)); 
    // 输出到控制台 
    console.log(JSON.stringify(workSheetsFromBuffer)); 
    const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']]; 
    var buffer = xlsx.build([{name: "mySheetName", data: data}]); // Returns a buffer 
    // 保存文件 
    fs.writeFileSync('user.xlsx', buffer, 'binary');
    

    输出结构

    输出结构

    输出的Excel

    输出的Excel

    config配置信息

    https://github.com/lorenwest/node-config

    开发

    建立github工程

    https://github.com/acharzuo/oa_excel_convert

    初始化nodejs工程

    npm init
    npm install --save node-xlsx
    npm install --save config
    mkdir config
    touch config/default.json
    

    index.js 代码

    var xlsx = require('node-xlsx');
    var fs = require('fs');
    var config = require("config");
    // 获取参数
    var arguments = process.argv.splice(2);
    // 命令行参数判断
    if(!arguments || arguments.length < 1){
    console.log("usage: node index <Excle Filename>")
    return;
    }
    const filename = arguments[0] ;
    const originFilename = `${__dirname}/` + filename;
    const originSheetname = '刷卡记录';
    var originWorkSheets = null
    // 读取文件
    try {
    originWorkSheets = xlsx.parse(fs.readFileSync(originFilename));
    } catch (error) {
    console.error("读取文件错误!\n" + originFilename + error);
    return;
    }
    var originSheetData = null;
    var targetSheetData = null;
    // 读取配置文件
    const WORK_IN_TIME = config.get('workInTime');
    const WORK_OUT_TIME = config.get('workOutTime');
    // 人员对应规则
    const ACCOUNT_PAIR = config.get('accountPair')
    // 转换函数
    // 输入原始数据Sheet的数据,拟合出目标Excel中新Sheet的数据。
    function convert(oriObj) {
    if(typeof oriObj != "object") return;
    var ret = [];
    // 一行的数据
    var line = [
    "", // id   编号
    "", // account  用户
    "", // date 日期
    "", // signIn   签到
    "", // signOut  签退
    "", // status   状态
    "", // ip   IP
    "", // device   设备
    "", // manualIn 签到时间
    "", // manualOut    签退时间
    "", // reason   原因
    "", // desc 描述
    "", // reviewStatus 补录状态
    "", // reviewedBy   审核人
    "" // reviewedDate  审核时间
    ];
    // 行号
    var index = 1 ;
    var month = "";
    const DATE_LINE_INDEX = 3;
    // 遍历所有行
    for( var i = 0; i < oriObj.length; i++){
    // 获取考勤日期的月份
    if( oriObj[i] && oriObj[i][0] && oriObj[i][0] === "考勤日期 : " && oriObj[i][2] ) {
    // 数据格式 模拟 ["2017/04/01 ~ 04/30 (ACHAR科技)"]
    var tmp = oriObj[i][2].split(" ");
    month = tmp[0].substr(0,7).replace("/","-");
    } else if (oriObj[i] && oriObj[i][0] && oriObj[i][0] === "工 号:" && oriObj[i][2]) {
    // 获取每个人每天的记录的记录
    for(var day = 0; day < 31; day++){
    var record = ""; // 打开记录
    if(oriObj[i+1][day]) {
    record = oriObj[i+1][day];
    record = record.trim();
    } else {
    continue;
    }
    var account = oriObj[i][10];
    account = ACCOUNT_PAIR[account];
    if(!account) {
    console.log(oriObj[i][10] + "没有对应的OA账号,已经智能跳过!");
    break;
    }
    // record = "15:45\n18:59\n"
    var recordSplit = record.split("\n");
    var signIn = recordSplit[0]; // 第一次打卡时间为签到时间
    var signOut = recordSplit.length > 1 ? recordSplit[recordSplit.length-1] : ""; // 最后一次打卡时间为签退时间
    // 整理字符格式,使用5位的时间表示方法
    signIn = signIn.length === 4 ? "0" + signIn : signIn;
    signOut = signOut.length === 4 ? "0" + signOut : signOut;
    var status = "normal";
    if(signIn > WORK_IN_TIME && signOut < WORK_OUT_TIME && signIn != signOut ){
    // 迟到早退 签到 > 8:50 && 签退 < 18:00 && 签到 != 签退
    status = "both";
    } else if(signIn > WORK_IN_TIME && signIn < WORK_OUT_TIME && signOut >= WORK_OUT_TIME){
    // 迟到判断 签到> 8:50 && 签到< 18:00 && 签退 >=18:00 
    status = "late";
    } else if (signIn < WORK_IN_TIME && signOut > WORK_IN_TIME && signOut < WORK_OUT_TIME ){
    // 早退判断 签到<= 8:50 && 签退>8:50 && 签退<=18:00
    status = "early";
    }
    var line = [];
    line[0] = index++;
    line[1] = account;
    line[2] = month + "-" + oriObj[DATE_LINE_INDEX][day];
    line[3] = signIn;
    line[4] = signOut;
    line[5] = status;
    line[6] = "127.0.0.1";
    line[7] = "得力打卡机01";
    line[8] = "00:00:00";
    line[9] = "00:00:00";
    line[10] = "";
    line[11] = "";
    line[12] = "";
    line[13] = "";
    line[14] = "0/0/0000 00:00:00";
    ret.push(line);
    }
    }
    }
    
    return ret;
    }
    // 获取指定sheet的数据 ,Sheet名称为:刷卡记录
    for( var i = 0; i < originWorkSheets.length; i++) {
    if(originWorkSheets[i] && originWorkSheets[i].name && originWorkSheets[i].name === originSheetname ) {
    originSheetData = originWorkSheets[i].data;
    }
    }
    // 执行转换
    targetSheetData = convert(originSheetData);
    // 输出转换后的格式
    if (targetSheetData) {
    //console.log(JSON.stringify(targetSheetData));
    var buffer = xlsx.build([{"name": "打卡记录", "data":targetSheetData}]);
    // 保存文件
    fs.writeFileSync( filename.replace(".","_转换."), buffer, 'binary');
    console.log("转换完成!");
    }
    
    

    config/default.json

    {
        "workInTime": "08:50", //上班时间,两位小时: 两位分钟
        "workOutTime": "18:00", //下班时间,两位小时: 两位分钟
        "accountPair": { //打卡机姓名与OA用户名对应"张涛涛": "zhangtaotao",
            "王长顺": "a",
            "京东陈": "b",
            "ACHAR": "c",
            "王思聪": "d",
            "边得力": "e",
            "姜孟女": "f",
            "孙悟空": "g",
            "曹丞相": "h",
            "花木兰": "j",
            "鲁智深": "z",
            "虚竹": "x",
            "芦沟": "cv",
            "大川": "b",
            "胡吗辟谷": "n",
            "春蚕": "n"
        }
    }
    

    文件材料

    见github仓库
    https://github.com/acharzuo/oa_excel_convert

    相关文章

      网友评论

          本文标题: node-xlsx 数据转换

          本文链接:https://www.haomeiwen.com/subject/trcntxtx.html