Просмотр исходного кода

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

TonyKang 5 лет назад
Родитель
Сommit
d2a70bf297
54 измененных файлов с 1546 добавлено и 511 удалено
  1. 1 1
      .gitignore
  2. 3 1
      .travis.yml
  3. 8 0
      app/base/base_bills_service.js
  4. 22 1
      app/controller/ledger_controller.js
  5. 2 0
      app/controller/report_controller.js
  6. 20 0
      app/controller/revise_controller.js
  7. 18 0
      app/controller/signature_controller.js
  8. 46 1
      app/controller/spss_controller.js
  9. 78 1
      app/controller/stage_extra_controller.js
  10. 6 2
      app/controller/tender_controller.js
  11. 8 1
      app/middleware/auto_logger.js
  12. 0 1
      app/middleware/stage_check.js
  13. 0 1
      app/public/js/compare_tz.js
  14. 105 25
      app/public/js/ledger.js
  15. 44 20
      app/public/js/revise.js
  16. 359 4
      app/public/js/se_jgcl.js
  17. 1 0
      app/public/js/spreadjs_rela/spreadjs_zh.js
  18. 127 3
      app/public/js/stage.js
  19. 1 1
      app/public/js/stage_change.js
  20. 7 81
      app/public/js/tender_list.js
  21. 6 81
      app/public/js/tender_list_info.js
  22. 7 82
      app/public/js/tender_list_manage.js
  23. 11 86
      app/public/js/tender_list_progress.js
  24. 148 0
      app/public/js/tender_showhide.js
  25. 2 1
      app/public/report/js/rpt_main.js
  26. 71 22
      app/public/report/js/rpt_signature.js
  27. 8 0
      app/router.js
  28. 1 1
      app/service/ledger_audit.js
  29. 23 15
      app/service/pay.js
  30. 1 1
      app/service/revise_audit.js
  31. 69 0
      app/service/signature_used.js
  32. 7 2
      app/service/stage.js
  33. 5 0
      app/service/stage_audit.js
  34. 3 4
      app/service/stage_bills.js
  35. 3 3
      app/service/stage_change.js
  36. 213 0
      app/service/stage_jgcl.js
  37. 1 0
      app/view/layout/layout.ejs
  38. 2 2
      app/view/login/login.ejs
  39. 1 0
      app/view/report/index.ejs
  40. 11 6
      app/view/report/rpt_all_popup.ejs
  41. 5 1
      app/view/setting/info.ejs
  42. 16 0
      app/view/spss/compare_stage.ejs
  43. 1 22
      app/view/spss/sub_menu.ejs
  44. 22 0
      app/view/spss/sub_menu_list.ejs
  45. 1 22
      app/view/spss/sub_mini_menu.ejs
  46. 12 1
      app/view/stage/index.ejs
  47. 0 1
      app/view/stage/pay.ejs
  48. 6 1
      app/view/stage_extra/jgcl.ejs
  49. 5 2
      app/view/tender/index.ejs
  50. 5 2
      app/view/tender/info.ejs
  51. 4 1
      app/view/tender/manage.ejs
  52. 5 2
      app/view/tender/progress.ejs
  53. 5 0
      config/config.default.js
  54. 10 6
      config/web.js

+ 1 - 1
.gitignore

@@ -9,4 +9,4 @@ app/public/download/
 .DS_Store
 *.swp
 package-lock.json
-app/public/js/web
+app/public/js/web

+ 3 - 1
.travis.yml

@@ -3,8 +3,10 @@ language: node_js
 node_js:
   - '6'
   - '8'
+before_install:
+  - npm i npminstall -g
 install:
-  - npm i npminstall && npminstall
+  - npminstall
 script:
   - npm run ci
 after_script:

+ 8 - 0
app/base/base_bills_service.js

@@ -507,6 +507,14 @@ class BaseBillsSerivce extends TreeService {
         node.is_leaf = false;
         return { create: datas, update: [node]};
     }
+
+    async deal2sgfh(tid) {
+        const sql = 'UPDATE ' + this.tableName + ' SET sgfh_qty = deal_qty, quantity = deal_qty + sjcl_qty + qtcl_qty, ' +
+            '   sgfh_tp = deal_tp, total_price = deal_tp + sjcl_tp + qtcl_tp' +
+            '  WHERE tender_id = ?';
+        const sqlParam = [tid];
+        await this.db.query(sql, sqlParam);
+    }
 }
 
 module.exports = BaseBillsSerivce;

+ 22 - 1
app/controller/ledger_controller.js

@@ -545,7 +545,28 @@ module.exports = app => {
         //         if (stream) await sendToWormhole(stream);
         //         ctx.body = {err: 1, msg: err.toString(), data: null};
         //     }
-        // }        
+        // }
+
+        /**
+         * 填设计量(Ajax)
+         *
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async deal2sgfh(ctx) {
+            try {
+                if (!ctx.tender.data) throw '标段数据错误';
+                if (ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) throw '您无权进行该操作';
+                if (this.ctx.tender.measure_type === measureType.tz.value) throw '该功能仅工程量清单模式可用';
+
+                await this.ctx.service.ledger.deal2sgfh(ctx.tender.id);
+                const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
+                ctx.body = {err: 0, msg: '', data: {bills: ledgerData}};
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
 
         /**
          * 下载(清单Excel模板 or 导出项目台账Excel)

+ 2 - 0
app/controller/report_controller.js

@@ -40,6 +40,7 @@ module.exports = app => {
                 const stageList = await ctx.service.stage.getValidStagesShort(tender.id);
                 const prjAccList = await ctx.service.projectAccount.getAllAccountByProjectId(tender.data.project_id);
                 const roleList = await ctx.service.signatureRole.getSignatureRolesByTenderId(tender.id);
+                const usedList = await ctx.service.signatureUsed.getSignatureUsedByTenderId(tender.id);
 
                 // const allTpls = await ctx.service.rptTpl.getAllTplByIds(tmpRptIds);
                 // for (const tpl of allTpls) {
@@ -103,6 +104,7 @@ module.exports = app => {
                     stage_list: JSON.stringify(stageList),
                     prj_account_list: JSON.stringify(prjAccList),
                     role_list: JSON.stringify(roleList),
+                    used_list: JSON.stringify(usedList),
                     tenderMenu,
                     preUrl: '/tender/' + tender.id,
                     measureType,

+ 20 - 0
app/controller/revise_controller.js

@@ -655,6 +655,26 @@ module.exports = app => {
         }
 
         /**
+         * 填设计量(Ajax)
+         *
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async deal2sgfh(ctx) {
+            try {
+                const revise = await this.checkRevise(ctx);
+                if (this.ctx.tender.measure_type === measureType.tz.value) throw '该功能仅工程量清单模式可用';
+
+                await this.ctx.service.revise.deal2sgfh(ctx.tender.id);
+                const ledgerData = await ctx.service.revise.getData(ctx.tender.id);
+                ctx.body = {err: 0, msg: '', data: {bills: ledgerData}};
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
+        /**
          * 新增审批人(Ajax)
          *
          * @param ctx

+ 18 - 0
app/controller/signature_controller.js

@@ -54,6 +54,24 @@ module.exports = app => {
             ctx.status = 201;
         }
 
+        /**
+         * 更新最近使用签名
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        async updateSignatureUsed(ctx) {
+            const params = JSON.parse(ctx.request.body.params);
+            const used_time = ctx.request.body.create_time;
+            const signused = await ctx.service.signatureUsed.updateUsed(params, used_time);
+            const signUsedList = await ctx.service.signatureUsed.getSignatureUsedByTenderId(params.tender_id);
+            // const rst = await ctx.service.signatureRole.createRole(params.name, params.bind_acc_id, params.prj_id, params.tender_id);
+            // console.log(rst);
+            ctx.body = { data: signUsedList };
+            // ctx.body = { data: { msg: 'test the network' } };
+            ctx.status = 201;
+        }
+
     }
 
     return ReportController;

+ 46 - 1
app/controller/spss_controller.js

@@ -26,7 +26,7 @@ module.exports = app => {
         }        
 
         /**
-         * 初始化用户信息页面
+         * 台账 对比 页面
          *
          * @param {Object} ctx - egg全局变量
          * @return {void}
@@ -67,6 +67,51 @@ module.exports = app => {
                 ctx.body = this.ajaxErrorBody(err, '查询数据错误');
             }
         }
+
+
+        /**
+         * 期计量 对比 页面
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async compareStage(ctx) {
+            try {
+                await this.layout('spss/compare_stage.ejs', {});
+            } catch (err) {
+                ctx.helper.log(err);
+            }
+        }
+
+
+        /**
+         * 台账 汇总 页面
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async gatherTz(ctx) {
+            try {
+                await this.layout('spss/compare_stage.ejs', {});
+            } catch (err) {
+                ctx.helper.log(err);
+            }
+        }
+
+
+        /**
+         * 期计量 汇总 页面
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async gatherStage(ctx) {
+            try {
+                await this.layout('spss/compare_stage.ejs', {});
+            } catch (err) {
+                ctx.helper.log(err);
+            }
+        }
     }
 
     return SpssController;

+ 78 - 1
app/controller/stage_extra_controller.js

@@ -29,7 +29,7 @@ module.exports = app => {
             try {
                 const renderData = {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.stageExtra.jgcl)
-                }
+                };
                 await this.layout('stage_extra/jgcl.ejs', renderData);
             } catch (err) {
                 ctx.helper.log(err);
@@ -37,6 +37,47 @@ module.exports = app => {
         }
 
         /**
+         * 获取甲供材料页面数据 (Get)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async loadJgcl (ctx) {
+            try {
+                const data = await ctx.service.stageJgcl.getStageData(ctx.stage.id);
+                const preData = await ctx.service.stageJgcl.getPreStageData(ctx.stage.order);
+                for (const d of data) {
+                    const pd = this.ctx.helper._.find(preData, {uuid: d.uuid});
+                    if (pd) {
+                        d.pre_arrive_qty = pd.arrive_qty;
+                        d.pre_arrive_tp = pd.arrive_tp;
+                        d.pre_deduct_qty = pd.deduct_qty;
+                        d.pre_deduct_tp = pd.deduct_tp;
+                    }
+                }
+                ctx.body = {err: 0, msg: '', data: data};
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.body = this.ajaxErrorBody(error, '获取甲供材料数据失败,请刷新');
+            }
+        }
+
+        /**
+         * 提交甲供材料数据 (Ajaz)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async updateJgcl (ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.stageJgcl.updateDatas(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.body = this.ajaxErrorBody(error, '提交甲供材料数据失败,请重试');
+            }
+        }
+
+        /**
          * 奖罚金(Get)
          * 
          * @param {Object} ctx - egg全局变量
@@ -53,6 +94,24 @@ module.exports = app => {
         }
 
         /**
+         * 获取奖罚金页面数据 (Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async loadBonus (ctx) {
+
+        }
+
+        /**
+         * 提交 奖罚金页面数据 (Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async updateBonus (ctx) {
+
+        }
+
+        /**
          * 其他(Get)
          * @param {Object} ctx - egg全局变量
          */
@@ -66,6 +125,24 @@ module.exports = app => {
                 ctx.helper.log(err);
             }
         }
+
+        /**
+         * 获取 其他 数据 (Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async loadOther (ctx) {
+
+        }
+
+        /**
+         * 提交 其他 数据 (Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async updateOther (ctx) {
+
+        }
     }
 
     return StageExtraController;

+ 6 - 2
app/controller/tender_controller.js

@@ -42,7 +42,7 @@ module.exports = app => {
                 for (const t of tenderList) {
                     if (t.user_id === this.ctx.session.sessionUser.accountId && (
                         t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
-                        const sum = await this.ctx.service.ledger.addUp({tender_id: t.id, is_leaf: true});
+                        const sum = await this.ctx.service.ledger.addUp({tender_id: t.id/*, is_leaf: true*/});
                         t.total_price = sum.total_price;
                         t.deal_tp = sum.deal_tp;
                     }
@@ -65,6 +65,8 @@ module.exports = app => {
                     auditConst,
                     userPermission,
                     valuations,
+                    uid: this.ctx.session.sessionUser.accountId,
+                    pid: this.ctx.session.sessionProject.id,
                 };
                 await this.layout(view, renderData, modal);
             } catch (err) {
@@ -104,6 +106,8 @@ module.exports = app => {
                 renderData.measureType = tenderConst.measureType;
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.jsFiles);
                 renderData.auditConst = auditConst;
+                renderData.uid = this.ctx.session.sessionUser.accountId;
+                renderData.pid = this.ctx.session.sessionProject.id;
                 await this.layout(view, renderData, modal);
             } catch (err) {
                 this.log(err);
@@ -284,7 +288,7 @@ module.exports = app => {
                 const tender = ctx.tender.data;
                 if (tender.user_id === this.ctx.session.sessionUser.accountId && (
                     tender.ledger_status === auditConst.ledger.status.checkNo || tender.ledger_status === auditConst.ledger.status.uncheck)) {
-                    const sum = await this.ctx.service.ledger.addUp({tender_id: tender.id, is_leaf: true});
+                    const sum = await this.ctx.service.ledger.addUp({tender_id: tender.id/*, is_leaf: true*/});
                     tender.total_price = sum.total_price;
                     tender.deal_tp = sum.deal_tp;
                 }

+ 8 - 1
app/middleware/auto_logger.js

@@ -19,8 +19,9 @@ module.exports = options => {
             }
             return ctx.getLogger('mixed');
         }
+
+        const bLogger = getBussinessLogger(this);
         if (this.session.sessionUser) {
-            const bLogger = getBussinessLogger(this);
             const logData = {
                 method: this.method,
                 user: this.session.sessionUser,
@@ -28,6 +29,12 @@ module.exports = options => {
                 data: this.body,
             };
             bLogger.info(JSON.stringify(logData));
+        } else {
+            const logData = {
+                method: this.method,
+                data: this.body,
+            };
+            bLogger.info(JSON.stringify(logData));
         }
 
         // 自动记录log的action

+ 0 - 1
app/middleware/stage_check.js

@@ -97,7 +97,6 @@ module.exports = options => {
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }
-            console.log(stage.readOnly);
 
             const lastRevise = yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
             stage.revising = (lastRevise && lastRevise.status !== reviseStatus.checked) || false;

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

@@ -69,7 +69,6 @@ $(document).ready(function () {
     // 初始化台账
     const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
     const billsSheet = billsSpread.getActiveSheet();
-    SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
     SpreadJsObj.initSheet(billsSheet, ledgerSpreadSetting);
     // 初始化部位
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);

+ 105 - 25
app/public/js/ledger.js

@@ -329,7 +329,7 @@ $(document).ready(function() {
                     self.refreshTree(sheet, refreshNode);
                     const sel = sheet.getSelections()[0];
                     sheet.setSelection(tree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
-                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, tree.nodes.indexOf(node)]);
                     self.refreshOperationValid(sheet);
                 });
             }
@@ -354,7 +354,7 @@ $(document).ready(function() {
                     self.refreshTree(sheet, refreshNode);
                     const sel = sheet.getSelections()[0];
                     sheet.setSelection(tree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
-                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, tree.nodes.indexOf(node)]);
                     self.refreshOperationValid(sheet);
                 });
             }
