Browse Source

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

TonyKang 4 years ago
parent
commit
4243e305f3

+ 11 - 8
app/controller/advance_controller.js

@@ -152,20 +152,23 @@ 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 || 0)), advancePayTotal, 10), 100);
+                const max_pr = ctx.helper.mul(ctx.helper.div(ctx.helper.sub(advancePayTotal, (prevAdvance && prevAdvance.prev_total_amount || 2)), advancePayTotal, 10), 100);
+
+                const isLimitMax = ctx.helper.round(max_pr, 2) === ctx.advance.pay_ratio;
                 // 特殊处理金额的显示(formatMoney)
                 let cur_amount,
                     prev_total_amount;
-                const s1 = parseFloat(ctx.advance.prev_amount).toString().split('.')[1];
-                const prev_amount = ctx.helper.formatMoney(ctx.advance.prev_amount, ',', s1 && s1.length || 0);
+                const s1 = parseFloat(ctx.advance.prev_amount).toString().split('.')[1] || '';
+                const prev_amount = ctx.helper.formatMoney(ctx.advance.prev_amount, ',', isLimitMax ? s1.length : 2);
                 if (status === uncheck || status === checkNo) {
-                    cur_amount = parseFloat(ctx.helper.round(ctx.advance.cur_amount, this.decimal)) || 0;
-                    const s2 = parseFloat(ctx.helper.add(cur_amount, ctx.advance.prev_amount)).toString().split('.')[1];
-                    prev_total_amount = ctx.helper.formatMoney(ctx.helper.add(cur_amount, ctx.advance.prev_amount), ',', s2 && s2.length || 0);
+                    // cur_amount = parseFloat(ctx.helper.round(ctx.advance.cur_amount, 2)) || 0;
+                    cur_amount = ctx.advance.cur_amount || 0;
+                    const s2 = parseFloat(ctx.helper.add(cur_amount, ctx.advance.prev_amount)).toString().split('.')[1] || '';
+                    prev_total_amount = ctx.helper.formatMoney(ctx.helper.add(cur_amount, ctx.advance.prev_amount), ',', isLimitMax ? s2.length : 2);
                 } else {
                     cur_amount = ctx.advance.cur_amount;
                     const s2 = parseFloat(ctx.advance.prev_total_amount).toString().split('.')[1];
-                    prev_total_amount = ctx.helper.formatMoney(ctx.advance.prev_total_amount, ',', s2 && s2.length || 0);
+                    prev_total_amount = ctx.helper.formatMoney(ctx.advance.prev_total_amount, ',', isLimitMax ? s2.length : 2);
                 }
 
                 renderData.isEdited = isEdited;
@@ -174,7 +177,7 @@ module.exports = app => {
                 renderData.prev_amount = prev_amount;
                 renderData.prev_total_amount = prev_total_amount;
                 renderData.max_pr = max_pr;
-                renderData.decimal = this.decimal;
+                renderData.decimal = 2;
                 renderData.advancePayTotal = advancePayTotal;
                 renderData.prevAdvance = prevAdvance;
                 await this.layout('advance/detail.ejs', renderData, 'advance/modal_audit.ejs');

+ 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;

+ 40 - 2
app/controller/stage_controller.js

@@ -193,6 +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);
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -329,8 +330,12 @@ module.exports = app => {
                             responseData.data.tags = await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id);
                             break;
                         case 'cooperation':
-                            responseData.data.cooperation = await this.ctx.service.ledgerCooperation.getValidData(
-                                ctx.tender.id, ctx.session.sessionUser.accountId);
+                            const uid = ctx.stage.curAuditor ? ctx.stage.curAuditor.aid : ctx.stage.status === auditConst.status.uncheck ? 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) : [];
+                            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;
                         case 'spec':
                             const spec = {zlj: JSON.parse(JSON.stringify(stdConst.zlj)), jrg: stdConst.jrg};
@@ -1806,6 +1811,39 @@ module.exports = app => {
                 ctx.redirect(ctx.request.header.referer);
             }
         }
