Parcourir la source

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

TonyKang il y a 4 ans
Parent
commit
633f28d171
39 fichiers modifiés avec 1030 ajouts et 137 suppressions
  1. 9 1
      app/const/audit.js
  2. 1 0
      app/const/tender_info.js
  3. 7 2
      app/controller/advance_controller.js
  4. 81 7
      app/controller/change_controller.js
  5. 3 0
      app/controller/tender_controller.js
  6. 23 0
      app/extend/helper.js
  7. 10 0
      app/lib/ledger.js
  8. 381 0
      app/lib/rptCustomData.js
  9. 1 1
      app/middleware/change_check.js
  10. 5 1
      app/middleware/tender_check.js
  11. 1 1
      app/public/js/advance_audit.js
  12. 40 19
      app/public/js/change_information_set.js
  13. 2 1
      app/public/js/change_information_show.js
  14. 19 1
      app/public/js/shenpi.js
  15. 1 1
      app/public/js/stage_pay.js
  16. 9 5
      app/public/js/tender.js
  17. 2 0
      app/public/report/js/rpt_custom.js
  18. 1 0
      app/router.js
  19. 1 1
      app/service/advance.js
  20. 92 4
      app/service/change.js
  21. 4 0
      app/service/change_audit.js
  22. 26 0
      app/service/change_audit_list.js
  23. 8 0
      app/service/ledger_cooperation.js
  24. 14 0
      app/service/report.js
  25. 1 0
      app/service/rpt_gather_memory.js
  26. 1 1
      app/service/stage.js
  27. 1 1
      app/service/stage_change.js
  28. 8 4
      app/service/stage_change_final.js
  29. 2 1
      app/service/stage_detail.js
  30. 2 13
      app/service/stage_pos_final.js
  31. 7 1
      app/view/advance/audit_btn.ejs
  32. 6 6
      app/view/advance/detail.ejs
  33. 5 1
      app/view/change/index.ejs
  34. 12 8
      app/view/change/information.ejs
  35. 131 47
      app/view/change/information_modal.ejs
  36. 9 5
      app/view/tender/detail_modal.ejs
  37. 2 2
      app/view/tender/shenpi_modal.ejs
  38. 98 1
      builder_report_index_define.js
  39. 4 1
      sql/update.sql

+ 9 - 1
app/const/audit.js

@@ -230,6 +230,7 @@ const status = {
     // checkNo: 4,     // 审批终止
     back: 5, // 重新上报
     backnew: 6, // 退回
+    revise: 9, // 修订变更
 };
 const statusButton = [];
 statusButton[status.uncheck] = '上报';
@@ -238,6 +239,7 @@ statusButton[status.checked] = '';
 // statusButton[status.checkNo] = '';
 statusButton[status.back] = '重新上报';
 statusButton[status.backnew] = '审批';
+statusButton[status.revise] = '修订';
 
 const statusButtonClass = [];
 statusButtonClass[status.uncheck] = 'btn-primary';
@@ -246,6 +248,7 @@ statusButtonClass[status.checked] = '';
 // statusButtonClass[status.checkNo] = '';
 statusButtonClass[status.back] = 'btn-warning';
 statusButtonClass[status.backnew] = 'btn-success';
+statusButtonClass[status.revise] = 'btn-warning';
 
 const statusString = [];
 statusString[status.uncheck] = '未上报';
@@ -254,6 +257,7 @@ statusString[status.checked] = '审批通过';
 // statusString[status.checkNo] = '终止';
 statusString[status.back] = '审批退回';
 statusString[status.backnew] = '审批退回';
+statusString[status.revise] = '修订中';
 
 const statusClass = [];
 statusClass[status.uncheck] = '';
@@ -262,18 +266,20 @@ statusClass[status.checked] = 'text-success';
 // statusClass[status.checkNo] = 'text-danger';
 statusClass[status.back] = 'text-warning';
 statusClass[status.backnew] = 'text-warning';
+statusClass[status.revise] = 'text-warning';
 
 /* ------------------------------------------------------- */
 
 // 变更令审批人状态
 const auditStatus = {
     uncheck: 1, // 待审批
-    checking: 2, // 审批中或者原报人待上报
+    checking: 2, // 审批中或者原报人待上报或者原报上报修订中
     checked: 3, // 审批通过或者原报人上报完成
     // checkNo: 4,     // 审批终止
     back: 5, // 退回到原报人重新上报
     backnew: 6, // 退回到上一个审批人
     checkAgain: 7, // 重新审批
+    revise: 9, // 修订变更
 };
 
 const auditStatusString = [];
@@ -284,6 +290,7 @@ auditStatusString[auditStatus.checked] = '审批通过';
 auditStatusString[auditStatus.back] = '退回';
 auditStatusString[auditStatus.backnew] = '审批退回';
 auditStatusString[auditStatus.checkAgain] = '重新审批';
+auditStatusString[auditStatus.revise] = '待修订';
 
 const auditStatusClass = [];
 auditStatusClass[auditStatus.uncheck] = '';
@@ -293,6 +300,7 @@ auditStatusClass[auditStatus.checked] = 'text-success';
 auditStatusClass[auditStatus.back] = 'text-warning';
 auditStatusClass[auditStatus.backnew] = 'text-warning';
 auditStatusClass[auditStatus.checkAgain] = 'text-warning';
+auditStatusClass[auditStatus.revise] = '';
 
 /* ------------------------------------------------------- */
 

+ 1 - 0
app/const/tender_info.js

@@ -100,6 +100,7 @@ const defaultInfo = {
         zanLiePrice: 0,
         startAdvance: 0,
         materialAdvance: 0,
+        safeAdvance: 0,
     },
     // 显示设置
     display: {

+ 7 - 2
app/controller/advance_controller.js

@@ -119,15 +119,20 @@ module.exports = app => {
          * @private
          */
         async _checkCanEntry(ctx) {
+            ctx.advance.filePermission = false;
             if (ctx.advance.status === auditConst.status.uncheck) {
-                if (ctx.session.sessionUser.accountId !== ctx.advance.uid) {
+                if (ctx.session.sessionUser.accountId !== ctx.advance.uid && !ctx.tender.isTourist) {
                     throw '无权访问';
+                } else if (ctx.session.sessionUser.accountId === ctx.advance.uid) {
+                    ctx.advance.filePermission = true;
                 }
             } else {
                 const auditors = await ctx.service.advanceAudit.getAuditorsWithOwner(ctx.advance.id, ctx.advance.times);
                 const cur_uid = ctx.session.sessionUser.accountId;
-                if (auditors.findIndex(item => item.audit_id === cur_uid) === -1) {
+                if (auditors.findIndex(item => item.audit_id === cur_uid) === -1 && !ctx.tender.isTourist) {
                     throw '无权访问';
+                } else if (auditors.findIndex(item => item.audit_id === cur_uid) !== -1 || ctx.session.sessionUser.accountId === ctx.advance.uid) {
+                    ctx.advance.filePermission = true;
                 }
             }
         }

+ 81 - 7
app/controller/change_controller.js

@@ -72,6 +72,11 @@ module.exports = app => {
                             const checkingAudit = await ctx.service.changeAudit.getLastUser(c.cid, c.times, status);
                             auditStatus = checkingAudit.uid === ctx.session.sessionUser.accountId ? 1 : 0;
                             break;
+                        case 9:
+                            auditStatus = 9;
+                            const changeUsedData = await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, c.cid);
+                            c.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.used_qty); }));
+                            break;
                         default:
                             break;
                     }
@@ -299,7 +304,7 @@ module.exports = app => {
                     shenpiConst,
                 };
                 // 根据auditStatus状态获取的不同的数据
-                if (auditStatus === 1 || auditStatus === 2) {
+                if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) {
                     renderData.changeUnits = changeConst.units;
                     renderData.precision = ctx.tender.info.precision;
                     // renderData.accountGroup = accountGroup;
@@ -314,7 +319,7 @@ module.exports = app => {
                         return { groupName: item, groupList };
                     });
                     // 重新上报获取审批流程
