MaiXinRong 2 лет назад
Родитель
Сommit
8b381dbd7a

+ 2 - 0
app/base/base_bills_service.js

@@ -611,6 +611,8 @@ class BaseBillsSerivce extends TreeService {
                     sjcl_expr: d.sjcl_expr,
                     qtcl_expr: d.qtcl_expr,
                     check_calc: 1,
+                    dgn_qty1: d.dgn_qty1,
+                    dgn_qty2: d.dgn_qty2,
                 };
                 for (const c of d.children) {
                     c.ledger_pid = newBills.ledger_id;

+ 47 - 0
app/const/spec_3f.js

@@ -0,0 +1,47 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const pushTiming = [
+    { value:'ledger.checked', name: '台账-审批通过' },
+    { value:'stage.checked', name: '期-审批通过' },
+    { value:'stage.flow', name: '期-上报/审批' },
+    { value:'revise.checked', name: '台账修订-审批通过' },
+    { value:'report.file', name: '报表-推送归档' },
+];
+
+const pushOperate = (function () {
+    const result = {};
+    for (const pt of pushTiming) {
+        const path = pt.value.split('.');
+        if (!result[path[0]]) result[path[0]] = {};
+        result[path[0]][path[1]] = pt.value;
+    }
+    return result;
+})();
+
+const specMsgStatus = (function () {
+    const status = { wait: 0, exec: 1, done: 2 };
+    const name = [];
+    name[status.wait] = '等待执行';
+    name[status.exec] = '等待中';
+    name[status.done] = '执行完成';
+    return { status, name };
+})();
+
+const pullClass = [
+    { value: 'gs-da', name: '甘肃档案' },
+];
+const pullType = [
+    { value: 'sync-ledger', name: '同步台账' },
+];
+
+module.exports = {
+    pushTiming, pushOperate, specMsgStatus, pullClass, pullType,
+};

+ 2 - 0
app/const/tender_info.js

@@ -31,6 +31,7 @@ const defaultInfo = {
             company: '',
             corporation: '',
             date: '',
+            management: '',
         },
         contract2: {
             company: '',
@@ -171,6 +172,7 @@ const defaultInfo = {
         same_code: true,
         sibling: true,
         over: true,
+        banMinusChangeBills: false,
     },
     fun_rela: {
         hintOver: true,

+ 4 - 2
app/controller/change_controller.js

@@ -772,9 +772,11 @@ module.exports = app => {
 
                 // 获取是否已存在调用变更令
                 let changeUsedData = await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, change.cid);
-                changeUsedData = ctx.helper._.filter(changeUsedData, function(item) {
+                changeUsedData = ctx.helper._.uniqWith(ctx.helper._.orderBy(ctx.helper._.filter(changeUsedData, function(item) {
                     return item.qty !== null;
-                })
+                }), ['sorder'], ['desc']), function(item1, item2) {
+                    return item1.cbid === item2.cbid;
+                });
                 renderData.changeUsedData = changeUsedData;
                 renderData.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.qty); }));
                 await this.layout('change/information.ejs', renderData, 'change/information_modal.ejs');

+ 24 - 0
app/controller/report_archive_controller.js

@@ -16,6 +16,7 @@ const signConst = require('../const/sign');
 const shenpiConst = require('../const/shenpi');
 const accountGroup = require('../const/account_group').group;
 const sendToWormhole = require('stream-wormhole');
+const pushOperate = require('../const/spec_3f').pushOperate;
 
 module.exports = app => {
     class ReportArchiveController extends app.BaseController {
@@ -116,6 +117,7 @@ module.exports = app => {
                 const groupList = accountList.filter(item => item.account_group === idx);
                 return { groupName: item, groupList };
             });
+            const needFileMsg = await this.ctx.service.specMsg.tenderNeedMsg(this.ctx.session.sessionProject.id, this.ctx.tender.id, pushOperate.report.file);
 
             //
             const renderData = {
@@ -144,6 +146,7 @@ module.exports = app => {
                 accountGroup: newAccountGroup,
                 accountList,
                 isAdmin,
+                needFileMsg,
             };
             if (stage_id === -1) {
                 await this.layout('report/index_archive.ejs', renderData, 'report/archive_popup.ejs');
@@ -787,6 +790,27 @@ module.exports = app => {
             }
             return response;
         }
+
+        async sendFileMsg(ctx) {
+            try {
+                if (this.ctx.session.sessionUser.accountId !== ctx.tender.data.user_id) throw '您无权操作';
+
+                const needFileMsg = await this.ctx.service.specMsg.tenderNeedMsg(this.ctx.session.sessionProject.id, this.ctx.tender.id, pushOperate.report.file);
+                if (!needFileMsg) throw '该标段暂不可进行该操作';
+
+                const waitingMsg = await this.ctx.service.specMsg.getDataByCondition({ tid: this.ctx.tender.id, timing: pushOperate.report.file, status: [0, 1] });
+                if (waitingMsg) throw '上一次归档完成,未执行完毕,请稍后再试';
+
+                const data = JSON.parse(ctx.request.body.data);
+                const stage = await this.ctx.service.stage.getDataById(data.sid);
+
+                await this.ctx.service.specMsg.addReportMsg(null, this.ctx.session.sessionProject.id, this.ctx.tender.data, stage, pushOperate.report.file);
+                ctx.body = { err: 0, msg: '提交成功,稍后将同步至档案系统', data: null };
+            } catch(err) {
+                this.ctx.log(err);
+                this.ctx.ajaxErrorBody(err, '操作失败');
+            }
+        }
     }
     return ReportArchiveController;
 };

+ 5 - 13
app/controller/stage_controller.js

@@ -186,7 +186,6 @@ module.exports = app => {
                     attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD');
                 }
                 renderData.attData = attData;
-                renderData.coopwd = ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) || ((ctx.stage.status === auditConst.status.checking || ctx.stage.status === auditConst.status.checkNoPre) && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId);
                 // 获取收方单列表
                 const sfData = await ctx.service.stageShoufang.getAllDataByCondition({ where: { sid: ctx.stage.id }, orders: [['id', 'desc']] });
                 for (const sf of sfData) {
@@ -197,7 +196,7 @@ module.exports = app => {
                 // 收方单附件删除权限
                 renderData.sfAttDelPower = ctx.session.sessionUser.accountId === ctx.stage.user_id || ctx.helper._.findIndex(ctx.stage.auditors2, { aid: ctx.session.sessionUser.accountId }) !== -1;
                 renderData.hintOver = projectFunInfo.hintOver && ctx.tender.info.fun_rela.hintOver;
-                renderData.hintMinusCb = projectFunInfo.banMinusChangeBills;
+                renderData.hintMinusCb = projectFunInfo.banMinusChangeBills && ctx.tender.info.ledger_check.banMinusChangeBills;
                 renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
             } catch (err) {
@@ -376,16 +375,9 @@ module.exports = app => {
                             responseData.data.tags = await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id);
                             break;
                         case 'cooperation':
-                            const uid = ctx.stage.curAuditor ?
-                                ctx.stage.curAuditor.aid :
-                                (ctx.stage.status === auditConst.status.uncheck ||
-                                (ctx.stage.status === auditConst.status.checkNo && ctx.stage.user_id === ctx.session.sessionUser.accountId) ?
-                                    ctx.stage.user_id : (ctx.stage.status === auditConst.status.checkNo && ctx.stage.user_id !== ctx.session.sessionUser.accountId) ?
-                                        ctx.session.sessionUser.accountId : null);
-                            responseData.data.cooperation = uid !== null ? await ctx.service.ledgerCooperation.getValidData(
-                                ctx.tender.id, uid) : [];
-                            const stageTimes = (ctx.stage.status === auditConst.status.checkNo && ctx.stage.user_id !== ctx.session.sessionUser.accountId) ? ctx.stage.times - 1 : ctx.stage.times;
-                            responseData.data.cooperationConfirm = uid !== null ? await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, stageTimes, uid) : [];
+                            responseData.data.cooperation = await ctx.service.ledgerCooperation.getValidData(ctx.tender.id, ctx.session.sessionUser.accountId);
+                            responseData.data.cooperationConfirm = await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.session.sessionUser.accountId);
+                            responseData.data.locked = await ctx.service.cooperationConfirm.getLockedId(ctx.tender, ctx.stage);
                             break;
                         case 'spec':
                             const spec = {zlj: JSON.parse(JSON.stringify(stdConst.zlj)), jrg: stdConst.jrg};
@@ -430,7 +422,7 @@ module.exports = app => {
                     { qty: 'contract_qty', tp: 'contract_tp' }, { qty: 'qc_qty', tp: 'qc_tp' },
                 ], this.ctx.tender.info.decimal, x => { return x.is_tp; });
                 checkData.checkBillsQty(['contract_qty', 'qc_qty']);
