Browse Source

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

TonyKang 4 năm trước cách đây
mục cha
commit
6643fe6326
41 tập tin đã thay đổi với 1082 bổ sung278 xóa
  1. 13 1
      app/const/tender_info.js
  2. 2 2
      app/controller/change_controller.js
  3. 21 1
      app/controller/schedule_controller.js
  4. 43 0
      app/public/css/radar-animation.css
  5. 2 2
      app/public/js/category.js
  6. 1 2
      app/public/js/change_information.js
  7. 3 3
      app/public/js/change_information_approval.js
  8. 2 2
      app/public/js/change_information_set.js
  9. 4 4
      app/public/js/change_information_show.js
  10. 48 24
      app/public/js/ledger.js
  11. 184 0
      app/public/js/ledger_check.js
  12. 1 1
      app/public/js/ledger_gather.js
  13. 3 1
      app/public/js/revise.js
  14. 183 1
      app/public/js/schedule_ledger.js
  15. 46 34
      app/public/js/stage.js
  16. 2 0
      app/public/js/tender_copy_setting.js
  17. 1 0
      app/router.js
  18. 10 4
      app/service/change.js
  19. 13 8
      app/service/change_audit.js
  20. 2 1
      app/service/change_audit_list.js
  21. 9 0
      app/service/rpt_gather_memory.js
  22. 44 0
      app/service/schedule_ledger.js
  23. 0 1
      app/service/stage_pay.js
  24. 0 1
      app/service/tender_info.js
  25. 2 2
      app/view/change/info.ejs
  26. 1 0
      app/view/layout/layout.ejs
  27. 1 1
      app/view/ledger/explode.ejs
  28. 1 1
      app/view/ledger/explode_modal.ejs
  29. 1 1
      app/view/ledger/gather.ejs
  30. 14 5
      app/view/schedule/ledger.ejs
  31. 204 0
      app/view/shares/check_modal2.ejs
  32. 1 1
      app/view/shares/import_excel_modal.ejs
  33. 0 81
      app/view/shares/ledger_check_modal.ejs
  34. 1 4
      app/view/stage/index.ejs
  35. 1 19
      app/view/stage/modal.ejs
  36. 1 0
      app/view/tender/detail.ejs
  37. 125 10
      app/view/tender/detail_modal.ejs
  38. 19 0
      builder_report_index_define.js
  39. 2 0
      config/web.js
  40. 3 60
      sql/update.sql
  41. 68 0
      sql/update20201126.sql