+
+        /**
+         * 删除本次审批 - 期审批管理页面
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveCooperationData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = { err: 0, msg: '', data: {} };
+                switch (data.type) {
+                    case 'save-confirm':
+                        await ctx.service.cooperationConfirm.save(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 'del-confirm':
+                        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;
+                    default:
+                        throw '参数有误';
+                }
+
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
     }
 
     return StageController;

+ 6 - 7
app/lib/rptCustomData.js

@@ -18,9 +18,8 @@ const auditConst = require('../const/audit');
  *
  * define: {
  *     "title": "请选择汇总的标段", "type": "month/final/checked-final/stage",
- *    "defaultCompare": [1, 2, 3], // 结果按序 t_n_qty, t_n_tp
+ *    "defaultCompare": [1, 2, 3], // 结果按序 rn_qty, rn_tp
  *    "match": { "quality": [2, 3], "qty": "<0" }, // class根据变更类型过滤,qty根据数量过滤
- *    "selectCompare": [{ "key": "jl", "title": "驻地监理" }, ...] // 结果按key t_key_qty, t_key_tp
  *    "merge": true,
  * }
  * defaultCompare为默认选择的审批人,0为原报,1-N为1-N审
@@ -222,7 +221,7 @@ class jhHelper {
             let load = false;
             if (bills.pre_cd && bills.pre_cd.length > 0) load = true;
             for (const dc of gsDefine.defaultCompare) {
-                if (bills['t_' + dc + '_cd'] && bills['t_' + dc + '_cd'].length > 0) load = true;
+                if (bills['r' + dc + '_cd'] && bills['r' + dc + '_cd'].length > 0) load = true;
             }
             if (!load) continue;
             gsDefine.merge ? this._loadMergeResult(bills, this.prefixes) : this._loadResult(bills, this.prefixes);
@@ -243,7 +242,7 @@ class jhHelper {
         for (const dc of gsDefine.defaultCompare) {
             const auditor = auditors[dc];
             const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
-            loadData.push({ data: auditorStage, fields: ['qc_qty', 'qc_tp'], prefix: `t_${dc}_`, relaId: 'pid' });
+            loadData.push({ data: auditorStage, fields: ['qc_qty', 'qc_tp'], prefix: `r${dc}_`, relaId: 'pid' });
         }
         helper.assignRelaData(billsData, loadData);
         // 计算截止本期
@@ -266,7 +265,7 @@ class jhHelper {
         for (const dc of gsDefine.defaultCompare) {
             const auditor = auditors[dc];
             const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
-            loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `t_${dc}_`, relaId: 'pid' });
+            loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `r${dc}_`, relaId: 'pid' });
         }
         helper.assignRelaData(posData, loadData);
         posData.forEach(x => {
@@ -300,8 +299,8 @@ class jhHelper {
         const stageChangeDetail = await this.getCurChangeDetailData(tender.id, stage.id);
         for (const dc of gsDefine.defaultCompare) {
             const scd = helper.filterTimesOrderData(stageChangeDetail, ['lid', 'pid', 'cid', 'cbid'], auditors[dc].times, auditors[dc].order);
-            this._loadChangeDetail(billsIndex, scd, gsDefine, `t_${dc}_`);
-            this.prefixes.push(`t_${dc}_`);
+            this._loadChangeDetail(billsIndex, scd, gsDefine, `r${dc}_`);
+            this.prefixes.push(`r${dc}_`);
         }
         const finalChangeData = await this.getPreChangeDetailData(tender.id, stage.order);
         this._loadChangeDetail(billsIndex, finalChangeData, gsDefine, 'pre_');

BIN
app/public/images/wechat.png


+ 18 - 9
app/public/js/advance_audit.js

@@ -11,6 +11,7 @@
 $(document).ready(function () {
     autoFlashHeight()
 
+    const decimal = 2
     let oldVal = null
     let timer = null
     let oldSearchVal = null
@@ -217,6 +218,9 @@ $(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)
@@ -229,32 +233,37 @@ $(document).ready(function () {
         }
         // 本期金额转化
         if (type === 1) {
-            if (val > re_amount) {
+            if (val >= re_amount) {
                 // 限制不能超过最大值
                 val = re_amount
+                debugger
+                isLimitMax = true
             }
-            $(this).val(fixedToSub(val, decimal)) // 重新赋值限制只有两位小数
+            $(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))
-            cur_amount = ZhCalc.round(val, decimal)
+            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]
             // 截止本期金额文案更新
-            $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', total && total.length || 0) + '元')
+            $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
         } else {
             // 支付比例转化
+
             val = fixedToSub(val)
-            if (val.toFixed(1) === max.toFixed(1)) {
-                val = max
+            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 = ZhCalc.round(ZhCalc.mul(advancePayTotal, ZhCalc.div(val, 100)), decimal)
+            cur_amount = isLimitMax ? re_amount : ZhCalc.round(ZhCalc.mul(advancePayTotal, ZhCalc.div(val, 100), 10), decimal)
             pay_ratio = val
-            cur_m_input.val(parseFloat(cur_amount.toFixed(decimal)))
+            cur_m_input.val(cur_amount)
             const total = parseFloat(ZhCalc.add(cur_amount, p_amount)).toString().split('.')[1]
             // 截止本期金额文案更新
-            $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', total && total.length || 0) + '元')
+            $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
         }
         const data = {
             pay_ratio,

+ 26 - 1
app/public/js/change.js

@@ -274,7 +274,7 @@ $(document).ready(() => {
        if (status !== 0) {
            url += '/status/'+ status;
        }
-       window.location.href = url;
+       window.location.href = url + window.location.search;
     });
     // 不再显示首次使用
     $('#changeFirst').click(function () {
@@ -290,4 +290,29 @@ $(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('排序:变更令号');
+    }
+
+    $('#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);
+        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);
+        const link = window.location.origin + window.location.pathname + '?sort='+ $('#sort-radio input[name="paizhi"]:checked').val() + '&order=' + $(this).val();
+        window.location.href = link;
+    })
 });

+ 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) {

+ 43 - 1
app/public/js/path_tree.js

@@ -1181,6 +1181,48 @@ const createNewPathTree = function (type, setting) {
             this.loadingPwd = false;
         }
 
+        // 解锁相关
+        _loadOnlinePwd() {
+            const cacheArr = this.pwdList;
+            for (const ca of cacheArr) {
+                if (!ca) continue;
+                if (!ca.ledger_id || !ca.pwd) continue;
+
+                const p = this.pwd.find(x => {return x.ledger_id == ca.ledger_id});
+                if (p) p.check = p.pwd === ca.pwd;
+            }
+        }
+        // 确认相关
+        _loadOnlineConfirm() {
+            const cacheArr = this.confirmList;
+            for (const ca of cacheArr) {
+                if (!ca) continue;
+                if (!ca.ledger_id) continue;
+
+                const p = this.pwd.find(x => {return x.ledger_id == ca.ledger_id});
+                if (p) {
+                    p.confirm = true;
+                    p.confirm_time = ca.create_time;
+                }
+            }
+        }
+        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];
         }
@@ -1369,7 +1411,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;
         }
     }

+ 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'));
         }
     });

+ 81 - 5
app/public/js/stage.js

@@ -309,15 +309,37 @@ $(document).ready(() => {
     };
     const stagePos = new StagePosData(stagePosSetting);
 
+    const setCooperationSelectHtml = function () {
+        const selectHtml = [];
+        selectHtml.push('<option>全部</option>');
+        const cooName = _.uniqWith(_.map(stageTree.pwd, 'company'));
+        for (const i of cooName) {
+            selectHtml.push('<option>', i, '</option>');
+        }
+        $('#cooperationSelect').html(selectHtml.join(''));
+    };
+
     const reloadCooperationHtml = function () {
         const html = [];
-        for (const p of stageTree.pwd) {
+        const select = $('#cooperationSelect').val();
+        const list = select !== '全部' ? _.filter(stageTree.pwd, { company: select }) : stageTree.pwd;
+        for (const p of list) {
             if (!p.node) continue;
-            html.push('<tr>', `<td>${p.node.code}</td>`, `<td>${p.node.name}</td>`);
-            html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
+            if (p.confirm) {
+                html.push(`<tr class="text-success">`);
+            } else {
+                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>');
+            }
+            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>');
             html.push('</tr>');
         }
         $('#cooperationList').html(html.join(''));
+
     };
 
     class Changes {
@@ -1924,9 +1946,11 @@ $(document).ready(() => {
         treeCalc.calculateAll(stageTree);
         // 加载解锁相关
         if (result.cooperation) {
-            stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
+            // stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
+            stageTree.loadOnlinePwd(result.cooperation, result.cooperationPwd, result.cooperationConfirm);
             $('#cooperationCount').html(stageTree.pwd.length || '');
             if (stageTree.pwd.length > 0) $('#cooperationCount').parent().show();
+            setCooperationSelectHtml();
             reloadCooperationHtml();
         }
         for (const t of result.tags) {
@@ -3982,6 +4006,13 @@ $(document).ready(() => {
     });
     $('[name=stage-start]').submit(function (e) {
         if (checkAuditorFrom()) {
+            // 再检查多人协同确认情况
+            const list = stageTree.pwd.find(x => {return !x.confirm });
+            if(list) {
+                toastr.error('请检查多人协同确认情况再上报');
+                $('#hide-all').hide();
+                return false;
+            }
             $(this).parent().parent().parent().modal('hide');
             dataChecker.checkAndPost(this.action, {});
             $('#hide-all').hide();
@@ -3989,6 +4020,13 @@ $(document).ready(() => {
         return false;
     });
     $('#audit-check0').submit(function (e) {
+        // 再检查多人协同确认情况
+        const list = stageTree.pwd.find(x => {return !x.confirm });
+        if(list) {
+            toastr.error('请检查多人协同确认情况再审批通过');
+            $('#hide-all').hide();
+            return false;
+        }
         const checkType = parseInt($('[name=checkType]').val());
         const data = {
             opinion: $(`${'#sp-done'}`).find('[name=opinion]').val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '),
@@ -4073,6 +4111,10 @@ $(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;
+            });
             SpreadJsObj.reloadRowsReadonly(slSpread.getActiveSheet(), refresh);
             stagePosSpreadObj.loadCurPosData();
             $('#unlock').modal('hide');
@@ -4082,5 +4124,39 @@ $(document).ready(() => {
             $('.invalid-feedback', '#unlock').show();
             $('.alert-warning', '#unlock').show();
         }
-    })
+    });
+    $('#cooperationSelect').change(function () {
+        reloadCooperationHtml();
+    });
+    // 确认
+    $('body').on('click', '[name=ledger-confirm]', function() {
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+        // 修改线上
+        postData(window.location.pathname + '/save/cooperation', { type: 'save-confirm', postData: { ledger_id: lid } }, function (result) {
+            p.confirm = true;
+            p.confirm_time = new Date();
+            stageTree.confirmList = result.cooperationConfirm;
+            reloadCooperationHtml();
+        });
+    });
+
+    // 确认
+    $('body').on('click', '[name=ledger-unconfirm]', function() {
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+        // 修改线上
+        postData(window.location.pathname + '/save/cooperation', { type: 'del-confirm', postData: { ledger_id: lid } }, function (result) {
+            p.confirm = false;
+            p.confirm_time = null;
+            stageTree.confirmList = result.cooperationConfirm;
+            reloadCooperationHtml();
+        });
+    });
 });

+ 2 - 0
app/router.js

@@ -235,6 +235,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/valid-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.searchValidChange');
     app.post('/tender/:id/measure/stage/:order/use-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.useChange');
     app.post('/tender/:id/measure/stage/:order/check', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.check');
+    app.post('/tender/:id/measure/stage/:order/save/cooperation', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.saveCooperationData');
 
     // 计量附件
     app.post('/tender/:id/measure/stage/:order/upload/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.uploadFile');
@@ -328,6 +329,7 @@ module.exports = app => {
     app.post('/tender/report_api/updateArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.updateReportArchive');
     app.post('/tender/report_api/removeArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.removeReportArchive');
 
+
     // 变更管理
     app.get('/tender/:id/change', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.index');
     app.get('/tender/:id/change/status/:status', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.status');

+ 6 - 3
app/service/advance.js

@@ -34,17 +34,20 @@ module.exports = app => {
             this.sqlBuilder.orderBy = [['order', 'desc']];
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
             const advance = await this.db.query(sql, sqlParam);
+            let isLastItem = false;
             for (const item of advance) {
                 let s1,
                     s3;
                 const s2 = item.prev_amount.toString().split('.')[1];
+                isLastItem = this.ctx.helper.add(item.cur_amount, item.prev_amount) === advancePayTotal;
                 item.pay_ratio = this.ctx.helper.mul(this.ctx.helper.div(item.cur_amount, advancePayTotal), 100, 2) || 0;
                 if (item.status === auditConst.status.uncheck || item.status === auditConst.status.checkNo) {
-                    const cur_amount = item.cur_amount && this.ctx.helper.round(item.cur_amount, decimal) || 0;
+                    const cur_amount = item.cur_amount || 0;
                     s1 = parseFloat(cur_amount).toString().split('.')[1];
                     s3 = parseFloat(this.ctx.helper.add(cur_amount, item.prev_amount)).toString().split('.')[1];
-                    item.cur_amount = this.ctx.helper.formatMoney(cur_amount, ',', s1 && s1.length || 0);
-                    item.prev_total_amount = this.ctx.helper.formatMoney(this.ctx.helper.add(cur_amount, item.prev_amount), ',', s3 && s3.length || 0);
+                    isLastItem && (s3 = advancePayTotal.toString().split('.')[1]);
+                    item.cur_amount = this.ctx.helper.formatMoney(cur_amount, ',', isLastItem ? s1 && s1.length || 0 : 2);
+                    item.prev_total_amount = this.ctx.helper.formatMoney(this.ctx.helper.add(cur_amount, item.prev_amount), ',', isLastItem ? s3 && s3.length || 0 : 2);
                 } else {
                     s1 = item.cur_amount && item.cur_amount.toString().split('.')[1];
                     s3 = item.prev_total_amount.toString().split('.')[1];

+ 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);

+ 59 - 0
app/service/cooperation_confirm.js

@@ -0,0 +1,59 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/6/1
+ * @version
+ */
+
+module.exports = app => {
+    class CooperationConfirm extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'cooperation_confirm';
+        }
+
+        async save(data) {
+            const info = await this.getDataByCondition({ tid: this.ctx.tender.id, sid: this.ctx.stage.id, times: this.ctx.stage.times, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+            if (info) {
+                const updateData = {
+                    id: info.id,
+                    create_time: new Date(),
+                };
+                return await this.db.update(this.tableName, updateData);
+            }
+            const insertData = {
+                tid: this.ctx.tender.id,
+                sid: this.ctx.stage.id,
+                times: this.ctx.stage.times,
+                uid: this.ctx.session.sessionUser.accountId,
+                ledger_id: data.ledger_id,
+                create_time: new Date(),
+            };
+            return await this.db.insert(this.tableName, insertData);
+        }
+
+        async del(data) {
+            return await this.db.delete(this.tableName, { tid: this.ctx.tender.id, sid: this.ctx.stage.id, times: this.ctx.stage.times, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+        }
+
+        async getValidData(tid, sid, times, uid) {
+            const condition = { where: { tid, sid, times, uid } };
+            // if (uid) {
+            //     condition.where.uid = uid;
+            //     condition.colums = ['ledger_id', 'pwd'];
+            // }
+            return await this.getAllDataByCondition(condition);
+        }
+    }
+
+    return CooperationConfirm;
+};

+ 55 - 0
app/service/cooperation_pwd.js

@@ -0,0 +1,55 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/6/1
+ * @version
+ */
+
+module.exports = app => {
+    class CooperationPwd extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'cooperation_pwd';
+        }
+
+        async save(data) {
+            const info = await this.getDataByCondition({ tid: this.ctx.tender.id, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+            if (info) {
+                const updateData = {
+                    id: info.id,
+                    pwd: data.pwd,
+                    create_time: new Date(),
+                };
+                return await this.db.update(this.tableName, updateData);
+            }
+            const insertData = {
+                tid: this.ctx.tender.id,
+                uid: this.ctx.session.sessionUser.accountId,
+                ledger_id: data.ledger_id,
+                pwd: data.pwd,
+                create_time: new Date(),
+            };
+            return await this.db.insert(this.tableName, insertData);
+        }
+
+        async getValidData(tid, uid) {
+            const condition = { where: { tid } };
+            if (uid) {
+                condition.where.uid = uid;
+                condition.colums = ['ledger_id', 'pwd'];
+            }
+            return await this.getAllDataByCondition(condition);
+        }
+    }
+
+    return CooperationPwd;
+};

+ 2 - 2
app/service/stage_pos.js

@@ -109,7 +109,7 @@ module.exports = app => {
         async getLastestStageData2(tid, sid, where) {
             const filterSql = this._getPosFilterSql(where);
             const sql = 'SELECT id, tid, sid, pid, lid, contract_qty, qc_qty, postil, `times`, `order`, `contract_expr`' +
-                '  FROM ' + this.tableName +
+                '  FROM ' + this.departTableName(tid) +
                 '  WHERE tid = ? And sid = ? ' + filterSql;
             const sqlParam = [tid, sid];
             const stagePos = await this.db.query(sql, sqlParam);
@@ -118,7 +118,7 @@ module.exports = app => {
         async getAuditorStageData2(tid, sid, times, order, where) {
             const filterSql = this._getPosFilterSql(where);
             const sql = 'SELECT id, tid, sid, pid, lid, contract_qty, qc_qty, postil, `times`, `order`, `contract_expr`' +
-                '  FROM ' + this.tableName +
+                '  FROM ' + this.departTableName(tid) +
                 '  WHERE tid = ? And sid = ? And (`times` < ? OR (`times` = ? AND `order` <= ?)) ' + filterSql;
             const sqlParam = [tid, sid, times, times, order];
             const stagePos = await this.db.query(sql, sqlParam);

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

@@ -22,6 +22,7 @@
                         <thead>
                             <tr>
                                 <th colspan="4" class="text-center">
+                                    <!-- 签约<%- advance.type === auditConst.type.start ? '开工' : '材料' %>预付款:<%- ctx.helper.formatMoney(advancePayTotal, ',', 2) %> -->
                                     签约<%- advance.type === auditConst.type.start ? '开工' : '材料' %>预付款:<%- ctx.helper.formatMoney(advancePayTotal, ',', parseFloat(advancePayTotal).toString().split('.')[1] && parseFloat(advancePayTotal).toString().split('.')[1].length || 0) %>
                                 </th>
@@ -348,7 +349,7 @@
 </div>
 <script>
     const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
-    const decimal = parseInt('<%- decimal %>');
+    // const decimal = parseInt('<%- decimal %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
     const advance = JSON.parse(unescape('<%- escape(JSON.stringify(advance)) %>'));
     const prevAdvance = JSON.parse(unescape('<%- escape(JSON.stringify(prevAdvance)) %>'));

+ 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">
+                        <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>

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

@@ -615,6 +615,7 @@
     // 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 %>;
 </script>
 <style>
 

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

@@ -460,17 +460,26 @@
 </div>
 <!--多人协同-->
 <div class="modal fade" id="cooperation" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
             <div class="modal-header">
                 <h5 class="modal-title">多人协同</h5>
             </div>
             <div class="modal-body">
-                <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
+                <% if (coopwd) { %>
+                    <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
+                <% } else { %>
+                    <div class="alert alert-warning">以下项目节及其子项(灰色项)未确认审批。</div>
+                <% } %>
+                <div class="mb-2">
+                    <select class="form-control form-control-sm w-25" id="cooperationSelect">
+                        <option>全部</option>
+                    </select>
+                </div>
                 <div class="modal-height-300">
                     <table class="table table-hover table-bordered">
                         <thead>
-                        <tr><th>项目节编号</th><th>项目节名称</th><th>解锁  </th></tr>
+                        <tr><th>项目节编号</th><th>项目节名称</th><% if (coopwd) { %><th>解锁  </th><% } %><th>单位/协同人名称</th><th>确认数据</th></tr>
                         </thead>
                         <tbody id="cooperationList">
                         </tbody>
@@ -479,7 +488,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-sm btn-primary">确认</button>
+                <!--<button type="button" class="btn btn-sm btn-primary">确认</button>-->
             </div>
         </div>
     </div>

+ 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">

+ 14 - 0
sql/update.sql

@@ -18,3 +18,17 @@ ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci N
 
 
 ALTER TABLE `zh_ledger_cooperation` ADD `company` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '单位或备注名,筛选用' AFTER `sign_path`;
+
+ALTER TABLE `zh_advance_audit` 
+CHANGE COLUMN `type` `type` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '预付款类型,0为开工预付款,1为材料预付款,2为安全生产费预付款' ;
+
+ALTER TABLE `zh_advance_pay` 
+CHANGE COLUMN `type` `type` INT(1) NOT NULL DEFAULT '0' COMMENT '预付款类型,0为开工预付款,1为材料预付款,2位安全生产费预付款' ;
+
+-- 接口相关
+ALTER TABLE `zh_tender`
+ADD COLUMN `s2b_gxby_check`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '工序报验-检查计量' AFTER `copy_id`,
+ADD COLUMN `s2b_gxby_limit`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '限制上报' AFTER `s2b_gxby_check`,
+ADD COLUMN `s2b_dagl_check`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '档案管理-检查计量' AFTER `s2b_gxby_limit`,
+ADD COLUMN `s2b_dagl_limit`  tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '档案管理-限制上报' AFTER `s2b_dagl_check`;
+