-                    if (auditStatus === 2) {
+                    if (auditStatus === 2 || auditStatus === 9) {
                         const auditList2 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
                         // 展示页右侧审批流程列表
                         const auditList3 = [];
@@ -568,7 +573,7 @@ module.exports = app => {
                     precision: ctx.tender.info.precision,
                 };
                 // 根据auditStatus状态获取的不同的数据
-                if (auditStatus === 1 || auditStatus === 2) {
+                if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) {
                     renderData.changeUnits = changeConst.units;
                     // renderData.accountGroup = accountGroup;
                     // 获取所有项目参与者
@@ -582,7 +587,7 @@ module.exports = app => {
                         return { groupName: item, groupList };
                     });
                     // 重新上报获取审批流程
-                    if (auditStatus === 2) {
+                    if (auditStatus === 2 || auditStatus === 9) {
                         const auditList2 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
                         // 展示页右侧审批流程列表
                         const auditList3 = [];
@@ -604,6 +609,7 @@ module.exports = app => {
                         }
                         renderData.auditList3 = auditList3;
                     }
+
                     // 获取公司列表
                     const companyList = await ctx.service.changeCompany.getAllDataByCondition({ where: { tid: ctx.tender.id } });
                     renderData.companyList = companyList;
@@ -705,6 +711,7 @@ module.exports = app => {
 
                 // 获取是否已存在调用变更令
                 const changeUsedData = await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, change.cid);
+                renderData.changeUsedData = changeUsedData;
                 renderData.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.used_qty); }));
                 await this.layout('change/information.ejs', renderData, 'change/information_modal.ejs');
             } catch (err) {
@@ -747,7 +754,8 @@ module.exports = app => {
                     case 'ledger_list':
                         await ctx.service.changeAuditList.saveLedgerListDatas(data.updateData);
                         // 取所有工料表
-                        responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
+                        responseData.data = { changeList: await ctx.service.changeAuditList.getList(ctx.change.cid),
+                            usedList: await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, ctx.change.cid) };
                         break;
                     case 'remove_list':
                         await ctx.service.changeAuditList.removeLedgerListDatas(data.updateData);
@@ -800,10 +808,20 @@ module.exports = app => {
                 if (ctx.change.uid !== ctx.session.sessionUser.accountId) {
                     throw '您无权上报该变更令数据';
                 }
-                if (!(ctx.change.status === audit.flow.status.uncheck || ctx.change.status === audit.flow.status.back)) {
+                if (!(ctx.change.status === audit.flow.status.uncheck || ctx.change.status === audit.flow.status.back || ctx.change.status === audit.flow.status.revise)) {
                     throw '该变更令当前无法上报';
                 }
-
+                // 判断是否是修订,判断有无审批人员作弊
+                if (ctx.change.status === audit.flow.status.revise && ctx.tender.info.shenpi.change === shenpiConst.sp_status.sqspr) {
+                    // 获取上一次的审批人流程
+                    const lastUserList = await ctx.service.changeAudit.getListGroupByTimes(ctx.change.cid, ctx.change.times - 1);
+                    const lastUidList = ctx.helper._.map(lastUserList, 'uid');
+                    // 判断上一次审批是否为非原报为审批人
+                    const nowUidList = ctx.helper._.map(ctx.change.auditors, 'uid');
+                    if (!ctx.helper._.isEqual(lastUidList, nowUidList) && nowUidList.length === 2 && nowUidList[0] === nowUidList[1]) {
+                        throw '该变更令不能指定原报人为单独审批人';
+                    }
+                }
                 await ctx.service.changeAudit.start(ctx.change.cid, ctx.change.times);
 
                 ctx.redirect(ctx.request.header.referer);
@@ -1291,6 +1309,62 @@ module.exports = app => {
         }
 
         /**
+         * 变更令修订重新上报
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async checkRevise(ctx) {
+            try {
+                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.cid });
+                if (!changeData) {
+                    throw '变更令数据错误';
+                }
+                if (changeData.status !== audit.flow.status.checked || ctx.session.sessionUser.accountId !== changeData.uid) {
+                    throw '您无权进行该操作';
+                }
+                if (ctx.session.sessionUser.loginStatus === 0) {
+                    const code = ctx.request.body.code;
+                    const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+                    if (!pa.auth_mobile) {
+                        throw '未绑定手机号';
+                    }
+                    const cacheKey = 'smsCode:' + ctx.session.sessionUser.accountId;
+                    const cacheCode = await app.redis.get(cacheKey);
+                    // console.log(cacheCode);
+                    if (cacheCode === null || code === undefined || cacheCode !== (code + pa.auth_mobile)) {
+                        throw '验证码不正确!';
+                    }
+                }
+
+                // 获取是否已存在调用变更令
+                // const changeUsedData = await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, changeData.cid);
+                // const stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.used_qty); }));
+                // if (stageChangeNum !== 0) {
+                //     throw '该变更令已被调用,无法重新审批';
+                // }
+                // 重新审批
+                const result = await ctx.service.change.checkRevise(changeData.cid);
+                if (!result) {
+                    throw '修订发起失败';
+                }
+                // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
+                ctx.body = {
+                    err: 0,
+                    url: ctx.request.header.referer,
+                    msg: '',
+                };
+            } catch (err) {
+                console.log(err);
+                // ctx.redirect(ctx.request.header.referer);
+                ctx.body = {
+                    err: 1,
+                    // url: ctx.request.header.referer,
+                    msg: err,
+                };
+            }
+        }
+
+        /**
          * 获取变更清单
          * @param ctx
          * @return {Promise<void>}

+ 3 - 0
app/controller/tender_controller.js

@@ -918,6 +918,9 @@ module.exports = app => {
                     case 'pwd':
                         info = await ctx.service.ledgerCooperation.save(data);
                         break;
+                    case 'company':
+                        info = await ctx.service.ledgerCooperation.saveCompany(data);
+                        break;
                     default:break;
                 }
                 ctx.body = { err: 0, msg: '', data: info };

+ 23 - 0
app/extend/helper.js

@@ -1364,6 +1364,29 @@ module.exports = {
         return counts(array, val);
     },
 
+    filterTimesOrderData(data, keyFields, times, order) {
+        const dataIndex = {};
+        for (const d of data) {
+            if (d.times > times || (d.times = times || d.order > order)) continue;
+            let key = 'd';
+            for (const kf of keyFields) {
+                key = key + '.' + (d[kf] || '');
+            }
+
+            const di = dataIndex[key];
+            if (di) {
+                if ((di.times * timesLen + di.order) < (d.times * timesLen + d.order)) dataIndex[key] = d;
+            } else {
+                dataIndex[key] = d;
+            }
+        }
+        const result = [];
+        for (const prop in dataIndex) {
+            result.push(dataIndex[prop]);
+        }
+        return result;
+    },
+
     filterLastestData(data, keyFields) {
         const dataIndex = {};
         for (const d of data) {

+ 10 - 0
app/lib/ledger.js

@@ -27,6 +27,16 @@ class baseTree {
         // 树设置
         this.setting = setting;
     }
+    clear() {
+        // 无索引
+        this.datas = [];
+        // 以key为索引
+        this.items = {};
+        // 以排序为索引
+        this.nodes = [];
+        // 根节点
+        this.children = [];
+    }
 
     /**
      * 根据id获取树结构节点数据

+ 381 - 0
app/lib/rptCustomData.js

@@ -0,0 +1,381 @@
+'use strict';
+
+/**
+ * 定制报表 注意不做任何混用,也不做任何继承
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+const auditConst = require('../const/audit');
+
+/**
+ * 季华项目 定制报表
+ * 汇总表,流水汇总2个标段(N个),汇总到期,每期汇总3个人的数据(3个),工程量清单流水表,并根据截至本期变更令使用情况筛选
+ *
+ * 借用 通用汇总标段选的界面
+ * 故配置可与汇总标段选择相同
+ *
+ * define: {
+ *     "title": "请选择汇总的标段", "type": "month/final/checked-final/stage",
+ *    "defaultCompare": [1, 2, 3], // 结果按序 t_n_qty, t_n_tp
+ *    "match": { "quality": [2, 3], "qty": "<0" }, // class根据变更类型过滤,qty根据数量过滤
+ *    "selectCompare": [{ "key": "jl", "title": "驻地监理" }, ...] // 结果按key t_key_qty, t_key_tp
+ *    "merge": true,
+ * }
+ * defaultCompare为默认选择的审批人,0为原报,1-N为1-N审
+ * match为保留的类型
+ * 如需要用户选择审批人,则应配置selectCompare(目前不可用,不可配置,如需使用,则需要额外界面),为后期可能的变动预留
+ *
+ */
+class jhHelper {
+
+    constructor (ctx) {
+        this.ctx = ctx;
+        this.result = [];
+    }
+
+    async _getValidStages(tenderId) {
+        const stages = await this.ctx.service.stage.db.select(this.ctx.service.stage.tableName, {
+            where: { tid: tenderId },
+            orders: [['order', 'desc']],
+        });
+        if (stages.length !== 0) {
+            const lastStage = stages[0];
+            if (lastStage.status === auditConst.stage.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
+                stages.splice(0, 1);
+            }
+        }
+        return stages;
+    }
+
+    async _getCheckedStages(tenderId) {
+        const stages = await this.db.select(this.ctx.service.stage.tableName, {
+            where: { tid: tenderId },
+            orders: [['order', 'desc']],
+        });
+        if (stages.length !== 0) {
+            const lastStage = stages[0];
+            if (lastStage.status !== auditConst.stage.status.checked) {
+                stages.splice(0, 1);
+            }
+        }
+        return stages;
+    }
+
+    /**
+     * 查询本期所有变更明细
+     * @param tid
+     * @param sid
+     * @returns {Promise<void>}
+    */
+    async getCurChangeDetailData(tid, sid) {
+        const sql = 'SELECT sc.*, c.type As c_type, c.class As c_class, c.quality As c_quality FROM ' + this.ctx.service.stageChange.tableName + ' sc' +
+                    '  Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
+                    '  WHERE sc.tid = ? and sc.sid = ?';
+        return await this.ctx.service.stageChange.db.query(sql, [tid, sid]);
+    }
+
+    async getPreChangeDetailData(tid, sOrder) {
+        const sql = 'SELECT sc.*, c.type As c_type, c.class As c_class, c.quality As c_quality FROM ' + this.ctx.service.stageChangeFinal.tableName + ' sc' +
+                    '  Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
+                    '  Left Join ' + this.ctx.service.stage.tableName + ' s ON sc.sid = s.id' +
+                    '  WHERE sc.tid = ? and s.order < ?';
+        return await this.ctx.service.stageChangeFinal.db.query(sql, [tid, sOrder]);
+    }
+
+    getLastestAuditors(auditors) {
+        const index = {};
+        for (const auditor of auditors) {
+            if (!index[auditor.aid] || auditor.order > index[auditor.aid].order) index[auditor.aid] = auditor;
+        }
+        const result = [];
+        for (const i in index) {
+            result.push(index[i]);
+        }
+        result.sort((x, y) => { return x.order - y.order; });
+        return result;
+    }
+
+    _loadChangeDetail(billsIndex, changeDetail, gsDefine, prefix) {
+        for (const cd of changeDetail) {
+            if (!cd.qty) continue;
+
+            let match = false;
+            for (const m of gsDefine.match) {
+                if (m.quality === cd.c_quality && ((m.minus && cd.qty < 0) || (!m.minus && cd.qty > 0))) match = true;
+            }
+            if (!match) continue;
+
+            const bills = billsIndex[cd.lid];
+            if (!bills) continue;
+
+            if (!bills[prefix + 'cd']) bills[prefix + 'cd'] = [];
+            bills[prefix + 'cd'].push(cd);
+            if (cd.pid) {
+                const pos = bills.pos.find(x => {return x.id === cd.pid});
+                if (pos) {
+                    if (!pos[prefix + 'cd']) pos[prefix + 'cd'] = [];
+                    pos[prefix + 'cd'].push(cd);
+                }
+            }
+        }
+    }
+
+    _loadMergeResult(bills, prefixes) {
+        const rst = {
+            id: bills.id,
+            tid: bills.tender_id,
+            b_code: bills.b_code,
+            name: bills.name,
+            unit: bills.unit,
+            unit_price: bills.unit_price
+        };
+        if (bills.pos && bills.pos.length > 0) {
+            for (const p of bills.pos) {
+                let gather = false;
+                if (p.pre_cd && p.pre_cd.length > 0) gather = true;
+                for (const prefix of prefixes) {
+                    if (p[prefix + '_cd'] && p[prefix + '_cd'].length > 0) gather = true;
+                }
+                if (gather) {
+                    rst.qc_qty = this.ctx.helper.add(rst.qc_qty, p.qc_qty);
+                    rst.qc_tp = this.ctx.helper.add(rst.qc_qty, p.qc_tp);
+                    rst.pre_qc_qty = this.ctx.helper.add(rst.pre_qc_qty, p.pre_qc_qty);
+                    rst.pre_qc_tp = this.ctx.helper.add(rst.pre_qc_tp, p.pre_qc_tp);
+                    rst.end_qc_qty = this.ctx.helper.add(rst.end_qc_qty, p.end_qc_qty);
+                    rst.end_qc_tp = this.ctx.helper.add(rst.end_qc_tp, p.end_qc_tp);
+                    for (const prefix of prefixes) {
+                        rst[prefix + 'qc_qty'] = this.ctx.helper.add(rst[prefix + 'qc_qty'], p[prefix + 'qc_qty']);
+                    }
+                }
+            }
+            for (const prefix of prefixes) {
+                rst[prefix + 'qc_tp'] = this.ctx.helper.mul(rst.unit_price, rst[prefix + 'qc_qty'], 2);
+            }
+        } else {
+            rst.qc_qty = bills.qc_qty;
+            rst.qc_tp = bills.qc_tp;
+            rst.pre_qc_qty = bills.pre_qc_qty;
+            rst.pre_qc_tp = bills.pre_qc_tp;
+            rst.end_qc_qty = bills.end_qc_qty;
+            rst.end_qc_tp = bills.end_qc_tp;
+            for (const prefix of prefixes) {
+                rst[prefix + 'qc_qty'] = bills[prefix + 'qc_qty'];
+                rst[prefix + 'qc_tp'] = bills[prefix + 'qc_tp'];
+            }
+        }
+        this.result.push(rst);
+    }
+
+    _loadResult(bills, prefixes) {
+        if (bills.pos) {
+            for (const p of bills.pos) {
+                let load = false;
+                if (p.pre_cd && p.pre_cd.length > 0) load = true;
+                for (const prefix of prefixes) {
+                    if (p[prefix + '_cd'] && p[prefix + '_cd'].length > 0) load = true;
+                }
+                if (!load) continue;
+
+                const rst = {
+                    b_code: bills.b_code,
+                    name: bills.name,
+                    unit: bills.unit,
+                    unit_price: bills.unit_price, 
+                };
+                rst.qc_qty = p.qc_qty;
+                rst.qc_tp = p.qc_tp;
+                rst.pre_qc_qty = p.pre_qc_qty;
+                rst.pre_qc_tp = p.pre_qc_tp;
+                rst.end_qc_qty = p.end_qc_qty;
+                rst.end_qc_tp = p.end_qc_tp;
+                for (const prefix of prefixes) {
+                    rst[prefix + 'qc_qty'] = p[prefix + 'qc_qty'];
+                    rst[prefix + 'qc_tp'] = p[prefix + 'qc_tp'];
+                }
+                this.result.push(rst);
+            }
+        } else {
+            const rst = {
+                b_code: bills.b_code,
+                name: bills.name,
+                unit: bills.unit,
+                unit_price: bills.unit_price, 
+            };
+            rst.qc_qty = bills.qc_qty;
+            rst.qc_tp = bills.qc_tp;
+            rst.pre_qc_qty = bills.pre_qc_qty;
+            rst.pre_qc_tp = bills.pre_qc_tp;
+            rst.end_qc_qty = bills.end_qc_qty;
+            rst.end_qc_tp = bills.end_qc_tp;
+            for (const prefix of prefixes) {
+                rst[prefix + 'qc_qty'] = bills[prefix + 'qc_qty'];
+                rst[prefix + 'qc_tp'] = bills[prefix + 'qc_tp'];
+            }
+            this.result.push(rst);
+        }
+    }
+
+    _generateResult(billsData, gsDefine) {
+        for (const bills of billsData) {
+            let load = false;
+            if (bills.pre_cd && bills.pre_cd.length > 0) load = true;
+            for (const dc of gsDefine.defaultCompare) {
+                if (bills['t_' + dc + '_cd'] && bills['t_' + dc + '_cd'].length > 0) load = true;
+            }
+            if (!load) continue;
+            gsDefine.merge ? this._loadMergeResult(bills, this.prefixes) : this._loadResult(bills, this.prefixes);
+        }
+    }
+
+    async _loadStageBillsData(tender, stage, gsDefine, auditors) {
+        const helper = this.ctx.helper;
+        // 加载截止上期/本期
+        let billsData = await this.ctx.service.ledger.getData(tender.id);
+        billsData = billsData.filter(x => { return x.b_code && x.is_leaf });
+        const curStage = await this.ctx.service.stageBills.getLastestStageData(tender.id, stage.id);
+        const preStage = stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
+        const loadData = [
+            { data: curStage, fields: ['qc_qty', 'qc_tp'], prefix: '', relaId: 'lid' },
+            { data: preStage, fields: ['qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' }
+        ];
+        for (const dc of gsDefine.defaultCompare) {
+            const auditor = auditors[dc];
+            const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
+            loadData.push({ data: auditorStage, fields: ['qc_qty', 'qc_tp'], prefix: `t_${dc}_`, relaId: 'pid' });
+        }
+        helper.assignRelaData(billsData, loadData);
+        // 计算截止本期
+        billsData.forEach(x => {
+            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
+            x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
+        });
+        return billsData;
+    }
+
+    async _loadStagePosData(tender, stage, gsDefine, auditors) {
+        const helper = this.ctx.helper;
+        const posData = await this.ctx.service.pos.getPosData({tid: tender.id});
+        const curStage = await this.ctx.service.stagePos.getLastestStageData2(tender.id, stage.id);
+        const preStage = stage.order > 1 ? await this.ctx.service.stagePosFinal.getFinalData(tender, stage.order - 1) : [];
+        const loadData = [
+            { data: curStage, fields: ['qc_qty'], prefix: '', relaId: 'pid' },
+            { data: preStage, fields: ['qc_qty'], prefix: 'pre_', relaId: 'pid' }
+        ];
+        for (const dc of gsDefine.defaultCompare) {
+            const auditor = auditors[dc];
+            const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
+            loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `t_${dc}_`, relaId: 'pid' });
+        }
+        helper.assignRelaData(posData, loadData);
+        posData.forEach(x => {
+            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
+        });
+        return posData;
+    }
+
+    async _gatherStageData(tender, stage, gsDefine) {
+        if (!stage) return;
+        const helper = this.ctx.helper;
+
+        await this.ctx.service.stage.doCheckStage(stage);
+        const auditors = this.getLastestAuditors(stage.auditors);
+        const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors);
+        const posData = await this._loadStagePosData(tender, stage, gsDefine, auditors);
+        // 创建索引
+        const billsIndex = {};
+        for (const b of billsData) {
+            billsIndex[b.id] = b;
+            b.pos = posData.filter(x => { return x.lid === b.id; });
+            b.pos.forEach(x => {
+                x.qc_tp = helper.mul(b.unit_price, x.qc_qty, 2);
+                x.pre_qc_tp = helper.mul(b.unit_price, x.pre_qc_qty, 2);
+                x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
+            })
+        }
+
+        // 查询比较人数据
+        this.prefixes = [];
+        const stageChangeDetail = await this.getCurChangeDetailData(tender.id, stage.id);
+        for (const dc of gsDefine.defaultCompare) {
+            const scd = helper.filterTimesOrderData(stageChangeDetail, ['lid', 'pid', 'cid', 'cbid'], auditors[dc].times, auditors[dc].order);
+            this._loadChangeDetail(billsIndex, scd, gsDefine, `t_${dc}_`);
+            this.prefixes.push(`t_${dc}_`);
+        }
+        const finalChangeData = await this.getPreChangeDetailData(tender.id, stage.order);
+        this._loadChangeDetail(billsIndex, finalChangeData, gsDefine, 'pre_');
+        this._generateResult(billsData, gsDefine);
+    }
+
+    async _gatherMonthData(tender, month, defaultCompare) {
+        const stages = await this._getValidStages(tender.id);
+        const stage = this.ctx.helper._.find(stages, {s_time: month});
+        await this._gatherStageData(tender, stage, defaultCompare);
+    }
+
+    async _gatherFinalData(tender, defaultCompare) {
+        const stages = await this._getValidStages(tender.id);
+        await this._gatherStageData(tender, stages[0], defaultCompare);
+    }
+
+    async _gatherCheckedFinalData(tender, defaultCompare) {
+        const stages = await this._getCheckedStages(tender.id);
+        await this._gatherStageData(tender, stages[0], defaultCompare);
+    }
+
+    async _gatherIndexData(tender, index, defaultCompare) {
+        const stages = await this._getValidStages(tender.id);
+        const stage = this.ctx.helper._.find(stages, {order: index});
+        await this._gatherStageData(tender, stage, defaultCompare);
+    }
+
+    /**
+     *
+     * @param {Array} memFieldKeys 报表添加的指标字段
+     * @param {object} gsDefine
+     * @param {object} gsCustom
+     * @returns {Promise<Array>}
+     */
+    async gather(memFieldKeys, gsDefine, gsCustom) {
+        if (!gsDefine || !gsDefine.enable) return [];
+        if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
+
+        const gsSetting = JSON.parse(gsDefine.setting);
+        if (!gsSetting.defaultCompare || !gsSetting.match) return[];
+        for (const t of gsCustom.tenders) {
+            const tender = await this.ctx.service.tender.getCheckTender(t.tid);
+
+            switch (gsSetting.type) {
+                case 'month':
+                    await this._gatherMonthData(tender, gsCustom.month, gsSetting);
+                    break;
+                case 'final':
+                    await this._gatherFinalData(tender, gsSetting);
+                    break;
+                case 'checked-final':
+                    await this._gatherCheckedFinalData(tender, gsSetting);
+                    break;
+                case 'stage':
+                    await this._gatherIndexData(tender, gsCustom.stage, gsSetting);
+                    break;
+                default: throw '未知汇总类型';
+            }
+        }
+        const helper = this.ctx.helper;
+        // 排序
+        this.result.sort((x, y) => { return helper.compareCode(x.b_code, y.b_code); });
+        return this.result;
+    }
+
+    async convert(tid, sid, memFieldKeys, setting) {
+        if (!setting || !setting.defaultCompare) return [];
+        const tender = await this.ctx.service.tender.getCheckTender(tid);
+        const stage = await this.ctx.service.stage.getDataById(sid);
+        await this._gatherStageData(tender, stage, { defaultCompare: setting.defaultCompare });
+    }
+}
+
+module.exports = {
+    jhHelper,
+};

+ 1 - 1
app/middleware/change_check.js

@@ -44,7 +44,7 @@ module.exports = options => {
                 if (change.curAuditor) {
                     change.readOnly = change.curAuditor.uid !== accountId;
                 } else {
-                    change.readOnly = change.status !== status.uncheck && change.status !== status.back;
+                    change.readOnly = change.status !== status.uncheck && change.status !== status.back && change.status !== status.revise;
                 }
             } else if (this.tender.isTourist) {
                 change.readOnly = true;

+ 5 - 1
app/middleware/tender_check.js

@@ -85,7 +85,11 @@ module.exports = options => {
             } else {
                 const scheduleUser = yield this.service.scheduleAudit.getDataByCondition({ tid: tender.id, audit_id: this.session.sessionUser.accountId });
                 if (scheduleUser) {
-                    schedule_permission = scheduleUser.permission;
+                    if (tender.isTourist && scheduleUser.permission === scPermission.no) {
+                        schedule_permission = scPermission.show;
+                    } else {
+                        schedule_permission = scheduleUser.permission;
+                    }
                 } else if (tender.isTourist) {
                     schedule_permission = scPermission.show;
                 }

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

@@ -353,7 +353,7 @@ $(document).ready(function () {
             }
             return {...file, showDel}
         })
-        let html = `<tr><td colspan="3"><a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a></td></tr>`
+        let html = advance.filePermission ? `<tr><td colspan="3"><a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a></td></tr>` : '';
         newFiles.forEach((file, idx) => {
             if (file.showDel) {
                 html += `<tr><td width="70">${idx + 1}</td><td><a href="/${file.filepath}" target="_blank">${file.filename}</a></td><td width="90"><a href="javascript: void(0);" class="text-danger file-del" data-id="${file.id}">移除</a></td></tr>`

+ 40 - 19
app/public/js/change_information_set.js

@@ -86,12 +86,12 @@ $.event.special.valuechange = {
 $(document).ready(() => {
     const changeSpreadSetting = {
         cols: [
-            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.isEdit'},
-            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.isEdit2'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.isEdit2'},
             {title: '变更部位', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
             {title: '变更详情', colSpan: '1', rowSpan: '2', field: 'detail', hAlign: 0, width: 120, formatter: '@', readOnly: false},
-            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit', cellType: 'unit', comboItems: changeUnits, comboEdit: true},
-            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.unit_price'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit2', cellType: 'unit', comboItems: changeUnits, comboEdit: true},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit2', getValue: 'getValue.unit_price'},
             {title: '原设计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'oamount', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.oamount'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.oa_tp'},
             {title: '申请变更增(+)减(-)|数量', colSpan: '2|1', rowSpan: '1|1', field: 'camount', hAlign: 2, width: 60, type: 'Number', readOnly: false, getValue: 'getValue.camount'},
@@ -143,13 +143,16 @@ $(document).ready(() => {
                 return ZhCalc.round(data.camount, findDecimal(data.unit));
             },
             del_list: function (data) {
-                return '移除';
+                return !_.find(changeUsedData, { id: data.id }) ? '移除' : '';
             }
         },
         readOnly: {
             isEdit: function (data) {
                 return !readOnly && data.lid != 0;
             },
+            isEdit2: function (data) {
+                return !readOnly && (data.lid != 0 || (data.lid == 0 && _.find(changeUsedData, { id: data.id })));
+            },
         },
     };
 
@@ -197,7 +200,7 @@ $(document).ready(() => {
         del: function () {
             const select = SpreadJsObj.getSelectObject(changeSpreadSheet);
             const index = changeList.indexOf(select);
-            if (index > -1) {
+            if (index > -1 && !_.find(changeUsedData, { id: select.id })) {
                 postData(window.location.pathname + '/save', {type: 'del', id: select.id}, function (result) {
                     changeList.splice(index, 1);
                     changeSpreadSheet.deleteRows(index, 1);
@@ -226,7 +229,7 @@ $(document).ready(() => {
             const sel = info.sheet.getSelections()[0];
             const col = info.sheet.zh_setting.cols[sel.col];
             const data = SpreadJsObj.getSelectObject(info.sheet);
-            if (col && col.field === 'del_list') {
+            if (col && col.field === 'del_list' && !_.find(changeUsedData, { id: data.id })) {
                 changeSpreadObj.del();
             }
             changeSpreadObj.resetXmjSpread(data);
@@ -265,10 +268,17 @@ $(document).ready(() => {
                     select.camount = ZhCalc.round(select.camount, findDecimal(validText)) || 0;
                     select.oamount = ZhCalc.round(select.oamount, findDecimal(validText)) || 0;
                 }
-                select[col.field] = validText;
                 if(col.field === 'camount') {
-                    select.spamount = ZhCalc.round(select.camount, findDecimal(select.unit)) || 0;
+                    // 判断是否大于等于限制值,否则无法更改
+                    const usedInfo = _.find(changeUsedData, { id: select.id });
+                    if (usedInfo && validText < usedInfo.used_qty) {
+                        toastr.error('已调用清单更改数值必须大于等于已调用值');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    select.spamount = ZhCalc.round(validText, findDecimal(select.unit)) || 0;
                 }
+                select[col.field] = validText;
                 console.log(select);
                 delete select.waitingLoading;
 
@@ -560,14 +570,14 @@ $(document).ready(() => {
                     name: '删除',
                     icon: 'fa-remove',
                     callback: function (key, opt) {
-                        changeSpreadObj.del(changeSpreadSheet);
+                        // changeSpreadObj.del(changeSpreadSheet);
                     },
                     disabled: function (key, opt) {
                         const select = SpreadJsObj.getSelectObject(changeSpreadSheet);
                         const sel = changeSpreadSheet.getSelections()[0];
                         changeSpreadObj.resetXmjSpread(select);
                         console.log(select, sel);
-                        if (!readOnly && select && sel.row !== changeSpreadSheet.getRowCount() - 1) {
+                        if (!readOnly && select && sel.row !== changeSpreadSheet.getRowCount() - 1 && !_.find(changeUsedData, { id: select.id })) {
                             return false;
                         } else {
                             return true;
@@ -598,13 +608,15 @@ $(document).ready(() => {
             for (const leaf of gcl.leafXmjs) {
                 const quantity = leaf.quantity !== undefined && leaf.quantity !== null ? leaf.quantity : 0;
                 const gcl_id = leaf.gcl_id ? leaf.gcl_id : '';
-                const bwmx = leaf.bwmx !== undefined ? leaf.bwmx : '';
+                const bwmx = leaf.bwmx !== undefined ? leaf.bwmx : (gcl.leafXmjs.length > 1 && gcl.name ? gcl.name : '');
                 const isChecked = data_bwmx.indexOf(
                     leaf.code + '!_!' + (leaf.jldy ? leaf.jldy : '') + '!_!' +
                     (leaf.dwgc ? leaf.dwgc : '') + '!_!' + (leaf.fbgc ? leaf.fbgc : '') + '!_!' + (leaf.fxgc ? leaf.fxgc : '')
                     + '!_!' + (leaf.gcl_id ? leaf.gcl_id : '0') + '!_!' +
                     (bwmx !== '' ? bwmx : leaf.jldy ? leaf.jldy : '') + '*;*' + quantity) !== -1 && isCheck ?
                     'checked' : '';
+                const isUsed = _.find(changeUsedData, { gcl_id: leaf.gcl_id, bwmx: bwmx, oamount: leaf.quantity });
+                const isDisabled = isUsed ? 'disabled ' : '';
                 codeHtml += '<tr quantity="' + quantity + '" gcl_id="' + gcl_id + '"><td>' + leaf.code + '</td>' +
                     '<td>' + (leaf.jldy ? leaf.jldy: '') + '</td>' +
                     '<td>' + (leaf.dwgc ? leaf.dwgc : '') + '</td>' +
@@ -612,7 +624,7 @@ $(document).ready(() => {
                     '<td>' + (leaf.fxgc ? leaf.fxgc : '') + '</td>' +
                     '<td>' + bwmx + '</td>' +
                     '<td class="text-right">' + (ZhCalc.round(quantity, findDecimal(gcl.unit)) ? ZhCalc.round(quantity, findDecimal(gcl.unit)) : 0) + '</td>' +
-                    '<td class="text-center"><input type="checkbox"' + isChecked +
+                    '<td class="text-center"><input type="checkbox" ' + isDisabled + isChecked +
                     '></td></tr>';
             }
         } else if (!isDeal && isCheck) {
@@ -686,7 +698,8 @@ $(document).ready(() => {
         const newLedgerList = remakeChangeSpread();
         // 更新至服务器
         postData(window.location.pathname + '/save', { type:'ledger_list', updateData: newLedgerList }, function (result) {
-            changeList = result;
+            changeList = result.changeList;
+            changeUsedData = result.usedList;
             SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
             changeSpreadObj.makeSjsFooter();
             const select = SpreadJsObj.getSelectObject(changeSpreadSheet);
@@ -898,7 +911,11 @@ function tableDataRemake(changeListData) {
                     let pushbwmx = '0*;*0';
                     if (listinfo.leafXmjs !== undefined) {
                         const leafInfo = listinfo.leafXmjs.find(function (item) {
-                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx) && item.code === clinfo.xmj_code && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            const flag = (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && item.gcl_id === clinfo.gcl_id && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            if (flag && item.code === clinfo.xmj_code) {
+                                return flag && item.code === clinfo.xmj_code;
+                            }
+                            return flag;
                         });
                         if (leafInfo) {
                             pushbwmx = leafInfo.code + '!_!' + (leafInfo.jldy !== undefined ? leafInfo.jldy : '') + '!_!' +
@@ -906,7 +923,7 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.fbgc ? leafInfo.fbgc : '') + '!_!' +
                                 (leafInfo.fxgc ? leafInfo.fxgc : '') + '!_!' +
                                 (leafInfo.gcl_id ? leafInfo.gcl_id : '') + '!_!' +
-                                (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (leafInfo.jldy !== undefined ? leafInfo.jldy : '')) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
+                                (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (listinfo.leafXmjs.length > 1 && listinfo.name ? listinfo.name : (leafInfo.jldy !== undefined ? leafInfo.jldy : ''))) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
                             // changeList.splice(index, 1);
@@ -929,7 +946,11 @@ function tableDataRemake(changeListData) {
                     let pushbwmx = '0*;*0';
                     if (listinfo.leafXmjs !== undefined) {
                         const leafInfo = listinfo.leafXmjs.find(function (item) {
-                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && item.code === clinfo.xmj_code && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            const flag = (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && item.gcl_id === clinfo.gcl_id && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            if (flag && item.code === clinfo.xmj_code) {
+                                return flag && item.code === clinfo.xmj_code;
+                            }
+                            return flag;
                         });
                         if (leafInfo) {
                             pushbwmx = leafInfo.code + '!_!' + (leafInfo.jldy !== undefined ? leafInfo.jldy : '') + '!_!' +
@@ -937,7 +958,7 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.fbgc ? leafInfo.fbgc : '') + '!_!' +
                                 (leafInfo.fxgc ? leafInfo.fxgc : '') + '!_!' +
                                 (leafInfo.gcl_id ? leafInfo.gcl_id : '') + '!_!' +
-                                (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (leafInfo.jldy !== undefined ? leafInfo.jldy : '')) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
+                                (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (listinfo.leafXmjs.length > 1 && listinfo.name ? listinfo.name : (leafInfo.jldy !== undefined ? leafInfo.jldy : ''))) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
                             // changeList.splice(index, 1);
@@ -1046,7 +1067,7 @@ function remakeChangeSpread() {
                 gcl_id,
             };
             const radionInfo = changeList.find(function (info) {
-                return info.code === code && (info.lid == lid || parseInt(info.lid) === parseInt(lindex)) && gcl_id == info.gcl_id && info.bwmx === bwmx;
+                return info.code === code && (info.lid == lid || parseInt(info.lid) === parseInt(lindex)) && gcl_id == info.gcl_id && (info.bwmx === bwmx || info.bwmx === xmj_jldy) && parseInt(info.oamount) === parseInt(oamount);
             });
             if (radionInfo) {
                 trlist.camount = radionInfo.camount;

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

@@ -203,7 +203,8 @@ $(document).ready(() => {
                 if (response.err === 0) {
                     codeSuccess(btn);
                     $("input[name='code']").removeAttr('readonly');
-                    $("#re-shenpi-btn").removeAttr('disabled');
+                    // $("#re-shenpi-btn").removeAttr('disabled');
+                    $("#re-shenpi-btn2").removeAttr('disabled');
                 } else {
                     toast(response.msg, 'error');
                 }

+ 19 - 1
app/public/js/shenpi.js

@@ -1106,6 +1106,24 @@ $(document).ready(function () {
         const X = $('#tender-list').find('.result').eq(now-1).offset().top;
         $('#tender-list').scrollTop(X - $('#tender-list').offset().top + $('#tender-list').scrollTop() -30);
     });
+
+    $('body').on('blur', '#coo_table .edit-company', function () {
+        const id = $(this).data('id');
+        const newVal = $(this).val();
+        const cooInfo = _.find(ledger_cooperation_list, { id: id });
+        if(cooInfo && cooInfo.company !== newVal) {
+            const data = {
+                type: 'company',
+                id,
+                company: newVal,
+            };
+            postData('/tender/' + cur_tenderid + '/shenpi/audit/save', data, function (result) {
+                const lcindex = _.findIndex(ledger_cooperation_list, { id: id });
+                cooInfo.company = newVal;
+                ledger_cooperation_list.splice(lcindex, 1, cooInfo);
+            });
+        }
+    })
 });
 
 function setRightData(datas, coolist) {
@@ -1197,7 +1215,7 @@ function setLeftTable(ledgerList, coolist, uid, title) {
         html += `<tr>` +
             `<td>${sc.code} ${sc.name}</td>` +
             `<td><p class="mb-0">${sc.pwd}</p><a href="javascript:void(0);" data-lid="${sc.ledger_id}" data-uid="${sc.user_id}" data-pwd="${sc.pwd}" class="edit-pwd">修改</a> <a href="javascript:void(0)" data-lid="${sc.ledger_id}" data-uid="${sc.user_id}" class="del-pwd text-danger">移除</a></td>` +
-            `<td>${pichtml}</td>` +
+            `<td>${pichtml}</td><td><input type="text" class="form-control form-control-sm edit-company" data-id="${sc.id}" value="${sc.company}" placeholder="输入单位名称或备注"></td>` +
             `</tr>`;
     }
     $('#coo_table').html(html);

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

@@ -366,7 +366,7 @@ $(document).ready(() => {
                     if (num === undefined || num === null || _.isNaN(num))
                         return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
                     if (i > 0) {
-                        if (param[i - 1].type !== 'calc') {
+                        if (param[i - 1].type !== 'calc' && param[i - 1].type !== 'left') {
                             return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
                         } else if (param[i - 1].value === '/' && num === 0) {
                             return [false, '输入的表达式非法:请勿除0'];

+ 9 - 5
app/public/js/tender.js

@@ -269,21 +269,22 @@ $(document).ready(function() {
             sheet.options.colHeaderVisible = false;
             sheet.defaults.rowHeight = 25;
             sheet.setColumnCount(3);
-            sheet.setRowCount(6);
+            sheet.setRowCount(7);
             sheet.setColumnWidth(0, 1);
             sheet.setColumnWidth(1, 200);
             sheet.setColumnWidth(2, 200);
             sheet.setRowHeight(0, 1);
-            sheet.getRange(1, 1, 5, 1).vAlign(1).backColor('#e4e7ea').locked(true);
-            sheet.getRange(1, 2, 5, 1).vAlign(1).hAlign(2).locked(true);
+            sheet.getRange(1, 1, 6, 1).vAlign(1).backColor('#e4e7ea').locked(true);
+            sheet.getRange(1, 2, 6, 1).vAlign(1).hAlign(2).locked(true);
             sheet.setText(1, 1, '签约合同价');
             sheet.setText(2, 1, '暂列金额');
             sheet.setText(3, 1, '签约合同价(不含暂列金)');
             sheet.setText(4, 1, '签约开工预付款');
             sheet.setText(5, 1, '签约材料预付款');
+            sheet.setText(6, 1, '安全生产费');
             const lineBorder = new spreadNS.LineBorder('#6a696e', spreadNS.LineStyle.thin);
-            sheet.getRange(0, 0, 6, 3).setBorder(lineBorder, {all: true});
-            sheet.getRange(0, 0, 6, 3).formatter('@');
+            sheet.getRange(0, 0, 7, 3).setBorder(lineBorder, {all: true});
+            sheet.getRange(0, 0, 7, 3).formatter('@');
             sheet.setSelection(1, 2, 1, 1);
         });
 
@@ -347,6 +348,7 @@ $(document).ready(function() {
             sheet.setValue(3, 2, accSub(property.deal_param.zanLiePrice, property.deal_param.contractPrice));
             sheet.setValue(4, 2, property.deal_param.startAdvance);
             sheet.setValue(5, 2, property.deal_param.materialAdvance);
+            sheet.setValue(6, 2, property.deal_param.safeAdvance);
 
         }
         function setReadOnly (readOnly) {
@@ -354,6 +356,7 @@ $(document).ready(function() {
             sheet.getCell(2, 2).locked(readOnly);
             sheet.getCell(4, 2).locked(readOnly);
             sheet.getCell(5, 2).locked(readOnly);
+            sheet.getCell(6, 2).locked(readOnly);
         }
         function getNewDealData () {
             const result = {};
@@ -361,6 +364,7 @@ $(document).ready(function() {
             result.zanLiePrice = _.toNumber(sheet.getText(2, 2));
             result.startAdvance = _.toNumber(sheet.getText(4, 2));
             result.materialAdvance = _.toNumber(sheet.getText(5, 2));
+            result.safeAdvance = _.toNumber(sheet.getText(6, 2));
             return result;
         }
 

+ 2 - 0
app/public/report/js/rpt_custom.js

@@ -143,6 +143,8 @@ const rptCustomObj = (function () {
             }
             for (const t of tenders) {
                 const tender = gsObj.tenderSourceTree.nodes.find(function (x) { return x.tid === t.tid});
+                if (!tender) continue;
+
                 tender.selected = true;
                 select.push(tender);
                 const st = this._addTender(tender);

+ 1 - 0
app/router.js

@@ -347,6 +347,7 @@ module.exports = app => {
 
     app.post('/tender/:id/change/approval', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.approval');
     app.post('/tender/:id/change/check/again', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.checkAgain');
+    app.post('/tender/:id/change/check/revise', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.checkRevise');
 
     app.post('/tender/:id/change/:cid/check/codeRepeat', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.checkCodeRepeat');
     app.post('/tender/:id/change/:cid/info/copy', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.copyChange');

+ 1 - 1
app/service/advance.js

@@ -25,7 +25,7 @@ module.exports = app => {
                 value: type,
                 operate: '=',
             });
-            if (this.ctx.session.sessionUser.accountId !== this.ctx.tender.data.user_id) {
+            if (this.ctx.session.sessionUser.accountId !== this.ctx.tender.data.user_id && !this.ctx.tender.isTourist) {
                 this.sqlBuilder.setAndWhere('status', {
                     value: auditConst.status.uncheck,
                     operate: '!=',

+ 92 - 4
app/service/change.js

@@ -253,17 +253,18 @@ module.exports = app => {
                         sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
                         sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
                         break;
-                    case 5: // 待上报(所有的)PS:取未上报和退回的变更令
+                    case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令
                         sql =
                             'SELECT a.* FROM ?? AS a WHERE ' +
                             'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
-                            '(a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
+                            '(a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
                         sqlParam = [
                             this.tableName,
                             this.ctx.service.changeAudit.tableName,
                             this.ctx.session.sessionUser.accountId,
                             audit.flow.status.uncheck,
                             audit.flow.status.back,
+                            audit.flow.status.revise,
                             tenderId,
                         ];
                         break;
@@ -326,17 +327,18 @@ module.exports = app => {
                         uid: this.ctx.session.sessionUser.accountId,
                         status: 2,
                     });
-                case 5: // 待上报(所有的)PS:取未上报和退回的变更令
+                case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令
                     const sql2 =
                         'SELECT count(*) AS count FROM ?? AS a WHERE ' +
                         'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) ' +
-                        'AND (a.status = ? OR a.status = ?) AND a.tid = ?';
+                        'AND (a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ?';
                     const sqlParam2 = [
                         this.tableName,
                         this.ctx.service.changeAudit.tableName,
                         this.ctx.session.sessionUser.accountId,
                         audit.flow.status.uncheck,
                         audit.flow.status.back,
+                        audit.flow.status.revise,
                         tenderId,
                     ];
                     const result2 = await this.db.query(sql2, sqlParam2);
@@ -1191,6 +1193,92 @@ module.exports = app => {
          * @param { string } cid - 查询的清单
          * @return {Promise<*>} - 可用的变更令列表
          */
+        async checkRevise(cid) {
+            // 初始化事务
+            this.transaction = await this.db.beginTransaction();
+            let result = false;
+            try {
+                const changeData = await this.getDataByCondition({ cid });
+                const pid = this.ctx.session.sessionProject.id;
+                // 获取所有审核人列表
+                const auditors = await this.ctx.service.changeAudit.getAllAuditors(changeData.tid);
+                // 添加到消息推送表
+                const noticeContent = await this.getNoticeContent(pid, changeData.tid, changeData.cid, this.ctx.session.sessionUser.accountId);
+                const records = [];
+                auditors.forEach(auditor => {
+                    records.push({
+                        pid,
+                        type: pushType.change,
+                        uid: auditor.uid,
+                        status: audit.flow.status.revise,
+                        content: noticeContent,
+                    });
+                });
+                await this.transaction.insert('zh_notice', records);
+
+                // 新增新一次的审批人列表
+                // 获取当前次数审批人列表
+                const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeData.cid, changeData.times);
+                const lastauditInfo = await this.ctx.service.changeAudit.getLastUser(changeData.cid, changeData.times, 1, 0);
+                let usort = lastauditInfo.usort + 1;
+                const newTimes = changeData.times + 1;
+                const insert_audit_array = [];
+                for (const al of auditList) {
+                    const insert_audit = {
+                        tid: al.tid,
+                        cid: al.cid,
+                        uid: al.uid,
+                        name: al.name,
+                        jobs: al.jobs,
+                        company: al.company,
+                        times: newTimes,
+                        usite: al.usite,
+                        usort,
+                        status: al.usite !== 0 ? audit.flow.auditStatus.uncheck : audit.flow.auditStatus.checking,
+                    };
+                    insert_audit_array.push(insert_audit);
+                    usort++;
+                }
+                await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit_array);
+                // 变更金额也退回
+                const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({
+                    where: { cid: changeData.cid },
+                });
+                let total_price = 0;
+                const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp;
+                for (const cl of changeList) {
+                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, tp_decimal));
+                }
+                // 设置变更令修订状态
+                const change_update = {
+                    w_code: changeData.w_code,
+                    status: audit.flow.status.revise,
+                    times: newTimes,
+                    cin_time: Date.parse(new Date()) / 1000,
+                    total_price,
+                    tp_decimal: null,
+                };
+                const options = {
+                    where: {
+                        cid: changeData.cid,
+                    },
+                };
+                await this.transaction.update(this.tableName, change_update, options);
+
+                await this.transaction.commit();
+                result = true;
+            } catch (error) {
+                await this.transaction.rollback();
+                result = false;
+            }
+            return result;
+        }
+
+        /**
+         * 重新审批变更令
+         * @param { string } cid - 查询的清单
+         * @return {Promise<*>} - 可用的变更令列表
+         */
         async checkAgain(cid) {
             // 初始化事务
             this.transaction = await this.db.beginTransaction();

+ 4 - 0
app/service/change_audit.js

@@ -116,6 +116,9 @@ module.exports = app => {
             } else if (change.status === statusConst.back && uid === change.uid) {
                 // 待重新上报
                 return 2;
+            } else if (change.status === statusConst.revise && uid === change.uid) {
+                // 修订上报
+                return 9;
             } else if (change.status === statusConst.back && uid !== change.uid) {
                 // 被退回但你不是原报人
                 return 3;
@@ -151,6 +154,7 @@ module.exports = app => {
             switch (status) {
                 case 1:// 待上报
                 case 2:// 待重新上报
+                case 9:// 待修订
                     sql = 'SELECT * FROM ?? WHERE ' +
                         'cid = ? AND times = ? GROUP BY usite';
                     sqlParam = [this.tableName, change.cid,

+ 26 - 0
app/service/change_audit_list.js

@@ -210,6 +210,9 @@ module.exports = app => {
             // 判断t_type是否为费用
             const transaction = await this.db.beginTransaction();
             try {
+                const sql1 = 'SELECT a.* FROM ?? as b LEFT JOIN ?? as a ON b.cbid = a.id WHERE b.cid = ? GROUP BY b.cbid';
+                const sqlParam1 = [this.ctx.service.stageChange.tableName, this.tableName, this.ctx.change.cid];
+                const usedList = await transaction.query(sql1, sqlParam1);
                 // 先删除原本的台账清单数据
                 const sql = 'DELETE FROM ?? WHERE cid = ? and lid != "0"';
                 const sqlParam = [this.tableName, this.ctx.change.cid];
@@ -224,6 +227,29 @@ module.exports = app => {
                 }
                 if (insertDatas.length > 0) await transaction.insert(this.tableName, insertDatas);
                 await this.calcCamountSum(transaction);
+                // 更新stage_change和stage_change_final的cbid
+                if (usedList.length > 0) {
+                    const updateList = [];
+                    const newList = await transaction.select(this.tableName, { where: { cid: this.ctx.change.cid } });
+                    for (const used of usedList) {
+                        const newone = this._.find(newList, { code: used.code, lid: used.lid, gcl_id: used.gcl_id, bwmx: used.bwmx });
+                        if (newone) {
+                            updateList.push({
+                                row: {
+                                    cbid: newone.id,
+                                },
+                                where: {
+                                    cid: this.ctx.change.cid,
+                                    cbid: used.id,
+                                },
+                            });
+                        }
+                    }
+                    if (updateList.length > 0) {
+                        await transaction.updateRows(this.ctx.service.stageChange.tableName, updateList);
+                        await transaction.updateRows(this.ctx.service.stageChangeFinal.tableName, updateList);
+                    }
+                }
                 await transaction.commit();
                 return true;
             } catch (err) {

+ 8 - 0
app/service/ledger_cooperation.js

@@ -64,6 +64,14 @@ module.exports = app => {
             return await this.db.update(this.tableName, updateData);
         }
 
+        async saveCompany(data) {
+            const updateData = {
+                id: data.id,
+                company: data.company,
+            };
+            return await this.db.update(this.tableName, updateData);
+        }
+
         async getValidData(tid, uid) {
             const condition = { where: { tid, status: 1 } };
             if (uid) {

+ 14 - 0
app/service/report.js

@@ -8,6 +8,8 @@
  * @version
  */
 
+const rptCustomData = require('../lib/rptCustomData');
+
 module.exports = app => {
     class Report extends app.BaseService {
 
@@ -188,6 +190,10 @@ module.exports = app => {
                             runnableRst.push(service.reportMemory.getSignSelect(params.tender_id, params.stage_id, customSelect));
                             runnableKey.push(filter);
                             break;
+                        case 'mem_stage_change':
+                            runnableRst.push(service.stageChange.getAllDataByCondition({ where: { tid: params.tender_id, sid: params.stage_id } }));
+                            runnableKey.push(filter);
+                            break;
                         case 'mem_stage_change_bills':
                             runnableRst.push(service.stageChangeFinal.getFinalData(params.tender_id));
                             runnableKey.push(filter);
@@ -230,6 +236,14 @@ module.exports = app => {
                     case 'mem_change_bills':
                         rst[filter] = await service.reportMemory.getChangeBillsData(params.tender_id, params.stage_id, memFieldKeys[filter]);
                         break;
+                    case 'mem_jh_im_change':
+                        const jhHelper1 = new rptCustomData.jhHelper(this.ctx);
+                        rst[filter] = await jhHelper1.convert(params.tender_id, params.stage_id, memFieldKeys[filter], customDefine.setting);
+                        break;
+                    case 'mem_jh_gather_im_change':
+                        const jhHelper2 = new rptCustomData.jhHelper(this.ctx);
+                        rst[filter] = await jhHelper2.gather(memFieldKeys[filter], customDefine.gather_select, customSelect ? customSelect.gather_select : null);
+                        break;
                     // case 'mem_material_bills':
                     //     rst[filter] = await service.rptGatherMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]);
                     //     break;

+ 1 - 0
app/service/rpt_gather_memory.js

@@ -482,6 +482,7 @@ module.exports = app => {
             if (!gsDefine || !gsDefine.enable) return [];
             if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
 
+            this.resultTree.clear();
             const gsSetting = JSON.parse(gsDefine.setting);
             let commonIndex = 0;
             const completeDatas = [];

+ 1 - 1
app/service/stage.js

@@ -90,7 +90,7 @@ module.exports = app => {
                 } else {
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
-            } else if (this.ctx.tender.isTourist) { // 游客
+            } else if (this.ctx.tender && this.ctx.tender.isTourist) { // 游客
                 stage.readOnly = true;
                 stage.curTimes = stage.times;
                 if (stage.status === status.uncheck || stage.status === status.checkNo) {

+ 1 - 1
app/service/stage_change.js

@@ -328,7 +328,7 @@ module.exports = app => {
 
         async getFinalUsedData(tid, cid) {
             const sql = 'SELECT c.lid, c.pid, SUM(c.qty) as used_qty,' +
-                '    cb.tid, cb.cid, cb.id, cb.code, cb.name, cb.unit, cb.unit_price, cb.detail, cb.samount' +
+                '    cb.tid, cb.cid, cb.id, cb.code, cb.name, cb.unit, cb.unit_price, cb.detail, cb.samount, cb.oamount, cb.bwmx, cb.gcl_id' +
                 '  FROM ' + this.ctx.service.changeAuditList.tableName + ' As cb' +
                 '  LEFT JOIN ' + this.tableName + ' As c ON cb.id = c.cbid ' +
                 '  INNER JOIN (' +

+ 8 - 4
app/service/stage_change_final.js

@@ -31,12 +31,16 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async getFinalData(tid) {
-            const sql = 'Select cf.*, c.code As c_code, c.name As c_name, c.new_code As c_new_code, c.new_name As c_new_name, c.content As c_content, c.basis As c_basis, c.cin_time As c_cin_time' +
-                '  FROM ' + this.tableName + ' cf Left Join ' + this.ctx.service.change.tableName + ' c' +
-                '  ON cf.cid = c.cid' +
+            const sql = 'Select cf.*,' +
+                '    c.code As c_code, c.name As c_name, c.new_code As c_new_code, c.new_name As c_new_name,' +
+                '    c.content As c_content, c.basis As c_basis, c.cin_time As c_cin_time,' +
+                '    c.class As c_class, c.type As c_type, c.quality As c_quality,' +
+                '    s.order As s_order' +
+                '  FROM ' + this.tableName + ' cf' +
+                '  Left Join ' + this.ctx.service.change.tableName + ' c ON cf.cid = c.cid' +
+                '  Left Join ' + this.ctx.service.stage.tableName + ' c ON cf.sid = s.id' +
                 '  Where cf.tid = ?';
             return await this.db.query(sql, [tid]);
-            //return await this.getAllDataByCondition({ where: { tid: tid } });
         }
 
         /**

+ 2 - 1
app/service/stage_detail.js

@@ -34,11 +34,12 @@ module.exports = app => {
             const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
+                '        WHERE tid = ? AND sid = ?' +
                 '      GROUP BY `lid`, `uuid`' +
                 '  ) As MaxFilter ' +
                 '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
                 '  WHERE Bills.tid = ? And Bills.sid = ?' + lidSql;
-            const sqlParam = [tid, sid];
+            const sqlParam = [tid, sid, tid, sid];
             if (!lid) {
                 return await this.db.query(sql, sqlParam);
             } else if (lid instanceof Array) {

+ 2 - 13
app/service/stage_pos_final.js

@@ -32,19 +32,8 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async getFinalData(tender, stageOrder) {
-            // const sql = 'SELECT Pos.* FROM ' +
-            //     //'  (SELECT pid, contract_qty, qc_qty, sorder FROM ' + this.tableName + ' WHERE tid = ?) As Pos' +
-            //     this.tableName + ' As Pos' +
-            //     '  INNER JOIN ( ' +
-            //     '    SELECT MAX(`sorder`) As `sorder`, `pid` From ' + this.tableName +
-            //     '      WHERE tid = ? AND sorder < ?' +
-            //     '      GROUP BY `pid`' +
-            //     '  ) As MaxFilter ' +
-            //     '  ON Pos.sorder = MaxFilter.sorder And Pos.pid = MaxFilter.pid';
-            // //const sqlParam = [tender.id, tender.id, stage.order];
-            // const sqlParam = [tender.id, stage.order];
-            return await this.getAllDataByCondition({
-                //columns: ['pid', 'contract_qty', 'qc_qty'],
+            return await this.db.select(this.departTableName(tender.id), {
+                //columns: ['lid', 'contract_qty', 'qc_qty', 'contract_tp', 'qc_tp'],
                 where: {tid: tender.id, sorder: stageOrder},
             });
         }

+ 7 - 1
app/view/advance/audit_btn.ejs

@@ -1,6 +1,10 @@
 
 <% if (ctx.advance.status === auditConst.status.uncheck) { %>
-<a href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm">上报审批</a>
+    <% if (ctx.session.sessionUser.accountId === ctx.advance.uid) { %>
+        <a href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm">上报审批</a>
+    <% } else if (ctx.tender.isTourist) { %>
+        <button class="btn btn-outline-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="上报中">上报中</button>
+    <% } %>
 <% } else if (ctx.advance.status === auditConst.status.checking) { %>
     <% if (ctx.advance.curAuditor && ctx.advance.curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
         <a id="sp-done-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm">审批通过</a>
@@ -14,6 +18,8 @@
     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted sp-list-btn">审批退回</a>
     <% if (ctx.session.sessionUser.accountId === ctx.advance.uid) { %>
         <a href="#sub-sp" data-target="#sub-sp" data-toggle="modal"  class="btn btn-primary btn-sm">重新上报</a>
+    <% } else if (ctx.tender.isTourist) { %>
+        <button class="btn btn-outline-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="重新上报中">重新上报中</button>
     <% } %>
 <% } else if (ctx.advance.status === auditConst.status.checkNoPre) { %>
     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted sp-list-btn">审批退回</a>

+ 6 - 6
app/view/advance/detail.ejs

@@ -350,14 +350,14 @@
     const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     const decimal = parseInt('<%- decimal %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
-    const advance = JSON.parse('<%- JSON.stringify(advance) %>');
-    const prevAdvance = JSON.parse('<%- JSON.stringify(prevAdvance) %>');
+    const advance = JSON.parse(unescape('<%- escape(JSON.stringify(advance)) %>'));
+    const prevAdvance = JSON.parse(unescape('<%- escape(JSON.stringify(prevAdvance)) %>'));
     const isEdited = JSON.parse('<%- isEdited %>');
     const advancePayTotal = parseFloat('<%- advancePayTotal %>');
     const preUrl = '<%- preUrl %>';
-    const fileList = JSON.parse('<%- JSON.stringify(fileList) %>') || [];
+    const fileList = JSON.parse(unescape('<%- escape(JSON.stringify(fileList)) %>')) || [];
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
-    const curAuditor = JSON.parse('<%- JSON.stringify(ctx.advance.curAuditor) %>');
+    const curAuditor = JSON.parse(unescape('<%- escape(JSON.stringify(ctx.advance.curAuditor)) %>'));
 
     // 展开历史审核记录
     $('td #fold-btn').click(function () {
@@ -380,8 +380,8 @@
 </script>
 <% if(isEdited && ctx.session.sessionUser.accountId === ctx.advance.uid) { %>
 <script>
-    const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
-    const accountGroup = JSON.parse('<%- JSON.stringify(accountGroup) %>');
+    const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
+    const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
     const shenpi_status = <%- ctx.tender.info.shenpi.advance %>;
     const shenpiConst =  JSON.parse('<%- JSON.stringify(shenpiConst) %>');
 </script>

+ 5 - 1
app/view/change/index.ejs

@@ -67,13 +67,17 @@
                         <td>
                             待上报
                         </td>
+                        <% } else if (c.status === auditConst.status.revise) { %>
+                            <td>
+                                待修订
+                            </td>
                         <% } else { %>
                         <td>
                             <%- c.changeAudit.name %>-<%- c.changeAudit.jobs %>
                             <span class="<%- auditConst.auditStatusClass[c.changeAudit.status] %>"><%- auditConst.auditStatusString[c.changeAudit.status] %></span>
                         </td>
                         <% } %>
-                        <td><% if ((c.status === auditConst.status.uncheck || (c.status === auditConst.status.back && c.uid === uid)) && !ctx.tender.isTourist) { %><a href="#del-bg" cid="<%= c.cid %>" data-toggle="modal" data-target="#del-bg" class="btn btn-outline-danger btn-sm delete-cid-modal">删除</a><% } %></td>
+                        <td><% if ((c.status === auditConst.status.uncheck || ((c.status === auditConst.status.back || (c.status === auditConst.status.revise && c.stageChangeNum === 0)) && c.uid === uid)) && !ctx.tender.isTourist) { %><a href="#del-bg" cid="<%= c.cid %>" data-toggle="modal" data-target="#del-bg" class="btn btn-outline-danger btn-sm delete-cid-modal">删除</a><% } %></td>
                     </tr>
                     <% } %>
                     </tbody>

+ 12 - 8
app/view/change/information.ejs

@@ -4,12 +4,12 @@
         <div class="title-main d-flex"><!--工具-->
             <% include ../tender/tender_sub_mini_menu.ejs %>
             <div>
-                <% if(auditStatus === auditConst.status.uncheck || auditStatus === auditConst.status.back) { %>
+                <% if(auditStatus === auditConst.status.uncheck || auditStatus === auditConst.status.back || auditStatus === auditConst.status.revise) { %>
                     <div class="d-inline-block">
                         <a class="btn btn-sm btn-primary" href="#add-bj" data-toggle="modal" data-target="#add-bj">拷贝其他变更令数据</a>
                     </div>
                 <% } %>
-                <% if (auditStatus === 1 || auditStatus === 2) { %>
+                <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
                     <div class="d-inline-block">
                         <a href="#addlist" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="open-list-modal" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-plus" aria-hidden="true"></i> 添加台账清单</a>
                     </div>
@@ -36,7 +36,7 @@
                 <!--info状态区分-->
                 <% if (auditStatus === 1) { %>
                     <a href="#sub-ap" data-category="up_change" data-toggle="modal" data-target="#sub-ap" class="btn btn-primary btn-sm">上报审批</a>
-                <% } else if (auditStatus === 2) { %>
+                <% } else if (auditStatus === 2 || auditStatus === 9) { %>
                     <a href="#sub-sp2" data-category="up_change" data-toggle="modal" data-target="#sub-sp2" class="btn btn-primary btn-sm">重新上报</a>
                 <% } else if (auditStatus === 3) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted">审批退回</a>
@@ -59,14 +59,17 @@
                 <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === auditList[auditList.length-1].uid) { %>
                     <% if (stageChangeNum === 0) { %>
                         <!--重新审批-->
-                        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm">重新审批</a>
+                        <!--<a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm">重新审批</a>-->
                     <% } else { %>
-                        <button class="btn btn-outline-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="已被调用">重新审批</button>
+                        <!--<button class="btn btn-outline-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="已被调用">重新审批</button>-->
                     <% } %>
                 <% } %>
+                <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === change.uid) { %>
+                    <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-revise" class="btn btn-warning btn-sm">修订变更</a>
+                <% } %>
             </div>
             <!--info状态区分-->
-            <% if (auditStatus === 1 || auditStatus === 2) { %>
+            <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
                 <div class="ml-auto px-4" id="show-save-btn" style="display: none">
                     <span>您修改了变更信息,记得保存修改。</span>
                     <button class="btn btn-sm btn-primary save_change_btn" id="save_change"><i class="fa fa-save"></i> 保存修改</button>
@@ -103,7 +106,7 @@
                 <div class="tab-content">
                     <div class="tab-pane active" id="bgxinxi">
                         <div class="sjs-sh-1" style="overflow-y: auto;">
-                            <% if (auditStatus === 1 || auditStatus === 2) { %>
+                            <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
                             <form class="p-2" action="/tender/<%- change.tid %>/change/<%- change.cid %>/information/save?_csrf_j=<%= ctx.csrf %>" method="post" id="change_form">
                                 <div class="form-group">
                                     <label><b class="text-danger">*&nbsp;</b>申请编号</label>
@@ -404,7 +407,7 @@
     const style1 = new GC.Spread.Sheets.Style();
     style1.locked = true;
 </script>
-<% if (auditStatus === 1 || auditStatus === 2) { %>
+<% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
 <script>
     let changeUnits = JSON.parse('<%- JSON.stringify(changeUnits) %>');
     changeUnits = _.map(changeUnits, 'unit');
@@ -435,6 +438,7 @@
         w_code: '<%- change.w_code %>',
     };
     let changeInfo = Object.assign({}, back_changeInfo);
+    let changeUsedData = JSON.parse(unescape('<%- escape(JSON.stringify(changeUsedData)) %>'));
 </script>
 <script src="/public/js/change_information_set.js"></script>
 <script src="/public/js/change_audit.js"></script>

+ 131 - 47
app/view/change/information_modal.ejs

@@ -1,4 +1,4 @@
-<% if (auditStatus === 1 || auditStatus === 2) { %>
+<% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
 <!--变更单位-->
 <div class="modal fade" id="editcompany" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
     <div class="modal-dialog" role="document">
@@ -153,7 +153,7 @@
     </div>
 </div>
 
-<% if (auditStatus === 2) { %>
+<% if (auditStatus === 2 || auditStatus === 9) { %>
     <!--重新上报-->
     <div class="modal fade" id="sub-sp2" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document">
@@ -926,56 +926,109 @@
 </div>
 <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === auditList[auditList.length-1].uid && stageChangeNum === 0) { %>
 <% if (!authMobile && ctx.session.sessionUser.loginStatus === 0) { %>
-    <!--终审重新审批-->
-    <div class="modal fade" id="sp-down-back" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title">重新审批</h5>
-                </div>
-                <div class="modal-body">
-                    <h5>重新审批需要您的手机短信验证</h5>
-                    <h5>您目前还没设置认证手机,请先设置。</h5>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="/profile/sms" class="btn btn-sm btn-primary">去设置</a>
+    <!--&lt;!&ndash;终审重新审批&ndash;&gt;-->
+    <!--<div class="modal fade" id="sp-down-back" data-backdrop="static">-->
+        <!--<div class="modal-dialog" role="document">-->
+            <!--<div class="modal-content">-->
+                <!--<div class="modal-header">-->
+                    <!--<h5 class="modal-title">重新审批</h5>-->
+                <!--</div>-->
+                <!--<div class="modal-body">-->
+                    <!--<h5>重新审批需要您的手机短信验证</h5>-->
+                    <!--<h5>您目前还没设置认证手机,请先设置。</h5>-->
+                <!--</div>-->
+                <!--<div class="modal-footer">-->
+                    <!--<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>-->
+                    <!--<a href="/profile/sms" class="btn btn-sm btn-primary">去设置</a>-->
+                <!--</div>-->
+            <!--</div>-->
+        <!--</div>-->
+    <!--</div>-->
+<!--<% } else { %>-->
+    <!--&lt;!&ndash;重新审批&ndash;&gt;-->
+<!--<div class="modal fade" id="sp-down-back" data-backdrop="static">-->
+    <!--<div class="modal-dialog" role="document">-->
+        <!--<form id="againForm" class="modal-content" method="post" action="/tender/<%- tender.id %>/change/check/again" onsubmit="return false;">-->
+            <!--<div class="modal-header">-->
+                <!--<h5 class="modal-title">重新审批</h5>-->
+            <!--</div>-->
+            <!--<div class="modal-body">-->
+                <!--<h5>确认由「终审-<%= auditList[auditList.length-1].name %>」重新审批「<%= change.code %>」?</h5>-->
+                <!--<% if (ctx.session.sessionUser.loginStatus === 0) { %>-->
+                <!--<div class="form-group">-->
+                    <!--<label>重审需要验证码确认,验证码将发送至尾号<%- authMobile.slice(-4) %>的手机</label>-->
+                    <!--<div class="input-group input-group-sm mb-3">-->
+                        <!--<input class="form-control" type="text" readonly="readonly" name="code" placeholder="输入短信中的6位验证码" />-->
+                        <!--<div class="input-group-append">-->
+                            <!--<button class="btn btn-outline-secondary" type="button" id="get-code">获取验证码</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                <!--</div>-->
+                <!--<% } %>-->
+            <!--</div>-->
+            <!--<div class="modal-footer">-->
+                <!--<input type="hidden" name="cid" value="<%= change.cid %>">-->
+                <!--<input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />-->
+                <!--<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>-->
+                <!--<button type="button" id="re-shenpi-btn" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定重审</button>-->
+            <!--</div>-->
+        <!--</form>-->
+    <!--</div>-->
+<!--</div>-->
+<% } %>
+<% } %>
+<% if (auditStatus === 4 && ctx.session.sessionUser.accountId === change.uid) { %>
+    <% if (!authMobile && ctx.session.sessionUser.loginStatus === 0) { %>
+        <!--原报修订变更-->
+        <div class="modal fade" id="sp-down-revise" data-backdrop="static">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">修订变更</h5>
+                    </div>
+                    <div class="modal-body">
+                        <h5>修订变更需要您的手机短信验证</h5>
+                        <h5>您目前还没设置认证手机,请先设置。</h5>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="/profile/sms" class="btn btn-sm btn-primary">去设置</a>
+                    </div>
                 </div>
             </div>
         </div>
-    </div>
-<% } else { %>
-    <!--重新审批-->
-<div class="modal fade" id="sp-down-back" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <form id="againForm" class="modal-content" method="post" action="/tender/<%- tender.id %>/change/check/again" onsubmit="return false;">
-            <div class="modal-header">
-                <h5 class="modal-title">重新审批</h5>
-            </div>
-            <div class="modal-body">
-                <h5>确认由「终审-<%= auditList[auditList.length-1].name %>」重新审批「<%= change.code %>」?</h5>
-                <% if (ctx.session.sessionUser.loginStatus === 0) { %>
-                <div class="form-group">
-                    <label>重审需要验证码确认,验证码将发送至尾号<%- authMobile.slice(-4) %>的手机</label>
-                    <div class="input-group input-group-sm mb-3">
-                        <input class="form-control" type="text" readonly="readonly" name="code" placeholder="输入短信中的6位验证码" />
-                        <div class="input-group-append">
-                            <button class="btn btn-outline-secondary" type="button" id="get-code">获取验证码</button>
-                        </div>
+    <% } else { %>
+        <!--修订变更-->
+        <div class="modal fade" id="sp-down-revise" data-backdrop="static">
+            <div class="modal-dialog" role="document">
+                <form id="reviseForm" class="modal-content" method="post" action="/tender/<%- tender.id %>/change/check/revise" onsubmit="return false;">
+                    <div class="modal-header">
+                        <h5 class="modal-title">修订变更</h5>
                     </div>
-                </div>
-                <% } %>
-            </div>
-            <div class="modal-footer">
-                <input type="hidden" name="cid" value="<%= change.cid %>">
-                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
-                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <button type="button" id="re-shenpi-btn" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定重审</button>
+                    <div class="modal-body">
+                        <h5>确认需要修订变更「<%= change.code %>」?</h5>
+                        <% if (ctx.session.sessionUser.loginStatus === 0) { %>
+                            <div class="form-group">
+                                <label>修订需要验证码确认,验证码将发送至尾号<%- authMobile.slice(-4) %>的手机</label>
+                                <div class="input-group input-group-sm mb-3">
+                                    <input class="form-control" type="text" readonly="readonly" name="code" placeholder="输入短信中的6位验证码" />
+                                    <div class="input-group-append">
+                                        <button class="btn btn-outline-secondary" type="button" id="get-code">获取验证码</button>
+                                    </div>
+                                </div>
+                            </div>
+                        <% } %>
+                    </div>
+                    <div class="modal-footer">
+                        <input type="hidden" name="cid" value="<%= change.cid %>">
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                        <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                        <button type="button" id="re-shenpi-btn2" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定修订</button>
+                    </div>
+                </form>
             </div>
-        </form>
-    </div>
-</div>
-<% } %>
+        </div>
+    <% } %>
 <% } %>
 
 <div class="modal fade" id="warning-ledger" data-backdrop="static">
@@ -1097,4 +1150,35 @@
             }
         });
     })
+
+    $('#re-shenpi-btn2').click(function () {
+        const data = {
+            cid: '<%- change.cid %>',
+        };
+        <% if (ctx.session.sessionUser.loginStatus === 0) { %>
+        const code = $("#reviseForm input[name='code']").val();
+        if ($(this).hasClass('disabled')) {
+            return false;
+        }
+        if (code.length < 6) {
+            // alert('请填写正确的验证码');
+            toast('请填写正确的验证码', 'error');
+            return false;
+        }
+        data.code = code;
+        <% } %>
+        $.ajax({
+            url: '/tender/<%- tender.id %>/change/check/revise?_csrf_j=' + csrf,
+            type: 'post',
+            data: data,
+            dataTye: 'json',
+            success: function(response) {
+                if (response.err === 0) {
+                    window.location.href = response.url;
+                } else {
+                    toast(response.msg, 'error');
+                }
+            }
+        });
+    })
 </script>

+ 9 - 5
app/view/tender/detail_modal.ejs

@@ -1219,20 +1219,21 @@
         SpreadJsObj.massOperationSheet(sheet, function () {
             sheet.defaults.rowHeight = 21;
             sheet.setColumnCount(2);
-            sheet.setRowCount(5);
+            sheet.setRowCount(6);
             sheet.setColumnWidth(0, 200);
             sheet.setColumnWidth(1, 200);
-            sheet.getRange(0, 0, 5, 1).vAlign(1).backColor('#e4e7ea').locked(true);
-            sheet.getRange(0, 1, 5, 1).vAlign(1).hAlign(2).locked(false);
+            sheet.getRange(0, 0, 6, 1).vAlign(1).backColor('#e4e7ea').locked(true);
+            sheet.getRange(0, 1, 6, 1).vAlign(1).hAlign(2).locked(false);
             sheet.setText(0, 0, '签约合同价');
             sheet.setText(1, 0, '暂列金额');
             sheet.setText(2, 0, '签约合同价(不含暂列金)');
             sheet.setText(3, 0, '签约开工预付款');
             sheet.setText(4, 0, '签约材料预付款');
+            sheet.setText(5, 0, '安全生产费');
             sheet.getCell(2, 1).locked(true);
             const lineBorder = new spreadNS.LineBorder('#dee2e6', spreadNS.LineStyle.thin);
-            sheet.getRange(0, 0, 5, 2).setBorder(lineBorder, {all: true});
-            sheet.getRange(0, 0, 5, 2).formatter('@');
+            sheet.getRange(0, 0, 6, 2).setBorder(lineBorder, {all: true});
+            sheet.getRange(0, 0, 6, 2).formatter('@');
             sheet.setSelection(0, 1, 1, 1);
         });
 
@@ -1295,6 +1296,7 @@
             sheet.setValue(2, 1, ZhCalc.sub(property.deal_param.contractPrice, property.deal_param.zanLiePrice));
             sheet.setValue(3, 1, property.deal_param.startAdvance);
             sheet.setValue(4, 1, property.deal_param.materialAdvance);
+            sheet.setValue(5, 1, property.deal_param.safeAdvance);
 
         }
         function setReadOnly (readOnly) {
@@ -1302,6 +1304,7 @@
             sheet.getCell(1, 1).locked(readOnly);
             sheet.getCell(3, 1).locked(readOnly);
             sheet.getCell(4, 1).locked(readOnly);
+            sheet.getCell(5, 1).locked(readOnly);
         }
         function getNewDealData () {
             const result = {};
@@ -1309,6 +1312,7 @@
             result.zanLiePrice = _.toNumber(sheet.getText(1, 1));
             result.startAdvance = _.toNumber(sheet.getText(3, 1));
             result.materialAdvance = _.toNumber(sheet.getText(4, 1));
+            result.safeAdvance = _.toNumber(sheet.getText(5, 1));
             return result;
         }
 

+ 2 - 2
app/view/tender/shenpi_modal.ejs

@@ -101,8 +101,8 @@
                         <div class="modal-height-500">
                             <table class="table table-hover table-bordered">
                                 <thead>
-                                <tr><th colspan="3" class="text-center" id="stage_audit"><%- yb.name %>(原报)</th></tr>
-                                <tr><th>项目节编号/名称</th><th>密码</th><th>签名</th></tr>
+                                <tr><th colspan="4" class="text-center" id="stage_audit"><%- yb.name %>(原报)</th></tr>
+                                <tr><th>项目节编号/名称</th><th>密码</th><th>签名</th><th>单位/协同人名称</th></tr>
                                 </thead>
                                 <tbody id="coo_table">
                                 </tbody>

+ 98 - 1
builder_report_index_define.js

@@ -1419,6 +1419,10 @@ const stage_change_bills = {
         { name: '变更清单-名称', field: 'name', type: dataType.str },
         { name: '变更清单-单位', field: 'unit', type: dataType.str },
         { name: '变更清单-单价', field: 'unit_price', type: dataType.str },
+        { name: '变更令-变更类型', field: 'c_type', type: dataType.str },
+        { name: '变更令-变更类别', field: 'c_class', type: dataType.int },
+        { name: '变更令-变更性质', field: 'c_quality', type: dataType.int },
+        { name: '调用期-序号', field: 's_order', type: dataType.int },
     ],
 };
 
@@ -1582,6 +1586,98 @@ const all_tag = {
         { name: '最后编辑时间', field: 'modify_time', type: dataType.time },
     ],
 };
+const stage_change = {
+    name: '本期-变更清单-全审批人 调用明细(mem_stage_change)',
+    remark: '',
+    key: 'mem_stage_change',
+    id: 60,
+    prefix: '本期-变更清单-全审批人 调用明细',
+    cols: [
+        { name: 'id', field: 'id', type: dataType.str },
+        { name: '标段id', field: 'tid', type: dataType.str },
+        { name: '期id', field: 'sid', type: dataType.str },
+        { name: '台账id', field: 'lid', type: dataType.str },
+        { name: '计量单元id', field: 'pid', type: dataType.str },
+        { name: '变更令id', field: 'cid', type: dataType.str },
+        { name: '变更清单id', field: 'cbid', type: dataType.int },
+        { name: '期-调用人-第几轮', field: 'stimes', type: dataType.str },
+        { name: '期-调用人-排序', field: 'sorder', type: dataType.str },
+        { name: '变更数量', field: 'qty', type: dataType.int },
+    ],
+};
+
+// 定制表
+// 季华项目 中间计量报表--变更相关 汇总对比表
+const jh_im_change = {
+    name: '【定制】季华-中间计量-变更 数据表(mem_jh_im_change)',
+    remark: '',
+    id: 61,
+    key: 'mem_jh_im_change',
+    prefix: '【定制】季华-中间计量-变更',
+    cols: [
+        { name: '清单编号', field: 'b_code', type: dataType.str },
+        { name: '名称', field: 'name', type: dataType.str },
+        { name: '单位', field: 'unit', type: dataType.str }, // 12
+        { name: '单价', field: 'unit_price', type: dataType.currency },
+
+        { name: '截止上期-数量变更-数量', field: 'pre_qc_qty', type: dataType.currency },
+        { name: '截止上期-数量变更-金额', field: 'pre_qc_tp', type: dataType.currency },
+        { name: '本期-数量变更-数量', field: 'qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额', field: 'qc_tp', type: dataType.currency },
+        { name: '截止本期-数量变更-数量', field: 'end_qc_qty', type: dataType.currency },
+        { name: '截止本期-数量变更-金额', field: 'end_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_0', field: 'r0_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_0', field: 'r0_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_1', field: 'r1_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_1', field: 'r1_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_2', field: 'r2_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_2', field: 'r2_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_3', field: 'r3_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_3', field: 'r3_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_4', field: 'r4_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_4', field: 'r4_qc_tp', type: dataType.currency },
+    ],
+};
+const jh_gather_im_change = {
+    name: '【定制】季华-中间计量-变更-汇总 数据表(mem_jh_gather_im_change)',
+    remark: '',
+    id: 62,
+    key: 'mem_jh_gather_im_change',
+    prefix: '【定制】季华-中间计量-变更-汇总',
+    cols: [
+        { name: '清单编号', field: 'b_code', type: dataType.str },
+        { name: '名称', field: 'name', type: dataType.str },
+        { name: '单位', field: 'unit', type: dataType.str },
+        { name: '单价', field: 'unit_price', type: dataType.currency },
+
+        { name: '截止上期-数量变更-数量', field: 'pre_qc_qty', type: dataType.currency },
+        { name: '截止上期-数量变更-金额', field: 'pre_qc_tp', type: dataType.currency },
+        { name: '本期-数量变更-数量', field: 'qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额', field: 'qc_tp', type: dataType.currency },
+        { name: '截止本期-数量变更-数量', field: 'end_qc_qty', type: dataType.currency },
+        { name: '截止本期-数量变更-金额', field: 'end_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_0', field: 'r0_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_0', field: 'r0_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_1', field: 'r1_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_1', field: 'r1_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_2', field: 'r2_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_2', field: 'r2_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_3', field: 'r3_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_3', field: 'r3_qc_tp', type: dataType.currency },
+
+        { name: '本期-数量变更-数量_4', field: 'r4_qc_qty', type: dataType.currency },
+        { name: '本期-数量变更-金额_4', field: 'r4_qc_tp', type: dataType.currency },
+    ],
+};
 
 const recursiveMkdirSync = async function(pathName) {
     if (!fs.existsSync(pathName)) {
@@ -1687,9 +1783,10 @@ const defines = [
     gather_stage_bills, gather_tender_info, gather_stage_pay, gather_deal_bills,
     material, materialGl, material_bills, material_pos, material_gl_detail,
     stage_sum_bills, stage_sum_pay, stage_audit, sign_select,
-    stage_change_bills, stage_change_ledger,
+    stage_change, stage_change_bills, stage_change_ledger,
     gcl_gather_bills, gcl_gather_xmj,
     ledger_tag, stage_tag, all_tag,
+    jh_im_change, jh_gather_im_change,
 ];
 for (const d of defines) {
     exportTableDefine(d);

+ 4 - 1
sql/update.sql

@@ -14,4 +14,7 @@ COMMENT = '报表归档表;\n只考虑项目id及期id,其他信息全部归
 
 -- 项目设置-功能设置
 ALTER TABLE `zh_project`
-ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能设置(json.stringify)' AFTER `rpt_nature`;
+ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能设置(json.stringify)' AFTER `rpt_nature`;
+
+
+ALTER TABLE `zh_ledger_cooperation` ADD `company` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '单位或备注名,筛选用' AFTER `sign_path`;