123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- 'use strict';
- /**
- *
- *
- * @author Mai
- * @date 2018/4/25
- * @version
- */
- const Service = require('egg').Service;
- module.exports = app => {
- const paramConst = app.paramConst;
- const nodeConst = app.nodeConst;
- class Match extends Service {
- /**
- * 初始化匹配所需变量
- * @param {Array|Object} bills - 导入的清单数据
- * @private
- */
- _init(bills) {
- this.bills = bills instanceof Array ? bills : [bills];
- this.bills[0].match_node = null;
- this.fixedBills = this.bills.filter(function (b) {
- return b.n_id < 100;
- });
- this.nodes = [];
- this.indexes = [];
- this.params = [];
- }
- /**
- * 获取指标模板数据
- * @param {Number} templateId - 指标模板Id
- * @returns {Promise<void>}
- * @private
- */
- async _getTemplateData (templateId) {
- this.templateNodes = await this.ctx.service.templateNode.getAllDataByCondition({ where: { template_id: templateId } });
- this.templateIndexes = await this.ctx.service.templateIndex.getAllDataByCondition({ where: { template_id: templateId } });
- this.templateParams = await this.ctx.service.templateParam.getAllDataByCondition({ where: { template_id: templateId } });
- }
- /**
- * 检查code是否满足匹配规则rule
- * @param {String} code - 匹配编号
- * @param {String} rule - 匹配规则
- * @returns {boolean}
- * @private
- */
- _matchCodeByRule(code, rule) {
- const codeParts = code.split('-');
- const ruleParts = rule.split('-');
- const numReg = /(^[0-9]+$)/, charReg = /(^[a-z]+$)/i;
- if (codeParts.length !== ruleParts.length) { return false; }
- for (let i = 0, iLen = codeParts.length; i < iLen; i++) {
- if (numReg.test(ruleParts[i])) {
- if (ruleParts[i] !== codeParts[i]) {
- return false;
- }
- } else if (!charReg.test(ruleParts[i])) {
- return false;
- }
- }
- return true;
- }
- _matchCodeByRules(code, rules, bills) {
- const ruleArr = rules.split(';');
- for (const r of ruleArr) {
- if (this._matchCodeByRule(code, r)) {
- bills.match_key = r;
- return true;
- }
- }
- return false;
- }
- /**
- * 过滤符合指标节点node匹配规则的清单
- * 已经匹配过的清单不再匹配
- *
- * @param {Object} node - 指标节点
- * @private
- */
- _filterBills (node) {
- const self = this;
- return this.bills.filter(function (b) {
- if (!b.match_node) {
- if (node.match_type === nodeConst.matchType.code) {
- return self._matchCodeByRules(b.code, node.match_key, b);
- } else {
- if (node.match_key === b.name) {
- b.match_key = b.name;
- return true;
- } else {
- return false;
- }
- }
- } else {
- return false;
- }
- })
- }
- /**
- * 根据指标参数取值类别,从清单取值
- *
- * @param {Object} param - 指标参数
- * @param {Object} bills - 清单节点
- * @returns {number}
- * @private
- */
- _getNodeBillsValue(param, bills) {
- if (bills) {
- switch (param.match_num) {
- case paramConst.matchNum.quantity: return bills.quantity;
- case paramConst.matchNum.total_price: return bills.total_price;
- case paramConst.matchNum.dgn_quantity1: return bills.dgn_quantity1;
- case paramConst.matchNum.dgn_quantity2: return bills.dgn_quantity2;
- default: return undefined;
- }
- } else {
- return undefined;
- }
- }
- _getChildrenBillsValue(param, bills) {
- if (bills) {
- const children = this.ctx.helper.filterObj(this.bills, 'n_pid', bills.n_id);
- switch(param.match_num) {
- case paramConst.matchNum.quantity: return this.ctx.helper.sumField(children, 'quantity');
- case paramConst.matchNum.total_price: return this.ctx.helper.sumField(children, 'total_price');
- case paramConst.matchNum.dgn_quantity1: return this.ctx.helper.sumField(children, 'dgn_quantity1');
- case paramConst.matchNum.dgn_quantity2: return this.ctx.helper.sumField(children, 'dgn_quantity2');
- }
- } else {
- return undefined;
- }
- }
- /**
- * 获取指标参数取值(固定Id匹配)
- * @param {Object} param - 指标参数
- * @returns {*}
- * @private
- */
- _getFixedIdParamValue(param) {
- for (const b of this.fixedBills) {
- if (b.n_id == param.match_key) {
- return this._getNodeBillsValue(param, b);
- }
- }
- return undefined;
- }
- /**
- * 获取指标参数取值(编号匹配)
- * @param param
- * @param nodeBills
- * @returns {*}
- * @private
- */
- _getCodeParamValue(param) {
- for (const b of this.bills) {
- if (this._matchCodeByRules(b.code, param.match_key, b)) {
- return this._getNodeBillsValue(param, b);
- }
- }
- return undefined;
- }
- /**
- * 获取父项
- * @param {Object} node - 分项清单节点
- * @private
- */
- _getParentBills(node) {
- return node ? this.ctx.helper.findObj(this.bills, 'n_id', node.n_pid) : null;
- }
- /**
- * 获取指标参数取值
- * @param {Object} param - 指标参数
- * @param {Object} nodeBills - 指标参数 所属 指标节点,绑定的 清单
- * @returns {*}
- * @private
- */
- _getParamValue(param, nodeBills) {
- if (!isNaN(Number(param.name))) {
- return Number(param.name);
- } else {
- switch (param.match_type) {
- case paramConst.matchType.fixed_id: return this._getFixedIdParamValue(param);
- case paramConst.matchType.node_default: return this._getNodeBillsValue(param, nodeBills);
- case paramConst.matchType.parent_default: return this._getNodeBillsValue(param, this._getParentBills(nodeBills));
- case paramConst.matchType.child_gather: return this._getChildrenBillsValue(param, nodeBills);
- case paramConst.matchType.code: return this._getCodeParamValue(param);
- // to do 匹配属性
- default: return undefined;
- }
- }
- }
- /**
- * 同步指标节点下的全部指标参数
- * @param {Number} nodeId
- * @private
- */
- _syncNodeParam(sourceId, nodeId, nodeBills) {
- const nodeParams = this.templateParams.filter(function (p) {
- return p.node_id === sourceId;
- });
- for (const np of nodeParams) {
- const newParam = {
- node_id: nodeId,
- lib_id: nodeBills.lib_id,
- param_id: this.params.length + 1,
- source_id: np.param_id,
- code: np.code,
- name: np.name,
- match_type: np.match_type,
- match_key: np.match_key,
- match_num: np.match_num,
- };
- newParam.match_value = this._getParamValue(newParam, nodeBills);
- newParam.calc_value = newParam.match_value;
- this.params.push(newParam);
- }
- }
- /**
- * 同步指标节点下的全部指标
- * @param {Number} nodeId
- * @private
- */
- _syncNodeIndex(node) {
- const nodeIndexes = this.templateIndexes.filter(function (i) {
- return i.node_id === node.source_id;
- });
- for (const ni of nodeIndexes) {
- const newIndex = {
- node_id: node.node_id,
- lib_id: node.lib_id,
- index_id: this.indexes.length + 1,
- source_id: ni.index_id,
- code: ni.code,
- name: ni.name,
- unit1: ni.unit1,
- unit2: ni.unit2,
- rule: ni.rule,
- calc_rule: ni.calc_rule,
- parse_rule: ni.parse_rule,
- index_type: ni.index_type,
- }
- this.indexes.push(newIndex);
- }
- }
- _getXMatchId(bills) {
- //const reg = /-([a-z])-/i;
- const reg = /-([a-z])/i;
- if (reg.test(bills.match_key)) {
- const ruleParts = bills.match_key.split('-');
- const charReg = /(^[a-z]+$)/i;
- let node = bills, parent = bills;
- for (let i = ruleParts.length - 1; i>= 0; i--) {
- if (parent) {
- if (charReg.test(ruleParts[i])) {
- return parent.n_id;
- }
- node = parent;
- parent = this.bills.find(function(x) {
- return x.n_id === node.n_pid;
- });
- } else {
- return -1;
- }
- }
- } else {
- return -1;
- }
- }
- /**
- * 匹配指标节点
- * @param node
- * @private
- */
- _matchNode(node) {
- if (!node) { return; }
- const matchedBills = this._filterBills(node);
- for (const mb of matchedBills) {
- const newNode = {
- node_id: this.nodes.length + 1,
- lib_id: mb.lib_id,
- source_id: node.node_id,
- code: node.code,
- name: node.name,
- match_type: node.match_type,
- match_key: mb.match_key,
- bills_id: mb.n_id,
- bills_xid: node.match_type === nodeConst.matchType.code ? this._getXMatchId(mb) : -1,
- index_class: node.index_class,
- class_name: node.class_name,
- };
- this.nodes.push(newNode);
- this._syncNodeParam(newNode.source_id, newNode.node_id, mb);
- this._syncNodeIndex(newNode);
- mb.match_node = newNode.node_id;
- }
- }
- /**
- * 按模板匹配规则,给清单匹配指标节点
- *
- * @param {Array} bills - 匹配的清单
- * @param {Number} templateId - 用户匹配的模板Id
- * @returns {Promise<void>}
- */
- async matchBills (bills, templateId = 1) {
- this._init(bills);
- // 获取指标模板全部数据
- await this._getTemplateData(templateId);
- // 同步全局指标参数
- this._syncNodeParam(paramConst.globalParamNodeId, paramConst.globalParamNodeId, this.bills[0]);
- // 遍历模板中所有指标节点,匹配清单
- for (const node of this.templateNodes) {
- this._matchNode(node);
- }
- // 计算全部指标节点
- const globalParams = this.params.filter(function (p) {
- return p.node_id === paramConst.globalParamNodeId;
- });
- for (const node of this.nodes) {
- const nodeParams = this.params.filter(function (n) {
- return n.node_id === node.node_id;
- });
- const nodeIndexes = this.indexes.filter(function (i) {
- return i.node_id === node.node_id;
- });
- this.ctx.service.indexCalc.calculate(nodeIndexes, globalParams, nodeParams);
- }
- for (const b of this.bills) {
- delete b.match_key;
- }
- }
- _syncCustomData(data, custom) {
- if (!custom || custom.length === 0) return;
- for (const d of data) {
- const c = custom.find(function (x) {return x.name === d.name});
- d.calc_value = c.calc_value;
- }
- }
- async reMatchBills(lib, templateId = 1) {
- const bills = await this.ctx.service.bills.getAllDataByCondition({ where: {lib_id: lib.id} });
- this._init(bills);
- for (const b of bills) {
- b.match_node = null;
- }
- // 获取指标模板全部数据
- await this._getTemplateData(templateId);
- // 同步全局指标参数
- this._syncNodeParam(paramConst.globalParamNodeId, paramConst.globalParamNodeId, this.bills[0]);
- // 遍历模板中所有指标节点,匹配清单
- for (const node of this.templateNodes) {
- this._matchNode(node);
- }
- // 计算全部指标节点
- const globalParams = this.params.filter(function (p) {
- return p.node_id === paramConst.globalParamNodeId;
- });
- const ogp = await this.ctx.service.tenderParam.getAllDataByCondition({ where: {lib_id: lib.id} });
- this._syncCustomData(globalParams, ogp);
- for (const node of this.nodes) {
- const nodeParams = this.params.filter(function (n) {
- return n.node_id === node.node_id;
- });
- const onp = await this.ctx.service.tenderParam.getParams(lib.id, node.bills_id);
- this._syncCustomData(nodeParams, onp);
- const nodeIndexes = this.indexes.filter(function (i) {
- return i.node_id === node.node_id;
- });
- this.ctx.service.indexCalc.calculate(nodeIndexes, globalParams, nodeParams);
- }
- for (const b of this.bills) {
- delete b.match_key;
- }
- }
- }
- return Match;
- };
|