Selaa lähdekoodia

章节汇总,增加通用配置

MaiXinRong 5 vuotta sitten
vanhempi
commit
580cc3d747
3 muutettua tiedostoa jossa 192 lisäystä ja 39 poistoa
  1. 30 0
      app/const/standard.js
  2. 154 37
      app/lib/rpt_data_analysis.js
  3. 8 2
      app/service/report_memory.js

+ 30 - 0
app/const/standard.js

@@ -0,0 +1,30 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const nodeType = [
+    {text: '', value: 0},
+    {text: '建安费', value: 1},
+    {text: '设备及工(器)具费', value: 2},
+    {text: '工程建设其他费', value: 3},
+    {text: '土地拆迁补偿', value: 4},
+    {text: '预备费', value: 5},
+    {text: '暂列金额', value: 6},
+    {text: '计日工', value: 7},
+    {text: '价差调整', value: 8},
+    {text: '索赔', value: 9},
+    {text: '新增费用', value: 10},
+    {text: '其他费用', value: 11},
+    {text: '回收金额', value: 12},
+    {text: '建设期贷款利息', value: 13},
+];
+
+module.exports = {
+    nodeType,
+};

+ 154 - 37
app/lib/rpt_data_analysis.js

@@ -8,6 +8,8 @@
  * @version
  */
 
