'use strict'; /** * * * @author Mai * @date * @version */ const math = require('mathjs'); const standard = require('../const/standard'); const moment = require('moment'); moment.locale('zh-cn'); const fs = require('fs'); const valueCheck = { _typeFun: { bool: '_checkBoolean', str: '_checkString', num: '_checkNumber', }, _checkBoolean(ctx, value, condition) { switch (condition.value) { case 'true': return !!value; case 'false': return !value; default: return true; } }, _checkNumber(ctx, value, condition) { // if (ctx.helper._.isNil(value)) value = 0; switch (condition.operate) { case 'non-zero': return !ctx.helper.checkZero(value); case '=': return !ctx.helper._.isNil(value) ? value === condition.value : false; case '>': return !ctx.helper._.isNil(value) ? value > condition.value : false; case '<': return !ctx.helper._.isNil(value) ? value < condition.value : false; case '>=': return !ctx.helper._.isNil(value) ? value >= condition.value : false; case '<=': return !ctx.helper._.isNil(value) ? value <= condition.value : false; default: return true; } }, _checkStringFit(ctx, value, condition) { switch (condition.operate) { case '=': return value === condition.value; case 'part': return value ? value.indexOf(condition.value) >= 0 : false; case 'enum': return (value && condition.value instanceof Array) ? condition.value.indexOf(value) >= 0 : false; default: return true; } }, _checkString(ctx, value, condition) { const result = this._checkStringFit(ctx, value, condition); return condition.opp ? !result : result; }, loadTypeFun(condition) { for (const c of condition) { c.fun = this._typeFun[c.type]; } }, checkData(ctx, data, condition) { if (condition.length > 0) { let con = condition[0]; let result = this[con.fun](ctx, data[con.field], con); for (let i = 1, iLen = condition.length; i < iLen; i++) { con = condition[i]; result = (con.rela && con.rela === 'or') ? (result || this[con.fun](ctx, data[con.field], con)) : (result && this[con.fun](ctx, data[con.field], con)); } return result; } return true; }, }; class PosIndex { /** * 构造函数 * @param {id|String, masterId|String, order|String} setting */ constructor(setting) { // 无索引 this.datas = []; // 以key为索引 this.items = {}; // 以分类id为索引的有序 this.ledgerPos = {}; // pos设置 this.setting = setting; } /** * 加载部位明细数据 * @param datas */ loadDatas(datas) { this.datas = datas; this.items = {}; this.ledgerPos = {}; for (const data of this.datas) { const key = data[this.setting.id]; this.items[key] = data; const masterKey = data[this.setting.masterId]; if (!this.ledgerPos[masterKey]) { this.ledgerPos[masterKey] = []; } this.ledgerPos[masterKey].push(data); } for (const prop in this.ledgerPos) { this.resortLedgerPos(this.ledgerPos[prop]); } } getLedgerPos(mid) { return this.ledgerPos[mid]; } resortLedgerPos(ledgerPos) { const self = this; if (ledgerPos instanceof Array) { ledgerPos.sort(function(a, b) { return a[self.setting.order] - b[self.setting.order]; }); } } } // 通用方法 const rdaUtils = { orderCalc(ctx, data, fields) { const orderMatch = new RegExp('o[0-9]+', 'igm'); for (const c of data) { if (c.order_calc && c.order_calc !== '') { const matchs = c.order_calc.match(orderMatch); const calcMatch = []; for (const m of matchs) { const order = m.substring(1, m.length); const orderData = data.find(function(x) { return (x.order + '') === order; }); if (orderData) { calcMatch.push({ match: m, value: orderData }); } } for (const f of fields) { let expr = c.order_calc; for (const m of calcMatch) { expr = expr.replace(m.match, m.value[f] ? m.value[f] : 0); } try { c[f] = ctx.helper.round(parseFloat(math.eval(expr)), 6); } catch (err) { } } } } }, }; // 可提供的数据处理方法 const changeSort = { name: '变更令排序', hint: '默认的变更令排序,同时对变更令,变更清单进行排序\n' + '变更令排序勿需勾选任何预定义处理指标,但是在指标映射中,需要添加如下指标:' + '1. 如果只有变更令数据,则必须添加,"变更令(change)"下的"变更令号"' + '2. 如果有变更清单需要排序,则必须在1的基础上添加,变更令(change)"下的"变更令uuid"和"变更清单(chang_audit_list)"下的"所属变更令uuid"&"清单编号"', intro: '报表对于主从表的排序有要求,解决变更令数据中的变更令、变更清单排序问题', /** * * @param ctx - context常量 * @param data - 全部数据源{Array} * @param fieldsKey - 计算字段 * @param options - 计算设置 */ fun(ctx, data, fieldsKey, options) { const change = options && options.change ? data[options.change] : data.change; if (!change) return; // 变更令排序 change.sort(function(a, b) { return a.code.localeCompare(b.code); }); const changeBills = options && options.changeBills ? data[options.changeBills] : data.change_audit_list; if (changeBills) { changeBills.sort(function(a, b) { const aCIndex = data.change.findIndex(function(c) { return c.cid === a.cid; }); const bCIndex = data.change.findIndex(function(c) { return c.cid === b.cid; }); return aCIndex === bCIndex ? ctx.helper.compareCode(a.code, b.code) : aCIndex - bCIndex; }); } }, }; const gatherGcl = { name: '汇总工程量清单', hint: '请使用mem_stage_bills下指标,注意事项:\n' + '1. 以下字段,不管报表是否实际使用,均应添加至指标映射,且在此处应勾选(不要求顺序):\n' + ' 清单编号(b_code), 名称(name), 单位(unit), 单价(unit_price), 树结构-是否子项(is_leaf)\n' + '2. 汇总后,以下字段,均会失效, 请勿使用:\n' + ' 台账ID(id), 树结构-ID(ledger_id), 树结构父项-ID(ledger_pid),\n' + ' 树结构-层级(level), 树结构-同层排序(order), 树结构-完整路径(full_path),\n' + ' 图册号(drawing_code), 备注(memo), 节点类型(node_type), 总额计量(is_tp)\n' + '3. 如需汇总"未计入清单章节项",请勾选"章节编号(chapter)"字段\n', intro: '根据三级清单树结构,汇总平面工程量清单,目前仅支持mem_stage_bills表', _gatherCalcField(ctx, gcl, data) { for (const prop in data) { if (((prop === 'total_price' || prop.indexOf('tp') > 0) || (prop === 'quantity' || prop.indexOf('qty') > 0)) && data[prop]) { gcl[prop] = ctx.helper.add(gcl[prop], data[prop]); } } }, _gatherTpField(ctx, gcl, data) { for (const prop in data) { if ((prop === 'total_price' || prop.indexOf('tp') > 0) && data[prop]) { gcl[prop] = ctx.helper.add(gcl[prop], data[prop]); } } }, _loadGatherInfo(gcl, data) { for (const prop in data) { if (/^t_[0-9]+_(id|name)$/.test(prop)) { gcl[prop] = data[prop]; } } }, _loadStageSumInfo(gcl, data) { for (const prop in data) { if (/^s_[0-9]+_order$/.test(prop)) { gcl[prop] = data[prop]; } } }, _gatherFields(gcl, data, fields) { for (const f of fields) { if (data[f]) { gcl[f] = ctx.helper.add(gcl[f], data[f]); } } }, fun(ctx, data, fieldsKey, options) { const tableName = options ? options.table : 'mem_stage_bills'; const gatherData = data[tableName]; if (!gatherData || gatherData.length === 0) return; const fields = ctx.helper._.map(fieldsKey, 'field'); const needFields = ['b_code', 'name', 'unit', 'unit_price', 'is_leaf']; for (const nf of needFields) { if (fields.indexOf(nf) === -1) return; } const gatherOther = fields.indexOf('chapter') >= 0; const gclBills = [], other = { name: '未计入清单章节项', chapter: '10000' }; if (tableName.indexOf('mem_gather_') >= 0) this._loadGatherInfo(other, gatherData[0]); if (tableName.indexOf('mem_stage_sum_') >= 0) this._loadStageSumInfo(other, gatherData[0]); for (const b of gatherData) { const child = ctx.helper._.find(gatherData, { ledger_pid: b.ledger_id }); if (child) continue; if (b.b_code && b.b_code !== '') { let gcl = gclBills.find(function(g) { return g.b_code === b.b_code && g.name === b.name && g.unit === b.unit && ctx.helper.checkZero(ctx.helper.sub(g.unit_price, b.unit_price)); }); if (!gcl) { gcl = { b_code: b.b_code, name: b.name, unit: b.unit, unit_price: b.unit_price, qc_bgl_code: [], chapter: b.chapter, deal_bills_qty: b.deal_bills_qty, deal_bills_tp: b.deal_bills_tp, }; if (tableName.indexOf('mem_gather_') >= 0) this._loadGatherInfo(gcl, b); if (tableName.indexOf('mem_stage_sum_') >= 0) this._loadStageSumInfo(gcl, b); gclBills.push(gcl); } this._gatherCalcField(ctx, gcl, b); if (b.qc_bgl_code && b.qc_bgl_code !== '') { gcl.qc_bgl_code = gcl.qc_bgl_code.concat(b.qc_bgl_code.split(';')); } } else if (gatherOther) { this._gatherTpField(ctx, other, b); } } if (gatherOther) gclBills.push(other); for (const g of gclBills) { if (g.qc_bgl_code) g.qc_bgl_code = g.qc_bgl_code.join(';'); g.final_ratio = ctx.helper.mul(ctx.helper.div(g.end_gather_tp, g.final_tp), 100); } data[tableName] = gclBills; }, }; const sortGcl = { name: '工程量清单排序', hint: '只对一张表,进行工程量清单排序,排序哪张表,根据勾选的清单编号字段决定:\n' + 'e.g.1 要对mem_stage_bills排序,需要勾选mem_stage_bills下的"清单编号(b_code)"字段\n' + 'e.g.2 要对mem_stage_im_zl排序,需要勾选mem_stage_im_zl下的"中间计量总量信息_编号(code)"字段\n' + '特别的,如有"未计入清单章节项": \n' + ' 1. 默认"未计入清单章节项"排列在最后\n' + ' 2. 如须"未计入清单章节项"排在100章之后,请在清单编号字段后,依次勾选"章节编号(chapter)", "名称(name)"\n', intro: '根据选择列,对数据进行工程量清单排序,兼容1000章后清单,以及403-1-a类的非纯数字编号排序', fun(ctx, data, fieldsKey, options) { if (fieldsKey.length !== 1 && fieldsKey.length !== 3) return; const code = fieldsKey[0].field; const chapter = fieldsKey.length > 1 ? fieldsKey[1].field : ''; const name = fieldsKey.length > 2 ? fieldsKey[2].field : ''; const sortData = data[fieldsKey[0].table]; if (!sortData) return; sortData.sort(function(a, b) { if (chapter !== '') { if (a[name] === '未计入清单章节项') { return b[chapter] === '100' ? 1 : -1; } else if (b[name] === '未计入清单章节项') { return a[chapter] === '100' ? -1 : 1; } return ctx.helper.compareCode(a[code], b[code]); } return ctx.helper.compareCode(a[code], b[code]); }); }, }; const gatherChapter = { name: '汇总章级数据', hint: '请使用mem_stage_bills/mem_stage_bills_compare/ledger,仅对一张表进行汇总,并生成数据:\n' + '1. 因为是汇总章级数据,必须在离散数据中添加"章节代码"&"章节名称"\n' + '2. 需勾选"清单编号(b_code)", "树结构-是否子项(is_leaf)"字段,可以对任何含有这些字段的表汇总\n' + '注意事项:\n' + '1. 算法对数据表没有要求,保证有上述字段,且按顺序勾选即可, 仅汇总金额\n' + '2. 算法计算后,原数据表中非数字类型的字段全部失效(除清单编号、名称外),请勿在指标映射中添加\n' + '示例:\n' + 'e.g.1 要对mem_stage_bills汇总,须勾选mem_stage_bills下的"清单编号(b_code)", "树结构-是否子项((is_leaf)"字段\n' + 'e.g.2 要对mem_stage_bills_compare汇总,须勾选mem_stage_bills_compare下的"清单编号(b_code)", "树结构-是否子项((is_leaf)"字段\n' + '结果:\n' + '汇总结果可参照 清单汇总--章节合计,但是不过滤1000-1300章数据', intro: '用于得到类似“清单汇总--章级合计”的数据,可通过options自定义数据', defaultSetting: { count: 9, unChapter: { name: '未计入清单章节合计', order: 1, }, gclSum: { name: '清单小计', order: 2, }, unGcl: { name: '非清单项费用', order: 3, }, sum: { name: '合计', order: 4, }, filter: [{node_type: standard.nodeType.find(function (x) {return x.text === '计日工'}).value}, {field: 'name', part: '计日工'}], }, customSetting1: { count: 7, gclSum: { name: '第100章至700章清单合计', order: 1, }, custom: [ {name: '已包含在清单合计中的材料、工程设备、专业工程暂估价', order: 2, visible: false}, {name: '清单合计减去材料、工程设备、专业工程暂估价(即8-9=10)', order_calc: 'o1-o2', order: 3}, {name: '计日工合计', node_type: '计日工', order: 4}, {name: '暂列金额(不含计日工总额)(即10×暂列金额比列)', order: 5, match: [{node_type: '暂列金额'}, {field: 'name', part: '暂列金额'}, {field: 'name', all: '暂定金额'}]}, {name: '投标报价、台账价(8+11+12)=13', order_calc: 'o1+o4+o5', order: 6}, ], rela: [ { table: 'deal_bills', key: 'code', fields: { source: 'total_price', target: 'ex_value1' }, }, { table: 'mem_change_bills', key: 'code', fields: { source: '', target: 'ex_value2' }, }, ], }, _getCalcChapter(chapter, options) { const gclChapter = [], otherChapter = [], customChapter = []; let serialNo = 1; for (const c of chapter) { const cc = { code: c.code, name: c.name, cType: 1 }; cc.serialNo = serialNo++; cc.filter = '^[\\D]*' + c.code.substr(0, c.code.length - 2) + '[0-9]{2}(-|$)'; // cc.visible = true; gclChapter.push(cc); if (options.activeFields) { cc.active = cc.serialNo > options.count; } else { if (serialNo > options.count) break; } } if (options.unChapter) { gclChapter.push({ name: options.unChapter.name, cType: 21, serialNo: serialNo + options.unChapter.order, order: options.unChapter.order, visible: options.unChapter.visible, }); } if (options.gclSum) { otherChapter.push({ name: options.gclSum.name, cType: 11, serialNo: serialNo + options.gclSum.order, order: options.gclSum.order, visible: options.gclSum.visible, }); } if (options.unGcl) { otherChapter.push({ name: options.unGcl.name, cType: 31, serialNo: serialNo + options.unGcl.order, order: options.unGcl.order, visible: options.unGcl.visible, }); } if (options.sum) { otherChapter.push({ name: options.sum.name , cType: 41, serialNo: serialNo + options.sum.order, order: options.sum.order, visible: options.sum.visible, }); } if (options.custom && options.custom instanceof Array) { for (const c of options.custom) { const cc = { name: c.name, serialNo: serialNo + c.order, order_calc: c.order_calc, cType: 5, order: c.order, visible: c.visible, }; if (c.match) { cc.match = JSON.parse(JSON.stringify(c.match)); for (const m of cc.match) { if (m.node_type && m.node_type !== '') { const nodeType = standard.nodeType.find(function (x) {return x.text === m.node_type}); m.node_type = nodeType.value; } } } customChapter.push(cc); } } return [gclChapter, otherChapter, customChapter]; }, _completeGatherInfo(chapters, source) { for (const f in source) { if (/^t_[0-9]*_(id|name)$/.test(f)) { for (const chapter of chapters) { chapter[f] = source[f]; } } } }, _completeStageSumInfo(chapters, source) { for (const f in source) { if (/^s_[0-9]*_order$/.test(f)) { for (const chapter of chapters) { chapter[f] = source[f]; } } } }, _getGclChapter(chapter, data, field) { for (const c of chapter) { if (c.filter) { const reg = new RegExp(c.filter); if (reg.test(data[field])) { return c; } } else { return c; } } }, _checkFilter(fullPath, filter) { for (const f of filter) { if (fullPath.indexOf(f + '-') === 0 || fullPath === f) return true; } return false; }, _gatherRela(ctx, data, rela, gclChapter, otherChapter) { if (!rela) return; const gatherRelaFields = function(chapter, source, field) { const fields = field instanceof Array ? field : [field]; for (const f of fields) { chapter[f.target] = ctx.helper.add(chapter[f.target], source[f.source]); } }; const relaBills = rela instanceof Array ? rela : [rela]; for (const rb of relaBills) { if (!rb.table) continue; const relaData = data[rb.table]; if (!relaData) continue; for (const rd of relaData) { for (const c of otherChapter) { if (c.cType === 41) { gatherRelaFields(c, rd, rb.fields); } else if (c.cType === 31 && (!rd[rb.key] || rd[rb.key] === '')) { gatherRelaFields(c, rd, rb.fields); } else if (c.cType === 11 && (rd[rb.key])) { gatherRelaFields(c, rd, rb.fields); } } if (rd[rb.key]) { const c = this._getGclChapter(gclChapter, rd, rb.key); if (c) gatherRelaFields(c, rd, rb.fields); } } } }, _orderCalc(ctx, chapter, fields) { const orderMatch = new RegExp('o[0-9]+', 'igm'); for (const c of chapter) { if (c.order_calc && c.order_calc !== '') { const matchs = c.order_calc.match(orderMatch); const calcMatch = []; for (const m of matchs) { const order = m.substring(1, m.length); const orderChapter = chapter.find(function(x) { return x.order == order; }); if (orderChapter) { calcMatch.push({ match: m, value: orderChapter }); } } for (const f of fields) { let expr = c.order_calc; for (const m of calcMatch) { expr = expr.replace(m.match, m.value[f] ? m.value[f] : 0); } try { c[f] = ctx.helper.round(parseFloat(math.eval(expr), 6)); } catch (err) { } } } } }, _checkMatch(match, d) { for (const m of match) { if (m.node_type) { if (m.node_type === d.node_type) return true; } else if (m.field) { const value = d[m.field]; if (m.part && value) { if (value.indexOf(m.part) >= 0) return true; } else if (m.all && value) { if (m.all === value) return true; } } } return false; }, fun(ctx, data, fieldsKey, options) { if (!data.tender_info || !data.tender_info.chapter) return; if (!fieldsKey && fieldsKey.length < 0) return; const calcFields = []; const gatherData = function(chapter, data) { if (!chapter) return; for (const f in data) { if (!data[f]) continue; if ((f.indexOf('tp') >= 0 || f === 'total_price')) { chapter[f] = ctx.helper.add(chapter[f], data[f]); if (calcFields.indexOf(f) === -1) calcFields.push(f); } } }; const fields = ctx.helper._.map(fieldsKey, 'field'); const needFields = ['b_code', 'is_leaf']; for (const nf of needFields) { if (fields.indexOf(nf) === -1) return; } const sourceData = data[fieldsKey[0].table]; if (!sourceData) return; const [gclChapter, otherChapter, customChapter] = this._getCalcChapter(data.tender_info.chapter, options ? options : this.defaultSetting); if (fieldsKey[0].table.indexOf('mem_gather') >= 0) { this._completeGatherInfo(gclChapter, sourceData[0]); this._completeGatherInfo(otherChapter, sourceData[0]); this._completeGatherInfo(customChapter, sourceData[0]); } if (fieldsKey[0].table.indexOf('mem_stage_sum_') >= 0) { this._completeStageSumInfo(gclChapter, sourceData[0]); this._completeStageSumInfo(otherChapter, sourceData[0]); this._completeStageSumInfo(customChapter, sourceData[0]); } const filter = [], defaultFilter = []; for (const d of sourceData) { if (this._checkMatch(this.defaultSetting.filter, d)) defaultFilter.push(d.full_path); if (this._checkFilter(d.full_path, filter)) continue; for (const c of customChapter) { if (c.match && this._checkMatch(c.match, d)) { gatherData(c, d); filter.push(d.full_path); } } if (!d.is_leaf) continue; for (const c of otherChapter) { if (c.cType === 41) { gatherData(c, d); } else if (c.cType === 31 && (!d.b_code || d.b_code === '')) { gatherData(c, d); } else if (c.cType === 11 && (d.b_code)) { gatherData(c, d); } } if (d.b_code) { const c = this._checkFilter(d.full_path, defaultFilter) ? gclChapter.find(x => { return x.cType === 21; }) : this._getGclChapter(gclChapter, d, 'b_code'); if (c) { gatherData(c, d); } } } this._gatherRela(ctx, data, options.rela, gclChapter, otherChapter); const chapter = gclChapter.concat(otherChapter).concat(customChapter); this._orderCalc(ctx, chapter, calcFields); chapter.sort(function(a, b) { return a.serialNo - b.serialNo; }); data[fieldsKey[0].table] = chapter.filter(function(x) { if (x.active) { for (const f of options.activeFields) { if (!ctx.helper.checkZero(x[f])) return true; } return false; } return (x.visible !== undefined && x.visible !== null) ? x.visible : true; }); }, }; const join = { name: '连接两张数据表', hint: '用于处理类似于关联签约清单的情况,会改变主表的数据', intro: '用于处理类似于关联签约清单的情况,会根据关联表(sub)改变主表(main)的数据', defaultSetting: { main: 'mem_stage_bills', sub: 'deal_bills', keyFields: [ { main: 'b_code', sub: 'code', type: 'string' }, { main: 'name', sub: 'name', type: 'string' }, { main: 'unit', sub: 'unit', type: 'string' }, { main: 'unit_price', sub: 'unit_price', type: 'number' }, ], importFields: [ { main: 'ex_value1', sub: 'quantity', type: 'sum' }, { main: 'ex_value2', sub: 'total_price', type: 'sum' }, ], joinType: 'outer', // 'outer', 'main', 'sub', 'inner', }, fun(ctx, data, fields, options) { if (!options || !options.main || !options.sub || !options.keyFields || options.keyFields.length === 0) return; const main = data[options.main]; const sub = data[options.sub]; if (!main || !sub) return; const _ = ctx.helper._, result = _.cloneDeep(main); for (const r of result) { r._join_tag = 'main'; for (const i of options.importFields) { r[i.main] = null; } } for (const s of sub) { let subR = result.filter(function(x) { for (const k of options.keyFields) { switch (k.type) { case 'string': if ((x[k.main] || '') !== (s[k.sub] || '')) return false; break; case 'number': if (!ctx.helper.checkZero(ctx.helper.sub(x[k.main], s[k.sub]))) return false; break; } } return true; }); for (let r of subR) { if (r && r._join_tag === 'main') { r._join_tag = 'both'; } if (!r) { r = { _join_tag: 'sub' }; for (const k of options.keyFields) { r[k.main] = s[k.sub]; } result.push(r); } for (const i of options.importFields) { // r[i.main] = s[i.sub]; if (i.type === 'sum') { r[i.main] = ctx.helper.add(r[i.main], s[i.sub]); } else { r[i.main] = s[i.sub]; } } } } switch (options.joinType) { case 'main': data[options.main] = _.filter(result, function(r) { return ['main', 'both'].indexOf(r._join_tag) >= 0; }); break; case 'sub': data[options.main] = _.filter(result, function(r) { return ['sub', 'both'].indexOf(r._join_tag) >= 0; }); break; case 'inner': data[options.main] = _.filter(result, function(r) { return r._join_tag === 'both'; }); break; case 'outer': data[options.main] = result; break; } }, }; const getChapterCode = { name: '获取章级编号', intro: '根据清单编号,计算章级编号,并写入指定字段,适用于未提供chapter字段的数据,例如签约清单', hint: '', defaultSetting: { table: 'mem_stage_bills', b_code: 'b_code', chapter: 'chapter', }, fun(ctx, data, fields, options) { if (!options || !options.table || !options.b_code || !options.chapter) return; const cData = data[options.table]; if (!cData) return; for (const d of cData) { d[options.chapter] = ctx.helper.getChapterCode(d[options.b_code]); } }, }; const filter = { name: '数据过滤', intro: '根据设置过滤数据,会直接修改数据表', defaultSetting: { table: 'pay', condition: [ { field: 'minus', type: 'bool', value: 'false' }, { field: 'ptype', type: 'num', operate: '=', value: 1, rela: 'and' }, { field: 'name', type: 'str', operate: '=', value: '扣回', rela: 'or' }, ], f_type: "or'", }, _typeFun: { bool: '_checkBoolean', str: '_checkString', num: '_checkNumber', }, fun(ctx, data, fields, options) { if (!options || !options.table || !options.condition) return; const fData = data[options.table]; if (!fData) return; valueCheck.loadTypeFun(options.condition); data[options.table] = fData.filter(function(d) { if (options.condition.length > 0) { let con = options.condition[0]; let result = valueCheck[con.fun](ctx, d[con.field], con); for (let i = 1, iLen = options.condition.length; i < iLen; i++) { con = options.condition[i]; result = (con.rela && con.rela === 'or') ? (result || valueCheck[con.fun](ctx, d[con.field], con)) : (result && valueCheck[con.fun](ctx, d[con.field], con)); } return result; } return true; }); }, }; const gatherStagePay = { name: '汇总合同支付数据', intro: '根据付扣款项等,分类汇总合同支付的数据', defaultSetting: { table: 'mem_stage_pay', custom: [ { name: '本期完成计量', ptype: 4, order: 1, visible: false }, { name: '业主违约罚金', match: '业主违约罚金', order: 2 }, { name: '迟付款利息', match: '迟付款利息', order: 3 }, { flow: true, minus: 0, rid: ['业主违约罚金', '迟付款利息'], order: 4 }, { name: '其他付款', minus: 0, rid: ['业主违约罚金', '迟付款利息'], order: 4 }, { name: '合计', order: 5, order_calc: 'o1+o2+o3+o4' }, { name: '动员预付款', order: 6 }, { name: '扣动员预付款', match: ['扣动员预付款', '扣回动员预付款', '扣开工预付款', '扣回开工预付款'], order: 7 }, { name: '扣材料预付款', match: '扣材料预付款', order: 8 }, { name: '承包人违约罚金', match: '承包人违约罚金', order: 9 }, { name: '保留金', match: '保留金', order: 10 }, { name: '税金', match: '税金', order: 11 }, { name: '质量保证金', match: '质量保证金', order: 12 }, { name: '其他扣款', minus: 1, rid: ['扣动员预付款', '扣回动员预付款', '扣开工预付款', '扣回开工预付款', '扣材料预付款', '承包人违约罚金', '保留金', '税金', '质量保证金'], order: 13 }, { name: '扣款合计', minus: 1, rid: [], order: 14 }, { name: '支付', ptype: 2, order: 15 }, ], }, _filterFields(ctx, d, source) { let filterData = source; if (d.ptype) { filterData = filterData.filter(function(x) { return x.ptype === d.ptype; }); } if (d.match) { filterData = filterData.filter(function(x) { if (x.name) { if (d.match instanceof Array) { for (const m of d.match) { if (x.name.indexOf(m) >= 0) return true; } } else { return x.name.indexOf(d.match) >= 0; } } else { return false; } }); } if (!ctx.helper._.isNil(d.minus)) { filterData = filterData.filter(function(x) { return d.minus === 1 ? x.minus : !x.minus; }); } if (d.rid) { filterData = filterData.filter(function(x) { if (x.name) { for (const r of d.rid) { if (x.name.indexOf(r) >= 0) return false; } } return true; }); } return filterData; }, _gatherFields(ctx, d, source, calcFields) { const filterData = this._filterFields(ctx, d, source); for (const fd of filterData) { for (const prop in fd) { if (prop.indexOf('tp') >= 0) { d[prop] = ctx.helper.add(d[prop], fd[prop]); if (calcFields.indexOf(prop) === -1) calcFields.push(prop); } } } }, _completeGatherInfo(d, source) { for (const f in source) { if (/^t_[0-9]*_(id|name)$/.test(f)) { d[f] = source[f]; } } }, _completeStageSumInfo(d, source) { for (const f in source) { if (/^t_[0-9]*_order$/.test(f)) { d[f] = source[f]; } } }, fun(ctx, data, fields, options) { if (!options || !options.table || !options.custom) return; const gatherData = data[options.table]; const result = [], calcFields = []; for (const c of options.custom) { const cData = JSON.parse(JSON.stringify(c)); cData.subOrder = 0; if (cData.flow) { const fData = this._filterFields(ctx, cData, gatherData); for (const [i, f] of fData.entries()) { f.order = cData.order; f.subOrder = i; result.push(f); } } else { if (!cData.order_calc && cData.empty !== 1) { this._gatherFields(ctx, cData, gatherData, calcFields); } if (options.table.indexOf('mem_gather') >= 0) this._completeGatherInfo(cData, gatherData[0]); if (options.table.indexOf('mem_stage_sum_') >= 0) this._completeStageSumInfo(cData, gatherData[0]); result.push(cData); } } rdaUtils.orderCalc(ctx, result, calcFields); data[options.table] = result.filter(function(x) { return x.visible === undefined || x.visible; }); data[options.table].sort(function(a, b) { return a.order === b.order ? a.subOrder - b.subOrder : a.order - b.order; }); }, }; const union = { name: '合并数据', intro: '类似sql的union,可合并任意数据,合并结果写到"预留扩展数据-合并(mem_union_data)"中', defaultSetting: { union: [ { table: 'mem_stage_bills', fields: [ { target: 'str1', source: 'chapter' }, { target: 'str2', source: 'name' }, { target: 'tp1', source: 'total_price' }, { target: 'tp2', source: 'gather_tp' }, { target: 'tp3', source: 'pre_gather_tp' }, { target: 'tp4', source: 'end_gather_tp' }, { target: 'str3', data: '章级合计哟' }, ], }, { table: 'mem_stage_pay', fields: [ { target: 'str2', source: 'name' }, { target: 'tp2', source: 'tp' }, { target: 'tp3', source: 'pre_tp' }, { target: 'tp4', source: 'end_tp' }, { target: 'str3', data: '合同支付哟' }, ], }, ], }, fun(ctx, data, fields, options) { if (!options || !options.union) return; const result = []; for (const u of options.union) { const unionData = data[u.table]; for (const d of unionData) { const nd = {}; for (const f of u.fields) { if (f.data) { nd[f.target] = f.data; } else if (f.source) { nd[f.target] = d[f.source]; } } result.push(nd); } } data.mem_union_data = result; }, }; const addSumChapter = { name: '添加章级合计', intro: '在排序好的工程量清单列表中,根据清单所属章级,添加章级标题行、合计行', defaultSetting: { table: 'mem_stage_bills', code: 'b_code', chapter: 'chapter', stdChapter: { title: '%s章', sum: '%s章合计' }, otherChapter: { title: '其他章', sum: '其他章合计' }, sum: { name: '总合计' }, fields: ['ex_value1', 'ex_value2', 'end_gather_tp', 'pre_gather_tp', 'gather_tp'], }, fun(ctx, data, fields, options) { if (!options || !options.table || !options.code || !options.chapter || !options.stdChapter) return; const gclData = data[options.table]; if (!gclData || !data.tender_info) return; const chapters = ctx.helper._.uniq(ctx.helper._.map(gclData, options.chapter)); const finalSum = options.sum ? { name: options.sum.name, chapterNum: 100000, chapterPart: 1 } : null; for (const chapter of chapters) { const chapterInfo = data.tender_info.chapter.find(function(x) { return x.code === chapter; }); const chapterOptions = chapterInfo ? options.stdChapter : options.otherChapter; // sum const chapterGcl = gclData.filter(function(x) { return x.chapter === chapter; }); const sum = { chapter, chapterPart: 3, chapterNum: parseInt(chapter) }; for (const cg of chapterGcl) { cg.chapterPart = 2; cg.chapterNum = parseInt(cg[options.chapter]); for (const f of options.fields) { sum[f] = ctx.helper.add(sum[f], cg[f]); if (finalSum) { finalSum[f] = ctx.helper.add(finalSum[f], cg[f]); } } } if (chapterOptions.sum !== undefined) { sum.name = chapterOptions.sum.replace('%s', chapter); gclData.push(sum); } // title if (chapterOptions.title !== undefined) { const title = { chapter, chapterPart: 1, chapterNum: parseInt(chapter) }; if (chapterInfo) { title[options.code] = options.stdChapter.title.replace('%s', chapter); title.name = chapterInfo.name; } else { title.name = chapterOptions.title; } gclData.push(title); } } if (finalSum) { gclData.push(finalSum); } gclData.sort(function(a, b) { if (a.chapter !== b.chapter) { return a.chapterNum - b.chapterNum; } else if (a.chapterPart !== b.chapterPart) { return a.chapterPart - b.chapterPart; } return ctx.helper.compareCode(a[options.code], b[options.code]); }); }, }; const auditSelect = { name: '审批人选择', hint: '需搭配用户交互--审批人选择一起使用', defaultSetting: { table: ['mem_stage_bills_compare', 'mem_stage_pos_compare', 'mem_stage_pay'], }, _stageBillsCompare(data, order) { const fields = []; for (const [i, o] of order.entries()) { const sPrefix = 'r' + o + '_'; const tPrefix = 'as' + i + '_'; fields.push({ source: sPrefix + 'contract_qty', target: tPrefix + 'contract_qty' }); fields.push({ source: sPrefix + 'contract_tp', target: tPrefix + 'contract_tp' }); fields.push({ source: sPrefix + 'qc_qty', target: tPrefix + 'qc_qty' }); fields.push({ source: sPrefix + 'qc_tp', target: tPrefix + 'qc_tp' }); fields.push({ source: sPrefix + 'gather_qty', target: tPrefix + 'gather_qty' }); fields.push({ source: sPrefix + 'gather_tp', target: tPrefix + 'gather_tp' }); } for (const d of data) { for (const f of fields) { d[f.target] = d[f.source]; } } }, _stagePosCompare(data, order) { const fields = []; for (const [i, o] of order.entries()) { const sPrefix = 'r' + o + '_'; const tPrefix = 'as' + i + '_'; fields.push({ source: sPrefix + 'contract_qty', target: tPrefix + 'contract_qty' }); fields.push({ source: sPrefix + 'qc_qty', target: tPrefix + 'qc_qty' }); fields.push({ source: sPrefix + 'gather_qty', target: tPrefix + 'gather_qty' }); } for (const d of data) { for (const f of fields) { d[f.target] = d[f.source]; } } }, _stagePay(data, order) { const fields = []; for (const [i, o] of order.entries()) { const sPrefix = 'r' + o + '_'; const tPrefix = 'as' + i + '_'; fields.push({ source: sPrefix + 'tp', target: tPrefix + 'tp' }); } for (const d of data) { for (const f of fields) { d[f.target] = d[f.source]; } } }, fun(ctx, data, fieldsKey, options, csRela) { if (!ctx.tender || !ctx.stage) return; if (!csRela.tplDefine) return; const asDefine = csRela.tplDefine.audit_select; if (!asDefine || !asDefine.enable || !asDefine.setting || asDefine.setting === '') return; const asCustom = csRela.cDefine ? csRela.cDefine.audit_select : null; const order = []; if (asCustom) { for (const asc of asCustom) { order.push(asc.sort || asc.order); } } for (const t of options.table) { switch (t) { case 'mem_stage_bills_compare': this._stageBillsCompare(data[t], order); break; case 'mem_stage_pos_compare': this._stagePosCompare(data[t], order); break; case 'mem_stage_pay': this._stagePay(data[t], order); break; } } }, }; const datetimeFormat = { name: '日期格式化', hint: '参见帮助', defaultSetting: { tables: [ { name: 'mem_stage_bonus', fields: [ { field: 'real_time', formatter: 'yyyy-MM-DD' }, { field: 'create_time', formatter: 'yyyy-MM-DD' }, ] }, ], }, fun(ctx, data, fieldsKey, options, csRela) { if (!options.tables) return; const tables = options.tables instanceof Array ? options.tables : [options.tables]; if (tables.length === 0) return; for (const table of tables) { const formatData = data[table.name]; for (const fd of formatData) { for (const f of table.fields) { fd[f.field] = moment(fd[f.field]).format(f.formatter); } } } }, }; const gatherSelectConverse = { name: '交叉汇总数据', hint: '需搭配 用户交互--汇总标段选择 一起使用', defaultSetting: { table: ['mem_gather_stage_bills'], }, _commonConverse(helper, data, count) { const result = []; const reg = new RegExp('^t_[0-9]+_'); for (let i = 0; i < count; i++) { const curReg = new RegExp('^t_' + i + '_'); for (const [i, d] of data.entries()) { const nd = { cross_index: i + 1 }; for (const prop in d) { if (reg.test(prop)) { if (curReg.test(prop)) { nd[prop.replace(curReg, 't_')] = d[prop]; } } else { nd[prop] = d[prop]; } } result.push(nd); } } // for (const d of data) { // for (let i = 0; i < count; i++) { // const curReg = new RegExp('^t_' + i + '_'); // const nd = {}; // for (const prop in d) { // if (reg.test(prop)) { // if (curReg.test(prop)) { // nd[prop.replace(curReg, 't_')] = d[prop]; // } // } else { // nd[prop] = d[prop]; // } // } // result.push(nd); // } // } return result; }, fun(ctx, data, fieldsKey, options, csRela) { if (!csRela.tplDefine) return; const gsDefine = csRela.tplDefine.gather_select; if (!gsDefine || !gsDefine.enable || !gsDefine.setting || gsDefine.setting === '') return; const gsCustom = csRela.cDefine ? csRela.cDefine.gather_select : null; const count = gsDefine.setting.special ? gsCustom.tenders.length - gsDefine.setting.special.length : gsCustom.tenders.length; for (const t of options.table) { switch (t) { case 'mem_gather_stage_bills': case 'mem_gather_stage_bills_filter': case 'mem_gather_stage_pos': case 'mem_gather_stage_pay': case 'mem_gather_deal_bills': case 'mem_union_data': data[t] = this._commonConverse(ctx.helper, data[t], count); break; } } }, }; const sortPos = { name: '计量单元排序', hint: '', defaultSetting: { bills: 'mem_stage_bills', pos: 'mem_stage_pos', }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.bills || !options.pos) return; const bills = data[options.bills]; const pos = data[options.pos]; if (!bills || bills.length === 0 || !pos || pos.length === 0) return; const billsIndex = {}; const findBillsIndex = function(billsId) { if (!billsIndex[billsId]) { billsIndex[billsId] = ctx.helper._.findIndex(bills, function(x) { return x.id === billsId; }); } return billsIndex[billsId]; }; pos.sort(function(x, y) { const xIndex = findBillsIndex(x.lid) * 1000 + x.porder; const yIndex = findBillsIndex(y.lid) * 1000 + y.porder; return xIndex - yIndex; }); }, }; const unionPos = { name: '拼接计量单元', hint: '', defaultSetting: { bills: 'mem_stage_bills', pos: 'mem_stage_pos', }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.bills || !options.pos) return; const bills = data[options.bills]; const pos = data[options.pos]; if (!bills || bills.length === 0 || !pos || pos.length === 0) return; const posIndex = new PosIndex({ id: 'id', masterId: 'lid', order: 'porder', }); posIndex.loadDatas(pos); const unionData = []; for (const b of bills) { unionData.push(b); const posRange = posIndex.getLedgerPos(b.id); b.posCount = posRange ? posRange.length : 0; if (!posRange || posRange.length === 0) continue; for (const p of posRange) { unionData.push(p); } } data[options.bills] = unionData; }, }; const splitXmjCode = { name: '拆分项目节编号', hint: '', defaultSetting: { table: 'mem_stage_bills', type: '11', // '18', '18-0-1', '18-1', '18-1-1' code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu'], }, // 11标准 _split11Std(data, options, helper) { for (const d of data) { if (!d[options.code]) continue; const splitCodes = d[options.code].split('-'); if (d.level === 2) { const field = options.targetField[0]; if (field && splitCodes.length > 1) { d[field] = helper.transFormToChinese(splitCodes[1]); } } else if (d.level === 3) { const field = options.targetField[1]; if (field && splitCodes.length > 2) { d[field] = splitCodes[2]; } } else if (d.level === 4) { const field = options.targetField[2]; if (field && splitCodes.length > 3) { d[field] = splitCodes[3]; } } else if (d.level > 4) { const field = options.targetField[3]; if (field && splitCodes.length > 4) { d[field] = splitCodes.reduce(function(s, v, i) { return i >= 4 ? (s ? s + '-' + v : v + '') : ''; }); } } } }, _getParentByLevel(data, node, level) { if (node.full_path) { const pid = node.full_path.split('-')[level - 1]; return data.find(function(x) { return x.level === level && x.ledger_id == pid; }); } return null; }, // 18标准 _split18Std(data, options, helper) { const types = options.type.split('-'); const isSplitSub = !!(types[1] && types[1] === '1'); const isKeepGD = !!(types[2] && types[2] === '1'); for (const d of data) { if (!d[options.code]) continue; let target = ''; if (d.level === 2) { target = options.targetField[0] ? options.targetField[0] : ''; } else if (d.level === 3) { target = options.targetField[1] ? options.targetField[1] : ''; } else if (d.level === 4) { target = options.targetField[2] ? options.targetField[2] : ''; } else if (d.level > 4) { target = options.targetField[3] ? options.targetField[3] : ''; } if (!target) continue; if (helper.check18MainCode(d[options.code])) { const parent = helper._.find(data, { ledger_id: d.ledger_pid }); const splitParent = !parent || parent.level < 5 ? parent : this._getParentByLevel(data, d, 4); d[target] = !splitParent ? d[options.code] : d[options.code].replace(splitParent[options.code], ''); } else if (helper.check18SubCode(d[options.code]) && isSplitSub) { const parent = helper._.find(data, { ledger_id: d.ledger_pid }); const splitParent = !parent || parent.level < 5 ? parent : this._getParentByLevel(data, d, 4); d[target] = !splitParent || helper.check18MainCode(splitParent.code) ? d[options.code] : d[options.code].replace(splitParent[options.code], ''); } else { d[target] = d[options.code]; } if (!isKeepGD) d[target] = d[target].replace(/^G[D]?/, ''); } }, // 根据层次填入 _splitDefault(data, options) { for (const d of data) { if (!d[options.code]) continue; if (d.level === 2) { if (options.targetField[0]) d[options.targetField[0]] = d[options.code]; } else if (d.level === 3) { if (options.targetField[1]) d[options.targetField[1]] = d[options.code]; } else if (d.level === 4) { if (options.targetField[2]) d[options.targetField[2]] = d[options.code]; } else if (d.level > 4) { if (options.targetField[3]) d[options.targetField[3]] = d[options.code]; } } }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.table || !options.code || !options.targetField) return; if (!data[options.table]) return; if (options.type === '11') { this._split11Std(data[options.table], options, ctx.helper); } else if (/^18(-[0,1]){0,2}$/.test(options.type)) { this._split18Std(data[options.table], options, ctx.helper); } else { this._splitDefault(data[options.table], options); } }, }; const stageSelectConverse = { name: '交叉多期汇总数据', hint: '需搭配 用户交互--单标段多期汇总选择 一起使用', defaultSetting: { table: ['mem_stage_sum_bills'], }, _commonConverse(helper, data, stages) { const result = []; const reg = new RegExp('^s_[0-9]+_'); for (const s of stages) { const curReg = new RegExp('^s_' + s + '_'); for (const [i, d] of data.entries()) { const nd = { cross_index: i + 1, s_order: s }; for (const prop in d) { if (reg.test(prop)) { if (curReg.test(prop)) { nd[prop.replace(curReg, 's_')] = d[prop]; } } else { nd[prop] = d[prop]; } } result.push(nd); } } return result; }, fun(ctx, data, fieldsKey, options, csRela) { if (!csRela.tplDefine) return; const gsDefine = csRela.tplDefine.stage_select; if (!gsDefine || !gsDefine.enable || !gsDefine.setting || gsDefine.setting === '') return; const gsCustom = csRela.cDefine ? csRela.cDefine.stage_select : null; if (gsCustom) { for (const t of options.table) { switch (t) { case 'mem_stage_sum_bills': case 'mem_stage_sum_bills_filter': case 'mem_stage_sum_pos': case 'mem_stage_sum_pay': case 'mem_union_data': data[t] = this._commonConverse(ctx.helper, data[t], gsCustom.stages); break; } } } else { console.log('gsCustom is null!'); } }, }; const materialSumSelectConverse = { name: '交叉【多期材差汇总】数据', hint: '需搭配 用户交互【材差-多期汇总选择】 一起使用', defaultSetting: { table: ['mem_material_sum_gl'], }, _commonConverse(helper, data, materials) { const result = []; const reg = new RegExp('^m_[0-9]+_'); for (const s of materials) { const curReg = new RegExp('^m_' + s + '_'); for (const [i, d] of data.entries()) { const stageId = `m_${s}_stageId`; if (d[stageId]) { for (const sid of d[stageId]) { const curStageReg = new RegExp(`^m_${s}_s${sid}_`); const nd = { cross_index: i + 1, s_order: `${s}_${sid}` }; for (const prop in d) { if (reg.test(prop)) { if (curStageReg.test(prop)) { nd[prop.replace(curStageReg, 'm_')] = d[prop]; } } else { nd[prop] = d[prop]; } } result.push(nd); } } else { const nd = { cross_index: i + 1, s_order: s }; for (const prop in d) { if (reg.test(prop)) { if (curReg.test(prop)) { nd[prop.replace(curReg, 'm_')] = d[prop]; } } else { nd[prop] = d[prop]; } } result.push(nd); } } } return result; }, fun(ctx, data, fieldsKey, options, csRela) { if (!csRela.tplDefine) return; const gsDefine = csRela.tplDefine.material_sum_select; if (!gsDefine || !gsDefine.enable || !gsDefine.setting || gsDefine.setting === '') return; const gsCustom = csRela.cDefine ? csRela.cDefine.material_sum_select : null; if (gsCustom) { for (const t of options.table) { switch (t) { case 'mem_material_sum_gl': data[t] = this._commonConverse(ctx.helper, data[t], gsCustom.materials); break; } } } else { console.log('gsCustom is null!'); } }, }; const loadCooperationData = { name: '加载协作数据', hint: '须使用台账、计量审批流程、协作数据作为基础', defaultSetting: { table: 'mem_stage_im_zl', co_sign: [0, 1, 2, 3], }, _findSign(relaId, stageCooperation, auditor) { if (!stageCooperation) return ''; if (relaId.length > 0) { for (const id of relaId) { const c = stageCooperation.find(x => { return x.ledger_id == id; }); if (c) return c.sign_path; } return ''; } return ''; }, _findCooperation(relaId, stageCooperation, auditor) { if (!stageCooperation) return null; if (relaId.length > 0) { for (const id of relaId) { const c = stageCooperation.find(x => { return x.ledger_id == id; }); if (c) return c; } return null; } return null; }, _completeSign(auditor) { if (!auditor) return ''; if (auditor.ass_user_id) { return auditor.sign_path ? 'public/upload/sign/' + auditor.sign_path : ''; } else { if (!auditor.end_time) return ''; return auditor.sign_path ? 'public/upload/sign/' + auditor.sign_path : ''; } }, _loadImCooperationData(ctx, data, options, csRela) { const coSignInfo = []; if (csRela && csRela.tplDefine && csRela.tplDefine.audit_select && csRela.cDefine && csRela.cDefine.audit_select) { if (csRela.cDefine.audit_select) { for (const asc of csRela.cDefine.audit_select) { coSignInfo.push({ aid: asc.aid, order: asc.order }); } } } const stageCooperation = []; let finish = true; for (const sa of data.stage_audit) { if (sa.end_time) stageCooperation.push(data.ledger_cooperation.filter(x => { return x.user_id === sa.aid; })); if (finish && !sa.end_time) finish = false; } for (const d of data[options.table]) { const bills = data.mem_stage_bills.find(x => { return x.id === d.lid; }); const relaId = bills ? bills.full_path.split('-').reverse() : []; d.cooperation = [], d.company = []; for (const [i, sa] of data.stage_audit.entries()) { const co = this._findCooperation(relaId, stageCooperation[i], sa); d.cooperation.push(this._findSign(relaId, stageCooperation[i], sa)); d.company.push(co ? co.company : ''); } if (finish) { for (const [i, cs] of coSignOrder.entries()) { if (data.stage_audit[cs] && data.stage_audit[cs].end_time) { d['co_sign' + (i + 1)] = d.cooperation[cs] || this._completeSign(data.stage_audit[cs]); d['co_opinion' + (i + 1)] = data.stage_audit[cs].opinion || ''; d['co_time' + (i + 1)] = data.stage_audit[cs].end_time; d['co_company' + (i + 1)] = d.company[cs] || data.stage_audit[cs].name; } } } } }, _findStageAuditAss(relaId, stageAuditAss, auditor) { if (!stageAuditAss || stageAuditAss.length === 0) return null; if (relaId.length > 0) { for (const id of relaId) { const c = stageAuditAss.find(x => { return x.ass_ledger_id.indexOf(id + '') >= 0; }); if (c) return c; } return null; } return null; }, _loadImAssistData(ctx, data, options, csRela) { const coSignInfo = []; if (csRela && csRela.tplDefine && csRela.tplDefine.audit_select && csRela.cDefine && csRela.cDefine.audit_select) { if (csRela.cDefine.audit_select) { for (const asc of csRela.cDefine.audit_select) { coSignInfo.push({ aid: asc.aid, order: asc.order }); } } } let finish = true; for (const sa of data.stage_audit) { if (sa.end_time) sa.ass = data.mem_stage_audit_ass.filter(x => { return x.user_id === sa.aid; }); if (finish && !sa.end_time) finish = false; } for (const d of data[options.table]) { const bills = data.mem_stage_bills.find(x => { return x.id === d.lid; }); const relaId = bills ? bills.full_path.split('-').reverse() : []; for (const [i, cs] of coSignInfo.entries()) { const sa = data.stage_audit.find(x => { if (x.aid !== undefined) return x.aid === cs.aid && x.order === cs.order; return x.order === cs.order; }); if (sa && sa.end_time) { const co = this._findStageAuditAss(relaId, sa.ass, sa); d['co_sign' + (i + 1)] = this._completeSign(co || sa); d['co_opinion' + (i + 1)] = sa.opinion || ''; d['co_time' + (i + 1)] = sa.end_time; d['co_name' + (i + 1)] = co ? co.name : sa.name; d['co_company' + (i + 1)] = co ? co.company : sa.company; } } } }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.table) return; if (!data[options.table]) return; if (!data.mem_stage_bills) return; if (!data.stage_audit) return; if (!data.ledger_cooperation && !data.mem_stage_audit_ass) return; if (['mem_stage_im_zl', 'mem_stage_im_tz'].indexOf(options.table) >= 0) { if (data.mem_stage_audit_ass) { this._loadImAssistData(ctx, data, options, csRela); } else { this._loadImCooperationData(ctx, data, options, csRela); } } }, }; const signSelect = { name: '签字', hint: '协作模式下,才需使用,其他情况勿需使用', defaultSetting: { table: 'mem_stage_im_zl', }, _findSign(relaId, stageCooperation, auditor) { if (!stageCooperation) return ''; if (relaId.length > 0) { for (const id of relaId) { const c = stageCooperation.find(x => { return x.ledger_id == id; }); if (c) return c.sign_path; } return ''; } return ''; }, _loadImCooperationData(ctx, data, options, csRela) { const stageCooperation = {}; for (const sa of data.stage_audit) { if (sa.end_time) stageCooperation[sa.aid] = data.ledger_cooperation.filter(x => { return x.user_id === sa.aid; }); } for (const d of data[options.table]) { const bills = data.mem_stage_bills.find(x => { return x.id === d.lid; }); const relaId = bills ? bills.full_path.split('-').reverse() : []; for (const ss of data.sign_select) { if (!ss.co_sign) ss.co_sign = []; ss.co_sign.push(this._findSign(relaId, stageCooperation[ss.id], ss) || 'public/upload/sign/' + ss.sign_path); } } }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.table) return; if (!data[options.table]) return; if (!data.mem_stage_bills) return; if (!data.stage_audit) return; if (!data.ledger_cooperation) return; if (['mem_stage_im_zl', 'mem_stage_im_tz'].indexOf(options.table) >= 0) { this._loadImCooperationData(ctx, data, options, csRela); } }, }; const getChangeLedger = { name: '获取 工程变更台账表 数据', hint: '须提供mem_stage_bills, mem_stage_change_bills作为数据支撑, 结果写入mem_stage_change_ledger', defaultSetting: { mergeName: true, calc: '', // split: 均分 level: '2-leaf', // 空表示表示保留所有的项目节,2-leaf表示保留第2层和最底层项目节,默认为空 }, _getSource(ctx, bills, changeList) { const result = []; for (const b of bills) { if (b.b_code) continue; const l = { id: b.id, code: b.code, name: b.name, unit: b.unit, ledger_id: b.ledger_id, ledger_pid: b.ledger_pid, level: b.level, full_path: b.full_path, total_price: b.total_price, deal_tp: b.deal_tp, contract_tp: b.contract_tp, qc_tp: b.qc_tp, gather_tp: b.gather_tp, end_contract_tp: b.end_contract_tp, end_qc_tp: b.end_qc_tp, end_gather_tp: b.end_gather_tp, }; result.push(l); const childGcl = bills.filter(x => { return x.ledger_pid === b.ledger_id && x.b_code}); if (!childGcl || childGcl.length === 0) continue; const gcl = bills.filter(x => { return x.full_path.indexOf(l.full_path + '-') === 0 && x.b_code; }); if (gcl.length === 0) continue; const gclIds = gcl.map(x => { return x.id; }); const changes = changeList.filter(x => { return gclIds.indexOf(x.lid) >= 0; }); if (!changes || changes.length === 0) continue; l.changes = []; for (const c of changes) { let mc = l.changes.find(x => { return x.cid === c.cid; }); if (!mc) { mc = { cid: c.cid, c_code: c.c_code, c_name: c.c_name, c_new_code: c.c_new_code, c_new_name: c.c_new_name, c_content: c.c_content, c_basis: c.c_basis, c_cin_time: c.c_cin_time * 1000, c_bills: [], }; l.changes.push(mc); } mc.c_bills.push(c); } } return result; }, _filterChangeLedger(ctx, changeLedger, options) { const result = []; for (const f of changeLedger) { const calc = changeLedger.filter(x => { return x.full_path.indexOf(f.full_path) === 0 && x.changes && x.changes.length > 0; }); if (!calc || calc.length === 0) continue; if (options.level === '2-leaf') if (f.level !== 2 && (!f.changes || f.changes.length === 0)) continue; result.push({ code: f.code, name: f.name, unit: f.unit, ledger_id: f.ledger_id, ledger_pid: f.ledger_pid, level: f.level, full_path: f.full_path, total_price: f.total_price, deal_tp: f.deal_tp, contract_tp: f.contract_tp, qc_tp: f.qc_tp, gather_tp: f.gather_tp, end_contract_tp: f.end_contract_tp, end_qc_tp: f.end_qc_tp, end_gather_tp: f.end_gather_tp, }); if (f.changes && f.changes.length > 0) { for (const c of f.changes) { const fc = { c_code: c.c_code, c_name: c.c_name, c_new_code: c.c_new_code, c_new_name: c.c_new_name, c_content: c.c_content, c_basis: c.c_basis, c_cin_time: c.c_cin_time, }; if (options.mergeName) fc.name = fc.c_name; result.push(fc); } } } return result; }, fun(ctx, data, fieldsKey, options, csRela) { if (!options) options = {}; if (!data.mem_stage_bills) return; if (!data.mem_stage_change_bills) return; const changeLedger = this._getSource(ctx, data.mem_stage_bills, data.mem_stage_change_bills); data.mem_stage_change_ledger = this._filterChangeLedger(ctx, changeLedger, options); }, }; const treeFilter = { name: '树结构数据过滤', hint: '过滤时,当父项符合条件时,会自动包含子项', defaultSetting: { table: 'mem_stage_bills', type: 'match/filter', subType: 'all/posterity/leaf', condition: [ { field: 'name', type: 'str', value: '建筑项目管理费', isPart: true }, ], }, _checkPath(matchPath, full_path) { for (const mp of matchPath) { if (full_path.indexOf(mp.match + '-') === 0) return true; if (mp.type === 'all' && full_path === mp.match) return true; } return false; }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.table || !options.condition || !options.type) return; const fData = data[options.table], self = this; if (!fData || fData.length === 0) return; if (!fData[0].full_path) return; valueCheck.loadTypeFun(options.condition); const matchPath = []; for (const d of fData) { if (this._checkPath(matchPath, d.full_path)) continue; if (valueCheck.checkData(ctx, d, options.condition)) { matchPath.push({ match: d.full_path, type: options.subType }); } } data[options.table] = fData.filter(x => { const match = self._checkPath(matchPath, x.full_path) && (options.subType === 'leaf' ? x.is_leaf : true); return options.type === 'match' ? match : !match; }); }, }; const gatherGcl2 = { name: '工程量清单汇总2', hint: '会生成新的工程量清单指标&相关项目节指标', defaultSetting: { billsTable: 'mem_stage_bills', posTable: 'mem_stage_pos', dealTable: 'deal_bills', }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.billsTable || !options.posTable) return; const bills = data[options.billsTable]; if (!bills) return; const pos = data[options.posTable]; if (!pos) return; const deal = data[options.dealTable]; const gclGatherModel = require('./gcl_gather').gclGather; const gatherUtil = new gclGatherModel(ctx); gatherUtil.gather(bills, pos, deal); data.mem_gcl_gather_bills = gatherUtil.gclList; data.mem_gcl_gather_xmj = gatherUtil.leafXmjs; } }; const gatherMaterialGl = { name: '分类汇总调差工料', hint: '根据工程量清单分类汇总调差工料,要求先使用【工程量清单汇总2】处理得到工程量清单数据,并引入【调差工料明细】', _relaGl(source, data) { if (!source) return; const gl = source.find(x => {return x.id === data.mb_id;}); if (gl) { data.gl_code = gl.code; data.gl_name = gl.name; data.gl_unit = gl.unit; data.gl_spec = gl.spec; data.gl_base_price = gl.base_price; data.gl_base_times = gl.base_times; data.gl_msg_tp = gl.msg_tp; data.gl_msg_times = gl.msg_times; data.gl_msg_spread = gl.msg_spread; data.gl_m_up_risk = gl.m_up_risk; data.gl_m_down_risk = gl.m_down_risk; data.gl_m_spread = gl.m_spread; } }, fun(ctx, data, fieldsKey, options, csRela) { if (!data.mem_gcl_gather_bills || !data.mem_gcl_gather_xmj || !data.mem_material_gl_detail) return; const result = []; for (const d of data.mem_material_gl_detail) { const xmj = data.mem_gcl_gather_xmj.find(x => { return d.gcl_id === x.org_gcl_id && d.xmj_id === x.id && (!d.mx_id || d.mx_id === x.mx_id); }); if (!xmj) continue; const gcl = data.mem_gcl_gather_bills.find(x => { return x.id === xmj.gcl_id; }); if (!gcl) continue; const gd = result.find(x => { return x.gather_gcl_id === gcl.id && x.mb_id === d.mb_id; }); if (!gd) { const newGd = { gather_gcl_id: gcl.id, mb_id: d.mb_id, gather_qty: d.gather_qty, quantity: d.quantity, b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price, cur_contract_qty: gcl.contract_qty, cur_contract_tp: gcl.contract_tp, cur_qc_qty: gcl.qc_qty, cur_qc_tp: gcl.qc_tp, cur_gather_qty: gcl.gather_qty, cur_gather_tp: gcl.gather_tp, }; this._relaGl(data.mem_material_gl, newGd); result.push(newGd); } else { gd.gather_qty = ctx.helper.add(gd.gather_qty, d.gather_qty); gd.quantity = ctx.helper.add(gd.quantity, d.quantity); } } data.mem_material_gl_detail = result; } }; const masterCross = { name: '主从交叉(汇总)数据-通用', hint: '此版本,要求表必须是主从关系', defaultSetting: { main: { tableName: 'mem_material_gather_bills', prefix: 'm_', fields: ['b_code', 'name', 'units', 'unit_price', 'quantity', 'total_price', 'gather_qty', 'gather_tp', 'jiacha'], }, sub: { tableName: 'mem_material_gather_gl', masterKey: 'id', subKey: 'gather_gcl_id', gatherKey: 'mb_id', prefix: 's_', fields: ['code', 'name', 'units'], quoteFields: ['quantity'], gatherFields: [], }, target: 'master_converse', base: 'main', }, _converse: function(ctx, options, mainTable, subTable) { const data = []; const converseData = []; subTable.forEach(x => { let cd = converseData.find(y => { return x[options.sub.gatherKey] === y[options.sub.gatherKey]}); if (cd) return; cd = {}; cd[options.sub.gatherKey] = x[options.sub.gatherKey]; for (const f of options.sub.fields) { cd[f] = x[f]; } converseData.push(cd); }); for (const [i, m] of mainTable.entries()) { const temp = { cross_index: i+1 }; for (const f of options.main.fields) { temp[options.main.prefix + f] = m[f]; } const rela = subTable.filter(x => { return x[options.sub.subKey] === m[options.sub.masterKey]; }); if (options.base === 'sub' && rela.length === 0) continue; for (const cd of converseData) { const nd = JSON.parse(JSON.stringify(temp)); nd.quote = false; for (const prop in cd) { nd[options.sub.prefix + prop] = cd[prop]; } rela.forEach(x => { if (x[options.sub.gatherKey] !== cd[options.sub.gatherKey]) return; if (!nd.quote) { for (const f of options.sub.quoteFields) { nd[options.sub.prefix + f] = x[f]; } nd.quote = true; } for (const f of options.sub.gatherFields) { nd[options.sub.prefix + f] = ctx.helper.add(nd[options.sub.prefix + f], x[f]); } }); data.push(nd); } } return data; }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.main || !options.sub || !options.target) return; const mainTable = data[options.main.tableName], subTable = data[options.sub.tableName]; if (!mainTable || !subTable) return; data[options.target] = this._converse(ctx, options, mainTable, subTable); }, }; const orderBy = { name: "简单排序", hint: "仅提供简单的排序", defaultSetting: { table: 'mem_material_sum_gl', orders: [['m_order', 'asc']], }, fun(ctx, data, fieldsKey, options, csRela) { if (!options || !options.table || !options.orders) return; const ascSort = function (x, y, field) { if (!x[field]) return 1; if (!y[field]) return -1; return x[field] === y[field] ? 0 : (x[field] > y[field] ? 1 : -1); }; const descSort = function (x, y, field) { if (!x[field]) return -1; if (!y[field]) return 1; return x[field] === y[field] ? 0 : (x[field] > y[field] ? -1 : 1); }; const orderFun = []; for (const order of options.orders) { if (order.length !== 2) return; if (['asc', 'desc'].indexOf(order[1]) === -1) return; orderFun.push({ field: order[0], fun: order[1] === 'asc' ? ascSort : descSort }); } data[options.table].sort((x, y) => { for (const order of orderFun) { const sortResult = order.fun(x, y, order.field); if (sortResult !== 0) return sortResult; } }); } }; const analysisObj = { changeSort, gatherGcl, sortGcl, gatherChapter, join, getChapterCode, filter, union, gatherStagePay, addSumChapter, auditSelect, datetimeFormat, gatherSelectConverse, stageSelectConverse, materialSumSelectConverse, sortPos, unionPos, splitXmjCode, loadCooperationData, getChangeLedger, treeFilter, gatherGcl2, gatherMaterialGl, masterCross, orderBy, }; const analysisDefine = (function(obj) { const result = []; for (const o in obj) { const analysis = obj[o]; if (analysis.name && analysis.fun) { result.push({ name: analysis.name, key: o, hint: analysis.hint, intro: analysis.intro, url: '/help?m=report&s=analysis&d=' + o, }); } } return result; })(analysisObj); module.exports = { analysisObj, analysisDefine, };