+ 13 - 1
app/const/tender_info.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const parseInfo = ['deal_info', 'construction_unit', 'tech_param', 'decimal', 'precision', 'deal_param', 'display', 'pay_account', 'shenpi'];
+const parseInfo = ['deal_info', 'construction_unit', 'tech_param', 'decimal', 'precision', 'deal_param', 'display', 'pay_account', 'shenpi', 'bid_info'];
 const arrayInfo = ['chapter'];
 const defaultInfo = {
     // 合同信息
@@ -16,6 +16,9 @@ const defaultInfo = {
         buildName: '',
         dealCode: '',
         dealName: '',
+        projectType: '',
+        dealType: '',
+        finalCode: '',
     },
     // 参建单位
     construction_unit: {
@@ -55,6 +58,14 @@ const defaultInfo = {
         dealPeriod: '',
         startDate: '',
         planEndDate: '',
+        realStartDate: '',
+        realEndDate: '',
+        structureScale: '',
+    },
+    bid_info: {
+        controlPrice: 0,
+        bidPrice: 0,
+        bidStartDate: '',
     },
     // 小数位数
     decimal: {
@@ -97,6 +108,7 @@ const defaultInfo = {
         thousandth: false,
         stage: {
             realComplete: false,
+            correct: false,
         }
     },
     chapter: [

+ 2 - 2
app/controller/change_controller.js

@@ -293,7 +293,7 @@ module.exports = app => {
                     whiteList,
                     auditList,
                     changeList,
-                    tpUnit: ctx.tender.info.decimal.tp,
+                    tpUnit: change.tp_decimal ? change.tp_decimal : ctx.tender.info.decimal.tp,
                     upUnit: ctx.tender.info.decimal.up,
                     authMobile: auth_mobile,
                     shenpiConst,
@@ -559,7 +559,7 @@ module.exports = app => {
                     attList,
                     whiteList,
                     auditList,
-                    tpUnit: ctx.tender.info.decimal.tp,
+                    tpUnit: change.tp_decimal ? change.tp_decimal : ctx.tender.info.decimal.tp,
                     upUnit: ctx.tender.info.decimal.up,
                     authMobile: auth_mobile,
                     shenpiConst,

+ 21 - 1
app/controller/schedule_controller.js

@@ -11,6 +11,7 @@
 const moment = require('moment');
 const measureType = require('../const/tender').measureType;
 const billsPosConvert = require('../lib/bills_pos_convert');
+const _ = require('lodash');
 
 module.exports = app => {
     class ScheduleController extends app.BaseController {
@@ -30,10 +31,12 @@ module.exports = app => {
 
         async ledger(ctx) {
             const tender = ctx.tender;
+            const scheduleLedgerList = await ctx.service.scheduleLedger.getAllDataByCondition({ where: { tid: tender.id } });
             const renderData = {
                 tender: tender.data,
                 tenderInfo: tender.info,
                 measureType,
+                scheduleLedgerList: _.map(scheduleLedgerList, 'ledger_id'),
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.schedule.ledger),
             };
             await this.layout('schedule/ledger.ejs', renderData, 'schedule/ledger_modal.ejs');
@@ -48,7 +51,7 @@ module.exports = app => {
         async loadLedgerData(ctx) {
             try {
                 const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
-                const posData = this.ctx.tender.data.measure_type === measureType.tz.value
+                const posData = ctx.tender.data.measure_type === measureType.tz.value
                     ? await ctx.service.pos.getPosData({ tid: ctx.tender.id }) : [];
                 const convert = new billsPosConvert(ctx);
                 convert.loadData(ledgerData, posData, []);
@@ -59,6 +62,23 @@ module.exports = app => {
                 ctx.body = { err: 1, msg: err.toString(), data: [] };
             }
         }
+
+        /**
+         * 台账选中提交(Ajax)
+         *
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveLedger(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.scheduleLedger.saveLedger(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: [] };
+            }
+        }
     }
 
     return ScheduleController;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 43 - 0
app/public/css/radar-animation.css


+ 2 - 2
app/public/js/category.js

@@ -146,8 +146,8 @@ function bindCategoryValueControl() {
                 const delTr = $('tr[vid=' + delVid + ']');
                 delTr.addClass('table-danger');
                 $('input', delTr).attr('disabled', '');
-                delTr.children()[1].innerText = '移动到其他项';
-                $('tr[vid=' + tarVid + ']').children()[1].innerText = tarValue.relaTenders.length + tarValue.newTenders.length;
+                delTr.children()[2].innerText = '移动到其他项';
+                $('tr[vid=' + tarVid + ']').children()[2].innerText = tarValue.relaTenders.length + tarValue.newTenders.length;
                 $('#del-cate-value').modal('hide');
             });
             $('#del-cate-value').modal('show');

+ 1 - 2
app/public/js/change_information.js

@@ -243,10 +243,9 @@ function getAllList(currPageNum = 1) {
     let html = '';
     // '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + att.id
     for(const [index,att] of currPageAttData.entries()) {
-        console.log(att.uid, accountId, auditStatus, Boolean(att.extra_upload));
         html += `<tr>
         <td width="25"><input type="checkbox" class="check-file" file-id=${att.id}></td>
-        <td>${index+1}</td>
+        <td>${((currPageNum-1)*15)+index+1}</td>
         <td><a href="javascript:void(0)" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a></td>
         <td>${moment(att.in_time * 1000).format('YYYY-MM-DD')}<br>${bytesToSize(att.filesize)}</td>
         <td>

+ 3 - 3
app/public/js/change_information_approval.js

@@ -17,9 +17,9 @@ $(document).ready(() => {
             {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true},
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.unit_price', readOnly: true},
             {title: '原设计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'oamount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.oamount', readOnly: true},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', getValue: 'getValue.oa_tp', readOnly: true},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.oa_tp', readOnly: true},
             {title: '申请变更增(+)减(-)|数量', colSpan: '2|1', rowSpan: '1|1', field: 'camount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.camount', readOnly: true},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', getValue: 'getValue.ca_tp', readOnly: true},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.ca_tp', readOnly: true},
         ],
         emptyRows: 0,
         headRows: 2,
@@ -42,7 +42,7 @@ $(document).ready(() => {
             title: '|金额',
             colSpan: '|1', rowSpan: '|1',
             field: 'sa_tp',
-            hAlign: 2, width: 80, formatter: '@', type: 'Number',
+            hAlign: 2, width: 80, type: 'Number',
             readOnly: true
         };
         changeSpreadSetting.cols.push(newColcount);

+ 2 - 2
app/public/js/change_information_set.js

@@ -69,9 +69,9 @@ $(document).ready(() => {
             {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit', cellType: 'unit', comboItems: changeUnits},
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.unit_price'},
             {title: '原设计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'oamount', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.oamount'},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', readOnly: true, getValue: 'getValue.oa_tp'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.oa_tp'},
             {title: '申请变更增(+)减(-)|数量', colSpan: '2|1', rowSpan: '1|1', field: 'camount', hAlign: 2, width: 60, type: 'Number', readOnly: false, getValue: 'getValue.camount'},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', readOnly: true, getValue: 'getValue.ca_tp'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.ca_tp'},
             {title: '操作', colSpan: '1', rowSpan: '2', field: 'del_list', hAlign: 1, width: 40, readOnly: true, cellType: 'mouseTouch', getValue: 'getValue.del_list'},
         ],
         emptyRows: 0,

+ 4 - 4
app/public/js/change_information_show.js

@@ -17,11 +17,11 @@ $(document).ready(() => {
             {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.unit_price'},
             {title: '原设计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'oamount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.oamount'},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', getValue: 'getValue.oa_tp'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.oa_tp'},
             {title: '申请变更增(+)减(-)|数量', colSpan: '2|1', rowSpan: '1|1', field: 'camount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.camount'},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', getValue: 'getValue.ca_tp'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.ca_tp'},
             {title: '审批后变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'samount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.samount'},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sa_tp', hAlign: 2, width: 80, formatter: '@', type: 'Number', getValue: 'getValue.sa_tp'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sa_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.sa_tp'},
         ],
         emptyRows: 0,
         headRows: 2,
@@ -43,7 +43,7 @@ $(document).ready(() => {
             title: '|金额',
             colSpan: '|1', rowSpan: '|1',
             field: 'sa_tp',
-            hAlign: 2, width: 80, formatter: '@', type: 'Number',
+            hAlign: 2, width: 80, type: 'Number',
         };
         changeSpreadSetting.cols.push(newColcount);
         changeSpreadSetting.cols.push(newColTp);

+ 48 - 24
app/public/js/ledger.js

@@ -963,6 +963,21 @@ $(document).ready(function() {
     sjsSettingObj.setFxTreeStyle(ledgerSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(ledgerSpreadSetting);
     ledgerTreeCol.initSpreadSetting(ledgerSpreadSetting);
+    ledgerSpreadSetting.rowHeader = [
+        {
+            rowHeaderType: 'tag',
+            setting: {
+                getColor: function (index, data) {
+                    if (!data) return;
+                    if (index%10 === 0) return '#007bff';
+                    if (index%10 === 1) return '#28a745';
+                    if (index%10 === 2) return '#dc3545';
+                    if (index%10 === 3) return '#da9500';
+                    if (index%10 === 4) return '#17a2b8';
+                }
+            },
+        },
+    ];
     // ledgerSpreadSetting.cols.push(
     //     {title: 'ledger_id', colSpan: '1', rowSpan: '2', field: 'ledger_id', hAlign: 2, width: 60, type: 'Number', readOnly: true},
     //     {title: 'ledger_pid', colSpan: '1', rowSpan: '2', field: 'ledger_pid', hAlign: 2, width: 60, type: 'Number', readOnly: true},
@@ -3228,30 +3243,39 @@ $(document).ready(function() {
         return false;
     });
 
-    LedgerChecker({
-        ledgerTree: ledgerTree,
-        ledgerPos: pos,
-        checkList: checkList,
-        decimal: tenderInfo.decimal,
-        checkOption: {
-            sibling: { enable: 1 },
-            empty_code: { enable: 1 },
-            calc: {
-                enable: 1,
-                fields: ['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity'],
-            },
-            zero: { enable: 1 },
-            tp: {
-                enable: 1,
-                fields: [
-                    {qty: 'sgfh_qty', tp: 'sgfh_tp'},
-                    {qty: 'sjcl_qty', tp: 'sjcl_tp'},
-                    {qty: 'qtcl_qty', tp: 'qtcl_tp'},
-                    {qty: 'quantity', tp: 'total_price'},
-                    {qty: 'deal_qty', tp: 'deal_tp'},
-                ],
-            },
-        }
+    $('#ledger-check2').click(() => {
+        const result = ledgerCheck2({
+            ledgerTree: ledgerTree,
+            ledgerPos: pos,
+            checkList: checkList,
+            decimal: tenderInfo.decimal,
+            checkOption: {
+                sibling: { enable: 1 },
+                empty_code: { enable: 1 },
+                calc: {
+                    enable: 1,
+                    fields: ['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity'],
+                },
+                zero: { enable: 1 },
+                tp: {
+                    enable: 1,
+                    fields: [
+                        {qty: 'sgfh_qty', tp: 'sgfh_tp'},
+                        {qty: 'sjcl_qty', tp: 'sjcl_tp'},
+                        {qty: 'qtcl_qty', tp: 'qtcl_tp'},
+                        {qty: 'quantity', tp: 'total_price'},
+                        {qty: 'deal_qty', tp: 'deal_tp'},
+                    ],
+                },
+            }
+        });
+        check2Viewing({
+            extra: ZhCalc.div(ledgerTree.datas.length + pos.datas.length, 10000, 0),
+            randomWait: true,
+            prefix: 'check2-',
+            checks: result,
+            checkList: checkList,
+        })
     });
 });
 

+ 184 - 0
app/public/js/ledger_check.js

@@ -0,0 +1,184 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+
+const ledgerCheckType = {
+    sibling: {value: 1, text: '项目节、清单同层'},
+    empty_code: {value: 2, text: '项目节、清单编号同时为空'},
+    calc: {value: 3, text: '清单数量不等于计量单元之和'},
+    zero: {value: 4, text: '清单数量或单价为0'},
+    tp: {value: 5, text: '清单金额≠数量×单价'},
+    over: {value: 6, text: '超计'},
+};
+const ledgerCheckUtil = {
+    checkSibling: function (ledgerTree) {
+        const error = [];
+        for (const node of ledgerTree.nodes) {
+            if (!node.children || node.children.length === 0) continue;
+            let hasXmj, hasGcl;
+            for (const child of node.children) {
+                if (child.b_code) hasXmj = true;
+                if (!child.b_code) hasGcl = true;
+            }
+            if (hasXmj && hasGcl) error.push(node);
+        }
+        return error;
+    },
+    checkCodeEmpty: function (ledgerTree) {
+        const error = [];
+        const checkNodeCode = function (node) {
+            if ((!node.code || node.code === '') && (!node.b_code || node.b_code === '')) error.push(node);
+            if (node.children && node.children.length > 0) {
+                for (const child of node.children) {
+                    checkNodeCode(child);
+                }
+            }
+        }
+        for (const topLevel of ledgerTree.children) {
+            if (topLevel.node_type !== 1) continue;
+
+            checkNodeCode(topLevel);
+        }
+        return error;
+    },
+    checkCalc: function (ledgerTree, ledgerPos, option) {
+        const error = [];
+        for (const node of ledgerTree.nodes) {
+            if (node.children && node.children.length > 0) continue;
+
+            const nodePos = ledgerPos.getLedgerPos(node.id);
+            if (!nodePos || nodePos.length === 0) continue;
+
+            const checkData = {}, calcData = {};
+            for (const f of option.fields) {
+                checkData[f] = node[f] || 0;
+                calcData[f] = 0;
+            }
+            for (const np of nodePos) {
+                for (const f of option.fields) {
+                    calcData[f] = ZhCalc.add(calcData[f], np[f]) || 0;
+                }
+            }
+            if (!_.isMatch(checkData, calcData)) error.push(node);
+        }
+        return error;
+    },
+    checkZero: function (ledgerTree) {
+        const error = [];
+        for (const node of ledgerTree.nodes) {
+            if ((!node.b_code || node.b_code === '')) continue;
+            if (node.children && node.children.length > 0) continue;
+
+            if ((checkZero(node.sgfh_qty) && checkZero(node.qtcl_qty) && checkZero(node.sjcl_qty)
+                    && checkZero(node.deal_qty) && checkZero(node.quantity))
+                || checkZero(node.unit_price)) error.push(node);
+        }
+        return error;
+    },
+    checkTp: function (ledgerTree, decimal, option) {
+        const error = [];
+        for (const node of ledgerTree.nodes) {
+            if (node.children && node.children.length > 0) continue;
+            if (option.filter && option.filter(node)) continue;
+
+            const checkData = {}, calcData = {};
+            for (const f of option.fields) {
+                checkData[f.tp] = node[f.tp] || 0;
+                calcData[f.tp] = ZhCalc.mul(node.unit_price, node[f.qty], decimal.tp) || 0;
+            }
+            if (!_.isMatch(checkData, calcData)) error.push(node);
+        }
+        return error;
+    },
+    checkOver: function(ledgerTree, ledgerPos, option) {
+        const error = [];
+        for (const node of ledgerTree.nodes) {
+            if (node.children && node.children.length > 0) continue;
+
+            if (option.isTz) {
+                const posRange = ledgerPos.getLedgerPos(node.id) || [];
+                if (posRange.length > 0) {
+                    for (const p of posRange) {
+                        if (p.end_contract_qty > p.quantity) {
+                            error.push(node);
+                            continue;
+                        }
+                    }
+                }
+            }
+            if (node.is_tp) {
+                if (node.end_contract_tp > node.total_price) error.push(node);
+            } else {
+                if (node.end_contract_qty > node.quantity) error.push(node);
+            }
+        }
+        return error;
+    },
+};
+
+const ledgerCheck2 = function (setting) {
+    const ledger = setting.ledgerTree, ledgerPos = setting.ledgerPos, decimal = setting.decimal;
+    const checkOption = setting.checkOption;
+
+    const assignWarningData = function (nodes, checkType, warningData) {
+        for (const node of nodes) {
+            warningData.push({
+                type: checkType,
+                ledger_id: node.ledger_id,
+                code: node.code,
+                b_code: node.b_code,
+                name: node.name,
+            })
+        }
+    };
+
+    const checkData = {
+        check_time: new Date(),
+        warning_data: [],
+    };
+    const progressData = [];
+    if (checkOption.sibling.enable) {
+        const sibling = ledgerCheckUtil.checkSibling(ledger, checkOption.sibling) || [];
+        assignWarningData(sibling, ledgerCheckType.sibling.value, checkData.warning_data);
+        progressData.push({key: 'sibling', caption: ledgerCheckType.sibling.text, error: sibling.length});
+    }
+    if (checkOption.empty_code.enable) {
+        const empty_code = ledgerCheckUtil.checkCodeEmpty(ledger, checkOption.empty_code) || [];
+        assignWarningData(empty_code, ledgerCheckType.empty_code.value, checkData.warning_data);
+        progressData.push({key: 'empty_code', caption: ledgerCheckType.empty_code.text, error: empty_code.length});
+    }
+    if (checkOption.calc.enable) {
+        const calc = ledgerCheckUtil.checkCalc(ledger, ledgerPos, checkOption.calc) || [];
+        assignWarningData(calc, ledgerCheckType.calc.value, checkData.warning_data);
+        progressData.push({key: 'calc', caption: ledgerCheckType.calc.text, error: calc.length});
+    }
+    if (checkOption.zero.enable) {
+        const zero = ledgerCheckUtil.checkZero(ledger, checkOption.zero) || [];
+        assignWarningData(zero, ledgerCheckType.zero.value, checkData.warning_data);
+        progressData.push({key: 'zero', caption: ledgerCheckType.zero.text, error: zero.length});
+    }
+    if (checkOption.tp.enable) {
+        const tp = ledgerCheckUtil.checkTp(ledger, decimal, checkOption.tp) || [];
+        assignWarningData(tp, ledgerCheckType.tp.value, checkData.warning_data);
+        progressData.push({key: 'tp', caption: ledgerCheckType.tp.text, error: tp.length});
+    }
+    if (checkOption.over && checkOption.over.enable) {
+        const over = ledgerCheckUtil.checkOver(ledger, ledgerPos, checkOption.over) || [];
+        assignWarningData(over, ledgerCheckType.over.value, checkData.warning_data);
+        progressData.push({key: 'over', caption: ledgerCheckType.over.text, error: over.length});
+    }
+    setting.checkList.clearCheckData();
+    if (checkData.warning_data.length > 0) {
+        setting.checkList.loadCheckData(checkData);
+    } else {
+        setting.checkList.hide();
+    }
+    return progressData;
+};

+ 1 - 1
app/public/js/ledger_gather.js

@@ -178,7 +178,7 @@ $(document).ready(() => {
 
         const chapterData = gclGatherModel.gatherChapterData(chapter, ['total_price'], filter);
         for (const c of chapterData) {
-            c.compare_tp = ZhCalc.sub(c.deal_bills_tp, c.total_price);
+            c.compare_tp = ZhCalc.sub(c.total_price, c.deal_bills_tp);
         }
         generateChapterHtml(chapterData);
     }, null, true);

+ 3 - 1
app/public/js/revise.js

@@ -1307,10 +1307,12 @@ $(document).ready(() => {
             if (node) {
                 const posData = pos.getLedgerPos(node.id) || [];
                 SpreadJsObj.loadSheetData(posSheet, 'data', posData);
+                posSheet.zh_setting.readOnly = posData.length === 0 && node.used;
             } else {
                 SpreadJsObj.loadSheetData(posSheet, 'data', []);
+                posSheet.zh_setting.readOnly = true;
             }
-            SpreadJsObj.resetFieldReadOnly(posSheet);
+            SpreadJsObj.refreshSheetReadOnly(posSheet);
             posSpreadObj.loadExprToInput();
             posSpreadObj.refreshOperationValid(posSheet);
         },

+ 183 - 1
app/public/js/schedule_ledger.js

@@ -8,6 +8,7 @@
 function getTenderId() {
     return window.location.pathname.split('/')[2];
 }
+const selects = [];
 $(function () {
     autoFlashHeight();
     // 初始化台账
@@ -45,7 +46,7 @@ $(function () {
         defaultRowHeight: 21,
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
-        readOnly: true,
+        // readOnly: true,
         localCache: {
             key: 'ledger-bills',
             colWidth: true,
@@ -58,11 +59,126 @@ $(function () {
     SpreadJsObj.selChangedRefreshBackColor(ledgerSpread.getActiveSheet());
 
     postData(window.location.pathname + '/load', {}, function (data) {
+        data = addIsSelect(data);
         ledgerTree.loadDatas(data);
         treeCalc.calculateAll(ledgerTree);
+        // console.log(ledgerTree);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
     }, null, true);
 
+    const ledgerSpreadObj = {
+        getselectButton: function() {
+            return {
+                select_siblings: $('#select_siblings').is(':checked'),
+                select_other_siblings: $('#select_other_siblings').is(':checked'),
+                select_children: $('#select_children').is(':checked'),
+            }
+        },
+        refreshTree: function (sheet, data) {
+            SpreadJsObj.massOperationSheet(sheet, function () {
+                const tree = sheet.zh_tree;
+                // 处理删除
+                if (data.delete) {
+                    data.delete.sort(function (x, y) {
+                        return y.deleteIndex - x.deleteIndex;
+                    });
+                    for (const d of data.delete) {
+                        sheet.deleteRows(d.deleteIndex, 1);
+                    }
+                }
+                // 处理新增
+                if (data.create) {
+                    const newNodes = data.create;
+                    if (newNodes) {
+                        newNodes.sort(function (a, b) {
+                            return a.index - b.index;
+                        });
+
+                        for (const node of newNodes) {
+                            sheet.addRows(node.index, 1);
+                            SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(node), 1);
+                        }
+                    }
+                }
+                // 处理更新
+                if (data.update) {
+                    const rows = [];
+                    for (const u of data.update) {
+                        rows.push(tree.nodes.indexOf(u));
+                    }
+                    SpreadJsObj.reLoadRowsData(sheet, rows);
+                }
+                // 处理展开
+                if (data.expand) {
+                    const expanded = [];
+                    for (const e of data.expand) {
+                        if (expanded.indexOf(e) === -1) {
+                            const posterity = tree.getPosterity(e);
+                            for (const p of posterity) {
+                                sheet.setRowVisible(tree.nodes.indexOf(p), p.visible);
+                                expanded.push(p);
+                            }
+                        }
+                    }
+                }
+            });
+        },
+        buttonClicked: function (e, info) {
+            if (info.sheet.zh_setting) {
+                const select = SpreadJsObj.getSelectObject(info.sheet);
+                const col = info.sheet.zh_setting.cols[info.col];
+                // if (materialCol.readOnly.isEdit(select)) {
+                //     return;
+                // }
+                if (col.field === 'is_select') {
+                    if (info.sheet.isEditing()) {
+                        info.sheet.endEdit(true);
+                    }
+                    // 选中和去除关联
+                    select.is_select = info.sheet.getValue(info.row, info.col) ? 1 : 0;
+                    selects.splice(0, selects.length);
+                    selects.push(select);
+                    const select_msg = ledgerSpreadObj.getselectButton();
+                    if (select_msg.select_children || select.is_select === 0) {
+                        updateChildrenSelect(select.children, select.is_select);
+                    }
+                    if (!select_msg.select_other_siblings && select_msg.select_siblings) {
+                        updateSiblingsSelect(info.sheet.zh_tree, select.ledger_pid, select.is_select, select_msg);
+                    }
+                    if (select_msg.select_other_siblings) {
+                        updateSiblingsSelect(info.sheet.zh_tree, select.ledger_pid, select.is_select, select_msg);
+                        updateOtherSiblingsSelect(info.sheet.zh_tree, select.ledger_pid, select.is_select, select_msg);
+                    }
+                    if(select.is_select === 1) {
+                        updateParentSelect(info.sheet.zh_tree, select.ledger_pid, select.is_select);
+                    }
+                    // console.log(selects);
+                    const refreshNode = ledgerTree.loadPostData({update: selects});
+                    ledgerSpreadObj.refreshTree(info.sheet, refreshNode);
+                }
+            }
+        },
+    };
+
+    ledgerSpread.bind(spreadNS.Events.ButtonClicked, ledgerSpreadObj.buttonClicked);
+
+    $('#ledger_submit').click(function () {
+        const select_ledger = _.filter(ledgerTree.nodes, { 'is_select': 1 });
+        console.log(select_ledger);
+        if (select_ledger.length === 0) {
+            toastr.error('请选择清单项');
+            return;
+        }
+        $(this).attr('disabled', true);
+        postData(window.location.pathname + '/save',  _.map(select_ledger, 'ledger_id'), function (result) {
+            toastr.success('设置成功');
+            setTimeout(function () {
+                window.location.reload();
+            },1500);
+        });
+    })
+
+
     // // 显示层次
     // (function (select, sheet) {
     //     $(select).click(function () {
@@ -90,3 +206,69 @@ $(function () {
     //     });
     // })('a[name=showLevel]', ledgerSpread.getActiveSheet());
 });
+function addIsSelect(datas) {
+    for (const d of datas) {
+        d.is_select = selectedLedgerList.length === 0 ? 1: selectedLedgerList.indexOf(d.ledger_id) !== -1 ? 1 : 0;
+    }
+    return datas;
+}
+
+function updateChildrenSelect(datas, is_select) {
+    for (const data of datas) {
+        data.is_select = is_select;
+        if(data.children && data.children.length > 0) {
+            updateChildrenSelect(data.children, is_select);
+        }
+        selects.push(data);
+    }
+}
+
+function updateSiblingsSelect(tree, pid, is_select, select_msg) {
+    const parent = pid !== -1 ? _.find(tree.nodes, { 'ledger_id': pid }) : tree;
+    if (parent) {
+        for(const d of parent.children) {
+            d.is_select = is_select;
+            if (select_msg.select_children || is_select === 0) {
+                updateChildrenSelect(d.children, is_select);
+            }
+            selects.push(d);
+        }
+    }
+}
+
+function updateOtherSiblingsSelect(tree, pid, is_select, select_msg) {
+    if(pid === -1) {
+        return;
+    }
+    const parent = _.find(tree.nodes, { 'ledger_id': pid });
+    if (parent) {
+        const grandparent = parent.ledger_pid === -1 ? tree : _.find(tree.nodes, { 'ledger_id': parent.ledger_pid });
+        if (grandparent) {
+            for (const d of grandparent.children) {
+                if (d.ledger_id !== pid) {
+                    if(d.children && d.children.length > 0) {
+                        for (const dd of d.children) {
+                            dd.is_select = is_select;
+                            if (select_msg.select_children || is_select === 0) {
+                                updateChildrenSelect(dd.children, is_select);
+                            }
+                            selects.push(dd);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+function updateParentSelect(tree, pid, is_select) {
+    if (pid !== -1) {
+        const parent = _.find(tree.nodes, { 'ledger_id': pid });
+        if (parent) {
+            const hadselectInfo = is_select === 0 ? _.findIndex(parent.children, { 'is_select': 1 }) : 1;
+            parent.is_select = (hadselectInfo !== -1 && is_select === 0) || is_select === 1 ? 1 : 0;
+            selects.push(parent);
+            updateParentSelect(tree, parent.ledger_pid, is_select);
+        }
+    }
+}

+ 46 - 34
app/public/js/stage.js

@@ -507,12 +507,12 @@ $(document).ready(() => {
     const slSpread = SpreadJsObj.createNewSpread($('#stage-ledger')[0]);
     customizeStageTreeSetting(ledgerSpreadSetting, customColDisplay());
     // 数量变更列,添加按钮
-    const col = _.find(ledgerSpreadSetting.cols, {field: 'qc_qty'});
-    col.readOnly = true;
-    col.cellType = 'activeImageBtn';
-    col.normalImg = '#ellipsis-icon';
-    col.indent = 5;
-    col.showImage = function (data) {
+    const qcCol = _.find(ledgerSpreadSetting.cols, {field: 'qc_qty'});
+    qcCol.readOnly = true;
+    qcCol.cellType = 'activeImageBtn';
+    qcCol.normalImg = '#ellipsis-icon';
+    qcCol.indent = 5;
+    qcCol.showImage = function (data) {
         if (!data || (data.children && data.children.length > 0) || !(data.b_code && data.b_code !== '')) {
             return false;
         } else {
@@ -520,6 +520,8 @@ $(document).ready(() => {
             return !(nodePos && nodePos.length > 0);
         }
     };
+    const ratioCol = ledgerSpreadSetting.cols.find(x => {return x.field === 'end_gather_percent' || x.field === 'end_correct_percent'});
+    ratioCol.field = tenderInfo.display.stage.correct ? 'end_correct_percent' : 'end_gather_percent';
     ledgerSpreadSetting.imageClick = function (data) {
         if (data.children && data.children.length > 0) return;
 
@@ -605,7 +607,9 @@ $(document).ready(() => {
                 if (def && def.color) return def.color;
             }
         }
-        return data && data.end_contract_qty > data.quantity ? '#f8d7da' : defaultColor;
+        if (checkTzMeasureType()) {
+            return data && data.end_contract_qty > data.quantity ? '#f8d7da' : defaultColor;
+        }
     };
     sjsSettingObj.setGridSelectStyle(posSpreadSetting);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(posSpreadSetting);
@@ -1197,11 +1201,9 @@ $(document).ready(() => {
         });
     }
     stageTreeSpreadObj.loadExprToInput(slSpread.getActiveSheet());
-    //let check_correct = false;
     $.contextMenu({
         selector: '#stage-ledger',
         build: function ($trigger, e) {
-            e.data.items.correct_percent.selected = check_correct;
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, slSpread);
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
@@ -1238,22 +1240,6 @@ $(document).ready(() => {
                     }
                 },
             },
-            // 'correct_percent': {
-            //     name: '使用数量矫正完成率',
-            //     type: 'checkbox',
-            //     events: {
-            //         change: function (e) {
-            //             check_correct = e.data.commands.correct_percent.$input[0].checked;
-            //             const sheet = slSpread.getActiveSheet();
-            //             const col = sheet.zh_setting.cols.find(x => {
-            //                 return x.field === 'end_gather_percent' || x.field === 'end_correct_percent'
-            //             });
-            //             col.field = check_correct ? 'end_correct_percent' : 'end_gather_percent';
-            //             SpreadJsObj.reLoadColsData(sheet, [col]);
-            //             e.data.$menu.hide();
-            //         }
-            //     },
-            // }
         }
     });
 
@@ -3061,7 +3047,27 @@ $(document).ready(() => {
                                 const node = stageTree.nodes.find(x => {return x.id === changeBills.gcl_id});
                                 SpreadJsObj.locateTreeNode(slSpread.getActiveSheet(), node.ledger_id);
                             } else {
-                                toastr.warning('该清单无法定位');
+                                const cb = {
+                                    b_code: changeBills.code || '',
+                                    name: changeBills.name || '',
+                                    unit: changeBills.unit || '',
+                                    unit_price: changeBills.unit_price || 0,
+                                };
+                                for (const node of stageTree.nodes) {
+                                    if (node.children && node.children.length > 0) continue;
+
+                                    const b = {
+                                        b_code: bills.b_code || '',
+                                        name: bills.name || '',
+                                        unit: bills.unit || '',
+                                        unit_price: bills.unit_price || 0,
+                                    };
+                                    if (_.isMatch(cb, b)) {
+                                        SpreadJsObj.locateTreeNode(slSpread.getActiveSheet(), node.ledger_id);
+                                        stagePosSpreadObj.loadCurPosData();
+                                        return;
+                                    }
+                                }
                             }
                         },
                         disabled: function (key, opt) {
@@ -3091,7 +3097,7 @@ $(document).ready(() => {
                 SpreadJsObj.loadSheetData(self.changeSheet, SpreadJsObj.DataType.Data, self.changes);
                 self.changeSheet.setSelection(0, 0, 1, 1);
                 if (self.changes.length > 0) self.analyzeChange(result.changes[0]);
-                self.curChangeId = result.changes[0].id;
+                self.curChangeId = self.changes.length > 0 ? self.changes[0].id : null;
                 self.loadChangeDetailData();
             });
         }
@@ -3604,6 +3610,9 @@ $(document).ready(() => {
                     return node.is_tp;
                 }
             },
+            over: {
+                enable: 1, isTz: checkTzMeasureType(),
+            }
         }
     };
     if (!checkTzMeasureType()) {
@@ -3615,7 +3624,16 @@ $(document).ready(() => {
             {qty: 'quantity', tp: 'total_price'},
         );
     }
-    LedgerChecker(stageCheckerSetting);
+    $('#ledger-check2').click(() => {
+        const result = ledgerCheck2(stageCheckerSetting);
+        check2Viewing({
+            extra: ZhCalc.div(stageTree.datas.length + stagePos.datas.length, 10000, 0),
+            randomWait: true,
+            prefix: 'check2-',
+            checks: result,
+            checkList: checkList,
+        })
+    });
 
     const dataChecker = DataChecker({
         checkUrl: window.location.pathname + '/check',
@@ -3766,10 +3784,4 @@ $(document).ready(() => {
         }
         stageTreeSpreadObj.measureByBatch(posName, ratio, apply2sibling);
     });
-    $('#correct_percent').click(function () {
-        const sheet = slSpread.getActiveSheet();
-        const col = sheet.zh_setting.cols.find(x => {return x.field === 'end_gather_percent' || x.field === 'end_correct_percent'});
-        col.field = this.checked ? 'end_correct_percent' : 'end_gather_percent';
-        SpreadJsObj.reLoadColsData(sheet, [sheet.zh_setting.cols.indexOf(col)]);
-    })
 });

+ 2 - 0
app/public/js/tender_copy_setting.js

@@ -95,7 +95,9 @@ function initTenderTree () {
     }
 }
 function recursiveGetTenderNodeHtml (node, arr, pid) {
+    // console.log(node, tender)
     if (node.id === tender.id) return ''
+    if (node.user_id && parseInt(node.user_id) !== cur_uid) return ''
     const html = [];
     html.push('<tr pid="' + pid + '">');
     // 名称

+ 1 - 0
app/router.js

@@ -434,4 +434,5 @@ module.exports = app => {
     app.get('/tender/:id/schedule', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.index');
     app.get('/tender/:id/schedule/ledger', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.ledger');
     app.post('/tender/:id/schedule/ledger/load', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.loadLedgerData');
+    app.post('/tender/:id/schedule/ledger/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.saveLedger');
 };

+ 10 - 4
app/service/change.js

@@ -487,6 +487,7 @@ module.exports = app => {
                     charge: postData.charge,
                     w_code: postData.w_code,
                     total_price,
+                    tp_decimal: this.ctx.tender.info.decimal.tp,
                 };
                 const options = {
                     where: {
@@ -579,13 +580,14 @@ module.exports = app => {
                 // 清单数据更新
                 const bills_list = postData.bills_list.split(',');
                 let total_price = 0;
+                const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp;
                 for (const bl of bills_list) {
                     const listInfo = bl.split('_');
                     const lid = listInfo[0];
                     const amount = listInfo[1];
                     const changeListInfo = await this.ctx.service.changeAuditList.getDataById(lid);
                     if (changeListInfo !== undefined) {
-                        total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(changeListInfo.unit_price, amount, this.ctx.tender.info.decimal.tp));
+                        total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(changeListInfo.unit_price, amount, tp_decimal));
                         const audit_amount = changeListInfo.audit_amount !== null && changeListInfo.audit_amount !== '' ? changeListInfo.audit_amount.split(',') : [];
                         audit_amount.push(amount);
                         const list_update = {
@@ -780,8 +782,9 @@ module.exports = app => {
                     where: { cid: changeInfo.cid },
                 });
                 let total_price = 0;
+                const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp;
                 for (const cl of changeList) {
-                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, this.ctx.tender.info.decimal.tp));
+                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, tp_decimal));
                 }
                 // 设置变更令退回
                 const change_update = {
@@ -790,6 +793,7 @@ module.exports = app => {
                     times: newTimes,
                     cin_time: Date.parse(new Date()) / 1000,
                     total_price,
+                    tp_decimal: null,
                 };
                 const options = {
                     where: {
@@ -919,6 +923,7 @@ module.exports = app => {
                     where: { cid: changeInfo.cid },
                 });
                 let total_price = 0;
+                const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp;
                 for (const cl of changeList) {
                     const audit_amount = cl.audit_amount.split(',');
                     const last_amount = audit_amount[audit_amount.length - 1];
@@ -928,7 +933,7 @@ module.exports = app => {
                         audit_amount: audit_amount.join(','),
                         spamount: parseFloat(last_amount),
                     };
-                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), this.ctx.tender.info.decimal.tp));
+                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), tp_decimal));
                     await this.transaction.update(this.ctx.service.changeAuditList.tableName, list_update);
                 }
 
@@ -1231,6 +1236,7 @@ module.exports = app => {
 
                 // 审批列表数据也要回退
                 let total_price = 0;
+                const tp_decimal = changeInfo.tp_decimal ? changeInfo.tp_decimal : this.ctx.tender.info.decimal.tp;
                 const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({
                     where: { cid: changeInfo.cid },
                 });
@@ -1243,7 +1249,7 @@ module.exports = app => {
                         audit_amount: audit_amount.join(','),
                         samount: '',
                     };
-                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), this.ctx.tender.info.decimal.tp));
+                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), tp_decimal));
                     await this.transaction.update(this.ctx.service.changeAuditList.tableName, list_update);
                 }
 

+ 13 - 8
app/service/change_audit.js

@@ -566,14 +566,6 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 await transaction.update(this.tableName, { id: audit.id, status: auditConst.auditStatus.checking, sin_time: new Date() });
-                const options = {
-                    where: {
-                        cid: cid,
-                    },
-                };
-                await transaction.update(this.ctx.service.change.tableName, {
-                    status: auditConst.status.checking,
-                }, options);
                 // 更新原报人审批状态
                 await transaction.update(this.tableName, {
                     id: yBAudit.id,
@@ -581,9 +573,11 @@ module.exports = app => {
                     sin_time: new Date(),
                 });
                 const changeList = await this.ctx.service.changeAuditList.getList(cid);
+                let total_price = 0;
                 // 更新清单spamount的值
                 const updateListData = [];
                 for (const cl of changeList) {
+                    total_price = this.ctx.helper.accAdd(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, this.ctx.tender.info.decimal.tp));
                     if(cl.camount !== cl.spamount) {
                         const uld = {
                             id: cl.id,
@@ -593,6 +587,17 @@ module.exports = app => {
                     }
                 }
                 if(updateListData.length > 0) await transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateListData);
+                const options = {
+                    where: {
+                        cid: cid,
+                    },
+                };
+                const updateData = {
+                    total_price,
+                    tp_decimal: this.ctx.tender.info.decimal.tp,
+                    status: auditConst.status.checking,
+                };
+                await transaction.update(this.ctx.service.change.tableName, updateData, options);
 
                 // 添加短信通知-需要审批提醒功能
                 const sms = new SMS(this.ctx);

+ 2 - 1
app/service/change_audit_list.js

@@ -189,8 +189,9 @@ module.exports = app => {
             const sqlParam = [this.tableName, this.ctx.change.cid];
             const changeList = await transaction.query(sql, sqlParam);
             let total_price = 0;
+            const tp_decimal = this.ctx.change.tp_decimal ? this.ctx.change.tp_decimal : this.ctx.tender.info.decimal.tp;
             for (const cl of changeList) {
-                total_price = this.ctx.helper.accAdd(total_price, this.ctx.helper.mul(cl.unit_price, cl.spamount, this.ctx.tender.info.decimal.tp));
+                total_price = this.ctx.helper.accAdd(total_price, this.ctx.helper.mul(cl.unit_price, cl.spamount, tp_decimal));
             }
             const updateData = {
                 total_price,

+ 9 - 0
app/service/rpt_gather_memory.js

@@ -67,6 +67,9 @@ const gatherUtils = {
         gatherNode['s_' + "qty"] = helper.add(gatherNode['s_' + "qty"], sourceNode.quantity);
         gatherNode['s_' + "tp"] = helper.add(gatherNode['s_' + "tp"], sourceNode.total_price);
 
+        gatherNode['s_' + "dgn_qty1"] = helper.add(gatherNode['s_' + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode['s_' + "dgn_qty2"] = helper.add(gatherNode['s_' + "dgn_qty2"], sourceNode.dgn_qty2);
+
         gatherNode['s_' + "contract_qty"] = helper.add(gatherNode['s_' + "contract_qty"], sourceNode.contract_qty);
         gatherNode['s_' + "contract_tp"] = helper.add(gatherNode['s_' + "contract_tp"], sourceNode.contract_tp);
         gatherNode['s_' + "qc_qty"] = helper.add(gatherNode['s_' + "qc_qty"], sourceNode.qc_qty);
@@ -87,6 +90,11 @@ const gatherUtils = {
         gatherNode['s_' + "end_qc_tp"] = helper.add(gatherNode['s_' + "end_qc_tp"], sourceNode.end_qc_tp);
         gatherNode['s_' + "end_gather_qty"] = helper.add(gatherNode['s_' + "end_gather_qty"], sourceNode.end_gather_qty);
         gatherNode['s_' + "end_gather_tp"] = helper.add(gatherNode['s_' + "end_gather_tp"], sourceNode.end_gather_tp);
+
+        gatherNode['s_' + "deal_dgn_qty1"] = helper.add(gatherNode['s_' + "deal_dgn_qty1"], sourceNode.deal_dgn_qty1);
+        gatherNode['s_' + "deal_dgn_qty2"] = helper.add(gatherNode['s_' + "deal_dgn_qty2"], sourceNode.deal_dgn_qty2);
+        gatherNode['s_' + "c_dgn_qty1"] = helper.add(gatherNode['s_' + "c_dgn_qty1"], sourceNode.c_dgn_qty1);
+        gatherNode['s_' + "c_dgn_qty2"] = helper.add(gatherNode['s_' + "c_dgn_qty2"], sourceNode.c_dgn_qty2);
     },
     gatherZone: function (tender, gatherNode, sourceNode, prefix, helper) {
         gatherNode[prefix + 'id'] = tender.id;
@@ -487,6 +495,7 @@ module.exports = app => {
             info.pay_account = tender.info.pay_account;
             info.deal_param.contractPriceWithoutZL = this.ctx.helper.sub(info.deal_param.contractPrice,
                 info.deal_param.zanLiePrice);
+            info.bid_info = tender.info.bid_info;
             return info;
         }
         async _getStageTenderInfo(stage, info) {

+ 44 - 0
app/service/schedule_ledger.js

@@ -0,0 +1,44 @@
+'use strict';
+
+module.exports = app => {
+    class ScheduleLedger extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'schedule_ledger';
+        }
+
+        async saveLedger(datas) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const oldDatas = await this.getAllDataByCondition({
+                    where: { tid: this.ctx.tender.id },
+                });
+                const oldLids = this._.map(oldDatas, 'ledger_id');
+                const insertDatas = [];
+                for (const l of datas) {
+                    if (oldLids.indexOf(l) === -1) {
+                        const data = {
+                            tid: this.ctx.tender.id,
+                            ledger_id: l,
+                        };
+                        insertDatas.push(data);
+                    } else {
+                        this._.pull(oldLids, l);
+                    }
+                }
+                if (oldLids.length > 0) {
+                    for (const ol of oldLids) {
+                        await transaction.delete(this.tableName, { tid: this.ctx.tender.id, ledger_id: ol });
+                    }
+                }
+                if (insertDatas.length > 0) await transaction.insert(this.tableName, insertDatas);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+    }
+    return ScheduleLedger;
+};

+ 0 - 1
app/service/stage_pay.js

@@ -269,7 +269,6 @@ module.exports = app => {
             const stagePays = stage.status === auditConst.stage.status.checked
                 ? await this.getStageLastestPays(stage.id)
                 : await this.getStagePays(stage);
-            console.log(stagePays);
             const sf = this._.find(stagePays, {ptype: payConst.payType.sf});
             return sf;
         }

+ 0 - 1
app/service/tender_info.js

@@ -307,7 +307,6 @@ module.exports = app => {
             }
 
             const [billsService] = await this._getLedgerService();
-            console.log(billsService);
 
             const changeBills = await this._reCalcLedger(tenderId, billsService, newDecimal, oldDecimal);
             const [changeSj, changeSb, changeSo] = await this._reCalcStageExtra(tenderId, newDecimal, oldDecimal);

+ 2 - 2
app/view/change/info.ejs

@@ -782,8 +782,8 @@
 <script>
     const changeUnits = JSON.parse('<%- JSON.stringify(changeUnits) %>');
     const precision = JSON.parse('<%- JSON.stringify(precision) %>');
-    const accountGroup = JSON.parse('<%- JSON.stringify(accountGroup) %>');
-    const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
+    const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
+    const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
     const shenpi_status = <%- ctx.tender.info.shenpi.change %>;
     const shenpiConst =  JSON.parse('<%- JSON.stringify(shenpiConst) %>');
     const changesUid =  <%- change.uid %>;

+ 1 - 0
app/view/layout/layout.ejs

@@ -20,6 +20,7 @@
     <link rel="stylesheet" href="/public/css/datepicker/datepicker.min.css" type="text/css">
     <link rel="stylesheet" href="/public/css/toastr.css">
     <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <link rel="stylesheet" href="/public/css/radar-animation.css">
     <!-- JS. -->
     <% for (const file of jsFiles) { %>
     <script type="text/javascript" src="<%- file %>"></script>

+ 1 - 1
app/view/ledger/explode.ejs

@@ -45,7 +45,7 @@
             </div>
             <div class="ml-auto">
                 <% if (tender.ledger_status !== auditConst.status.checked) { %>
-                    <a class="btn btn-sm btn-primary mr-1" href="#ledger-check-modal" data-toggle="modal" data-target="#ledger-check-modal">数据检查</a>
+                    <a class="btn btn-sm btn-primary mr-1" id="ledger-check2" href="javascript: void(0);">数据检查</a>
                 <% } %>
                 <% if (tender.ledger_status === auditConst.status.checkNo) { %>
                     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-dark sp-list-btn">审批退回</a>

+ 1 - 1
app/view/ledger/explode_modal.ejs

@@ -402,4 +402,4 @@
 <% include ../shares/import_excel_modal.ejs %>
 <% include ../shares/delete_hint_modal.ejs %>
 <% include ../shares/check_data_modal.ejs %>
-<% include ../shares/ledger_check_modal.ejs %>
+<% include ../shares/check_modal2.ejs %>

+ 1 - 1
app/view/ledger/gather.ejs

@@ -46,7 +46,7 @@
                         <div class="side-bar-1"></div>
                         <div class="sjs-sh-1">
                             <table class="table table-bordered">
-                                <tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台账金额</th><th>签约-台账</th></tr>
+                                <tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台账金额</th><th>台账-签约</th></tr>
                                 <tbody id="chapter-list"></tbody>
                             </table>
                         </div>

+ 14 - 5
app/view/schedule/ledger.ejs

@@ -7,22 +7,30 @@
                 <div class="d-inline-block">
                     <a class="btn btn-sm btn-light">
                         <div class="custom-control custom-checkbox">
-                            <input type="checkbox" class="custom-control-input" id="customCheckDisabled" checked="">
-                            <label class="custom-control-label text-primary" for="customCheckDisabled">自动选择同级项</label>
+                            <input type="checkbox" class="custom-control-input" id="select_siblings" checked>
+                            <label class="custom-control-label text-primary" for="select_siblings">自动选择同级项</label>
                         </div>
                     </a>
                 </div>
                 <div class="d-inline-block">
                     <a class="btn btn-sm btn-light">
                         <div class="custom-control custom-checkbox">
-                            <input type="checkbox" class="custom-control-input" id="customCheckDisabled2">
-                            <label class="custom-control-label text-primary" for="customCheckDisabled2">跨级选择同级项</label>
+                            <input type="checkbox" class="custom-control-input" id="select_other_siblings">
+                            <label class="custom-control-label text-primary" for="select_other_siblings">跨级选择同级项</label>
+                        </div>
+                    </a>
+                </div>
+                <div class="d-inline-block">
+                    <a class="btn btn-sm btn-light">
+                        <div class="custom-control custom-checkbox">
+                            <input type="checkbox" class="custom-control-input" id="select_children" checked>
+                            <label class="custom-control-label text-primary" for="select_children">自动选择子项</label>
                         </div>
                     </a>
                 </div>
             </div>
             <div class="ml-auto">
-                <a href="#add-qi" data-toggle="modal" data-target="#add-qi" class="btn btn-primary btn-sm pull-right">确认提交<div></div></a>
+                <button type="button" id="ledger_submit" class="btn btn-primary btn-sm pull-right">确认提交</button>
             </div>
         </div>
     </div>
@@ -42,6 +50,7 @@
     const tenderInfo = JSON.parse(unescape('<%- escape(JSON.stringify(tenderInfo)) %>'));
     const thousandth = <%- ctx.tender.info.display.thousandth %>;
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
+    const selectedLedgerList = JSON.parse('<%- JSON.stringify(scheduleLedgerList) %>');
 </script>
 <script>
     $.subMenu({

+ 204 - 0
app/view/shares/check_modal2.ejs

@@ -0,0 +1,204 @@
+<!--数据检查-->
+<div class="modal fade" id="checking2" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">数据检查</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-6">
+                        <!--雷达扫描动画-->
+                        <div class="L_transform">
+                            <div class="trans_bg">
+                                <div class="bg_shade"></div>
+                                <div class="circles topcircle active">
+                                    <div class="trio"><p class="c-icon"></p></div>
+                                </div>
+                                <div class="circles leftcircle ">
+                                    <div class="trio"><p class="c-icon"></p></div>
+                                </div>
+                                <div class="circles leftcircle2 ">
+                                    <div class="trio"><p class="c-icon"></p></div>
+                                </div>
+                                <div class="circles rightcircle ">
+                                    <div class="trio"><p class="c-icon"></p></div>
+                                </div>
+                                <div class="circles rightcircle2">
+                                    <div class="trio"><p class="c-icon"></p></div>
+                                </div>
+                                <div class="heart_box">
+                                    <div class="heart"></div>
+                                    <div class="shan" style="transform: rotate(274deg);"></div>
+                                </div>
+                            </div>
+                        </div>
+                        <!--雷达扫描动画结束-->
+                    </div>
+                    <div class="col-6">
+                        <p>数据检查,将检查罗列台账中以下内容:</p>
+                        <div id="check2-list">
+                            <div class="card p-2 border-success border-0">
+                                <div class="d-flex justify-content-start">
+                                    <span class="text-success mr-2"><i class="fa fa-check-circle fa-2x"></i></span>
+                                    <div class="w-100">
+                                        项目节、清单同层
+                                        <div class="progress mt-1">
+                                            <div class="progress-bar bg-success" role="progressbar" style="width: 100%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">100%</div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="card p-2 border-success border-0">
+                                <div class="d-flex justify-content-start">
+                                    <span class="text-warning mr-2"><i class="fa fa-info-circle fa-2x"></i></span>
+                                    <div class="w-100">
+                                        项目节、清单编号同时为空
+                                        <div class="progress mt-1">
+                                            <div class="progress-bar bg-warning" role="progressbar" style="width: 100%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">100%</div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="card p-2 border-success border-0">
+                                <div class="d-flex justify-content-start">
+                                    <span class="text-primary mr-2"><i class="fa fa-cog fa-spin fa-2x"></i></span>
+                                    <div class="w-100">
+                                        清单数量不等于计量单元之和
+                                        <div class="progress mt-1">
+                                            <div class="progress-bar" role="progressbar" style="width: 30%;" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100">30%</div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <p class="text-center text-primary" id="check2-hint">检查中,请等待...</p>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                    <button type="button" class="btn btn-sm btn-primary" id="check2-result">查看结果</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    const getmatrix = function(a,b,c,d,e,f){
+        var aa=Math.round(180*Math.asin(a)/ Math.PI);
+        var bb=Math.round(180*Math.acos(b)/ Math.PI);
+        var cc=Math.round(180*Math.asin(c)/ Math.PI);
+        var dd=Math.round(180*Math.acos(d)/ Math.PI);
+        var deg=0;
+        if(aa==bb||-aa==bb){
+            deg=dd;
+        }else if(-aa+bb==180){
+            deg=180+cc;
+        }else if(aa+bb==180){
+            deg=360-cc||360-dd;
+        }
+        return deg>=360?0:deg;
+
+    }
+    const radarFind = function (select) {
+        $('.circles').removeClass('active');
+        $(select).addClass('active');
+    }
+    let radarHandle, progressHandle;
+    const check2Viewing = function (setting) {
+        if (!setting.prefix) setting.prefix = 'check2-';
+        if (setting.randomWait) {
+            for (const c of setting.checks) {
+                c.wait = _.random(1, 5) + setting.extra;
+            }
+        }
+
+        // 雷达
+        let radarObj=$('.shan');
+        radarHandle = setInterval(function(){
+            var transform = radarObj.css('transform');
+            var deg= transform === 'none' ? 0 : eval('get'+ transform);//构造getmatrix函数,返回上次旋转度数
+            var step=45;
+            radarObj.css({'transform':'rotate('+(deg+step)%360+'deg)'});
+            var dd = radarObj.css({'transform':'rotate('+(deg+step)%360+'deg)'});
+            //上
+            if(deg>300&&deg<360 ||deg>0 &&deg<20){
+                radarFind('.topcircle');
+                // 右
+            }else if(deg>20 && deg<45){
+                radarFind('.rightcircle');
+            }else if(deg>70 && deg<90){
+                radarFind('.rightcircle2');
+                // 左
+            }else if(deg>150 && deg<180){
+                radarFind('.leftcircle2');
+            }else if(deg>230 && deg<300){
+                radarFind('.leftcircle');
+            }
+        }, 100);
+
+        const initCheckList = function (prefix, checks) {
+            $('#check2-result').hide();
+            $('#check2-hint').removeClass('text-warning').removeClass('text-success').addClass('text-primary').html('检查中,请等待...');
+            const html = [];
+            for (const c of checks) {
+                const domid = prefix + c.key;
+                html.push(`<div class="card p-2 border-success border-0" id="${domid}">`);
+                html.push('<div class="d-flex justify-content-start">');
+                html.push('<span class="text-muted mr-2"><i class="fa fa-circle-o fa-2x"></i></span>');
+                html.push('<div class="w-100">', c.caption);
+                html.push('<div class="progress mt-1">', '<div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>', '</div>');
+                html.push('</div>');
+                html.push('</div>');
+                html.push('</div>');
+            }
+            $('#check2-list').html(html.join(''));
+        }
+        const doSomeCheck = function (setting, index) {
+            const check = setting.checks[index];
+            console.log(check.wait);
+            if (!check) return;
+
+            setting.total = setting.total + (check.error || 0);
+            const obj = $('#' + setting.prefix + check.key);
+            $('.fa-circle-o', obj).removeClass('fa-circle-o').addClass('fa-cog');
+            $('.text-muted').removeClass('text-muted').addClass('text-primary');
+            $('.progress-bar', obj).attr('aria-valuemax', check.wait*10);
+            const handle = setInterval(function () {
+                const now = _.toInteger($('.progress-bar', obj).attr('aria-valuenow')) || 0;
+                if (now < check.wait * 10) {
+                    const percent = Math.min(ZhCalc.div((now + 1) * 10, check.wait, 0), 100);
+                    $('.progress-bar', obj).attr('aria-valuenow', Math.min(now + 1, check.wait*10)).html(percent + '%').width(percent + '%');
+                }
+            }, 100);
+            setTimeout(() => {
+                clearInterval(handle);
+                $('.fa-cog', obj).removeClass('fa-cog').addClass(check.error > 0 ? 'fa-info-circle' : 'fa-check-circle');
+                $('.text-primary', obj).removeClass('text-primary').addClass(check.error > 0 ? 'text-warning' : 'text-success');
+                $('.progress-bar', obj).addClass(check.error > 0 ? 'bg-warning' : 'bg-success');
+                if (index === setting.checks.length - 1) {
+                    if (setting.total > 0) {
+                        $('#check2-result').show();
+                        $('#check2-hint').removeClass('text-primary').addClass('text-warning').html('检查完成,发现问题,请查阅检查结果。');
+                    } else {
+                        $('#check2-hint').removeClass('text-primary').addClass('text-success').html('检查完成,没有任何问题。');
+                    }
+                } else {
+                    doSomeCheck(setting, index + 1);
+                }
+            }, check.wait*1000 + 500);
+        }
+
+        initCheckList(setting.prefix, setting.checks);
+        $('#checking2').modal('show');
+        setting.total = 0;
+        doSomeCheck(setting, 0);
+        $('#check2-result').click(() => {
+            $('#checking2').modal('hide');
+            setting.checkList.show();
+        });
+    }
+    $('#checking2').bind('hidden.bs.modal', function () {
+        clearInterval(radarHandle);
+    });
+</script>

+ 1 - 1
app/view/shares/import_excel_modal.ejs

@@ -20,7 +20,7 @@
             <div class="modal-footer d-flex justify-content-between">
                 <div>
                     <div class="custom-control custom-checkbox custom-control-inline" id="filter-excel">
-                        <input type="radio" class="custom-control-input" name="customRadioInline1" id="filter-qty-price" checked="">
+                        <input type="checkbox" class="custom-control-input" name="customRadioInline1" id="filter-qty-price" checked="">
                         <label class="custom-control-label" for="filter-qty-price">过滤清单数量和单价为0项</label>
                     </div>
                 </div>

+ 0 - 81
app/view/shares/ledger_check_modal.ejs

@@ -112,87 +112,6 @@
             return result;
         }
 
-        const ledgerCheckUtil = {
-            checkSibling: function (ledgerTree) {
-                const error = [];
-                for (const node of ledgerTree.nodes) {
-                    if (!node.children || node.children.length === 0) continue;
-                    let hasXmj, hasGcl;
-                    for (const child of node.children) {
-                        if (child.b_code) hasXmj = true;
-                        if (!child.b_code) hasGcl = true;
-                    }
-                    if (hasXmj && hasGcl) error.push(node);
-                }
-                return error;
-            },
-            checkCodeEmpty: function (ledgerTree) {
-                const error = [];
-                const checkNodeCode = function (node) {
-                    if ((!node.code || node.code === '') && (!node.b_code || node.b_code === '')) error.push(node);
-                    if (node.children && node.children.length > 0) {
-                        for (const child of node.children) {
-                            checkNodeCode(child);
-                        }
-                    }
-                }
-                for (const topLevel of ledgerTree.children) {
-                    if (topLevel.node_type !== 1) continue;
-
-                    checkNodeCode(topLevel);
-                }
-                return error;
-            },
-            checkCalc: function (ledgerTree, option) {
-                const error = [];
-                for (const node of ledgerTree.nodes) {
-                    if (node.children && node.children.length > 0) continue;
-
-                    const nodePos = ledgerPos.getLedgerPos(node.id);
-                    if (!nodePos || nodePos.length === 0) continue;
-
-                    const checkData = {}, calcData = {};
-                    for (const f of option.fields) {
-                        checkData[f] = node[f] || 0;
-                        calcData[f] = 0;
-                    }
-                    for (const np of nodePos) {
-                        for (const f of option.fields) {
-                            calcData[f] = ZhCalc.add(calcData[f], np[f]) || 0;
-                        }
-                    }
-                    if (!_.isMatch(checkData, calcData)) error.push(node);
-                }
-                return error;
-            },
-            checkZero: function (ledgerTree) {
-                const error = [];
-                for (const node of ledgerTree.nodes) {
-                    if ((!node.b_code || node.b_code === '')) continue;
-                    if (node.children && node.children.length > 0) continue;
-
-                    if ((checkZero(node.sgfh_qty) && checkZero(node.qtcl_qty) && checkZero(node.sjcl_qty)
-                        && checkZero(node.deal_qty) && checkZero(node.quantity))
-                        || checkZero(node.unit_price)) error.push(node);
-                }
-                return error;
-            },
-            checkTp: function (ledgerTree, option) {
-                const error = [];
-                for (const node of ledgerTree.nodes) {
-                    if (node.children && node.children.length > 0) continue;
-                    if (option.filter && option.filter(node)) continue;
-
-                    const checkData = {}, calcData = {};
-                    for (const f of option.fields) {
-                        checkData[f.tp] = node[f.tp] || 0;
-                        calcData[f.tp] = ZhCalc.mul(node.unit_price, node[f.qty], decimal.tp) || 0;
-                    }
-                    if (!_.isMatch(checkData, calcData)) error.push(node);
-                }
-                return error;
-            }
-        };
 
         const assignWarningData = function (nodes, checkType, warningData) {
             for (const node of nodes) {

+ 1 - 4
app/view/stage/index.ejs

@@ -34,10 +34,7 @@
                 </div>
                 <div class="d-inline-block ml-3">
                     <a id="exportExcel" class="btn btn-primary btn-sm" href="javascript: void(0)">导出计量台账Excel</a>
-                    <a class="btn btn-sm btn-primary" href="#ledger-check-modal" data-toggle="modal" data-target="#ledger-check-modal">数据检查</a>
-                </div>
-                <div class="d-inline-block">
-                    <a class="btn btn-sm btn-primary" href="#correct" data-toggle="modal" data-target="#correct"><i class="fa fa-cog"></i></a>
+                    <a class="btn btn-sm btn-primary" href="javascript: void(0);" id="ledger-check2">数据检查</a>
                 </div>
             </div>
             <div class="ml-auto">

+ 1 - 19
app/view/stage/modal.ejs

@@ -450,24 +450,6 @@
         </div>
     </div>
 </div>
-<div class="modal fade" id="correct" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">操作确认</h5>
-            </div>
-            <div class="modal-body">
-                <div class="custom-control custom-checkbox">
-                    <input type="checkbox" class="custom-control-input" id="correct_percent">
-                    <label class="custom-control-label " for="correct_percent">使用数量纠正完成率</label>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-sm btn-primary" data-dismiss="modal">确认</button>
-            </div>
-        </div>
-    </div>
-</div>
 <% include ./audit_modal.ejs %>
 <% include ../shares/merge_peg_modal.ejs %>
-<% include ../shares/ledger_check_modal.ejs %>
+<% include ../shares/check_modal2.ejs %>

+ 1 - 0
app/view/tender/detail.ejs

@@ -152,6 +152,7 @@
     const tenders = JSON.parse(unescape('<%- escape(JSON.stringify(tenders)) %>'));
     const category = JSON.parse(unescape('<%- escape(JSON.stringify(categoryData)) %>'));
     const tender = JSON.parse('<%- JSON.stringify(tender) %>');
+    const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     //4 标段期数计量进度//
     var myChart = echarts.init(document.getElementById('chartContainer4'));
     var option = {

+ 125 - 10
app/view/tender/detail_modal.ejs

@@ -17,6 +17,9 @@
                         <li class="nav-item">
                             <a class="nav-link" data-toggle="tab" href="#jscs" role="tab">技术参数</a>
                         </li>
+                        <li class="nav-item">
+                            <a class="nav-link" data-toggle="tab" href="#zbxx" role="tab">中标信息</a>
+                        </li>
                     </ul>
                     <div class="tab-content">
                         <div class="tab-pane active" id="htxx">
@@ -38,7 +41,7 @@
                                             <input type="text" class="form-control" value="" id="deal-code" maxlength="100" oninput="limitReturn(this)">
                                         </div>
                                     </div>
-                                    <div class="col-12">
+                                    <div class="col-12 mb-2">
                                         <div class="input-group input-group-sm">
                                             <div class="input-group-prepend">
                                                 <span class="input-group-text" style="width:90px">合同名称</span>
@@ -46,6 +49,36 @@
                                             <input type="text" class="form-control" value="" id="deal-name" maxlength="100" oninput="limitReturn(this)">
                                         </div>
                                     </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text" style="width:90px">工程类别</span>
+                                            </div>
+                                            <select class="form-control" id="project-type">
+                                                <option value="">请选择</option>
+                                                <option value="设计">设计</option>
+                                                <option value="监理">监理</option>
+                                                <option value="施工">施工</option>
+                                                <option value="其他">其他</option>
+                                            </select>
+                                        </div>
+                                    </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text" style="width:90px">合同类别</span>
+                                            </div>
+                                            <input type="text" class="form-control" value="" id="deal-type">
+                                        </div>
+                                    </div>
+                                    <div class="col-12">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text" style="width:90px">结算书编号</span>
+                                            </div>
+                                            <input type="text" class="form-control" value="" id="final-code">
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                         </div>
@@ -270,6 +303,60 @@
                                             <input type="date" class="form-control" value="" id="plan-end-date">
                                         </div>
                                     </div>
+                                    <div class="col-6 pr-0 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">实际开工日期</span>
+                                            </div>
+                                            <input type="date" class="form-control" value="" id="real-start-date">
+                                        </div>
+                                    </div>
+                                    <div class="col-6">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">实际完工日期</span>
+                                            </div>
+                                            <input type="date" class="form-control" value="" id="real-end-date">
+                                        </div>
+                                    </div>
+                                    <div class="col-12">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">构造物规模</span>
+                                            </div>
+                                            <textarea class="form-control" id="structure-scale"></textarea>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="tab-pane" id="zbxx">
+                            <div class="form-group">
+                                <div class="row">
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">业主控制价</span>
+                                            </div>
+                                            <input type="number" class="form-control nospin" value="" id="control-price" onchange="checkNumberValid(this)">
+                                        </div>
+                                    </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">中标价</span>
+                                            </div>
+                                            <input type="number" class="form-control nospin" value="" id="bid-price" onchange="checkNumberValid(this)">
+                                        </div>
+                                    </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">开标日期</span>
+                                            </div>
+                                            <input type="date" class="form-control" value="" id="bid-start-date">
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                         </div>
@@ -538,20 +625,24 @@
             <div class="modal-body">
                 <div class="form-group">
                     <div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" class="form-check-input" id="ledger-dgn-qty" checked="">
-                        <label class="form-check-label" for="ledger-dgn-qty">项目节数量</label>
+                        <input type="checkbox" class="custom-control-input" id="ledger-dgn-qty" checked="">
+                        <label class="custom-control-label" for="ledger-dgn-qty">项目节数量</label>
                     </div>
                     <div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" class="form-check-input" id="ledger-cl-qty" checked="">
-                        <label class="form-check-label" for="ledger-cl-qty">错漏增减</label>
+                        <input type="checkbox" class="custom-control-input" id="ledger-cl-qty" checked="">
+                        <label class="custom-control-label" for="ledger-cl-qty">错漏增减</label>
                     </div>
                     <div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" class="form-check-input" id="thousandth" checked="">
-                        <label class="form-check-label" for="thousandth">千分位</label>
+                        <input type="checkbox" class="custom-control-input" id="thousandth" checked="">
+                        <label class="custom-control-label" for="thousandth">千分位</label>
                     </div>
                     <div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" class="form-check-input" id="stage-rc" checked="">
-                        <label class="form-check-label" for="stage-rc">实际完成量</label>
+                        <input type="checkbox" class="custom-control-input" id="stage-rc" checked="">
+                        <label class="custom-control-label" for="stage-rc">实际完成量</label>
+                    </div>
+                    <div class="custom-control custom-checkbox mb-2">
+                        <input type="checkbox" class="custom-control-input" checked="" id="stage-correct">
+                        <label class="custom-control-label" for="stage-correct">使用数量纠正完成率</label>
                     </div>
                 </div>
             </div>
@@ -705,6 +796,9 @@
         $('#build-name').val(property.deal_info.buildName);
         $('#deal-code').val(property.deal_info.dealCode);
         $('#deal-name').val(property.deal_info.dealName);
+        $('#project-type').val(property.deal_info.projectType);
+        $('#deal-type').val(property.deal_info.dealType);
+        $('#final-code').val(property.deal_info.finalCode);
 
         // 参建单位
         // 建设单位
@@ -737,6 +831,14 @@
         $('#deal-period').val(property.tech_param.dealPeriod);
         $('#start-date').val(property.tech_param.startDate);
         $('#plan-end-date').val(property.tech_param.planEndDate);
+        $('#real-start-date').val(property.tech_param.realStartDate);
+        $('#real-end-date').val(property.tech_param.realEndDate);
+        $('#structure-scale').val(property.tech_param.structureScale);
+
+        // 中标信息
+        $('#control-price').val(property.bid_info.controlPrice);
+        $('#bid-price').val(property.bid_info.bidPrice);
+        $('#bid-start-date').val(property.bid_info.bidStartDate);
     }
 
     $('#bd-set-1').on('show.bs.modal', function () {
@@ -748,6 +850,9 @@
                 buildName: $('#build-name').val(),
                 dealCode: $('#deal-code').val(),
                 dealName: $('#deal-name').val(),
+                projectType: $('#project-type').val(),
+                dealType: $('#deal-type').val(),
+                finalCode: $('#final-code').val(),
             },
             construction_unit: {
                 build: {
@@ -785,6 +890,14 @@
                 dealPeriod: $('#deal-period').val(),
                 startDate: $('#start-date').val(),
                 planEndDate: $('#plan-end-date').val(),
+                realStartDate: $('#real-start-date').val(),
+                realEndDate: $('#real-end-date').val(),
+                structureScale: $('#structure-scale').val(),
+            },
+            bid_info: {
+                controlPrice: _.toNumber($('#control-price').val()),
+                bidPrice: _.toNumber($('#bid-price').val()),
+                bidStartDate: $('#bid-start-date').val(),
             }
         };
         const tenderId = window.location.pathname.split('/')[2];
@@ -792,6 +905,7 @@
             property.deal_info = data.deal_info;
             property.construction_unit = data.construction_unit;
             property.tech_param = data.tech_param;
+            property.bid_info = data.bid_info;
             $('#bd-set-1').modal('hide');
         });
     }
@@ -1197,6 +1311,7 @@
         $('#ledger-cl-qty')[0].checked = property.display.ledger.clQty;
         $('#thousandth')[0].checked = property.display.thousandth;
         $('#stage-rc')[0].checked = property.display.stage.realComplete;
+        $('#stage-correct')[0].checked = property.display.stage.correct;
     }
     $('#bd-set-5').on('show.bs.modal', function () {
         loadDisplayProperty();
@@ -1206,7 +1321,7 @@
             display: {
                 ledger: { dgnQty: $('#ledger-dgn-qty')[0].checked, clQty: $('#ledger-cl-qty')[0].checked, },
                 thousandth: $('#thousandth')[0].checked,
-                stage: { realComplete: $('#stage-rc')[0].checked, },
+                stage: { realComplete: $('#stage-rc')[0].checked, correct: $('#stage-correct')[0].checked },
             },
         };
         const tenderId = window.location.pathname.split('/')[2];

+ 19 - 0
builder_report_index_define.js

@@ -836,6 +836,13 @@ const gather_stage_bills = {
         { name: '(标段)变更-设计数量2', field: 't_c_dgn_qty2', type: dataType.currency },
 
         { name: '树结构-是否子项', field: 'is_leaf', type: dataType.int },
+
+        { name: '(合计)台账-设计数量1', field: 's_dgn_qty1', type: dataType.currency },
+        { name: '(合计)台账-设计数量2', field: 's_dgn_qty2', type: dataType.currency },
+        { name: '(合计)合同-设计数量1', field: 's_deal_dgn_qty1', type: dataType.currency },
+        { name: '(合计)合同-设计数量2', field: 's_deal_dgn_qty2', type: dataType.currency },
+        { name: '(合计)变更-设计数量1', field: 's_c_dgn_qty1', type: dataType.currency },
+        { name: '(合计)变更-设计数量2', field: 's_c_dgn_qty2', type: dataType.currency },
     ],
 };
 const gather_tender_info = {
@@ -922,6 +929,18 @@ const gather_tender_info = {
         { name: '付款账号-农民工工资专用账户-分账划拨比例(%)', field: 'pay_account.worker.rate', type: dataType.str },
         { name: '付款账号-农民工工资专用账户-联系人', field: 'pay_account.worker.contact', type: dataType.str },
         { name: '付款账号-农民工工资专用账户-联系电话', field: 'pay_account.worker.phone', type: dataType.str },
+
+        { name: '合同信息-工程类别', field: 'deal_info.projectType', type: dataType.str},
+        { name: '合同信息-合同类别', field: 'deal_info.dealType', type: dataType.str},
+        { name: '合同信息-结算书编号', field: 'deal_info.finalCode', type: dataType.str},
+
+        { name: '技术参数-实际开工日期', field: 'tech_param.realStartDate', type: dataType.str},
+        { name: '技术参数-实际完工日期', field: 'tech_param.realEndDate', type: dataType.str},
+        { name: '技术参数-构造物规模', field: 'tech_param.structureScale', type: dataType.str},
+
+        { name: '中标信息-业主控制价', field: 'bid_info.controlPrice', type: dataType.currency },
+        { name: '中标信息-中标价', field: 'bid_info.bidPrice', type: dataType.currency },
+        { name: '中标信息-开标日期', field: 'bid_info.bidStartDate', type: dataType.str },
     ],
 };
 const gather_stage_pay = {

+ 2 - 0
config/web.js

@@ -132,6 +132,7 @@ const JsFiles = {
                     '/public/js/path_tree.js',
                     '/public/js/ledger_tree_col.js',
                     '/public/js/std_lib.js',
+                    '/public/js/ledger_check.js',
                     '/public/js/ledger.js',
                 ],
                 mergeFile: 'explode',
@@ -304,6 +305,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/stage_im.js',
+                    '/public/js/ledger_check.js',
                     '/public/js/stage.js',
                     '/public/js/stage_audit.js',
                 ],

+ 3 - 60
sql/update.sql

@@ -1,71 +1,4 @@
-ALTER TABLE `zh_tender`
-ADD COLUMN `copy_id` INT(10) NULL COMMENT '被拷贝标段id' AFTER `uuid`;
+ALTER TABLE `zh_change` ADD `tp_decimal` TINYINT(3) NULL DEFAULT NULL COMMENT '金额位数' AFTER `sin_time`;
 
-
-ALTER TABLE `zh_change_audit_list` ADD `gcl_id` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '台账对应id(非准确)' AFTER `xmj_jldy`;
-UPDATE `zh_change_audit_list` SET `gcl_id`=`lid` WHERE `lid` != '0';
-
-ALTER TABLE `zh_s2b_proj`
-ADD COLUMN `merge_code`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `common_option`;
-
-CREATE TABLE `zh_tender_tag` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `tid` int(11) NOT NULL COMMENT '标段id',
-  `pid` int(11) NOT NULL COMMENT '项目id',
-  `ledger_time` datetime DEFAULT NULL COMMENT '台账分解审批完成时间',
-  `revise_time` datetime DEFAULT NULL COMMENT '最后一次台账修订审批完成时间',
-  `stage_time` datetime DEFAULT NULL COMMENT '最后一次期审批完成时间',
-  `bgl_time` datetime DEFAULT NULL COMMENT '最后一次变更令审批完成时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2049 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-CREATE TABLE `zh_s2b_proj_push` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `pid` int(11) NOT NULL COMMENT '项目id-zh_s2b_proj中的id',
-  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
-  `url` varchar(255) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '推送的url',
-  `ledger` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账审批通过-是否推送',
-  `revise` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账修订审批通过-是否推送',
-  `stage` tinyint(1) NOT NULL DEFAULT '1' COMMENT '期审批通过-是否推送',
-  `bgl` tinyint(1) NOT NULL DEFAULT '1' COMMENT '变更令审批通过-是否需要推送',
-  `add_time` datetime(4) DEFAULT NULL COMMENT '创建时间',
-  `lastest_time` datetime(4) DEFAULT NULL COMMENT '最后修改时间',
-  `push_time` datetime(4) DEFAULT NULL COMMENT '最近一次推送时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-Insert Into zh_tender_tag (tid, pid) Select id, project_id From zh_tender Where 1=1;
-
-CREATE TABLE `zh_s2b_proj_push` (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `pid` int(11) NOT NULL COMMENT '项目id-zh_s2b_proj中的id',
-  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
-  `url` varchar(255) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '推送的url',
-  `ledger` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账审批通过-是否推送',
-  `revise` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账修订审批通过-是否推送',
-  `stage` tinyint(1) NOT NULL DEFAULT '1' COMMENT '期审批通过-是否推送',
-  `bgl` tinyint(1) NOT NULL DEFAULT '1' COMMENT '变更令审批通过-是否需要推送',
-  `add_time` datetime(4) DEFAULT NULL COMMENT '创建时间',
-  `lastest_time` datetime(4) DEFAULT NULL COMMENT '最后修改时间',
-  `push_time` datetime(4) DEFAULT NULL COMMENT '最近一次推送时间',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-ALTER TABLE `zh_s2b_c_proj`
-ADD COLUMN `push_tender`  varchar(1000) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '推送的标段' AFTER `base_data`;
-
-ALTER TABLE `zh_s2b_proj`
-ADD COLUMN `filter_tender`  varchar(1000) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '过滤标段' AFTER `merge_code`;
-
-ALTER TABLE `zh_category_value` ADD `sort` int(11) DEFAULT NULL COMMENT '排序' AFTER `value`;
-UPDATE `zh_category_value` SET `sort`=`id`;
+ALTER TABLE `zh_tender_info`
+ADD COLUMN `bid_info`  varchar(200) NULL AFTER `tech_param`;

+ 68 - 0
sql/update20201126.sql

@@ -0,0 +1,68 @@
+ALTER TABLE `zh_tender`
+ADD COLUMN `copy_id` INT(10) NULL COMMENT '被拷贝标段id' AFTER `uuid`;
+
+
+ALTER TABLE `zh_change_audit_list` ADD `gcl_id` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '台账对应id(非准确)' AFTER `xmj_jldy`;
+UPDATE `zh_change_audit_list` SET `gcl_id`=`lid` WHERE `lid` != '0';
+
+-- sync2bim相关
+ALTER TABLE `zh_s2b_proj`
+ADD COLUMN `merge_code`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `common_option`;
+
+-- ----------------------------
+-- Table structure for zh_tender_tag
+-- ----------------------------
+CREATE TABLE `zh_tender_tag` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `pid` int(11) NOT NULL COMMENT '项目id',
+  `ledger_time` datetime DEFAULT NULL COMMENT '台账分解审批完成时间',
+  `revise_time` datetime DEFAULT NULL COMMENT '最后一次台账修订审批完成时间',
+  `stage_time` datetime DEFAULT NULL COMMENT '最后一次期审批完成时间',
+  `bgl_time` datetime DEFAULT NULL COMMENT '最后一次变更令审批完成时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2049 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+-- ----------------------------
+-- Table structure for zh_s2b_proj_push
+-- ----------------------------
+CREATE TABLE `zh_s2b_proj_push` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` int(11) NOT NULL COMMENT '项目id-zh_s2b_proj中的id',
+  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
+  `url` varchar(255) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '推送的url',
+  `ledger` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账审批通过-是否推送',
+  `revise` tinyint(1) NOT NULL DEFAULT '1' COMMENT '台账修订审批通过-是否推送',
+  `stage` tinyint(1) NOT NULL DEFAULT '1' COMMENT '期审批通过-是否推送',
+  `bgl` tinyint(1) NOT NULL DEFAULT '1' COMMENT '变更令审批通过-是否需要推送',
+  `add_time` datetime(4) DEFAULT NULL COMMENT '创建时间',
+  `lastest_time` datetime(4) DEFAULT NULL COMMENT '最后修改时间',
+  `push_time` datetime(4) DEFAULT NULL COMMENT '最近一次推送时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+Insert Into zh_tender_tag (tid, pid) Select id, project_id From zh_tender Where 1=1;
+
+-- ----------------------------
+-- Table structure for zh_s2b_push_log
+-- ----------------------------
+CREATE TABLE `zh_s2b_push_log` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` int(11) NOT NULL COMMENT '项目id',
+  `push_id` int(11) NOT NULL COMMENT '推送id',
+  `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '推送url',
+  `push_data` text COLLATE utf8_unicode_ci COMMENT '推送内容',
+  `push_time` datetime NOT NULL COMMENT '推送时间',
+  `push_result` text COLLATE utf8_unicode_ci COMMENT '推送结果',
+  `push_err` varchar(1000) CHARACTER SET utf8 DEFAULT NULL COMMENT '推送错误',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ALTER TABLE `zh_s2b_c_proj`
+ADD COLUMN `push_tender`  varchar(1000) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '推送的标段' AFTER `base_data`;
+
+ALTER TABLE `zh_s2b_proj`
+ADD COLUMN `filter_tender`  varchar(1000) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT '过滤标段' AFTER `merge_code`;
+
+ALTER TABLE `zh_category_value` ADD `sort` int(11) DEFAULT NULL COMMENT '排序' AFTER `value`;
+UPDATE `zh_category_value` SET `sort`=`id`;