فهرست منبع

Merge branch 'master' of http://192.168.1.41:3000/maixinrong/Calculation

TonyKang 5 سال پیش
والد
کامیت
7f13609a0e
44فایلهای تغییر یافته به همراه813 افزوده شده و 183 حذف شده
  1. 1 1
      app/controller/report_controller.js
  2. 15 50
      app/controller/stage_controller.js
  3. 7 0
      app/extend/helper.js
  4. 117 5
      app/lib/rpt_data_analysis.js
  5. 8 0
      app/public/js/gather_stage.js
  6. 8 0
      app/public/js/gather_tz.js
  7. 27 0
      app/public/js/global.js
  8. 8 0
      app/public/js/ledger_gather.js
  9. 10 8
      app/public/js/material.js
  10. 19 24
      app/public/js/revise.js
  11. 4 0
      app/public/js/se_bonus.js
  12. 4 0
      app/public/js/se_jgcl.js
  13. 4 0
      app/public/js/se_other.js
  14. 0 1
      app/public/js/shares/cs_tools.js
  15. 2 2
      app/public/js/shares/tenders2tree.js
  16. 29 0
      app/public/js/spreadjs_rela/spreadjs_zh.js
  17. 0 1
      app/public/js/stage.js
  18. 12 0
      app/public/js/stage_change.js
  19. 4 0
      app/public/js/stage_pay.js
  20. 1 1
      app/public/report/js/rpt_custom.js
  21. 24 13
      app/service/pos.js
  22. 4 0
      app/service/report.js
  23. 55 0
      app/service/report_memory.js
  24. 1 1
      app/service/revise_bills.js
  25. 43 24
      app/service/revise_pos.js
  26. 3 0
      app/service/rpt_gather_memory.js
  27. 83 14
      app/service/stage.js
  28. 34 1
      app/service/stage_audit.js
  29. 2 2
      app/view/dashboard/index.ejs
  30. 8 0
      app/view/ledger/audit.ejs
  31. 8 0
      app/view/ledger/bwtz.ejs
  32. 8 0
      app/view/ledger/explode.ejs
  33. 7 2
      app/view/report/index.ejs
  34. 2 1
      app/view/report/rpt_print.ejs
  35. 2 1
      app/view/report/rpt_printA3.ejs
  36. 8 0
      app/view/stage/bwtz.ejs
  37. 8 0
      app/view/stage/compare.ejs
  38. 8 0
      app/view/stage/gather.ejs
  39. 8 0
      app/view/stage/index.ejs
  40. 6 6
      app/view/stage/stage_sub_menu.ejs
  41. 1 1
      app/view/stage/stage_sub_mini_menu.ejs
  42. 96 1
      builder_report_index_define.js
  43. 10 1
      sql/update.sql
  44. 104 22
      test/app/lib/rpt_data_analysis.test.js

+ 1 - 1
app/controller/report_controller.js

@@ -7,7 +7,6 @@
 const tenderMenu = require('../../config/menu').tenderMenu;
 const measureType = require('../const/tender').measureType;
 const auditConst = require('../const/audit');
-// const auditConst = require('../const/audit').stage;
 const accountGroup = require('../const/account_group').group;
 const JpcEx = require('../reports/rpt_component/jpc_ex');
 const JV = require('../reports/rpt_component/jpc_value_define');
@@ -159,6 +158,7 @@ module.exports = app => {
                     categoryData,
                     tenderList,
                     auditConst: auditConst.stage,
+                    ledgerAuditConst: auditConst.ledger,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.report.main),
                     customSelects,
                     rptCustomType: reportConst.rptCustomType,

+ 15 - 50
app/controller/stage_controller.js

@@ -411,7 +411,7 @@ module.exports = app => {
                         responseData.data = await ctx.service.stageBills.updateStageBillsCalcType(data.bills.calcType);
                     }
                 }
-                await ctx.service.stage.updateCheckCalcFlag(ctx.stage.id, true);
+                await ctx.service.stage.updateCheckCalcFlag(ctx.stage, true);
                 await ctx.service.stage.updateCacheTime(ctx.stage.id);
                 ctx.body = responseData;
             } catch (err) {
@@ -465,7 +465,7 @@ module.exports = app => {
                     result.change.data = await ctx.service.stageChange.getLastestStageData(ctx.tender.id,
                         ctx.stage.id, data.target.bills.id, '-1');
                 }
-                await ctx.service.stage.updateCheckCalcFlag(ctx.stage.id, true);
+                await ctx.service.stage.updateCheckCalcFlag(ctx.stage, true);
                 await ctx.service.stage.updateCacheTime(ctx.stage.id);
                 ctx.body = {err: 0, msg: '', data: result};
             } catch(err) {
@@ -678,6 +678,15 @@ module.exports = app => {
             }
         }
 
