浏览代码

1. 合同支付,启用&停用、计提期限相关
2. 协同&多人协同,台账节点操作唯一相关

MaiXinRong 6 月之前
父节点
当前提交
2526190267

+ 4 - 4
app/base/base_tree_service.js

@@ -73,7 +73,7 @@ class TreeService extends Service {
             this.initSqlBuilder();
             this.sqlBuilder.setAndWhere(this.setting.mid, {
                 operate: '=',
-                value: mid,
+                value: this.db.escape(mid),
             });
             this.sqlBuilder.setAndWhere(this.setting.level, {
                 operate: '<=',
@@ -335,7 +335,7 @@ class TreeService extends Service {
         const cacheKey = this.setting.keyPre + mid;
         let maxId = this.setting.cacheKey ? parseInt(await this.cache.get(cacheKey)) : undefined;
         if (!maxId) {
-            const sql = 'SELECT Max(??) As max_id FROM ?? Where ' + this.setting.mid + ' = ?';
+            const sql = 'SELECT Max(??) As max_id FROM ?? Where ' + this.db.escape(this.setting.mid) + ' = ?';
             const sqlParam = [this.setting.kid, this.tableName, mid];
             const queryResult = await this.db.queryOne(sql, sqlParam);
             maxId = queryResult.max_id || 0;
@@ -794,7 +794,7 @@ class TreeService extends Service {
                 selfOperate: orderInc > 0 ? '+' : '-',
             });
             this.sqlBuilder.setAndWhere(this.setting.mid, {
-                value: select[this.setting.mid],
+                value: this.db.escape(select[this.setting.mid]),
                 operate: '=',
             });
             this.sqlBuilder.setAndWhere(this.setting.pid, {
@@ -820,7 +820,7 @@ class TreeService extends Service {
             const newSubStr = this.db.escape(select[this.setting.kid] + '-');
             const sqlArr = [];
             sqlArr.push('Update ?? SET `' + this.setting.fullPath + '` = Replace(`' + this.setting.fullPath + '`,' + oldSubStr + ',' + newSubStr + ') Where');
-            sqlArr.push('(`' + this.setting.mid + '` = ' + select[this.setting.mid] + ')');
+            sqlArr.push('(`' + this.setting.mid + '` = ' + this.db.escape(select[this.setting.mid]) + ')');
             sqlArr.push(' And (');
             for (const data of nexts) {
                 sqlArr.push('`' + this.setting.fullPath + '` Like ' + this.db.escape(data[this.setting.fullPath] + '%'));

+ 1 - 0
app/const/tender_info.js

@@ -200,6 +200,7 @@ const defaultInfo = {
     },
     fun_rela: {
         hintOver: true,
+        repel: false,
         stage_change: {
             minusNoValue: true,
         },

+ 6 - 0
app/controller/pay_controller.js

@@ -94,9 +94,15 @@ module.exports = app => {
                 // await this.ctx.service.phasePayDetail.calculateSave(ctx.phasePay);
                 const pays = await this.ctx.service.phasePayDetail.getDetailData(ctx.phasePay);
                 const calcBase = this.ctx.service.phasePay.getPhasePayCalcBase(ctx.phasePay, ctx.tender.info);
+                const projectFunInfo = await this.ctx.service.project.getFunRela(ctx.session.sessionProject.id);
+                const lastStage = await this.ctx.service.stage.getLastestCompleteStage(ctx.tender.id);
                 const renderData = {
                     pays,
                     calcBase,
+                    lockPayExpr: projectFunInfo.lockPayExpr,
+                    auditConst: audit.common,
+                    deadlineType: this.ctx.service.phasePayDetail.deadlineType,
+                    maxStageOrder: lastStage.order,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.phasePay.detail)
                 };
                 await this.layout('phase_pay/detail.ejs', renderData, 'phase_pay/detail_modal.ejs');

+ 6 - 0
app/controller/stage_controller.js

@@ -375,6 +375,12 @@ module.exports = app => {
                             const assistLocked = await ctx.service.stageAuditAss.getLockedId(ctx.stage);
                             const auditLocked = await ctx.service.stageAudit.getLockedId(ctx.stage);
                             responseData.data.locked = [...assistLocked, ...auditLocked];
+                            if (ctx.tender.info.fun_rela.repel && !ctx.stage.readOnly) {
+                                const assistComfirm = await ctx.service.stageAuditAss.getComfirmLockedId(ctx.stage);
+                                const auditComfirm = ctx.stage.curAuditors && ctx.stage.curAuditors.length > 0 && ctx.stage.curAuditors[0].audit_type === auditType.key.union
+                                    ? await ctx.service.stageAuditAss.getComfirmLockedId(ctx.stage) : [];
+                                responseData.data.locked.push(...assistComfirm, ...auditComfirm);
+                            }
                             break;
                         case 'pos':
                             if (hpack) {

+ 226 - 18
app/public/js/phase_pay_detail.js

@@ -43,8 +43,50 @@ $(document).ready(() => {
             },
             isGatherValid: function(data) {
                 return !data.pay_type && (!data.children || data.children.length === 0);
+            },
+            isOwner: function(data) {
+                return data.create_user_id === userID;
+            },
+            isFinish: function(data) {
+                return data.pre_finish;
+            },
+            isYB: function() {
+                return userID === phasePay.create_user_id;
+            },
+            isOld: function(data) {
+                return data.phase_id !== data.create_phase_id;
+            },
+            isLock: function (data) {
+                const result = !!lockPayExpr && payUtils.check.isStarted(data) && payCalc.hasBase(data.expr);
+                return result;
+            },
+            tpReadOnly: function(data) {
+                return payUtils.check.isYf(data) || payUtils.check.isLock(data);
+            },
+            startTpReadOnly: function(data) {
+                if (payUtils.check.isOld(data)) {
+                    return payUtils.check.isStarted(data) || !payUtils.check.isYB(data) || payUtils.check.isLock(data);
+                } else {
+                    return payUtils.check.isWC(data) || payUtils.check.isSF(data) || payUtils.check.isYf(data) || !(payUtils.check.isOwner(data) || payUtils.check.isYB());
+                }
             }
-        }
+        },
+        menuVisible: {
+            pause: function (data) {
+                if (payUtils.check.isOld(data)) {
+                    return payUtils.check.isYB();
+                } else {
+                    return payUtils.check.isOwner(data) || payUtils.check.isYB();
+                }
+            },
+            deadline: function (data) {
+                if (payUtils.check.isOld(data)) {
+                    return !payUtils.check.isFinish(data) && payUtils.check.isYB();
+                } else {
+                    return payUtils.check.isOwner(data) || payUtils.check.isYB();
+                }
+            }
+        },
     };
     const payCalc = (function (b, a) {
         class PayCalc {
@@ -61,6 +103,13 @@ $(document).ready(() => {
                 this.orderReg = /f\d+/ig;
                 this.nodeReg = /<<[a-z0-9\-]+>>/ig;
             }
+            hasBase(expr) {
+                if (!expr) return false;
+                for (const b of this.bases) {
+                    if (data.expr.indexOf(b.code) >= 0) return true;
+                }
+                return false;
+            }
             trans2OrderExpr(expr, payTree) {
                 const nodeParam = expr.match(this.nodeReg);
                 if (nodeParam) {
@@ -283,8 +332,8 @@ $(document).ready(() => {
                         // if (payNode.pre_finish) return [false, '已达扣款限额,请勿修改'];
                         // const value = expr ? payCalc.calculateExpr(expr) : num;
                         // if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
-                        // data.rprice = num;
-                        // data.rexpr = expr;
+                        // data.range_tp = num;
+                        // data.range_expr = expr;
                         return [false, '已经开始使用,请勿修改扣款限额'];
                     }
                 } else {
@@ -458,31 +507,34 @@ $(document).ready(() => {
                 const preNode = payTree.getPreSiblingNode(select);
                 setObjEnable($('a[name=base-opr][type=add]'), !readOnly && !payUtils.check.isSf(select) && !payUtils.check.isYf(select));
                 const delValid = !payUtils.check.isFixed(select) && !payUtils.check.isStarted(select);
-                setObjEnable($('a[name=base-opr][type=del]'), !readOnly && delValid);
+                setObjEnable($('a[name=base-opr][type=delete]'), !readOnly && delValid);
                 setObjEnable($('a[name=base-opr][type=up-move]'), !readOnly && !payUtils.check.isFixed(select) && preNode);
                 setObjEnable($('a[name=base-opr][type=down-move]'), !readOnly && !payUtils.check.isFixed(select) && !payTree.isLastSibling(select));
             },
             loadExprToInput: function() {
                 const sel = sheet.getSelections()[0];
                 const col = sheet.zh_setting.cols[sel.col];
-                const data = SpreadJsObj.getSelectObject(this.sheet);
-                if (data) {
+                const data = SpreadJsObj.getSelectObject(sheet);
+                if (data && (!data.children || data.children.length === 0)) {
                     if (col.field === 'tp') {
-                        $('#expr').val(data.expr).attr('field', 'expr').attr('org', data.expr)
-                            .attr('readOnly', readOnly|| payCol.readOnly.tp(data));
-                    } else if (col.field === 'stage_tp') {
-                        $('#expr').val(data.start_expr).attr('field', 'start_expr').attr('org', data.start_expr)
-                            .attr('readOnly', readOnly|| payCol.readOnly.sprice(data) || payBase.isYF(data));
-                    } else if (col.field === 'rprice') {
-                        $('#expr').val(data.range_expr).attr('field', 'range_expr').attr('org', data.range_expr)
-                            .attr('readOnly', readOnly|| payCol.readOnly.rprice(data) || payBase.isYF(data));
+                        const expr = payCalc.trans2OrderExpr(data.expr, payTree);
+                        $('#pay-expr').val(expr).attr('field', 'expr').attr('org', expr)
+                            .attr('readOnly', readOnly|| payUtils.check.tpReadOnly(data));
+                    } else if (col.field === 'start_tp') {
+                        const expr = payCalc.trans2OrderExpr(data.start_expr, payTree) || data.start_tp;
+                        $('#pay-expr').val(expr).attr('field', 'start_expr').attr('org', expr)
+                            .attr('readOnly', readOnly|| payUtils.check.startTpReadOnly(data) || payUtils.check.isYf(data));
+                    } else if (col.field === 'range_tp') {
+                        const expr = payCalc.trans2OrderExpr(data.range_expr, payTree);
+                        $('#pay-expr').val(expr).attr('field', 'range_expr').attr('org', expr)
+                            .attr('readOnly', readOnly|| payUtils.check.rangeTpReadOnly(data) || payUtils.check.isYf(data));
                     } else {
-                        $('#expr').val('').attr('readOnly', true);
+                        $('#pay-expr').val('').attr('readOnly', true);
                     }
-                    $('#expr').attr('data-row', sel.row);
+                    $('#pay-expr').attr('data-row', sel.row);
                 } else {
-                    $('#expr').val('').attr('readOnly', true);
-                    $('#expr').removeAttr('data-row');
+                    $('#pay-expr').val('').attr('readOnly', true);
+                    $('#pay-expr').removeAttr('data-row');
                 }
             },
             refreshTree: function (data) {
@@ -757,6 +809,162 @@ $(document).ready(() => {
             $('#reload-calc-base').click(function() {
                 payEvent.reloadCalcBase();
             });
+
+            const deadlineObj = {
+                payNode: null,
+                refreshHint: function() {
+                    const dlType = $('[name=dl-type]:checked').val();
+                    const dt = deadlineType[dlType];
+                    if (dlType && dt) {
+                        const dlValue = $('#dl-value').val();
+                        $('#range-hint').text(`当 ${dt.name} >= ${dlValue} 时 `);
+                        $('#dl-hint').show();
+                    } else {
+                        $('#dl-hint').hide();
+                    }
+                },
+                initView: function(data) {
+                    this.payNode = data;
+                    $('#dl-pay-name').html(data.name);
+                    // 模式
+                    if (data.dl_type) {
+                        $('[name=dl-type][value=' + data.dl_type +']')[0].checked = true;
+                    } else {
+                        $('#dl-type-none')[0].checked = true;
+                    }
+                    $('#dl-value').val(data.dl_value);
+                    this.refreshHint();
+                },
+                getDlCount: function() {
+                    try {
+                        const result = parseInt($('#dl-value').val());
+                        if (result <= 0) throw '限制值请输入正整数';
+                        return result;
+                    } catch (err) {
+                        toastr.warning('限制值请输入正整数');
+                        return 0;
+                    }
+                },
+                getDlTp: function() {
+                    try {
+                        const result = parseFloat($('#dl-value').val());
+                        return result;
+                    } catch (err) {
+                        toastr.warning('限制值请输入数值');
+                        return 0;
+                    }
+                },
+                getUpdateData: function() {
+                    const result = { postType: 'update', postData: { id: this.payNode.id } };
+                    result.postData.dl_type = $('[name=dl-type]:checked').val();
+                    if (result.postData.dl_type) {
+                        if (result.postData.dl_type === deadlineType.phaseCount.key) {
+                            result.postData.dl_value = this.getDlCount();
+                            if (result.postData.dl_value < phasePay.phase_order) {
+                                toastr.warning(`已计量至第${phasePay.phase_order}期,计提期限不可小于该期`);
+                                return null;
+                            }
+                        } else if (result.postData.dl_type === deadlineType.stageCount.key) {
+                            result.postData.dl_value = this.getDlCount();
+                            if (result.postData.dl_value < maxStageOrder) {
+                                toastr.warning(`已计量至第${maxStageOrder}期,计提期限不可小于该期`);
+                                return null;
+                            }
+                        } else {
+                            result.postData.dl_value = this.getDlTp();
+                            const dt = deadlineType[result.postData.dl_type];
+                            if (!dt) {
+                                toastr.warning('限制模式错误,请刷新页面重试');
+                                return null;
+                            }
+                            const compareValue = payCalc.addBase[`pre_${dt.key}_tp`];
+                            if (result.postData.dl_type < compareValue) {
+                                toastr.warning(`截止上期,${dt.name}已计量${compareValue},计提期限不可小于该值`);
+                                return null;
+                            }
+                        }
+                    } else {
+                        result.postData.dl_value = 0;
+                    }
+                    return result;
+                },
+            };
+            $('[name=dl-type]').change(deadlineObj.refreshHint);
+            $('#dl-value').change(deadlineObj.refreshHint);
+            $('#deadline-ok').click(function() {
+                const updateData = deadlineObj.getUpdateData();
+                if (!updateData) return;
+                postData('update', updateData, function(result) {
+                    payEvent.reloadPays(result.reload);
+                    $('#deadline').modal('hide');
+                });
+            });
+
+            // 右键菜单
+            $.contextMenu({
+                selector: '#pay-spread',
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, spread);
+                    return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+                },
+                items: {
+                    'start': {
+                        name: '启用',
+                        icon: 'fa-play',
+                        callback: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const data = {
+                                postType: 'update',
+                                postData: { id: select.id, is_pause: 0 }
+                            };
+                            // 更新至服务器
+                            postData('update', data, function (result) {
+                                payEvent.reloadPays(result.reload);
+                            });
+                        },
+                        visible: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            return (!select.children || select.children.length ===0) && !readOnly  && select.is_pause && payUtils.menuVisible.pause(select);
+                        }
+                    },
+                    'stop': {
+                        name: '停用',
+                        icon: 'fa-pause',
+                        callback: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const data = {
+                                postType: 'update',
+                                postData: { id: select.id, is_pause: 1 }
+                            };
+                            // 更新至服务器
+                            postData('update', data, function (result) {
+                                payEvent.reloadPays(result.reload);
+                            });
+                        },
+                        visible: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            return (!select.children || select.children.length === 0) && !readOnly && !select.is_pause && payUtils.menuVisible.pause(select);
+                        },
+                    },
+                    'setDeadline': {
+                        name: '设置计提期限',
+                        icon: 'fa-clipboard',
+                        callback: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            if (select.range_tp) {
+                                deadlineObj.initView(select);
+                                $('#deadline').modal('show');
+                            } else {
+                                toastr.warning('计提期限用于达到条件时,即刻计量至付(扣)款限额,应先设置付(扣)款限额');
+                            }
+                        },
+                        visible: function (key, opt) {
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            return (!select.children || select.children.length === 0) && !readOnly && payUtils.menuVisible.deadline(select);
+                        }
+                    },
+                }
+            });
         }
 
         return { spread, sheet, payTree, loadDatas: payEvent.reloadPays }

+ 17 - 14
app/service/phase_pay_detail.js

@@ -23,11 +23,12 @@ const defaultPays = [
 ];
 const TreeService = require('../base/base_tree_service');
 const Ledger = require('../lib/ledger');
-const deallineType = {
-    phaseCount: 'phaseCount',
-    stageCount: 'stageCount',
-    gather: 'gather',
-    contract: 'contract',
+const deadlineType = {
+    phaseCount: { key: 'phaseCount', type: '计量期数', name: '合同支付期数' },
+    stageCount: { key: 'stageCount', type: '计量期数', name: '计量期数' },
+    gather: { key: 'gather', type: '计量金额', name: '累计完成金额' },
+    contract: { key: 'contract', type: '计量金额', name: '累计合同金额' },
+    qc: { key: 'qc', type: '计量金额', name: '累计变更金额' },
 };
 const math = require('mathjs');
 math.config({
@@ -167,15 +168,16 @@ class PayCalculator {
      */
     _checkDeadline(pay) {
         switch (pay.dl_type) {
-            case deallineType.phaseCount:
+            case deadlineType.phaseCount.key:
                 return this.phasePay.phase_order >= pay.dl_value;
-            case deallineType.stageCount:
+            case deadlineType.stageCount.key:
                 const maxStageOrder = this.ctx.helper._.max(this.phasePay.rela_stage.map(x => { return x.stage_order; }));
                 return maxStageOrder >= pay.dl_value;
-            case deallineType.gather:
-            case deallineType.contract:
-                const deallineTp = this.add[pay.dl_type + '_tp'];
-                return deallineTp >= pay.dl_value;
+            case deadlineType.gather.key:
+            case deadlineType.contract.key:
+            case deadlineType.qc.key:
+                const deadlineTp = this.addBase[pay.dl_type + '_tp'];
+                return deadlineTp >= pay.dl_value;
             default :
                 return false;
         }
@@ -329,6 +331,7 @@ class PhasePayDetail extends TreeService {
             uuid: true,
         });
         this.tableName = 'phase_pay_detail';
+        this.deadlineType = deadlineType;
     }
 
     getMasterKey(phasePay) {
@@ -551,7 +554,7 @@ class PhasePayDetail extends TreeService {
         const datas = data instanceof Array ? data : [data];
         for (const d of datas) {
             for (const prop in d) {
-                if (calcField.indexOf(prop) > 0) return true;
+                if (calcField.indexOf(prop) >= 0) return true;
             }
         }
         return false;
@@ -566,7 +569,7 @@ class PhasePayDetail extends TreeService {
                 const node = orgData.find(x => { return x.id === d.id; });
                 if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
                 const ud = this._filterValidField(node.id, d);
-                ud.update_user_id = ctx.session.sessionUser.accountId;
+                ud.update_user_id = this.ctx.session.sessionUser.accountId;
                 updateDatas.push(ud);
             }
             if (updateDatas.length > 0) await this.db.updateRows(this.tableName, updateDatas);
@@ -574,7 +577,7 @@ class PhasePayDetail extends TreeService {
             const node = await this.getDataById(data.id);
             if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
             const updateData = this._filterValidField(node.id, data);
-            updateData.update_user_id = ctx.session.sessionUser.accountId;
+            updateData.update_user_id = this.ctx.session.sessionUser.accountId;
             await this.db.update(this.tableName, updateData);
         }
     }

+ 4 - 0
app/service/stage_audit.js

@@ -2363,6 +2363,10 @@ module.exports = app => {
         async getLockedId(stage) {
             return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, audit_locked: 1 } });
         }
+
+        async getComfirmLockedId(stage) {
+            return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, order: stage.curOrder, status: auditConst.status.checked } });
+        }
     }
 
     return StageAudit;

+ 8 - 0
app/service/stage_audit_ass.js

@@ -232,6 +232,14 @@ module.exports = app => {
             return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, locked: 1 } });
         }
 
+        async getComfirmLockedId(stage) {
+            if (stage.curAuditors && stage.curAuditors.length > 0) {
+                return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, user_id: stage.curAuditors.map(x => { return x.aid; }), confirm: 1}});
+            } else {
+                return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, user_id: stage.user_id, confirm: 1}});
+            }
+        }
+
         async getReportData(sid, stimes) {
             const sql = 'SELECT saa.tid, saa.sid, saa.times, saa.user_id, saa.ass_ledger_id, saa.ass_user_id, saa.name, saa.company, saa.role, pa.sign_path, pa.stamp_path' +
                 `   FROM ${this.tableName} saa LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON saa.ass_user_id = pa.id` +

+ 5 - 2
app/view/phase_pay/detail.ejs

@@ -23,7 +23,7 @@
                 <% if (!ctx.phasePay.readOnly) { %>
                 <button class="btn btn-sm btn-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="计算全部" id="calc-all"><i class="fa fa-play"></i></button>
                 <% } %>
-                <% if (!ctx.phasePay.audit_status === auditConst.status.uncheck) { %>
+                <% if (ctx.phasePay.audit_status === auditConst.status.uncheck) { %>
                 <button class="btn btn-sm btn-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="刷新基数" id="reload-calc-base"><i class="fa fa-repeat"></i></button>
                 <% } %>
             </div>
@@ -66,9 +66,12 @@
     <img src="/public/images/file_clip_hover.png" id="rela-file-hover" />
 </div>
 <script>
+    const lockPayExpr = <%- lockPayExpr %>;
+    const phasePay = JSON.parse('<%- JSON.stringify(ctx.phasePay) %>');
     const readOnly = <%- ctx.phasePay.readOnly %>;
+    const maxStageOrder = <%- maxStageOrder %>;
     const details = JSON.parse('<%- JSON.stringify(pays) %>');
     const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');
     const addBase = JSON.parse('<%- JSON.stringify(ctx.phasePay.calc_base) %>');
-    const throusanth = <%- ctx.tender.info.display.thousandth %>;
+    const deadlineType = JSON.parse('<%- JSON.stringify(deadlineType) %>');
 </script>

+ 59 - 0
app/view/phase_pay/detail_modal.ejs

@@ -0,0 +1,59 @@
+<!--设置计提期限-->
+<div class="modal fade" id="deadline" 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">
+                <p>请设置付(扣)款项 <b id="dl-pay-name">本期应付</b> 的计提期限</p>
+                <div class="form-group">
+                    <label for="formGroupExampleInput">限制模式为:</label>
+                    <div>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="dl-type-none" value="none">
+                            <label class="form-check-label" for="dl-type-none">无</label>
+                        </div>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="inlineRadio2" value="phaseCount">
+                            <label class="form-check-label" for="inlineRadio2">合同支付期数</label>
+                        </div>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="inlineRadio3" value="stageCount">
+                            <label class="form-check-label" for="inlineRadio3">计量期数</label>
+                        </div>
+                        <br/>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="inlineRadio4" value="contract">
+                            <label class="form-check-label" for="inlineRadio4">累计合同金额</label>
+                        </div>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="inlineRadio5" value="qc">
+                            <label class="form-check-label" for="inlineRadio5">累计变更金额</label>
+                        </div>
+                        <div class="form-check form-check-inline">
+                            <input class="form-check-input" type="radio" name="dl-type" id="inlineRadio6" value="gather">
+                            <label class="form-check-label" for="inlineRadio6">累计完成金额</label>
+                        </div>
+                    </div>
+                </div>
+                <div class="form-group" dl-type="1">
+                    <label>限制值</label>
+                    <input class="form-control form-control-sm" id="dl-value" type="number">
+                </div>
+                <!--公用提示-->
+                <div id="dl-hint">
+                    <p>设置为:</p>
+                    <p id="range-hint" class="pl-3 text-danger">当 累计完成计量金额 >= 50000.00 时</p>
+                    <p class="pl-3">当期金额直接计量至(扣款限额 - 截止上期金额)</p>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <% if (!ctx.phasePay.readOnly) { %>
+                <button type="button" class="btn btn-primary btn-sm" id="deadline-ok">确定</button>
+                <% } %>
+            </div>
+        </div>
+    </div>
+</div>