@@ -737,7 +737,7 @@ $(document).ready(function() {
                 const result = tree.loadPostData(data.ledger);
                 self.refreshTree(sheet, result);
                 sheet.setSelection(result.create[0].index, sel.col, sel.rowCount, sel.colCount);
-                SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, result.create[0].index]);
                 self.refreshOperationValid(sheet);
                 removeLocalCache(copyBlockTag);
             }, null, true);
@@ -857,7 +857,7 @@ $(document).ready(function() {
                     treeOperationObj.refreshTree(sheet, refreshNode);
                 })
             }
-        }
+        },
     };
     sjsSettingObj.setFxTreeStyle(ledgerSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     ledgerTreeCol.initSpreadSetting(ledgerSpreadSetting);
@@ -923,6 +923,8 @@ $(document).ready(function() {
         });
 
         $('#bills-expr').bind('change mouseleave', function () {
+            if (document.activeElement.id !== "bills-expr") return;
+
             const expr = $(this);
             const sheet = ledgerSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(sheet);
@@ -1096,6 +1098,13 @@ $(document).ready(function() {
             const row = selection[0].row;
             const select = ledgerTree.nodes[row];
             return select;
+        },
+        disabled: function (key, opt) {
+            const sheet = ledgerSpread.getActiveSheet();
+            const selection = sheet.getSelections();
+            const row = selection[0].row;
+            const select = ledgerTree.nodes[row];
+            return select && select.level <= 1;
         }
     };
     if (!readOnly) {
@@ -1137,6 +1146,18 @@ $(document).ready(function() {
                 return !readOnly;
             }
         };
+        if (!checkTzMeasureType()) {
+            billsContextMenuOptions.items.applyDeal2Sgfh = {
+                name: '填设计量',
+                callback: function (key, opt) {
+                    postData(window.location.pathname + '/deal2sgfh', null, function (result) {
+                        ledgerTree.loadDatas(result.bills);
+                        treeCalc.calculateAll(ledgerTree);
+                        SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
+                    });
+                }
+            };
+        }
         billsContextMenuOptions.items.sprSort = '-----------';
     }
     if (!readOnly) {
@@ -1285,10 +1306,10 @@ $(document).ready(function() {
                             if (refreshNode.create[0]) {
                                 if (sel && sel[0]) {
                                     ledgerSheet.setSelection(refreshNode.create[0].index, sel[0].col, sel[0].rowCount, sel[0].colCount);
-                                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                                    SpreadJsObj.reloadRowsBackColor(ledgerSheet, [sel[0].row, refreshNode.create[0].index]);
                                 } else {
                                     ledgerSheet.setSelection(refreshNode.create[0].index, 0, 1, 1);
-                                    SpreadJsObj.reloadRowsBackColor(sheet, [refreshNode.create[0].index]);
+                                    SpreadJsObj.reloadRowsBackColor(ledgerSheet, [refreshNode.create[0].index]);
                                 }
                             }
                             treeOperationObj.refreshOperationValid(ledgerSheet);
@@ -1338,6 +1359,24 @@ $(document).ready(function() {
         editStarting: function (e, info) {
             posOperationObj.ledgerTreeNode = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
         },
+        loadExprToInput: function () {
+            const sheet = posSpread.getActiveSheet();
+            const sel = sheet.getSelections()[0];
+            if (!sel || !sheet.zh_setting) return;
+
+            const col = sheet.zh_setting.cols[sel.col], cell = sheet.getCell(sel.row, sel.col);
+            if (col && col.type === 'Number') {
+                const data = SpreadJsObj.getSelectObject(sheet);
+                if (data) {
+                    $('#pos-expr').val(data[col.field]).attr('field', col.field).attr('org', data[col.field])
+                        .attr('row', sel.row).attr('readOnly', readOnly || cell.locked());
+                } else {
+                    $('#pos-expr').val('').attr('readOnly', true);
+                }
+            } else {
+                $('#pos-expr').val('').attr('readOnly', true);
+            }
+        },
         /**
          * 加载计量单元 根据当前台账选择节点
          */
@@ -1350,6 +1389,7 @@ $(document).ready(function() {
             } else {
                 SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), 'data', []);
             }
+            posOperationObj.loadExprToInput();
         },
         /**
          * 编辑单元格响应事件
@@ -1603,19 +1643,7 @@ $(document).ready(function() {
             }
         },
         selectionChanged: function (e, info) {
-            const col = info.sheet.zh_setting.cols[info.newSelections[0].col];
-            const cell = info.sheet.getCell(info.newSelections[0].row, info.newSelections[0].col);
-            if (col && col.type === 'Number') {
-                const data = SpreadJsObj.getSelectObject(info.sheet);
-                if (data) {
-                    $('#pos-expr').val(data[col.field]).attr('field', col.field).attr('org', data[col.field])
-                        .attr('row', info.newSelections[0].row).attr('readOnly', readOnly || cell.locked());
-                } else {
-                    $('#pos-expr').val('').attr('readOnly', true);
-                }
-            } else {
-                $('#pos-expr').val('').attr('readOnly', true);
-            }
+            posOperationObj.loadExprToInput();
         },
         addPegs: function (pegs) {
             if (!pegs || pegs.length <= 0) return;
@@ -1637,10 +1665,12 @@ $(document).ready(function() {
     posSpread.bind(spreadNS.Events.SelectionChanged, posOperationObj.selectionChanged);
     if (!posSpreadSetting.readOnly) {
         $('#pos-expr').bind('change mouseleave', function () {
+            if (document.activeElement.id !== "pos-expr") return;
+
             const expr = $(this);
             const posSheet = posSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(posSheet);
-            if (select) return;
+            if (!select) return;
 
             const field = expr.attr('field'), orgValue = expr.attr('org'), newValue = expr.val(), row = trimInvalidChar(expr.attr('row'));
             if (orgValue === newValue || (!orgValue && newValue == '')) { return; }
@@ -1786,12 +1816,12 @@ $(document).ready(function() {
             treeOperationObj.refreshTree(mainSheet, refreshNode);
             if (refreshNode.create && refreshNode.create.length > 0) {
                 mainSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
-                SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[refreshNode.create.length - 1].index]);
+                SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, refreshNode.create[refreshNode.create.length - 1].index]);
             } else {
                 const node = _.find(ledgerTree.nodes, {code: stdNode.code, name: stdNode.name});
                 if (node) {
                     mainSheet.setSelection(ledgerTree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
-                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, ledgerTree.nodes.indexOf(node)]);
+                    SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, ledgerTree.nodes.indexOf(node)]);
                 }
             }
             treeOperationObj.refreshOperationValid(mainSheet);
@@ -2009,14 +2039,13 @@ $(document).ready(function() {
                     treeOperationObj.refreshTree(mainSheet, refreshData);
                     const sel = mainSheet.getSelections()[0];
                     mainSheet.setSelection(refreshData.create[0].index, sel.col, sel.rowCount, sel.colCount);
-                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                    SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, refreshData.create[0].index]);
                     treeOperationObj.refreshOperationValid(mainSheet);
                     ledgerSpread.focus();
                     posOperationObj.loadCurPosData();
                 });
             });
             }
-            SpreadJsObj.forbiddenSpreadContextMenu(selector, this.spread);
             $('#upload-deal-bills').click(function () {
                     const file = $('#deal-bills-file')[0];
                     const formData = new FormData();
@@ -2029,12 +2058,49 @@ $(document).ready(function() {
                         $('#upload-deal').modal('hide');
                     });
                 });
+            if (!readOnly) {
+                $.contextMenu({
+                    selector: selector,
+                    build: function ($trigger, e) {
+                        const target = SpreadJsObj.safeRightClickSelection($trigger, e, self.spread);
+                        return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+                    },
+                    items: {
+                        apply: {
+                            name: '应用全部清单单价至台账',
+                            disabled: function (key, opt) {
+                                const sheet = self.spread.getActiveSheet();
+                                return sheet.getRowCount() === 0;
+                            },
+                            callback: function (key, opt) {
+                                const datas = [], sourceData = self.spread.getActiveSheet().zh_data;
+                                for (const db of sourceData) {
+                                    const targets = ledgerTree.nodes.filter(function (x) {
+                                        return x.b_code === db.code && x.name === db.name && x.unit === db.unit;
+                                    });
+                                    for (const t of targets) {
+                                        if (t.children && t.children.length > 0) continue;
+                                        const data = ledgerTree.getNodeKeyData(t);
+                                        data.unit_price = db.unit_price;
+                                        datas.push(data);
+                                    }
+                                }
+                                postData(window.location.pathname + '/update', {postType: 'update', postData: datas}, function (result) {
+                                    const refreshNode = ledgerTree.loadPostData(result);
+                                    treeOperationObj.refreshTree(ledgerSpread.getActiveSheet(), refreshNode);
+                                });
+                            }
+                        }
+                    }
+                });
+            }
         }
         loadData () {
             const self = this;
             postData(this.url+'/get-data', {}, function (data) {
                 self.data = data;
                 SpreadJsObj.loadSheetData(self.spread.getActiveSheet(), 'data', data);
+                if (data.length > 0) self.spread.getActiveSheet().setSelection(0, 0, 1, 1);
             });
         }
         calculateData () {
@@ -2182,6 +2248,20 @@ $(document).ready(function() {
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                     }
                 }
+                if (info.cellRange.col === 0 && info.cellRange.colCount === 1) {
+                    const dealBills = self.dealSpread.getActiveSheet().zh_data;
+                    if (dealBills && dealBills.length > 0) {
+                        for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                            const curRow = iRow + info.cellRange.row;
+                            const bills = _.find(dealBills, {code: info.sheet.getText(curRow, 0)});
+                            if (bills) {
+                                info.sheet.getCell(curRow, 1).value(bills.name);
+                                info.sheet.getCell(curRow, 2).value(bills.unit);
+                                info.sheet.getCell(curRow, 3).value(bills.unit_price);
+                            }
+                        }
+                    }
+                }
             });
             this.qdSpread.bind(spreadNS.Events.EditEnded, function (e, info) {
                 if (info.col === 0) {
@@ -2219,7 +2299,7 @@ $(document).ready(function() {
                             const result = ledgerTree.loadPostData(data.ledger);
                             treeOperationObj.refreshTree(sheet, result);
                             sheet.setSelection(result.create[0].index, sel.col, sel.rowCount, sel.colCount);
-                            SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshNode.create[0].index]);
+                            SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, result.create[0].index]);
                             treeOperationObj.refreshOperationValid(sheet);
                             self.obj.modal('hide');
                         }, null, true);

+ 44 - 20
app/public/js/revise.js

@@ -984,10 +984,10 @@ $(document).ready(() => {
                                     if (refreshNode.create[0]) {
                                         if (sel && sel[0]) {
                                             billsSheet.setSelection(refreshNode.create[0].index, sel[0].col, sel[0].rowCount, sel[0].colCount);
-                                            SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshData.create[0].index]);
+                                            SpreadJsObj.reloadRowsBackColor(billsSheet, [sel[0].row, refreshNode.create[0].index]);
                                         } else {
                                             billsSheet.setSelection(refreshNode.create[0].index, 0, 1, 1);
-                                            SpreadJsObj.reloadRowsBackColor(sheet, [refreshData.create[0].index]);
+                                            SpreadJsObj.reloadRowsBackColor(billsSheet, [refreshNode.create[0].index]);
                                         }
                                     }
                                     billsTreeSpreadObj.refreshOperationValid(billsSheet);
@@ -1001,6 +1001,24 @@ $(document).ready(() => {
     }
     // 计量单元 相关方法&绑定spreadjs事件
     const posSpreadObj = {
+        loadExprToInput: function () {
+            const sel = posSheet.getSelections()[0];
+            if (!sel) return;
+
+            const col = posSheet.zh_setting.cols[sel.col];
+            const cell = posSheet.getCell(sel.col, sel.col);
+            if (col && col.type === 'Number') {
+                const data = SpreadJsObj.getSelectObject(posSheet);
+                if (data) {
+                    $('#pos-expr').val(data[col.field]).attr('field', col.field).attr('org', data[col.field])
+                        .attr('row', sel.row).attr('readOnly', readOnly || cell.locked());
+                } else {
+                    $('#pos-expr').val('').attr('readOnly', true);
+                }
+            } else {
+                $('#pos-expr').val('').attr('readOnly', true);
+            }            
+        },
         /**
          * 加载计量单元 根据当前台账选择节点
          */
@@ -1013,6 +1031,7 @@ $(document).ready(() => {
                 SpreadJsObj.loadSheetData(posSheet, 'data', []);
             }
             SpreadJsObj.resetFieldReadOnly(posSheet);
+            posSpreadObj.loadExprToInput();
         },
         editStarting: function (e, info) {
             posSpreadObj.billsNode = SpreadJsObj.getSelectObject(billsSheet);
@@ -1285,19 +1304,7 @@ $(document).ready(() => {
             });
         },
         selectionChanged: function (e, info) {
-            const col = info.sheet.zh_setting.cols[info.newSelections[0].col];
-            const cell = info.sheet.getCell(info.newSelections[0].col, info.newSelections[0].col);
-            if (col && col.type === 'Number') {
-                const data = SpreadJsObj.getSelectObject(info.sheet);
-                if (data) {
-                    $('#pos-expr').val(data[col.field]).attr('field', col.field).attr('org', data[col.field])
-                        .attr('row', info.newSelections[0].row).attr('readOnly', readOnly || cell.locked());
-                } else {
-                    $('#pos-expr').val('').attr('readOnly', true);
-                }
-            } else {
-                $('#pos-expr').val('').attr('readOnly', true);
-            }
+            posSpreadObj.loadExprToInput();
         },
         addPegs: function (pegs) {
             if (!pegs || pegs.length <= 0) return;
@@ -1320,12 +1327,15 @@ $(document).ready(() => {
     if (!readOnly && isTz) {
         $('#pos-expr').bind('change mouseleave', function () {
             if (this.readOnly) return;
+            if (document.activeElement.id !== 'pos-expr') return;
 
             const expr = $(this);
             const select = SpreadJsObj.getSelectObject(posSheet);
+            if (!select) return;
+
             const row = posSheet.getSelections()[0].row;
             const field = expr.attr('field'), orgValue = expr.attr('org'), newValue = trimInvalidChar(expr.val());
-            if (orgValue === newValue || (!orgValue && newValue == '')) { return; }
+            if (orgValue === newValue || (!orgValue && newValue == '')) return;
 
             const data = {id: select.id};
             if (newValue !== '') {
@@ -1465,7 +1475,7 @@ $(document).ready(() => {
                         const sel = mainSheet.getSelections()[0];
                         if (sel && refreshData.create[0]) {
                             mainSheet.setSelection(mainTree.nodes.indexOf(refreshData.create[0]), sel.col, sel.rowCount, sel.colCount);
-                            SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, mainTree.nodes.indexOf(refreshData.create[0])]);
+                            SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, mainTree.nodes.indexOf(refreshData.create[0])]);
                         }
                         billsTreeSpreadObj.refreshOperationValid(mainSheet);
                         billsSpread.focus();
@@ -1536,7 +1546,7 @@ $(document).ready(() => {
                         const sel = mainSheet.getSelections()[0];
                         if (sel && refreshData.create[0]) {
                             mainSheet.setSelection(mainTree.nodes.indexOf(refreshData.create[0]), sel.col, sel.rowCount, sel.colCount);
-                            SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, mainTree.nodes.indexOf(refreshData.create[0])]);
+                            SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, mainTree.nodes.indexOf(refreshData.create[0])]);
                         }
                         billsTreeSpreadObj.refreshOperationValid(mainSheet);
                         billsSpread.focus();
@@ -1650,6 +1660,20 @@ $(document).ready(() => {
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                     }
                 }
+                if (info.cellRange.col === 0 && info.cellRange.colCount === 1) {
+                    const dealBills = self.dealSpread.getActiveSheet().zh_data;
+                    if (dealBills && dealBills.length > 0) {
+                        for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                            const curRow = iRow + info.cellRange.row;
+                            const bills = _.find(dealBills, {code: info.sheet.getText(curRow, 0)});
+                            if (bills) {
+                                info.sheet.getCell(curRow, 1).value(bills.name);
+                                info.sheet.getCell(curRow, 2).value(bills.unit);
+                                info.sheet.getCell(curRow, 3).value(bills.unit_price);
+                            }
+                        }
+                    }
+                }
             });
             this.qdSpread.bind(spreadNS.Events.EditEnded, function (e, info) {
                 if (info.col === 0) {
@@ -1950,12 +1974,12 @@ $(document).ready(() => {
             if (sel) {
                 if (refreshNode.create && refreshNode.create.length > 0) {
                     mainSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
-                    SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, refreshData.create[refreshNode.create.length - 1]]);
+                    SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, refreshNode.create[refreshNode.create.length - 1].index]);
                 } else {
                     const node = _.find(mainTree.nodes, {code: stdNode.code, name: stdNode.name});
                     if (node) {
                         mainSheet.setSelection(mainTree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
-                        SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, mainTree.nodes.indexOf(node)]);
+                        SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, mainTree.nodes.indexOf(node)]);
                     }
                 }
             }

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

@@ -13,10 +13,10 @@ const spreadSetting = {
         {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 185, formatter: '@'},
         {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
         {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
-        {title: '本期到场|数量',  colSpan: '2|1', rowSpan: '1|1', field: 'get_qty', hAlign: 2, width: 60, type: 'Number'},
-        {title: '|金额',  colSpan: '|1', rowSpan: '|1', field: 'get_tp', hAlign: 2, width: 60, type: 'Number'},
-        {title: '截止本期到场|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_get_qty', hAlign: 2, width: 60, type: 'Number'},
-        {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_get_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+        {title: '本期到场|数量',  colSpan: '2|1', rowSpan: '1|1', field: 'arrive_qty', hAlign: 2, width: 60, type: 'Number'},
+        {title: '|金额',  colSpan: '|1', rowSpan: '|1', field: 'arrive_tp', hAlign: 2, width: 60, type: 'Number'},
+        {title: '截止本期到场|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_arrive_qty', hAlign: 2, width: 60, type: 'Number'},
+        {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_arrive_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
         {title: '本期扣回|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deduct_qty', hAlign: 2, width: 60, type: 'Number'},
         {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deduct_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
         {title: '截止本期扣回|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_deduct_qty', hAlign: 2, width: 60, type: 'Number'},
@@ -55,4 +55,359 @@ $(document).ready(() => {
             jgclSpread.refresh();
         }
     });
+
+    class Jgcl {
+        constructor (setting) {
+            this.data = [];
+        }
+        resortData() {
+            this.data.sort(function (a, b) {
+                return a.order - b.order;
+            });
+        }
+        calculateAll() {
+            for (const d of this.data) {
+                d.end_arrive_qty = ZhCalc.add(d.pre_arrive_qty, d.arrive_qty);
+                d.end_arrive_tp = ZhCalc.add(d.pre_arrive_tp, d.arrive_tp);
+                d.end_deduct_qty = ZhCalc.add(d.pre_deduct_qty, d.deduct_qty);
+                d.end_deduct_tp = ZhCalc.add(d.pre_deduct_tp, d.deduct_tp);
+            }
+        }
+        loadDatas(datas) {
+            this.data = datas;
+            this.calculateAll();
+            this.resortData();
+        }
+        loadUpdateData(updateData) {
+            if (updateData.add) {
+                for (const a of updateData.add) {
+                    this.data.push(a);
+                }
+            }
+            if (updateData.update) {
+                for (const u of updateData.update) {
+                    const d = this.data.find(function (x) {
+                        return u.id === x.id;
+                    });
+                    if (d) {
+                        _.assign(d, u);
+                    } else {
+                        this.data.push(d);
+                    }
+                }
+            }
+            if (updateData.del) {
+                _.remove(this.data, function (d) {
+                    return updateData.del.indexOf(d.id) >= 0;
+                });
+            }
+            this.calculateAll();
+            this.resortData();
+        }
+    }
+    const jgclObj = new Jgcl();
+
+    postData(window.location.pathname + '/load', null, function (result) {
+        jgclObj.loadDatas(result);
+        SpreadJsObj.loadSheetData(jgclSheet, SpreadJsObj.DataType.Data, jgclObj.data);
+    });
+
+    if (!readOnly) {
+        const jgclOprObj = {
+            /**
+             * 删除按钮响应事件
+             * @param sheet
+             */
+            deletePress: function (sheet) {
+                if (!sheet.zh_setting || readOnly) return;
+
+                const sortData = sheet.zh_data;
+                const datas = [];
+                const sels = sheet.getSelections();
+                if (!sels || !sels[0]) return;
+
+                for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
+                    let bDel = false;
+                    const node = sortData[iRow];
+                    if (node) {
+                        const data = {id: node.id};
+                        for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
+                            const colSetting = sheet.zh_setting.cols[iCol];
+                            if (colSetting.field === 'name') {
+                                toastr.error('名称不能为空,如需删除甲供材料请使用右键删除');
+                                return;
+                            }
+                            const style = sheet.getStyle(iRow, iCol);
+                            if (!style.locked) {
+                                const colSetting = sheet.zh_setting.cols[iCol];
+                                data[colSetting.field] = null;
+                                bDel = true;
+                            }
+                        }
+                        if (bDel) {
+                            datas.push(data);
+                        }
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/update', {updateType: 'update', updateData: datas}, function (result) {
+                        jgclObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(jgclSheet);
+                    }, function () {
+                        SpreadJsObj.reLoadSheetData(jgclSheet);
+                    });
+                }
+            },
+            deleteJgcl: function (sheet) {
+                if (!sheet.zh_setting || readOnly) return;
+
+                const sortData = sheet.zh_data;
+                const datas = [];
+                const sels = sheet.getSelections();
+                if (!sels || !sels[0]) return;
+                const hint = {
+                    isOld: {type: 'warning', msg: '该甲供材料已计量,不可删除'},
+                    invalidDel: {type: 'warning', msg: '该甲供材料不是您新增的,只有原报和新增人可删除'},
+                };
+
+                for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
+                    const node = sortData[iRow];
+                    if (node.pre_used) {
+                        toastMessageUniq(hint.isOld);
+                        continue;
+                    } else {
+                        if (node.add_uid !== userID || stageUserId !== userID) {
+                            toastMessageUniq(hint.invalidDel);
+                            continue;
+                        }
+                        datas.push(node.id);
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/update', {del: datas}, function (result) {
+                        jgclObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(jgclSheet);
+                    }, function () {
+                        SpreadJsObj.reLoadSheetData(jgclSheet);
+                    });
+                }
+            },
+            editEnded: function (e, info) {
+                if (!info.sheet.zh_setting || !info.sheet.zh_data) return;
+
+                const node = info.sheet.zh_data[info.row];
+                const col = info.sheet.zh_setting.cols[info.col];
+                const data = {};
+
+                if (node) {
+                    data.update = {};
+                    data.update.id = node.id;
+
+                    const oldValue = node ? node[col.field] : null;
+                    const newValue = trimInvalidChar(info.editingText);
+                    if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    data.update[col.field] = newValue;
+                } else {
+                    if (col.field !== 'name') {
+                        toastr.warning('新增甲供材料,请先输入名称');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    data.add = {};
+                    data.add.order = info.row + 1;
+                    data.add.name = trimInvalidChar(info.editingText);
+                }
+
+                postData(window.location.pathname + '/update', data, function (result) {
+                    jgclObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadSheetData(info.sheet);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+            editStarting(e, info) {
+                if (!info.sheet.zh_setting || !info.sheet.zh_data) {
+                    info.cancel = true;
+                    return;
+                }
+
+                const col = info.sheet.zh_setting.cols[info.col];
+                const node = info.sheet.zh_data[info.row];
+                if (!node) return;
+
+                switch (col.field) {
+                    case 'name':
+                    case 'unit':
+                    case 'unit_price':
+                        info.cancel = readOnly || node.pre_used;
+                        break;
+                }
+            },
+            clipboardPasting(e, info) {
+                const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
+                info.cancel = true;
+
+                if (!setting || !sortData) return;
+                const pasteData = info.pasteData.html
+                    ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
+                    : (info.pasteData.text === ''
+                        ? SpreadJsObj.Clipboard.getAnalysisPasteText()
+                        : SpreadJsObj.analysisPasteText(info.pasteData.text));
+                const hint = {
+                    name: {type: 'warning', msg: '甲供材料名称不可为空,已过滤'},
+                    unit_price: {type: 'warning', msg: '输入的 单价 非法,已过滤'},
+                    arrive_qty: {type: 'warning', msg: '输入的 本期到场-数量 非法,已过滤'},
+                    reduce_qty: {type: 'warning', msg: '输入的 本期扣回-数量 非法,已过滤'},
+                };
+
+                const uDatas = [], iDatas = [];
+                for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                    const curRow = info.cellRange.row + iRow;
+                    const node = sortData[curRow];
+
+                    let bPaste = false;
+                    const data = {};
+                    for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                        const curCol = info.cellRange.col + iCol;
+                        const colSetting = setting.cols[curCol];
+                        const value = trimInvalidChar(pasteData[iRow][iCol]);
+
+                        if (colSetting.field === 'name' && (!value || value === '')) {
+                            toastMessageUniq(hint.name);
+                            break;
+                        }
+                        if (colSetting.type === 'Number') {
+                            const num = _.toNumber(value);
+                            if (num) {
+                                data[colSetting.field] = num;
+                                bPaste = true;
+                            }
+                        } else {
+                            data[colSetting.field] = value;
+                            bPaste = true;
+                        }
+                    }
+                    if (bPaste) {
+                        if (node) {
+                            data.id = node.id;
+                            uDatas.push(data);
+                        } else {
+                            data.order = curRow + 1;
+                            iDatas.push(data);
+                        }
+                    }
+                }
+                const updateData = {};
+                if (uDatas.length > 0) updateData.update = uDatas;
+                if (iDatas.length > 0) updateData.add = iDatas;
+                if (uDatas.length > 0 || iDatas.length > 0) {
+                    postData(window.location.pathname + '/update', updateData, function (result) {
+                        jgclObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(info.sheet);
+                    });
+                } else {
+                    SpreadJsObj.reLoadSheetData(info.sheet);
+                }
+            },
+            upMove: function () {
+                const sels = jgclSheet.getSelections(), sortData = jgclSheet.zh_data;
+                const node = sortData[sels[0].row];
+                const preNode = sortData[sels[0].row - 1];
+                const data = [
+                    {id: node.id, order: preNode.order},
+                    {id: preNode.id, order: node.order}
+                ];
+                postData(window.location.pathname + '/update', {update: data}, function (result) {
+                    jgclObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadRowsData(jgclSheet, [sels[0].row, sels[0].row - 1]);
+                    jgclSheet.setSelection(sels[0].row - 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+                });
+            },
+            downMove: function () {
+                const sels = jgclSheet.getSelections(), sortData = jgclSheet.zh_data;
+                const node = sortData[sels[0].row];
+                const nextNode = sortData[sels[0].row + 1];
+                const data = [
+                    {id: node.id, order: nextNode.order},
+                    {id: nextNode.id, order: node.order}
+                ];
+                postData(window.location.pathname + '/update', {update: data}, function (result) {
+                    jgclObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadRowsData(jgclSheet, [sels[0].row, sels[0].row + 1]);
+                    jgclSheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+                });
+            }
+        };
+        jgclSheet.bind(spreadNS.Events.EditEnded, jgclOprObj.editEnded);
+        jgclSheet.bind(spreadNS.Events.EditStarting, jgclOprObj.editStarting);
+        jgclSheet.bind(spreadNS.Events.ClipboardPasting, jgclOprObj.clipboardPasting);
+        SpreadJsObj.addDeleteBind(jgclSpread, jgclOprObj.deletePress);
+        $.contextMenu({
+            selector: '#jgcl-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, jgclSpread);
+                return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+            },
+            items: {
+                del: {
+                    name: '删除',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        jgclOprObj.deleteJgcl(jgclSheet);
+                    },
+                    disabled: function (key, opt) {
+                        const sels = jgclSheet.getSelections();
+                        if (!sels || !sels[0]) return true;
+
+                        const row = sels[0].row;
+                        const node = jgclObj.data[row];
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                sprDel: '------------',
+                upMove: {
+                    name: '上移',
+                    icon: 'fa-arrow-up',
+                    callback: function (key, opt) {
+                        jgclOprObj.upMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = jgclSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row === 0) return true;
+
+                        const row = sels[0].row;
+                        const node = jgclObj.data[row];
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                downMove: {
+                    name: '下移',
+                    icon: 'fa-arrow-down',
+                    callback: function (key, opt) {
+                        jgclOprObj.downMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = jgclSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row >= jgclObj.data.length - 1) return true;
+
+                        const row = sels[0].row;
+                        const node = jgclObj.data[row];
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                }
+            },
+        })
+    }
 });

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

@@ -788,6 +788,7 @@ const SpreadJsObj = {
         const index = tree.nodes.indexOf(node);
         const sels = sheet.getSelections();
         sheet.setSelection(index, sels[0].col, 1, 1);
+        SpreadJsObj.reloadRowsBackColor(sheet, [index, sels[0].row]);
         sheet.getParent().focus();
         sheet.showRow(index, spreadNS.VerticalPosition.center);
     },

+ 127 - 3
app/public/js/stage.js

@@ -122,7 +122,7 @@ function getNodeList(node) {
 }
 
 $(document).ready(() => {
-    let detail, searchLedger;
+    let detail, searchLedger, checkedChanges;
     // 界面布局
     autoFlashHeight();
     // 初始化 台账树结构 数据结构
@@ -187,7 +187,7 @@ $(document).ready(() => {
                             return null;
                         }
                     }},
-                    {title: '变更令号', field: 'code', width: 100, formatter: '@', readOnly: true, hAlign: 0, },
+                    {title: '变更令号', field: 'p_code', width: 100, formatter: '@', readOnly: true, hAlign: 0, },
                     {title: '名称', field: 'name', width: 120, formatter: '@', readOnly: true, hAlign: 0,},
                     {title: '变更部位', field: 'b_bwmx', width: 100, formatter: '@', readOnly: true, hAlign: 0,},
                     //{title: '总数量', field: 'b_amount', width: 60, formatter: '@', readOnly: true, hAlign: 2, },
@@ -985,6 +985,8 @@ $(document).ready(() => {
     const stagePosSpreadObj = {
         loadExprToInput(sheet) {
             const sel = sheet.getSelections()[0];
+            if (!sel) return;
+
             const col = sheet.zh_setting.cols[sel.col], cell = sheet.getCell(sel.row, sel.col);
             if (col && col.type === 'Number') {
                 const data = SpreadJsObj.getSelectObject(sheet);
@@ -1014,6 +1016,7 @@ $(document).ready(() => {
             } else {
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', []);
             }
+            stagePosSpreadObj.loadExprToInput(spSpread.getActiveSheet());
         },
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {
@@ -1123,7 +1126,7 @@ $(document).ready(() => {
                 const range = info.cellRange;
                 const validField = ['contract_qty', 'qc_qty', 'postil'];
                 if (!checkTzMeasureType()) {
-                    validField.push('name', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'position');
+                    validField.push('name', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'position', 'drawing_code');
                 }
                 for (let iCol = range.col; iCol < range.col + range.colCount; iCol++) {
                     const col = info.sheet.zh_setting.cols[iCol];
@@ -1379,6 +1382,7 @@ $(document).ready(() => {
     if (!readOnly) {
         $('#pos-expr').bind('change mouseleave', function () {
             if (this.readOnly) return;
+            if (document.activeElement.id !== "pos-expr") return;
 
             const expr = $(this);
             const posSheet = spSpread.getActiveSheet();
@@ -1491,6 +1495,7 @@ $(document).ready(() => {
             if (detail) {
                 detail.spread.refresh();
             }
+            if (checkedChanges) checkedChanges.refresh();
         }
     });
 
@@ -1805,6 +1810,7 @@ $(document).ready(() => {
             if (detail) {
                 detail.spread.refresh();
             }
+            if (checkedChanges) checkedChanges.refresh();
         }
     });
 
@@ -2530,6 +2536,114 @@ $(document).ready(() => {
             $('#view-calc-img').attr('src', calcImgSrc);
         }
     }
+    class CheckedChange {
+        constructor (setting) {
+            const self = this;
+            this.changeSpreadSetting = {
+                cols: [
+                    {title: '变更令号', colSpan: '1', rowSpan: '1', field: 'p_code', hAlign: 0, width: 100, formatter: '@'},
+                    {title: '变更名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 180, formatter: '@'},
+                    {title: '金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 80, type: 'Number'},
+                    {title: '批复文号', colSpan: '1', rowSpan: '1', field: 'w_code', hAlign: 0, width: 100, formatter: '@'},
+                ],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                readOnly: true,
+            };
+            this.changeSpread = SpreadJsObj.createNewSpread(setting.changeObj[0]);
+            this.changeSheet = this.changeSpread.getActiveSheet();
+            SpreadJsObj.initSheet(this.changeSheet, this.changeSpreadSetting);
+
+            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: '@'},
+                ],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                readOnly: true
+            };
+            this.changeBillsSpread = SpreadJsObj.createNewSpread(setting.changeBillsObj[0]);
+            this.changeBillsSheet = this.changeBillsSpread.getActiveSheet();
+            SpreadJsObj.initSheet(this.changeBillsSheet, this.changeBillsSpreadSetting);
+
+            this.changeSheet.bind(spreadNS.Events.SelectionChanged, function (e, info) {
+                const change = SpreadJsObj.getSelectObject(self.changeSheet);
+                if (change.cid === self.curChangeId) { return; }
+                self.curChangeId = change.cid;
+                if (change.detail) {
+                    self.loadChangeDetailData();
+                } else {
+                    postData(window.location.pathname + '/change/detail', {cid: change.cid}, function (result) {
+                        change.detail = result;
+                        self.analyzeChange(change);
+                        self.loadChangeDetailData();
+                    });
+                }
+            });
+            this.changes = null;
+            this.reloadChangeData();
+            setting.reloadObj.click(function() {
+                self.reloadChangeData();
+            });
+        }
+        loadChangeDetailData() {
+            const change = SpreadJsObj.getSelectObject(this.changeSheet);
+            if (change) {
+                SpreadJsObj.loadSheetData(this.changeBillsSheet, SpreadJsObj.DataType.Data, change.bills);
+            } else {
+                SpreadJsObj.loadSheetData(this.changeBillsSheet, SpreadJsObj.DataType.Data, []);
+            }
+        }
+        refresh() {
+            this.changeSpread.refresh();
+            this.changeBillsSpread.refresh();
+        }
+        reloadChangeData() {
+            const self = this;
+            postData(window.location.pathname + '/change/data', null, function (result) {
+                self.changes = result.changes;
+                SpreadJsObj.loadSheetData(self.changeSheet, SpreadJsObj.DataType.Data, self.changes);
+                self.changeSheet.setSelection(0, 0, 1, 1);
+                if (self.changes.length > 0) self.analyzeChange(result.changes[0]);
+                self.loadChangeDetailData();
+            });
+        }
+        analyzeChange(change) {
+            change.bills = change.detail.bills;
+            for (const b of change.bills) {
+                console.log(b);
+                const aub = change.detail.addUsedBills.find(function (x) {
+                    return x.id === b.id;
+                });
+                if (aub) {
+                    b.used_qty = aub.used_qty;
+                }
+                b.qty = _.toNumber(b.samount);
+                b.valid_qty = ZhCalc.sub(b.qty, b.used_qty);
+                b.tp = ZhCalc.round(ZhCalc.mul(b.qty, b.unit_price), tenderInfo.decimal.tp);
+                b.pos = _.filter(change.detail.curUsedBills, {cbid: b.id});
+                b.cur_qty = 0;
+                for (const p of b.pos) {
+                    p.f_qty = p.p_qty ? p.p_qty : p.l_qty;
+                    b.cur_qty = ZhCalc.add(b.cur_qty, p.qty);
+                }
+            }
+        }
+    }
     // 展开收起附件
     $('a', '.right-nav').bind('click', function () {
         //const main = $('#main-view'), tool = $('#tools-view');
@@ -2577,6 +2691,16 @@ $(document).ready(() => {
                     detail.spread.refresh();
                 }
             }
+            if (tab.attr('content') === '#checked-change') {
+                if (!checkedChanges) {
+                    checkedChanges = new CheckedChange({
+                        changeObj: $('#cc-spread'),
+                        changeBillsObj: $('#ccb-spread'),
+                        reloadObj: $('#refresh-cc'),
+                    });
+                    checkedChanges.refresh();
+                }
+            }
         } else {
             tab.removeClass('active');
             tabPanel.removeClass('active');

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

@@ -71,7 +71,7 @@ $(document).ready(() => {
     // 初始化变更令spread
     const changeSpreadSetting = {
         cols: [
-            {title: '变更令号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: true},
+            {title: '变更令号', colSpan: '1', rowSpan: '1', field: 'p_code', hAlign: 0, width: 150, formatter: '@', readOnly: true},
             {title: '变更名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 350, formatter: '@', readOnly: true},
             {title: '金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 100, type: 'Number', readOnly: true},
             {title: '批复文号', colSpan: '1', rowSpan: '1', field: 'w_code', hAlign: 0, width: 150, formatter: '@', readOnly: true},

+ 7 - 81
app/public/js/tender_list.js

@@ -317,14 +317,15 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
 function getTenderTreeHtml () {
     if (tenderTree.length > 0) {
         const html = [];
-        html.push('<table class="table table-hover table-bordered">');
-        html.push('<thead>', '<tr>');
+        html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
+        html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');
         html.push('<th>', '标段名称', '</th>');
         html.push('<th>', '创建人', '</th>');
         html.push('<th>', '创建时间', '</th>');
         html.push('<th>', '计量期数', '</th>');
         html.push('<th>', '审批状态', '</th>');
         html.push('</tr>', '</thead>');
+        parentId = 0;
         for (const t of tenderTree) {
             html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
         }
@@ -361,6 +362,8 @@ $(document).ready(() => {
     initTenderTree();
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
+    localHideList();
+
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();
@@ -386,6 +389,7 @@ $(document).ready(() => {
             initCategoryLevelNode();
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
+            localHideList();
             $('#cate-set').modal('hide');
         });
     });
@@ -417,88 +421,10 @@ $(document).ready(() => {
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
             bindTenderUrl();
+            localHideList();
             $('#add-bd').modal('hide');
             $('[name=name]', '#add-bd').val('');
             $('#hide-all').hide();
         });
     });
-
-    // 展开和收起
-    $('body').on('click', '.fold-switch', function () {
-        if ($(this).children('i').hasClass('fa-minus-square-o')) {
-            $(this).children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-            $(this).attr('title', '展开');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'hide');
-        } else {
-            $(this).children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-            $(this).attr('title', '收起');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'show');
-        }
-    });
-    
-    // 一键展开和收起
-    $('body').on('click', '.tree-toggle', function () {
-        const item = $(this).attr('data-item');
-        for (const tree of tenderTree) {
-            if (tree && tree.sort_id !== undefined) {
-                const cid = tree.sort_id;
-                const node = findTenderTreeNode(parseInt(cid), tenderTree);
-                console.log(node);
-                console.log(returnItem);
-                if (item === 'open') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '收起');
-                    doTrStatus(returnItem, 'show', 'all');
-                } else if (item === 'hide') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
-                    doTrStatus(returnItem, 'hide', 'all')
-                }
-            }
-        }
-    })
 });
-
-function doTrStatus(node, status, all = '') {
-    if (status === 'show') {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').show();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '收起');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-plus-square-o').removeClass('fa-minus-square-o').addClass('fa-minus-square-o');
-        }
-    } else {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').hide();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '展开');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-minus-square-o').removeClass('fa-plus-square-o').addClass('fa-plus-square-o');
-        }
-    }
-    // 判断是否还有一层
-    if (node.children && all === '') {
-        for (const [index,c] of node.children.entries()) {
-            const title = $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').eq(index).attr('title');
-            if (title === '收起') {
-                doTrStatus(c, status);
-            }
-        }
-    } else if (node.children && all === 'all') {
-        for (const c of node.children) {
-            doTrStatus(c, status, 'all');
-        }
-    }
-}
-let returnItem;
-const findTenderTreeNode = function(sortId, tree) {
-    tree.forEach((item) => {
-        if (item.sort_id !== undefined && item.sort_id === sortId) {
-            returnItem = item;
-            return item;
-        } else if (item.children && item.children.length > 0) {
-            findTenderTreeNode(sortId, item.children);
-        }
-    });
-}

+ 6 - 81
app/public/js/tender_list_info.js

@@ -342,8 +342,8 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
 function getTenderTreeHtml () {
     if (tenderTree.length > 0) {
         const html = [];
-        html.push('<table class="table table-hover table-bordered">');
-        html.push('<thead>', '<tr>');
+        html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
+        html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');
         html.push('<th>', '名称', '</th>');
         html.push('<th>', '计量模式', '</th>');
         html.push('<th>', '计量期数', '</th>');
@@ -357,6 +357,7 @@ function getTenderTreeHtml () {
         html.push('<th>', '本期应付', '</th>');
         html.push('<th>', '截止本期应付', '</th>');
         html.push('</tr>', '</thead>');
+        parentId = 0;
         for (const t of tenderTree) {
             html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
         }
@@ -393,6 +394,7 @@ $(document).ready(() => {
     initTenderTree();
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
+    localHideList();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();
@@ -418,6 +420,7 @@ $(document).ready(() => {
             initCategoryLevelNode();
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
+            localHideList();
             $('#cate-set').modal('hide');
         });
     });
@@ -449,88 +452,10 @@ $(document).ready(() => {
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
             bindTenderUrl();
+            localHideList();
             $('#add-bd').modal('hide');
             $('[name=name]', '#add-bd').val('');
             $('#hide-all').hide();
         });
     });
-
-    // 展开和收起
-    $('body').on('click', '.fold-switch', function () {
-        if ($(this).children('i').hasClass('fa-minus-square-o')) {
-            $(this).children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-            $(this).attr('title', '展开');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'hide');
-        } else {
-            $(this).children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-            $(this).attr('title', '收起');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'show');
-        }
-    });
-
-    // 一键展开和收起
-    $('body').on('click', '.tree-toggle', function () {
-        const item = $(this).attr('data-item');
-        for (const tree of tenderTree) {
-            if (tree && tree.sort_id !== undefined) {
-                const cid = tree.sort_id;
-                const node = findTenderTreeNode(parseInt(cid), tenderTree);
-                console.log(node);
-                console.log(returnItem);
-                if (item === 'open') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '收起');
-                    doTrStatus(returnItem, 'show', 'all');
-                } else if (item === 'hide') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
-                    doTrStatus(returnItem, 'hide', 'all')
-                }
-            }
-        }
-    })
 });
-
-function doTrStatus(node, status, all = '') {
-    if (status === 'show') {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').show();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '收起');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-plus-square-o').removeClass('fa-minus-square-o').addClass('fa-minus-square-o');
-        }
-    } else {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').hide();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '展开');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-minus-square-o').removeClass('fa-plus-square-o').addClass('fa-plus-square-o');
-        }
-    }
-    // 判断是否还有一层
-    if (node.children && all === '') {
-        for (const [index,c] of node.children.entries()) {
-            const title = $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').eq(index).attr('title');
-            if (title === '收起') {
-                doTrStatus(c, status);
-            }
-        }
-    } else if (node.children && all === 'all') {
-        for (const c of node.children) {
-            doTrStatus(c, status, 'all');
-        }
-    }
-}
-let returnItem;
-const findTenderTreeNode = function(sortId, tree) {
-    tree.forEach((item) => {
-        if (item.sort_id !== undefined && item.sort_id === sortId) {
-            returnItem = item;
-            return item;
-        } else if (item.children && item.children.length > 0) {
-            findTenderTreeNode(sortId, item.children);
-        }
-    });
-}

+ 7 - 82
app/public/js/tender_list_manage.js

@@ -301,7 +301,8 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
 }
 function getTenderTreeHeaderHtml() {
     const html = [];
-    html.push('<thead>', '<tr>');
+    html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
+    html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');
     html.push('<th>', '名称', '</th>');
     html.push('<th>', '创建人', '</th>');
     html.push('<th>', '创建时间', '</th>');
@@ -314,8 +315,8 @@ function getTenderTreeHeaderHtml() {
 function getTenderTreeHtml () {
     if (tenderTree.length > 0) {
         const html = [];
-        html.push('<table class="table table-hover table-bordered">');
         html.push(getTenderTreeHeaderHtml());
+        parentId = 0;
         for (const t of tenderTree) {
             html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
         }
@@ -373,6 +374,7 @@ $(document).ready(() => {
     initTenderTree();
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
+    localHideList();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();
@@ -398,6 +400,7 @@ $(document).ready(() => {
             initCategoryLevelNode();
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
+            localHideList();
             $('#cate-set').modal('hide');
         });
     });
@@ -436,6 +439,7 @@ $(document).ready(() => {
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
             bindTenderUrl();
+            localHideList();
             $('#add-bd').modal('hide');
             $('[name=name]', '#add-bd').val('');
         });
@@ -471,6 +475,7 @@ $(document).ready(() => {
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
             bindTenderUrl();
+            localHideList();
             $('#edit-bd').modal('hide');
         });
     });
@@ -516,84 +521,4 @@ $(document).ready(() => {
             $('#del-bd').modal('hide');
         }
     });
-
-    // 展开和收起
-    $('body').on('click', '.fold-switch', function () {
-        if ($(this).children('i').hasClass('fa-minus-square-o')) {
-            $(this).children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-            $(this).attr('title', '展开');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'hide');
-        } else {
-            $(this).children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-            $(this).attr('title', '收起');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'show');
-        }
-    });
-
-    // 一键展开和收起
-    $('body').on('click', '.tree-toggle', function () {
-        const item = $(this).attr('data-item');
-        for (const tree of tenderTree) {
-            if (tree && tree.sort_id !== undefined) {
-                const cid = tree.sort_id;
-                const node = findTenderTreeNode(parseInt(cid), tenderTree);
-                console.log(node);
-                console.log(returnItem);
-                if (item === 'open') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '收起');
-                    doTrStatus(returnItem, 'show', 'all');
-                } else if (item === 'hide') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
-                    doTrStatus(returnItem, 'hide', 'all')
-                }
-            }
-        }
-    })
 });
