浏览代码

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

MaiXinRong 4 年之前
父节点
当前提交
4e3d2bb707

+ 1 - 0
.gitignore

@@ -11,6 +11,7 @@ app/public/upload/
 *.swp
 package-lock.json
 app/public/js/web
+app/public/archive
 .vscode/
 /report_temp
 /file

+ 36 - 1
app/controller/advance_controller.js

@@ -152,7 +152,7 @@ module.exports = app => {
                 // 获取上一期预付款记录
                 const prevAdvance = await ctx.service.advance.getPreviousRecord(ctx.tender.id, ctx.advance.type);
                 // 最大支付比例
-                const max_pr = ctx.helper.mul(ctx.helper.div(ctx.helper.sub(advancePayTotal, (prevAdvance && prevAdvance.prev_total_amount || 2)), advancePayTotal, 10), 100);
+                const max_pr = ctx.helper.mul(ctx.helper.div(ctx.helper.sub(advancePayTotal, (prevAdvance && prevAdvance.prev_total_amount || 0)), advancePayTotal, 10), 100);
 
                 const isLimitMax = ctx.helper.round(max_pr, 2) === ctx.advance.pay_ratio;
                 // 特殊处理金额的显示(formatMoney)
@@ -227,6 +227,41 @@ module.exports = app => {
         }
 
         /**
+         * 删除期
+         * @param {*} ctx 全局上下文
+         */
+        async delete(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const id = data && this.app._.toInteger(data.id);
+                if (isNaN(id) || id <= 0) {
+                    throw '参数错误';
+                }
+                const advance = await ctx.service.advance.getDataById(id);
+                if (!advance) {
+                    throw '参数错误';
+                }
+                // 检查权限等
+                if (advance.uid !== ctx.session.sessionUser.accountId) {
+                    throw '您无权删除';
+                }
+                if (advance.status !== auditConst.status.uncheck && advance.status !== auditConst.status.checkNo) {
+                    console.log(advance.status !== auditConst.status.uncheck);
+                    console.log(advance.status !== auditConst.status.checkNo);
+                    throw '当前不允许删除';
+                }
+                const isDeleted = await ctx.service.advance.deleteAdvance(id);
+                if (!isDeleted) {
+                    throw '删除失败,请重试';
+                }
+                ctx.body = { err: 0, msg: '' };
+            } catch (error) {
+                this.log(error);
+                ctx.body = { err: 1, msg: error.toString(), data: null };
+            }
+        }
+
+        /**
          * 添加审批人
          * @param {Object} ctx 全局上下文
          */

+ 3 - 1
app/controller/change_controller.js

@@ -41,7 +41,9 @@ module.exports = app => {
             // const tenderList = await this.service.tender.getList();
 
             const page = ctx.page;
-            const changes = await ctx.service.change.getListByStatus(tender.id, status);
+            const sorts = ctx.query.sort ? ctx.query.sort : 0;
+            const orders = ctx.query.order ? ctx.query.order : 0;
+            const changes = await ctx.service.change.getListByStatus(tender.id, status, 1, sorts, orders);
             const total = await ctx.service.change.getCountByStatus(tender.id, status);
             if (changes !== null) {
                 let i = 0;

+ 2 - 2
app/controller/report_archive_controller.js

@@ -14,7 +14,7 @@ const fsUtil = require('../public/js/fsUtil');
 const auditConst = require('../const/audit');
 
 module.exports = app => {
-    class ReportController extends app.BaseController {
+    class ReportArchiveController extends app.BaseController {
 
         async index(ctx) {
             const tender = ctx.tender;
@@ -270,6 +270,6 @@ module.exports = app => {
         }
 
     }
-    return ReportController;
+    return ReportArchiveController;
 };
 

+ 12 - 7
app/controller/stage_controller.js

@@ -193,7 +193,7 @@ 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.session.sessionUser.accountId === ctx.stage.user_id) || (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId);
+                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.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId);
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -330,10 +330,15 @@ 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.session.sessionUser.accountId : null;
+                            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) : [];
-                            responseData.data.cooperationPwd = uid !== null ? await ctx.service.cooperationPwd.getValidData(ctx.tender.id, uid) : [];
+                            // responseData.data.cooperationPwd = uid !== null ? await ctx.service.cooperationPwd.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) : [];
                             break;
@@ -1832,10 +1837,10 @@ module.exports = app => {
                         await ctx.service.cooperationConfirm.del(data.postData);
                         responseData.data.cooperationConfirm = await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.session.sessionUser.accountId);
                         break;
-                    case 'save-pwd':
-                        const result = await ctx.service.cooperationPwd.save(data.postData);
-                        responseData.data.cooperationPwd = await ctx.service.cooperationPwd.getValidData(ctx.tender.id, ctx.session.sessionUser.accountId);
-                        break;
+                    // case 'save-pwd':
+                    //     const result = await ctx.service.cooperationPwd.save(data.postData);
+                    //     responseData.data.cooperationPwd = await ctx.service.cooperationPwd.getValidData(ctx.tender.id, ctx.session.sessionUser.accountId);
+                    //     break;
                     default:
                         throw '参数有误';
                 }

二进制
app/public/css/ztree/img/diy/10.png


+ 12 - 0
app/public/js/advance.js

@@ -213,6 +213,18 @@ $(document).ready(function () {
             $('#audit-list').append(historyHTML)
         })
     })
