|
@@ -0,0 +1,253 @@
|
|
|
+'use strict';
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * @author Mai
|
|
|
+ * @date 2018/4/25
|
|
|
+ * @version
|
|
|
+ */
|
|
|
+
|
|
|
+const Service = require('egg').Service;
|
|
|
+const paramConst = require('../const/template_param');
|
|
|
+const nodeConst = require('../const/template_node');
|
|
|
+module.exports = app => {
|
|
|
+
|
|
|
+ class Match extends Service {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化匹配所需变量
|
|
|
+ * @param {Array|Object} bills - 导入的清单数据
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _init(bills) {
|
|
|
+ this.bills = bills instanceof Array ? bills : [bills];
|
|
|
+ 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({ template_id: templateId });
|
|
|
+ this.templateIndexes = await this.ctx.service.templateIndex.getAllDataByCondition({ template_id: templateId });
|
|
|
+ this.templateParams = await this.ctx.service.templateParam.getAllDataByCondition({ template_id: templateId });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查code是否满足匹配规则rule
|
|
|
+ * @param {String} code - 匹配编号
|
|
|
+ * @param {String} rule - 匹配规则
|
|
|
+ * @returns {boolean}
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _matchCode(code, rule) {
|
|
|
+ const codeParts = code.split('-');
|
|
|
+ const ruleParts = rule.split('-');
|
|
|
+ const numReg = /(^[0-9]+$)/;
|
|
|
+ if (codeParts.length !== ruleParts.length) { return false; }
|
|
|
+ for (let i = 0, iLen = codeParts.length; i < iLen; i++) {
|
|
|
+ if (numReg.test(ruleParts[i]) && ruleParts[i] !== codeParts[i]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 过滤符合指标节点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._matchCode(b.code, node.match_key);
|
|
|
+ } else {
|
|
|
+ return node.match_key === b.name;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据指标参数取值类别,从清单取值
|
|
|
+ *
|
|
|
+ * @param {Object} param - 指标参数
|
|
|
+ * @param {Object} bills - 清单节点
|
|
|
+ * @returns {number}
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _getNodeBillsValue(param, 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指标参数取值(固定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._matchCode(b.code, param.match_key)) {
|
|
|
+ return this._getNodeBillsValue(param, b);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return undefined;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指标参数取值
|
|
|
+ * @param {Object} param - 指标参数
|
|
|
+ * @param {Object} nodeBills - 指标参数 所属 指标节点,绑定的 清单
|
|
|
+ * @returns {*}
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _getParamValue(param, nodeBills) {
|
|
|
+ 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.code: return this._getCodeParamValue(param);
|
|
|
+ // to do 匹配属性
|
|
|
+ default: return undefined;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步指标节点下的全部指标参数
|
|
|
+ * @param {Number} nodeId
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _syncNodeParam(nodeId, nodeBills) {
|
|
|
+ const nodeParams = this.templateParams.filter(function (p) {
|
|
|
+ return p.node_id === nodeId;
|
|
|
+ });
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 匹配指标节点
|
|
|
+ * @param node
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _matchNode(node) {
|
|
|
+ if (!node) { return; }
|
|
|
+
|
|
|
+ const matchedBills = this._filterBills(node);
|
|
|
+ console.log(matchedBills);
|
|
|
+ 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: node.match_key,
|
|
|
+ bills_id: mb.n_id,
|
|
|
+ }
|
|
|
+ this.nodes.push(newNode);
|
|
|
+ this._syncNodeParam(newNode.source_id, mb);
|
|
|
+ this._syncNodeIndex(newNode);
|
|
|
+ mb.match_node = newNode.node_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param bills
|
|
|
+ * @returns {Promise<void>}
|
|
|
+ */
|
|
|
+ async matchBills (bills) {
|
|
|
+ this._init(bills);
|
|
|
+ // 获取指标模板全部数据
|
|
|
+ await this._getTemplateData(1);
|
|
|
+ // 同步全局指标参数
|
|
|
+ this._syncNodeParam(0, this.bills[0]);
|
|
|
+ // 遍历模板中所有指标节点,匹配清单
|
|
|
+ for (const node of this.templateNodes) {
|
|
|
+ this._matchNode(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return Match;
|
|
|
+}
|