-
-function doTrStatus(node, status, all = '') {
-    if (status === 'show') {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').show();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '收起');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-plus-square-o').removeClass('fa-minus-square-o').addClass('fa-minus-square-o');
-        }
-    } else {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').hide();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '展开');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-minus-square-o').removeClass('fa-plus-square-o').addClass('fa-plus-square-o');
-        }
-    }
-    // 判断是否还有一层
-    if (node.children && all === '') {
-        for (const [index,c] of node.children.entries()) {
-            const title = $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').eq(index).attr('title');
-            if (title === '收起') {
-                doTrStatus(c, status);
-            }
-        }
-    } else if (node.children && all === 'all') {
-        for (const c of node.children) {
-            doTrStatus(c, status, 'all');
-        }
-    }
-}
-let returnItem;
-const findTenderTreeNode = function(sortId, tree) {
-    tree.forEach((item) => {
-        if (item.sort_id !== undefined && item.sort_id === sortId) {
-            returnItem = item;
-            return item;
-        } else if (item.children && item.children.length > 0) {
-            findTenderTreeNode(sortId, item.children);
-        }
-    });
-}
-

+ 11 - 86
app/public/js/tender_list_progress.js

@@ -286,7 +286,7 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
     const html = [];
     html.push('<tr pid="' + pid + '">');
     // 名称
