'use strict'; /** * * 清单汇总(需使用 decimal.min.js, zh_calc.js, path_tree.js, lodash.js) * * @author Mai * @date * @version */ const gclGatherModel = (function () { // 需要汇总计算的字段 const ledgerGatherFields = ['quantity', 'total_price', 'deal_qty', 'deal_tp', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp']; const posGatherFields = ['quantity', 'contract_qty', 'qc_qty', 'gather_qty', 'pre_contract_qty', 'pre_qc_qty', 'pre_gather_qty', 'end_contract_qty', 'end_qc_qty', 'end_gather_qty']; // 初始化 清单树 const gsTreeSetting = { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, keys: ['id', 'tender_id', 'ledger_id'], stageId: 'id', }; gsTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp']; const gsTree = createNewPathTree('stage', gsTreeSetting); // 初始化 部位明细 const posSetting = { id: 'id', ledgerId: 'lid', updateFields: ['contract_qty', 'qc_qty'], }; const gsPos = new StagePosData(posSetting); let deal = []; const gclList = [], leafXmjs = []; const mergeChar = ';'; /** * 将所有数据加载至树结构 * * @param ledger - 台账数据 * @param curStage - 当期计量数据 * @param preStage - 截止上期计量数据 * @param bgl - 变更令数据 */ function loadLedgerData (ledger, curStage, preStage, bgl) { // 加载树结构数据 gsTree.loadDatas(ledger); // 加载本期计量数据 if (curStage) { gsTree.loadCurStageData(curStage); } if (preStage) { gsTree.loadPreStageData(preStage); } } function loadPosData(pos, curPos, prePos) { gsPos.loadDatas(pos); gsPos.loadCurStageData(curPos); gsPos.loadPreStageData(prePos); } function loadDealBillsData(dealBills) { deal = dealBills; } function gatherfields(obj, src, fields) { if (obj && src) { for (const f of fields) { obj[f] = ZhCalc.add(obj[f], src[f]); } } } /** * 新建 清单汇总节点 * @param node - 最底层 工程量清单节点 * @returns {{b_code: *|string[], name, unit, unit_price: *|string[], leafXmjs: Array}} */ function newGclNode(node) { const gcl = { b_code: node.b_code, name: node.name, unit: node.unit, unit_price: node.unit_price, leafXmjs: [], }; gclList.push(gcl); return gcl; } /** * 获取清单汇总节点 * * @param node - 最底层清单节点 * @returns {*} */ function getGclNode(node) { const gcl = gclList.find(function (g) { return g.b_code === node.b_code && g.name === node.name && g.unit === node.unit && checkZero(g.unit_price - node.unit_price); }); if (gcl) { return gcl } else { return newGclNode(node); } } /** * 检查 text 是否是Peg * e.g. K123+000(true) Kab+123(false) K123.234+234(false) K12+324.234(true) * * @param text * @returns {*} * @constructor */ function CheckPeg(text) { const pegReg = /[a-zA-Z]?[kK][0-9]+[++][0-9]{3}([.][0-9]+)?/; return pegReg.test(text); } /** * 获取 桩号节点 * @param node - 检索起始节点 * @returns {*} */ function getPegNode (node) { if (node) { if (CheckPeg(node.name)) { return node; } else { const parent = gsTree.getParent(node); return parent ? getPegNode(parent) : null; } } } /** * 获取节点的第N层父节点 * * @param node - 节点(检索起点) * @param level - 第N层 * @returns {*} */ function getNodeByLevel(node, level) { let cur = node; while (cur && cur.level > level) { cur = gsTree.getParent(cur); } return cur; } /** * 获取 单位工程 * * @param xmj - 计量单元(最底层项目节) * @returns {string} */ function getDwgc(peg, xmj) { if (peg) { return peg.name; } else { const node = getNodeByLevel(xmj, 2); return node ? node.name : ''; } } /** * 获取 分部工程 * * @param peg - 桩号节点 * @param xmj - 计量单元(最底层项目节) * @returns {string} */ function getFbgc(peg, xmj) { if (peg && peg.id !== xmj.id) { const node = getNodeByLevel(xmj, peg.level + 1); return node ? node.name : ''; } else { const node = getNodeByLevel(xmj, 3); return node ? node.name : ''; } } /** * 获取 分项工程 * * @param peg - 桩号节点 * @param xmj - 计量单元(最底层项目节) * @returns {string} */ function getFxgc(peg, xmj) { if (!peg) { const node = getNodeByLevel(xmj, 4); return node ? node.name : ''; } else if (peg.id === xmj.id) { if (xmj.level > 4) { let value = ''; for (let level = 4; level < xmj.level; level++) { const node = getNodeByLevel(xmj, level); value = value === '' ? node.name : value + mergeChar + node.name; } return value; } else { return ''; } } else { if (peg.level + 2 < xmj.level) { let value = ''; for (let level = peg.level + 2; level < xmj.level; level++) { const node = getNodeByLevel(xmj, level); value = value === '' ? node.name : value + mergeChar + node.name; } return value; } else { return ''; } } } /** * 新建 最底层项目节 缓存数据 * @param leafXmj * @returns {{id, code: *|string[], jldy, fbgc: string, fxgc: string, dwgc: string, bwmx: string, drawing_code: string}} */ function newCacheLeafXmj(leafXmj) { const peg = getPegNode(leafXmj); const cacheLX = { id: leafXmj.id, code: leafXmj.code, jldy: leafXmj.name, fbgc: getFbgc(peg, leafXmj), fxgc: getFxgc(peg, leafXmj), dwgc: getDwgc(leafXmj), drawing_code: leafXmj.drawing_code, }; leafXmjs.push(cacheLX); return cacheLX; } /** * 获取缓存的最底层项目节数据 * * @param leafXmj - 最底层项目节 * @returns {*} */ function getCacheLeafXmj(leafXmj) { const cacheLX = leafXmjs.find(function (lx) { return lx.id === leafXmj.id; }); if (!cacheLX) { return newCacheLeafXmj(leafXmj); } else { return cacheLX; } } /** * 汇总节点 * @param node - 最底层 工程量清单 节点 * @param leafXmj - 所属 最底层 项目节 */ function loadGatherGclNode(node, leafXmj) { const gcl = getGclNode(node); gatherfields(gcl, node, ledgerGatherFields); const cacheLeafXmj = getCacheLeafXmj(leafXmj); const posRange = gsPos.getLedgerPos(node.id); const detail = posRange && posRange.length > 0 ? posRange : [node]; for (const d of detail) { const dx = _.assign({}, cacheLeafXmj); gatherfields(dx, d, posGatherFields); dx.gcl_id = node.id; if (d.name !== node.name) { dx.bwmx = d.name; dx.mx_id = d.id; } if (d.drawing_code) { dx.drawing_code = d.drawing_code; } gcl.leafXmjs.push(dx); } } /** * (递归)汇总树节点 * @param nodes - 汇总节点列表 * @param leafXmj - 汇总节点所属的底层项目节 */ function recursiveGatherGclData(nodes, leafXmj) { for (const node of nodes) { if (node.b_code) { if (node.children.length > 0) { recursiveGatherGclData(node.children, leafXmj); } else { loadGatherGclNode(node, leafXmj); } } else if (node.children.length > 0) { recursiveGatherGclData(node.children, node); } } } function gatherDealBillsData() { if (deal && deal.length > 0) { for (const node of deal) { node.b_code = node.code; if (!node.quantity || !node.unit_price) continue; const gcl = getGclNode(node); gcl.deal_bills_qty = node.quantity; gcl.deal_bills_tp = node.total_price; } } } function calculateGatherData() { for (const gcl of gclList) { gcl.pre_gather_qty = ZhCalc.add(gcl.pre_contract_qty, gcl.pre_qc_qty); gcl.pre_gather_tp = ZhCalc.add(gcl.pre_contract_tp, gcl.pre_qc_tp); gcl.gather_qty = ZhCalc.add(gcl.contract_qty, gcl.qc_qty); gcl.end_contract_qty = ZhCalc.add(gcl.pre_contract_qty, gcl.contract_qty); gcl.end_qc_qty = ZhCalc.add(gcl.pre_qc_qty, gcl.qc_qty); gcl.end_gather_qty = ZhCalc.add(gcl.pre_gather_qty, gcl.gather_qty); gcl.end_final_qty = ZhCalc.add(gcl.end_qc_qty, gcl.quantity); gcl.gather_tp = ZhCalc.add(gcl.contract_tp, gcl.qc_tp); gcl.end_contract_tp = ZhCalc.add(gcl.pre_contract_tp, gcl.contract_tp); gcl.end_qc_tp = ZhCalc.add(gcl.pre_qc_tp, gcl.qc_tp); gcl.end_gather_tp = ZhCalc.add(gcl.pre_gather_tp, gcl.gather_tp); gcl.dgn_price = ZhCalc.round(ZhCalc.div(gcl.total_price, gcl.dgn_qty1), 2); gcl.end_final_tp = ZhCalc.add(gcl.end_qc_tp, gcl.total_price); gcl.end_gather_percent = ZhCalc.mul(ZhCalc.div(gcl.end_gather_tp, gcl.end_final_tp), 100, 2); for (const xmj of gcl.leafXmjs) { xmj.pre_gather_qty = ZhCalc.add(xmj.pre_contract_qty, xmj.pre_qc_qty); xmj.gather_qty = ZhCalc.add(xmj.contract_qty, xmj.qc_qty); xmj.end_contract_qty = ZhCalc.add(xmj.pre_contract_qty, xmj.contract_qty); xmj.end_qc_qty = ZhCalc.add(xmj.pre_qc_qty, xmj.qc_qty); xmj.end_gather_qty = ZhCalc.add(xmj.pre_gather_qty, xmj.gather_qty); xmj.end_final_qty = ZhCalc.add(xmj.end_qc_qty, xmj.quantity); xmj.end_gather_percent = ZhCalc.mul(ZhCalc.div(xmj.end_gather_qty, xmj.end_final_qty), 100, 2); } } } function compareCode(str1, str2, symbol = '-') { if (!str1) { return 1; } else if (!str2) { return -1; } function compareSubCode(code1, code2) { if (numReg.test(code1)) { if (numReg.test(code2)) { return parseInt(code1) - parseInt(code2); } else { return -1 } } else { if (numReg.test(code2)) { return 1; } else { return code1 === code2 ? 0 : (code1 < code2 ? -1 : 1); //code1.localeCompare(code2); } } } const numReg = /^[0-9]+$/; const aCodes = str1.split(symbol), bCodes = str2.split(symbol); for (let i = 0, iLength = Math.min(aCodes.length, bCodes.length); i < iLength; ++i) { const iCompare = compareSubCode(aCodes[i], bCodes[i]); if (iCompare !== 0) { return iCompare; } } return aCodes.length - bCodes.length; } /** * 根据树结构 清单汇总 */ function gatherGclData() { // 清空旧数据 if (gclList.length > 0) { gclList.length = 0; //splice(0, gclList.length); } recursiveGatherGclData(gsTree.children, null); calculateGatherData(); gatherDealBillsData(); gclList.sort(function (a, b) { return compareCode(a.b_code, b.b_code); }); return gclList; } function checkDiffer(gclList) { for (const gcl of gclList) { gcl.differ = false; } for (const [i, gcl] of gclList.entries()) { if (i === gclList.length - 1) continue; const next = gclList[i+1]; if (gcl.b_code === next.b_code) { if (gcl.name !== next.name || gcl.unit !== next.unit || !checkZero(gcl.unit_price - next.unit_price)) { gcl.differ = true; next.differ = true; } } } } function _getCalcChapter(chapter) { const gclChapter = [], otherChapter = []; let serialNo = 1; for (const c of chapter) { const cc = { code: c.code, name: c.name, cType: 1 }; cc.serialNo = serialNo++; cc.filter = '^[^0-9]*' + c.code.substr(0, c.code.length - 2) + '[0-9]{2}-'; gclChapter.push(cc); } gclChapter.push({ name: '未计入章节清单合计', cType: 21, serialNo: serialNo++, }); otherChapter.push({ name: '清单小计(A)', cType: 11, serialNo: serialNo++ }); otherChapter.push({ name: '非清单项费用(B)', cType: 31, serialNo: serialNo++ }); otherChapter.push({ name: '合计(C=A+B)', cType: 41, serialNo: serialNo }); return [gclChapter, otherChapter]; } function _gatherChapterFields(chapter, data, fields) { for (const f of fields) { chapter[f] = ZhCalc.add(chapter[f], data[f]); } } function _getGclChapter(chapter, data) { for (const c of chapter) { if (c.filter) { const reg = new RegExp(c.filter); if (reg.test(data.b_code)) { return c; } } else { return c; } } } function gatherChapterData(chapter, fields) { const [gclChapter, otherChapter] = _getCalcChapter(chapter); for (const d of gsTree.datas) { if (d.children && d.children.length > 0) continue; for (const c of otherChapter) { if (c.cType === 41) { gatherfields(c, d, fields); } else if (c.cType === 31 && (!d.b_code || d.b_code === '')) { gatherfields(c, d, fields); } else if (c.cType === 11 && (d.b_code)) { gatherfields(c, d, fields); } } if (d.b_code) { const c = _getGclChapter(gclChapter, d); gatherfields(c, d, fields); } } for (const d of deal) { if (!d.quantity || !d.unit_price) continue; for (const c of otherChapter) { if (c.cType === 41 || c.cType === 11) { c.deal_bills_tp = ZhCalc.add(c.deal_bills_tp, d.total_price); } } const c = _getGclChapter(gclChapter, d); c.deal_bills_tp = ZhCalc.add(c.deal_bills_tp, d.total_price); } return gclChapter.concat(otherChapter); } return { loadLedgerData, loadPosData, loadDealBillsData, gatherGclData, checkDiffer, gatherChapterData, }; })();