-                if (projRela.banMinusChangeBills) {
+                if (projRela.banMinusChangeBills && ctx.tender.info.ledger_check.banMinusChangeBills) {
                     const change = await this.ctx.service.change.getAllChangeHasMinus(ctx.tender.id);
                     if (change.length > 0) {
                         const cid = change.map(x => { return x.cid; });

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

@@ -200,7 +200,7 @@ $(document).ready(() => {
                     }
                     validText = ZhCalc.round(validText, findDecimal(select.unit)) || 0;
                     // 判断是否 正数必须大于等于限制值,负数必须小于等于限制值,否则无法更改
-                    const usedInfo = _.find(changeUsedData, { id: select.id });
+                    const usedInfo = _.find(changeUsedData, { cbid: select.id });
                     if (usedInfo && validText >= 0 && validText < usedInfo.qty) {
                         toastr.error('清单变更数值必须大于等于已调用值 ' + usedInfo.qty);
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);

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

@@ -1621,8 +1621,11 @@ function tableDataRemake(changeListData) {
                     listinfo = changeListData[clinfo.lid - 1];
                     if (listinfo === undefined) {
                         toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
-                        // changeList.splice(index, 1);
-                        removeList.push(clinfo);
+                        if (changeStatus !== auditConst.status.revise) {
+                            removeList.push(clinfo);
+                        } else {
+                            updateList.push(makeWhiteList(clinfo));
+                        }
                         continue;
                     }
                     $('#table-list-select tr[data-index="'+ clinfo.lid +'"]').addClass('table-success');
@@ -1646,8 +1649,11 @@ function tableDataRemake(changeListData) {
                                 (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);
-                            removeList.push(clinfo);
+                            if (changeStatus !== auditConst.status.revise) {
+                                removeList.push(clinfo);
+                            } else {
+                                updateList.push(makeWhiteList(clinfo));
+                            }
                             continue;
                         }
                     } else {
@@ -1683,9 +1689,13 @@ function tableDataRemake(changeListData) {
                                 (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 {
                             // console.log(clinfo, listinfo.leafXmjs);
-                            toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
                             // changeList.splice(index, 1);
-                            removeList.push(clinfo);
+                            toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
+                            if (changeStatus !== auditConst.status.revise) {
+                                removeList.push(clinfo);
+                            } else {
+                                updateList.push(makeWhiteList(clinfo));
+                            }
                             continue;
                         }
                     } else {
@@ -1733,7 +1743,7 @@ function tableDataRemake(changeListData) {
             }
         }
         if(updateList.length > 0) {
-            // console.log(updateList);
+            console.log(updateList);
             postData(window.location.pathname + '/save', { type:'update_list', updateData: updateList }, function (result) {
             }, function () {
             });
@@ -1747,6 +1757,18 @@ function tableDataRemake(changeListData) {
     }
 }
 
+function makeWhiteList(clinfo) {
+    clinfo.lid = 0;
+    clinfo.xmj_code = null;
+    clinfo.xmj_jldy = null;
+    clinfo.xmj_dwgc = null;
+    clinfo.xmj_fbgc = null;
+    clinfo.xmj_fxgc = null;
+    clinfo.gcl_id = '';
+    clinfo.mx_id = null;
+    return clinfo;
+}
+
 // 清单搜索隐藏清单table部分值
 function makeListTable(changeListData, showListData = changeListData) {
     // 先加载台账数据

+ 16 - 3
app/public/js/material.js

@@ -339,10 +339,23 @@ $(document).ready(() => {
             };
             const sheet = materialSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(sheet);
+            const selection = sheet.getSelections();
+            const sel = selection ? selection[0] : sheet.getSelections()[0];
+            const row = sel ? sel.row : -1;
+            const first = materialBillsData[row];
+            let last = first;
+            if (sel.rowCount > 1 && first) {
+                for (let r = 1; r < sel.rowCount; r++) {
+                    const rNode = materialBillsData[sel.row + r];
+                    if (!rNode) break;
+                    last = rNode;
+                }
+            }
+            const preNode = materialBillsData[row - 1];
             // 还需判断是否已被调差清单调用
             setObjEnable($('#del'), !readOnly && select && materialBase.isUsed(select) && rowCount === 1);
-            setObjEnable($('#up-move'), !readOnly && select && materialBillsData.indexOf(select) > 0 && !$('#bills0_list').is(':checked'));
-            setObjEnable($('#down-move'), !readOnly && select && materialBillsData.indexOf(select) < materialBillsData.length - 1 && !$('#bills0_list').is(':checked'));
+            setObjEnable($('#up-move'), !readOnly && first && preNode && materialBillsData.indexOf(last) > 0 && sel.row + sel.rowCount <= materialBillsData.length && !$('#bills0_list').is(':checked'));
+            setObjEnable($('#down-move'), !readOnly && first && materialBillsData.indexOf(last) < materialBillsData.length - 1 && sel.row + sel.rowCount <= materialBillsData.length && !$('#bills0_list').is(':checked'));
         },
         add: function () {
             const sheet = materialSpread.getActiveSheet();
@@ -537,7 +550,7 @@ $(document).ready(() => {
             materialSpreadObj.refreshActn(sel.rowCount);
             const data = SpreadJsObj.getSelectObject(info.sheet);
             materialSpreadObj.setReadOnly(true);
-            console.log(data);
+            // console.log(data);
         },
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {

+ 26 - 2
app/public/js/path_tree.js

@@ -1227,11 +1227,24 @@ const createNewPathTree = function (type, setting) {
             // stage关联索引
             this.stageItems = {};
         }
+
+        _loadLockedNodes(ids){
+            this.Locked = ids || [];
+            for (const f of this.Locked) {
+                const node = this.getItems(f.ledger_id);
+                node.locked = true;
+                const posterity = this.getPosterity(node);
+                for (const pn of posterity) {
+                    pn.locked = true;
+                    pn.lock = true;
+                }
+            }
+        }
         /**
          * 加载数据(初始化), 并给数据添加部分树结构必须数据
          * @param datas
          */
-        loadDatas(datas) {
+        loadDatas(datas, locked) {
             super.loadDatas(datas);
             // 清空旧数据
             this.stageItems = {};
@@ -1240,6 +1253,7 @@ const createNewPathTree = function (type, setting) {
                 const keyName = itemsPre + data[this.setting.stageId];
                 this.stageItems[keyName] = data;
             }
+            this._loadLockedNodes(locked)
         }
         // 解锁相关
         _loadPwdCache() {
@@ -1473,12 +1487,22 @@ const createNewPathTree = function (type, setting) {
             refresh.push(this.getNodeIndex(p.node));
             const posterity = this._getPwdPosterity(p.node);
             for (const pn of posterity) {
-                pn.lock = isLock;
+                pn.lock = pn.locked || isLock;
                 refresh.push(this.getNodeIndex(pn));
             }
             if (!this.loadingPwd) this._savePwdCache();
             return refresh;
         }
+
+        getLockedInfo(node) {
+            const ownerNodes = this.getAllParents(node);
+            const lockedInfo = [];
+            for (const on of ownerNodes) {
+                const filter = this.Locked.filter(x => { return x.ledger_id === on.ledger_id; });
+                lockedInfo.push(...filter);
+            }
+            return lockedInfo;
+        }
     }
 
     class MasterTree extends FxTree {

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

@@ -365,6 +365,10 @@ $(document).ready(() => {
         const html = [];
         const select = $('#cooperationSelect').val();
         const list = select !== '全部' ? _.filter(stageTree.pwd, { company: select }) : stageTree.pwd;
+        // 根据台账排序
+        list.sort(function (a, b) {
+            return _.findIndex(stageTree.nodes, { ledger_id: a.ledger_id }) - _.findIndex(stageTree.nodes, { ledger_id: b.ledger_id });
+        });
         for (const p of list) {
             if (!p.node) continue;
             if (p.confirm) {
@@ -373,17 +377,22 @@ $(document).ready(() => {
                 html.push(`<tr>`);
             }
             html.push(`<td>${p.node.code}</td>`, `<td>${p.node.name}</td>`);
-            if(coopwd) {
-                html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
+
+            let lockedHint = '';
+            const lockedInfo = stageTree.getLockedInfo(p.node);
+            if (lockedInfo.length > 0) {
+                const lockedUser = lockedInfo.map(x => { return  x.name; });
+                lockedHint = ` (审批人 ${lockedUser.join(',')} 确认通过)`;
             }
+            html.push('<td>', p.check ? `已解锁` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, lockedHint, '</td>');
             html.push('<td>', p.company, '</td>');
-            if (stage.status === auditConst.status.checking && !checkUsed(stageTree, stagePos, p.node)) {
+            if ((stage.status === auditConst.status.checking || stage.status === auditConst.status.checkNoPre) && !checkUsed(stageTree, stagePos, p.node)) {
                 html.push('<td>', '本期未计量', '</td>');
             } else if (p.check && p.confirm) {
-                html.push('<td>', moment(p.confirm_time).format('YYYY-MM-DD HH:mm') + ' ' + (coopwd ? `<a name="ledger-unconfirm" href="javascript: void(0);" lid="${p.ledger_id}">重新审批</a>` : ''), '</td>');
+                html.push('<td>', moment(p.confirm_time).format('YYYY-MM-DD HH:mm') + ' ' + `<a name="ledger-unconfirm" href="javascript: void(0);" lid="${p.ledger_id}">重新审批</a>`, '</td>');
             } else if (!p.check && p.confirm) {
                 html.push('<td>', moment(p.confirm_time).format('YYYY-MM-DD HH:mm'), '</td>');
-            } else if (p.check && !p.confirm && coopwd) {
+            } else if (p.check && !p.confirm && !readOnly) {
                 html.push('<td>', `<a name="ledger-confirm" href="javascript: void(0);" lid="${p.ledger_id}" class="btn btn-sm btn-success">确认</a>`, '</td>');
             } else {
                 html.push('<td>', '</td>');
@@ -1639,7 +1648,20 @@ $(document).ready(() => {
                     $('#shoufang-pos').text('').hide();
                     $('#addshoufang').modal('show');
                 }
-            }
+            },
+            lockedSpr: '----',
+            lockedHint: {
+                name: '检查审批状态',
+                visible: function (key, opt) {
+                    const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                    return node.locked;
+                },
+                callback: function (key, opt) {
+                    const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                    const lockedInfo = stageTree.getLockedInfo(node);
+                    toastr.warning(`审批人 ${lockedInfo.map(x => { return x.name; }).join(',')} 审批通过,如需修改,请联系审批人重新审批`);
+                }
+            },
         }
     });
 
@@ -2078,7 +2100,8 @@ $(document).ready(() => {
     // 加载计量单元数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
     postData(window.location.pathname + '/load', { filter: 'ledger;pos;detail;change;import_change;tag;cooperation' }, function (result) {
         // 加载树结构
-        stageTree.loadDatas(result.ledgerData);
+        console.log(result.locked);
+        stageTree.loadDatas(result.ledgerData, result.locked);
         // 加载部位明细
         stagePos.loadDatas(result.posData);
         checkShowLast(result.ledgerData.length);
@@ -4625,7 +4648,7 @@ $(document).ready(() => {
         const noUsed = stageTree.pwd.filter(x => {return !checkUsed(stageTree, stagePos, x.node) });
         const data = {
             opinion: $(`${'#sp-done'}`).find('[name=opinion]').val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '),
-            noUsed: noUsed.map(x => { return x.id; }),
+            coop_noUsed: noUsed && noUsed.length > 0 ? noUsed.map(x => { return x.id; }) : [],
             checkType,
         };
         $('#sp-done').modal('hide');
@@ -4635,11 +4658,13 @@ $(document).ready(() => {
     });
     $('#audit-check1').submit(function (e) {
         const checkType = parseInt($('[name=checkType]:checked').val());
+        const confirm = stageTree.pwd.filter(x => {return x.confirm });
         const data = {
             opinion: $(`${'#sp-back'}`).find('[name=opinion]').val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '),
+            coop_checked: confirm && confirm.length > 0 ? confirm.map(x => { return x.id; }) : [],
             checkType,
         };
-        if ($('#warning-text').length) $('#warning-text').remove()
+        if ($('#warning-text').length) $('#warning-text').remove();
         if (!checkType && !$('#warning-text').length) {
             $('#reject-process').prepend('<p id="warning-text" style="color: red; margin: 0;">请选择退回流程</p>');
             return false

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

@@ -310,10 +310,13 @@ const rptCustomObj = (function () {
         if (gsObj.setting.type === 'zone') $('#gather-by-zone').show();
         if (gsObj.setting.type === 'stage') $('#gather-by-stage').show();
         if (gsObj.setting.type === 'stage-zone') $('#gather-by-stage-zone').show();
+        if (gsObj.setting.type === 'checked-zone') $('#gather-by-checked-zone').show();
 
         if (gsSelect) {
             if (gsSelect.zone) {
                 $('#gather-zone').val(gsSelect.zone ? gsSelect.zone : '');
+            } else if (gsSelect.checked_zone) {
+                $('#gather-checked-zone').val(gsSelect.checked_zone ? gsSelect.checked_zone : '');
             } else if (gsSelect.month) {
                 $('#gather-month').val(gsSelect.month ? gsSelect.month: '');
             } else if (gsSelect.stage) {
@@ -613,6 +616,15 @@ const rptCustomObj = (function () {
                 return;
             }
             data[sGatherSelect].stage_zone = stageBegin + ':' + stageEnd;
+        } else if (gsObj.setting.type === 'checked-zone') {
+            data[sGatherSelect].checked_zone = $('#gather-checked-zone').val();
+            if (data[sGatherSelect].checked_zone === '') {
+                hintObj.html('请选择 汇总周期').show();
+                return;
+            } else if(data[sGatherSelect].checked_zone.indexOf(' - ') < 0) {
+                hintObj.html('请选择 完整汇总周期').show();
+                return;
+            }
         }
         hintObj.hide();
         if (resolve) {

+ 2 - 0
app/router.js

@@ -431,6 +431,8 @@ module.exports = app => {
     app.post('/tender/report_api/addArchiveEncryption', sessionAuth, 'reportArchiveController.addReportArchiveEncryption');
     app.post('/tender/report_api/updateArchiveEncryption', sessionAuth, 'reportArchiveController.updateReportArchiveEncryption');
     app.post('/tender/report_api/removeArchiveEncryption', sessionAuth, 'reportArchiveController.removeReportArchiveEncryption');
+    app.post('/tender/:id/sendReportFileMsg', sessionAuth, tenderCheck, uncheckTenderCheck, 'reportArchiveController.sendFileMsg');
+    app.get('/tender/:id/measure/stage/:order/sendReportFileMsg', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'reportArchiveController.sendFileMsg');
 
     // 电子签名
     app.get('/tender/:id/signReport', sessionAuth, tenderCheck, uncheckTenderCheck, 'reportArchiveController.signReport');

+ 72 - 0
app/service/cooperation_confirm.js

@@ -8,6 +8,8 @@
  * @version
  */
 
+const auditConst = require('../const/audit');
+
 module.exports = app => {
     class CooperationConfirm extends app.BaseService {
         /**
@@ -57,6 +59,76 @@ module.exports = app => {
         async delBycheckNoPre(uid, stage, transaction) {
             return await transaction.delete(this.tableName, { tid: stage.tid, sid: stage.id, times: stage.times, uid });
         }
+
+        async lockConfirm4CheckNoPre(stage, uid, pre_uid, transaction) {
+            if (!transaction) throw '缺少参数';
+
+            const locked = await this.getAllDataByCondition({ where: { sid: stage.id, locked: 1, times: stage.curTimes } });
+            // 审批人数据锁定
+            const locking = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, uid: uid } });
+            if (locking.length > 0) {
+                const updateLock = locking.map(x => { return { id: x.id, locked: 1 }; });
+                await transaction.updateRows(this.tableName, updateLock);
+            }
+            const preConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, uid: pre_uid } });
+            // 前审批人数据,与被锁定数据相关数据确认状态保留
+            locked.push(...locking);
+            if (preConfirm.length > 0) {
+                const delConfirm = [];
+                for (const pc of preConfirm) {
+                    const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: pc.ledger_id });
+                    const billsOwner = bills.full_path.split('-');
+                    const exist = locked.find(x => { return billsOwner.indexOf(x.ledger_id + '') >= 0; });
+                    if (!exist) delConfirm.push(pc.id);
+                }
+                if (delConfirm.length > 0) await transaction.delete(this.tableName, { id: delConfirm });
+            }
+        }
+
+        async lockComfirm4CheckNo(stage, uid, auditors, transaction) {
+            if (!transaction) throw '缺少参数';
+            // 审批人数据锁定
+            const lockConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, uid: uid } });
+            if (lockConfirm.length === 0) return;
+
+            const insertData = [];
+            lockConfirm.forEach(x => {
+                delete x.id;
+                x.locked = 1;
+                x.times = x.times + 1;
+                insertData.push(x);
+            });
+            // 审批人前所有角色,与锁定数据相关确认状态保留
+            const keepUid = [ stage.user_id ];
+            for (const a of auditors) {
+                if (a.aid === uid) break;
+                keepUid.push(a.aid);
+            }
+            const keepConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, uid: keepUid } });
+            for (const kc of keepConfirm) {
+                const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: kc.ledger_id });
+                const billsOwner = bills.full_path.split('-');
+                const exist = lockConfirm.find(x => { return billsOwner.indexOf(x.ledger_id + '') >= 0; });
+                if (exist) {
+                    delete kc.id;
+                    kc.locked = 0;
+                    kc.times = kc.times + 1;
+                    insertData.push(kc);
+                }
+            }
+            if (insertData.length > 0) await transaction.insert(this.tableName, insertData);
+        }
+
+        async cancelLock(stage, uid, transaction) {
+            await transaction.update(this.tableName, { locked: 0 }, { where: { sid: stage.id, times: stage.curTimes, uid } });
+        }
+
+        async getLockedId(tender, stage) {
+            const sql = `SELECT cc.ledger_id, cc.uid, pa.name FROM ${this.tableName} cc` +
+                    `  LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON cc.uid = pa.id` +
+                    '  WHERE cc.sid = ? AND cc.times = ? AND cc.locked = 1';
+            return await this.db.query(sql, [stage.id, stage.times]);
+        }
     }
 
     return CooperationConfirm;

+ 3 - 0
app/service/ledger_audit.js

@@ -15,6 +15,7 @@ const SmsAliConst = require('../const/sms_alitemplate');
 const wxConst = require('../const/wechat_template');
 const shenpiConst = require('../const/shenpi');
 const pushType = require('../const/audit').pushType;
+const pushOperate = require('../const/spec_3f').pushOperate;
 
 module.exports = app => {
     class LedgerAudit extends app.BaseService {
@@ -390,6 +391,8 @@ module.exports = app => {
                             begin_time: Date.parse(begin_audit.begin_time),
                         };
                         await this.ctx.helper.sendWechat(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), wxConst.template.ledger, wechatData);
+                        // 审批通过 - 检查三方特殊推送
+                        await this.ctx.service.specMsg.addLedgerMsg(transaction, pid, this.ctx.tender, pushOperate.ledger.checked);
                     }
                 } else {
                     // 同步标段信息

+ 90 - 0
app/service/report_memory.js

@@ -24,11 +24,14 @@ const stageImVersion = '1.3';
 const PermissionCheck = require('../const/account_permission').PermissionCheck;
 
 const Ledger = require('../lib/ledger');
+const moment = require('moment');
+const auditConst = require('../const/audit');
 
 const billsFields = (function () {
     const cur = ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'qc_minus_tp', 'gather_qty', 'gather_tp', 'postil'];
     const pre = ['pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_qc_minus_qty', 'pre_qc_minus_tp', 'pre_gather_qty', 'pre_gather_tp'];
     const end = ['end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp', 'end_qc_minus_qty', 'end_qc_minus_tp', 'end_gather_qty', 'end_gather_tp'];
+    const year = ['year_contract_qty', 'year_contract_tp', 'year_qc_qty', 'year_qc_tp', 'year_qc_minus_qty', 'year_qc_minus_tp', 'year_gather_qty', 'year_gather_tp'];
     const final = ['final_tp', 'final_ratio'];
     const final1 = [ 'final_1_qty', 'final_1_tp', 'final_1_ratio'];
     const stageDgn = ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'];
@@ -111,6 +114,7 @@ module.exports = app => {
                     'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp',
                     'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'final_1_tp',
                     'end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp',
+                    'year_contract_tp', 'year_qc_tp', 'year_contract_pc_tp', 'year_qc_pc_tp', 'year_pc_tp', 'year_gather_tp',
                 ],
                 calc: function (node, helper, decimal) {
                     if (node.children && node.children.length === 0) {
@@ -382,6 +386,88 @@ module.exports = app => {
             }
         }
 
+        async _getValidStages(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.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
+                    stages.splice(0, 1);
+                }
+            }
+            return stages;
+        }
+
+        async _getTimeZoneStages(tender, zone) {
+            const times = zone.split(' - ');
+            if (times.length !== 2) throw '选择的汇总周期无效';
+            const beginTime = moment(times[0], 'YYYY-MM');
+            const endTime = moment(times[1], 'YYYY-MM');
+
+            const stages = await this._getValidStages(tender.id), validStages = [];
+            for (const stage of stages) {
+                const sTime = moment(stage.s_time, 'YYYY-MM');
+                if (sTime.isBetween(beginTime, endTime, null, '[]')) {
+                    validStages.push(stage);
+                }
+            }
+            return validStages;
+        }
+
+        async _gatherStageBills(tender, stages) {
+            let billsIndexData = {};
+            const helper = this.ctx.helper;
+            const sumAssignRelaData = function (index, rela) {
+                const loadFields = function (datas, fields, prefix, relaId) {
+                    for (const d of datas) {
+                        if (!index[d[relaId]]) index[d[relaId]] = {};
+                        const m = index[d[relaId]];
+                        m[relaId] = d[relaId];
+                        if (m) {
+                            for (const f of fields) {
+                                if (d[f] !== undefined) {
+                                    m[prefix + f] = helper.add(m[prefix + f], d[f]);
+                                }
+                            }
+                        }
+                    }
+                };
+                for (const r of rela) {
+                    loadFields(r.data, r.fields, r.prefix, r.relaId);
+                }
+            };
+            for (const stage of stages) {
+                await this.ctx.service.stage.doCheckStage(stage);
+                const curStage = stage.readOnly
+                    ? await this.ctx.service.stageBills.getAuditorStageData2(tender.id, stage.id, stage.curTimes, stage.curOrder)
+                    : await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
+                const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: stage.id } });
+                sumAssignRelaData(billsIndexData, [
+                    { data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: '', relaId: 'lid' },
+                    { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
+                ]);
+            }
+            const result = [];
+            for (const prop in billsIndexData) {
+                const yearStageBills = billsIndexData[prop];
+                yearStageBills.gather_qty = helper.add(yearStageBills.contract_qty, yearStageBills.qc_qty);
+                yearStageBills.gather_tp = helper.sum([yearStageBills.contract_tp, yearStageBills.qc_tp, yearStageBills.pc_tp]);
+                result.push(yearStageBills);
+            }
+            return result;
+        };
+
+        async _loadStageBillsZone(tender, zone){
+            const stages = await this._getTimeZoneStages(tender, zone);
+            return await this._gatherStageBills(tender, stages);
+        }
+
+        async _loadStageBillsYear(tender, year) {
+            return await this._loadStageBillsZone(tender, `${year}-01 - ${year}-12`);
+        }
+
         async getStageBillsData(tid, sid, fields) {
             try {
                 await this.ctx.service.tender.checkTender(tid);
@@ -413,11 +499,15 @@ module.exports = app => {
                 }
                 const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
                 const endBpcStage = await this.ctx.service.stageBillsPc.getEndStageData(this.ctx.stage);
+                const yearStage = this._checkFieldsExistReg(fields, 'year_') && this.ctx.stage.s_time
+                    ? await this._loadStageBillsYear(this.ctx.tender, this.ctx.stage.s_time.split('-')[0])
+                    : [];
                 this.ctx.helper.assignRelaData(billsData, [
                     { data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid' },
                     { data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
                     { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
                     { data: endBpcStage, fields: ['end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp', 'org_price_his'], prefix: '', relaId: 'lid' },
+                    { data: yearStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_qty', 'gather_tp'], prefix: 'year_', relaId: 'lid' },
                 ]);
                 billsData.forEach(x => {
                     if (x.org_price_his && x.org_price_his.length > 0) {

+ 3 - 0
app/service/revise_audit.js

@@ -15,6 +15,7 @@ const wxConst = require('../const/wechat_template');
 const shenpiConst = require('../const/shenpi');
 const pushType = require('../const/audit').pushType;
 const RevisePrice = require('../lib/revise_price');
+const pushOperate = require('../const/spec_3f').pushOperate;
 
 module.exports = app => {
     class ReviseAudit extends app.BaseService {
@@ -493,6 +494,8 @@ module.exports = app => {
                             code: this.ctx.session.sessionProject.code,
                         };
                         await this.ctx.helper.sendWechat(users, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), wxConst.template.revise, wechatData2);
+                        // 审批通过 - 检查三方特殊推送
+                        await this.ctx.service.specMsg.addReviseMsg(transaction, pid, revise, pushOperate.ledger.checked);
                     }
                 } else {
                     // 同步修订信息

+ 161 - 57
app/service/rpt_gather_memory.js

@@ -238,10 +238,10 @@ module.exports = app => {
             this.resultDealBills = [];
         }
 
-        async _getValidStages(tenderId) {
+        async _getValidStages(tenderId, sort = 'desc') {
             const stages = await this.db.select(this.ctx.service.stage.tableName, {
                 where: { tid: tenderId },
-                orders: [['order', 'desc']],
+                orders: [['order', sort]],
             });
             if (stages.length !== 0) {
                 const lastStage = stages[0];
@@ -281,34 +281,70 @@ module.exports = app => {
             const beginTime = moment(times[0], 'YYYY-MM');
             const endTime = moment(times[1], 'YYYY-MM');
 
-            const stages = await this._getValidStages(tender.id), validStages = [];
+            const stages = await this._getValidStages(tender.id, 'asc'), validStages = [];
+            let preStage, endStage;
             for (const stage of stages) {
                 const sTime = moment(stage.s_time, 'YYYY-MM');
                 if (sTime.isBetween(beginTime, endTime, null, '[]')) {
                     validStages.push(stage);
+                } else if (sTime.isBefore(beginTime)) {
+                    if (!preStage || moment(preStage.s_time, 'YYYY-MM').isBefore(sTime)) preStage = stage;
+                } else if (sTime.isAfter(endTime)) {
+                    if (!endStage || moment(endStage.s_time, 'YYYY-MM').isAfter(sTime)) endStage = stage;
                 }
             }
-            return validStages;
+            return [validStages, preStage, endStage];
         }
-
         async _getOrderZoneStages (tender, zone) {
             let [iBegin, iEnd] = zone.split(':');
             iBegin = this.ctx.helper._.toInteger(iBegin) || 0;
             iEnd = this.ctx.helper._.toInteger(iEnd) || 0;
-            const stages = await this._getValidStages(tender.id), validStages = [];
+            const stages = await this._getValidStages(tender.id, 'asc'), validStages = [];
+            let preStage, endStage;
             for (const stage of stages) {
-                if (stage.order < iBegin || stage.order > iEnd) continue;
+                if (stage.order < iBegin) {
+                    if (!preStage || preStage.order < stage.order) preStage = stage;
+                } else if (stage.order > iEnd) {
+                    if (!endStage || endStage.order > stage.order) endStage = stage;
+                } else {
+                    validStages.push(stage);
+                }
+            }
+            return [validStages, preStage, endStage];
+        }
+        async _getCheckedZoneStages(tender, zone) {
+            const times = zone.split(' - ');
+            if (times.length !== 2) throw '选择的汇总周期无效';
+            const beginTime = moment(times[0], 'YYYY-MM-DD');
+            const endTime = moment(times[1], 'YYYY-MM-DD');
+
+            const stages = await this._getValidStages(tender.id, 'asc'), validStages = [];
+            let preStage, endStage;
+            for (const stage of stages) {
+                if (stage.status !== auditConst.stage.status.checked) continue;
+
+                const finalAudit = await this.ctx.service.stageAudit.getLastestAuditor(stage.id, stage.times, stage.status);
+                if (!finalAudit) continue;
 
-                validStages.push(stage);
+                const sTime = moment(moment(finalAudit.end_time).format('YYYY-MM-DD'), 'YYYY-MM-DD');
+                stage.checked_day = sTime;
+                stage.checked_time = moment(finalAudit.end_time);
+                if (sTime.isBetween(beginTime, endTime, null, '[]')) {
+                    validStages.push(stage);
+                } else if (sTime.isBefore(beginTime)) {
+                    if (!preStage || preStage.checked_time.isBefore(stage.checked_time)) preStage = stage;
+                } else if (sTime.isAfter(endTime)) {
+                    if (!endStage || endStage.checked_time.isAfter(stage.checked_time)) endStage = stage;
+                }
             }
-            return validStages;
+            return [validStages, preStage, endStage];
         }
 
         /**
          * 台账数据
          */
 
-        async _gatherStagesData(completeData, tender, stages) {
+        async _gatherStagesData(completeData, tender, stages, preStage) {
             const resultPos = this.resultPos;
             const helper = this.ctx.helper;
             completeData.id = tender.id;
@@ -344,12 +380,20 @@ module.exports = app => {
                 rootId: -1,
                 keys: ['id', 'tender_id', 'ledger_id'],
                 stageId: 'id',
-                calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp'],
+                calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
                 calc: function (node) {
                     if (node.children && node.children.length === 0) {
+                        node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
                         node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
+                        node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
+                        node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
+                        node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
                     }
+                    node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
                     node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
+                    node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
+                    node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                    node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
                 }
             });
             const billsData = await this.ctx.service.ledger.getData(tender.id);
@@ -361,7 +405,11 @@ module.exports = app => {
             const pos = new Ledger.pos({
                 id: 'id', ledgerId: 'lid',
                 calc: function (node) {
-                    node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
+                    node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
+                    node.gather_tp = helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
+                    node.end_contract_tp = helper.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
+                    node.end_qc_tp = helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
+                    node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
                 },
             });
             const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: tender.id} });
@@ -374,6 +422,18 @@ module.exports = app => {
                 posIndexData[indexPre + p.id] = p;
             }
 
+            if (preStage) {
+                await this.ctx.service.stage.doCheckStage(preStage);
+                const endStage = await this.ctx.service.stageBillsFinal.getFinalData(tender, preStage.order);
+                sumAssignRelaData(billsIndexData, [
+                    { data: endStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' },
+                ]);
+                const endStagePos = await this.ctx.service.stagePosFinal.getFinalData(tender, preStage.order);
+                sumAssignRelaData(posIndexData, [
+                    {data: endStagePos, fields: ['contract_qty', 'qc_qty'], prefix: 'pre_', relaId: 'lid'},
+                ]);
+            }
+
             for (const stage of stages) {
                 await this.ctx.service.stage.doCheckStage(stage);
                 const curStage = stage.readOnly
@@ -397,18 +457,26 @@ module.exports = app => {
             pos.loadDatas(posData);
             pos.calculateAll();
             this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
-                gatherUtils.gatherZone(tender, gatherNode, sourceNode, completeData.prefix, helper);
+                gatherUtils.gatherStage(tender, gatherNode, sourceNode, completeData.prefix, helper);
             }, function (gatherNode, sourceNode) {
                 const posRange = pos.getLedgerPos(sourceNode.id);
                 if (!posRange || posRange.length === 0) return;
                 resultPos.loadGatherPos(gatherNode.id, posRange, (gatherPos, sourcePos) => {
-                    gatherUtils.gatherZonePos(tender, gatherPos, sourcePos, completeData.prefix, helper);
+                    gatherUtils.gatherStagePos(tender, gatherPos, sourcePos, completeData.prefix, helper);
                 });
             });
         }
         async _gatherZoneData(tender, completeData, zone) {
-            const stages = await this._getTimeZoneStages(tender, zone);
-            await this._gatherStagesData(completeData, tender, stages);
+            const [stages, preStage, endStage] = await this._getTimeZoneStages(tender, zone);
+            await this._gatherStagesData(completeData, tender, stages, preStage);
+        }
+        async _gatherIndexZoneData(tender, completeData, stageZone) {
+            const [stages, preStage, endStage] = await this._getOrderZoneStages(tender, stageZone);
+            await this._gatherStagesData(completeData, tender, stages, preStage);
+        }
+        async _gatherCheckedZoneData(tender, completeData, zone) {
+            const [stages, preStage, endStage] = await this._getCheckedZoneStages(tender, zone);
+            await this._gatherStagesData(completeData, tender, stages, preStage);
         }
 
         async _gatherStageData(completeData, tender, stage, hasPre) {
@@ -505,10 +573,6 @@ module.exports = app => {
             const stage = this.ctx.helper._.find(stages, {order: index});
             await this._gatherStageData(completeData, tender, stage, hasPre);
         }
-        async _gatherIndexZoneData(tender, completeData, stageZone) {
-            const stages = await this._getOrderZoneStages(tender, stageZone);
-            await this._gatherStagesData(completeData, tender, stages);
-        }
         async _gatherFinalData(tender, completeData, hasPre) {
             const stages = await this._getValidStages(tender.id);
             await this._gatherStageData(completeData, tender, stages[0], hasPre);
@@ -618,6 +682,9 @@ module.exports = app => {
                         case 'stage-zone':
                             await this._gatherIndexZoneData(tender, completeData, gsCustom.stage_zone);
                             break;
+                        case 'checked-zone':
+                            await this._gatherCheckedZoneData(tender, completeData, gsCustom.checked_zone);
+                            break;
                     }
                     commonIndex++;
                 } else {
@@ -694,19 +761,49 @@ module.exports = app => {
                 info.end_sf_tp = helper.add(stage.sf_tp, stage.pre_sf_tp);
             }
         }
-
-        async _getStagesTenderInfo(stages, info) {
+        async _getStagesTenderInfo(stages, info, preStage) {
             const helper = this.ctx.helper;
+            if (preStage) {
+                info.pre_contract_tp = helper.add(preStage.contract_tp, preStage.pre_contract_tp);
+                info.pre_qc_tp = helper.add(preStage.qc_tp, preStage.pre_qc_tp);
+                info.pre_gather_tp = helper.add(info.pre_contract_tp, info.pre_qc_tp);
+                info.pre_yf_tp = helper.add(preStage.yf_tp, preStage.pre_yf_tp);
+            }
+
             for (const stage of stages) {
                 await this.ctx.service.stage.doCheckStage(stage);
                 await this.ctx.service.stage.checkStageGatherData(stage, this.ctx.session.sessionUser.is_admin);
 
+
                 info.contract_tp = helper.add(info.contract_tp, stage.contract_tp);
                 info.qc_tp = helper.add(info.qc_tp, stage.qc_tp);
 
                 info.yf_tp = helper.add(info.yf_tp, stage.yf_tp);
             }
             info.gather_tp = helper.add(info.contract_tp, info.qc_tp);
+            info.end_contract_tp = helper.add(info.pre_contract_tp, info.contract_tp);
+            info.end_qc_tp = helper.add(info.pre_qc_tp, info.qc_tp);
+            info.end_gather_tp = helper.add(info.pre_gather_tp, info.gather_tp);
+            info.end_yf_tp = helper.add(info.pre_yf_tp, info.yf_tp);
+        }
+
+        async _gatherZoneTenderInfo(tender, index, zone) {
+            const info = await this._getBaseTenderInfo(tender);
+            const [stages, preStage, endStage] = await this._getTimeZoneStages(tender, zone);
+            await this._getStagesTenderInfo(stages, info, preStage);
+            this.resultTenderInfo.push(info);
+        }
+        async _gatherOrderZoneTenderInfo(tender, index, stageZone) {
+            const info = await this._getBaseTenderInfo(tender);
+            const [stages, preStage, endStage] = await this._getOrderZoneStages(tender, stageZone);
+            await this._getStagesTenderInfo(stages, info, preStage);
+            this.resultTenderInfo.push(info);
+        }
+        async _gatherCheckedZoneTenderInfo(tender, index, zone) {
+            const info = await this._getBaseTenderInfo(tender);
+            const [stages, preStage, endStage] = await this._getCheckedZoneStages(tender, zone);
+            await this._getStagesTenderInfo(stages, info, preStage);
+            this.resultTenderInfo.push(info);
         }
 
         async _gatherMonthTenderInfo(tender, index, month, hasPre) {
@@ -716,7 +813,6 @@ module.exports = app => {
             await this._getStageTenderInfo(stage, info);
             this.resultTenderInfo.push(info);
         }
-
         async _gatherOrderTenderInfo(tender, index, order, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getValidStages(tender.id);
@@ -724,28 +820,12 @@ module.exports = app => {
             await this._getStageTenderInfo(stage, info);
             this.resultTenderInfo.push(info);
         }
-
-        async _gatherZoneTenderInfo(tender, index, zone) {
-            const info = await this._getBaseTenderInfo(tender);
-            const stages = await this._getTimeZoneStages(tender, zone);
-            await this._getStagesTenderInfo(stages, info);
-            this.resultTenderInfo.push(info);
-        }
-
-        async _gatherOrderZoneTenderInfo(tender, index, stageZone) {
-            const info = await this._getBaseTenderInfo(tender);
-            const stages = await this._getOrderZoneStages(tender, stageZone);
-            await this._getStagesTenderInfo(stages, info);
-            this.resultTenderInfo.push(info);
-        }
-
         async _gatherFinalTenderInfo(tender, index, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getValidStages(tender.id);
             await this._getStageTenderInfo(stages[0], info);
             this.resultTenderInfo.push(info);
         }
-
         async _gatherCheckedFinalTenderInfo(tender, index, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getCheckedStages(tender.id);
@@ -757,7 +837,6 @@ module.exports = app => {
             const info = await this._getBaseTenderInfo(tender);
             this.resultTenderInfo.push(info);
         }
-
         async _gatherSpecialTenderInfo(tender, sKey) {
             const info = await this._getBaseTenderInfo(tender);
             info.spec = sKey;
@@ -797,6 +876,9 @@ module.exports = app => {
                         case 'stage-zone':
                             await this._gatherOrderZoneTenderInfo(tender, commonIndex, gsCustom.stage_zone);
                             break;
+                        case 'checked-zone':
+                            await this._gatherCheckedZoneTenderInfo(tender, commonIndex, gsCustom.checked_zone);
+                            break;
                     }
                     commonIndex++;
                 } else {
@@ -866,12 +948,27 @@ module.exports = app => {
                 }
             }
         }
-
-        async _gatherStagesPay(completeData, tender, stages) {
+        async _gatherStagesPay(completeData, tender, stages, preStage) {
             const helper = this.ctx.helper;
             completeData.id = tender.id;
             completeData.name = tender.name;
 
+            if (preStage) await this.ctx.service.stage.doCheckStage(preStage);
+            const preDealPay = preStage ? await this.ctx.service.stagePay.getStagePays(preStage) : [];
+            for (const dp of preDealPay) {
+                dp.end_tp = helper.add(dp.pre_tp, dp.tp);
+                this._gatherPayRecord(dp, function (gatherData, sourceData) {
+                    gatherData[completeData.prefix + 'id'] = tender.id;
+                    gatherData[completeData.prefix + 'name'] = tender.name;
+
+                    gatherData[completeData.prefix + 'pre_tp'] = sourceData.end_tp;
+                    gatherData.s_pre_tp = helper.add(gatherData.s_pre_tp, sourceData.end_tp);
+
+                    gatherData[completeData.prefix + 'end_tp'] = sourceData.end_tp;
+                    gatherData.s_end_tp = helper.add(gatherData.s_end_tp, sourceData.end_tp);
+                });
+            }
+
             for (const stage of stages) {
                 await this.ctx.service.stage.doCheckStage(stage);
 
@@ -885,43 +982,47 @@ module.exports = app => {
 
                         gatherData[completeData.prefix + 'tp'] = helper.add(gatherData[completeData.prefix + 'tp'], sourceData.tp);
                         gatherData['s_' + 'tp'] = helper.add(gatherData['s_' + 'tp'], sourceData.tp);
+
+                        gatherData[completeData.prefix + 'end_tp'] = helper.add(gatherData[completeData.prefix + 'end_tp'], sourceData.tp);
+                        gatherData['s_' + 'end_tp'] = helper.add(gatherData['s_' + 'end_tp'], sourceData.tp);
                     });
                 }
             }
         }
 
+        async _gatherZoneStagePay(sTender, completeData, zone) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const [stages, preStage, endStage] = await this._getTimeZoneStages(tender, zone);
+            await this._gatherStagesPay(completeData, tender, stages, preStage);
+        }
+        async _gatherOrderZoneStagePay(sTender, completeData, stageZone) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const [stages, preStage, endStage] = await this._getOrderZoneStages(tender, stageZone);
+            await this._gatherStagesPay(completeData, tender, stages, preStage);
+        }
+        async _gatherCheckedZoneStagePay(sTender, completeData, zone) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const [stages, preStage, endStage] = await this._getCheckedZoneStages(tender, zone);
+            await this._gatherStagesPay(completeData, tender, stages, preStage);
+        }
+
         async _gatherMonthStagePay(sTender, completeData, month, hasPre) {
             const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {s_time: month});
             await this._gatherStagePay(completeData, tender, stage, hasPre);
         }
-
         async _gatherOrderStagePay(sTender, completeData, order, hasPre) {
             const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {order: order});
             await this._gatherStagePay(completeData, tender, stage, hasPre);
         }
-
-        async _gatherZoneStagePay(sTender, completeData, zone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
-            const stages = await this._getTimeZoneStages(tender, zone);
-            await this._gatherStagesPay(completeData, tender, stages);
-        }
-
-        async _gatherOrderZoneStagePay(sTender, completeData, stageZone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
-            const stages = await this._getOrderZoneStages(tender, stageZone)
-            await this._gatherStagesPay(completeData, tender, stages);
-        }
-
         async _gatherFinalStagePay(sTender, completeData, hasPre) {
             const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const stages = await this._getValidStages(tender.id);
             await this._gatherStagePay(completeData, tender, stages[0], hasPre);
         }
-
         async _gatherCheckedFinalStagePay(sTender, completeData, hasPre) {
             const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const stages = await this._getCheckedStages(tender.id);
@@ -962,6 +1063,9 @@ module.exports = app => {
                         case 'stage-zone':
                             await this._gatherOrderZoneStagePay(tender, completeData, gsCustom.stage_zone);
                             break;
+                        case 'checked-zone':
+                            await this._gatherCheckedZoneStagePay(tender, completeData, gsCustom.checked_zone);
+                            break;
                     }
                     commonIndex++;
                 }

+ 74 - 0
app/service/spec_msg.js

@@ -0,0 +1,74 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class SpecPull extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 's2b_spec_msg';
+        }
+
+        async tenderNeedMsg(pid, tid, timing) {
+            const specProj = await this.db.get('zh_s2b_spec_proj', { id: pid });
+            if (!specProj || !specProj.is_push) return false;
+
+            switch (specProj.push_tender_type) {
+                case 1:
+                    const filter = specProj.filter_tender ? specProj.filter_tender.split(',') : [];
+                    if (filter.indexOf(tid + '') >= 0) return false;
+                    break;
+                case 2:
+                    const access = specProj.access_tender ? specProj.access_tender.split(',') : [];
+                    if (access.indexOf(tid + '') < 0) return false;
+                    break;
+            }
+
+            const soleTender = await this.db.get('zh_s2b_spec_tender', { id: tid, is_valid: 1 });
+            const specPush = await this.db.get('zh_s2b_spec_push', { pid, tid: soleTender ? tid : 0, valid: 1, push_timing: timing });
+            return !!specPush;
+        }
+
+        async addLedgerMsg(transaction, pid, tender, timing) {
+            const needMsg = await this.tenderNeedMsg(pid, tender.id, timing);
+            if (!needMsg) return;
+            await transaction.insert(this.tableName, { pid, tid: tender.id, timing });
+        }
+
+        async addReviseMsg(transaction, pid, revise, timing) {
+            const needMsg = await this.tenderNeedMsg(pid, revise.tid, timing);
+            if (!needMsg) return;
+            await transaction.insert(this.tableName, { pid, tid: revise.tid, rid: revise.id, timing });
+        }
+
+        async addStageMsg(transaction, pid, stage, timing) {
+            const needMsg = await this.tenderNeedMsg(pid, stage.tid, timing);
+            if (!needMsg) return;
+            await transaction.insert(this.tableName, { pid, tid: stage.tid, sid: stage.id, timing });
+        }
+
+        async addReportMsg(transaction, pid, tender, stage, timing) {
+            const needMsg = await this.tenderNeedMsg(pid, stage.tid, timing);
+            if (!needMsg) return;
+            if (transaction) {
+                await transaction.insert(this.tableName, { pid, tid: tender.id, sid: stage ? stage.id : 0, timing });
+            } else {
+                await this.db.insert(this.tableName, { pid, tid: tender.id, sid: stage ? stage.id : 0, timing });
+            }
+        }
+    }
+
+    return SpecPull;
+};

+ 1 - 0
app/service/stage.js

@@ -656,6 +656,7 @@ module.exports = app => {
                     }
                 }
                 await transaction.delete(this.ctx.service.stageShoufang.tableName, { sid: id });
+                await transaction.delete(this.ctx.service.cooperationConfirm.tableName, { sid: id });
                 // 记录删除日志
                 await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.stage, projectLogConst.status.delete, '第' + stageInfo.order + '期');
                 await transaction.commit();

+ 22 - 3
app/service/stage_audit.js

@@ -19,6 +19,7 @@ const pushType = require('../const/audit').pushType;
 const syncApiConst = require('../const/sync_api');
 const measureType = require('../const/tender').measureType;
 const RevisePrice = require('../lib/revise_price');
+const pushOperate = require('../const/spec_3f').pushOperate;
 
 module.exports = app => {
     class StageAudit extends app.BaseService {
@@ -314,6 +315,8 @@ module.exports = app => {
                     tp_history: JSON.stringify(this.ctx.stage.tp_history),
                     cache_time_r: this.ctx.stage.cache_time_l,
                 });
+                // 多人协同,取消下一审批人存在的锁定
+                await this.ctx.service.cooperationConfirm.cancelLock(this.ctx.stage, audit.aid, transaction);
 
                 // 添加短信通知-需要审批提醒功能
                 // const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
@@ -348,6 +351,8 @@ module.exports = app => {
                 };
                 await this.ctx.helper.sendWechat(audit.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), wxConst.template.stage, wechatData);
 
+                // 上报/审批 - 检查三方特殊推送
+                await this.ctx.service.specMsg.addStageMsg(transaction, this.ctx.session.sessionProject.id, this.ctx.stage, pushOperate.stage.flow);
                 // todo 更新标段tender状态 ?
                 await transaction.commit();
                 // 通知发送 - 第三方更新
@@ -444,6 +449,8 @@ module.exports = app => {
                         tp_history: JSON.stringify(this.ctx.stage.tp_history),
                         cache_time_r: this.ctx.stage.cache_time_l,
                     });
+                    // 多人协同,取消下一审批人存在的锁定
+                    await this.ctx.service.cooperationConfirm.cancelLock(this.ctx.stage, nextAudit.aid, transaction);
 
                     // 添加短信通知-需要审批提醒功能
                     // const smsUser = await this.ctx.service.projectAccount.getDataById(nextAudit.aid);
@@ -546,7 +553,11 @@ module.exports = app => {
                         code: this.ctx.session.sessionProject.code,
                     };
                     await this.ctx.helper.sendWechat(users, smsTypeConst.const.JL, smsTypeConst.judge.result.toString(), wxConst.template.stage, wechatData);
+                    // 审批通过 - 检查三方特殊推送
+                    await this.ctx.service.specMsg.addStageMsg(transaction, pid, this.ctx.stage, pushOperate.stage.checked);
                 }
+                // 上报/审批 - 检查三方特殊推送
+                await this.ctx.service.specMsg.addStageMsg(transaction, pid, this.ctx.stage, pushOperate.stage.flow);
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -642,6 +653,9 @@ module.exports = app => {
                 await this.ctx.service.stageSafeProd.updateHistory(this.ctx.stage, transaction);
                 await this.ctx.service.stageTempLand.updateHistory(this.ctx.stage, transaction);
 
+                // 锁定本人数据,保留锁定数据相关确认状态
+                await this.ctx.service.cooperationConfirm.lockComfirm4CheckNo(this.ctx.stage, audit.aid, auditors, transaction);
+
                 // 添加短信通知-审批退回提醒功能
                 // const mobile_array = [];
                 const stageInfo = await this.ctx.service.stage.getDataById(stageId);
@@ -686,6 +700,8 @@ module.exports = app => {
                     code: this.ctx.session.sessionProject.code,
                 };
                 await this.ctx.helper.sendWechat(users, smsTypeConst.const.JL, smsTypeConst.judge.result.toString(), wxConst.template.stage, wechatData);
+                // 上报/审批 - 检查三方特殊推送
+                await this.ctx.service.specMsg.addStageMsg(transaction, pid, this.ctx.stage, pushOperate.stage.flow);
 
                 await transaction.commit();
             } catch (err) {
@@ -804,9 +820,8 @@ module.exports = app => {
                 await this.ctx.service.stageSafeProd.updateHistory(this.ctx.stage, transaction);
                 await this.ctx.service.stageTempLand.updateHistory(this.ctx.stage, transaction);
 
-                // 多人协同数据确认删除本人和上一个审批人确认状态
-                await this.ctx.service.cooperationConfirm.delBycheckNoPre(audit.aid, this.ctx.stage, transaction);
-                await this.ctx.service.cooperationConfirm.delBycheckNoPre(preAuditor.aid, this.ctx.stage, transaction);
+                // 锁定本人数据,保留锁定数据相关确认状态
+                await this.ctx.service.cooperationConfirm.lockConfirm4CheckNoPre(this.ctx.stage, audit.aid, preAuditor.aid, transaction);
 
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -847,6 +862,8 @@ module.exports = app => {
                 };
                 await this.ctx.helper.sendWechat(preAuditor.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), wxConst.template.stage, wechatData);
 
+                // 上报/审批 - 检查三方特殊推送
+                await this.ctx.service.specMsg.addStageMsg(transaction, pid, this.ctx.stage, pushOperate.stage.flow);
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -1008,6 +1025,8 @@ module.exports = app => {
                 };
                 await this.ctx.helper.sendWechat(audit.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), wxConst.template.stage, wechatData);
 
+                // 上报/审批 - 检查三方特殊推送
+                await this.ctx.service.specMsg.addStageMsg(transaction, this.ctx.session.sessionProject.id, this.ctx.stage, pushOperate.stage.flow);
                 await transaction.commit();
                 // 通知发送 - 第三方更新
                 if (this.ctx.session.sessionProject.custom && syncApiConst.notice_type.indexOf(this.ctx.session.sessionProject.customType) !== -1) {

+ 1 - 1
app/view/change/information.ejs

@@ -516,5 +516,5 @@
     const changeLedgerList = JSON.parse(unescape('<%- escape(JSON.stringify(changeLedgerList)) %>'));
     const changePosList = JSON.parse(unescape('<%- escape(JSON.stringify(changePosList)) %>'));
 </script>
-<script src="/public/js/change_information_approval.js?202206211"></script>
+<script src="/public/js/change_information_approval.js?202211041"></script>
 <% } %>

+ 12 - 0
app/view/report/index_archive.ejs

@@ -18,6 +18,11 @@
                         <div class="dropdown-menu" aria-labelledby="dropdownMenuButton" id="optionSelectableStages"></div>
                     </div>
                 </div>
+                <% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && needFileMsg) { %>
+                <div class="d-inline-block">
+                    <button class="btn btn-sm btn-primary" type="button" onclick="sendReportFileMsg();">同步档案系统</button>
+                </div>
+                <% } %>
             </div>
             <div>
             </div>
@@ -314,6 +319,13 @@
         );
     }
 
+
+    function sendReportFileMsg() {
+        postData('sendReportFileMsg', { sid: current_stage_id, sorder: current_stage_order }, function (result, msg) {
+            toastr.success(msg);
+        });
+    }
+
     $(function () {
         //阻止事件冒泡
         //不仅仅要stopPropagation,还要preventDefault

+ 8 - 0
app/view/report/rpt_all_popup.ejs

@@ -377,6 +377,14 @@
                                 <input id="gather-zone" class="datepicker-here form-control mt-0" placeholder="点击选择周期" data-range="true" data-multiple-dates-separator=" - "  data-min-view="months" data-view="months" data-date-format="yyyy-MM" data-language="zh" type="text" autocomplete="off">
                             </div>
                         </div>
+                        <div id="gather-by-checked-zone" name="gather-type">
+                            <div class="input-group input-group-sm">
+                                <div class="input-group-prepend">
+                                    <span class="input-group-text">汇总周期</span>
+                                </div>
+                                <input id="gather-checked-zone" class="datepicker-here form-control mt-0" placeholder="点击选择周期" data-range="true" data-multiple-dates-separator=" - "  data-min-view="days" data-view="days" data-date-format="yyyy-MM-dd" data-language="zh" type="text" autocomplete="off">
+                            </div>
+                        </div>
                         <div id="gather-by-stage" name="gather-type">
                             <div class="input-group input-group-sm">
                                 <div class="input-group-prepend">

+ 1 - 1
app/view/revise/sub_mini_menu.ejs

@@ -6,7 +6,7 @@
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <% include ./sub_menu_list.ejs %>
-        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
+        <!--<div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>-->
     </div>
 </div>
 <script>

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

@@ -533,7 +533,6 @@
     // const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     const curAuditor = JSON.parse('<%- JSON.stringify(curAuditor) %>');
     const thirdParty = JSON.parse('<%- JSON.stringify(thirdParty) %>');
-    const coopwd = <%- coopwd %>;
     const sfAttDelPower = <%- sfAttDelPower %>;
     let sfData = JSON.parse(unescape('<%- escape(JSON.stringify(sfData)) %>'));
     const hintOver = <%- hintOver %>;

+ 2 - 2
app/view/stage/modal.ejs

@@ -477,7 +477,7 @@
                 <h5 class="modal-title">多人协同</h5>
             </div>
             <div class="modal-body">
-                <% if (coopwd) { %>
+                <% if (!stage.readOnly) { %>
                     <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
                 <% } else { %>
                     <div class="alert alert-warning">以下项目节及其子项(灰色项)未确认审批。</div>
@@ -490,7 +490,7 @@
                 <div class="modal-height-300">
                     <table class="table table-hover table-bordered">
                         <thead>
-                        <tr><th>项目节编号</th><th>项目节名称</th><% if (coopwd) { %><th>解锁  </th><% } %><th>单位/协同人名称</th><th>确认数据</th></tr>
+                        <tr><th>项目节编号</th><th>项目节名称</th><th>解锁  </th><th>单位/协同人名称</th><th>确认数据</th></tr>
                         </thead>
                         <tbody id="cooperationList">
                         </tbody>

+ 17 - 0
app/view/tender/detail_modal.ejs

@@ -59,6 +59,7 @@
                                                 <option value="设计">设计</option>
                                                 <option value="监理">监理</option>
                                                 <option value="施工">施工</option>
+                                                <option value="检测">检测</option>
                                                 <option value="其他">其他</option>
                                             </select>
                                         </div>
@@ -139,6 +140,14 @@
                                             <input type="date" class="form-control" value="" id="contract1-date">
                                         </div>
                                     </div>
+                                    <div class="col-12 mt-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text">项目经理部</span>
+                                            </div>
+                                            <input type="text" class="form-control" value="" id="contract1-management" maxlength="100" oninput="limitReturn(this)">
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                             <div class="form-group mb-4">
@@ -938,6 +947,7 @@
         $('#contract1-company').val(property.construction_unit.contract1.company);
         $('#contract1-corporation').val(property.construction_unit.contract1.corporation);
         $('#contract1-date').val(property.construction_unit.contract1.date);
+        $('#contract1-management').val(property.construction_unit.contract1.management);
         // 承包单位2
         $('#contract2-company').val(property.construction_unit.contract2.company);
         $('#contract2-corporation').val(property.construction_unit.contract2.corporation);
@@ -999,6 +1009,7 @@
                     company: $('#contract1-company').val(),
                     corporation: $('#contract1-corporation').val(),
                     date: $('#contract1-date').val(),
+                    management: $('#contract1-management').val(),
                 },
                 contract2: {
                     company: $('#contract2-company').val(),
@@ -1836,6 +1847,10 @@
                         <input type="checkbox" class="custom-control-input" id="lc_over" checked="">
                         <label class="custom-control-label" for="lc_over">超计判断</label>
                     </div>
+                    <div class="custom-control custom-checkbox mb-2">
+                        <input type="checkbox" class="custom-control-input" id="lc_banMinusChangeBills" checked="">
+                        <label class="custom-control-label" for="lc_banMinusChangeBills">强制调用负变更(限制上报审批/审批通过)</label>
+                    </div>
                 </div>
             </div>
             <div class="modal-footer">
@@ -1893,6 +1908,7 @@
         $('#lc_same_code')[0].checked = property.ledger_check.same_code;
         $('#lc_sibling')[0].checked = property.ledger_check.sibling;
         $('#lc_over')[0].checked = property.ledger_check.over;
+        $('#lc_banMinusChangeBills')[0].checked = property.ledger_check.banMinusChangeBills;
     };
 
     $('#bd-set-10').on('show.bs.modal', function () {
@@ -1905,6 +1921,7 @@
                 same_code: $('#lc_same_code')[0].checked,
                 sibling: $('#lc_sibling')[0].checked,
                 over: $('#lc_over')[0].checked,
+                banMinusChangeBills: $('#lc_banMinusChangeBills')[0].checked,
             },
         };
         const tenderId = window.location.pathname.split('/')[2];

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

@@ -9,7 +9,6 @@
 </div>
 <script>
     const tenders = JSON.parse(unescape('<%- escape(JSON.stringify(tenderList)) %>'));
-    console.log(tenders);
     const categoryType = JSON.parse('<%- JSON.stringify(settingConst.cType) %>');
     const category = JSON.parse(unescape('<%- escape(JSON.stringify(categoryData)) %>'));
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');

+ 1 - 1
db_script/baseUtils.js

@@ -4,7 +4,7 @@
 const fs = require('fs');
 const path = require('path');
 var util = require('util');
-var logPath = path.join(__dirname, 'change_rela.log');
+var logPath = path.join(__dirname, `${process.argv[1]}.log`);
 var logFile = fs.createWriteStream(logPath, { flags: 'a' });
 console.log = function() {
     logFile.write(util.format.apply(null, arguments) + '\n');

+ 138 - 0
db_script/repair1027.js

@@ -0,0 +1,138 @@
+// 计算变更令,正负变更数
+
+const defaultInfo = require('../app/const/tender_info');
+const BaseUtil = require('./baseUtils');
+const querySql = BaseUtil.querySql;
+const ZhCalc = BaseUtil.ZhCalc;
+
+const checkStage = async function(stage, decimal, preStage) {
+    const billsTable = 'zh_stage_bills_' + stage.tid % 10;
+    const stageBills = await querySql(`Select * From ${billsTable} Where sid = ?`, [stage.id]);
+
+    const history = stage.tp_history ? JSON.parse(stage.tp_history) : null;
+    if (history) {
+        for (const h of history) {
+            const sbFilter = stageBills.filter(x => {
+                return x.times < h.times || (x.times === h.times && x.order <= h.order);
+            });
+            const sbLatest = BaseUtil.filterLastestData(sbFilter, ['lid']);
+            history.positive_qc_tp = 0;
+            history.negative_qc_tp = 0;
+            for (const sbl of sbLatest) {
+                stage.positive_qc_tp = ZhCalc.add(sbl.positive_qc_tp, stage.positive_qc_tp);
+                stage.negative_qc_tp = ZhCalc.add(sbl.negative_qc_tp, stage.negative_qc_tp);
+            }
+        }
+        await querySql('Update zh_stage Set tp_history = ? Where id = ?', [JSON.stringify(history), stage.id]);
+    }
+
+    const stageBillsLatest = BaseUtil.filterLastestData(stageBills, ['lid']);
+    if (stageBillsLatest.length === 0) return;
+
+    stage.positive_qc_tp = 0;
+    stage.pre_positive_qc_tp = preStage ? ZhCalc.add(preStage.positive_qc_tp, preStage.pre_positive_qc_tp) : 0;
+    stage.negative_qc_tp = 0;
+    stage.pre_negative_qc_tp = preStage ? ZhCalc.add(preStage.negative_qc_tp, preStage.pre_negative_qc_tp) : 0;
+    for (const sbl of stageBillsLatest) {
+        stage.positive_qc_tp = ZhCalc.add(sbl.positive_qc_tp, stage.positive_qc_tp);
+        stage.negative_qc_tp = ZhCalc.add(sbl.negative_qc_tp, stage.negative_qc_tp);
+    }
+
+    await querySql('Update zh_stage Set positive_qc_tp = ?, pre_positive_qc_tp = ?, negative_qc_tp = ?, pre_negative_qc_tp = ? Where id = ?', [stage.positive_qc_tp, stage.pre_positive_qc_tp, stage.negative_qc_tp, stage.pre_negative_qc_tp, stage.id]);
+    console.log(`Update Stage ${stage.order}: p_tp(${stage.positive_qc_tp}), pre_p_tp(${stage.pre_positive_qc_tp}), n_tp(${stage.negative_qc_tp}), pre_n_tp(${stage.pre_negative_qc_tp})`);
+};
+
+const checkStageBills = async function (stage, decimal, preStage, reCalcBills) {
+    const billsTable = 'zh_stage_bills_' + stage.tid % 10;
+    const billsFinalTable = 'zh_stage_bills_final_' + stage.tid % 10;
+    const ledgerTable = 'zh_ledger_' + stage.tid % 10;
+    // 计算更新stagePos相关
+    const stageChange = await querySql(`SELECT sc.*, l.unit_price FROM zh_stage_change sc Left Join ${ledgerTable} l ON sc.lid = l.id WHERE sid = ?`, [stage.id]);
+    const stageBills = await querySql(`SELECT * From ${billsTable} where sid = ?`, [stage.id]);
+    if (reCalcBills) {
+        for (const sb of stageBills) {
+            const filterTimesOrder = stageChange.filter(x => {
+                if (x.no_value) return false;
+                if (x.lid !== sb.lid) return false;
+                return x.stimes < sb.times || (x.stimes === sb.times && x.sorder <= sb.order);
+            });
+            const filterLatest = BaseUtil.filterLastestData(filterTimesOrder, ['pid', 'cbid'], 'stimes', 'sorder');
+            if (filterLatest.length === 0) continue;
+
+            sb.positive_qc_qty = 0;
+            sb.negative_qc_qty = 0;
+            for (const fl of filterLatest) {
+                if (!sb.unit_price) sb.unit_price = fl.unit_price;
+                if (fl.minus) {
+                    sb.negative_qc_qty = ZhCalc.add(sb.negative_qc_qty, fl.qty);
+                } else {
+                    sb.positive_qc_qty = ZhCalc.add(sb.positive_qc_qty, fl.qty);
+                }
+            }
+            if (sb.positive_qc_qty || sb.negative_qc_qty) {
+                sb.positive_qc_tp = ZhCalc.mul(sb.unit_price, sb.positive_qc_qty, decimal.tp);
+                sb.negative_qc_tp = ZhCalc.mul(sb.unit_price, sb.negative_qc_qty, decimal.tp);
+                await querySql(`Update ${billsTable} Set positive_qc_qty = ?, positive_qc_tp = ?, negative_qc_qty = ?, negative_qc_tp = ? Where id = ?`,
+                    [sb.positive_qc_qty, sb.positive_qc_tp, sb.negative_qc_qty, sb.negative_qc_tp, sb.id]);
+            }
+        }
+        console.log(`Update StageBills ${stage.order}: ${stageBills.length}`);
+    }
+    // 计算更新stagePosFinal
+    const stageBillsLatest = BaseUtil.filterLastestData(stageBills, ['lid']);
+    const stageBillsLatestIndex = {};
+    stageBillsLatest.forEach(x => { stageBillsLatestIndex[x.lid] = x; });
+    const preStageBillsFinal = preStage ? await querySql(`Select * From ${billsFinalTable} Where sid = ?`, [preStage.id]) : [];
+    const preStageBillsFinalIndex = {};
+    preStageBillsFinal.forEach(x => { preStageBillsFinalIndex[x.lid] = x; });
+    const stageBillsFinal = await querySql(`Select * From ${billsFinalTable} Where sid = ?`, [stage.id]);
+    for (const sbf of stageBillsFinal) {
+        const curSb = stageBillsLatestIndex[sbf.lid];
+        const preSb = preStageBillsFinalIndex[sbf.lid];
+        if (preSb) {
+            if (curSb) {
+                sbf.positive_qc_qty = ZhCalc.add(preSb.positive_qc_qty, curSb.positive_qc_qty);
+                sbf.positive_qc_tp = ZhCalc.add(preSb.positive_qc_tp, curSb.positive_qc_tp);
+                sbf.negative_qc_qty = ZhCalc.add(preSb.negative_qc_qty, curSb.negative_qc_qty);
+                sbf.negative_qc_tp = ZhCalc.add(preSb.negative_qc_tp, curSb.negative_qc_tp);
+            } else {
+                sbf.positive_qc_qty = preSb.positive_qc_qty;
+                sbf.positive_qc_tp = preSb.positive_qc_tp;
+                sbf.negative_qc_qty = preSb.negative_qc_qty;
+                sbf.negative_qc_tp = preSb.negative_qc_tp;
+            }
+        } else if (curSb) {
+            sbf.positive_qc_qty = curSb.positive_qc_qty;
+            sbf.positive_qc_tp = curSb.positive_qc_tp;
+            sbf.negative_qc_qty = curSb.negative_qc_qty;
+            sbf.negative_qc_tp = curSb.negative_qc_tp;
+        }
+        if (sbf.positive_qc_qty || sbf.negative_qc_qty)
+            await querySql(`Update ${billsFinalTable} Set positive_qc_qty = ?, positive_qc_tp = ?, negative_qc_qty = ?, negative_qc_tp = ? Where id = ?`,
+                [sbf.positive_qc_qty, sbf.positive_qc_tp, sbf.negative_qc_qty, sbf.negative_qc_tp, sbf.id]);
+    }
+    console.log(`Update StageBillsFinal ${stage.order}: ${stageBillsFinal.length}`);
+};
+
+const doRepair1027 = async function(tid, sorder, reCalcBills) {
+    try {
+        const tender = await querySql('Select * From zh_tender where id = ?', [tid]);
+        for (const t of tender) {
+            console.log(`Update Tender ${t.id}:`);
+            const info = await querySql('Select * From zh_tender_info where tid = ?', [t.id]);
+            const decimal = info.length > 0 && info[0].decimal ? JSON.parse(info[0].decimal) : defaultInfo.defaultInfo.decimal;
+
+            const stage = await querySql('Select * From zh_stage where tid = ? and `order` = ?', [t.id, sorder]);
+            const preStage = sorder > 1 ? await querySql('Select * From zh_stage where tid = ? and `order` = ?', [t.id, sorder - 1]) : [];
+            await checkStageBills(stage[0], decimal, preStage[0], reCalcBills);
+            await checkStage(stage[0], decimal, preStage[0], reCalcBills);
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    BaseUtil.closePool();
+};
+const tenderId = parseInt(process.argv[3]);
+const stageOrder = parseInt(process.argv[4]);
+const reCalcBills = parseInt(process.argv[5]);
+doRepair1027(tenderId, stageOrder, reCalcBills);

+ 5 - 120
sql/update.sql

@@ -1,122 +1,6 @@
-ALTER TABLE `zh_stage_audit`
-ADD COLUMN `lock_lid`  text NULL COMMENT '锁定台账id(以,分隔)' AFTER `opinion`;
-
-ALTER TABLE `zh_material_stage_bills` ADD `expr` VARCHAR(1000) NULL DEFAULT NULL COMMENT '表达式' AFTER `quantity`;
-UPDATE `zh_material_stage_bills` a, `zh_material_bills` b SET a.`expr`= b.`expr` WHERE a.`mb_id` = b.`id`;
-
-UPDATE `zh_material_bills` a, `zh_material` b SET a.`expr`= null WHERE a.`mid` = b.`id` AND t_type = 2 AND b.`is_stage_self` = 1;
-
-CREATE TABLE `zh_s2b_spec_pull` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `pid` int(11) NOT NULL,
-  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
-  `pull_type` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '类型',
-  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
-  `info` text COLLATE utf8_unicode_ci COMMENT '拉取数据所需信息(json)',
-  `memo` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
-  `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '获取数据地址',
-  `valid` tinyint(4) unsigned NOT NULL DEFAULT '1' COMMENT '是否启用',
-  `pull_class` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '分类',
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-ALTER TABLE `zh_tender_info`
-ADD COLUMN `gxby_info`  varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '工序报验信息' AFTER `fun_rela`,
-ADD COLUMN `dagl_info`  varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '档案管理信息' AFTER `gxby_info`;
-
-ALTER TABLE `zh_ledger_extra_0`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_1`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_2`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_3`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_4`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_5`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_6`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_7`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_8`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_ledger_extra_9`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-
-ALTER TABLE `zh_pos_extra_0`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_1`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_2`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_3`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_4`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_5`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_6`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_7`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_8`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_9`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_10`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_11`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_12`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_13`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_14`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_15`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_16`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_17`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_18`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-ALTER TABLE `zh_pos_extra_19`
-ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
-ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
-
-
+ALTER TABLE `zh_s2b_spec_msg`
+ADD COLUMN `push_count`  int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '执行推送数量' AFTER `status`;
+-- 以上于2022/11/2更新uat、prod,下次更新时,不可执行
 
+ALTER TABLE `zh_cooperation_confirm`
+ADD COLUMN `locked`  tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否锁定' AFTER `create_time`;

+ 119 - 0
sql/update20221024.sql

@@ -0,0 +1,119 @@
+ALTER TABLE `zh_material_stage_bills` ADD `expr` VARCHAR(1000) NULL DEFAULT NULL COMMENT '表达式' AFTER `quantity`;
+-- 同步旧数据
+UPDATE `zh_material_stage_bills` a, `zh_material_bills` b SET a.`expr`= b.`expr` WHERE a.`mb_id` = b.`id`;
+
+UPDATE `zh_material_bills` a, `zh_material` b SET a.`expr`= null WHERE a.`mid` = b.`id` AND t_type = 2 AND b.`is_stage_self` = 1;
+
+CREATE TABLE `zh_s2b_spec_pull` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `pid` int(11) NOT NULL,
+  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
+  `pull_type` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '类型',
+  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
+  `info` text COLLATE utf8_unicode_ci COMMENT '拉取数据所需信息(json)',
+  `memo` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
+  `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '获取数据地址',
+  `valid` tinyint(4) unsigned NOT NULL DEFAULT '1' COMMENT '是否启用',
+  `pull_class` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '分类',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ALTER TABLE `zh_tender_info`
+ADD COLUMN `gxby_info`  varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '工序报验信息' AFTER `fun_rela`,
+ADD COLUMN `dagl_info`  varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '档案管理信息' AFTER `gxby_info`;
+
+ALTER TABLE `zh_ledger_extra_0`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_1`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_2`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_3`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_4`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_5`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_6`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_7`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_8`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_ledger_extra_9`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+
+ALTER TABLE `zh_pos_extra_0`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_1`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_2`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_3`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_4`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_5`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_6`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_7`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_8`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_9`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_10`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_11`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_12`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_13`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_14`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_15`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_16`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_17`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_18`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+ALTER TABLE `zh_pos_extra_19`
+ADD COLUMN `dagl_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '档案管理id' AFTER `dagl_url`,
+ADD COLUMN `gxby_id`  varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '工序报验id' AFTER `dagl_id`;
+
+
+