-    html.push('<td class="in-' + node.level + '">');
+    html.push('<td width="40%" class="in-' + node.level + '">');
     if (node.cid) {
         html.push('<span class="fold-switch mr-1" title="收起" cid="'+ node.sort_id +'"><i class="fa fa-minus-square-o"></i></span> <i class="fa fa-folder-o"></i> ', node.name);
     } else {
@@ -298,13 +298,13 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
     }
     html.push('</td>');
     // 计量期数
-    html.push('<td>');
+    html.push('<td width="120">');
     if (!node.cid) {
         html.push(node.lastStage ? '第' + node.lastStage.order + '期' : '台账');
     }
     html.push('</td>');
     // 累计合同计量
-    html.push('<td>');
+    html.push('<td width="15%">');
     const sum = node.lastStage ? ZhCalc.add(node.total_price, node.lastStage.end_qc_tp) : node.total_price;
     html.push(node.sum_tp ? node.sum_tp : '');
     html.push('</td>');
@@ -328,13 +328,14 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
 function getTenderTreeHtml () {
     if (tenderTree.length > 0) {
         const html = [];
-        html.push('<table class="table table-hover table-bordered">');
-        html.push('<thead>', '<tr>');
-        html.push('<th>', '名称', '</th>');
+        html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
+        html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');;
+        html.push('<th width="60%">', '名称', '</th>');
         html.push('<th width="120">', '计量期数', '</th>');
-        html.push('<th>', '总价 <i class="fa fa-question-circle text-primary"  data-placement="bottom" data-toggle="tooltip" data-original-title="0号台账+截止本期数量变更"></i>', '</th>');
+        html.push('<th width="10%">', '总价 <i class="fa fa-question-circle text-primary"  data-placement="bottom" data-toggle="tooltip" data-original-title="0号台账+截止本期数量变更"></i>', '</th>');
         html.push('<th>', '截止上期完成/本期完成/未完成', '</th>');
         html.push('</tr>', '</thead>');
+        parentId = 0;
         for (const t of tenderTree) {
             html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
         }
@@ -371,6 +372,7 @@ $(document).ready(() => {
     initTenderTree();
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
+    localHideList();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();
@@ -396,6 +398,7 @@ $(document).ready(() => {
             initCategoryLevelNode();
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
+            localHideList();
             $('#cate-set').modal('hide');
         });
     });
@@ -426,87 +429,9 @@ $(document).ready(() => {
             initTenderTree();
             $('.c-body').html(getTenderTreeHtml());
             bindTenderUrl();
+            localHideList();
             $('#add-bd').modal('hide');
             $('[name=name]', '#add-bd').val('');
         });
     });
