瀏覽代碼

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

TonyKang 4 年之前
父節點
當前提交
9cd045a737

+ 2 - 0
app/base/base_bills_service.js

@@ -597,6 +597,7 @@ class BaseBillsSerivce extends TreeService {
                     c.ledger_pid = newBills.ledger_id;
                 }
                 const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, newBills.unit);
+                newBills.deal_qty = this.ctx.helper.round(d.deal_qty, precision.value);
                 if (d.pos && d.pos.length > 0) {
                     for (const pos of d.pos) {
                         const newPos = {
@@ -637,6 +638,7 @@ class BaseBillsSerivce extends TreeService {
                 newBills.sjcl_tp = this.ctx.helper.mul(newBills.qtcl_qty, newBills.unit_price, tpDecimal);
                 newBills.qtcl_tp = this.ctx.helper.mul(newBills.sjcl_qty, newBills.unit_price, tpDecimal);
                 newBills.total_price = this.ctx.helper.mul(newBills.quantity, newBills.unit_price, tpDecimal);
+                newBills.deal_tp = this.ctx.helper.mul(newBills.deal_qty, newBills.unit_price, tpDecimal);
                 if (defaultData) this.ctx.helper._.assignIn(newBills, defaultData);
                 pbd.push(newBills);
             }

+ 42 - 0
app/controller/schedule_controller.js

@@ -77,12 +77,21 @@ module.exports = app => {
             const tender = ctx.tender;
             const schedule = await ctx.service.schedule.getDataByCondition({ tid: tender.id });
             const scheduleMonth = await ctx.service.scheduleMonth.getAllDataByCondition({ where: { tid: tender.id }, orders: [['yearmonth', 'asc']] });
+            const stageOrderList = await ctx.service.stage.getAllDataByCondition({ columns: ['id', 'order'], where: { tid: tender.id } });
+            const scheduleStage = await ctx.service.scheduleStage.getAllDataByCondition({ where: { tid: tender.id } });
+            let curScheduleStage = scheduleStage.length > 0 ? scheduleStage[scheduleStage.length - 1] : null;
+            if (ctx.params.order && scheduleStage.length > 0) {
+                curScheduleStage = _.find(scheduleStage, { order: parseInt(ctx.params.order) });
+            }
             const renderData = {
                 tender: tender.data,
                 tenderInfo: tender.info,
                 schedule,
                 scheduleMonth,
                 measureType,
+                stageOrderList,
+                scheduleStage,
+                curScheduleStage,
                 scheduleLedgerList: await this._getSelectedLedgerList(ctx),
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.schedule.stageTp),
             };
@@ -181,6 +190,39 @@ module.exports = app => {
         }
 
         /**
+         * 计量进度金额模式计算方式提交(Ajax)
+         *
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveStageTp(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = {
+                    err: 0,
+                    msg: '',
+                    data: {},
+                };
+                switch (data.type) {
+                    case 'add_stage':
+                        responseData.data = await ctx.service.scheduleStage.add(data.postData);
+                        break;
+                    case 'del_stage':
+                        responseData.data = await ctx.service.scheduleStage.del(data.postData);
+                        break;
+                    case 'reload_stage':
+                        responseData.data = await ctx.service.scheduleStage.changeOrder(data.postData);
+                        break;
+                    default: throw '参数有误';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
+        /**
          * 计量进度工程量模式计算方式提交(Ajax)
          *
          * @param ctx

+ 2 - 0
app/controller/setting_controller.js

@@ -99,6 +99,7 @@ module.exports = app => {
 
                 // 过滤数据
                 ctx.service.projectAccount.searchFilter(ctx.request.query, projectId);
+                ctx.sort = ['id', 'desc'];
                 const total = await ctx.service.projectAccount.getCountWithBuilder();
 
                 // 获取数据规则
@@ -195,6 +196,7 @@ module.exports = app => {
                 // const rule = ctx.service.projectAccount.rule('updateUser');
                 // const frontRule = ctx.helper.validateConvert(rule);
                 const page = ctx.page;
+                ctx.sort = ['id', 'desc'];
                 const total = await ctx.service.projectAccount.count({ project_id: projectId });
                 // 获取项目用户列表
                 // const accountData = await ctx.service.projectAccount.getAllDataByCondition({

+ 7 - 6
app/lib/rpt_data_analysis.js

@@ -49,6 +49,7 @@ const valueCheck = {
         }
     },
     _checkString(ctx, value, condition) {
+        if (!value) return false;
         switch (condition.operate) {
             case '=':
                 return value === condition.value;
@@ -65,15 +66,15 @@ const valueCheck = {
             c.fun = this._typeFun[c.type];
         }
     },
-    checkData(data, condition) {
+    checkData(ctx, data, condition) {
         if (condition.length > 0) {
             let con = condition[0];
-            let result = this[con.fun](ctx, d[con.field], con);
+            let result = this[con.fun](ctx, data[con.field], con);
             for (let i = 1, iLen = condition.length; i < iLen; i++) {
                 con = condition[i];
                 result = (con.rela && con.rela === 'or')
-                    ? (result || this[con.fun](ctx, d[con.field], con))
-                    : (result && this[con.fun](ctx, d[con.field], con));
+                    ? (result || this[con.fun](ctx, data[con.field], con))
+                    : (result && this[con.fun](ctx, data[con.field], con));
             }
             return result;
         }
@@ -1695,7 +1696,7 @@ const treeFilter = {
     },
     _checkPath(matchPath, full_path) {
         for (const mp of matchPath) {
-            if (full_path.indexOf(mp) === 1) return true;
+            if (full_path.indexOf(mp) === 0) return true;
         }
         return false;
     },
@@ -1718,7 +1719,7 @@ const treeFilter = {
             }
         }
         data[options.table] = fData.filter(x => {
-            const match = self._checkPath(matchPath, x.full_path);
+            const match = self._checkPath(matchPath, x.full_path) && (options.subType === 'leaf' ? x.is_leaf : true);
             return options.type === 'match' ? match : !match;
         });
     },

+ 71 - 0
app/lib/stage_im.js

@@ -242,6 +242,72 @@ class StageIm {
             return result;
         }
     }
+    /**
+     * 获取 单位工程
+     *
+     * @param xmj - 计量单元(最底层项目节)
+     * @returns {string}
+     */
+    _getDwgc(peg, xmj) {
+        if (peg) {
+            return peg.name;
+        } else {
+            const node = this._getNodeByLevel(xmj, 2);
+            return node ? node.name : '';
+        }
+    }
+    /**
+     * 获取 分部工程
+     *
+     * @param peg - 桩号节点
+     * @param xmj - 计量单元(最底层项目节)
+     * @returns {string}
+     */
+    _getFbgc(peg, xmj) {
+        if (peg && peg.id !== xmj.id) {
+            const node = this._getNodeByLevel(xmj, peg.level + 1);
+            return node ? node.name : '';
+        } else {
+            const node = this._getNodeByLevel(xmj, 3);
+            return node ? node.name : '';
+        }
+    }
+    /**
+     * 获取 分项工程
+     *
+     * @param peg - 桩号节点
+     * @param xmj - 计量单元(最底层项目节)
+     * @returns {string}
+     */
+    _getFxgc(peg, xmj) {
+        if (!peg) {
+            const node = this._getNodeByLevel(xmj, 4);
+            return node ? node.name : '';
+        } else if (peg.id === xmj.id) {
+            if (xmj.level > 4) {
+                let value = '';
+                for (let level = 4; level < xmj.level; level++) {
+                    const node = this._getNodeByLevel(xmj, level);
+                    value = value === '' ? node.name : value + mergeChar + node.name;
+                }
+                return value;
+            } else {
+                return '';
+            }
+        } else {
+            if (peg.level + 2 < xmj.level) {
+                let value = '';
+                for (let level = peg.level + 2; level < xmj.level; level++) {
+                    const node = this._getNodeByLevel(xmj, level);
+                    value = value === '' ? node.name : value + mergeChar + node.name;
+                }
+                return value;
+            } else {
+                return '';
+            }
+        }
+    }
+
 
     _checkCustomDetail(im) {
         const self = this;
@@ -457,6 +523,7 @@ class StageIm {
             pre_jl: node.pre_gather_tp, pre_contract_jl: node.pre_contract_tp, pre_qc_jl: node.pre_qc_tp,
             end_jl: node.end_gather_tp, end_contract_jl: node.end_contract_tp, end_qc_jl: node.end_qc_tp,
             peg: peg ? this._getPegStr(peg.name) : '', drawing_code: this._getDrawingCode(node),
+            dwgc: this._getDwgc(peg, node), fbgc: this._getFbgc(peg, node), fxgc: this._getFxgc(peg, node),
             position: '',
             lIndex: nodeIndex,
         };
@@ -564,6 +631,7 @@ class StageIm {
             lIndex: index,
             bw: bw, jldy: node.name,
             changes: [], gclBills: [],
+            dwgc: this._getDwgc(peg, node), fbgc: this._getFbgc(peg, node), fxgc: this._getFxgc(peg, node),
         };
         this._checkCustomDetail(im);
         return im;
@@ -746,6 +814,7 @@ class StageIm {
                     peg: peg ? this._getPegStr(peg.name) : '',
                     position: '',
                     lIndex: nodeIndex,
+                    dwgc: this._getDwgc(peg, node), fbgc: this._getFbgc(peg, node), fxgc: this._getFxgc(peg, node),
                 };
                 if (this.ctx.stage.im_gather && node.check) {
                     im.check = true;
@@ -817,6 +886,7 @@ class StageIm {
                         end_jl: pp.end_gather_qty, end_contract_jl: pp.end_contract_qty, end_qc_jl: pp.end_qc_qty,
                         bw,
                         peg: this._checkPeg(pp.name) ? this._getPegStr(pp.name) : (peg ? this._getPegStr(peg.name) : ''),
+                        dwgc: this._getDwgc(peg, node), fbgc: this._getFbgc(peg, node), fxgc: this._getFxgc(peg, node),
                         xm: pp.name, jldy: pp.name,
                         drawing_code: pp.drawing_code,
                         changes: [],
@@ -859,6 +929,7 @@ class StageIm {
                     end_tp: p.end_gather_tp, end_contract_tp: p.end_contract_tp, end_qc_tp: p.end_qc_tp,
                     bw,
                     peg: peg ? this._getPegStr(peg.name) : '',
+                    dwgc: this._getDwgc(peg, node), fbgc: this._getFbgc(peg, node), fxgc: this._getFxgc(peg, node),
                     xm: node.name,
                     drawing_code: this._getDrawingCode(p),
                     changes: [],

+ 8 - 11
app/public/css/main.css

@@ -51,8 +51,14 @@ font-size: .875rem;
 .input-group-text .group-checkbox[type="checkbox"],.input-group-text .group-checkbox[type="radio"]{
   margin-top: .3rem;
 }
-.custom-control {
-  min-height: 1.2rem
+.custom-control-label::before {
+  top:.1rem;
+}
+.custom-control-label::after{
+  top:.1rem;
+}
+.custom-switch .custom-control-label::after{
+  top:.25rem;
 }
 .custom-control-label {
   cursor: pointer;
@@ -73,12 +79,6 @@ font-size: .875rem;
 .custom-control-warning-label{
   color:#da9500;
 }
-.custom-control-label::before{
-  top:.15rem;
-}
-.custom-control-label::after{
-  top:.15rem;
-}
 /*
 .btn.disabled, .btn:disabled {
   opacity:.4
@@ -1086,9 +1086,6 @@ legend {
   padding:.2em .4em;
   top:0;
 }
-.custom-switch .custom-control-label::after{
-  top:.25rem;
-}
 .search-group {
   position: relative;
 }

+ 1 - 10
app/public/css/main_s.css

@@ -68,17 +68,11 @@ font-size: .875rem;
 }
 .custom-control-warning-input:checked ~ .custom-control-warning-label::before{
   border-color:#da9500 ;
-  background-color:#da9500 
+  background-color:#da9500
 }
 .custom-control-warning-label{
   color:#da9500;
 }
-.custom-control-label::before{
-  top:.15rem;
-}
-.custom-control-label::after{
-  top:.15rem;
-}
 /*
 .btn.disabled, .btn:disabled {
   opacity:.4
@@ -1089,9 +1083,6 @@ legend {
   padding:.2em .4em;
   top:0;
 }
-.custom-switch .custom-control-label::after{
-  top:.25rem;
-}
 .search-group {
   position: relative;
 }

+ 29 - 3
app/public/js/change_information_set.js

@@ -16,10 +16,34 @@ function sortByCode(a, b) {
     for (let i = 0; i < code1length; i ++) {
         if (i+1 <= code2length) {
             if (code1[i] != code2[i]) {
-                if (!/^\d+$/.test(code1[i])) {
-                    return code1[i].charCodeAt() - code2[i].charCodeAt();
-                } else {
+                if (/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
                     return parseInt(code1[i]) - parseInt(code2[i]);
+                } else if (!/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
+                    return 1;
+                } else if (/^\d+$/.test(code1[i]) && !/^\d+$/.test(code2[i])) {
+                    return -1;
+                } else {
+                    const str1length = code1[i].length;
+                    const str2length = code2[i].length;
+                    for (let j = 0; j < str1length; j++) {
+                        if (j+1 <= str2length) {
+                            if (code1[i].charAt(j) != code2[i].charAt(j)) {
+                                return code1[i].charAt(j).charCodeAt() - code2[i].charAt(j).charCodeAt();
+                            }  else if (j+1 == str1length && code1[i].charAt(j) == code2[i].charAt(j)) {
+                                if (str1length == str2length) {
+                                    return 0;
+                                } else {
+                                    return str1length - str2length;
+                                }
+                            }
+                        } else {
+                            if (j+1 >= str1length) {
+                                return 1;
+                            } else {
+                                return -1;
+                            }
+                        }
+                    }
                 }
             } else if (i+1 == code1length && code1[i] == code2[i]) {
                 if (code1length == code2length) {
@@ -368,7 +392,9 @@ $(document).ready(() => {
                 dealBillList.splice(exist_index, 1);
             }
         }
+        console.log(gclGatherData.concat(dealBillList));
         changeListData = gclGatherData.concat(dealBillList).sort(sortByCode);
+        console.log(changeListData);
         // 先加载台账数据
         let listHtml = '';
         let list_index = 1;

+ 60 - 2
app/public/js/ledger_bwtz.js

@@ -22,12 +22,58 @@ $(document).ready(() => {
     if (thousandth) sjsSettingObj.setTpThousandthFormat(xmjSpreadSetting);
     SpreadJsObj.initSheet(unitSheet, unitSpreadSetting);
 
+    const filterUnitTree = createNewPathTree('filter', {
+        id: 'ledger_id',
+        pid: 'ledger_pid',
+        order: 'order',
+        level: 'level',
+        rootId: -1,
+        fullPath: 'full_path',
+    });
+
     const unitTreeObj = {
+        getFilterUnitTree: function (unitTree) {
+            const filter = $('#unit-filter').val();
+            if (!filter || unitTree.nodes.length === 0) return unitTree;
+            filterUnitTree.clearDatas();
+            const filterPath = [];
+            const checkFullPath = function (checkPath, valuePath) {
+                if (valuePath.indexOf(checkPath + '-') >= 0) return true;
+
+                const pathArray = checkPath.split('-');
+                const tmpArray = [];
+                for (let i = 0, iLen = pathArray.length; i < iLen; i++) {
+                    tmpArray.push(pathArray.slice(0, i+1).join('-'));
+                }
+                for (const ta of tmpArray) {
+                    if (ta === valuePath) return true;
+                }
+                return false;
+            };
+            for (const node of unitTree.nodes) {
+                if ((node.code && node.code.indexOf(filter) >= 0) || (node.b_code && node.b_code.indexOf(filter) >= 0)
+                    || (node.name && node.name.indexOf(filter) >= 0) || (node.pos_name && node.pos_name.indexOf(filter) >= 0))
+                    filterPath.push(node.full_path);
+            }
+            for (const node of unitTree.nodes) {
+                for (const fp of filterPath) {
+                    if (checkFullPath(fp, node.full_path)) {
+                        filterUnitTree.addData(node, ['id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'pos_name',
+                            'code', 'b_code', 'name', 'unit', 'unit_price', 'quantity', 'total_price', 'drawing_code_merge', 'memo_merge']);
+                        break;
+                    }
+                }
+            }
+            filterUnitTree.sortTreeNode();
+            return filterUnitTree;
+        },
         loadCurUnitData: function () {
             const node = SpreadJsObj.getSelectObject(xmjSheet);
             SpreadJsObj.resetTopAndSelect(unitSheet);
             if (node && node.unitTree) {
-                SpreadJsObj.loadSheetData(unitSheet, SpreadJsObj.DataType.Tree, node.unitTree);
+                const relaTree = unitTreeObj.getFilterUnitTree(node.unitTree);
+                if ($('#unit-show-1')[0].checked) relaTree.expandByLevel(1);
+                SpreadJsObj.loadSheetData(unitSheet, SpreadJsObj.DataType.Tree, relaTree);
             } else {
                 SpreadJsObj.initSheet(unitSheet, unitSpreadSetting);
             }
@@ -55,7 +101,6 @@ $(document).ready(() => {
                 n.unitTree.loadDatas(n.unitTreeData);
             }
         }
-        console.log(xmjTree);
         SpreadJsObj.loadSheetData(xmjSheet, SpreadJsObj.DataType.Tree, xmjTree);
         unitTreeObj.loadCurUnitData();
     });
@@ -170,6 +215,19 @@ $(document).ready(() => {
         xmjSpread.refresh();
         unitSpread.refresh();
     });
+    $('#unit-filter').bind('keydown', function (e) {
+        const evt = window.event || e;
+        if (e.keyCode == 13) unitTreeObj.loadCurUnitData();
+    });
+    $('#unit-show-1').bind('change', function () {
+        if (this.checked) {
+            unitSheet.zh_tree.expandByLevel(1);
+            SpreadJsObj.refreshTreeRowVisible(unitSheet);
+        } else {
+            unitSheet.zh_tree.expandByCustom(() => { return true; });
+            SpreadJsObj.refreshTreeRowVisible(unitSheet);
+        }
+    });
 
     // 显示层次
     (function (select, sheet) {

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

@@ -1407,6 +1407,12 @@ const createNewPathTree = function (type, setting) {
     }
 
     class FilterTree extends BaseTree {
+        clearDatas() {
+            this.items = {};
+            this.nodes = [];
+            this.datas = [];
+            this.children = [];
+        }
         addData(data, fields) {
             const item = {};
             for (const prop in data) {

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

@@ -53,7 +53,7 @@ $(function () {
     const monthsCols = [];
     if(scheduleMonth.length > 0) {
         for (const sm of scheduleMonth) {
-            if (sm.stage_used === 1) {
+            if (sm.stage_gcl_used === 1) {
                 const yearmonth = sm.yearmonth.split('-')[0] + '年' + parseInt(sm.yearmonth.split('-')[1]) + '月';
                 const cols = {title: yearmonth + '|计划工程量', colSpan: '4|1', rowSpan: '1|1', field: sm.yearmonth+'_plan_gcl', hAlign: 2, width: 90, type: 'Number', readOnly: true};
                 const cols2 = {title: '|计划金额(万元)', colSpan: '|1', rowSpan: '|1', field: sm.yearmonth+'_plan_tp', hAlign: 2, width: 90, type: 'Number', readOnly: true};
@@ -96,7 +96,7 @@ $(function () {
         const showList = ['ledger_id', 'ledger_pid', 'order', 'level', 'tender_id', 'full_path',
             'code', 'name', 'unit', 'dgn_qty1', 'dgn_qty2', 'dgn_price', 'quantity', 'total_price'];
         for (const m of scheduleMonth) {
-            if (m.stage_used === 1) {
+            if (m.stage_gcl_used === 1) {
                 showList.push(m.yearmonth + '_plan_tp');
                 showList.push(m.yearmonth + '_plan_gcl');
                 showList.push(m.yearmonth + '_sj_tp');
@@ -385,7 +385,7 @@ function setMonthToLedger(ledgerList, slm) {
     if (slm.length > 0) {
         for(const s of slm) {
             const index = _.findIndex(ledgerList, { 'ledger_id': s.lid });
-            const canCalc = _.find(scheduleMonth, { 'yearmonth': s.yearmonth, 'stage_used': 1});
+            const canCalc = _.find(scheduleMonth, { 'yearmonth': s.yearmonth, 'stage_gcl_used': 1});
             if (index && index !== -1 && canCalc) {
                 ledgerList[index][s.yearmonth + '_plan_tp'] = s.plan_tp;
                 ledgerList[index][s.yearmonth + '_plan_gcl'] = s.plan_gcl;

+ 93 - 213
app/public/js/schedule_stage_tp.js

@@ -22,9 +22,6 @@ $(function () {
         level: 'level',
         rootId: -1,
         fullPath: 'full_path',
-        //treeCacheKey: 'ledger_bills_fold' + '_' + getTenderId(),
-        // markFoldKey: 'bills-fold',
-        // markFoldSubKey: window.location.pathname.split('/')[2],
     };
     const ledgerTree = createNewPathTree('filter', treeSetting);
 
@@ -37,16 +34,16 @@ $(function () {
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '自开工至本月计划完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '截止本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '截止本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'end_gather_qty', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'end_gather_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本年计划完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本年累计完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本月计划完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'gather_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '下月计划|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
     ];
@@ -71,59 +68,70 @@ $(function () {
     SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
     SpreadJsObj.selChangedRefreshBackColor(ledgerSpread.getActiveSheet());
 
-    postData('/tender/' + getTenderId() + '/schedule/ledger/load', {}, function (data) {
-        // let treeData = [];
-        // for(const sl of selectedLedgerList) {
-        //     const one = _.find(data, { 'ledger_id' : sl });
-        //     treeData.push(one);
-        // }
-        // treeData = setLeafData(treeData);
-        // console.log(treeData);
-        // let treeData = data;
-        const calcList = ['total_price'];
-        const showList = ['ledger_id', 'ledger_pid', 'order', 'level', 'tender_id', 'full_path',
-            'code', 'name', 'unit', 'dgn_qty1', 'dgn_qty2', 'dgn_price', 'quantity', 'total_price'];
-        for (const m of scheduleMonth) {
-            if (m.stage_used === 1) {
-                showList.push(m.yearmonth + '_plan_tp');
-                showList.push(m.yearmonth + '_plan_gcl');
-                showList.push(m.yearmonth + '_sj_tp');
-                showList.push(m.yearmonth + '_sj_gcl');
-            }
-            // calcList.push(m + '_tp');
-            // calcList.push(m + '_gcl');
-        }
-        const baseLedgerTree = createNewPathTree('base', {
-            id: 'ledger_id',
-            pid: 'ledger_pid',
-            order: 'order',
-            level: 'level',
-            rootId: -1,
-            fullPath: 'full_path',
-            calcFields: calcList,
-            calcFun: function (node) {
+    if (curScheduleStage && curScheduleStage.order) {
+        postData('/tender/' + getTenderId() + '/measure/stage/' + curScheduleStage.order + '/load', { filter: 'ledger' }, function (data) {
+            const calcList = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
+                'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp'];
+            const showList = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'ledger_id', 'ledger_pid', 'order', 'level', 'tender_id', 'full_path',
+                'code', 'name', 'unit', 'dgn_qty1', 'dgn_qty2', 'dgn_price', 'quantity', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
+                'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp'];
+            const baseLedgerTreeSetting = {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                fullPath: 'full_path',
+                calcFields: calcList,
+            };
+            baseLedgerTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil', 'used', 'contract_expr'];
+            baseLedgerTreeSetting.calcFun = function (node) {
+                if (!node.children || node.children.length === 0) {
+                    node.pre_gather_qty = ZhCalc.add(node.pre_contract_qty, node.pre_qc_qty);
+                    node.gather_qty = ZhCalc.add(node.contract_qty, node.qc_qty);
+                    node.end_contract_qty = ZhCalc.add(node.pre_contract_qty, node.contract_qty);
+                    node.end_qc_qty = ZhCalc.add(node.pre_qc_qty, node.qc_qty);
+                    node.end_gather_qty = ZhCalc.add(node.pre_gather_qty, node.gather_qty);
+                }
+                node.pre_gather_tp = ZhCalc.add(node.pre_contract_tp, node.pre_qc_tp);
+                node.gather_tp = ZhCalc.add(node.contract_tp, node.qc_tp);
+                node.end_contract_tp = ZhCalc.add(node.pre_contract_tp, node.contract_tp);
+                node.end_qc_tp = ZhCalc.add(node.pre_qc_tp, node.qc_tp);
+                node.end_gather_tp = ZhCalc.add(node.pre_gather_tp, node.gather_tp);
+                node.end_final_tp = ZhCalc.add(node.end_qc_tp, node.total_price);
+                if (!node.children || node.children.length === 0) {
+                    if (node.end_contract_qty) {
+                        node.end_correct_tp = ZhCalc.add(node.end_qc_tp, ZhCalc.mul(node.end_contract_qty, node.unit_price, tenderInfo.decimal.tp));
+                    } else {
+                        node.end_correct_tp = node.end_gather_tp;
+                    }
+                }
+                node.end_gather_percent = ZhCalc.mul(ZhCalc.div(node.end_gather_tp, node.end_final_tp), 100, 2);
+                node.end_correct_percent = ZhCalc.mul(ZhCalc.div(node.end_correct_tp, node.end_final_tp), 100, 2);
+                node.final_dgn_price = ZhCalc.round(ZhCalc.div(node.end_gather_tp, ZhCalc.add(node.deal_dgn_qty1, node.c_dgn_qty1)), tenderInfo.decimal.up);
                 node.dgn_price = ZhCalc.round(ZhCalc.div(node.total_price, node.dgn_qty1), 2);
-            }
-        });
-        const newLedgerList = setMonthToLedger(data.bills, data.slm);
-        baseLedgerTree.loadDatas(newLedgerList);
-        treeCalc.calculateAll(baseLedgerTree);
-        console.log(baseLedgerTree);
-        for (const d of baseLedgerTree.nodes) {
-            if (!d.b_code) {
-                const one = _.find(selectedLedgerList, function (item) {
-                    return item === d.ledger_id;
-                });
-                if(one) {
-                    ledgerTree.addData(d, showList);
+            };
+            const baseLedgerTree = createNewPathTree('base', baseLedgerTreeSetting);
+            // const newLedgerList = setMonthToLedger(data.bills, data.slm);
+            baseLedgerTree.loadDatas(data.ledgerData);
+            treeCalc.calculateAll(baseLedgerTree);
+            console.log(baseLedgerTree);
+            for (const d of baseLedgerTree.nodes) {
+                if (!d.b_code) {
+                    const one = _.find(selectedLedgerList, function (item) {
+                        return item === d.ledger_id;
+                    });
+                    if(one) {
+                        ledgerTree.addData(d, showList);
+                    }
                 }
             }
-        }
-        console.log(ledgerTree);
-        ledgerTree.sortTreeNode(true);
-        // console.log(ledgerTree);
-        SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
-    }, null, true);
+            console.log(ledgerTree);
+            ledgerTree.sortTreeNode(true);
+            // console.log(ledgerTree);
+            SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
+        }, null, true);
+    }
 
     const ledgerSpreadObj = {
         refreshTree: function (sheet, data) {
@@ -175,183 +183,55 @@ $(function () {
                 }
             });
         },
-        editEnded: function (e, info) {
-            if (info.sheet.zh_setting) {
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                const col = info.sheet.zh_setting.cols[info.col];
-                const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
-                const orgValue = select[col.field];
-                if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
-                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                    return;
-                }
-                if (isNaN(validText)) {
-                    toastr.error('不能输入其它非数字类型字符');
-                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                    return;
-                }
-                const yearmonth = col.field.split('_')[0];
-                // 判断输入位数,提示
-                const reg = new RegExp('^([-]?)\\d+(\\.\\d{0,'+ parseInt(tenderInfo.decimal.up) +'})?$');
-                if (validText !== null && (!reg.test(validText))) {
-                    toastr.error('输入工程量小数位数不能大于' + tenderInfo.decimal.up + '位');
-                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                    return;
-                }
-                const sj_gcl = validText;
-                const sj_tp = select.dgn_price && select.dgn_price !== 0 ? ZhCalc.round(ZhCalc.mul(validText, select.dgn_price), tenderInfo.decimal.tp) : 0;
-                select[col.field] = validText;
-                const updateData = {
-                    lid: select.ledger_id,
-                    yearmonth,
-                    sj_gcl,
-                    sj_tp,
-                };
-                console.log(updateData);
-                postData(window.location.pathname + '/save', {type: 'ledger_edit', postData: updateData}, function (result) {
-                    select[yearmonth + '_sj_tp'] = sj_tp;
-                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                },function () {
-                    select[col.field] = orgValue;
-                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                })
-            }
-        },
-        deletePress: function (sheet) {
-            return;
-        },
-        clipboardPasted(e, info) {
-            const hint = {
-                cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
-                numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
-                numberCan: {type: 'error', msg: '请粘贴大于0并且小于3位小数的浮点数'},
-            };
-            const range = info.cellRange;
-            const sortData = info.sheet.zh_data || [];
-            if (info.cellRange.row + info.cellRange.rowCount > sortData.length) {
-                toastMessageUniq(hint.cellError);
-                SpreadJsObj.reLoadSheetHeader(materialMonthSpread.getActiveSheet());
-                SpreadJsObj.reLoadSheetData(materialMonthSpread.getActiveSheet());
-                return;
-            }
-            if (sortData.length > 0 && range.col + range.colCount > 4 + months.length) {
-                toastMessageUniq(hint.cellError);
-                SpreadJsObj.reLoadSheetHeader(materialMonthSpread.getActiveSheet());
-                SpreadJsObj.reLoadSheetData(materialMonthSpread.getActiveSheet());
-                return;
-            }
-            const data = [];
-            for (let iRow = 0; iRow < range.rowCount; iRow++) {
-                let bPaste = true;
-                const curRow = range.row + iRow;
-                const materialMonthData = sortData[curRow];
-                const hintRow = range.rowCount > 1 ? curRow : '';
-                let sameCol = 0;
-                for (let iCol = 0; iCol < range.colCount; iCol++) {
-                    const curCol = range.col + iCol;
-                    const colSetting = info.sheet.zh_setting.cols[curCol];
-                    if (!colSetting) continue;
-
-                    let validText = info.sheet.getText(curRow, curCol);
-                    validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
-                    const orgValue = sortData[curRow][colSetting.field];
-                    if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
-                        sameCol++;
-                        if (range.colCount === sameCol)  {
-                            bPaste = false;
-                        }
-                        continue;
-                    }
-                    const num = parseFloat(validText);
-                    if (isNaN(validText)) {
-                        toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
-                        bPaste = false;
-                        continue;
-                    }
-                    if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
-                        toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
-                        bPaste = false;
-                        continue;
-                    }
-                    materialMonthData[colSetting.field] = validText;
-                    sortData[curRow][colSetting.field] = validText;
-                }
-                if (bPaste) {
-                    data.push(materialMonthData);
-                } else {
-                    SpreadJsObj.reLoadRowData(info.sheet, curRow);
-                }
-            }
-            if (data.length === 0) {
-                SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
-                return;
-            }
-            // // 更新至服务器
-            // postData(window.location.pathname + '/month/save', { type:'paste', updateData: data }, function (result) {
-            //     SpreadJsObj.reLoadSheetData(materialMonthSpread.getActiveSheet());
-            //     materialBillsData = result.materialBillsData;
-            //     SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
-            //     m_tp = result.m_tp;
-            //     resetTpTable();
-            // }, function () {
-            //     SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
-            //     return;
-            // });
-        },
     };
 
-    ledgerSpread.bind(spreadNS.Events.EditEnded, ledgerSpreadObj.editEnded);
-    SpreadJsObj.addDeleteBind(ledgerSpread, ledgerSpreadObj.deletePress);
-
-    // 月份添加
-    $('#add-month').click(function () {
-        const id = parseInt($('#month-select').val());
-        if(id === 0) {
+    $('#add-stage').click(function () {
+        const yearmonth = $('#month_list').val();
+        const order = parseInt($('#stage_list').val());
+        if (yearmonth === '0') {
             toastr.error('请选择计划进度月');
             return;
         }
+        if (order === 0) {
+            toastr.error('请选择计量期');
+            return;
+        }
         const _self = $(this);
-        postData(window.location.pathname + '/save', {type: 'add_stage', postData: { id: id }}, function (result) {
+        postData(window.location.pathname + '/save', {type: 'add_stage', postData: { yearmonth, order }}, function (result) {
             _self.addClass('disabled').attr('disabled', true);
-            toastr.success('创建成功');
+            toastr.success('新增成功');
             setTimeout(function () {
                 window.location.reload();
             }, 500)
         })
     });
 
-    $('#month-table input[type="checkbox"]').click(function () {
-        const selectedMonth = [];
-        $('#month-table input:checkbox:checked').each(function () {
-            selectedMonth.push('「' + $(this).parents('td').siblings('td').text() + '」');
-        });
-        if(selectedMonth.length > 0) {
-            $('#del-month-list').text(selectedMonth.join(''));
-            $('#del-month-list').parent().show();
-            $('#del-month').removeAttr('disabled');
-        } else {
-            $('#del-month-list').parent().hide();
-            $('#del-month').attr('disabled', true);
+    $('#reload-stage').click(function () {
+        const order = parseInt($('#reload-stage-list').val());
+        const id = parseInt($(this).data('id'));
+        if (order === 0) {
+            toastr.error('请选择计量期');
+            return;
         }
+        const _self = $(this);
+        postData('/tender/'+ getTenderId() + '/schedule/stage/save', {type: 'reload_stage', postData: { id, order }}, function (result) {
+            _self.addClass('disabled').attr('disabled', true);
+            toastr.success('重新生成成功');
+            setTimeout(function () {
+                window.location.href = '/tender/'+ getTenderId() + '/schedule/stage/order/' + order;
+            }, 500)
+        })
     });
 
-    $('#del-month').click(function () {
-        const selectedMonth = [];
-        $('#month-table input:checkbox:checked').each(function () {
-            selectedMonth.push($(this).parents('td').siblings().text());
-        });
-        if (selectedMonth.length === 0) {
-            toastr.error('请选择删除的计划周期');
-            return;
-        }
+    $('#del-stage').click(function () {
+        const id = parseInt($(this).data('id'));
         const _self = $(this);
-        postData(window.location.pathname + '/save', {type: 'del_stage', postData: selectedMonth}, function (result) {
+        postData('/tender/'+ getTenderId() + '/schedule/stage/save', {type: 'del_stage', postData: { id }}, function (result) {
             _self.addClass('disabled').attr('disabled', true);
             toastr.success('删除成功');
             setTimeout(function () {
-                window.location.reload();
+                window.location.href = '/tender/'+ getTenderId() + '/schedule/stage';
             }, 500)
-
         })
     });
 

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

@@ -270,12 +270,31 @@ $(document).ready(() => {
             });
             return cur.indexOf(bonusData) === cur.length - 1;
         }
+        sum () {
+            const result = {
+                tp: 0,
+            };
+            for (const d of this.data) {
+                result.tp = ZhCalc.add(result.tp, d.tp);
+            }
+            return result;
+        }
     }
     const bonusObj = new Bonus();
+    const refreshSum = function () {
+        const sum = bonusObj.sum();
+        const html = [];
+        const getTrHtml = function (name, value) {
+            return '<tr><td>' + name + '</td><td class="text-right">' + (!checkZero(value) ? value : '') + ' </td></tr>';
+        };
+        html.push(getTrHtml('金额', sum.tp));
+        $('#sum').html(html.join(' '));
+    };
 
     postData(window.location.pathname + '/load', null, function (result) {
         bonusObj.loadDatas(result);
         SpreadJsObj.loadSheetData(bonusSheet, SpreadJsObj.DataType.Data, bonusObj.data);
+        refreshSum();
     });
 
     if (!readOnly) {
@@ -322,6 +341,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', {update: datas}, function (result) {
                         bonusObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(bonusSheet);
+                        refreshSum();
                     }, function () {
                         SpreadJsObj.reLoadSheetData(bonusSheet);
                     });
@@ -357,6 +377,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', {del: datas}, function (result) {
                         bonusObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(sheet);
+                        refreshSum();
                     }, function () {
                         SpreadJsObj.reLoadSheetData(sheet);
                     });
@@ -394,6 +415,7 @@ $(document).ready(() => {
                 postData(window.location.pathname + '/update', data, function (result) {
                     bonusObj.loadUpdateData(result);
                     SpreadJsObj.reLoadSheetData(info.sheet);
+                    refreshSum();
                 }, function () {
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                 });
@@ -457,6 +479,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', updateData, function (result) {
                         bonusObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(info.sheet);
+                        refreshSum();
                     });
                 } else {
                     SpreadJsObj.reLoadSheetData(info.sheet);

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

@@ -162,12 +162,37 @@ $(document).ready(() => {
             this.calculateAll();
             this.resortData();
         }
+        sum () {
+            const result = {
+                total_price: 0,
+                tp: 0,
+                end_tp: 0,
+            };
+            for (const d of this.data) {
+                result.total_price = ZhCalc.add(result.total_price, d.total_price);
+                result.tp = ZhCalc.add(result.tp, d.tp);
+                result.end_tp = ZhCalc.add(result.end_tp, d.end_tp);
+            }
+            return result;
+        }
     }
     const seOtherObj = new SeOther();
+    const refreshSum = function () {
+        const sum = seOtherObj.sum();
+        const html = [];
+        const getTrHtml = function (name, value) {
+            return '<tr><td>' + name + '</td><td class="text-right">' + (!checkZero(value) ? value : '') + ' </td></tr>';
+        };
+        html.push(getTrHtml('金额', sum.total_price));
+        html.push(getTrHtml('本期金额', sum.tp));
+        html.push(getTrHtml('截止本期金额', sum.end_tp));
+        $('#sum').html(html.join(' '));
+    };
 
     postData(window.location.pathname + '/load', null, function (result) {
         seOtherObj.loadDatas(result);
         SpreadJsObj.loadSheetData(otherSheet, SpreadJsObj.DataType.Data, seOtherObj.data);
+        refreshSum();
     });
 
     if (!readOnly) {
@@ -211,6 +236,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', {update: datas}, function (result) {
                         seOtherObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(otherSheet);
+                        refreshSum();
                     }, function () {
                         SpreadJsObj.reLoadSheetData(otherSheet);
                     });
@@ -245,6 +271,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', {del: datas}, function (result) {
                         seOtherObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(otherSheet);
+                        refreshSum();
                     }, function () {
                         SpreadJsObj.reLoadSheetData(otherSheet);
                     });
@@ -282,6 +309,7 @@ $(document).ready(() => {
                 postData(window.location.pathname + '/update', data, function (result) {
                     seOtherObj.loadUpdateData(result);
                     SpreadJsObj.reLoadSheetData(info.sheet);
+                    refreshSum();
                 }, function () {
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                 });
@@ -362,6 +390,7 @@ $(document).ready(() => {
                     postData(window.location.pathname + '/update', updateData, function (result) {
                         seOtherObj.loadUpdateData(result);
                         SpreadJsObj.reLoadSheetData(info.sheet);
+                        refreshSum();
                     });
                 } else {
                     SpreadJsObj.reLoadSheetData(info.sheet);

+ 16 - 42
app/public/js/shenpi.js

@@ -645,7 +645,7 @@ $(document).ready(function () {
         },
         setAllRightPwd: function(uid) {
             selects = [];
-            for (const l of ledgerTree.datas) {
+            for (const l of ledgerTree.nodes) {
                 const coo = _.find(ledger_cooperation_list, { 'ledger_id': l.ledger_id, 'user_id': parseInt(uid) });
                 if (l.pwd && !coo) {
                     delete l.pwd;
@@ -781,7 +781,7 @@ $(document).ready(function () {
                         flag = false;
                     }
                     $('#cooperation-num').text(ledger_cooperation_list.length);
-                    setLeftTable(ledgerTree.datas, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
+                    setLeftTable(ledgerTree.nodes, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
                     selects = [select];
                     // if(select) {
                     //     setAllChildrenCanEdit(select, flag);
@@ -841,7 +841,7 @@ $(document).ready(function () {
             }
             $('#stage_audits').html(newhtml);
             if(ledger_data) {
-                setLeftTable(ledgerTree.datas, ledger_cooperation_list, cur_uid, yb.name + '(原报)');
+                setLeftTable(ledgerTree.nodes, ledger_cooperation_list, cur_uid, yb.name + '(原报)');
                 ledgerSpreadObj.setAllRightPwd(cur_uid);
             }
         }
@@ -850,14 +850,14 @@ $(document).ready(function () {
                 ledger_data = true;
                 const ledgerList = setRightData(data.ledgerList, data.ledgerCooperationList);
                 ledgerTree.loadDatas(ledgerList);
-                ledger_cooperation_list = data.ledgerCooperationList;
-                const yb = _.find(accountList, { 'id': cur_uid });
-                setLeftTable(ledgerList, ledger_cooperation_list, cur_uid, yb.name + '(原报)');
                 // treeCalc.calculateAll(ledgerTree);
                 selects = [];
                 // updateByCanEdit(ledgerTree.nodes, _.filter(ledger_cooperation_list, { user_id: cur_uid }), false);
                 ledgerTree.loadPostData({update: selects});
                 console.log(ledgerTree);
+                ledger_cooperation_list = data.ledgerCooperationList;
+                const yb = _.find(accountList, { 'id': cur_uid });
+                setLeftTable(ledgerTree.nodes, ledger_cooperation_list, cur_uid, yb.name + '(原报)');
                 SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
                 ledgerSpreadObj.setFontColor();
             }, null, true);
@@ -868,7 +868,7 @@ $(document).ready(function () {
     $('#stage_audits').change(function () {
         const uid = $(this).val();
         const title = $("#stage_audits option:selected").text();
-        setLeftTable(ledgerTree.datas, ledger_cooperation_list, uid, title);
+        setLeftTable(ledgerTree.nodes, ledger_cooperation_list, uid, title);
         ledgerSpreadObj.setAllRightPwd(uid);
     });
 
@@ -884,8 +884,8 @@ $(document).ready(function () {
         postData('/tender/' + cur_tenderid + '/shenpi/audit/save', data, function (result) {
             const lcindex = _.findIndex(ledger_cooperation_list, { ledger_id, user_id });
             ledger_cooperation_list.splice(lcindex, 1);
-            setLeftTable(ledgerTree.datas, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
-            const select = _.find(ledgerTree.datas, { ledger_id });
+            setLeftTable(ledgerTree.nodes, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
+            const select = _.find(ledgerTree.nodes, { ledger_id });
             delete select.pwd;
             // const refreshNode = ledgerTree.loadPostData({update: select});
             selects = [select];
@@ -946,8 +946,8 @@ $(document).ready(function () {
         postData('/tender/' + cur_tenderid + '/shenpi/audit/save', data, function (result) {
             const lcindex = _.findIndex(ledger_cooperation_list, { ledger_id, user_id });
             ledger_cooperation_list.splice(lcindex, 1, result);
-            setLeftTable(ledgerTree.datas, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
-            const select = _.find(ledgerTree.datas, { ledger_id });
+            setLeftTable(ledgerTree.nodes, ledger_cooperation_list, user_id, $('#stage_audits option:selected').text());
+            const select = _.find(ledgerTree.nodes, { ledger_id });
             select.pwd = validText;
             const refreshNode = ledgerTree.loadPostData({update: select});
             ledgerSpreadObj.refreshTree(ledgerSpread.getActiveSheet(), refreshNode);
@@ -1063,36 +1063,6 @@ function setAllChildrenCanEdit(ledgerInfo, flag) {
         }
     }
 }
-// 编号排序,多重判断
-function sortByCode(a, b) {
-    let code1 = a.code.split('-');
-    let code2 = b.code.split('-');
-    let code1length = code1.length;
-    let code2length = code2.length;
-    for (let i = 0; i < code1length; i ++) {
-        if (i+1 <= code2length) {
-            if (code1[i] != code2[i]) {
-                if (!/^\d+$/.test(code1[i])) {
-                    return code1[i].charCodeAt() - code2[i].charCodeAt();
-                } else {
-                    return parseInt(code1[i]) - parseInt(code2[i]);
-                }
-            } else if (i+1 == code1length && code1[i] == code2[i]) {
-                if (code1length == code2length) {
-                    return 0;
-                } else {
-                    return code1length - code2length;
-                }
-            }
-        } else {
-            if (i+1 >= code1length) {
-                return 1;
-            } else {
-                return -1;
-            }
-        }
-    }
-}
 function setLeftTable(ledgerList, coolist, uid, title) {
     $('#stage_audit').text(title);
     const showCooList = _.filter(coolist, { 'user_id': parseInt(uid) });
@@ -1113,7 +1083,11 @@ function setLeftTable(ledgerList, coolist, uid, title) {
     }
 
     let html = '';
-    for (const sc of showCooList.sort(sortByCode)) {
+    // showCooList 需要根据右边台账顺序进行排序
+    showCooList.sort(function (a, b) {
+        return _.findIndex(ledgerList, { ledger_id: a.ledger_id }) - _.findIndex(ledgerList, { ledger_id: b.ledger_id });
+    });
+    for (const sc of showCooList) {
         const pichtml = sc.sign_path ? `<img src="/${sc.sign_path}" width="60"><input type="file" data-id="${sc.id}" class="upload-img-file" style="display: none;"><a href="javascript: void(0);" class="d-inline-flex upload-img">更改</a>`
             : `<img src="" style="display: none" width="60"><input type="file" data-id="${sc.id}" class="upload-img-file" style="display: none;"><a href="javascript: void(0);" class="btn btn-outline-primary btn-sm upload-img">上传签名</a>`;
         html += `<tr>` +

+ 95 - 24
app/public/js/stage.js

@@ -31,7 +31,6 @@ function getExprInfo (field) {
  */
 function customColDisplay () {
     const defaultSetting = [
-        { title: '签约合同', fields: ['deal_qty', 'deal_tp'], visible: true },
         { title: '本期计量合同', fields: ['contract_qty', 'contract_tp'], visible: true },
         { title: '本期数量变更', fields: ['qc_qty', 'qc_tp', 'qc_bgl'], visible: true },
         { title: '本期完成计量', fields: ['gather_qty', 'gather_tp'], visible: true },
@@ -43,11 +42,18 @@ function customColDisplay () {
         { title: '备注', fields: ['memo'], visible: true },
         { title: '总额计量', fields: ['is_tp'], visible: true},
     ];
-    if (checkTzMeasureType()) {
-        defaultSetting.splice(0, 1);
+    if (!checkTzMeasureType()) {
+        defaultSetting.unshift({ title: '台账', fields: ['quantity', 'total_price'], visible: true}, { title: '签约合同', fields: ['deal_qty', 'deal_tp'], visible: true });
     }
     const settingStr = Cookies.get(ckColSetting);
-    return settingStr ? JSON.parse(settingStr) : defaultSetting;
+    if (settingStr) {
+        const customSetting = JSON.parse(settingStr);
+        for (const ds of defaultSetting) {
+            const cs = customSetting.find(x => {return x.title === ds.title});
+            if (cs) ds.visible = cs.visible;
+        }
+    }
+    return defaultSetting;
 }
 
 /**
@@ -2874,6 +2880,24 @@ $(document).ready(() => {
                     }
                 });
             }
+            function upload(formData) {
+                if (formData.length < 1) {
+                    return;
+                }
+                postDataWithFile(window.location.pathname + '/detail/add-img', formData, function (result) {
+                    const html = [];
+                    html.push('<div class="img-item">');
+                    html.push('<div class="img-bar">');
+                    html.push('<a href="javascript: void(0);" class="text-danger" title="删除"><i class="fa fa-remove" style="font-size: 24px"></i></a>');
+                    html.push('</div>');
+                    html.push('<div class="focus" style="width:100%; height:100%"><img src="', '/' + result, '" id="draggable" style="width:100%; height:100%"></div>');
+                    html.push('</div>');
+                    $('.img-view').append(html.join(''));
+                    $('.img-bar').click(removeImageItem);
+                    setdraggrable();
+                    $('#upload-img-file').val('');
+                });
+            }
             // 移动图片
             const moveImageItem = function (ev) {
                 const item = this;
@@ -2934,6 +2958,54 @@ $(document).ready(() => {
             $('#upload-img').click(function () {
                 $('#upload-img-file').trigger('click');
             });
+            // 拖拽上传
+            //拖拽上传文件
+            const dragbox = document.querySelector('#upload-img');
+            dragbox.addEventListener('dragover', function(e) {
+                e.preventDefault(); // 必须阻止默认事件
+            }, false);
+            dragbox.addEventListener('drop', function(e) {
+                e.preventDefault(); // 阻止默认事件
+                var file = null,
+                    data = e.dataTransfer.types;
+                for (var i = 0; i < data.length; i += 1) {
+                    if (data[i] === 'Files') {
+                        file = e.dataTransfer.files; //获取文件
+                        break;
+                    }else{
+                        var text = e.dataTransfer.getData('text/plain');
+                        $('.dragFile').append(text); //将拖拽的文字添加到容器里
+                        break;
+                    }
+                }
+                if (file && file[0].type.indexOf('image') !== -1) {
+                    var formData = new FormData();
+                    formData.append('file', file[0]); //上传单个文件的添加方式
+                    upload(formData); //upload 异步上传
+                }
+            }, false);
+            // 粘贴上传
+            $(".img-view").on('paste', function(ev) {
+                var file = null,
+                    data = (event.clipboardData || window.clipboardData).items;
+                for (var i = 0; i < data.length; i += 1) {
+                    if ((data[i].kind == 'string') && (data[i].type.match('^text/plain'))) {
+                        data[i].getAsString(function(str) {
+                            $('.dragFile').append(str); //容器里追加拷贝的文字
+                        })
+                        break;
+                    } else if ((data[i].kind == 'file') && (data[i].type.match('^image/'))) {
+                        file = data[i].getAsFile(); //读取图片文件
+                        break;
+                    }
+                }
+                if (file) {
+                    var formData = new FormData();
+                    formData.append('file', file); //上传单个文件的添加方式
+                    upload(formData); //异步上传文件
+                }
+            });
+
             $('#upload-img-file').change(function () {
                 const file = this.files[0];
                 const ext = file.name.toLowerCase().split('.').splice(-1)[0];
@@ -2945,19 +3017,7 @@ $(document).ready(() => {
                 if ($(this).val()) {
                     const formData = new FormData();
                     formData.append('file', this.files[0]);
-                    postDataWithFile(window.location.pathname + '/detail/add-img', formData, function (result) {
-                        const html = [];
-                        html.push('<div class="img-item">');
-                        html.push('<div class="img-bar">');
-                        html.push('<a href="javascript: void(0);" class="text-danger" title="删除"><i class="fa fa-remove" style="font-size: 24px"></i></a>');
-                        html.push('</div>');
-                        html.push('<div class="focus" style="width:100%; height:100%"><img src="', '/' + result, '" id="draggable" style="width:100%; height:100%"></div>');
-                        html.push('</div>');
-                        $('.img-view').append(html.join(''));
-                        $('.img-bar').click(removeImageItem);
-                        setdraggrable();
-                        $('#upload-img-file').val('');
-                    });
+                    upload(formData);
                 }
             });
 
@@ -3187,15 +3247,26 @@ $(document).ready(() => {
             this.changeSheet = this.changeSpread.getActiveSheet();
             SpreadJsObj.initSheet(this.changeSheet, this.changeSpreadSetting);
 
+            const getTipText = function (data) {
+                if (!data) return '';
+
+                const tips = [];
+                if (data.xmj_dwgc) tips.push(data.xmj_dwgc);
+                if (data.xmj_fbgc) tips.push(data.xmj_fbgc);
+                if (data.xmj_fxgc) tips.push(data.xmj_fxgc);
+                if (data.xmj_jldy) tips.push(data.xmj_jldy);
+                return tips.join('-');
+            };
+
             this.changeBillsSpreadSetting = {
                 cols: [
-                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
-                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, type: 'Number'},
-                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 50, formatter: '@'},
-                    {title: '单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
-                    {title: '数量', colSpan: '1', rowSpan: '1', field: 'qty', hAlign: 2, width: 60, formatter: '@'},
-                    {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 60, formatter: '@'},
-                    {title: '变更部位', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@'},
+                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@', cellType: 'tip', getTip: getTipText},
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, type: 'Number', cellType: 'tip', getTip: getTipText},
+                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'tip', getTip: getTipText},
+                    {title: '单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', cellType: 'tip', getTip: getTipText},
+                    {title: '数量', colSpan: '1', rowSpan: '1', field: 'qty', hAlign: 2, width: 60, formatter: '@', cellType: 'tip', getTip: getTipText},
+                    {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 60, formatter: '@', cellType: 'tip', getTip: getTipText},
+                    {title: '变更部位', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@', cellType: 'tip', getTip: getTipText},
                 ],
                 emptyRows: 0,
                 headRows: 1,

+ 63 - 1
app/public/js/stage_bwtz.js

@@ -29,12 +29,58 @@ $(document).ready(() => {
     unitSheet.frozenColumnCount(5);
     unitSheet.options.frozenlineColor = '#93b5e4';
 
+    const filterUnitTree = createNewPathTree('filter', {
+        id: 'ledger_id',
+        pid: 'ledger_pid',
+        order: 'order',
+        level: 'level',
+        rootId: -1,
+        fullPath: 'full_path',
+    });
+
     const unitTreeObj = {
+        getFilterUnitTree: function (unitTree) {
+            const filter = $('#unit-filter').val();
+            if (!filter || unitTree.nodes.length === 0) return unitTree;
+            filterUnitTree.clearDatas();
+            const filterPath = [];
+            const checkFullPath = function (checkPath, valuePath) {
+                if (valuePath.indexOf(checkPath + '-') >= 0) return true;
+
+                const pathArray = checkPath.split('-');
+                const tmpArray = [];
+                for (let i = 0, iLen = pathArray.length; i < iLen; i++) {
+                    tmpArray.push(pathArray.slice(0, i+1).join('-'));
+                }
+                for (const ta of tmpArray) {
+                    if (ta === valuePath) return true;
+                }
+                return false;
+            };
+            for (const node of unitTree.nodes) {
+                if ((node.code && node.code.indexOf(filter) >= 0) || (node.b_code && node.b_code.indexOf(filter) >= 0)
+                    || (node.name && node.name.indexOf(filter) >= 0) || (node.pos_name && node.pos_name.indexOf(filter) >= 0))
+                    filterPath.push(node.full_path);
+            }
+            for (const node of unitTree.nodes) {
+                for (const fp of filterPath) {
+                    if (checkFullPath(fp, node.full_path)) {
+                        filterUnitTree.addData(node, ['id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'pos_name',
+                            'code', 'b_code', 'name', 'unit', 'unit_price', 'quantity', 'total_price', 'drawing_code_merge', 'memo_merge']);
+                        break;
+                    }
+                }
+            }
+            filterUnitTree.sortTreeNode();
+            return filterUnitTree;
+        },
         loadCurUnitData: function () {
             const node = SpreadJsObj.getSelectObject(xmjSheet);
             SpreadJsObj.resetTopAndSelect(unitSheet);
             if (node && node.unitTree) {
-                SpreadJsObj.loadSheetData(unitSheet, SpreadJsObj.DataType.Tree, node.unitTree);
+                const relaTree = unitTreeObj.getFilterUnitTree(node.unitTree);
+                if ($('#unit-show-1')[0].checked) relaTree.expandByLevel(1);
+                SpreadJsObj.loadSheetData(unitSheet, SpreadJsObj.DataType.Tree, relaTree);
             } else {
                 SpreadJsObj.initSheet(unitSheet, unitSpreadSetting);
             }
@@ -210,6 +256,22 @@ $(document).ready(() => {
         xmjSpread.refresh();
         unitSpread.refresh();
     });
+
+
+    $('#unit-filter').bind('keydown', function (e) {
+        const evt = window.event || e;
+        if (e.keyCode == 13) unitTreeObj.loadCurUnitData();
+    });
+    $('#unit-show-1').bind('change', function () {
+        if (!unitSheet.zh_tree) return;
+        if (this.checked) {
+            unitSheet.zh_tree.expandByLevel(1);
+            SpreadJsObj.refreshTreeRowVisible(unitSheet);
+        } else {
+            unitSheet.zh_tree.expandByCustom(() => { return true; });
+            SpreadJsObj.refreshTreeRowVisible(unitSheet);
+        }
+    });
     // 显示层次
     (function (select, sheet) {
         $(select).click(function () {

+ 2 - 0
app/router.js

@@ -442,6 +442,8 @@ module.exports = app => {
     app.get('/tender/:id/schedule/plan', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.plan');
     app.post('/tender/:id/schedule/plan/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.savePlan');
     app.get('/tender/:id/schedule/stage', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.stageTp');
+    app.get('/tender/:id/schedule/stage/order/:order', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.stageTp');
+    app.post('/tender/:id/schedule/stage/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.saveStageTp');
     app.get('/tender/:id/schedule/stage/gcl', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.stageGcl');
     app.post('/tender/:id/schedule/stage/gcl/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.saveStageGcl');
 

+ 2 - 2
app/service/schedule_month.js

@@ -82,7 +82,7 @@ module.exports = app => {
         async addStageUsed(data) {
             const updateData = {
                 id: data.id,
-                stage_used: 1,
+                stage_gcl_used: 1,
             };
             return await this.db.update(this.tableName, updateData);
         }
@@ -93,7 +93,7 @@ module.exports = app => {
                 const updateDatas = [];
                 const updateLmDatas = [];
                 for (const m of data) {
-                    updateDatas.push({ row: { stage_used: 0, sj_gcl: null, sj_tp: null }, where: { yearmonth: m, tid: this.ctx.tender.id } });
+                    updateDatas.push({ row: { stage_gcl_used: 0, sj_gcl: null, sj_tp: null }, where: { yearmonth: m, tid: this.ctx.tender.id } });
                     updateLmDatas.push({ row: { sj_gcl: null, sj_tp: null }, where: { yearmonth: m, tid: this.ctx.tender.id } });
                 }
                 if (updateDatas.length > 0) await transaction.updateRows(this.tableName, updateDatas);

+ 85 - 0
app/service/schedule_stage.js

@@ -0,0 +1,85 @@
+'use strict';
+
+module.exports = app => {
+    class ScheduleStage extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'schedule_stage';
+        }
+
+        async getLastPlanMonth() {
+            const sql = 'SELECT `yearmonth` FROM ?? WHERE `tid` = ? ORDER BY `yearmonth` DESC Limit 0,1';
+            const sqlParam = [this.tableName, this.ctx.tender.id];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        async add(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const insertData = {
+                    tid: this.ctx.tender.id,
+                    yearmonth: data.yearmonth,
+                    order: data.order,
+                };
+                // 更新schedule_month stage_tp_used为1
+                const updateData = {
+                    stage_tp_used: 1,
+                };
+                const option = {
+                    where: {
+                        tid: this.ctx.tender.id,
+                        yearmonth: data.yearmonth,
+                    },
+                };
+                await transaction.update(this.ctx.service.scheduleMonth.tableName, updateData, option);
+                await transaction.insert(this.tableName, insertData);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async del(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const info = await this.getDataById(data.id);
+                await transaction.delete(this.tableName, { id: data.id });
+                // 更新schedule_month stage_tp_used为0
+                const updateData = {
+                    stage_tp_used: 0,
+                };
+                const option = {
+                    where: {
+                        tid: this.ctx.tender.id,
+                        yearmonth: info.yearmonth,
+                    },
+                };
+                await transaction.update(this.ctx.service.scheduleMonth.tableName, updateData, option);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async changeOrder(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const updateData = {
+                    id: data.id,
+                    order: data.order,
+                };
+                await transaction.update(this.tableName, updateData);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+    }
+    return ScheduleStage;
+};

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

@@ -44,6 +44,29 @@
                             <li class="nav-item">
                                 <a class="nav-link active" data-toggle="tab" href="#jldyjlqd" role="tab">计量单元/计量清单</a>
                             </li>
+                            <li class="nav-item">
+                                <div class="d-inline-block ml-2">
+                                    <a class="btn btn-sm btn-light">
+                                        <div class="custom-control custom-checkbox">
+                                            <input type="checkbox" class="custom-control-input" id="unit-show-1">
+                                            <label class="custom-control-label text-primary" for="unit-show-1">只显示第一层</label>
+                                        </div>
+                                    </a>
+                                </div>
+                                <% if (ctx.app.config.is_debug) {%>
+                                <div class="d-inline-block">
+                                    <div class="input-group input-group-sm ml-2">
+                                        <div class="input-group-prepend">
+                                            <span class="input-group-text" id="basic-addon1">数据筛选</span>
+                                        </div>
+                                        <input type="text" class="form-control form-control-sm m-0" id="unit-filter" placeholder="可根据 计量单元/清单编号/名称 筛选数据" style="width: 300px">
+                                    </div>
+                                </div>
+                                <div class="d-inline-block ml-2">
+                                    <div class="alert-warning p-1"><i class="fa Example of exclamation-circle fa-exclamation-circle "></i> 父项/子项任一符合,均显示</div>
+                                </div>
+                                <% } %>
+                            </li>
                         </ul>
                     </div>
                     <div class="sp-wrap" id="unit-spread">

+ 1 - 1
app/view/schedule/plan_modal.ejs

@@ -33,7 +33,7 @@
                     <% for (const m of scheduleMonth) { %>
                     <tr>
                         <td><%- m.yearmonth %></td>
-                        <td><% if (m.stage_used === 0) { %><label></label><input type="checkbox" value="<%- m.id %>"><% } %></td>
+                        <td><% if (m.stage_gcl_used === 0 && m.stage_tp_used) { %><label></label><input type="checkbox" value="<%- m.id %>"><% } %></td>
                     </tr>
                     <% } %>
                 </table>

+ 2 - 2
app/view/schedule/stage_gcl_modal.ejs

@@ -11,7 +11,7 @@
                     <select class="form-control" id="month-select">
                         <option value="0">选择计量月</option>
                         <% for (const m of scheduleMonth) { %>
-                            <% if (m.stage_used === 0) { %>
+                            <% if (m.stage_gcl_used === 0) { %>
                             <option value="<%- m.id %>"><%- m.yearmonth.split('-')[0] %>年<%- parseInt(m.yearmonth.split('-')[1]) %>月 %></option>
                             <% } %>
                         <% } %>
@@ -36,7 +36,7 @@
                 <table class="table table-bordered table-hover" id="month-table">
                     <tr><th>计量月</th><th width="100">删除</th></tr>
                     <% for (const m of scheduleMonth) { %>
-                    <% if (m.stage_used === 1) { %>
+                    <% if (m.stage_gcl_used === 1) { %>
                     <tr><td><%- m.yearmonth %></td><td><label></label><input type="checkbox" value="<%- m.id %>"></td></tr>
                     <% } %>
                     <% } %>

+ 11 - 2
app/view/schedule/stage_tp.ejs

@@ -14,23 +14,31 @@
                         </a>
                     </div>
                 </div>
+                <% if (scheduleStage.length > 0) { %>
                 <div class="d-inline-block">
                     <div class="dropdown">
                         <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                            2020年3月(第3期)
+                            <%- curScheduleStage.yearmonth.split('-')[0] %>年<%- parseInt(curScheduleStage.yearmonth.split('-')[1]) %>月(第<%- curScheduleStage.order %>期)
                         </button>
                         <div class="dropdown-menu" aria-labelledby="dropdownMenuButton" x-placement="bottom-start" style="position: absolute; transform: translate3d(0px, 26px, 0px); top: 0px; left: 0px; will-change: transform;">
-                            <a class="dropdown-item" href="#">2020年2月(第2期)</a>
+                            <% for (const s of scheduleStage) { %>
+                            <% if (s.id !== curScheduleStage.id) { %>
+                            <a class="dropdown-item" href="/tender/<%- tender.id %>/schedule/stage/order/<%- s.order %>"><%- s.yearmonth.split('-')[0] %>年<%- parseInt(s.yearmonth.split('-')[1]) %>月(第<%- s.order %>期)</a>
+                            <% } %>
+                            <% } %>
                         </div>
                     </div>
                 </div>
                 <div class="d-inline-flex">
                     <a href="#delete" data-toggle="modal" data-target="#delete" class="btn btn-sm btn-outline-danger">删除本期进度</a>
                 </div>
+                <% } %>
             </div>
             <div class="ml-auto">
                 <a href="" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#add">创建新计量进度</a>
+                <% if (scheduleStage.length > 0) { %>
                 <a href="" class="btn btn-sm btn-warning" data-toggle="modal" data-target="#re-build">重新生成本月进度</a>
+                <% } %>
             </div>
         </div>
     </div>
@@ -48,5 +56,6 @@
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
     const schedule = JSON.parse('<%- JSON.stringify(schedule) %>');
     const scheduleMonth = JSON.parse('<%- JSON.stringify(scheduleMonth) %>');
+    const curScheduleStage = JSON.parse('<%- JSON.stringify(curScheduleStage) %>');
     const monthList = _.map(scheduleMonth, 'yearmonth');
 </script>

+ 28 - 13
app/view/schedule/stage_tp_modal.ejs

@@ -8,26 +8,35 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label>计划进度月</label>
-                    <select class="form-control">
-                        <option>2020年1月</option>
-                        <option>2020年2月</option>
-                        <option>2020年3月</option>
+                    <select class="form-control" id="month_list">
+                        <option value="0">选择计划进度月</option>
+                        <% for (const m of scheduleMonth) { %>
+                        <% if (!ctx.helper._.find(scheduleStage, { yearmonth: m.yearmonth })) { %>
+                        <option value="<%- m.yearmonth %>"><%- m.yearmonth.split('-')[0] %>年<%- parseInt(m.yearmonth.split('-')[1]) %>月 %></option>
+                        <% } %>
+                        <% } %>
                     </select>
                 </div>
                 <div class="form-group">
                     <label>计量期</label>
-                    <select class="form-control">
-                        <option>第3期</option>
+                    <select class="form-control" id="stage_list">
+                        <option value="0">选择计量期</option>
+                        <% for (const so of stageOrderList) { %>
+                        <% if (!ctx.helper._.find(scheduleStage, { order: so.order })) { %>
+                        <option value="<%- so.order %>">第<%- so.order %>期</option>
+                        <% } %>
+                        <% } %>
                     </select>
                 </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" >确认创建</button>
+                <button type="button" class="btn btn-sm btn-primary" id="add-stage">确认创建</button>
             </div>
         </div>
     </div>
 </div>
+<% if (scheduleStage.length > 0) { %>
 <!--重新生成本月计量进度-->
 <div class="modal fade" id="re-build" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -37,18 +46,23 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label>计划进度月:2020年3月</label>
+                    <label>计划进度月:<%- curScheduleStage.yearmonth.split('-')[0] %>年<%- parseInt(curScheduleStage.yearmonth.split('-')[1]) %>月</label>
                 </div>
                 <div class="form-group">
                     <label>计量期</label>
-                    <select class="form-control">
-                        <option>第3期</option>
+                    <select class="form-control" id="reload-stage-list">
+                        <option value="0">选择计量期</option>
+                        <% for (const so of stageOrderList) { %>
+                        <% if (!ctx.helper._.find(scheduleStage, { order: so.order })) { %>
+                        <option value="<%- so.order %>">第<%- so.order %>期</option>
+                        <% } %>
+                        <% } %>
                     </select>
                 </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" >确认生成</button>
+                <button type="button" class="btn btn-sm btn-primary" data-id="<%- curScheduleStage.id %>" id="reload-stage">确认生成</button>
             </div>
         </div>
     </div>
@@ -61,16 +75,17 @@
                 <h5 class="modal-title">删除本期计量进度</h5>
             </div>
             <div class="modal-body">
-                <h6>确认删除「2020年3月(第3期)」计量进度?</h6>
+                <h6>确认删除「<%- curScheduleStage.yearmonth.split('-')[0] %>年<%- parseInt(curScheduleStage.yearmonth.split('-')[1]) %>月(第<%- curScheduleStage.order %>期)」计量进度?</h6>
                 <h6>删除后,数据无法恢复,请谨慎操作。</h6>
             </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-danger">确定删除</button>
+                <button type="button" class="btn btn-sm btn-danger" data-id="<%- curScheduleStage.id %>" id="del-stage">确定删除</button>
             </div>
         </div>
     </div>
 </div>
+<% } %>
 <!--首次使用提示-->
 <div class="modal fade" id="second" data-backdrop="static">
     <div class="modal-dialog" role="document">

+ 18 - 1
app/view/setting/info.ejs

@@ -50,7 +50,24 @@
                             </div>
                             <div class="form-group">
                                 <label>创建时间</label>
-                                <input class="form-control form-control-sm" value=<%= dateStr%> type="text" readonly>
+                                <input class="form-control form-control-sm" value="<%= dateStr%>" type="text" readonly>
+                            </div>
+                            <legend>其他信息(报表显示)</legend>
+                            <div class="form-group">
+                                <label>主管部门</label>
+                                <input class="form-control form-control-sm" type="text" value="<%= projectData.rpt_authority %>" <% if (projectData.user_account !== ctx.session.sessionUser.account) { %>readonly<% } else { %>name="rpt_authority" id="rpt_authority"<% } %>>
+                            </div>
+                            <div class="form-group">
+                                <label>建设项目类别</label>
+                                <input class="form-control form-control-sm" type="text" value="<%= projectData.rpt_items %>" value="<%= projectData.rpt_authority %>" <% if (projectData.user_account !== ctx.session.sessionUser.account) { %>readonly<% } else { %>name="rpt_items" id="rpt_items"<% } %>>
+                            </div>
+                            <div class="form-group">
+                                <label>级别</label>
+                                <input class="form-control form-control-sm" type="text" value="<%= projectData.rpt_level %>" <% if (projectData.user_account !== ctx.session.sessionUser.account) { %>readonly<% } else { %>name="rpt_level" id="rpt_level"<% } %>>
+                            </div>
+                            <div class="form-group">
+                                <label>建设性质</label>
+                                <input class="form-control form-control-sm" type="text" value="<%= projectData.rpt_nature %>" <% if (projectData.user_account !== ctx.session.sessionUser.account) { %>readonly<% } else { %>name="rpt_nature" id="rpt_nature"<% } %>>
                             </div>
                             <% if (projectData.user_account === ctx.session.sessionUser.account) { %></form><% } %>
                     </div>

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

@@ -109,7 +109,7 @@
         if (!setting.prefix) setting.prefix = 'check2-';
         if (setting.randomWait) {
             for (const c of setting.checks) {
-                c.wait = _.random(2, 4) + setting.extra;
+                c.wait = _.random(2, 3) + setting.extra;
             }
         }
 

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

@@ -56,6 +56,29 @@
                             <li class="nav-item">
                                 <a class="nav-link active" data-toggle="tab" href="#jldyjlqd" role="tab">计量单元/计量清单</a>
                             </li>
+                            <li class="nav-item">
+                                <div class="d-inline-block ml-2">
+                                    <a class="btn btn-sm btn-light">
+                                        <div class="custom-control custom-checkbox">
+                                            <input type="checkbox" class="custom-control-input" id="unit-show-1">
+                                            <label class="custom-control-label text-primary" for="unit-show-1">只显示第一层</label>
+                                        </div>
+                                    </a>
+                                </div>
+                                <% if (ctx.app.config.is_debug) {%>
+                                <div class="d-inline-block">
+                                    <div class="input-group input-group-sm ml-2">
+                                        <div class="input-group-prepend">
+                                            <span class="input-group-text" id="basic-addon1">数据筛选</span>
+                                        </div>
+                                        <input type="text" class="form-control form-control-sm m-0" id="unit-filter" placeholder="可根据 计量单元/清单编号/名称 筛选数据" style="width: 300px">
+                                    </div>
+                                </div>
+                                <div class="d-inline-block ml-2">
+                                    <div class="alert-warning p-1"><i class="fa Example of exclamation-circle fa-exclamation-circle "></i> 父项/子项任一符合,均显示</div>
+                                </div>
+                                <% } %>
+                            </li>
                         </ul>
                     </div>
                     <div class="sp-wrap" id="unit-spread">

+ 12 - 4
app/view/stage/modal.ejs

@@ -322,10 +322,18 @@
                 <h5 class="modal-title">添加草图</h5>
             </div>
             <div class="modal-body">
-                <p>
-                    <input type="file" id="upload-img-file" style="display: none;">
-                    <a href="javascript: void(0);" class="btn btn-outline-primary btn-sm" id="upload-img">上传图片</a>
-                </p>
+                <!--<p>-->
+                    <!--<input type="file" id="upload-img-file" style="display: none;">-->
+                    <!--<a href="javascript: void(0);" class="btn btn-outline-primary btn-sm" id="upload-img">上传图片</a>-->
+                <!--</p>-->
+                <input type="file" id="upload-img-file" style="display: none;">
+                <div class="card mb-2" id="upload-img">
+                    <div class="card-body p-1">
+                        <div class="text-center"><i class="fa fa-folder-open-o fa-3x"></i></div>
+                        <div class="text-center">点击或拖动图片文件到这里进行上传</div>
+                        <div class="text-center text-muted">仅支持单个文件上传,可以通过QQ、微信截图粘贴上传</div>
+                    </div>
+                </div>
                 <div class="img-view">
                 </div>
                 <div class="mt-2">

+ 13 - 4
app/view/stage_extra/bonus.ejs

@@ -16,11 +16,20 @@
     </div>
     <div class="content-wrap">
         <div class="c-header p-0"></div>
-        <div class="c-body">
-            <div class="sjs-height-0" id="bonus-spread">
+        <div class="w-100 sub-content row">
+            <div class="c-body col-9">
+                <div class="sjs-height-0" id="bonus-spread">
+                </div>
+                <div z-index="0" style="display: none;">
+                    <input class="datepicker-here form-control form-control-sm" data-date-format="yyyy-MM-DD" data-language="zh" type="text" autocomplete="off" id="dp-input">
+                </div>
             </div>
-            <div z-index="0" style="display: none;">
-                <input class="datepicker-here form-control form-control-sm" data-date-format="yyyy-MM-DD" data-language="zh" type="text" autocomplete="off" id="dp-input">
+            <div class="c-body col-3">
+                <table class="table table-bordered" style="width: 99%">
+                    <tr><th class="text-center" width="66.6%">名称</th><th class="text-center">金额</th></tr>
+                    <tbody id="sum">
+                    </tbody>
+                </table>
             </div>
         </div>
     </div>

+ 13 - 4
app/view/stage_extra/other.ejs

@@ -16,11 +16,20 @@
     </div>
     <div class="content-wrap">
         <div class="c-header p-0"></div>
-        <div class="c-body">
-            <div class="sjs-height-1" id="other-spread" z-index="1">
+        <div class="w-100 sub-content row">
+            <div class="c-body col-9">
+                <div class="sjs-height-1" id="other-spread" z-index="1">
+                </div>
+                <div z-index="0" style="display: none;">
+                    <input class="datepicker-here form-control form-control-sm" data-date-format="yyyy-MM-DD" data-language="zh" type="text" autocomplete="off" id="dp-input">
+                </div>
             </div>
-            <div z-index="0" style="display: none;">
-                <input class="datepicker-here form-control form-control-sm" data-date-format="yyyy-MM-DD" data-language="zh" type="text" autocomplete="off" id="dp-input">
+            <div class="c-body col-3">
+                <table class="table table-bordered" style="width: 99%">
+                    <tr><th class="text-center" width="66.6%">名称</th><th class="text-center">金额</th></tr>
+                    <tbody id="sum">
+                    </tbody>
+                </table>
             </div>
         </div>
     </div>

+ 8 - 8
app/view/tender/tender_sub_menu.ejs

@@ -43,14 +43,14 @@
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material"><i class="fa fa-line-chart"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
-        <!--<div class="nav-box">-->
-            <!--<h3><i class="fa fa-bar-chart "></i> 形象进度</h3>-->
-            <!--<ul class="nav-list list-unstyled sub-list">-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage/gcl') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/stage"><span>计量进度</span></a></li>-->
-            <!--</ul>-->
-        <!--</div>-->
+        <div class="nav-box">
+            <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
+            <ul class="nav-list list-unstyled sub-list">
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>
+                <li <% if (ctx.url.indexOf('/tender/' + ctx.tender.id + '/schedule/stage') !== -1) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/stage"><span>计量进度</span></a></li>
+            </ul>
+        </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/report') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/report"><i class="fa fa-file-text-o"></i> <span>报表</span></a></li>

+ 8 - 8
app/view/tender/tender_sub_mini_menu.ejs

@@ -41,14 +41,14 @@
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material"><i class="fa fa-line-chart"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
-        <!--<div class="nav-box">-->
-            <!--<h3><i class="fa fa-bar-chart "></i> 形象进度</h3>-->
-            <!--<ul class="nav-list list-unstyled sub-list">-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>-->
-                <!--<li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage/gcl') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/stage"><span>计量进度</span></a></li>-->
-            <!--</ul>-->
-        <!--</div>-->
+        <div class="nav-box">
+            <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
+            <ul class="nav-list list-unstyled sub-list">
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/stage/gcl') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/stage"><span>计量进度</span></a></li>
+            </ul>
+        </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/report') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/report"><i class="fa fa-file-text-o"></i> <span>报表</span></a></li>

+ 6 - 0
builder_report_index_define.js

@@ -695,6 +695,9 @@ const stage_im_zl = {
         { name: '审批意见2', field: 'co_opinion2', type: dataType.time },
         { name: '审批意见3', field: 'co_opinion3', type: dataType.time },
         { name: '审批意见4', field: 'co_opinion4', type: dataType.time },
+        { name: '单位工程', field: 'dwgc', type: dataType.str },
+        { name: '分部工程', field: 'fbgc', type: dataType.str },
+        { name: '分项工程', field: 'fxgc', type: dataType.str },
     ],
 };
 const stage_im_tz = {
@@ -744,6 +747,9 @@ const stage_im_tz = {
         { name: '审批意见2', field: 'co_opinion2', type: dataType.time },
         { name: '审批意见3', field: 'co_opinion3', type: dataType.time },
         { name: '审批意见4', field: 'co_opinion4', type: dataType.time },
+        { name: '单位工程', field: 'dwgc', type: dataType.str },
+        { name: '分部工程', field: 'fbgc', type: dataType.str },
+        { name: '分项工程', field: 'fxgc', type: dataType.str },
     ],
 };
 const stage_im_tz_bills = {

+ 5 - 0
sql/update.sql

@@ -40,3 +40,8 @@ CREATE TABLE `zh_ledger_tag` (
   `modify_time` datetime DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=216 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ALTER TABLE `zh_project` ADD `rpt_authority` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '主管部门(报表显示)' AFTER `page_path`;
+ALTER TABLE `zh_project` ADD `rpt_items` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '建设项目类别(报表显示)' AFTER `rpt_authority`;
+ALTER TABLE `zh_project` ADD `rpt_level` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '级别(报表显示)' AFTER `rpt_items`;
+ALTER TABLE `zh_project` ADD `rpt_nature` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '建设性质(报表显示)' AFTER `rpt_level`;