+
+    $('a[data-target="#del-qi"').on('click', function () {
+      const id = $(this).data('id')
+      const order = $(this).data('order') //期数
+      $('#del-qi').find('.modal-body').children()[0].innerText = `确认删除「第${order}期」?`
+      $('#del-qi #del-confirm').click(function() {
+        postData(`${window.location.pathname}/delete`, {id}, (res) => {
+          console.log(res);
+          window.location.reload()
+        })
+      })
+    })
     function formatMoney(s, dot = ',', decimal = 2) {
         if (!s) {
             s = 0;

+ 6 - 7
app/public/js/advance_audit.js

@@ -218,9 +218,7 @@ $(document).ready(function () {
         const type = parseInt($(this).data('type'))
         let pay_ratio = null
         let cur_amount = null
-
         let isLimitMax = false  // 用来判断是否达到最大
-
         if (val < min) {
             // 限制最小值为min
             $(this).val(min)
@@ -236,32 +234,33 @@ $(document).ready(function () {
             if (val >= re_amount) {
                 // 限制不能超过最大值
                 val = re_amount
-                debugger
                 isLimitMax = true
             }
+            
             $(this).val(isLimitMax ? val : fixedToSub(val, decimal)) // 重新赋值限制只有两位小数
             const pay_a_input = $(`.pay-input[data-type=${reverse(type)}]`)
-            pay_ratio = parseFloat(ZhCalc.mul(ZhCalc.div(val, advancePayTotal), 100).toFixed(2))
+            pay_ratio = ZhCalc.mul(ZhCalc.div(val, advancePayTotal), 100).toFixed(2)
             cur_amount = isLimitMax ? re_amount : ZhCalc.round(val, decimal)
             pay_a_input.val(pay_ratio)
-            const total = parseFloat(ZhCalc.add(cur_amount, p_amount)).toString().split('.')[1]
+            const total = ZhCalc.add(cur_amount, p_amount).toString().split('.')[1] || ''
             // 截止本期金额文案更新
             $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
         } else {
-            // 支付比例转化
 
+            // 支付比例转化
             val = fixedToSub(val)
             if (val.toFixed(2) === max.toFixed(2)) {
               // 比例达到最大,特殊处理金额的显示小数点
                 val = fixedToSub(max, 2);
                 isLimitMax = true
             }
+
             $(this).val(val) // 重新赋值限制只有两位小数
             const cur_m_input = $(`.pay-input[data-type=${reverse(type)}]`)
             cur_amount = isLimitMax ? re_amount : ZhCalc.round(ZhCalc.mul(advancePayTotal, ZhCalc.div(val, 100), 10), decimal)
             pay_ratio = val
             cur_m_input.val(cur_amount)
-            const total = parseFloat(ZhCalc.add(cur_amount, p_amount)).toString().split('.')[1]
+            const total = ZhCalc.add(cur_amount, p_amount).toString().split('.')[1] || ''
             // 截止本期金额文案更新
             $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
         }

+ 42 - 0
app/public/js/change.js

@@ -274,6 +274,11 @@ $(document).ready(() => {
        if (status !== 0) {
            url += '/status/'+ status;
        }
+       let orderSetting = getLocalCache('change-'+ $('#tenderId').val() +'-list-order');
+       if (orderSetting) {
+           const orders = orderSetting.split('|');
+           url += '?sort=' + orders[0] + '&order=' + orders[1];
+       }
        window.location.href = url;
     });
     // 不再显示首次使用
@@ -290,4 +295,41 @@ $(document).ready(() => {
     $('.delete-cid-modal').on('click', function () {
         $('#delete-cid').val($(this).attr('cid'));
     });
+
+    // 排序初始化
+    let orderSetting = getLocalCache('change-'+ $('#tenderId').val() +'-list-order');
+    if (!orderSetting) orderSetting = 'time|desc';
+    const orders = orderSetting.split('|');
+    $("#sort-radio input[value='"+ orders[0] +"']").prop('checked', true);
+    $("#order-radio input[value='"+ orders[1] +"']").prop('checked', true);
+    if (orders[0] === 'time') {
+        $('#bpaixu').text('排序:创建时间');
+    } else {
+        $('#bpaixu').text('排序:变更令号');
+    }
+    // let sortSetting = getLocalCache('change-'+ $('#tenderId').val() +'-list-sort');
+    // if (sortSetting && parseInt(sortSetting) === 1) {
+    //     $('#bpaixu').click();
+    // }
+    // $('#sort-dropdown').on('shown.bs.dropdown', function () {
+    //     setLocalCache('change-'+ $('#tenderId').val() +'-list-sort', 1);
+    // });
+    // $('#sort-dropdown').on('hidden.bs.dropdown', function () {
+    //     setLocalCache('change-'+ $('#tenderId').val() +'-list-sort', 0);
+    // });
+
+    $('#sort-radio input[name="paizhi"]').click(function () {
+        const orderStr = $(this).val() + '|' + $('#order-radio input[name="paixu"]:checked').val();
+        setLocalCache('change-'+ $('#tenderId').val() +'-list-order', orderStr);
+        // setLocalCache('change-'+ $('#tenderId').val() +'-list-sort', 1);
+        const link = window.location.origin + window.location.pathname + '?sort='+ $(this).val() + '&order=' + $('#order-radio input[name="paixu"]:checked').val();
+        window.location.href = link;
+    });
+    $('#order-radio input[name="paixu"]').click(function () {
+        const orderStr = $('#sort-radio input[name="paizhi"]:checked').val() + '|' + $(this).val();
+        setLocalCache('change-'+ $('#tenderId').val() +'-list-order', orderStr);
+        // setLocalCache('change-'+ $('#tenderId').val() +'-list-sort', 1);
+        const link = window.location.origin + window.location.pathname + '?sort='+ $('#sort-radio input[name="paizhi"]:checked').val() + '&order=' + $(this).val();
+        window.location.href = link;
+    })
 });

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

@@ -272,7 +272,7 @@ $(document).ready(() => {
                     // 判断是否大于等于限制值,否则无法更改
                     const usedInfo = _.find(changeUsedData, { id: select.id });
                     if (usedInfo && validText < usedInfo.used_qty) {
-                        toastr.error('已调用清单更数值必须大于等于已调用值');
+                        toastr.error('清单更数值必须大于等于已调用值');
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                         return;
                     }

+ 9 - 0
app/public/js/global.js

@@ -107,6 +107,15 @@ $(function(){
             $(this).attr('href', $(this).attr('href') + '?pageSize=' + getLocalCache('account-pageSize'));
         }
     });
+
+    $('.change_sort_link').each(function () {
+        const tender_id = $(this).attr('href').split('/')[2];
+        let orderSetting = getLocalCache('change-'+ tender_id +'-list-order');
+        if(orderSetting) {
+            const orders = orderSetting.split('|');
+            $(this).attr('href', $(this).attr('href') + '?sort=' + orders[0] + '&order=' + orders[1]);
+        }
+    });
 });
 
 function checkShowLast (count) {

+ 24 - 22
app/public/js/path_tree.js

@@ -1167,12 +1167,14 @@ const createNewPathTree = function (type, setting) {
                 if (p) p.check = p.pwd === pwd;
             }
         }
-        loadPwd(data, cacheKey) {
+        loadPwd(data, cacheKey, confirmList) {
             this.loadingPwd = true;
             try {
                 this.pwdCacheKey = cacheKey;
+                this.confirmList = confirmList;
                 this.pwd = data;
                 this._loadPwdCache();
+                this._loadOnlineConfirm();
                 for (const p of this.pwd) {
                     p.node = this.getItems(p.ledger_id);
                     this.lockNode(p, !p.check);
@@ -1206,22 +1208,22 @@ const createNewPathTree = function (type, setting) {
                 }
             }
         }
-        loadOnlinePwd(data, pwdList, confirmList) {
-            this.loadingPwd = true;
-            try {
-                this.pwdList = pwdList;
-                this.confirmList = confirmList;
-                this.pwd = data;
-                this._loadOnlinePwd();
-                this._loadOnlineConfirm();
-                // 旧数据上传,新数据补齐
-                for (const p of this.pwd) {
-                    p.node = this.getItems(p.ledger_id);
-                    this.lockNode(p, !p.check);
-                }
-            } catch(err) {}
-            this.loadingPwd = false;
-        }
+        // loadOnlinePwd(data, pwdList, confirmList) {
+        //     this.loadingPwd = true;
+        //     try {
+        //         this.pwdList = pwdList;
+        //         this.confirmList = confirmList;
+        //         this.pwd = data;
+        //         this._loadOnlinePwd();
+        //         this._loadOnlineConfirm();
+        //         // 旧数据上传,新数据补齐
+        //         for (const p of this.pwd) {
+        //             p.node = this.getItems(p.ledger_id);
+        //             this.lockNode(p, !p.check);
+        //         }
+        //     } catch(err) {}
+        //     this.loadingPwd = false;
+        // }
 
         getStageItems(id) {
             return this.stageItems[itemsPre + id];
@@ -1411,7 +1413,7 @@ const createNewPathTree = function (type, setting) {
                 pn.lock = isLock;
                 refresh.push(this.getNodeIndex(pn));
             }
-            // if (!this.loadingPwd) this._savePwdCache();
+            if (!this.loadingPwd) this._savePwdCache();
             return refresh;
         }
     }
@@ -1642,7 +1644,7 @@ const createNewPathTree = function (type, setting) {
                 this.loadCompareNode(source, c, cur, loadFun);
             }
         }
-    
+
         generateSortNodes() {
             const self = this;
             const addSortNode = function (node) {
@@ -1656,13 +1658,13 @@ const createNewPathTree = function (type, setting) {
                 addSortNode(n);
             }
         }
-    
+
         loadCompareTree(data, loadFun) {
             for (const c of data.billsTree.children) {
                 this.loadCompareNode(data, c, null, loadFun);
             }
         }
-    
+
         calculateDiffer() {
             if (this.setting.calcDiffer) {
                 for (const d of this.datas) {
@@ -1670,7 +1672,7 @@ const createNewPathTree = function (type, setting) {
                 }
             }
         }
-    
+
         loadCompareData(data1, data2) {
             this.loadCompareTree(data1, this.setting.loadInfo1);
             this.loadCompareTree(data2, this.setting.loadInfo2);

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

@@ -196,7 +196,7 @@ $(document).ready(() => {
     // 设置页显示数目
     $('.nav-tabs .nav-link').each(function () {
         const pageSize = getLocalCache('account-pageSize') ? getLocalCache('account-pageSize') : '';
-        if (getLocalCache('account-pageSize')) {
+        if (getLocalCache('account-pageSize') && $(this).attr('href').indexOf('pageSize') === -1) {
             $(this).attr('href', $(this).attr('href') + '?pageSize=' + getLocalCache('account-pageSize'));
         }
     });

+ 15 - 6
app/public/js/stage.js

@@ -340,7 +340,16 @@ $(document).ready(() => {
                 html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
             }
             html.push('<td>', p.company, '</td>');
-            html.push('<td>', p.check ? (p.confirm ? (moment(p.confirm_time).format('YYYY-MM-DD HH:mm') + ' ' + (coopwd ? `<a name="ledger-unconfirm" href="javascript: void(0);" lid="${p.ledger_id}">重新审批</a>` : '')) : `<a name="ledger-confirm" href="javascript: void(0);" lid="${p.ledger_id}" class="btn btn-sm btn-success">确认</a>`) : '' ,'</td>');
+            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>');
+            } 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) {
+                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>');
+            }
+            // html.push('<td>', p.check ? (p.confirm ? (moment(p.confirm_time).format('YYYY-MM-DD HH:mm') + ' ' + (coopwd ? `<a name="ledger-unconfirm" href="javascript: void(0);" lid="${p.ledger_id}">重新审批</a>` : '')) : `<a name="ledger-confirm" href="javascript: void(0);" lid="${p.ledger_id}" class="btn btn-sm btn-success">确认</a>`) : '' ,'</td>');
             html.push('</tr>');
         }
         $('#cooperationList').html(html.join(''));
@@ -1951,8 +1960,8 @@ $(document).ready(() => {
         treeCalc.calculateAll(stageTree);
         // 加载解锁相关
         if (result.cooperation) {
-            // stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
-            stageTree.loadOnlinePwd(result.cooperation, result.cooperationPwd, result.cooperationConfirm);
+            stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2], result.cooperationConfirm);
+            // stageTree.loadOnlinePwd(result.cooperation, result.cooperationPwd, result.cooperationConfirm);
             $('#cooperationCount').html(stageTree.pwd.length || '');
             if (stageTree.pwd.length > 0) $('#cooperationCount').parent().show();
             setCooperationSelectHtml();
@@ -4117,9 +4126,9 @@ $(document).ready(() => {
         if (p.pwd === $('#unlock-pwd').val()) {
             const refresh = stageTree.lockNode(p, false);
             // 修改线上
-            postData(window.location.pathname + '/save/cooperation', { type: 'save-pwd', postData: { ledger_id: lid, pwd: $('#unlock-pwd').val() } }, function (result) {
-                stageTree.pwdList = result.cooperationPwd;
-            });
+            // postData(window.location.pathname + '/save/cooperation', { type: 'save-pwd', postData: { ledger_id: lid, pwd: $('#unlock-pwd').val() } }, function (result) {
+            //     stageTree.pwdList = result.cooperationPwd;
+            // });
             SpreadJsObj.reloadRowsReadonly(slSpread.getActiveSheet(), refresh);
             stagePosSpreadObj.loadCurPosData();
             $('#unlock').modal('hide');

+ 18 - 4
app/public/report/js/rpt_archive.js

@@ -10,6 +10,9 @@ let rptArchiveObj = {
     iniPage: function() {
         //初始化页面的归档信息
         let me = rptArchiveObj;
+        me.currentNode = null;
+        me.currentArchiveUuid = null;
+        me.currentArchiveDateStr = null;
         const archivedRptIds = [];
         for (let aItem of ARCHIVE_LIST) {
             archivedRptIds.push(parseInt(aItem.rpt_id));
@@ -57,6 +60,8 @@ let rptArchiveObj = {
         zTreeHelper.createTreeDirectly(TOP_TREE_NODES, rpt_prj_folder_setting, "rptTplTree", me);
         me.treeObj.expandAll(true);
         me.refreshNodes();
+        rptArchiveObj._countChkedRptTpl();
+        rptArchiveObj._buildeArchiveDateSelect();
     },
     toggleBtn: function (enabled) {
         if (current_stage_status === 3 && enabled) {
@@ -131,11 +136,11 @@ let rptArchiveObj = {
 
     _buildeArchiveDateSelect: function () {
         let me = rptArchiveObj;
+        let targetDom = document.getElementById("currentDrpArchiveSelect");
+        targetDom.innerHTML = me.currentArchiveDateStr;
+        let drpDom = $("#drpArchiveSelect");
+        drpDom.empty();
         if (me.currentNode && me.currentArchiveUuid && me.currentArchiveDateStr) {
-            let targetDom = document.getElementById("currentDrpArchiveSelect");
-            targetDom.innerHTML = me.currentArchiveDateStr;
-            let drpDom = $("#drpArchiveSelect");
-            drpDom.empty();
             for (let aItem of ARCHIVE_LIST) {
                 if (me.currentNode.refId === parseInt(aItem.rpt_id)) {
                     for (let item of aItem.items) {
@@ -179,6 +184,7 @@ let rptArchiveObj = {
         //初始化当前报表已经归档的信息
         //ARCHIVE_LIST结构:[{rpt_id, items: [{uuid, update_time, is_common}...最多3个]}...] (当前项目、当前期的所有报表归档信息)
         if (currentNode) {
+            //1. cardArchiveInfo
             let cardArchiveInfo = $('#cardArchiveInfo');
             cardArchiveInfo.empty();
             let auditDate = null;
@@ -217,6 +223,14 @@ let rptArchiveObj = {
                 }
             }
             cardArchiveInfo.append('</div>');
+            //2. selectionArchiveInfo
+            let selectionArchiveInfo = $('#selectionArchiveInfo');
+            selectionArchiveInfo.empty();
+            if (achivedAmt > 0) {
+                for (let idx = 0; idx < achivedItem.items.length; idx++) {
+                    selectionArchiveInfo.append('<a class="dropdown-item" href="javascript: void(0);">#' + (idx + 1) + ' ' + achivedItem.items[idx].updateDate_time + '</a>');
+                }
+            }
         }
     },
     _getCurrentArchives: function (currentNode) {

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

@@ -18,7 +18,8 @@ const rpt_tpl_setting = {
             leaf:true
         },
         key: {
-            children: "items"
+            children: "items",
+            title: "title"
         },
         simpleData: {
             enable: true,

+ 17 - 0
app/public/report/js/rpt_main.js

@@ -213,8 +213,25 @@ let zTreeOprObj = {
     },
     refreshNodes: function() {
         let me = this;
+        const _set_archive_icon = function (tplNode) {
+            for (let aItem of ARCHIVE_LIST) {
+                let hasArchive = false;
+                if (parseInt(aItem.rpt_id) === parseInt(tplNode.refId)) {
+                    hasArchive = true;
+                    tplNode.icon = "/public/css/ztree/img/diy/10.png";
+                    break;
+                }
+                if (!hasArchive) {
+                    if (!tplNode.isParent) {
+                        tplNode.icon = null;
+                        tplNode.className = "button ico_docu";
+                    }
+                }
+            }
+        };
         let private_setupIsParent = function(node){
             node.isParent = (node.nodeType === RT.NodeType.NODE || node.level === 0);
+            _set_archive_icon(node);
             if (node.items && node.items.length) {
                 for (let i = 0; i < node.items.length; i++) {
                     private_setupIsParent(node.items[i]);

+ 1 - 0
app/router.js

@@ -136,6 +136,7 @@ module.exports = app => {
     app.get('/tender/:id/advance', sessionAuth, tenderCheck, 'advanceController.index');
     app.get('/tender/:id/advance/material', sessionAuth, tenderCheck, 'advanceController.materialList');
     app.post('/tender/:id/advance/create', sessionAuth, tenderCheck, 'advanceController.create');
+    app.post('/tender/:id/advance/delete', sessionAuth, tenderCheck, 'advanceController.delete');
     app.get('/tender/:id/advance/:order/detail', sessionAuth, tenderCheck, advanceCheck, 'advanceController.detail');
     app.post('/tender/:id/advance/:type/create', sessionAuth, tenderCheck, 'advanceController.create');
     app.post('/tender/:id/advance/:order/audit/add', sessionAuth, tenderCheck, advanceCheck, 'advanceController.addAudit');

+ 7 - 0
app/service/advance.js

@@ -200,7 +200,14 @@ module.exports = app => {
             return await this.update(payload, {
                 id,
             });
+        }
 
+        /**
+         * 删除预付款记录
+         * @param {String} id 预付款id
+         */
+        async deleteAdvance(id) {
+            return await this.deleteById(id);
         }
     }
     return Advance;

+ 16 - 7
app/service/change.js

@@ -227,18 +227,18 @@ module.exports = app => {
          * @param {int} hadlimit - 分页
          * @return {object} list - 列表
          */
-        async getListByStatus(tenderId, status = 0, hadlimit = 1) {
+        async getListByStatus(tenderId, status = 0, hadlimit = 1, sortBy = '', orderBy = '') {
             let sql = '';
             let sqlParam = '';
             if (this.ctx.tender.isTourist && status === 0) {
-                sql = 'SELECT * FROM ?? WHERE tid = ? ORDER BY in_time DESC';
+                sql = 'SELECT a.* FROM ?? As a WHERE a.tid = ?';
                 sqlParam = [this.tableName, tenderId];
             } else {
                 switch (status) {
                     case 0: // 包含你的所有变更令
                         sql =
                             'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' +
-                            '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? ) ORDER BY a.in_time DESC';
+                            '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? )';
                         sqlParam = [
                             this.tableName,
                             tenderId,
@@ -250,14 +250,14 @@ module.exports = app => {
                         ];
                         break;
                     case 1: // 待处理(你的)
-                        sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
+                        sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?)';
                         sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
                         break;
                     case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令
                         sql =
                             'SELECT a.* FROM ?? AS a WHERE ' +
                             'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
-                            '(a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
+                            '(a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ?';
                         sqlParam = [
                             this.tableName,
                             this.ctx.service.changeAudit.tableName,
@@ -273,17 +273,26 @@ module.exports = app => {
                         sql =
                             'SELECT a.* FROM ?? AS a WHERE ' +
                             'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' +
-                            'a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                            'a.status = ? AND a.tid = ?';
                         sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId];
                         break;
                     case 3: // 已完成(所有的)
-                        sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                        sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ?';
                         sqlParam = [this.tableName, status, tenderId];
                         break;
                     default:
                         break;
                 }
             }
+            if (sortBy && orderBy) {
+                if (sortBy === 'code') {
+                    sql += ' ORDER BY CHAR_LENGTH(a.code) ' + orderBy + ',convert(a.code using gbk) ' + orderBy;
+                } else {
+                    sql += ' ORDER BY a.in_time ' + orderBy;
+                }
+            } else {
+                sql += ' ORDER BY a.in_time DESC';
+            }
             if (hadlimit) {
                 const limit = this.app.config.pageSize;
                 const offset = limit * (this.ctx.page - 1);

+ 4 - 0
app/service/cooperation_confirm.js

@@ -53,6 +53,10 @@ module.exports = app => {
             // }
             return await this.getAllDataByCondition(condition);
         }
+
+        async delBycheckNoPre(uid, stage, transaction) {
+            return await transaction.delete(this.tableName, { tid: stage.tid, sid: stage.id, times: stage.times, uid });
+        }
     }
 
     return CooperationConfirm;

+ 2 - 0
app/service/ledger_cooperation.js

@@ -34,12 +34,14 @@ module.exports = app => {
                 const result = await this.db.insert(this.tableName, data);
                 data.id = result.insertId;
                 data.sign_path = null;
+                data.company = '';
                 data.status = 1;
                 // }
             } else if (data.pwd !== '' && info) {
                 data.id = info.id;
                 await this.db.update(this.tableName, data);
                 data.sign_path = info.sign_path;
+                data.company = info.company;
             }
             return data;
         }

+ 4 - 0
app/service/stage_audit.js

@@ -750,6 +750,10 @@ module.exports = app => {
                 await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
                 await this.ctx.service.stageOther.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 transaction.update(this.ctx.service.stage.tableName, {
                     id: stageId,

+ 2 - 1
app/view/advance/index.ejs

@@ -52,7 +52,7 @@
                             <th class="text-center" width="15%">截止本期金额</th>
                             <th class="text-center">附件</th>
                             <th class="text-center">进度</th>
-                            <th class="text-center" width="100">操作</th>
+                            <th class="text-center" width="150">操作</th>
                         </tr>
                     </thead>
                     <tbody id="advanceList">
@@ -76,6 +76,7 @@
                                 <td>
                                     <% if((item.status === auditConst.status.uncheck || item.status === auditConst.status.checkNo) && item.uid === ctx.session.sessionUser.accountId) { %>
                                         <a href="/tender/<%- ctx.tender.id %>/advance/<%- item.id %>/detail" class="btn btn-primary btn-sm">编辑</a>
+                                        <a href="del-qi" class="btn btn-outline-danger btn-sm ml-1" data-toggle="modal" data-target="#del-qi" data-id="<%- item.id %>" data-order="<%- item.order %>">删除</a>
                                     <% } else if(item.status === auditConst.status.checking && item.curAuditor.audit_id === ctx.session.sessionUser.accountId) {%>
                                         <a href="/tender/<%- ctx.tender.id %>/advance/<%- item.id %>/detail" class="btn btn-success btn-sm">审批</a>
                                     <% } else {%>

+ 17 - 0
app/view/advance/modal.ejs

@@ -60,6 +60,23 @@
         </div>
     </div>
 </div>
+<div class="modal fade" id="del-qi" data-backdrop="static">
+  <div class="modal-dialog" role="document">
+      <div class="modal-content">
+          <div class="modal-header">
+              <h5 class="modal-title">删除期</h5>
+          </div>
+          <div class="modal-body">
+            <h6>确认删除「第3期」?</h6>
+            <h6>删除后,数据无法恢复,请谨慎操作。</h6>
+          </div>
+          <div class="modal-footer">
+            <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            <button type="button" class="btn btn-danger" id="del-confirm">确定删除</button>
+          </div>
+      </div>
+  </div>
+</div>
 <script>
     // 展开历史审核记录
     $('#audit-list').on('click', 'a', function() {

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

@@ -5,6 +5,41 @@
             <% include ../tender/tender_sub_mini_menu.ejs %>
             <div>
                 <div class="d-inline-block">
+                    <div class="btn-group" id="sort-dropdown">
+                        <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" id="bpaixu">排序:创建时间</button>
+                        <div class="dropdown-menu" aria-labelledby="bpaixu">
+                            <ul class="list-unstyled px-3 mb-0" id="sort-radio">
+                                <li class="mb-2">
+                                    <div class="custom-control custom-radio">
+                                        <input type="radio" class="custom-control-input" id="pai1" name="paizhi" value="time" checked="">
+                                        <label class="custom-control-label" for="pai1">创建时间</label>
+                                    </div>
+                                </li>
+                                <li class="mb-2">
+                                    <div class="custom-control custom-radio">
+                                        <input type="radio" class="custom-control-input" id="pai3" name="paizhi" value="code">
+                                        <label class="custom-control-label" for="pai3">变更令号</label>
+                                    </div>
+                                </li>
+                            </ul>
+                            <ul class="list-unstyled px-3 pt-2 mb-0 border-top" id="order-radio">
+                                <li class="mb-2">
+                                    <div class="custom-control custom-radio">
+                                        <input type="radio" class="custom-control-input" id="pdown" name="paixu" value="desc" checked="">
+                                        <label class="custom-control-label" for="pdown">降序</label>
+                                    </div>
+                                </li>
+                                <li class="mb-2">
+                                    <div class="custom-control custom-radio">
+                                        <input type="radio" class="custom-control-input" id="pup" name="paixu" value="asc">
+                                        <label class="custom-control-label" for="pup">升序</label>
+                                    </div>
+                                </li>
+                            </ul>
+                        </div>
+                    </div>
+                </div>
+                <div class="d-inline-block">
                     <select class="form-control form-control-sm" id="status_select">
                         <option value="0">全部</option>
                         <% for (const fs in filter.status) { %>
@@ -31,7 +66,7 @@
                 <table class="table table-bordered">
                     <thead>
                     <tr>
-                        <th width="20%">申请编号/变更令号</th><th width="30%">工程名称</th>
+                        <th width="20%" id="sort_change">申请编号/变更令号</th><th width="30%">工程名称</th>
                         <th width="10%">变更类别</th><th width="10%">变更金额</th>
                         <th width="10%">审批状态</th><th width="15%">审批进度</th><th></th>
                     </tr>

+ 5 - 5
app/view/material/list.ejs

@@ -64,12 +64,12 @@
 <script>
     const materialType = JSON.parse('<%- materialType %>');
     const materialBillsData = JSON.parse(unescape('<%- escape(JSON.stringify(materialBillsData)) %>'));
-    let materialListData = JSON.parse('<%- JSON.stringify(materialListData) %>');
+    let materialListData = JSON.parse(unescape('<%- escape(JSON.stringify(materialListData)) %>'));
     const notJoinList = JSON.parse('<%- JSON.stringify(materialNotJoinListData) %>');
-    const ledger = JSON.parse('<%- JSON.stringify(ledger) %>');
-    const curLedgerData = JSON.parse('<%- JSON.stringify(curLedgerData) %>');
-    const pos = JSON.parse('<%- JSON.stringify(pos) %>');
-    const curPosData = JSON.parse('<%- JSON.stringify(curPosData) %>');
+    const ledger = JSON.parse(unescape('<%- escape(JSON.stringify(ledger)) %>'));
+    const curLedgerData = JSON.parse(unescape('<%- escape(JSON.stringify(curLedgerData)) %>'));
+    const pos = JSON.parse(unescape('<%- escape(JSON.stringify(pos)) %>'));
+    const curPosData = JSON.parse(unescape('<%- escape(JSON.stringify(curPosData)) %>'));
     const readOnly = <%- material.readOnly %>;
     const stage_order = <%- material.order %>;
 </script>

+ 22 - 9
app/view/report/index.ejs

@@ -73,11 +73,7 @@
                                             <button id="btnArchiveList" type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" disabled>
                                                 已归档
                                             </button>
-                                            <div class="dropdown-menu" aria-labelledby="btnGroupDrop1" style="min-width:112px">
-                                                <!--
-                                                <a class="dropdown-item" href="#">#1 2021-03-01</a>
-                                                <a class="dropdown-item" href="#">#2 2021-02-28</a>
-                                                -->
+                                            <div class="dropdown-menu" aria-labelledby="btnGroupDrop1" style="min-width:112px" id="selectionArchiveInfo">
                                             </div>
                                         </div>
                                     </div>
@@ -399,8 +395,11 @@
     buildTplTree();
 
     function chkAndSetNode(parentItem) {
+        parentItem.title = '';
         if (parentItem.nodeType === 1) {
             parentItem.isParent = true;
+        } else {
+            parentItem.title = parentItem.name + '(' + parentItem.refId + ')';
         }
         if (parentItem.items) {
             for (let dtlItem of parentItem.items) {
@@ -536,10 +535,24 @@
                 break;
             }
         }
-        buildStageSelection();
-        setupSignature();
-        //还有必要触发报表刷新!
-        zTreeOprObj.onClick(null, null, zTreeOprObj.currentNode);
+        let params = {prjId: PROJECT_ID, stgId: current_stage_id};
+        $.bootstrapLoading.start();
+        CommonAjax.postXsrfEx("/tender/report_api/getReportArchive", params, 10000, true, getCookie('csrfToken_j'),
+            function(result){
+                $.bootstrapLoading.end();
+                ARCHIVE_LIST = result.data;
+                buildStageSelection();
+                setupSignature();
+                zTreeOprObj.refreshNodes();
+                //还有必要触发报表刷新!
+                zTreeOprObj.onClick(null, null, zTreeOprObj.currentNode);
+                //console.log(ARCHIVE_LIST);
+            }, function(err){
+                $.bootstrapLoading.end();
+            }, function(ex){
+                $.bootstrapLoading.end();
+            }
+        );
     }
 
     function setupSignature() {

+ 1 - 1
app/view/report/index_archive.ejs

@@ -276,7 +276,7 @@
         //rptArchiveObj.onClick(null, null, rptArchiveObj.currentNode);
         const params = {prjId: PROJECT_ID, stgId: current_stage_id};
         $.bootstrapLoading.start();
-        CommonAjax.postXsrfEx("/tender/report_api/getReportArchive", params, 10000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/getReportArchive", params, 10000, true, getCookie('csrfToken_j'),
             function(result){
                 $.bootstrapLoading.end();
                 // console.log(result);

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

@@ -511,6 +511,52 @@
         </div>
     </div>
 </div>
+<!--全屏显示报表-->
+<div class="modal fade" id="fullscreen" data-backdrop="static">
+    <div class="modal-dialog modal-full" role="document">
+        <div class="modal-content">
+            <div class="modal-header d-flex justify-content-between">
+                <h5 class="modal-title" id="fullScrTitle"></h5>
+                <div class="print-toolsbar">
+                    <div class="panel">
+                        <div class="panel-body">
+                            <div class="btn-group" role="group">
+                                <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="缩小">-</button>
+                                <button class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="重置默认大小">1000%</button>
+                                <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="放大">+</button>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="panel">
+                        <div class="panel-body">
+                            <div class="input-group input-group-sm">
+                                <div class="input-group-prepend">
+                                    <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="第一页"><i class="fa fa-angle-double-left "></i></button>
+                                    <button type="button" class="btn btn-outline-primary btn-sm" disabled="" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上一页"><i class="fa fa-angle-left "></i></button>
+                                </div>
+                                <input class="form-control" value="1/10" style="width:60px" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="输入页码按回车键,快速跳转">
+                                <div class="input-group-append">
+                                    <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下一页"><i class="fa fa-angle-right"></i></button>
+                                    <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="尾页"><i class="fa fa-angle-double-right "></i></button>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="panel">
+                        <div class="panel-body">
+                            <button type="button" class="btn btn-outline-primary btn-sm" data-dismiss="modal"><i class="fa fa-window-close-o"></i> 退出全屏</button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-body">
+                <div class="modal-fullscreen">
+                    <canvas id="fullScrCanvas" height="100%" width="100%"></canvas>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
 
 <% include ../stage/audit_modal.ejs %>
 

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

@@ -98,7 +98,7 @@
                 <div class="row">
                     <div class="col-6">
                         <% const yb = ctx.helper._.find(accountList, { id: ctx.tender.data.user_id }) %>
-                        <div class="modal-height-500">
+                        <div class="modal-height-500" style="overflow: auto;">
                             <table class="table table-hover table-bordered">
                                 <thead>
                                 <tr><th colspan="4" class="text-center" id="stage_audit"><%- yb.name %>(原报)</th></tr>

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

@@ -35,7 +35,7 @@
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/change') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/change"><i class="fa fa-retweet"></i> <span>工程变更</span></a></li>
+                <li <% if (ctx.url.indexOf('/tender/' + ctx.tender.id + '/change') !== -1) { %>class="active"<% } %>><a class="change_sort_link" href="/tender/<%- ctx.tender.id %>/change"><i class="fa fa-retweet"></i> <span>工程变更</span></a></li>
             </ul>
         </div>
         <div class="nav-box">

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

@@ -39,7 +39,7 @@
         </div>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/change') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/change"><i class="fa fa-retweet"></i> <span>工程变更</span></a></li>
+                <li <% if (ctx.url.indexOf('/tender/' + ctx.tender.id + '/change') !== -1) { %>class="active"<% } %>><a class="change_sort_link" href="/tender/<%- ctx.tender.id %>/change"><i class="fa fa-retweet"></i> <span>工程变更</span></a></li>
             </ul>
         </div>
         <div class="nav-box">

+ 27 - 14
sql/update.sql

@@ -1,28 +1,39 @@
-ALTER TABLE `zh_project_account` ADD `wx_unionid` VARCHAR(50) NULL COMMENT '微信绑定unionid(同一个开放平台共用)' AFTER `wx_openid`;
+ALTER TABLE `zh_ledger_cooperation` ADD `company` VARCHAR(100) NULL DEFAULT '' COMMENT '单位或备注名,筛选用' AFTER `sign_path`;
 
 --
+-- 表的结构 `zh_cooperation_confirm`
 --
-CREATE TABLE `calculation`.`zh_rpt_archive` (
-  `archive_id` INT NOT NULL,
-  `prj_id` INT NULL,
-  `stage_id` INT NULL,
-  `content` VARCHAR(4000) NULL,
-  PRIMARY KEY (`archive_id`),
-  INDEX `PRJ_STG` (`prj_id` ASC, `stage_id` ASC))
-COMMENT = '报表归档表;\n只考虑项目id及期id,其他信息全部归入content';
 
-ALTER TABLE `zh_project`
-ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能设置(json.stringify)' AFTER `rpt_nature`;
+CREATE TABLE `zh_cooperation_confirm` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `sid` int(11) NOT NULL COMMENT '期id',
+  `times` tinyint(11) NOT NULL COMMENT '次数',
+  `ledger_id` int(11) NOT NULL COMMENT '台账id',
+  `uid` int(11) NOT NULL COMMENT '审批人id',
+  `create_time` datetime DEFAULT NULL COMMENT '确认时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='多人协同确认表';
 
+--
+-- 表的结构 `zh_cooperation_pwd`
+--
+
+CREATE TABLE `zh_cooperation_pwd` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `ledger_id` int(11) NOT NULL COMMENT '台账id',
+  `uid` int(11) NOT NULL COMMENT '审批人id',
+  `pwd` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '密码',
+  `create_time` datetime DEFAULT NULL COMMENT '解锁时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='多人协同密码解锁表';
 
-ALTER TABLE `zh_ledger_cooperation` ADD `company` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '单位或备注名,筛选用' AFTER `sign_path`;
 
-ALTER TABLE `zh_advance_audit` 
+ALTER TABLE `zh_advance_audit`
 CHANGE COLUMN `type` `type` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '预付款类型,0为开工预付款,1为材料预付款,2为安全生产费预付款' ;
 
-ALTER TABLE `zh_advance_pay` 
+ALTER TABLE `zh_advance_pay`
 CHANGE COLUMN `type` `type` INT(1) NOT NULL DEFAULT '0' COMMENT '预付款类型,0为开工预付款,1为材料预付款,2位安全生产费预付款' ;
 
 -- 接口相关

+ 17 - 0
sql/update20210420.sql

@@ -0,0 +1,17 @@
+ALTER TABLE `zh_project_account` ADD `wx_unionid` VARCHAR(50) NULL COMMENT '微信绑定unionid(同一个开放平台共用)' AFTER `wx_openid`;
+
+--
+-- 报表归档表
+--
+CREATE TABLE `calculation`.`zh_rpt_archive` (
+  `archive_id` INT NOT NULL,
+  `prj_id` INT NULL,
+  `stage_id` INT NULL,
+  `content` VARCHAR(4000) NULL,
+  PRIMARY KEY (`archive_id`),
+  INDEX `PRJ_STG` (`prj_id` ASC, `stage_id` ASC))
+COMMENT = '报表归档表;\n只考虑项目id及期id,其他信息全部归入content';
+
+-- 项目设置-功能设置
+ALTER TABLE `zh_project`
+ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能设置(json.stringify)' AFTER `rpt_nature`;