-
-    // 展开和收起
-    $('body').on('click', '.fold-switch', function () {
-        if ($(this).children('i').hasClass('fa-minus-square-o')) {
-            $(this).children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-            $(this).attr('title', '展开');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'hide');
-        } else {
-            $(this).children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-            $(this).attr('title', '收起');
-            const cid = $(this).attr('cid');
-            const node = findTenderTreeNode(parseInt(cid), tenderTree);
-            doTrStatus(returnItem, 'show');
-        }
-    });
-
-    // 一键展开和收起
-    $('body').on('click', '.tree-toggle', function () {
-        const item = $(this).attr('data-item');
-        for (const tree of tenderTree) {
-            if (tree && tree.sort_id !== undefined) {
-                const cid = tree.sort_id;
-                const node = findTenderTreeNode(parseInt(cid), tenderTree);
-                console.log(node);
-                console.log(returnItem);
-                if (item === 'open') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '收起');
-                    doTrStatus(returnItem, 'show', 'all');
-                } else if (item === 'hide') {
-                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
-                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
-                    doTrStatus(returnItem, 'hide', 'all')
-                }
-            }
-        }
-    })
 });
-
-function doTrStatus(node, status, all = '') {
-    if (status === 'show') {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').show();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '收起');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-plus-square-o').removeClass('fa-minus-square-o').addClass('fa-minus-square-o');
-        }
-    } else {
-        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').hide();
-        if (all === 'all') {
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '展开');
-            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-minus-square-o').removeClass('fa-plus-square-o').addClass('fa-plus-square-o');
-        }
-    }
-    // 判断是否还有一层
-    if (node.children && all === '') {
-        for (const [index,c] of node.children.entries()) {
-            const title = $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').eq(index).attr('title');
-            if (title === '收起') {
-                doTrStatus(c, status);
-            }
-        }
-    } else if (node.children && all === 'all') {
-        for (const c of node.children) {
-            doTrStatus(c, status, 'all');
-        }
-    }
-}
-let returnItem;
-const findTenderTreeNode = function(sortId, tree) {
-    tree.forEach((item) => {
-        if (item.sort_id !== undefined && item.sort_id === sortId) {
-            returnItem = item;
-            return item;
-        } else if (item.children && item.children.length > 0) {
-            findTenderTreeNode(sortId, item.children);
-        }
-    });
-}

+ 148 - 0
app/public/js/tender_showhide.js

@@ -0,0 +1,148 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author EllisRan
+ * @date 2020/03/06
+ * @version
+ */
+let hideList = [];
+let returnItem;
+const findTenderTreeNode = function(sortId, tree) {
+    tree.forEach((item) => {
+        if (item.sort_id !== undefined && item.sort_id === sortId) {
+            returnItem = item;
+            return item;
+        } else if (item.children && item.children.length > 0) {
+            findTenderTreeNode(sortId, item.children);
+        }
+    });
+}
+
+function removeValueToCate(cate) {
+    const changeCate = JSON.parse(JSON.stringify(cate));
+    const newCate = [];
+    for (const c of changeCate) {
+        delete c.value;
+        newCate.push(c);
+    }
+    return newCate;
+}
+
+function localHideList() {
+    const pro_cate = getLocalCache('pro_'+ pid + '_category_list');
+    const cate = JSON.stringify(removeValueToCate(category));
+    if (pro_cate && cate === pro_cate) {
+        const userTenderHideList = getLocalCache(uphlname);
+        if (userTenderHideList) {
+            hideList = JSON.parse(userTenderHideList);
+            for (const h of hideList) {
+                const cid = h.sort_id;
+                const node = findTenderTreeNode(parseInt(cid), tenderTree);
+                $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
+                $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
+                doTrStatus(returnItem, 'hide');
+            }
+        }
+    } else {
+        removeLocalCache(uphlname);
+        setLocalCache('pro_'+ pid + '_category_list', cate);
+    }
+    setTopTr();
+}
+$(window).resize(setTopTr);
+// 设置表头固定并动态调整宽度高度
+function setTopTr() {
+    for(let item = 0; item < $(".c-body table>thead>tr>th").length; item ++) {
+        $(".c-body table>thead>tr>th").eq(item).outerWidth($(".c-body table>tbody>tr:first").children('td').eq(item).outerWidth());
+    }
+    $('.c-body table').css('margin-top', $(".c-body table>thead").height() - 4);
+}
+
+function doTrStatus(node, status, all = '') {
+    if (status === 'show') {
+        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').show();
+        if (all === 'all') {
+            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '收起');
+            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-plus-square-o').removeClass('fa-minus-square-o').addClass('fa-minus-square-o');
+        }
+    } else {
+        $('.c-body').find('tr[pid="'+ node.sort_id +'"]').hide();
+        if (all === 'all') {
+            if (node.children) {
+                hideList.push({sort_id: node.sort_id});
+                setLocalCache(uphlname, JSON.stringify(hideList));
+            }
+            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').attr('title', '展开');
+            $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch i').removeClass('fa-minus-square-o').removeClass('fa-plus-square-o').addClass('fa-plus-square-o');
+        }
+    }
+    // 判断是否还有一层
+    if (node.children && all === '') {
+        for (const [index,c] of node.children.entries()) {
+            const title = $('.c-body').find('tr[pid="'+ node.sort_id +'"] .fold-switch').eq(index).attr('title');
+            if (title === '收起') {
+                doTrStatus(c, status);
+            }
+        }
+    } else if (node.children && all === 'all') {
+        for (const c of node.children) {
+            doTrStatus(c, status, 'all');
+        }
+    }
+}
+
+$(document).ready(() => {
+    // 展开和收起
+    $('body').on('click', '.fold-switch', function () {
+        if ($(this).children('i').hasClass('fa-minus-square-o')) {
+            $(this).children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
+            $(this).attr('title', '展开');
+            const cid = $(this).attr('cid');
+            const node = findTenderTreeNode(parseInt(cid), tenderTree);
+            doTrStatus(returnItem, 'hide');
+            hideList.push({sort_id: cid});
+            setLocalCache(uphlname, JSON.stringify(hideList));
+        } else {
+            $(this).children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
+            $(this).attr('title', '收起');
+            const cid = $(this).attr('cid');
+            const node = findTenderTreeNode(parseInt(cid), tenderTree);
+            doTrStatus(returnItem, 'show');
+            const index = hideList.findIndex(function(item) {
+                return parseInt(item.sort_id) === parseInt(cid);
+            });
+            hideList.splice(index, 1);
+            setLocalCache(uphlname, JSON.stringify(hideList));
+        }
+        setTopTr();
+    });
+
+    // 一键展开和收起
+    $('body').on('click', '.tree-toggle', function () {
+        const item = $(this).attr('data-item');
+        hideList = [];
+        if (item === 'open') {
+            setLocalCache(uphlname, JSON.stringify(hideList));
+        }
+        for (const tree of tenderTree) {
+            if (tree && tree.sort_id !== undefined) {
+                const cid = tree.sort_id;
+                const node = findTenderTreeNode(parseInt(cid), tenderTree);
+                if (item === 'open') {
+                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
+                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '收起');
+                    doTrStatus(returnItem, 'show', 'all');
+                } else if (item === 'hide') {
+                    $('.c-body tr td span[cid="' + cid + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
+                    $('.c-body tr td span[cid="' + cid + '"]').attr('title', '展开');
+                    doTrStatus(returnItem, 'hide', 'all');
+                }
+            }
+        }
+        setTopTr();
+    })
+});
+
+

