Pārlūkot izejas kodu

指标库,导入数据源,自动根据指标模板匹配全部指标

MaiXinRong 7 gadi atpakaļ
vecāks
revīzija
c7f22b607f

+ 14 - 1
app/base/base_service.js

@@ -127,6 +127,19 @@ class BaseService extends Service {
         return list;
     }
 
-
+    /**
+     * 在事务中写入数据
+     *
+     * @param {Array|Object} datas
+     * @param transaction - 事务
+     * @returns {Promise<void>}
+     */
+    async insertData(data, transaction) {
+        const datas = data instanceof Array ? data : [data];
+        const insertResult = await transaction.insert(this.tableName, datas);
+        if (insertResult.affectedRows !== datas.length) {
+            throw '写入错误';
+        }
+    }
 }
 module.exports = BaseService;

+ 6 - 0
app/public/js/global.js

@@ -87,3 +87,9 @@ const postData = function (url, data, successCallback, errorCallBack) {
         }
     });
 };
+
+GetUrlQueryString = function (name) {
+    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+    var r = window.location.search.substr(1).match(reg);
+    return r ?  unescape(r[2]) : null;
+}

+ 6 - 6
app/public/js/template.js

@@ -127,9 +127,9 @@ $(document).ready(function () {
     $('#nodeMatchCode').blur(function () {
         const self = $(this);
         if (self.val() === self.attr('org-value')) { return; }
-        const path = window.location.pathname.split('/');
+        const nodeId = GetUrlQueryString('id');
         postData('/template/updateNodeMatch', {
-            id: path.length > 2 ? path[2] : 1,
+            id: nodeId ? nodeId : 1,
             match_key: $(this).val(),
         }, function (data) {
             self.attr('org-value', data.match_key);
@@ -146,10 +146,10 @@ $(document).ready(function () {
     $('input[name=paramMatchCode]').blur(function () {
         const self = $(this);
         if (self.val() === self.attr('org-value')) { return; }
-        const path = window.location.pathname.split('/');
+        const nodeId = GetUrlQueryString('id');
         const paramCode = $(this).parent().parent().prev().attr('code');
         postData('/template/updateParamMatch', {
-            node_id: path.length > 2 ? path[2] : 1,
+            node_id: nodeId ? nodeId : 1,
             code: paramCode,
             match_key: $(this).val(),
         }, function (data) {
@@ -165,10 +165,10 @@ $(document).ready(function () {
         const newMatchNum = self.attr('value');
         const oldMatchNum = self.parent().prev().val();
         if (newMatchNum === oldMatchNum) { return; }
-        const path = window.location.pathname.split('/');
+        const nodeId = GetUrlQueryString('id');
         const paramCode = $(this).parent().parent().parent().parent().prev().attr('code');
         postData('/template/updateParamMatch', {
-            node_id: path.length > 2 ? path[2] : 1,
+            node_id: nodeId ? nodeId : 1,
             code: paramCode,
             match_num: newMatchNum,
         }, function (data) {

+ 253 - 0
app/service/match.js

@@ -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;
+}

+ 5 - 1
app/service/quotaLib.js

@@ -123,7 +123,7 @@ module.exports = app => {
          * @param {Object} jsonData - json文件数据
          * @return {Boolean} - 更新结果
          */
-        async batchAdd(postData,jsonData) {
+        async batchAdd(postData, jsonData) {
             const conn = await this.db.beginTransaction(); // 初始化事务
             try{
                 const insertData = {
@@ -145,7 +145,11 @@ module.exports = app => {
                 for(let i = 0; i < billsData.length; i++) {
                     billsData[i] = this.ctx.helper.operationJson(billsData[i],'lib_id',lib_id);
                 }
+                await this.ctx.service.match.matchBills(billsData);
                 const billsResult = await conn.insert('is_quota_bills',billsData);
+                const nodeResult = await this.ctx.service.tenderNode.insertData(this.ctx.service.match.nodes, conn);
+                const indexResult = await this.ctx.service.tenderIndex.insertData(this.ctx.service.match.indexes, conn);
+                const paramResult = await this.ctx.service.tenderParam.insertData(this.ctx.service.match.params, conn);
                 await conn.commit(); // 提交事务
                 return true;
             } catch (err) {

+ 1 - 1
app/service/template_index.js

@@ -1,7 +1,7 @@
 'use strict';
 
 /**
- * 指标节点业务类
+ * 指标模板 -- 指标节点业务类
  *
  * @author Mai
  * @date 2018/4/19

+ 7 - 7
app/service/template_param.js

@@ -37,14 +37,14 @@ module.exports = app => {
                 throw '导入指标参数错误';
             }
         }
-
-        /**
-         * 保存指标节点匹配规则
-         *
-         * @param {Object} data
-         * @returns {Promise<*>}
-         */
         async updateNodeMatch(data, condition) {
+
+            /**
+             * 保存指标节点匹配规则
+             *
+             * @param {Object} data
+             * @returns {Promise<*>}
+             */
             try {
                 if (data.match_key && !this.ctx.helper.validMatchCode(data.match_key)) {
                     throw '用于绑定的分项编号有误'

+ 27 - 0
app/service/tender_index.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class TenderIndex extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_index';
+        }
+
+    };
+
+    return TenderIndex;
+};

+ 27 - 0
app/service/tender_node.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ * 标段 -- 指标节点业务类
+ *
+ * @author Mai
+ * @date 2018/4/25
+ * @version
+ */
+
+module.exports = app => {
+    class TenderNode extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_node';
+        }
+
+    };
+
+    return TenderNode;
+};

+ 26 - 0
app/service/tender_param.js

@@ -0,0 +1,26 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class TenderParam extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_param';
+        }
+    };
+
+    return TenderParam;
+};

+ 3 - 0
app/view/template/index.ejs

@@ -153,6 +153,9 @@
         const loadText = function (arr) {
             for (const a of arr) {
                 a.text = a.code + ' ' + a.name;
+                if (a.match_key) {
+                    a.text = a.text + ' (' + a.match_key + ')';
+                }
                 if (a.children && a.children.length > 0) {
                     loadText(a.children);
                 }