+        async _updateStageCache(ctx, payCalculator) {
+            await ctx.service.stage.update({
+                check_calc: false,
+                contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp,
+                yf_tp: payCalculator.yf.tp,
+                sf_tp: payCalculator.sf.tp
+            }, {id: ctx.stage.id});
+        }
+
         /**
          * 合同支付 (Get)
          * @param ctx
@@ -719,12 +728,7 @@ module.exports = app => {
                     // 计算 本期金额
                     const payCalculator = new PayCalculator(ctx, ctx.stage, ctx.tender.info);
                     await payCalculator.calculateAll(renderData.dealPay);
-                    await this.ctx.service.stage.update({
-                        check_calc: false,
-                        contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp,
-                        yf_tp: payCalculator.yf.tp,
-                        sf_tp: payCalculator.sf.tp
-                    }, {id: this.ctx.stage.id});
+                    await this._updateStageCache(ctx, payCalculator);
                 }
                 await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs');
             } catch (err) {
@@ -759,13 +763,7 @@ module.exports = app => {
                         await ctx.service.pay.del(data.id);
                         responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage);
                         await payCalculator.calculateAll(responseData.data);
-                        await this.ctx.service.stage.update({
-                            check_calc: false,
-                            contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp,
-                            yf_tp: payCalculator.yf.tp,
-                            sf_tp: payCalculator.sf.tp
-                        }, {id: this.ctx.stage.id});
-
+                        await this._updateStageCache(ctx, payCalculator);
                         break;
                     case 'changeOrder':
                         responseData.data = await ctx.service.pay.changeOrder(data.id1, data.id2);
@@ -776,12 +774,7 @@ module.exports = app => {
                         if (bReCalc) {
                             responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage);
                             await payCalculator.calculateAll(responseData.data);
-                            await this.ctx.service.stage.update({
-                                check_calc: false,
-                                contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp,
-                                yf_tp: payCalculator.yf.tp,
-                                sf_tp: payCalculator.sf.tp
-                            }, {id: this.ctx.stage.id});
+                            await this._updateStageCache(ctx, payCalculator);
                         } else {
                             if (data.updateData instanceof Array) {
                                 responseData.data = await ctx.service.stagePay.getStagePay(ctx.stage, this.app._.map(responseData.data, 'id'));
@@ -794,12 +787,7 @@ module.exports = app => {
                         await ctx.service.stagePay.save(data.updateData);
                         responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage);
                         await payCalculator.calculateAll(responseData.data);
-                        await this.ctx.service.stage.update({
-                            check_calc: false,
-                            contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp,
-                            yf_tp: payCalculator.yf.tp,
-                            sf_tp: payCalculator.sf.tp
-                        }, {id: this.ctx.stage.id});
+                        await this._updateStageCache(ctx, payCalculator);
                         break;
                 }
 
@@ -1044,12 +1032,10 @@ module.exports = app => {
                 //     opinion: ctx.request.body.opinion,
                 // };
                 if (!data.checkType || isNaN(data.checkType)) {
-                    console.log('error1');
                     throw '提交数据错误';
                 }
                 if (data.checkType === auditConst.status.checkNo) {
                     if (!data.checkType || isNaN(data.checkType)) {
-                        console.log('error2');
                         throw '提交数据错误';
                     }
                 }
@@ -1078,13 +1064,11 @@ module.exports = app => {
 
                 if (ctx.stage.auditors[ctx.stage.auditors.length - 1].aid === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) {
                     await ctx.service.stageAudit.checkAgain(ctx.stage.id, ctx.stage.times);
-                    console.log('success');
                     ctx.redirect(ctx.request.header.referer);
                 } else {
                     throw '您无权进行该操作';
                 }
             } catch (err) {
-                console.log(err);
                 this.log(err);
                 ctx.session.postError = err.toString();
                 ctx.redirect(ctx.request.header.referer);
@@ -1225,21 +1209,6 @@ module.exports = app => {
         }
 
         /**
-         * 报表
-         * @param ctx
-         * @returns {Promise<void>}
-         */
-        async report(ctx) {
-            try {
-                const renderData = await this._getDefaultRenderData(ctx);
-                await this.layout('stage/report.ejs', renderData, 'stage/report_modal.ejs');
-            } catch (err) {
-                this.log(err);
-                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
-            }
-        }
-
-        /**
          * 上传附件
          * @param {Object} ctx - egg全局变量
          * @return {void}
@@ -1593,10 +1562,6 @@ module.exports = app => {
 
             ctx.body = responseData;
         }
-
-        async differ(ctx) {
-
-        }
     }
 
     return StageController;

+ 7 - 0
app/extend/helper.js

@@ -1020,6 +1020,13 @@ module.exports = {
         return result;
     },
 
+    check18MainCode(code) {
+        return /^([0-9]([0-9][0-9])*)?(GD[0-9]{3}([0-9][0-9])*)?$/.test(code);
+    },
+    check18SubCode(code) {
+        return /^(GD)?G?[A-Z]{2}[A-Z]{0,2}([0-9]{2})+$/.test(code);
+    },
+
     /**
      * 判断是否是移动端访问
      * @param request

+ 117 - 5
app/lib/rpt_data_analysis.js

@@ -417,7 +417,7 @@ const gatherChapter = {
                 }
                 if (rd[rb.key]) {
                     const c = this._getGclChapter(gclChapter, rd, rb.key);
-                    gatherRelaFields(c, rd, rb.fields);
+                    if (c) gatherRelaFields(c, rd, rb.fields);
                 }
             }
         }
@@ -1161,8 +1161,6 @@ const unionPos = {
         if (!options || !options.bills || !options.pos) return;
         const bills = data[options.bills];
         const pos = data[options.pos];
-        console.log(bills.length);
-        console.log(pos.length);
         if (!bills || bills.length === 0 || !pos || pos.length === 0) return;
         const posIndex = new PosIndex({
             id: 'id',
@@ -1175,7 +1173,6 @@ const unionPos = {
             unionData.push(b);
             const posRange = posIndex.getLedgerPos(b.id);
             b.posCount = posRange ? posRange.length : 0;
-            console.log(b.id + '-posCount: ' + b.posCount);
             if (!posRange || posRange.length === 0) continue;
 
             for (const p of posRange) {
@@ -1184,7 +1181,121 @@ const unionPos = {
         }
         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: function (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: function (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;
+            });
+        } else {
+            return null;
+        }
+    },
+    // 18标准
+    _split18Std: function (data, options, helper) {
+        const types = options.type.split('-');
+        const isSplitSub = types[1] && types[1] === '1' ? true : false;
+        const isKeepGD = types[2] && types[2] === '1' ? true : false;
+        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: function (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: function (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 analysisObj = {
     changeSort,
@@ -1202,6 +1313,7 @@ const analysisObj = {
     gatherSelectConverse,
     sortPos,
     unionPos,
+    splitXmjCode,
 };
 const analysisDefine = (function (obj) {
     const result = [];

+ 8 - 0
app/public/js/gather_stage.js

@@ -61,6 +61,10 @@ $(document).ready(function () {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'spss-gather-stage-bills',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             function checkDiffer(data) {
                 return !checkZero(data.qty_differ) && !checkZero(data.tp_differ);
@@ -82,6 +86,10 @@ $(document).ready(function () {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'spss-gather-stage-bills',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             function checkDiffer(data) {
                 const fieldSufs = sheet.zh_setting.fieldSufs;

+ 8 - 0
app/public/js/gather_tz.js

@@ -61,6 +61,10 @@ $(document).ready(function () {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'spss-gather-tz-bills',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             function checkDiffer(data) {
                 return !checkZero(data.qty_differ) && !checkZero(data.tp_differ);
@@ -82,6 +86,10 @@ $(document).ready(function () {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'spss-gather-tz-pos',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             function checkDiffer(data) {
                 const fieldSufs = sheet.zh_setting.fieldSufs;

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

@@ -802,3 +802,30 @@ jQuery.bootstrapLoading = {
         $("#progressModal").modal('hide');
     }
 };
+// 光标插入button内容
+$.fn.extend({
+    insertAtCaret: function(myValue){
+        var $t=$(this)[0];
+        if (document.selection) {
+            this.focus();
+            sel = document.selection.createRange();
+            sel.text = myValue;
+            this.focus();
+        }
+        else
+        if ($t.selectionStart || $t.selectionStart == '0') {
+            var startPos = $t.selectionStart;
+            var endPos = $t.selectionEnd;
+            var scrollTop = $t.scrollTop;
+            $t.value = $t.value.substring(0, startPos) + myValue + $t.value.substring(endPos, $t.value.length);
+            this.focus();
+            $t.selectionStart = startPos + myValue.length;
+            $t.selectionEnd = startPos + myValue.length;
+            $t.scrollTop = scrollTop;
+        }
+        else {
+            this.value += myValue;
+            this.focus();
+        }
+    }
+});

+ 8 - 0
app/public/js/ledger_gather.js

@@ -31,6 +31,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'ledger-gather-gcl',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             return data 
                 ? $('#compare-tag')[0].checked && data.compare_differ 
@@ -60,6 +64,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'ledger-gather-leafXmj',
+            colWidth: true,
+        },
     });
     const leafXmjSheet = leafXmjSpread.getActiveSheet();
 

+ 10 - 8
app/public/js/material.js

@@ -114,7 +114,7 @@ $(document).ready(() => {
             {title: '本期材料调差|上涨幅度(%)', colSpan: '4|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.isEdit'},
             {title: '|下跌幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.isEdit'},
             {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
-            {title: '|调金额', colSpan: '|1', rowSpan: '1|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
+            {title: '|调金额', colSpan: '|1', rowSpan: '1|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
             {title: '截止上期调差金额', colSpan: '1', rowSpan: '2', field: 'pre_tp', hAlign: 2, width: 120, type: 'Number', readOnly: true},
             {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.remark'},
         ],
@@ -545,7 +545,8 @@ $(document).ready(() => {
 
         $('#expr_select button').on('click', function () {
             const code = $(this).text();
-            $('#expr').val($('#expr').val() + code);
+            // $('#expr').val($('#expr').val() + code);
+            $('#expr').insertAtCaret(code);
         });
 
         const ExprObj = {
@@ -563,13 +564,13 @@ $(document).ready(() => {
                     } else if (/^[a-z]/.test(expr[i])) {
                         if (num !== '') {
                             param.push({type: 'num', value: num});
-                            base = '';
+                            num = '';
                         }
                         base = base + expr[i];
                     } else if (expr[i] === '(') {
                         if (num !== '') {
                             param.push({type: 'num', value: num});
-                            base = '';
+                            num = '';
                         }
                         if (base !== '') {
                             param.push({type: 'base', value: base});
@@ -579,7 +580,7 @@ $(document).ready(() => {
                     } else if (expr[i] === ')') {
                         if (num !== '') {
                             param.push({type: 'num', value: num});
-                            base = '';
+                            num = '';
                         }
                         if (base !== '') {
                             param.push({type: 'base', value: base});
@@ -589,7 +590,7 @@ $(document).ready(() => {
                     } else if (/^[\+\-*\/]/.test(expr[i])) {
                         if (num !== '') {
                             param.push({type: 'num', value: num});
-                            base = '';
+                            num = '';
                         }
                         if (base !== '') {
                             param.push({type: 'base', value: base});
@@ -602,7 +603,7 @@ $(document).ready(() => {
                 }
                 if (num !== '') {
                     param.push({type: 'num', value: num});
-                    base = '';
+                    num = '';
                 }
                 if (base !== '') {
                     param.push({type: 'base', value: base});
@@ -643,7 +644,7 @@ $(document).ready(() => {
                             return [false, '输入的表达式非法:不存在计算基数' + p.value];
                         if (invalidParam && invalidParam.indexOf(p.value) >= 0)
                             return [false, '不可使用计算基数' + p.value];
-                        if (i > 0 && param[i - 1].type === 'calc')
+                        if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
                             return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
                     }
                     if (p.type === 'left') {
@@ -684,6 +685,7 @@ $(document).ready(() => {
             const [valid, msg] = ExprObj._checkExpr(expr);
             if (!valid) {
                 toastr.error(msg);
+                return false;
             }
             postData(window.location.pathname + '/save', { type:'expr', id: $('#materialbillsId').val(), expr: expr }, function (result) {
                 m_tp = result.m_tp;

+ 19 - 24
app/public/js/revise.js

@@ -140,12 +140,12 @@ $(document).ready(() => {
                 }
             };
             const invalidAll = function () {
-                setObjEnable($('a[nam=base-opr][type=add]'), false);
-                setObjEnable($('a[nam=base-opr][type=delete]'), false);
-                setObjEnable($('a[nam=base-opr][type=up-move]'), false);
-                setObjEnable($('a[nam=base-opr][type=down-move]'), false);
-                setObjEnable($('a[nam=base-opr][type=up-level]'), false);
-                setObjEnable($('a[nam=base-opr][type=down-level]'), false);
+                setObjEnable($('a[name=base-opr][type=add]'), false);
+                setObjEnable($('a[name=base-opr][type=delete]'), false);
+                setObjEnable($('a[name=base-opr][type=up-move]'), false);
+                setObjEnable($('a[name=base-opr][type=down-move]'), false);
+                setObjEnable($('a[name=base-opr][type=up-level]'), false);
+                setObjEnable($('a[name=base-opr][type=down-level]'), false);
             };
             const sel = selection ? selection[0] : sheet.getSelections()[0];
             const row = sel ? sel.row : -1;
@@ -179,21 +179,16 @@ $(document).ready(() => {
             const preNode = tree.getPreSiblingNode(first);
             const valid = !sheet.zh_setting.readOnly;
 
-            setObjEnable($('a[nam=base-opr][type=add]'), valid && first && first.level > 1);
-            setObjEnable($('a[nam=base-opr][type=delete]'), valid && first && sameParent && first.level > 1 && !nodeUsed);
-            setObjEnable($('a[nam=base-opr][type=up-move]'), valid && first && sameParent && first.level > 1 && preNode);
-            setObjEnable($('a[nam=base-opr][type=down-move]'), valid && first && sameParent && first.level > 1 && !tree.isLastSibling(last));
-            if (isTz) {
-                const posRange = last ? pos.getLedgerPos(last.id) : [];
-                setObjEnable($('a[nam=base-opr][type=up-level]'), valid && first && sameParent && tree.getParent(first) && !nodeUsed
-                    && first.level > 2 && ((!posRange || posRange.length === 0) || tree.isLastSibling(last)));
-                const preNodePosRange = preNode ? pos.getLedgerPos(preNode.id) : [];
-                setObjEnable($('a[nam=base-opr][type=down-level]'), valid && first && sameParent && !nodeUsed
-                    && first.level > 1 && preNode && (!preNodePosRange || preNodePosRange.length === 0));
-            } else {
-                setObjEnable($('a[nam=base-opr][type=up-level]'), valid && first && sameParent && first.level > 2 && tree.getParent(first));
-                setObjEnable($('a[nam=base-opr][type=down-level]'), valid && first && sameParent && first.level > 1 && preNode);
-            }
+            setObjEnable($('a[name=base-opr][type=add]'), valid && first && first.level > 1);
+            setObjEnable($('a[name=base-opr][type=delete]'), valid && first && sameParent && first.level > 1 && !nodeUsed);
+            setObjEnable($('a[name=base-opr][type=up-move]'), valid && first && sameParent && first.level > 1 && preNode);
+            setObjEnable($('a[name=base-opr][type=down-move]'), valid && first && sameParent && first.level > 1 && !tree.isLastSibling(last));
+            const posRange = last ? pos.getLedgerPos(last.id) : [];
+            setObjEnable($('a[name=base-opr][type=up-level]'), valid && first && sameParent && tree.getParent(first) && !nodeUsed
+                && first.level > 2 && ((!posRange || posRange.length === 0) || tree.isLastSibling(last)));
+            const preNodePosRange = preNode ? pos.getLedgerPos(preNode.id) : [];
+            setObjEnable($('a[name=base-opr][type=down-level]'), valid && first && sameParent
+                && first.level > 1 && preNode && (!preNodePosRange || preNodePosRange.length === 0) && !preNode.used);
             setObjEnable($('#cut'), valid);
             setObjEnable($('#paste'), valid);
         },
@@ -680,7 +675,7 @@ $(document).ready(() => {
                 postData(window.location.pathname + '/update', {postType: 'update', postData: datas}, function (result) {
                     const refreshNode = sheet.zh_tree.loadPostData(result);
                     billsTreeSpreadObj.refreshTree(sheet, refreshNode);
-                    treeOperationObj.loadExprToInput(sheet);
+                    billsTreeSpreadObj.loadExprToInput(sheet);
                 });
             }
         },
@@ -1279,7 +1274,7 @@ $(document).ready(() => {
                             data.postData[col.field] = math.evaluate(transExpr(newText));
                             const exprInfo = getExprInfo(col.field);
                             if (exprInfo) {
-                                data.updateData[exprInfo.expr] = newText;
+                                data.postData[exprInfo.expr] = newText;
                             }
                         } catch(err) {
                             toastr.error('输入的表达式非法');
@@ -1311,7 +1306,7 @@ $(document).ready(() => {
          * @param sheet
          */
         deletePress: function (sheet) {
-            if (!sheet.zh_settting) return;
+            if (!sheet.zh_setting) return;
 
             const sortData = sheet.zh_data;
             const datas = [], posSelects = [];

+ 4 - 0
app/public/js/se_bonus.js

@@ -55,6 +55,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: readOnly,
+        localCache: {
+            key: 'stage-extra-bonus',
+            colWidth: true,
+        },
         imageClick: function (data, hitinfo) {
             if (!data) return;
 

+ 4 - 0
app/public/js/se_jgcl.js

@@ -35,6 +35,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: readOnly,
+        localCache: {
+            key: 'stage-extra-jgcl',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             if (data) {
                 if (data.end_deduct_tp) {

+ 4 - 0
app/public/js/se_other.js

@@ -36,6 +36,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: readOnly,
+        localCache: {
+            key: 'stage-extra-other',
+            colWidth: true,
+        },
         getColor: function (sheet, data, row, col, defaultColor) {
             if (data) {
                 if (data.total_price) {

+ 0 - 1
app/public/js/shares/cs_tools.js

@@ -105,7 +105,6 @@ const showSideTools = function (show) {
                 if (!curBills) { return }
 
                 SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), curBills.ledger_id, true);
-                console.log(curBills);
                 if (setting.afterLocated) {
                     setting.afterLocated();
                 }

+ 2 - 2
app/public/js/shares/tenders2tree.js

@@ -72,7 +72,7 @@ const Tender2Tree = (function () {
         return tenderCategory;
     }
 
-    function convert (category, tenders) {
+    function convert (category, tenders, ledgerAuditConst, stageAuditConst) {
         tenderTree.clearDatas();
 
         const levelCategory = category.filter(function (c) {
@@ -85,7 +85,7 @@ const Tender2Tree = (function () {
                 tid: t.id,
                 name: t.name,
                 phase: t.lastStage ? '第' + t.lastStage.order + '期' : '台账',
-                status: t.lastStage ? auditConst.stage.statusString[t.lastStage.status] : auditConst.ledger.statusString[t.ledger_status]
+                status: t.lastStage ? stageAuditConst.statusString[t.lastStage.status] : ledgerAuditConst.statusString[t.ledger_status]
             }, parent);
         }
         tenderTree.sortTreeNode(false);

+ 29 - 0
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -341,6 +341,34 @@ const SpreadJsObj = {
         this._initSheetHeader(sheet);
         this.endMassOperation(sheet);
     },
+    _rememberColWidth: function (sheet) {
+        sheet.bind(spreadNS.Events.ColumnWidthChanged, function (e, info) {
+            if (!info.sheet.zh_setting) return;
+            const setting = info.sheet.zh_setting;
+            if (!setting.localCache || !setting.localCache.key) return;
+            if (!setting.localCache.colWidthCache) return;
+            const cache = setting.localCache.colWidthCache;
+
+            for (const col of info.colList) {
+                const colSetting = setting.cols[col];
+                if (colSetting && colSetting.field)
+                    cache[colSetting.field] = info.sheet.getColumnWidth(col);
+            }
+            setLocalCache(setting.localCache.key + '-colWidth', JSON.stringify(cache));
+        });
+    },
+    _loadCacheSetting: function (sheet, setting) {
+        if (!setting.localCache || !setting.localCache.key) return;
+        if (setting.localCache.colWidth) {
+            const cache = getLocalCache(setting.localCache.key + '-colWidth');
+            setting.localCache.colWidthCache = cache ? JSON.parse(cache) : {};
+            for (const prop in setting.localCache.colWidthCache) {
+                const col = _.find(setting.cols, {field: prop});
+                if (col) col.width = setting.localCache.colWidthCache[prop];
+            }
+            this._rememberColWidth(sheet);
+        }
+    },
     /**
      * 初始化sheet, 设置sheet.zh_setting, 并初始化表头
      * @param {GC.Spread.Sheets.Worksheet} sheet
@@ -348,6 +376,7 @@ const SpreadJsObj = {
      */
     initSheet: function (sheet, setting) {
         this.beginMassOperation(sheet);
+        this._loadCacheSetting(sheet, setting);
         setting.pos = sheet.getParent().pos;
         if (!setting.tree) setting.tree = {};
         sheet.zh_setting = setting;

+ 0 - 1
app/public/js/stage.js

@@ -2716,7 +2716,6 @@ $(document).ready(() => {
         analyzeChange(change) {
             change.bills = change.detail.bills;
             for (const b of change.bills) {
-                console.log(b);
                 const aub = change.detail.addUsedBills.find(function (x) {
                     return x.id === b.id;
                 });

+ 12 - 0
app/public/js/stage_change.js

@@ -83,6 +83,10 @@ $(document).ready(() => {
         defaultRowHeight: 21,
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
+        localCache: {
+            key: 'stage-change',
+            colWidth: true,
+        }
     };
     const changeSpread = SpreadJsObj.createNewSpread($('#bgl-spread')[0]);
     SpreadJsObj.initSheet(changeSpread.getActiveSheet(), changeSpreadSetting);
@@ -112,6 +116,10 @@ $(document).ready(() => {
         defaultRowHeight: 21,
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
+        localCache: {
+            key: 'stage-change-bills',
+            colWidth: true,
+        }
     };
     const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
     SpreadJsObj.initSheet(billsSpread.getActiveSheet(), billsSpreadSetting);
@@ -130,6 +138,10 @@ $(document).ready(() => {
         defaultRowHeight: 21,
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
+        localCache: {
+            key: 'stage-change-pos',
+            colWidth: true,
+        }
     };
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
     SpreadJsObj.initSheet(posSpread.getActiveSheet(), posSpreadSetting);

+ 4 - 0
app/public/js/stage_pay.js

@@ -148,6 +148,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: readOnly,
+        localCache: {
+            key: 'stage-pay',
+            colWidth: true,
+        },
         pos: SpreadJsObj.getObjPos($('#pay-spread')[0]),
     };
     paySpreadSetting.imageClick = function (data) {

+ 1 - 1
app/public/report/js/rpt_custom.js

@@ -435,7 +435,7 @@ const rptCustomObj = (function () {
             selectedBackColor: '#fffacd',
         };
         SpreadJsObj.initSheet(gsObj.gsSheet, spreadSetting);
-        gsObj.tenderSourceTree = Tender2Tree.convert(category, tenders);
+        gsObj.tenderSourceTree = Tender2Tree.convert(category, tenders, ledgerAuditConst, auditConst);
         SpreadJsObj.loadSheetData(gsObj.gsSheet, SpreadJsObj.DataType.Tree, gsObj.tenderSourceTree);
         gsSpread.bind(spreadNS.Events.ButtonClicked, gatherSelectSpreadObj.gsButtonClicked);
 

+ 24 - 13
app/service/pos.js

@@ -234,6 +234,7 @@ module.exports = app => {
             const bills = await this.ctx.service.ledger.getDataById(op.lid);
             const billsPos = await this.getAllDataByCondition({where: {tid: tid, lid: op.lid} });
             const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            let needUpdateBills;
             for (const d of data) {
                 if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
                     if (d.sgfh_qty !== undefined) {
@@ -252,29 +253,39 @@ module.exports = app => {
                         d.qtcl_qty = op.qtcl_qty;
                     }
                     d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
+                    needUpdateBills = true;
                 }
             }
             const updateBills = {id: bills.id};
-            for (const bp of billsPos) {
-                const newPos = data.find(function (x) { return x.id === bp.id });
-                const calcData = newPos ? newPos : bp;
-                updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, calcData.sgfh_qty);
-                updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, calcData.sjcl_qty);
-                updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, calcData.qtcl_qty);
-                updateBills.quantity = this.ctx.helper.add(updateBills.quantity, calcData.quantity);
+            if (needUpdateBills) {
+                for (const bp of billsPos) {
+                    const newPos = data.find(function (x) { return x.id === bp.id });
+                    updateBills.sgfh_qty = newPos && newPos.sgfh_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sgfh_qty, newPos.sgfh_qty)
+                        : this.ctx.helper.add(updateBills.sgfh_qty, bp.sgfh_qty);
+                    updateBills.sjcl_qty = newPos && newPos.sjcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sjcl_qty, newPos.sjcl_qty)
+                        : this.ctx.helper.add(updateBills.sjcl_qty, bp.sjcl_qty);
+                    updateBills.qtcl_qty = newPos && newPos.qtcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.qtcl_qty, newPos.qtcl_qty)
+                        : this.ctx.helper.add(updateBills.qtcl_qty, bp.qtcl_qty);
+                    updateBills.quantity = newPos && newPos.quantity !== undefined
+                        ? this.ctx.helper.add(updateBills.quantity, newPos.quantity)
+                        : this.ctx.helper.add(updateBills.quantity, bp.quantity);
+                }
+                const info = this.ctx.tender.info;
+                updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
             }
-            const info = this.ctx.tender.info;
-            updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
-            updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
-            updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
-            updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
 
             const transaction = await this.db.beginTransaction();
             try {
                 for (const d of data) {
                     transaction.update(this.tableName, d);
                 }
-                await transaction.update(this.ctx.service.ledger.tableName, updateBills);
+                if (needUpdateBills) await transaction.update(this.ctx.service.ledger.tableName, updateBills);
                 await transaction.commit();
                 updateBills.ledger_id = bills.ledger_id;
                 return {

+ 4 - 0
app/service/report.js

@@ -148,6 +148,10 @@ module.exports = app => {
                             runnableRst.push(service.rptGatherMemory.getMaterialGl(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
+                        case 'mem_sum_stage_bills':
+                            runnableRst.push(service.rptGatherMemory.getSumStageBillsData(params.tender_id, memFieldKeys[filter]));
+                            runnableKey.push(filter);
+                            break;
                         default:
                             break;
                     }

+ 55 - 0
app/service/report_memory.js

@@ -867,6 +867,61 @@ module.exports = app => {
                 return [];
             }
         }
+
+        async getSumStageBillsData(tid, sid, fields) {
+            await this.ctx.service.tender.checkTender(tid);
+
+            const billsData = await this.ctx.service.ledger.getData(this.ctx.tender.id);
+            const checkStageField = function (stageOrder) {
+                for (const f of fields) {
+                    if (f.indexOf('s' + stageOrder + '_') >= 0) {
+                        return true;
+                    }
+                }
+                return false;
+            };
+
+            const calcFields = ['deal_tp', 'total_price'], calcPrefix = [];
+            const stages = this.ctx.service.stage.getValidStages(this.ctx.tender.id);
+            for (const stage of stages) {
+                if (!checkStageField(stage.order)) return;
+
+                await this.ctx.service.stage.doCheckStage(stage);
+                calcFields.push('s' + stageOrder + '_contract_tp');
+                calcFields.push('s' + stageOrder + '_qc_tp');
+                calcFields.push('s' + stageOrder + '_gather_tp');
+                calcFields.push('s' + stageOrder + '_');
+
+                const curStage = stage.readOnly
+                    ? await this.ctx.service.stageBills.getAuditorStageData(this.ctx.tender.id, stage.id, stage.curTimes, stage.curOrder)
+                    : await this.ctx.service.stageBills.getLastestStageData(this.ctx.tender.id, stage.id);
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp'], prefix: 's' + stage.order + '_', relaId: 'lid'}
+                ]);
+            }
+
+            const billsTree = new Ledger.billsTree(this.ctx, {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                keys: ['id', 'tender_id', 'ledger_id'],
+                stageId: 'id',
+                calcFields: calcFields,
+                calc: function (node) {
+                    for (const prefix of calcPrefix) {
+                        if (node.children && node.children.length === 0) {
+                            node[prefix + 'gather_qty'] = self.ctx.helper.add(node[prefix + 'contract_qty'], node[prefix + 'qc_qty']);
+                        }
+                        node[prefix + 'gather_tp'] = self.ctx.helper.add(node[prefix + 'contract_tp'], node[prefix + 'qc_tp']);
+                    }
+                }
+            });
+            billsTree.loadDatas(billsData);
+            billsTree.calculateAll();
+            return billsTree.getDefaultDatas();
+        }
     }
 
     return ReportMemory;

+ 1 - 1
app/service/revise_bills.js

@@ -132,7 +132,7 @@ module.exports = app => {
                 this._cacheMaxLid(tid, maxId + data.length);
                 await this.transaction.commit();
             } catch (err) {
-                await this.transaction.rollback();console.log(lastChild);
+                await this.transaction.rollback();
                 throw err;
             }
 

+ 43 - 24
app/service/revise_pos.js

@@ -181,11 +181,13 @@ module.exports = app => {
         }
 
         async updatePosArr(tid, data) {
+            console.log(data);
             if (data.length === 0) return;
             const op = await this.getDataById(data[0].id);
             const bills = await this.ctx.service.reviseBills.getDataById(op.lid);
             const billsPos = await this.getAllDataByCondition({where: {tid: tid, lid: op.lid} });
             const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            let needUpdateBills;
             for (const d of data) {
                 if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
                     if (d.sgfh_qty !== undefined) {
@@ -204,33 +206,43 @@ module.exports = app => {
                         d.qtcl_qty = op.qtcl_qty;
                     }
                     d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
+                    needUpdateBills = true;
                 }
             }
             const updateBills = {id: bills.id};
-            for (const bp of billsPos) {
-                const newPos = data.find(function (x) { return x.id === bp.id });
-                const calcData = newPos ? newPos : bp;
-                updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, calcData.sgfh_qty);
-                updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, calcData.sjcl_qty);
-                updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, calcData.qtcl_qty);
-                updateBills.quantity = this.ctx.helper.add(updateBills.quantity, calcData.quantity);
+            if (needUpdateBills) {
+                for (const bp of billsPos) {
+                    const newPos = data.find(function (x) { return x.id === bp.id });
+                    updateBills.sgfh_qty = newPos && newPos.sgfh_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sgfh_qty, newPos.sgfh_qty)
+                        : this.ctx.helper.add(updateBills.sgfh_qty, bp.sgfh_qty);
+                    updateBills.sjcl_qty = newPos && newPos.sjcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sjcl_qty, newPos.sjcl_qty)
+                        : this.ctx.helper.add(updateBills.sjcl_qty, bp.sjcl_qty);
+                    updateBills.qtcl_qty = newPos && newPos.qtcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.qtcl_qty, newPos.qtcl_qty)
+                        : this.ctx.helper.add(updateBills.qtcl_qty, bp.qtcl_qty);
+                    updateBills.quantity = newPos && newPos.quantity !== undefined
+                        ? this.ctx.helper.add(updateBills.quantity, newPos.quantity)
+                        : this.ctx.helper.add(updateBills.quantity, bp.quantity);
+                }
+                const info = this.ctx.tender.info;
+                updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
             }
-            const info = this.ctx.tender.info;
-            updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
-            updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
-            updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
-            updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
 
             const transaction = await this.db.beginTransaction();
             try {
                 for (const d of data) {
-                    transaction.update(this.tableName, d);
+                    await transaction.update(this.tableName, d);
                 }
-                transaction.update(this.ctx.service.reviseBills.tableName, updateBills);
+                if (needUpdateBills) await transaction.update(this.ctx.service.reviseBills.tableName, updateBills);
                 await transaction.commit();
                 updateBills.ledger_id = bills.ledger_id;
                 return {
-                    ledger: { update: [updateBills] },
+                    ledger: { update: needUpdateBills ? [updateBills] : [] },
                     pos: data,
                 }
             } catch(err) {
@@ -267,7 +279,10 @@ module.exports = app => {
                 await transaction.update(this.ctx.service.reviseBills.tableName, updateBills);
                 await transaction.commit();
                 updateBills.ledger_id = bills.ledger_id;
-                return { ledger: { update: [updateBills] }, pos: data };
+                return {
+                    ledger: { update: [updateBills] },
+                    pos: data
+                };
             } catch(err) {
                 await transaction.rollback();
                 throw err;
@@ -291,6 +306,7 @@ module.exports = app => {
             const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
             const updateBills = {id: bills.id};
             const billsPos = await this.getAllDataByCondition({where: {tid: tid, lid: bills.id} });
+            let needUpdateBills;
             for (const bp of billsPos) {
                 const d = data.find(function (x) {
                     return bp.id ? x.id === bp.id : false;
@@ -305,7 +321,7 @@ module.exports = app => {
             try {
                 for (const d of data) {
                     const op = d.id ? this._.find(orgPos, {id: d.id}) : null;
-                    if (d.sgfh_qty || d.sjcl_qty || d.qtcl_qty) {
+                    if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
                         if (d.sgfh_qty !== undefined) {
                             d.sgfh_qty = this.round(d.sgfh_qty, precision.value);
                         } else if (op) {
@@ -326,6 +342,7 @@ module.exports = app => {
                         updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, d.qtcl_qty);
                         d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
                         updateBills.quantity = this.ctx.helper.add(updateBills.quantity, d.quantity);
+                        needUpdateBills = true;
                     }
                     if (d.id) {
                         await transaction.update(this.tableName, d);
@@ -334,19 +351,21 @@ module.exports = app => {
                     }
                 }
                 const info = this.ctx.tender.info;
-                updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
-                updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
-                updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
-                updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
-                await transaction.update(this.ctx.service.reviseBills.tableName, updateBills);
-                updateBills.ledger_id = bills.ledger_id;
+                if (needUpdateBills) {
+                    updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
+                    await transaction.update(this.ctx.service.reviseBills.tableName, updateBills);
+                    updateBills.ledger_id = bills.ledger_id;
+                }
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
                 throw err;
             }
             result.pos = data;
-            result.ledger.update = [updateBills];
+            result.ledger.update = needUpdateBills ? [updateBills] : [];
             return result;
         }
     }

+ 3 - 0
app/service/rpt_gather_memory.js

@@ -117,6 +117,9 @@ const gatherUtils = {
     gatherSpecial: function (gatherNode, sourceNode, prefix, helper) {
         gatherNode[prefix + "qty"] = helper.add(gatherNode[prefix + "qty"], sourceNode.quantity);
         gatherNode[prefix + "tp"] = helper.add(gatherNode[prefix + "tp"], sourceNode.total_price);
+
+        gatherNode[prefix + "dgn_qty1"] = helper.add(gatherNode[prefix + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode[prefix + "dgn_qty2"] = helper.add(gatherNode[prefix + "dgn_qty2"], sourceNode.dgn_qty2);
     },
 };
 

+ 83 - 14
app/service/stage.js

@@ -28,6 +28,46 @@ module.exports = app => {
             this.tableName = 'stage';
         }
 
+        /**
+         * 根据id查找数据
+         *
+         * @param {Number} id - 数据库中的id
+         * @return {Object} - 返回单条数据
+         */
+        async getDataById(id) {
+            const result = await this.db.get(this.tableName, { id });
+            if (result)
+                result.tp_history = result.tp_history ? JSON.parse(result.tp_history) : [];
+            return result;
+        }
+
+        /**
+         * 根据条件查找单条数据
+         *
+         * @param {Object} condition - 筛选条件
+         * @return {Object} - 返回单条数据
+         */
+        async getDataByCondition(condition) {
+            const result = await this.db.get(this.tableName, condition);
+            if (result)
+                result.tp_history = result.tp_history ? JSON.parse(result.tp_history) : [];
+            return result;
+        }
+
+        /**
+         * 根据条件查找列表数据
+         *
+         * @param {Object} condition - 筛选条件
+         * @return {Array} - 返回数据
+         */
+        async getAllDataByCondition(condition) {
+            const result = await this.db.select(this.tableName, condition);
+            for (const r of result) {
+                r.tp_history = r.tp_history ? JSON.parse(r.tp_history) : [];
+            }
+            return result;
+        }
+
         async doCheckStage(stage) {
             const status = auditConst.status;
             stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times);
@@ -119,6 +159,7 @@ module.exports = app => {
             this.sqlBuilder.orderBy = [['order', 'desc']];
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
             const stage = await this.db.queryOne(sql, sqlParam);
+            if (stage) stage.tp_history = stage.tp_history ? JSON.parse(stage.tp_history) : [];
             return stage;
         }
 
@@ -140,6 +181,7 @@ module.exports = app => {
             this.sqlBuilder.orderBy = [['order', 'desc']];
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
             const stage = await this.db.queryOne(sql, sqlParam);
+            if (stage) stage.tp_history = stage.tp_history ? JSON.parse(stage.tp_history) : [];
             return stage;
         }
 
@@ -167,18 +209,30 @@ module.exports = app => {
 
         async checkStageGatherData(stage) {
             // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
-            if (stage.status !== auditConst.status.checked && stage.check_calc) {
-                const curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
-                const isActive = curAuditor ? curAuditor.aid === this.ctx.session.sessionUser.accountId : stage.user_id === this.ctx.session.sessionUser.accountId;
-                stage.curTimes = stage.status === auditConst.status.checkNo ? stage.times - 1 : stage.times;
-                stage.curOrder = curAuditor ? curAuditor.order : 0;
-                if (isActive) {
+            if (stage.status !== auditConst.status.checked) {
+                await this.doCheckStage(stage);
+                if (!stage.readOnly && stage.check_calc) {
                     const tpData = await this.ctx.service.stageBills.getSumTotalPrice(stage);
                     stage.contract_tp = tpData.contract_tp;
                     stage.qc_tp = tpData.qc_tp;
                     const tp = await this.ctx.service.stagePay.getSpecialTotalPrice(stage);
                     stage.yf_tp = tp.yf;
                     stage.sf_tp = tp.sf;
+                    await this.update({
+                        check_calc: false,
+                        contract_tp: stage.contract_tp, qc_tp: stage.qc_tp,
+                        yf_tp: stage.yf_tp, sf_tp: stage.sf_tp
+                    }, {id: stage.id});
+                } else if (stage.tp_history) {
+                    const his = this.ctx.helper._.find(stage.tp_history, {times: stage.curTimes, order: stage.curOrder});
+                    console.log(his);
+                    if (his) {
+                        stage.contract_tp = his.contract_tp;
+                        stage.qc_tp = his.qc_tp;
+                        stage.yf_tp = his.yf_tp;
+                        stage.sf_tp = his.sf_tp;
+                        stage.tp = this.ctx.helper.add(stage.contract_tp, stage.qc_tp);
+                    }
                 }
             }
         }
@@ -197,15 +251,18 @@ module.exports = app => {
                 s.tp = this.ctx.helper.add(s.contract_tp, s.qc_tp);
                 s.pre_tp = this.ctx.helper.add(s.pre_contract_tp, s.pre_qc_tp);
                 s.end_tp = this.ctx.helper.add(s.pre_tp, s.tp);
+                s.tp_history = s.tp_history ? JSON.parse(s.tp_history) : [];
             }
             if (stages.length !== 0) {
-                const lastStage = stages[stages.length - 1];
+                const lastStage = stages[0];
                 if (lastStage.status === auditConst.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
-                    stages.splice(stages.length - 1, 1);
+                    stages.splice(0, 1);
                 }
             }
             // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
-            if (stages.length > 0 && stages[0].status !== auditConst.status.checked) {
+            if (stages.length === 0) return stages;
+
+            if (stages[0].status !== auditConst.status.checked) {
                 const stage = stages[0];
                 await this.doCheckStage(stage);
                 if (!stage.readOnly) {
@@ -217,6 +274,16 @@ module.exports = app => {
                     stage.sf_tp = tp.sf;
                     stage.tp = this.ctx.helper.add(stage.contract_tp, stage.qc_tp);
                     stage.end_tp = this.ctx.helper.add(stage.pre_tp, stage.tp);
+                } else {
+                    const his = this.ctx.helper._.find(stage.tp_history, {times: stage.curTimes, order: stage.curOrder});
+                    if (his) {
+                        stage.contract_tp = his.contract_tp;
+                        stage.qc_tp = his.qc_tp;
+                        stage.yf_tp = his.yf_tp;
+                        stage.sf_tp = his.sf_tp;
+                        stage.tp = this.ctx.helper.add(stage.contract_tp, stage.qc_tp);
+                        stage.end_tp = this.ctx.helper.add(stage.pre_tp, stage.tp);
+                    }
                 }
             }
             for (const s of stages) {
@@ -393,8 +460,8 @@ module.exports = app => {
             return calcBase;
         }
 
-        async updateCheckCalcFlag(sid, check) {
-            const result = await this.db.update(this.tableName, {id: sid, check_calc: check});
+        async updateCheckCalcFlag(stage, check) {
+            const result = await this.db.update(this.tableName, {id: stage.id, check_calc: check});
             return result.affectedRows === 1;
         }
 
@@ -412,7 +479,9 @@ module.exports = app => {
         async deleteStage(id) {
             const transaction = await this.db.beginTransaction();
             try {
+                const stageInfo = await this.getDataById(id);
                 await transaction.delete(this.tableName, { id });
+                await transaction.delete(this.ctx.service.pos.tableName, {add_stage: id});
                 await transaction.delete(this.ctx.service.stageAudit.tableName, { sid: id });
                 await transaction.delete(this.ctx.service.stageBills.tableName, { sid: id });
                 await transaction.delete(this.ctx.service.stageChange.tableName, { sid: id });
@@ -437,7 +506,7 @@ module.exports = app => {
                 await transaction.delete(this.ctx.service.stagePay.tableName, { sid: id });
                 await transaction.delete(this.ctx.service.pay.tableName, { csid: id });
                 // 删除计量附件文件
-                const attList = await this.ctx.service.stageAtt.getAllDataByCondition({ where: { sid: id } });
+                const attList = await this.ctx.service.stageAtt.getAllDataByCondition({ where: { tid: stageInfo.tid, sid: stageInfo.order } });
                 if (attList.length !== 0) {
                     for (const att of attList) {
                         if (fs.existsSync(path.join(this.app.baseDir, att.filepath))) {
@@ -445,7 +514,7 @@ module.exports = app => {
                         }
                     }
                 }
-                await transaction.delete(this.ctx.service.stageAtt.tableName, { sid: id });
+                await transaction.delete(this.ctx.service.stageAtt.tableName, { tid: stageInfo.tid, sid: stageInfo.order });
                 // 其他台账
                 await transaction.delete(this.ctx.service.stageJgcl.tableName, { sid: id });
                 const bonus = await this.ctx.service.stageBonus.getStageData(id);
@@ -500,7 +569,7 @@ module.exports = app => {
                         cb.value = sum.contract_tp;
                         break;
                     case 'bqbg':
-                        cb.value = sum.contract_tp;
+                        cb.value = sum.qc_tp;
                         break;
                     case 'ybbqwc':
                         const sumGcl = await this.ctx.service.stageBills.getSumTotalPriceGclByMaterial(stage_list, '^1[0-9]{2}-');

+ 34 - 1
app/service/stage_audit.js

@@ -216,7 +216,7 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
-                await transaction.update(this.tableName, {id: audit.id, status: auditConst.status.checking, begin_time: new Date()});
+                await transaction.update(this.tableName, { id: audit.id, status: auditConst.status.checking, begin_time: new Date() });
                 // 计算原报最终数据
                 const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份下一审核人数据
@@ -226,12 +226,20 @@ module.exports = app => {
                 await this.ctx.service.stageOther.updateHistory(this.ctx.stage, transaction);
                 // 更新期数据
                 const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
+                this.ctx.stage.tp_history.push({
+                    times: this.ctx.stage.curTimes, order: 0,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
+                    yf_tp: yfPay.tp,
+                    sf_tp: sfPay.tp,
+                });
                 await transaction.update(this.ctx.service.stage.tableName, {
                     id: stageId, status: auditConst.status.checking,
                     contract_tp: tpData.contract_tp,
                     qc_tp: tpData.qc_tp,
                     yf_tp: yfPay.tp,
                     sf_tp: sfPay.tp,
+                    tp_history: JSON.stringify(this.ctx.stage.tp_history),
                     cache_time_r: this.ctx.stage.cache_time_l,
                 });
 
@@ -276,6 +284,13 @@ module.exports = app => {
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
                 // 计算并合同支付最终数据
                 const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
+                this.ctx.stage.tp_history.push({
+                    times: times, order: audit.order,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
+                    yf_tp: yfPay.tp,
+                    sf_tp: sfPay.tp,
+                });
                 // 无下一审核人表示,审核结束
                 if (nextAudit) {
                     // 复制一份下一审核人数据
@@ -292,6 +307,7 @@ module.exports = app => {
                         qc_tp: tpData.qc_tp,
                         yf_tp: yfPay.tp,
                         sf_tp: sfPay.tp,
+                        tp_history: JSON.stringify(this.ctx.stage.tp_history),
                         cache_time_r: this.ctx.stage.cache_time_l,
                     });
 
@@ -326,6 +342,7 @@ module.exports = app => {
                         qc_tp: tpData.qc_tp,
                         yf_tp: yfPay.tp,
                         sf_tp: sfPay.tp,
+                        tp_history: JSON.stringify(this.ctx.stage.tp_history),
                         cache_time_r: this.ctx.stage.cache_time_l,
                     });
 
@@ -389,6 +406,13 @@ module.exports = app => {
             try {
                 // 计算并合同支付最终数据
                 const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
+                this.ctx.stage.tp_history.push({
+                    times: times, order: audit.order,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
+                    yf_tp: yfPay.tp,
+                    sf_tp: sfPay.tp,
+                });
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -398,6 +422,7 @@ module.exports = app => {
                     times: times + 1,
                     yf_tp: yfPay.tp,
                     sf_tp: sfPay.tp,
+                    tp_history: JSON.stringify(this.ctx.stage.tp_history),
                     cache_time_r: this.ctx.stage.cache_time_l,
                 });
                 // 拷贝新一次审核流程列表
@@ -466,6 +491,13 @@ module.exports = app => {
             try {
                 // 计算并合同支付最终数据
                 const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
+                this.ctx.stage.push({
+                    times: times, order: audit.order,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
+                    yf_tp: yfPay.tp,
+                    sf_tp: sfPay.tp,
+                });
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
                     id: stageId,
@@ -474,6 +506,7 @@ module.exports = app => {
                     times: times,
                     yf_tp: yfPay.tp,
                     sf_tp: sfPay.tp,
+                    tp_history: JSON.stringify(this.ctx.stage.tp_history),
                     cache_time_r: this.ctx.stage.cache_time_l,
                 });
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});

+ 2 - 2
app/view/dashboard/index.ejs

@@ -40,7 +40,7 @@
                                                         <div class="col-3 ml-auto text-right pl-0"><a href="/tender/<%- t.id %>/ledger/audit" class="btn btn-sm btn-outline-primary">审批</a></div>
                                                     </div>
                                                     <p class="mt-1 mb-0"><%- ctx.session.sessionUser.name %><small class="ml-1 text-muted"><%- (role ? '- ' + role : '') %></small>
-                                                        <span class="pull-right text-muted"><%- t.begin_time.toLocaleString() %></span>
+                                                        <span class="pull-right text-muted"><%- (t.begin_time ? t.begin_time.toLocaleString() : '') %></span>
                                                     </p>
                                                 </div>
                                             </li>
@@ -53,7 +53,7 @@
                                                         <div class="col-3 ml-auto text-right pl-0"><a href="/tender/<%- t.id %>/ledger" class="btn btn-sm btn-outline-primary">重新上报</a></div>
                                                     </div>
                                                     <p class="mt-1 mb-0"><%- ctx.session.sessionUser.name %><small class="ml-1 text-muted"><%- (role ? '- ' + role : '') %></small>
-                                                        <span class="pull-right text-muted"><%- t.end_time.toLocaleString() %></span>
+                                                        <span class="pull-right text-muted"><%- (t.end_time ? t.end_time.toLocaleString() : '') %></span>
                                                     </p>
                                                 </div>
                                             </li>

+ 8 - 0
app/view/ledger/audit.ejs

@@ -98,5 +98,13 @@
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
     let ledgerSpreadSetting = '<%- ledgerSpreadSetting %>';
     ledgerSpreadSetting = JSON.parse(ledgerSpreadSetting);
+    ledgerSpreadSetting.localCache = {
+        key: 'ledger-bills',
+        colWidth: true,
+    };
     let posSpreadSetting = JSON.parse('<%- posSpreadSetting %>');
+    posSpreadSetting.localCache = {
+        key: 'ledger-pos',
+        colWidth: true,
+    };
 </script>

+ 8 - 0
app/view/ledger/bwtz.ejs

@@ -89,6 +89,10 @@
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'bwtz-xmj',
+            colWidth: true,
+        }
     };
     const unitSpreadSetting = {
         cols: [
@@ -114,6 +118,10 @@
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'bwtz-unit',
+            colWidth: true,
+        }
     };
     const decimal = <%- ctx.tender.info.decimal.tp %>;
 </script>

+ 8 - 0
app/view/ledger/explode.ejs

@@ -178,7 +178,15 @@
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
     let ledgerSpreadSetting = '<%- ledgerSpreadSetting %>';
     ledgerSpreadSetting = JSON.parse(ledgerSpreadSetting);
+    ledgerSpreadSetting.localCache = {
+        key: 'ledger-bills',
+        colWidth: true,
+    };
     let posSpreadSetting = JSON.parse('<%- posSpreadSetting %>');
+    posSpreadSetting.localCache = {
+        key: 'ledger-pos',
+        colWidth: true,
+    };
 </script>
 <% if ((tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === tender.user_id) { %>
 <script>

+ 7 - 2
app/view/report/index.ejs

@@ -1,12 +1,16 @@
+<% if (stg_id === -1) {%>
 <% include ../tender/tender_sub_menu.ejs %>
+<% } else { %>
+<% include ../stage/stage_sub_menu.ejs %>
+<% } %>
 <div class="panel-content">
     <div class="panel-title">
         <div class="title-main d-flex">
             <% if(stg_id === -1) { %>
                 <% include ../tender/tender_sub_mini_menu.ejs %>
             <% } else { %>
-                <% include ../stage/stage_sub_mini_menu.ejs %> <%
-            } %>
+                <% include ../stage/stage_sub_mini_menu.ejs %>
+            <% } %>
             <div>
                 <div class="d-inline-block">
                     <div class="dropdown">
@@ -215,6 +219,7 @@
     const tenders = JSON.parse('<%- JSON.stringify(tenderList) %>');
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
+    const ledgerAuditConst = JSON.parse('<%- JSON.stringify(ledgerAuditConst) %>');
     $(document).ready(() => {
         rptCustomObj.initTenderTree(tenders, category);
     });

+ 2 - 1
app/view/report/rpt_print.ejs

@@ -8,6 +8,7 @@
     <script type="text/javascript" src="/public/report/js/jpc_output.js"></script>
     <script type="text/javascript" src="/public/report/js/rpt_print.js"></script>
     <script type="text/javascript" src="/public/report/js/rpt_preview_common.js"></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
 </head>
 <style type="text/css">
     .pageBreakOrg {
@@ -39,4 +40,4 @@
 </body>
 <SCRIPT type="text/javascript">
 </SCRIPT>
-</html>
+</html>

+ 2 - 1
app/view/report/rpt_printA3.ejs

@@ -8,6 +8,7 @@
     <script type="text/javascript" src="/public/report/js/jpc_output.js"></script>
     <script type="text/javascript" src="/public/report/js/rpt_print.js"></script>
     <script type="text/javascript" src="/public/report/js/rpt_preview_common.js"></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
 </head>
 <style type="text/css">
     .pageBreak {
@@ -23,4 +24,4 @@
 </body>
 <SCRIPT type="text/javascript">
 </SCRIPT>
-</html>
+</html>

+ 8 - 0
app/view/stage/bwtz.ejs

@@ -109,6 +109,10 @@
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'stage-bwtz-xmj',
+            colWidth: true,
+        },
     };
     const unitSpreadSetting = {
         cols: [
@@ -149,6 +153,10 @@
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'stage-bwtz-unit',
+            colWidth: true,
+        },
     };
     const decimal = <%- ctx.tender.info.decimal.tp %>;
 </script>

+ 8 - 0
app/view/stage/compare.ejs

@@ -69,7 +69,15 @@
     //const auditors = JSON.parse(<%- JSON.stringify(ctx.stage.auditors) %>);
     const stage = JSON.parse('<%- JSON.stringify(ctx.stage) %>');
     const ledgerSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
+    ledgerSpreadSetting.localCache = {
+        key: 'stage-compare-bills',
+        colWidth: true,
+    }
     const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
+    posSpreadSetting.localCache = {
+        key: 'stage-compare-pos',
+        colWidth: true,
+    }
     const scCacheKey = 'stage-compare-role-' + stage.tid + '-' + stage.order;
     let scRoles = getLocalCache(scCacheKey);
     scRoles = scRoles ? scRoles.split(',') : [0];

+ 8 - 0
app/view/stage/gather.ejs

@@ -92,6 +92,14 @@
 <script>
     const stage = JSON.parse('<%- JSON.stringify(ctx.stage) %>');
     const gclSpreadSetting = JSON.parse('<%- JSON.stringify(gclSpread) %>');
+    gclSpreadSetting.localCache = {
+        key: 'stage-gather-gcl',
+        colWidth: true,
+    }
     const leafXmjSpreadSetting = JSON.parse('<%- JSON.stringify(leafXmjSpread) %>');
+    leafXmjSpreadSetting.localCache = {
+        key: 'stage-gather-leafXmj',
+        colWidth: true,
+    }
     chapter = JSON.parse('<%- JSON.stringify(ctx.tender.info.chapter) %>');
 </script>

+ 8 - 0
app/view/stage/index.ejs

@@ -565,7 +565,15 @@
     }
     const readOnly = <%- stage.readOnly || stage.revising %>;
     const ledgerSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
+    ledgerSpreadSetting.localCache = {
+        key: 'stage-bills',
+        colWidth: true,
+    }
     const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
+    ledgerSpreadSetting.localCache = {
+        key: 'stage-pos',
+        colWidth: true,
+    }
     const tender = JSON.parse('<%- JSON.stringify(tender) %>');
     const tenderInfo = JSON.parse('<%- JSON.stringify(ctx.tender.info) %>');
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');

+ 6 - 6
app/view/stage/stage_sub_menu.ejs

@@ -27,7 +27,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/pay') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/pay"><span class="ml-3">合同支付</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/pay"><span class="ml-3">合同支付</span></a>
                 </li>
             </ul>
         </div>
@@ -35,7 +35,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/bwtz') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/bwtz"><span class="ml-3">部位台帐</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/bwtz"><span class="ml-3">部位台帐</span></a>
                 </li>
             </ul>
         </div>
@@ -43,27 +43,27 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/change') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/change"><span class="ml-3">变更概况</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/change"><span class="ml-3">变更概况</span></a>
                 </li>
             </ul>
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/gather') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/gather"><span class="ml-3">清单汇总</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/gather"><span class="ml-3">清单汇总</span></a>
                 </li>
             </ul>
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/compare') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/compare"><span class="ml-3">审核比较</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/compare"><span class="ml-3">审核比较</span></a>
                 </li>
             </ul>
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/compare') { %>active<% } %>">
+                <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/report') { %>active<% } %>">
                     <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/report"><span class="ml-3">报表</span></a>
                 </li>
             </ul>

+ 1 - 1
app/view/stage/stage_sub_mini_menu.ejs

@@ -63,7 +63,7 @@
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/compare') { %>active<% } %>">
+                <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/report') { %>active<% } %>">
                     <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/report"><span class="ml-3">报表</span></a>
                 </li>
             </ul>

+ 96 - 1
builder_report_index_define.js

@@ -779,6 +779,21 @@ const gather_stage_bills = {
         { name: '(特殊3-需替换key3)台账-金额', field: 'ts_key3_tp', type: dataType.currency },
 
         { name: '交叉排序', field: 'cross_index', type: dataType.int },
+
+        { name: '树结构-id', fields: 'id', type: dataType.int },
+        { name: '树结构-父项id', fields: 'pid', type: dataType.int },
+        { name: '树结构-层次', fields: 'level', type: dataType.int },
+        { name: '树结构-排序', fields: 'order', type: dataType.int },
+        { name: '树结构-完整路径', fields: 'full_path', type: dataType.str },
+
+        { name: '(特殊1-需替换key1)台账-设计数量1', field: 'ts_key1_dgn_qty1', type: dataType.currency },
+        { name: '(特殊1-需替换key1)台账-设计数量2', field: 'ts_key1_dgn_qty2', type: dataType.currency },
+
+        { name: '(特殊2-需替换key2)台账-设计数量1', field: 'ts_key2_dgn_qty1', type: dataType.currency },
+        { name: '(特殊2-需替换key2)台账-设计数量2', field: 'ts_key2_dgn_qty2', type: dataType.currency },
+
+        { name: '(特殊3-需替换key3)台账-设计数量1', field: 'ts_key3_dgn_qty1', type: dataType.currency },
+        { name: '(特殊3-需替换key3)台账-设计数量2', field: 'ts_key3_dgn_qty2', type: dataType.currency },
     ],
 };
 const gather_tender_info = {
@@ -994,6 +1009,85 @@ const materialGl = {
     ],
 };
 
+const sum_stage_bills = {
+    name: '期汇总-清单数据表(mem_sum_stage_bills)',
+    remark: '',
+    id: 42,
+    key: 'mem_sum_stage_bills',
+    prefix: '期汇总-清单数据',
+    cols: [
+        { name: '台账ID', field: 'id', type: dataType.int },
+        { name: '标段ID', field: 'tender_id', type: dataType.int },
+        { name: '树结构-ID', field: 'ledger_id', type: dataType.int },
+        { name: '树结构-父项ID', field: 'ledger_pid', type: dataType.int },
+        { name: '树结构-层级', field: 'level', type: dataType.int },
+        { name: '树结构-同层排序', field: 'order', type: dataType.int },
+        { name: '树结构-完整路径', field: 'full_path', type: dataType.str },
+        { name: '树结构-是否子项', field: 'is_leaf', type: dataType.int }, // 8
+
+        { name: '项目节编号', field: 'code', type: dataType.str },
+        { name: '清单编号', field: 'b_code', type: dataType.str },
+        { name: '名称', field: 'name', type: dataType.str },
+        { name: '单位', field: 'unit', type: dataType.str }, // 12
+        { name: '单价', field: 'unit_price', type: dataType.currency },
+
+        { name: '签约-数量', field: 'deal_qty', type: dataType.currency },
+        { name: '签约-金额', field: 'deal_tp', type: dataType.currency },
+
+        { name: '施工复核-数量', field: 'sgfh_qty', type: dataType.currency },
+        { name: '施工复核-金额', field: 'sgfh_tp', type: dataType.currency },
+        { name: '设计错漏-数量', field: 'sjcl_qty', type: dataType.currency },
+        { name: '设计错漏-金额', field: 'sjcl_tp', type: dataType.currency },
+        { name: '其他错漏-数量', field: 'qtcl_qty', type: dataType.currency },
+        { name: '其他错漏-金额', field: 'qtcl_tp', type: dataType.currency },
+        { name: '台账-数量', field: 'quantity', type: dataType.currency },
+        { name: '台账-金额', field: 'total_price', type: dataType.currency },
+
+        { name: '项目节-数量1', field: 'dgn_qty1', type: dataType.currency },
+        { name: '项目节-数量2', field: 'dgn_qty2', type: dataType.currency },
+
+        { name: '图册号', field: 'drawing_code', type: dataType.str },
+        { name: '备注', field: 'memo', type: dataType.str },
+        { name: '节点类型', field: 'node_type', type: dataType.int },
+        { name: '总额计量', field: 'is_tp', type: dataType.int },
+
+        { name: '第1期-合同-数量', field: 's1_contract_qty', type: dataType.currency },
+        { name: '第1期-合同-金额', field: 's1_contract_tp', type: dataType.currency },
+        { name: '第1期-变更-数量', field: 's1_qc_qty', type: dataType.currency },
+        { name: '第1期-变更-金额', field: 's1_qc_tp', type: dataType.currency },
+        { name: '第1期-完成-数量', field: 's1_gather_qty', type: dataType.currency },
+        { name: '第1期-完成-金额', field: 's1_gather_tp', type: dataType.currency },
+
+        { name: '第2期-合同-数量', field: 's2_contract_qty', type: dataType.currency },
+        { name: '第2期-合同-金额', field: 's2_contract_tp', type: dataType.currency },
+        { name: '第2期-变更-数量', field: 's2_qc_qty', type: dataType.currency },
+        { name: '第2期-变更-金额', field: 's2_qc_tp', type: dataType.currency },
+        { name: '第2期-完成-数量', field: 's2_gather_qty', type: dataType.currency },
+        { name: '第2期-完成-金额', field: 's2_gather_tp', type: dataType.currency },
+
+        { name: '第3期-合同-数量', field: 's3_contract_qty', type: dataType.currency },
+        { name: '第3期-合同-金额', field: 's3_contract_tp', type: dataType.currency },
+        { name: '第3期-变更-数量', field: 's3_qc_qty', type: dataType.currency },
+        { name: '第3期-变更-金额', field: 's3_qc_tp', type: dataType.currency },
+        { name: '第3期-完成-数量', field: 's3_gather_qty', type: dataType.currency },
+        { name: '第3期-完成-金额', field: 's3_gather_tp', type: dataType.currency },
+
+        { name: '第4期-合同-数量', field: 's4_contract_qty', type: dataType.currency },
+        { name: '第4期-合同-金额', field: 's4_contract_tp', type: dataType.currency },
+        { name: '第4期-变更-数量', field: 's4_qc_qty', type: dataType.currency },
+        { name: '第4期-变更-金额', field: 's4_qc_tp', type: dataType.currency },
+        { name: '第4期-完成-数量', field: 's4_gather_qty', type: dataType.currency },
+        { name: '第4期-完成-金额', field: 's4_gather_tp', type: dataType.currency },
+
+        { name: '第5期-合同-数量', field: 's5_contract_qty', type: dataType.currency },
+        { name: '第5期-合同-金额', field: 's5_contract_tp', type: dataType.currency },
+        { name: '第5期-变更-数量', field: 's5_qc_qty', type: dataType.currency },
+        { name: '第5期-变更-金额', field: 's5_qc_tp', type: dataType.currency },
+        { name: '第5期-完成-数量', field: 's5_gather_qty', type: dataType.currency },
+        { name: '第5期-完成-金额', field: 's5_gather_tp', type: dataType.currency },
+    ],
+};
+
 const recursiveMkdirSync = async function(pathName) {
     if (!fs.existsSync(pathName)) {
         const upperPath = path.dirname(pathName);
@@ -1094,7 +1188,8 @@ const defines = [
     stage_pay,
     stage_im_zl, stage_im_tz, stage_im_tz_bills,
     gather_stage_bills, gather_tender_info, gather_stage_pay, gather_deal_bills,
-    material, materialGl
+    material, materialGl,
+    sum_stage_bills
 ];
 for (const d of defines) {
     exportTableDefine(d);

+ 10 - 1
sql/update.sql

@@ -48,6 +48,12 @@ ADD COLUMN `contract_expr`  varchar(255) CHARACTER SET ascii COLLATE ascii_gener
 ALTER TABLE `zh_stage_pos`
 ADD COLUMN `contract_expr`  varchar(255) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT '' COMMENT '合同计量-公式' AFTER `postil`;
 
+ALTER TABLE `zh_stage_bills_final`
+ADD COLUMN `contract_expr`  varchar(255) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT '' COMMENT '合同计量-公式' AFTER `used`;
+
+ALTER TABLE `zh_stage_pos_final`
+ADD COLUMN `contract_expr`  varchar(255) CHARACTER SET ascii COLLATE ascii_general_ci NULL DEFAULT '' COMMENT '合同计量-公式' AFTER `used`;
+
 ALTER TABLE `zh_project_account` ADD `backdoor_password` VARCHAR(255) NULL DEFAULT NULL COMMENT '副密码' AFTER `password`;
 
 CREATE TABLE `calculation`.`zh_rpt_tree_node_cust` (
@@ -62,4 +68,7 @@ ALTER TABLE `zh_project` ADD `page_show` VARCHAR(5000) CHARACTER SET utf8 COLLAT
 
 ALTER TABLE `zh_project` CHANGE `creator` `creator` INT(11) NOT NULL COMMENT '创建者';
 
-INSERT INTO `zh_permission`(`id`, `name`, `controller`, `action`, `pid`, `icon_class`, `create_time`, `isshow`) VALUES (71,'页面显示','project','pageshow',38,'',NULL,1)
+INSERT INTO `zh_permission`(`id`, `name`, `controller`, `action`, `pid`, `icon_class`, `create_time`, `isshow`) VALUES (71,'页面显示','project','pageshow',38,'',NULL,1);
+
+ALTER TABLE `zh_stage`
+ADD COLUMN `tp_history`  text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '金额类的历史记录' AFTER `cache_time_l`;

+ 104 - 22
test/app/lib/rpt_data_analysis.test.js

@@ -494,39 +494,121 @@ describe('test/app/service/report_memory.test.js', () => {
         // ctx.helper.saveBufferFile(JSON.stringify(x, "", "\t"), ctx.app.baseDir + '/mem_stage_pos.json');
     });
     it('test sortPos/unionPos', function* () {
-        const ctx = app.mockContext(mockData);
+        const ctx = app.mockContext();
+        const postData = {
+            account: 'zengpeiwen',
+            project: 'P1201',
+            project_password: '123456',
+        };
+        ctx.session = {};
+        const loginResult = yield ctx.service.projectAccount.accountLogin(postData, 2);
 
         // test12 - 第6期
-        const stage = yield ctx.service.stage.getDataByCondition({tid: 12, order: 6});
         const params = {
-            tender_id: stage.tid,
-            stage_id: stage.id,
+            tender_id: 2546,
         };
         const filters = ['mem_stage_bills', 'tender_info', 'mem_stage_pos'];
         const data = yield ctx.service.report.getReportData(params, filters, {
             mem_stage_bills: [
-                'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
-                'code', 'b_code', 'name', 'unit', 'unit_price',
-                'deal_qty', 'deal_tp',
-                'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
-                'dgn_qty1', 'dgn_qty2',
-                'drawing_code', 'memo', 'node_type', 'is_tp',
-                'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil',
-                'pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_gather_qty', 'pre_gather_tp',
-                'end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp', 'end_gather_qty', 'end_gather_tp',
-                'final_tp', 'final_ratio',
-                'qc_bgl_code',
-                'chapter',
+                'id'
             ],
-            mem_stage_pos: [],
+            mem_stage_pos: ['name'],
         });
         // sortPos
-        // reportDataAnalysis.analysisObj.sortPos.fun(ctx, data, [], {bills: 'mem_stage_bills', pos: 'mem_stage_pos'});
-        // yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_bills, "", "\t"), path.join(savePath, 'mem_stage_bills.json'));
-        // yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_pos, "", "\t"), path.join(savePath, 'mem_stage_pos.json'));
+        reportDataAnalysis.analysisObj.sortPos.fun(ctx, data, [], {bills: 'mem_stage_bills', pos: 'mem_stage_pos'});
+        yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_bills, "", "\t"), path.join(savePath, 'mem_stage_bills.json'));
+        yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_pos, "", "\t"), path.join(savePath, 'mem_stage_pos.json'));
 
         // unionPos
-        reportDataAnalysis.analysisObj.unionPos.fun(ctx, data, [], {bills: 'mem_stage_bills', pos: 'mem_stage_pos'});
-        yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_bills, "", "\t"), path.join(savePath, 'mem_stage_bills.json'));
+        // reportDataAnalysis.analysisObj.unionPos.fun(ctx, data, [], {bills: 'mem_stage_bills', pos: 'mem_stage_pos'});
+        // yield ctx.helper.saveBufferFile(JSON.stringify(data.mem_stage_bills, "", "\t"), path.join(savePath, 'mem_stage_bills.json'));
+    });
+    it('test splitXmjCode', function* () {
+        const ctx = app.mockContext(mockData);
+
+        // test12 - 第6期
+        const testData11 = {
+            bills: [
+                { code: '1', level: 1 },
+                { code: '1-1', level: 2 },
+                { code: '1-1-1', level: 3 },
+                { code: '1-1-1-1', level: 4 },
+                { code: '1-1-1-1-1', level: 5 },
+                { code: '1-1-1-1-1-1', level: 6 },
+            ]
+        };
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData11, [], {table: 'bills', type: '11', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData11.bills[1].xiang === '一' );
+        assert(testData11.bills[2].mu ==='1');
+        assert(testData11.bills[3].jie === '1');
+        assert(testData11.bills[4].ximu === '1');
+        assert(testData11.bills[5].ximu === '1-1');
+
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData11, [], {table: 'bills', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData11.bills[1].xiang === '1-1' );
+        assert(testData11.bills[2].mu === '1-1-1');
+        assert(testData11.bills[3].jie === '1-1-1-1');
+        assert(testData11.bills[4].ximu === '1-1-1-1-1');
+        assert(testData11.bills[5].ximu === '1-1-1-1-1-1');
+
+        const testData18 = {
+            bills: [
+                { code: '1', level: 1, ledger_id: 1, ledger_pid: -1, full_path: '1' }, // 0
+                { code: '101', level: 2, ledger_id: 2, ledger_pid: 1, full_path: '1-2' },
+                { code: '10101', level: 3, ledger_id: 3, ledger_pid: 2, full_path: '1-2-3' },
+                { code: '1010101', level: 4, ledger_id: 4, ledger_pid: 3, full_path: '1-2-3-4' },
+                { code: '1010103', level: 4, ledger_id: 5, ledger_pid: 3, full_path: '1-2-3-5' },
+                { code: '101010301', level: 5, ledger_id: 6, ledger_pid: 5, full_path: '1-2-3-5-6' }, // 5
+                { code: '102', level: 2, ledger_id: 7, ledger_pid: 1, full_path: '1-7' },
+                { code: 'LJ05', level: 3, ledger_id: 8, ledger_pid: 7, full_path: '1-7-8' },
+                { code: 'LJ0502', level: 4, ledger_id: 9, ledger_pid: 8, full_path: '1-7-8-9' },
+                { code: 'LJ050204', level: 5, ledger_id: 10, ledger_pid: 9, full_path: '1-7-8-9-10' },
+                { code: 'GDLJ05020401', level: 6, ledger_id: 11, ledger_pid: 10, full_path: '1-7-8-9-10-11' }, // 10
+            ]
+        };
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData18, [], {table: 'bills', type:'18', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData18.bills[1].xiang === '01');
+        assert(testData18.bills[2].mu === '01');
+        assert(testData18.bills[3].jie === '01');
+        assert(testData18.bills[4].jie === '03');
+        assert(testData18.bills[5].ximu === '01');
+        assert(testData18.bills[6].xiang === '02');
+        assert(testData18.bills[7].mu === 'LJ05');
+        assert(testData18.bills[8].jie === 'LJ0502');
+        assert(testData18.bills[9].ximu === 'LJ050204');
+        assert(testData18.bills[10].ximu === 'LJ05020401');
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData18, [], {table: 'bills', type:'18-1', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData18.bills[1].xiang === '01');
+        assert(testData18.bills[2].mu === '01');
+        assert(testData18.bills[3].jie === '01');
+        assert(testData18.bills[4].jie === '03');
+        assert(testData18.bills[5].ximu === '01');
+        assert(testData18.bills[6].xiang === '02');
+        assert(testData18.bills[7].mu === 'LJ05');
+        assert(testData18.bills[8].jie === '02');
+        assert(testData18.bills[9].ximu === '04');
+        assert(testData18.bills[10].ximu === '0401');
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData18, [], {table: 'bills', type:'18-0-1', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData18.bills[1].xiang === '01');
+        assert(testData18.bills[2].mu === '01');
+        assert(testData18.bills[3].jie === '01');
+        assert(testData18.bills[4].jie === '03');
+        assert(testData18.bills[5].ximu === '01');
+        assert(testData18.bills[6].xiang === '02');
+        assert(testData18.bills[7].mu === 'LJ05');
+        assert(testData18.bills[8].jie === 'LJ0502');
+        assert(testData18.bills[9].ximu === 'LJ050204');
+        assert(testData18.bills[10].ximu === 'GDLJ05020401');
+        reportDataAnalysis.analysisObj.splitXmjCode.fun(ctx, testData18, [], {table: 'bills', type:'18-1-1', code: 'code', targetField: ['xiang', 'mu', 'jie', 'ximu']});
+        assert(testData18.bills[1].xiang === '01');
+        assert(testData18.bills[2].mu === '01');
+        assert(testData18.bills[3].jie === '01');
+        assert(testData18.bills[4].jie === '03');
+        assert(testData18.bills[5].ximu === '01');
+        assert(testData18.bills[6].xiang === '02');
+        assert(testData18.bills[7].mu === 'LJ05');
+        assert(testData18.bills[8].jie === '02');
+        assert(testData18.bills[9].ximu === '04');
+        assert(testData18.bills[10].ximu === 'GD0401');
     });
 });