var fs = require('fs'); var book = require('topsin.excelxs'); var db = require('topsin.database'); var crypto = require('topsin.crypto'); var error = require('topsin.error'); // 读取配置文件 var config = JSON.parse(fs.readFile('./config.json')); // 主函数 function Main(props){ // 执行初始化 this.init(); } // 初始化方法 Main.prototype.init = function(){ this.dirlist = this.readDir(config.dirPath, -1) // 获取文件夹下的文件列表 if(this.dirlist.length === 0){ // 没有文件就退出 return } this.readXlsx(this.dirlist) // 循环读取文件列表 } // 读取文件夹 获取xlsx Main.prototype.readDir = function(path){ return fs.listDir(path).filter(function(v){return v.completeSuffix === "XLSX"}) } // 循环读取文件列表 Main.prototype.readXlsx = function(list){ var that = this list.forEach(function(v){ // 读取excel文件 that.excelxs(v.dir + '/' + v.name, v.name) }) } // 读取excelxs Main.prototype.excelxs = function(path,name){ if(book.open(path)) { var sheet = book.getActiveSheet() // 获取当前表 if(sheet.isNull()){return} // 获取表字段数量 var keysCount = sheet.getLastCol() // 获取字段数组 this.keys = [] // 存放所有字段 this.newkeys = [] // (如果有)存放新的字段 this.attrData = config.dataKeys["attr_data"] // 存放 attr_data for(var i=0;i<keysCount;i++){ // 读取第一行的字段 if(config.dataKeys[crypto.md5(sheet.getCellValue(0, i))]){ // 如果是之前存在的字段 直接放入keys 以md5加密作为中介 this.keys.push(config.dataKeys[crypto.md5(sheet.getCellValue(0, i))].dbkey) } else { // 读取不到的字段 可能是attr_data下的 也可能是新增的 if(!this.attrData[crypto.md5(sheet.getCellValue(0, i))]){ // 在attr_data下读取 不存在的是新增的 this.newkeys.push(sheet.getCellValue(0, i)) // 给newkeys添加新增的字段 } } } this.keys.push('attr_data') // keys添加上 attr_data var that = this if(this.newkeys.length !== 0){ // 如果有新增的字段 this.newkeys.forEach(function(v){ var mdkey = crypto.md5(v) // md5状态 var dbkeyArr = [] var str = "" var tempv = v + " " for(var i = 0,len=tempv.length;i<len;i++){ // 数据库字段 命名规则 if(/[a-zA-Z]/.test(tempv[i])){ str += tempv[i].toLowerCase() } else if(tempv[i] === " " || tempv[i] === "\n"){ dbkeyArr.push(str) str = "" } else { i = len } } var dbkey = dbkeyArr.join("_") dbkey += "_" + mdkey.substr(0,10) that.attrData[mdkey] = { // 内存中的attrData添加新字段的map name:v, dbkey: dbkey } config.dataKeys["attr_data"][mdkey] = { // 配置里也要添加 name:v, dbkey: dbkey } }) } var datalist = [] // 定义数组 两次循环获取表数据 for(var j = 1,length = sheet.getLastRow();j<length;j++){ datalist[j-1] = {} datalist[j-1]["attr_data"] = {} // 对attr_data的处理 for(var i = 0;i<keysCount;i++){ // dbkey 是 对应到数据库的key var dbkey = config.dataKeys[crypto.md5(sheet.getCellValue(0, i))] ? config.dataKeys[crypto.md5(sheet.getCellValue(0, i))].dbkey : null if(dbkey === "posting_date"){ // 对日期的特殊处理 datalist[j-1][dbkey] = formatDate(sheet.getCellValue(j, i)) } else if (dbkey === "confirmation_entry_time") { // 对时间的特殊处理 datalist[j-1][dbkey] = formatTime(sheet.getCellValue(j, i)) } else if(!config.dataKeys[crypto.md5(sheet.getCellValue(0, i))]) { // 对attr_data字段的特殊处理 datalist[j-1]["attr_data"][this.attrData[crypto.md5(sheet.getCellValue(0, i))].dbkey] = sheet.getCellValue(j, i) } else { datalist[j-1][dbkey] = sheet.getCellValue(j, i) } } } // 数据处理 this.paytionType({ datalist:datalist }) book.saveAs(config.rdir + '/' + name) // 读取完的文件另存为 然后可以删除 // 删除处理过的文件 fs.unlink(path) book.close() } } Main.prototype.paytionType = function(props){ // 处理数据 db.addConnection(config.dbconfig, "Scott_PMO_TRAINING"); // 连接数据库 this.tablename = 'sec_production_order_confirmation_2' // 设置数据库表名 this.query = db.query('Scott_PMO_TRAINING'); // 获取操作对象 var dbDatas = getDbData(this.query,this.tablename) // 获取数据库的所有数据 if(!dbDatas){return} console.log("数据库的数据数量:" + dbDatas.length) if(this.newkeys.length === 0){ // 不存在新的字段 只要新增就行 // console.log(this.query.deleteRow({ // table:'sec_production_order_confirmation_2', // where: ["id >= 0"] // })) // 删除所有数据 console.log("插入操作"); var res = this.filterOldData(props.datalist,dbDatas) // 数据过滤 var newData = res.newData // 获取要插入的数据 console.log("新的数据:"+newData.length); console.log(newData[0]); if(newData.length === 0) {return} this.insertAny(newData) // 插入数据库操作 } else { // 对旧的数据执行更新操作 对新的数据执行添加 console.log('要对字段扩展:') var res = this.filterOldData(props.datalist,dbDatas,"newkey") // 数据过滤 顺便更新旧的数据 var newData = res.newData // 获取要插入的数据 console.log("新的数据:"+newData.length); console.log(newData[0]); // 插入新数据 if(newData.length === 0) { return } this.insertAny(newData) // 插入数据库操作 } db.removeConnection('Scott_PMO_TRAINING'); // 移除数据库操作 } Main.prototype.insertAny = function(datas){ // 批量插入数据 this.query.begin() var that = this try{ this.query.batchInsert( that.tablename, that.keys, datas ); if (this.query.lastError().isValid()){ throw this.query.lastError().text(); } this.query.commit(); } catch(err) { console.log("插入数据错误") console.log(err) this.query.rollback(); } } function getDbData(query,tablename){ // 获取数据库所有数据 query.begin(); var data; try { data = query.selectArrayMap({ table: tablename, field: '*', field_format:{"tags":'array', attr_data:'json'} }); if (query.lastError().isValid()){ throw query.lastError().text(); } query.commit(); } catch (error) { console.log("获取数据库数据错误"); console.log(error); query.rollback(); // data = false; } return data } // key过滤 根据唯一的key将数据分为两组 一组是新数据 一组是原来的数据 Main.prototype.filterOldData = function (datas,dbdatas, type){ var type = type || null console.log("type:"+ type) // 类型 是否执行字段更新操作 // 获取dbdata的唯一字段列表 dbI = dbdatas.map(function(v){ var tempStr = "" tempStr += v["confirmation"] + v["plant"] + v["material"] + v["posting_date"] + v["confirmation_entry_time"] + v["activity"] return tempStr }) var oldData = [], newData = []; for(var i = 0,len=datas.length;i<len;i++){ var v = datas[i] var dataI = v["confirmation"] + v["plant"] + v["material"] + v["posting_date"] + v["confirmation_entry_time"] + v["activity"] if(dbI.indexOf(dataI) >= 0){ // 老数据 var updateData = {} if(type === "newkey"){ updateData["attr_data"] = v["attr_data"] } // 判断老数据是否更新了 for(var key in v){ if(key==="attr_data"){ var tempflag = false for(var tempdbkey in dbdatas[dbI.indexOf(dataI)][key]){ if(v[key][tempdbkey] && dbdatas[dbI.indexOf(dataI)][key][tempdbkey] != v[key][tempdbkey]){ tempflag = true } } if(tempflag){ updateData["attr_data"] = v["attr_data"] } } else { if(v[key] != dbdatas[dbI.indexOf(dataI)][key]) { updateData[key] = v[key] } } } if(JSON.stringify(updateData) !== "{}"){ // 有要更新的情况 console.log("更新...") this.UpdateKeys(updateData,dbdatas[dbI.indexOf(dataI)]["id"]) } oldData.push(v) } else{ // 新数据 newData.push(v) } } console.log("旧的数据:"+oldData.length) console.log(oldData[oldData.length-1]); return { oldData:oldData, newData:newData } } // 更新数据 Main.prototype.UpdateKeys = function(data,id){ console.log(data) console.log(id) // 执行更新操作 this.query.begin() var that = this try { this.query.updateRow({ table:that.tablename, data:data, where:{id:id}, update_policy:{tags:'array_append', attr_data:'json_merge'} }) if (this.query.lastError().isValid()){ throw this.query.lastError().text(); } this.query.commit(); } catch (error) { console.log("更新错误") console.log(error) this.query.rollback(); } } function formatDate(numb) { var time = new Date((numb - 1) * 24 * 3600000 + 1) time.setYear(time.getFullYear() - 70) var year = time.getFullYear() + '' var month = time.getMonth() + 1 + '' var date = time.getDate() + '' return year + "-" + (month<10?"0"+month:month) + "-" + (date<10?"0"+date:date) } function formatTime(numb) { var hourTmp = numb * 24; var hour = Math.floor(hourTmp); var minuteTmp = hourTmp - hour; var minute = Math.floor(minuteTmp * 60); var secondTmp = (minuteTmp*60) - minute; var second = Math.round(secondTmp*60); if(second >= 60){ second = 0 minute += 1 } if(minute >= 60) { minute = minute - 60 hour += 1 } if(hour >= 24) { hour = 0 } return (hour<10? "0" + hour : hour) + ":" + (minute<10? "0" + minute : minute) + ":" + (second<10? "0" + second : second) } function configReset(bol){ config.isUseing = bol fs.writeFile('./config.json',JSON.stringify(config)) // 覆盖写入json } if(!config.isUseing){ // 如果没在运行程序就可以实例化 configReset(true) // 状态变成运行中 var demo = new Main() configReset(false) // 状态变成未运行 } // ["attr_data","action_data","extra_data","tags","sys_tags","sys_data"]