+const math = require('mathjs');
+const standard = require('../const/standard');
 const changeSort = {
     name: '变更令排序',
     hint: '默认的变更令排序,同时对变更令,变更清单进行排序\n' +
@@ -19,8 +21,9 @@ const changeSort = {
      * @param ctx - context常量
      * @param data - 全部数据源{Array}
      * @param fieldsKey - 计算字段
+     * @param options - 计算设置
      */
-    fun: function(ctx, data, fieldsKey) {
+    fun: function(ctx, data, fieldsKey, options) {
         if (!data.change) return;
         // 变更令排序
         data.change.sort(function (a, b) {
@@ -51,7 +54,7 @@ const gatherGcl = {
         '  树结构-层级(level), 树结构-同层排序(order), 树结构-完整路径(full_path),\n' +
         '  图册号(drawing_code), 备注(memo), 节点类型(node_type), 总额计量(is_tp)\n' +
         '3. 如需汇总"未计入清单章节项",请勾选"章节编号(chapter)"字段\n',
-    fun: function (ctx, data, fieldsKey) {
+    fun: function (ctx, data, fieldsKey, options) {
         const gatherFields = function(gcl, data, fields) {
             for (const f of fields) {
                 if (data[f]) {
@@ -124,7 +127,7 @@ const sortGcl = {
         '特别的,如有"未计入清单章节项": \n' +
         '  1. 默认"未计入清单章节项"排列在最后\n' +
         '  2. 如须"未计入清单章节项"排在100章之后,请在清单编号字段后,依次勾选"章节编号(chapter)", "名称(name)"\n',
-    fun: function (ctx, data, fieldsKey) {
+    fun: function (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 : '';
@@ -161,46 +164,148 @@ const gatherChapter = {
         'e.g.2 要对mem_stage_bills_compare汇总,须勾选mem_stage_bills_compare下的"清单编号(b_code)", "树结构-是否子项((is_leaf)"字段\n' +
         '结果:\n' +
         '汇总结果可参照 清单汇总--章节合计,但是不过滤1000-1300章数据',
-    fun: function (ctx, data, fieldsKey) {
-        if (!data.tender_info || !data.tender_info.chapter) return;
-        if (!fieldsKey && fieldsKey.length < 0) return;
+    defaultSetting: {
+        count: 9,
+        unChapter: {
+            name: '未计入清单章节合计',
+            order: 1,
+        },
+        gclSum: {
+            name: '清单小计',
+            order: 2,
+        },
+        unGcl: {
+            name: '非清单项费用',
+            order: 3,
+        },
+        sum: {
+            name: '合计',
+            order: 4,
+        }
+    },
+    customSetting1: {
+        count: 7,
+        gclSum: {
+            name: '第100章至700章清单合计',
+            order: 1,
+        },
+        custom: [
+            {name: '已包含在清单合计中的材料、工程设备、专业工程暂估价', order: 2},
+            {name: '清单合计减去材料、工程设备、专业工程暂估价(即8-9=10)', order_calc: 'o1-o2', order: 3},
+            {name: '计日工合计', node_type: '计日工', order: 4},
+            {name: '暂列金额(不含计日工总额)(即10×暂列金额比列)', node_type: '暂列金额', order: 5},
+            {name: '投标报价、台账价(8+11+12)=13', order_calc: 'o1+o4+o5', order: 6},
+        ],
+    },
+    _getCalcChapter: function (chapter, options) {
+        const gclChapter = [], otherChapter = [], customChapter = [];
 
-        const getCalcChapter = function (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 = '^' + 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];
-        };
-        const getGclChapter = function (chapter, data) {
-            for (const c of chapter) {
-                if (c.filter) {
-                    const reg = new RegExp(c.filter);
-                    if (reg.test(data.b_code)) {
-                        return c;
-                    }
+        let serialNo = 1;
+        for (const c of chapter) {
+            const cc = { code: c.code, name: c.name, cType: 1 };
+            cc.serialNo = serialNo++;
+            cc.filter = '^' + c.code.substr(0, c.code.length - 2) + '[0-9]{2}-';
+            gclChapter.push(cc);
+
+            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 });
+        }
+        if (options.gclSum) {
+            otherChapter.push({ name: options.gclSum.name, cType: 11, serialNo: serialNo + options.gclSum.order, order: options.gclSum.order  });
+        }
+        if (options.unGcl) {
+            otherChapter.push({ name: options.unGcl.name, cType: 31, serialNo: serialNo + options.unGcl.order, order: options.unGcl.order  });
+        }
+        if (options.sum) {
+            otherChapter.push({ name: options.sum.name , cType: 41, serialNo: serialNo + options.sum.order, order: options.sum.order  });
+        }
+
+        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,
+                };
+                if (c.node_type && c.node_type !== '') {
+                    const nodeType = standard.nodeType.find(function (x) {return x.text === c.node_type});
+                    cc.node_type = nodeType.value;
                 } else {
+                    cc.node_type = -1;
+                }
+                customChapter.push(cc);
+            }
+        }
+        return [gclChapter, otherChapter, customChapter];
+    },
+    _getGclChapter: function (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;
             }
-        };
-        const gatherData = function(chapter, data) {
+        }
+    },
+    _checkFilter: function (fullPath, filter) {
+        for (const f of filter) {
+            if (fullPath.indexOf(f + '-') === 0 || fullPath === f) return true;
+        }
+        return false;
+    },
+    _orderCalc: function (ctx, chapter, fields) {
+        const orderMatch = new RegExp('o[0-9]+', 'igm');
+        for (const c of chapter) {
+            if (c.order_calc && c.order_calc !== '') {
+                console.log(c.order_calc);
+                const matchs = c.order_calc.match(orderMatch);
+                const calcMatch = [];
+                for (const m of matchs) {
+                    const order = m.substring(1, m.length);
+                    console.log(order);
+                    const orderChapter = chapter.find(function (x) {return x.order == order});
+                    console.log(orderChapter);
+                    if (orderChapter) {
+                        calcMatch.push({match: m, value: orderChapter})
+                    }
+                }
+                console.log(calcMatch);
+                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(math.eval(expr), 6);
+                    } catch(err) {
+                    }
+                }
+            }
+        }
+    },
+    fun: function (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] && (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 [gclChapter, otherChapter] = getCalcChapter(data.tender_info.chapter);
+        const [gclChapter, otherChapter, customChapter] = this._getCalcChapter(data.tender_info.chapter, options ? options : this.defaultSetting);
         const fields = ctx.helper._.map(fieldsKey, 'field');
         const needFields = ['b_code', 'is_leaf'];
         for (const nf of needFields) {
@@ -208,24 +313,36 @@ const gatherChapter = {
         }
         const sourceData = data[fieldsKey[0].table];
         if (!sourceData) return;
+        const filter = [];
         for (const d of sourceData) {
-            if (!d.is_leaf) continue;
+            for (const c of customChapter) {
+                if (c.node_type && c.node_type > 0 && c.node_type === d.node_type) {
+                    gatherData(c, d);
+                    filter.push(d.full_path);
+                }
+            }
+
+            if (!d.is_leaf || this._checkFilter(d.full_path, filter)) 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, fields);
+                    gatherData(c, d);
                 } else if (c.cType === 11 && (d.b_code)) {
-                    gatherData(c, d, fields);
+                    gatherData(c, d);
                 }
             }
             if (d.b_code) {
-                const c = getGclChapter(gclChapter, d);
-                gatherData(c, d, fields);
+                const c = this._getGclChapter(gclChapter, d);
+                gatherData(c, d);
             }
         }
-        data[fieldsKey[0].table] = gclChapter.concat(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;
     },
 };
 

+ 8 - 2
app/service/report_memory.js

@@ -91,7 +91,9 @@ module.exports = app => {
 
         _checkFieldsExist(source, check) {
             for (const s of source) {
-                if (check.indexOf(s)) return true;
+                if (check.indexOf(s) >= 0) {
+                    return true;
+                }
             }
             return false;
         }
@@ -299,6 +301,8 @@ module.exports = app => {
         }
 
         async _calcBillsBgl() {
+            if (!this.ctx.stage) return;
+
             const helper = this.ctx.helper;
             const tender = this.ctx.tender;
             const stage = this.ctx.stage;
@@ -322,7 +326,9 @@ module.exports = app => {
 
         async getStageBillsData(tid, sid, fields) {
             await this.ctx.service.tender.checkTender(tid);
-            await this.ctx.service.stage.checkStage(sid);
+            if (sid) {
+                await this.ctx.service.stage.checkStage(sid);
+            }
 
             const billsData = await this.ctx.service.ledger.getData(this.ctx.tender.id);
             if (this._checkFieldsExist(fields, stageFields)) {