'use strict'; /** * * * @author Zhong * @date 2018/6/1 * @version */ import mongoose from 'mongoose'; import CompilationModel from "../../users/models/compilation_model"; import moment from 'moment'; const uuidV1 = require('uuid/v1'); const billsLibModel = mongoose.model('std_bills_lib_list'); const billsGuideLibModel = mongoose.model('std_billsGuidance_lib'); const billsGuideItemsModel = mongoose.model('std_billsGuidance_items'); const stdBillsLibModel = mongoose.model('std_bills_lib_list'); const stdBillsModel = mongoose.model('std_bills_lib_bills'); const stdBillsJobsModel = mongoose.model('std_bills_lib_jobContent'); const stdRationModel = mongoose.model('std_ration_lib_ration_items'); const engLibModel = mongoose.model('engineering_lib'); const _ = require('lodash'); module.exports = { getComBillsLibInfo, getBillsGuideLibs, initBillsGuideLib, updateBillsGuideLib, getLibWithBills, getItemsBybills, updateItems, testItems }; async function getCompilationList(req) { let compilationModel = new CompilationModel(); return await compilationModel.getPermissionCompilationList(req); } async function getComBillsLibInfo(req) { let rst = { compilationList: [], billsLibs: [] }; let compilationList = await getCompilationList(req); if (compilationList.length <= 0) { throw '没有数据'; } else { for (let compilation of compilationList) { rst.compilationList.push({ _id: compilation._id, name: compilation.name }); } rst.billsLibs = await billsLibModel.find({ deleted: false }, '-_id billsLibId billsLibName'); return rst; } } async function getBillsGuideLibs(findData) { return await billsGuideLibModel.find(findData); } //拷贝工作内容并转化为树结构,形成项目指引数据 async function genGuidanceItems(guidanceLibId, billsLibId) { let bills = await stdBillsModel.find({ billsLibId: billsLibId, deleted: false, 'jobs.0': { $exists: true } }); //设置工作内容数据 let jobIds = []; let totalJobs = []; for (let bill of bills) { for (let job of bill.jobs) { jobIds.push(job.id); } } jobIds = Array.from(new Set(jobIds)); if (jobIds.length > 0) { totalJobs = await stdBillsJobsModel.find({ deleted: false, id: { $in: jobIds } }); } if (totalJobs.length > 0) { let jobIdIndex = {};//id索引 for (let job of totalJobs) { jobIdIndex[job.id] = job; } let insertArr = []; for (let bill of bills) { //排序后根据serialNo转换成NextSiblingID,倒序 bill.jobs.sort(function (a, b) { let rst = 0; if (a.serialNo > b.serialNo) { rst = -1; } else if (a.serialNo < b.serialNo) { rst = 1; } return rst; }); let jobNoIndex = {};//下标索引 for (let i = 0; i < bill.jobs.length; i++) { let newItem = { libID: guidanceLibId, ID: uuidV1(), ParentID: -1, NextSiblingID: jobNoIndex[i - 1] ? jobNoIndex[i - 1]['ID'] : -1, name: jobIdIndex[bill.jobs[i]['id']]['content'], type: 0, billsID: bill.ID }; jobNoIndex[i] = newItem; insertArr.push({ insertOne: { document: newItem } }); } } await billsGuideItemsModel.bulkWrite(insertArr); } } async function initBillsGuideLib(updateData) { await billsGuideLibModel.create(updateData); await genGuidanceItems(updateData.ID, updateData.billsLibId); } async function updateBillsGuideLib(data) { if (data.updateType === 'delete') { //删除所有条目 await billsGuideLibModel.remove(data.findData); await billsGuideItemsModel.remove({ libID: data.findData.ID }); } else { await billsGuideLibModel.update(data.findData, { $set: data.updateData }); await engLibModel.update({ 'billsGuidance_lib.id': data.findData.ID }, { $set: { 'billsGuidance_lib.$.name': data.updateData.name } }, { multi: true }); } } async function getLibWithBills(libID) { let guidanceLib = await getBillsGuideLibs({ ID: libID }); if (guidanceLib.length === 0) { throw '不存在此指引库!'; } let billsLib = await stdBillsLibModel.findOne({ billsLibId: guidanceLib[0].billsLibId }); if (!billsLib) { throw '引用的清单规则库不存在!'; } let bills = await stdBillsModel.find({ billsLibId: billsLib.billsLibId }, '-_id code name ID NextSiblingID ParentID jobs items comment'); return { guidanceLib: guidanceLib[0], bills }; } function getAttrs(field, datas) { let rst = []; for (let data of datas) { if (data[field]) { rst.push(data[field]); } } return rst; } //定额项目指所引用定额是否被删除 function rationAllExist(rationItems, stdRationIdx) { for (let item of rationItems) { if (!stdRationIdx[item.rationID]) { return false; } } return true; } //将同层树结构转为顺序数组 function chainToArr(nodes) { let rst = []; let tempIdx = {}; let nodeIdx = {}; //建索引 for (let node of nodes) { tempIdx[node.ID] = { ID: node.ID, NextSiblingID: node.NextSiblingID, preSibling: null, nextSibling: null }; nodeIdx[node.ID] = node; } //建链 for (let i in tempIdx) { let temp = tempIdx[i]; if (temp.NextSiblingID != -1) { let next = tempIdx[temp.NextSiblingID]; temp.nextSibling = next; next.preSibling = temp; } } let firstNode = null; for (let i in tempIdx) { if (!tempIdx[i].preSibling) { firstNode = tempIdx[i]; break; } } //获得顺序队列 while (firstNode) { rst.push(nodeIdx[firstNode.ID]); firstNode = firstNode.nextSibling; } return rst; } async function getItemsBybills(guidanceLibID, billsID) { const type = { job: 0, ration: 1 }; let items = await billsGuideItemsModel.find({ libID: guidanceLibID, billsID: billsID, deleted: false }); let rationItems = _.filter(items, { type: type.ration }); let rationIds = getAttrs('rationID', rationItems); let stdRations = await stdRationModel.find({ ID: { $in: rationIds }, $or: [{ isDeleted: null }, { isDeleted: false }] }); let stdRationIndex = {}; for (let stdRation of stdRations) { stdRationIndex[stdRation.ID] = stdRation; } //判断定额完整性 if (!rationAllExist(rationItems, stdRationIndex)) { //建定额链, 排序后再清除不存在的定额,保证顺序正确性 rationItems = chainToArr(rationItems); //清除已被删除的定额 let removeIds = []; _.remove(rationItems, function (item) { if (!stdRationIndex[item.rationID]) { removeIds.push(item.ID); return true; } return false; }); _.remove(items, function (item) { return removeIds.includes(item.ID); }); await billsGuideItemsModel.remove({ ID: { $in: removeIds } }); //重组树结构 let bulkArr = []; for (let i = 0, len = rationItems.length; i < len; i++) { rationItems[i].NextSiblingID = rationItems[i + 1] ? rationItems[i + 1].ID : -1; bulkArr.push({ updateOne: { filter: { ID: rationItems[i].ID }, update: { $set: { NextSiblingID: rationItems[i].NextSiblingID } } } }); } await billsGuideItemsModel.bulkWrite(bulkArr); } return items; } async function updateItems(updateDatas) { let bulkArr = []; for (let updateData of updateDatas) { if (updateData.updateType === 'create') { bulkArr.push({ insertOne: { document: updateData.updateData } }); } else if (updateData.updateType === 'update') { bulkArr.push({ updateOne: { filter: updateData.findData, update: { $set: updateData.updateData } } }); } else { bulkArr.push({ deleteOne: { filter: updateData.findData } }); } } if (bulkArr.length > 0) { await billsGuideItemsModel.bulkWrite(bulkArr); } } async function testItems(libID) { let items = await billsGuideItemsModel.find({ libID: libID }); //删除垃圾数据 let delBulk = []; let itemsMapping = {}; for (let item of items) { itemsMapping[item.ID] = true; } for (let item of items) { if (item.ParentID != -1 && !itemsMapping[item.ParentID]) { delBulk.push({ deleteOne: { filter: { ID: item.ID } } }); } } if (delBulk.length > 0) { console.log(`delBulk.length`); console.log(delBulk.length); await billsGuideItemsModel.bulkWrite(delBulk); } /* //查找同层节点含有相同NextSiblingID的节点 let rst = []; let billsGroup = {}; for(let item of items){ if(!billsGroup[item.billsID]){ billsGroup[item.billsID] = [item]; } else { billsGroup[item.billsID].push(item); } } for(let bGroup in billsGroup){ let group = billsGroup[bGroup]; let parentGroup = {}; for(let gItem of group){ if(!parentGroup[gItem.ParentID]){ parentGroup[gItem.ParentID] = [gItem] } else { parentGroup[gItem.ParentID].push(gItem); } } for(let pGroup in parentGroup){ let pGroupData = parentGroup[pGroup]; let nextGroup = {}; for(let nItem of pGroupData){ let sameNext = _.filter(pGroupData, {NextSiblingID: nItem.NextSiblingID}); if(sameNext.length > 1){ console.log(`sameNext`); console.log(sameNext); if(!nextGroup[nItem.ParentID + nItem.NextSiblingID]){ rst.push({NextSiblingID: nItem.NextSiblingID, ParentID: nItem.ParentID}); nextGroup[nItem.ParentID + nItem.NextSiblingID] = 1; } } } } }*/ return delBulk.length; }