+ 2 - 1
app/public/report/js/rpt_main.js

@@ -320,6 +320,7 @@ let zTreeOprObj = {
                     }
                     // zTreeOprObj.resetESignature(zTreeOprObj.currentRptPageRst);
                     rptSignatureHelper.buildSelectableAccount();
+                    rptSignatureHelper.buildSelectableAccountUsed();
                     rptSignatureHelper.buildRoleDom(ROLE_LIST);
                     me.showPage(1, canvas);
                 } else {
@@ -776,4 +777,4 @@ function getStageOrder() {
 
 function getStageTimes() {
     return current_stage_times;
-}
+}

+ 71 - 22
app/public/report/js/rpt_signature.js

@@ -17,6 +17,7 @@ let rptSignatureHelper = {
         // $("#project_account_select_div").empty();
         let accDiv = $('#project_account_select_div');
         let accSelect = $('#project_account_select_dom'); //绑定成员
+        let searchInput = $('#search_account').val();
         accDiv.empty();
         accSelect.empty();
         //2. 一个个加可选用户项
@@ -25,29 +26,31 @@ let rptSignatureHelper = {
         const acc_role_keys = [];
         for (let accIdx = 0; accIdx < PRJ_ACCOUNT_LIST.length; accIdx++) {
             const prjAccount = PRJ_ACCOUNT_LIST[accIdx];
-            let companyKey = prjAccount.account_group;
-            let roleKey = prjAccount.role;
-            if (companyKey === '') {
-                companyKey = '其他单位';
-            }
-            if (roleKey === '') {
-                roleKey = DFT_ROLE_NAME;
-            }
-            let keyIdx = acc_role_keys.indexOf(companyKey);
-            if (keyIdx < 0) {
-                acc_role_keys.push(companyKey);
-                prj_accounts.push([]);
-                prj_sel_option_accounts.push([]);
-                keyIdx = prj_accounts.length - 1;
-                //这里先push一些 html prefix,在后面统一在push html suffix
-                prj_accounts[keyIdx].push('<ul class="list-group">');
-                prj_accounts[keyIdx].push('<li class="px-2 text-muted"><i class="fa fa-caret-down"></i> ' + companyKey + '</li>');
-                prj_sel_option_accounts[keyIdx].push('<optgroup label=" ' + companyKey + '">');
+            if (searchInput === '' || (searchInput !== '' && prjAccount.name.indexOf(searchInput) !== -1)) {
+                let companyKey = prjAccount.account_group;
+                let roleKey = prjAccount.role;
+                if (companyKey === '') {
+                    companyKey = '其他单位';
+                }
+                if (roleKey === '') {
+                    roleKey = DFT_ROLE_NAME;
+                }
+                let keyIdx = acc_role_keys.indexOf(companyKey);
+                if (keyIdx < 0) {
+                    acc_role_keys.push(companyKey);
+                    prj_accounts.push([]);
+                    prj_sel_option_accounts.push([]);
+                    keyIdx = prj_accounts.length - 1;
+                    //这里先push一些 html prefix,在后面统一在push html suffix
+                    prj_accounts[keyIdx].push('<ul class="list-group">');
+                    prj_accounts[keyIdx].push('<li class="px-2 text-muted"><i class="fa fa-caret-down"></i> ' + companyKey + '</li>');
+                    prj_sel_option_accounts[keyIdx].push('<optgroup label=" ' + companyKey + '">');
+                }
+                //push item
+                prj_accounts[keyIdx].push('<li class="add-sign-list-item"><a href="javascript:void(0)" onclick="rptSignatureHelper.createEsignatureByAccIdx(' + accIdx + ')" class="btn-link pull-right" title="添加" data-dismiss="modal"><i class="fa fa-plus"></i></a>' +
+                    prjAccount.name + '-<small class="text-muted">' + roleKey + '</small></li>');
+                prj_sel_option_accounts[keyIdx].push('<option value="' + accIdx + '">' + prjAccount.name + '-' + roleKey + '</option>');
             }
-            //push item
-            prj_accounts[keyIdx].push('<li class="add-sign-list-item"><a href="javascript:void(0)" onclick="rptSignatureHelper.createEsignatureByAccIdx(' + accIdx + ')" class="btn-link pull-right" title="添加" data-dismiss="modal"><i class="fa fa-plus"></i></a>' +
-                prjAccount.name + '-<small class="text-muted">' + roleKey + '</small></li>');
-            prj_sel_option_accounts[keyIdx].push('<option value="' + accIdx + '">' + prjAccount.name + '-' + roleKey + '</option>');
         }
         for (const prjAccList of prj_accounts) {
             prjAccList.push('</ul>');
@@ -62,6 +65,33 @@ let rptSignatureHelper = {
         accDiv.append(prj_accounts.join(''));
         accSelect.append(prj_sel_option_accounts.join(''));
     },
+    buildSelectableAccountUsed: function () {
+        //PRJ_ACCOUNT_LIST
+        //1. 清理所有选择项
+        // $("#project_account_select_div").empty();
+        let accDiv = $('#account_used_select_div');
+        accDiv.empty();
+
+        //2. 一个个加可选用户项
+        const prj_accounts = [];
+        for (let uidx = 0; uidx < USED_LIST.length; uidx++) {
+            const accIdx = PRJ_ACCOUNT_LIST.findIndex(function(item) {
+                return item.id === USED_LIST[uidx].uid;
+            });
+            if (accIdx === -1 || accIdx === undefined) {
+                continue;
+            }
+            const prjAccount = PRJ_ACCOUNT_LIST[accIdx];
+            let roleKey = prjAccount.role;
+            if (roleKey === '') {
+                roleKey = DFT_ROLE_NAME;
+            }
+            //push item
+            prj_accounts.push('<li class="add-sign-list-item"><a href="javascript:void(0)" onclick="rptSignatureHelper.createEsignatureByAccIdx(' + accIdx + ')" class="btn-link pull-right" title="添加" data-dismiss="modal"><i class="fa fa-plus"></i></a>' +
+                prjAccount.name + '-<small class="text-muted">' + roleKey + '</small></li>');
+        }
+        accDiv.append(prj_accounts.join(''));
+    },
     createEsignatureByAccIdx: function (accIdx) {
         rptSignatureHelper.createPreSelectedSignature(PRJ_ACCOUNT_LIST[accIdx], null);
     },
@@ -128,6 +158,25 @@ let rptSignatureHelper = {
             //.appendChild(pNode);
             //*/
             // 2.2 date-picker
+
+            // 更新最近使用名单
+            const params = {};
+            params.uid = userAcc.id;
+            params.prj_id = PROJECT_ID;
+            params.tender_id = TENDER_ID;
+            CommonAjax.postXsrfEx("/tender/report_api/updateSignatureUsed", params, 10000, true, getCookie('csrfToken'),
+                function(result){
+                    console.log(result);
+                    USED_LIST = result.data;
+                    $('#search_account').val('');
+                    rptSignatureHelper.buildSelectableAccount();
+                    rptSignatureHelper.buildSelectableAccountUsed();
+                }, function(err){
+                    // hintBox.unWaitBox();
+                }, function(ex){
+                    // hintBox.unWaitBox();
+                }
+            );
         }
     },
     cleanOldSignature: function (signature_name) {

+ 8 - 0
app/router.js

@@ -99,6 +99,7 @@ module.exports = app => {
     app.get('/tender/:id/ledger/download/:file', sessionAuth, tenderCheck, 'ledgerController.download');
     app.post('/tender/:id/pos/update', sessionAuth, tenderCheck, 'ledgerController.posUpdate');
     app.post('/tender/:id/pos/paste', sessionAuth, tenderCheck, 'ledgerController.posPaste');
+    app.post('/tender/:id/ledger/deal2sgfh', sessionAuth, tenderCheck, 'ledgerController.deal2sgfh');
     // 台账审批相关
     app.get('/tender/:id/ledger/audit', sessionAuth, tenderCheck, 'ledgerAuditController.index');
     app.post('/tender/:id/ledger/audit/add', sessionAuth, tenderCheck, 'ledgerAuditController.add');
@@ -115,6 +116,7 @@ module.exports = app => {
     app.post('/tender/:id/revise/add', sessionAuth, tenderCheck, 'reviseController.add');
     app.post('/tender/:id/revise/cancel', sessionAuth, tenderCheck, 'reviseController.cancel');
     app.post('/tender/:id/revise/save', sessionAuth, tenderCheck, 'reviseController.save');
+    //app.post('/tender/:id/revise/deal2sgfh', sessionAuth, tenderCheck, 'reviseController.deal2sgfh');
     // 台账修订页面
     app.get('/tender/:id/revise/info', sessionAuth, tenderCheck, 'reviseController.info');
     app.post('/tender/:id/revise/info/load', sessionAuth, tenderCheck, 'reviseController.loadInfoData');
@@ -195,6 +197,8 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/compare/load', sessionAuth, tenderCheck, stageCheck, 'stageController.compareAuditor');
     // 附加功能
     app.get('/tender/:id/measure/stage/:order/extra/jgcl', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.jgcl');
+    app.post('/tender/:id/measure/stage/:order/extra/jgcl/load', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.loadJgcl');
+    app.post('/tender/:id/measure/stage/:order/extra/jgcl/update', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.updateJgcl');
     app.get('/tender/:id/measure/stage/:order/extra/bonus', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.bonus');
     app.get('/tender/:id/measure/stage/:order/extra/other', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.other');
 
@@ -209,6 +213,7 @@ module.exports = app => {
     app.get('/getFileByUUID/:uuid/:rptName/:suffix', sessionAuth, 'reportController.getFileByUUID');
     // rptRouter.get('/getFileByUUID/:uuid/:rptName/:suffix', reportController.getFileByUUID);
     app.post('/tender/report_api/createSignatureRole', sessionAuth, 'signatureController.createSignatureRole');
+    app.post('/tender/report_api/updateSignatureUsed', sessionAuth, datetimeFill, 'signatureController.updateSignatureUsed');
     app.post('/tender/report_api/updateRoleRelationship', sessionAuth, 'signatureController.updateRoleRel');
     app.post('/tender/report_api/createRoleRelationship', sessionAuth, 'signatureController.createRoleRel');
     // 变更管理
@@ -277,4 +282,7 @@ module.exports = app => {
     // 标段对比
     app.get('/compare/tz', sessionAuth, 'spssController.compareTz');
     app.post('/compare/tz/load', sessionAuth, 'spssController.loadCompareTz');
+    app.get('/compare/stage', sessionAuth, 'spssController.compareStage');
+    app.get('/gather/tz', sessionAuth, 'spssController.gatherTz');
+    app.get('/gather/stage', sessionAuth, 'spssController.gatherStage');
 };

+ 1 - 1
app/service/ledger_audit.js

@@ -203,7 +203,7 @@ module.exports = app => {
             if (!audit) {
                 throw '审核人信息错误';
             }
-            const sum = await this.ctx.service.ledger.addUp({tender_id: tenderId, is_leaf: true});
+            const sum = await this.ctx.service.ledger.addUp({tender_id: tenderId/*, is_leaf: true*/});
 
             const transaction = await this.db.beginTransaction();
             try {

+ 23 - 15
app/service/pay.js

@@ -30,23 +30,31 @@ module.exports = app => {
          */
         async addDefaultPayData(tid, transaction) {
             const existPays = this.getAllDataByCondition({tid: tid});
-            const pays = JSON.parse(JSON.stringify(payConst.payTemplate));
-            if (existPays.length >= pays.length) { return false; }
+            if (existPays.length >= 0) { return false; }
 
-            for (const p of pays) {
-                p.tid = tid;
-                p.csid = 0;
-                p.cstimes = 0;
-                p.csorder = 0;
-                p.csaorder = 0;
-            }
-            let result;
-            if (transaction) {
-                result = await transaction.insert(this.tableName, pays);
-            } else {
-                result = await this.db.insert(this.tableName, pays);
+            try {
+                const projectData = await this.ctx.service.project.getDataById(this.ctx.session.sessionProject.id);
+                const pays = projectData.dealpay_json 
+                    ? JSON.parse(projectData.dealpay_json)
+                    : JSON.parse(JSON.stringify(payConst.payTemplate));
+    
+                for (const p of pays) {
+                    p.tid = tid;
+                    p.csid = 0;
+                    p.cstimes = 0;
+                    p.csorder = 0;
+                    p.csaorder = 0;
+                }
+                let result;
+                if (transaction) {
+                    result = await transaction.insert(this.tableName, pays);
+                } else {
+                    result = await this.db.insert(this.tableName, pays);
+                }
+                return result.affectedRows === pays.length;
+            } catch(error) {
+                throw '项目的默认合同支付数据有误';
             }
-            return result.affectedRows === pays.length;
         }
 
         async _getMaxOrder(tenderId) {

+ 1 - 1
app/service/revise_audit.js

@@ -291,7 +291,7 @@ module.exports = app => {
                             {id: lastStage.id, cache_time_l: cacheTime, cache_time_r: cacheTime});
                         // 拷贝修订数据至台账
                         await this._replaceLedgerByRevise(transaction, revise);
-                        const sum = await this.ctx.service.reviseBills.addUp({tender_id: revise.tid, is_leaf: true});
+                        const sum = await this.ctx.service.reviseBills.addUp({tender_id: revise.tid/*, is_leaf: true*/});
                         await transaction.update(this.ctx.service.tender.tableName, {
                             id: revise.tid, total_price: sum.total_price, deal_tp: sum.deal_tp
                         });

+ 69 - 0
app/service/signature_used.js

@@ -0,0 +1,69 @@
+'use strict';
+
+/**
+ * Created by EllisRan on 2020/3/3.
+ */
+
+const BaseService = require('../base/base_service');
+
+module.exports = app => {
+
+    class SignatureUsed extends BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'signature_used';
+            this.dataId = 'id';
+        }
+
+        async getSignatureUsedByTenderId(tenderId) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '=',
+            });
+            this.sqlBuilder.orderBy = [['used_time', 'desc']];
+            // this.sqlBuilder.columns = ['id', 'uid', 'prj_id', 'tender_id', 'used_time'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const list = await this.db.query(sql, sqlParam);
+            return list;
+        }
+
+        async updateUsed(data, used_time) {
+            let rst = null;
+            this.transaction = await this.db.beginTransaction();
+            try {
+                const used = await this.getDataByCondition({ uid: data.uid, prj_id: data.prj_id, tender_id: data.tender_id });
+                if (!used) {
+                    const insertData = {
+                        uid: data.uid,
+                        prj_id: data.prj_id,
+                        tender_id: data.tender_id,
+                        used_time,
+                    };
+                    rst = await this.transaction.insert(this.tableName, insertData);
+                } else {
+                    const updateData = {
+                        id: used.id,
+                        used_time,
+                    };
+                    rst = await this.transaction.update(this.tableName, updateData);
+                }
+                await this.transaction.commit();
+            } catch (ex) {
+                console.log(ex);
+                // 回滚
+                await this.transaction.rollback();
+            }
+            return rst;
+        }
+
+    }
+    return SignatureUsed;
+};

+ 7 - 2
app/service/stage.js

@@ -155,7 +155,7 @@ module.exports = app => {
             // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
             if (stage.status !== auditConst.status.checked && stage.check_calc) {
                 const curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
-                const isActive = curAuditor ? curAuditor.id === this.ctx.session.sessionUser.accountId : stage.user_id === this.ctx.session.sessionUser.accountId;
+                const isActive = curAuditor ? curAuditor.aid === this.ctx.session.sessionUser.accountId : stage.user_id === this.ctx.session.sessionUser.accountId;
                 stage.curTimes = stage.status === auditConst.status.checkNo ? stage.times - 1 : stage.times;
                 stage.curOrder = curAuditor ? curAuditor.order : 0;
                 if (isActive) {
@@ -192,7 +192,7 @@ module.exports = app => {
             if (stages.length > 0 && stages[0].status !== auditConst.status.checked) {
                 const stage = stages[0];
                 const curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
-                const isActive = curAuditor ? curAuditor.id === this.ctx.session.sessionUser.accountId : stage.user_id === this.ctx.session.sessionUser.accountId;
+                const isActive = curAuditor ? curAuditor.aid === this.ctx.session.sessionUser.accountId : stage.user_id === this.ctx.session.sessionUser.accountId;
                 if (isActive) {
                     stage.curTimes = stage.times;
                     stage.curOrder = curAuditor ? curAuditor.order : 0;
@@ -268,6 +268,11 @@ module.exports = app => {
                 if (!dealResult) {
                     throw '新增期合同支付数据失败';
                 }
+                // 新增期其他台账数据
+                if (preStage) {
+                    const jgclResult = await this.ctx.service.stageJgcl.addInitialStageData(newStage, preStage, transaction);
+                    if (!jgclResult) throw '初始化甲供材料数据失败';
+                }
 
                 await transaction.commit();
                 return newStage;

+ 5 - 0
app/service/stage_audit.js

@@ -212,6 +212,7 @@ module.exports = app => {
                 const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份下一审核人数据
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, 1, transaction);
+                await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
                 // 更新期数据
                 const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -265,6 +266,7 @@ module.exports = app => {
                 if (nextAudit) {
                     // 复制一份下一审核人数据
                     await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, nextAudit.order, transaction);
+                    await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
                     // 流程至下一审批人
                     await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
                     // 同步 期信息
@@ -376,6 +378,7 @@ module.exports = app => {
                 await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份最新数据给原报
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
+                await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
 
                 // 添加短信通知-审批退回提醒功能
                 const mobile_array = [];
@@ -453,6 +456,7 @@ module.exports = app => {
                 await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份最新数据给下一人
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
+                await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
 
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -660,6 +664,7 @@ module.exports = app => {
                 // 复制一份最新数据给下一人
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 2, transaction);
+                await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
 
                 // 本期结束
                 // 生成截止本期数据 final数据

+ 3 - 4
app/service/stage_bills.js

@@ -359,12 +359,11 @@ module.exports = app => {
         async getSumTotalPrice(stage) {
             const sql = 'SELECT Sum(`contract_tp`) As `contract_tp`, Sum(`qc_tp`) As `qc_tp` FROM ' + this.tableName + ' As Bills ' +
                 '  INNER JOIN ( ' +
-                '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid` From ' + this.tableName +
-                '      WHERE `times` <= ? AND `order` <= ?' +
+                '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `sid` From ' + this.tableName +
+                '      WHERE `times` <= ? AND `order` <= ? AND `sid` = ?' +
                 '      GROUP BY `lid`' +
                 '  ) As MaxFilter ' +
-                '  ON (Bills.times * ' + timesLen + ' + `order`) = MaxFilter.flow And Bills.lid = MaxFilter.lid' +
-                '  WHERE Bills.sid = ?';
+                '  ON (Bills.times * ' + timesLen + ' + `order`) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.sid = MaxFilter.sid';
             const sqlParam = [stage.curTimes, stage.curOrder, stage.id];
             const result = await this.db.queryOne(sql, sqlParam);
             return result;

+ 3 - 3
app/service/stage_change.js

@@ -37,7 +37,7 @@ module.exports = app => {
          */
         async getLastestStageData(tid, sid, lid, pid) {
             const sql = 'SELECT c.*,' +
-                '  oc.code As c_code, oc.new_code As c_new_code' +
+                '  oc.p_code As c_code, oc.new_code As c_new_code' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes`) As `stimes`, MAX(`sorder`) As `sorder`, `lid`, `pid`, `sid` From ' + this.tableName +
@@ -63,7 +63,7 @@ module.exports = app => {
          */
         async getAuditorStageData(tid, sid, times, order, lid, pid) {
             const sql = 'SELECT c.*,' +
-                '  oc.code As c_code, oc.new_code As c_new_code' +
+                '  oc.p_code As c_code, oc.new_code As c_new_code' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes`) As `stimes`, MAX(`sorder`) As `sorder`, `lid`, `pid`, `sid` From ' + this.tableName +
@@ -79,7 +79,7 @@ module.exports = app => {
 
         async getLastestAllStageData(tid, sid) {
             const sql = 'SELECT c.*,' +
-                '  oc.code As c_code, oc.new_code As c_new_code' +
+                '  oc.p_code As c_code, oc.new_code As c_new_code' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes`) As `stimes`, MAX(`sorder`) As `sorder`, `lid`, `pid`, `sid` From ' + this.tableName +

+ 213 - 0
app/service/stage_jgcl.js

@@ -0,0 +1,213 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+
+const timesLen = require('../const/audit').stage.timesLen;
+const payConst = require('../const/deal_pay');
+
+module.exports = app => {
+    class StageJgcl extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_jgcl';
+        }
+
+        async getStageData(sid) {
+            const data = await this.getAllDataByCondition({where: { sid: sid }});
+            return data;
+        }
+
+        async getPreStageData(sorder) {
+            const sql = 'SELECT c.uuid, Sum(c.arrive_qty) as arrive_qty, Sum(c.arrive_tp) as arrive_tp, Sum(c.deduct_qty) as deduct_qty, Sum(c.deduct_tp) as deduct_tp From ' + this.tableName + ' c' +
+                '  LEFT JOIN ' + this.ctx.service.stage.tableName + ' s ON s.id = c.sid' +
+                '  WHERE s.`order` < ? And s.`tid` = ?' +
+                '  GROUP By uuid';
+            const sqlParam = [sorder, this.ctx.tender.id];
+            const data = await this.db.query(sql, sqlParam);
+            return data;
+        }
+
+        async getEndStageData(sorder) {
+            const sql = 'SELECT c.uuid, Sum(c.arrive_qty) as arrive_qty, Sum(c.arrive_tp) as arrive_tp, Sum(c.deduct_qty) as deduct_qty, Sum(c.deduct_tp) as deduct_tp From ' + this.tableName + ' c' +
+                '  LEFT JOIN ' + this.ctx.service.stage.tableName + ' s ON s.id = c.sid' +
+                '  WHERE s.`order` <= ? And s.`tid` = ?' +
+                '  GROUP By uuid';
+            const sqlParam = [sorder, this.ctx.tender.id];
+            const data = await this.db.query(sql, sqlParam);
+            return data;
+        }
+
+        async _addDatas(data) {
+            const datas = data instanceof Array ? data : [data];
+            const insertData = [];
+            for (const d of datas) {
+                if (!d.name || !d.order) throw '新增甲供材料,提交的数据错误';
+                const nd = {
+                    uuid: this.uuid.v4(),
+                    add_sid: this.ctx.stage.id,
+                    add_uid: this.ctx.session.sessionUser.accountId,
+                    sid: this.ctx.stage.id,
+                };
+                nd.name = d.name;
+                nd.order = d.order;
+                if (d.unit) nd.unit = d.unit;
+                if (d.unit_price) nd.unit_price = d.unit_price;
+                const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, d.unit_price);
+                if (d.arrive_qty) {
+                    nd.arrive_qty = this.ctx.helper.round(d.arrive_qty, precision.value);
+                    nd.arrive_tp = this.ctx.helper.mul(nd.unit_price, nd.arrive_qty, this.ctx.tender.info.decimal.tp);
+                }
+                if (d.deduct_qty) {
+                    nd.deduct_qty = this.ctx.helper.round(d.deduct_qty, precision.value);
+                    nd.deduct_tp = this.ctx.helper.mul(nd.unit_price, nd.deduct_qty, this.ctx.tender.info.decimal.tp);
+                }
+                if (d.source) nd.source = d.source;
+                if (d.bills_code) nd.bills_code = d.bills_code;
+                if (d.check_code) nd.check_code = d.check_code;
+                if (d.memo) nd.memo = d.memo;
+                insertData.push(nd);
+            }
+            await this.db.insert(this.tableName, insertData);
+            return await this.getAllDataByCondition({
+                where: { sid: this.ctx.stage.id, uuid: this.ctx.helper._.map(insertData, 'uuid') }
+            });
+        }
+
+        async _delDatas (data) {
+            const datas = data instanceof Array ? data : [data];
+            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            for (const od of orgDatas) {
+                if (od.pre_used) throw '甲供材料往期已经计量,不可删除';
+            }
+            await this.db.delete(this.tableName, {id: datas});
+            return datas;
+        }
+
+        async _updateDatas (data) {
+            const datas = data instanceof Array ? data : [data];
+            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            const info = this.ctx.tender.info;
+
+            const uDatas = [];
+            for (const d of datas) {
+                const od = this.ctx.helper._.find(orgDatas, {id: d.id});
+                if (!od) continue;
+
+                const nd = {id: od.id};
+                if (d.name) nd.name = d.name;
+                if (od.sid === od.add_sid) {
+                    if (d.unit) nd.unit = d.unit;
+                    nd.unit_price = d.unit_price ? this.ctx.helper.round(d.unit_price, info.decimal.up) : od.unit_price;
+                }
+                const precision = this.ctx.helper.findPrecision(info.precision, d.unit_price);
+                if (d.arrive_qty) {
+                    nd.arrive_qty = this.ctx.helper.round(d.arrive_qty, precision.value);
+                    nd.arrive_tp = this.ctx.helper.mul(nd.unit_price, nd.arrive_qty, info.decimal.tp);
+                } else if (d.unit_price) {
+                    nd.arrive_tp = this.ctx.helper.mul(nd.unit_price, od.arrive_qty, info.decimal.tp);
+                }
+                if (d.deduct_qty) {
+                    nd.deduct_qty = this.ctx.helper.round(d.deduct_qty, precision.value);
+                    nd.deduct_tp = this.ctx.helper.mul(nd.unit_price, nd.deduct_qty, info.decimal.tp);
+                } else if (d.unit_price) {
+                    nd.deduct_tp = this.ctx.helper.mul(nd.unit_price, od.deduct_qty, info.decimal.tp);
+                }
+                if (d.source) nd.source = d.source;
+                if (d.bills_code) nd.bills_code = d.bills_code;
+                if (d.check_code) nd.check_code = d.check_code;
+                if (d.memo) nd.memo = d.memo;
+                if (d.order) nd.order = d.order;
+                uDatas.push(nd);
+            }
+            if (uDatas.length > 0) {
+                await this.db.updateRows(this.tableName, uDatas);
+                return uDatas;
+            } else {
+                return [];
+            }
+        }
+
+        async updateDatas(data) {
+            const result = {add: [], del: [], update: []};
+            try {
+                if (data.add) {
+                    result.add = await this._addDatas(data.add);
+                }
+                if (data.update) {
+                    result.update = await this._updateDatas(data.update);
+                }
+                if (data.del) {
+                    result.del = await this._delDatas(data.del);
+                }
+                return result;
+            } catch (err) {
+                if (err) result.err = err;
+                return result;
+            }
+        }
+
+        async updateHistory(stage, transaction) {
+            const datas = await this.getStageData(stage.id);
+            if (datas.length === 0) return;
+
+            const filter = {stimes: this.ctx.stage.curTimes, sorder: this.ctx.stage.curOrder};
+            const updateDatas = [];
+            for (const d of datas) {
+                const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
+                const his = this.ctx.helper._.find(datas, filter);
+                if (his) {
+                    his.arrive_qty = d.arrive_qty;
+                    his.arrive_tp = d.arrive_tp;
+                    his.deduct_qty = d.deduct_qty;
+                    his.deduct_tp = d.deduct_tp;
+                } else {
+                    history.push({
+                        stimes: this.ctx.stage.curTimes, sorder: this.ctx.stage.curOrder,
+                        arraive_qty: d.arrive_qty, arrive_tp: d.arrive_tp,
+                        deduct_qty: d.deduct_qty, deduct_tp: d.deduct_tp
+                    });
+                }
+                updateDatas.push({ id: d.id, shistory: JSON.stringify(history) });
+            }
+            await transaction.updateRows(this.tableName, updateDatas);
+        }
+
+        async addInitialStageData(stage, preStage, transaction) {
+            if (!stage || !preStage) {
+                throw '标段数据有误';
+            }
+            const preDatas = await this.getStageData(preStage.id);
+            if (preDatas.length > 0) {
+                for (const pd of preDatas) {
+                    delete pd.id;
+                    pd.pre_used = pd.pre_used || !this.ctx.helper.checkZero(pd.arrive_qty) || !this.ctx.helper.checkZero(pd.deduct_qty);
+                    delete pd.arrive_qty;
+                    delete pd.arrive_tp;
+                    delete pd.deduct_qty;
+                    delete pd.deduct_tp;
+                    pd.sid = stage.id;
+                }
+                const result = await transaction.insert(this.tableName, preDatas);
+                return result.affectedRows === preDatas.length;
+            } else {
+                return true;
+            }
+
+        }
+    }
+
+    return StageJgcl;
+};

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

@@ -68,6 +68,7 @@
     if (toastInfo !== '') {
         toastr[toastInfo.type](toastInfo.message);
     }
+    const userID = <%- ctx.session.sessionUser.accountId %>;
     let user = '<%= ctx.session.sessionUser.name %>';
     <% if (ctx.app.config.is_debug) { %>
     const is_debug = true;

+ 2 - 2
app/view/login/login.ejs

@@ -14,8 +14,8 @@
 <div class="container">
     <!--演示版-->
     <form class="form-signin" method="post" action="/login">
-        <h4 class="d-flex justify-content-center mb-4"><span id="project_name"></span>纵横云计量</h4>
-        <p class="text-center mb-4 text-muted"></p>
+        <h4 class="text-center mb-0">纵横云计量</h4>
+        <p class="text-center mb-4 text-muted" id="project_name"></p>
         <!--<nav class="nav nav-tabs nav-justified mb-3" role="tablist" id="login-tab">-->
             <!--<a class="nav-item nav-link" data-toggle="tab" data-type="1" href="#preview" role="tab">演示版登录</a>-->
             <!--<a class="nav-item nav-link active" data-toggle="tab" data-type="2" href="#paid" role="tab">项目版登录</a>-->

+ 1 - 0
app/view/report/index.ejs

@@ -205,6 +205,7 @@
     const STAGE_LIST = <%- stage_list %>;
     const PRJ_ACCOUNT_LIST = <%- prj_account_list %>;
     const ROLE_LIST = <%- role_list %>;
+    let USED_LIST = <%- used_list %>;
     const STAGE_STATUS = <%- stg_status %>;
     let STAGE_AUDIT = [];
     let ROLE_REL_LIST = [];

+ 11 - 6
app/view/report/rpt_all_popup.ejs

@@ -169,7 +169,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal" onclick="rptSignatureHelper.removeSelectSignature()">取消</button>
-                <a onclick="rptSignatureHelper.setupAfterSelectSignature()" class="btn btn-primary btn-sm" data-dismiss="modal">确定</a>
+                <a href="javascript:void(0);" onclick="rptSignatureHelper.setupAfterSelectSignature()" class="btn btn-primary btn-sm" data-dismiss="modal">确定</a>
             </div>
         </div>
     </div>
@@ -200,9 +200,9 @@
                     <div class="tab-pane fade show active" id="adst-1" role="tabpanel" aria-labelledby="home-tab">
                         <div class="input-group input-group-sm mt-1 mb-2">
                             <div class="input-group-prepend">
-                                <span class="input-group-text" id="inputGroup-sizing-sm"><i class="fa fa-search"></i></span>
+                                <span class="input-group-text" id="inputGroup-sizing-sm"><i class="fa fa-search" onclick="rptSignatureHelper.buildSelectableAccount(this);"></i></span>
                             </div>
-                            <input type="text" class="form-control form-control-sm" placeholder="搜索...">
+                            <input type="text" id="search_account" class="form-control form-control-sm" placeholder="搜索..."  onkeypress="searchAccount()">
                         </div>
                         <div class="modal-height-300" id="project_account_select_div">
                         </div>
@@ -235,8 +235,7 @@
                     </div>
                     <div class="tab-pane fade" id="adst-3" role="tabpanel" aria-labelledby="contact-tab">
                         <div class="modal-height-300">
-                            <ul class="list-group">
-                            </ul>
+                            <ul class="list-group" id="account_used_select_div"></ul>
                         </div>
                     </div>
                 </div>
@@ -248,4 +247,10 @@
 <script>
     zTreeOprObj.getCustomerCfg();
     zTreeOprObj.iniFontCfgDom(CUST_CFG);
-</script>
+
+    function searchAccount() {
+        if (event.keyCode == 13) {
+            rptSignatureHelper.buildSelectableAccount(this);
+        }
+    }
+</script>

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

@@ -59,9 +59,13 @@
         </div>
     </div>
 </div>
+<script>
+    $(function () {
+        autoFlashHeight();
+    })
+</script>
 <% if (projectData.user_account === ctx.session.sessionUser.account) { %>
 <script type="text/javascript">
-    autoFlashHeight();
     function updateinfo()
     {
         $("#info-form").submit();

+ 16 - 0
app/view/spss/compare_stage.ejs

@@ -0,0 +1,16 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main d-flex">
+            <% include ./sub_mini_menu.ejs %>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header p-0"></div>
+        <div class="c-body">
+            暂无该功能...<br>
+            会不会做,什么时候做...<br>
+            小编太忙了,如急需,请联系...<br>
+        </div>
+    </div>
+</div>

+ 1 - 22
app/view/spss/sub_menu.ejs

@@ -5,28 +5,7 @@
         </div>
     </div>
     <div class="scrollbar-auto">
-        <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 审核比较</h3>
-            <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/compare/tz"><span class="ml-3">台账对比</span></a>
-                </li>
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/compare/stage"><span class="ml-3">期计量对比</span></a>
-                </li>
-            </ul>
-        </div>
-        <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 标段汇总</h3>
-            <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/gather/tz"><span class="ml-3">台账汇总</span></a>
-                </li>
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/gather/stage"><span class="ml-3">期计量汇总</span></a>
-                </li>
-            </ul>
-        </div>
+        <% include ./sub_menu_list.ejs %>
         <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
     </div>
 </div>

+ 22 - 0
app/view/spss/sub_menu_list.ejs

@@ -0,0 +1,22 @@
+<div class="nav-box">
+    <h3><i class="fa fa-list-alt"></i> 审核比较</h3>
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === '/compare/tz') { %>active<% } %>">
+            <a href="/compare/tz"><span class="ml-3">台账对比</span></a>
+        </li>
+        <li class="<% if (ctx.url === '/compare/stage') { %>active<% } %>">
+            <a href="/compare/stage"><span class="ml-3">期计量对比</span></a>
+        </li>
+    </ul>
+</div>
+<div class="nav-box">
+    <h3><i class="fa fa-list-alt"></i> 标段汇总</h3>
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
+            <a href="/gather/tz"><span class="ml-3">台账汇总</span></a>
+        </li>
+        <li class="<% if (ctx.url === '/gather/stage') { %>active<% } %>">
+            <a href="/gather/stage"><span class="ml-3">期计量汇总</span></a>
+        </li>
+    </ul>
+</div>

+ 1 - 22
app/view/spss/sub_mini_menu.ejs

@@ -5,28 +5,7 @@
         <i class="fa fa-bars"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
-        <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 审核比较</h3>
-            <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/compare/tz') { %>active<% } %>">
-                    <a href="/compare/tz"><span class="ml-3">台账对比</span></a>
-                </li>
-                <li class="<% if (ctx.url === '/compare/stage') { %>active<% } %>">
-                    <a href="/compare/stage"><span class="ml-3">期计量对比</span></a>
-                </li>
-            </ul>
-        </div>
-        <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 标段汇总</h3>
-            <ul class="nav-list list-unstyled">
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/gather/tz"><span class="ml-3">台账汇总</span></a>
-                </li>
-                <li class="<% if (ctx.url === '/gather/tz') { %>active<% } %>">
-                    <a href="/gather/stage"><span class="ml-3">期计量汇总</span></a>
-                </li>
-            </ul>
-        </div>
+        <% include ./sub_menu_list.ejs %>
         <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
     </div>
 </div>

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

@@ -491,6 +491,15 @@
                             </div>
                         </div>
                     </div>
+                    <div id="checked-change" class="tab-pane tab-select-show">
+                        <div class="sjs-bar">
+                            <button class="btn btn-sm btn-outline-primary pull-right" href="javascript: void(0);" id="refresh-cc" hint="如果有新审批通过的变更令,请点击刷新">重新获取变更令</button>
+                        </div>
+                        <div class="sjs-height-5" id="cc-spread" style="overflow:hidden">
+                        </div>
+                        <div class="sjs-bottom" id="ccb-spread">
+                        </div>
+                    </div>
                 </div>
             </div>
         </div>
@@ -509,6 +518,9 @@
                 <li class="nav-item">
                     <a class="nav-link" content="#shuqian" href="javascript: void(0);" style="display: none;">书签</a>
                 </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#checked-change" href="javascript: void(0);">变更令</a>
+                </li>
             </ul>
         </div>
     </div>
@@ -532,7 +544,6 @@
     const imType = JSON.parse('<%- JSON.stringify(imType) %>');
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
     let attData = JSON.parse('<%- JSON.stringify(attData) %>');
-    const userID = '<%- ctx.session.sessionUser.accountId %>';
     const ckColSetting = 'stage-col-visible-1.0.3-<%- tender.id %>';
 </script>
 <% if (ctx.stage.status === auditConst.status.uncheck && ctx.session.sessionUser.accountId === ctx.stage.user_id) {%>

+ 0 - 1
app/view/stage/pay.ejs

@@ -60,7 +60,6 @@
     const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
     const uploadPermission = <%- uploadPermission %>;
-    const userID = <%- ctx.session.sessionUser.accountId %>;
     const preContractTp = <%- (pre.contract_tp || 0) %>;
     const preQcTp = <%- (pre.qc_tp || 0) %>;
     const preGatherTp = <%- (pre.gather_tp || 0) %>;

+ 6 - 1
app/view/stage_extra/jgcl.ejs

@@ -16,4 +16,9 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    const stageId = <%- ctx.stage.id %>;
+    const stageUserId = <%- ctx.stage.user_id %>;
+    const readOnly = <%- ctx.stage.readOnly %>;
+</script>

+ 5 - 2
app/view/tender/index.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
     <% include ./sub_menu.ejs %>
     <div class="content-wrap">
-        <div class="sjs-height-0">
+        <div class="sjs-height-0" style="background-color: #fff">
             <div class="c-body" onselectstart="return false" style="{-moz-user-select:none}">
             </div>
         </div>
@@ -13,4 +13,7 @@
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
-</script>
+    const uid = '<%- uid %>';
+    const pid = '<%- pid %>';
+    const uphlname = 'user_' + uid + '_pro_' + pid + '_category_hide_list';
+</script>

+ 5 - 2
app/view/tender/info.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
     <% include ./sub_menu.ejs %>
     <div class="content-wrap">
-        <div class="sjs-height-0">
+        <div class="sjs-height-0" style="background-color: #fff">
             <div class="c-body" onselectstart="return false" style="{-moz-user-select:none}">
             </div>
         </div>
@@ -13,4 +13,7 @@
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
-</script>
+    const uid = '<%- uid %>';
+    const pid = '<%- pid %>';
+    const uphlname = 'user_' + uid + '_pro_' + pid + '_category_hide_list';
+</script>

+ 4 - 1
app/view/tender/manage.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
     <% include ./sub_menu.ejs %>
     <div class="content-wrap">
-        <div class="sjs-height-0">
+        <div class="sjs-height-0" style="background-color: #fff">
             <div class="c-body" onselectstart="return false" style="{-moz-user-select:none}">
             </div>
         </div>
@@ -12,4 +12,7 @@
     const categoryType = JSON.parse('<%- JSON.stringify(settingConst.cType) %>');
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
+    const uid = '<%- uid %>';
+    const pid = '<%- pid %>';
+    const uphlname = 'user_' + uid + '_pro_' + pid + '_category_hide_manange_list';
 </script>

+ 5 - 2
app/view/tender/progress.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
     <% include ./sub_menu.ejs %>
     <div class="content-wrap">
-        <div class="sjs-height-0">
+        <div class="sjs-height-0" style="background-color: #fff">
             <div class="c-body" onselectstart="return false" style="{-moz-user-select:none}">
             </div>
         </div>
@@ -11,4 +11,7 @@
     const tenders = JSON.parse('<%- JSON.stringify(tenderList) %>');
     const categoryType = JSON.parse('<%- JSON.stringify(settingConst.cType) %>');
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
-</script>
+    const uid = '<%- uid %>';
+    const pid = '<%- pid %>';
+    const uphlname = 'user_' + uid + '_pro_' + pid + '_category_hide_list';
+</script>

+ 5 - 0
config/config.default.js

@@ -54,6 +54,11 @@ module.exports = appInfo => {
         cache: false,
     };
 
+    config.static = {
+        maxAge: 0,
+        buffer: false,
+    }
+
     // 分页相关
     config.pageSize = 15;
 

+ 10 - 6
config/web.js

@@ -62,6 +62,7 @@ const JsFiles = {
                 ],
                 mergeFiles: [
                     "/public/js/zh_calc.js",
+                    "/public/js/tender_showhide.js",
                     "/public/js/tender_list.js"
                 ],
                 mergeFile: 'tender_list',
@@ -74,6 +75,7 @@ const JsFiles = {
                 ],
                 mergeFiles: [
                     "/public/js/zh_calc.js",
+                    "/public/js/tender_showhide.js",
                     "/public/js/tender_list_info.js"
                 ],
                 mergeFile: 'tender_list_info',
@@ -86,6 +88,7 @@ const JsFiles = {
                 ],
                 mergeFiles: [
                     "/public/js/zh_calc.js",
+                    "/public/js/tender_showhide.js",
                     "/public/js/tender_list_progress.js"
                 ],
                 mergeFile: 'tender_list_progress',
@@ -99,6 +102,7 @@ const JsFiles = {
                 ],
                 mergeFiles: [
                     "/public/js/zh_calc.js",
+                    "/public/js/tender_showhide.js",
                     "/public/js/tender_list_manage.js",
                 ],
                 mergeFile: 'tender_list_manage',
@@ -362,7 +366,7 @@ const JsFiles = {
             jgcl: {
                 files: [
                     "/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js",
-                    "/public/js/decimal.min.js",                    
+                    "/public/js/decimal.min.js",
                 ],
                 mergeFiles: [
                     "/public/js/sub_menu.js",
@@ -371,12 +375,12 @@ const JsFiles = {
                     "/public/js/path_tree.js",
                     "/public/js/se_jgcl.js",
                 ],
-                mergeFile: 'se_jgcl',                
+                mergeFile: 'se_jgcl',
             },
             bonus: {
                 files: [
                     "/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js",
-                    "/public/js/decimal.min.js",                    
+                    "/public/js/decimal.min.js",
                 ],
                 mergeFiles: [
                     "/public/js/sub_menu.js",
@@ -385,12 +389,12 @@ const JsFiles = {
                     "/public/js/path_tree.js",
                     "/public/js/se_bonus.js",
                 ],
-                mergeFile: 'se_bonus',                
+                mergeFile: 'se_bonus',
             },
             other: {
                 files: [
                     "/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js",
-                    "/public/js/decimal.min.js",                    
+                    "/public/js/decimal.min.js",
                 ],
                 mergeFiles: [
                     "/public/js/sub_menu.js",
@@ -400,7 +404,7 @@ const JsFiles = {
                     "/public/js/path_tree.js",
                     "/public/js/se_other.js",
                 ],
-                mergeFile: 'se_other',                
+                mergeFile: 'se_other',
             },
         },
         measure: {