Przeglądaj źródła

移动节点下所有合同至其它节点功能和部分合同设置功能

ellisran 1 tydzień temu
rodzic
commit
055af5ed7c

+ 31 - 1
app/controller/contract_controller.js

@@ -208,7 +208,7 @@ module.exports = app => {
                         responseData.data = commonJson && commonJson[(data.is_tender ? 'tender_' : '') + 'contract_type'] ? commonJson[(data.is_tender ? 'tender_' : '') + 'contract_type'] : [];
                         break;
                     case 'set-contract-type':
-                        result = await ctx.service.subProject.saveCommonJson(ctx.subProject.id, (data.is_tender ? 'tender_' : '') + 'contract_type', data.contract_type);
+                        result = await ctx.service.subProject.saveCommonJsons(ctx.subProject.id, ['contract_type', 'tender_contract_type'], data.contract_type);
                         break;
                     default: throw '参数有误';
                 }
@@ -257,6 +257,7 @@ module.exports = app => {
                     expensesPayList,
                     incomePayList,
                     thisUrl: `/sp/${ctx.subProject.id}` + (ctx.contract_tender ? `/contract/tender/${ctx.contract.id}/detail` : '/contract/detail'),
+                    is_setting: false,
                 };
                 await this.layout('contract/panel.ejs', renderData, 'contract/setting_modal.ejs');
             } catch (err) {
@@ -288,6 +289,7 @@ module.exports = app => {
                     types,
                     thisUrl: `/sp/${ctx.subProject.id}` + (ctx.contract_tender ? `/contract/tender/${ctx.contract.id}/detail` : '/contract/detail'),
                     stdChapters,
+                    is_setting: false,
                 };
 
                 const contractColSet = await ctx.service.contractColSet.getContractColSet(ctx.subProject.id, ctx.contractOptions.tid, ctx.contract_type);
@@ -661,6 +663,34 @@ module.exports = app => {
                 }
             }
         }
+
+        async setting(ctx) {
+            try {
+                if (!ctx.subProject.page_show.openTenderContract && !ctx.subProject.page_show.openContract) {
+                    throw '该功能已关闭或无法查看';
+                }
+                if (!ctx.session.sessionUser.is_admin) {
+                    throw '您没有权限查看该页面';
+                }
+                const types_from = ctx.query.from || 'subProject';
+                const commonJson = ctx.subProject.common_json ? JSON.parse(ctx.subProject.common_json) : null;
+                const types = commonJson && commonJson.contract_type ? commonJson.contract_type : [];
+                const tender_types = commonJson && commonJson.tender_contract_type ? commonJson.tender_contract_type : [];
+                const renderData = {
+                    types_from,
+                    types,
+                    tender_types,
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.contract.setting),
+                    thisUrl: `/sp/${ctx.subProject.id}/contract/setting`,
+                    is_setting: true,
+                };
+                await this.layout('contract/setting.ejs', renderData);
+            } catch (err) {
+                ctx.log(err);
+                ctx.session.postError = err.toString();
+                ctx.redirect(`/sp/${ctx.subProject.id}/dashboard`);
+            }
+        }
     }
 
     return ContractController;

+ 163 - 4
app/public/js/contract_detail.js

@@ -960,13 +960,18 @@ $(document).ready(function() {
                 if (info.newSelections) {
                     if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row || info.newSelections[0].rowCount !== info.oldSelections[0].rowCount) {
                         const node = SpreadJsObj.getSelectObject(info.sheet);
-                        $('#move-new-node').text(node ? node.code : '');
+                        $('.move-new-node').text(node ? node.code : '');
                     }
                     info.sheet.setSelection(info.newSelections[0].row, 0, 1, info.sheet.getColumnCount());
                 }
             },
         }
         moveSpread.bind(spreadNS.Events.SelectionChanged, moveTreeSpreadObj.selectionChanged);
+        const move2Spread = SpreadJsObj.createNewSpread($('#move2-contract-spread')[0]);
+        const move2Sheet = move2Spread.getActiveSheet();
+        SpreadJsObj.initSheet(move2Sheet, moveSpreadSetting);
+        move2Spread.bind(spreadNS.Events.SelectionChanged, moveTreeSpreadObj.selectionChanged);
+
         $('#cons-move').on('shown.bs.modal', function () {
             const node = SpreadJsObj.getSelectObject(contractSheet);
             if (!(node && node.c_code)) {
@@ -976,8 +981,8 @@ $(document).ready(function() {
             }
             $('#move-node').text(node.c_code);
             const parentNode = _.find(contractTree.nodes, { contract_id: node.contract_pid });
-            $('#move-parent-node').text(parentNode ? parentNode.code : '');
-            $('#move-new-node').text(parentNode ? parentNode.code : '');
+            $('.move-parent-node').text(parentNode ? parentNode.code : '');
+            $('.move-new-node').text(parentNode ? parentNode.code : '');
             const onlyTree = _.cloneDeep(_.filter(contractTree.nodes, function (item) {
                 return item.code !== undefined && item.c_code === undefined;
             }));
@@ -1054,6 +1059,127 @@ $(document).ready(function() {
             });
         });
 
+        $('#cons-move2').on('shown.bs.modal', function () {
+            const node = SpreadJsObj.getSelectObject(contractSheet);
+            if (!(node && node.code)) {
+                toastr.error('节点编号不存在');
+                $('#cons-move2').modal('hide');
+                return;
+            }
+            $('.move-parent-node').text(node ? node.code : '');
+            $('.move-new-node').text(node ? node.code : '');
+            const onlyTree = _.cloneDeep(_.filter(contractTree.nodes, function (item) {
+                return item.code !== undefined && item.c_code === undefined;
+            }));
+            for (const t of onlyTree) {
+                if (!t.is_leaf && _.findIndex(onlyTree, { contract_pid: t.contract_id }) === -1) {
+                    t.is_leaf = 1;
+                }
+            }
+            moveTree.loadDatas(onlyTree);
+            SpreadJsObj.loadSheetData(move2Sheet, SpreadJsObj.DataType.Tree, moveTree);
+            const contracts = _.filter(node.children, function (item) {
+                return item.c_code !== undefined;
+            });
+            let html = '';
+            for(const c of contracts) {
+                html += `<tr>
+                                    <td class="text-center"><input class="" checked type="checkbox" contract_id="${c.id}" /></td>
+                                    <td>${c.c_code}</td>
+                                    <td>${c.name}</td>
+                                </tr>`
+            }
+            $('#move2-contracts').html(html);
+            // 找出node对应父节点并选中,底色也要跟着更新
+            const parentIndex = _.findIndex(moveTree.nodes, { contract_id: node.contract_id });
+            if (parentIndex !== -1) {
+                move2Sheet.setSelection(parentIndex, 0, 1, move2Sheet.getColumnCount());
+                SpreadJsObj.reloadRowsBackColor(move2Sheet, [0, parentIndex]);
+            }
+            move2Spread.refresh();
+            $('#select-move2-all').prop('checked', true);
+        });
+
+        $('#select-move2-all').click(function () {
+            const checkAll = $(this).prop('checked');
+            $('#move2-contracts').find('input[type="checkbox"]').prop('checked', checkAll);
+        });
+
+        $('#move2-contracts').on('change', 'input[type="checkbox"]', function () {
+            const allChecked = $('#move2-contracts').find('input[type="checkbox"]').length === $('#move2-contracts').find('input[type="checkbox"]:checked').length;
+            $('#select-move2-all').prop('checked', allChecked);
+        });
+
+        $('#move2-contract-btn').click(function () {
+            const node = SpreadJsObj.getSelectObject(contractSheet);
+            if (!(node && node.code)) {
+                toastr.error('节点编号不存在');
+                $('#cons-move2').modal('hide');
+                return;
+            }
+            const newNode = SpreadJsObj.getSelectObject(move2Sheet);
+            const newParentNode = _.find(contractTree.nodes, { contract_id: newNode.contract_id });
+            if (node.contract_id === newParentNode.contract_id) {
+                toastr.warning('合同所属节点无变化');
+                return;
+            }
+            // 要移动的合同已勾选
+            const data = [];
+            let newOrder = newParentNode.children ? newParentNode.children.length + 1 : 1;
+            $('#move2-contracts').find('input[type="checkbox"]:checked').each(function () {
+                const contractId = $(this).attr('contract_id');
+                const contractNode = _.find(node.children, { id: contractId });
+                data.push({
+                    id: contractNode.id,
+                    contract_pid: newParentNode.contract_id,
+                    level: newParentNode.level + 1,
+                    order: newOrder,
+                    full_path: newParentNode.full_path + '-' + contractNode.contract_id,
+                });
+                newOrder += 1;
+            });
+            if (data.length === 0) {
+                toastr.warning('请勾选要移动的合同');
+                return;
+            }
+            if (node.children.length === data.length) {
+                node.is_leaf = 1;
+                data.push({
+                    id: node.id,
+                    is_leaf: 1,
+                });
+            } else if (node.children.length > 1) {
+                // 可能需要移动node的children数组比data里面选的减值
+                for (const [i, child] of node.children.entries()) {
+                    if (!_.find(data, { id: child.id })) {
+                        if (i !== child.order) {
+                            child.order = i;
+                            data.push({
+                                id: child.id,
+                                order: child.order,
+                            });
+                        }
+                    }
+                }
+            }
+            if (newParentNode.is_leaf === 1) {
+                newParentNode.is_leaf = 0;
+                data.push({
+                    id: newParentNode.id,
+                    is_leaf: 0,
+                });
+            }
+            console.log(data, newParentNode);
+            postData(window.location.pathname + '/update', {postType: 'update', postData: data, updateAll: true}, function (result) {
+                toastr.success('合同已移动成功');
+                const refreshNode = contractTree.loadPostData(result);
+                contractTreeSpreadObj.refreshTree(contractSheet, refreshNode);
+                const newNode = SpreadJsObj.getSelectObject(contractSheet);
+                contractTreeSpreadObj.changeContractTab(newNode, true);
+                $('#cons-move2').modal('hide');
+            });
+        });
+
         contractContextMenuOptions.items.create = {
             name: '新增节点',
             icon: 'fa-plus',
@@ -1285,7 +1411,40 @@ $(document).ready(function() {
                 if (!tree) return true;
                 const first = sheet.zh_tree.nodes[row];
                 const valid = !sheet.zh_setting.readOnly;
-                return !(valid && first && first.c_code && !first.settle_code && first.level > 1);
+                return !(valid && first && first.c_code && first.level > 1);
+            }
+        }
+        contractContextMenuOptions.items.move2 = {
+            name: '移动本节点下合同至其它节点',
+            icon: 'fa-arrow-left',
+            callback: function (key, opt) {
+                $('#cons-move2').modal('show');
+            },
+            visible: function (key, opt) {
+                const sheet = contractSheet;
+                const selection = sheet.getSelections();
+                const sel = selection ? selection[0] : sheet.getSelections()[0];
+                const row = sel ? sel.row : -1;
+                const tree = sheet.zh_tree;
+                if (!tree) return false;
+                const first = sheet.zh_tree.nodes[row];
+                const valid = !sheet.zh_setting.readOnly;
+                return valid && first && first.code !== undefined;
+            },
+            disabled: function (key, opt) {
+                const sheet = contractSheet;
+                const selection = sheet.getSelections();
+                const sel = selection ? selection[0] : sheet.getSelections()[0];
+                const row = sel ? sel.row : -1;
+                if (sel.rowCount > 1) return true;
+                const tree = sheet.zh_tree;
+                if (!tree) return true;
+                const first = sheet.zh_tree.nodes[row];
+                console.log(first);
+                const valid = !sheet.zh_setting.readOnly;
+                return !(valid && first && first.code !== undefined && first.children.length > 0 && _.findIndex(first.children, function (item) {
+                    return item.c_code !== undefined;
+                }) !== -1);
             }
         }
         contractContextMenuOptions.items.batchInsert = {

+ 115 - 0
app/public/js/contract_setting.js

@@ -0,0 +1,115 @@
+'use strict';
+
+/**
+ * 项目信息js
+ *
+ * @author EllisRan.
+ * @date 2019/3/19
+ * @version
+ */
+function setTypeTable(types, type) {
+    $('#'+ type + '-type-table').empty();
+    types.forEach(t => {
+        const typeRow = `<tr>
+                                    <td><input class="form-control form-control-sm" name="value" placeholder="请输入值" value="${t}"></td>
+                                    <td>
+                                        <a href="javascript:void(0);" class="btn btn-sm text-danger remove-type-btn"><i class="fa fa-remove"></i></a>
+                                    </td>
+                                </tr>`;
+        $('#'+ type + '-type-table').append(typeRow);
+    });
+}
+$(document).ready(() => {
+    autoFlashHeight();
+    // setTypeTable(types_from === 'subProject' ? subProject_types : tender_types);
+    // $('#bd-set-1').on('show.bs.modal', function () {
+    //     $('#type-table').empty();
+    //     // 看url上是否带有tender
+    //     const is_tender = window.location.pathname.includes('tender') ? 1 : 0;
+    //     console.log(window.location, is_tender);
+    //     postData(`/sp/${spid}/contract/audit/save`, { type: 'get-contract-type', is_tender }, function (types) {
+    //         setTypeTable(types);
+    //     });
+    // });
+    $('#addType').click(function(){
+        const type = $('#types-tabs a.active').attr('type');
+        const newType = `<tr>
+                                <td><input class="form-control form-control-sm" name="value" placeholder="请输入值" value=""></td>
+                                <td>
+                                    <a href="javascript:void(0);" class="btn btn-sm text-danger remove-type-btn"><i class="fa fa-remove"></i></a>
+                                </td>
+                            </tr>`;
+        $('#'+ type + '-type-table').append(newType);
+    });
+
+    $('body').on('click', '.remove-type-btn', function() {
+        const input = $(this).parents('td').siblings('td').eq(0).children('input');
+        input.attr('disabled', true);
+        // 文字加删除线并移除foucs
+        if (input.val() === '') {
+            input.removeAttr('placeholder');
+        }
+        input.css('text-decoration', 'line-through');
+        input.blur();
+        $(this).remove();
+        checkAndShowTypesBtn();
+    });
+
+    $('body').on('blur', '#contract-types-set input[name="value"]', function() {
+        checkAndShowTypesBtn();
+    });
+
+    function checkAndShowTypesBtn(return_type = false) {
+        const new_subProject_types = [];
+        const new_tender_types = [];
+        const type = ['subProject', 'tender'];
+        for (const t of type) {
+            $('#'+ t + '-type-table tr').each(function () {
+                const input = $(this).find('input[name="value"]');
+                if (!input.prop('disabled')) {
+                    const value = input.val().trim();
+                    if (value) {
+                        if (t === 'subProject') {
+                            new_subProject_types.push(value);
+                        } else {
+                            new_tender_types.push(value);
+                        }
+                    }
+                }
+            });
+        }
+        console.log(new_tender_types, tender_types, new_subProject_types, subProject_types);
+        // 用lodash对比数组内容是否相同
+        if (_.isEqual(new_tender_types.sort(), tender_types.sort()) && _.isEqual(new_subProject_types.sort(), subProject_types.sort())) {
+            $('#show-type-btn').hide();
+        } else {
+            $('#show-type-btn').show();
+        }
+        if (return_type) {
+            return {
+                new_subProject_types,
+                new_tender_types
+            };
+        }
+    }
+
+    $('#set-type-btn').click(function() {
+        const { new_subProject_types, new_tender_types } = checkAndShowTypesBtn(true);
+        postData(`/sp/${spid}/contract/audit/save`, { type: 'set-contract-type', contract_type: { contract_type: new_subProject_types, tender_contract_type: new_tender_types } }, function (res) {
+            toastr.success('设置成功');
+            tender_types = new_tender_types;
+            subProject_types = new_subProject_types;
+            setTypeTable(tender_types, 'tender');
+            setTypeTable(subProject_types, 'subProject');
+            checkAndShowTypesBtn();
+        });
+    });
+
+    $('#cancel-type-btn').click(function() {
+        toastr.warning('已取消改动');
+        // const is_tender = $('#types-tabs a.active').attr('type') === 'subPorjct' ? 0 : 1;
+        setTypeTable(tender_types, 'tender');
+        setTypeTable(subProject_types, 'subProject');
+        checkAndShowTypesBtn();
+    });
+});

+ 1 - 0
app/router.js

@@ -351,6 +351,7 @@ module.exports = app => {
     app.post('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
     app.get('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/col-set', sessionAuth, subProjectCheck, contractCheck, 'contractController.colSet');
+    app.get('/sp/:id/contract/setting', sessionAuth, subProjectCheck, 'contractController.setting');
 
 
     // 资料归集-列表

+ 15 - 0
app/service/sub_project.js

@@ -753,6 +753,21 @@ module.exports = app => {
             return result.affectedRows === 1;
         }
 
+        async saveCommonJsons(id, field, datas) {
+            const subProject = await this.getDataById(id);
+            subProject.common_json = subProject.common_json ? JSON.parse(subProject.common_json) : {};
+            const updateData = {
+                id,
+            };
+            const fields = field instanceof Array ? field : [field];
+            for (const f of fields) {
+                if (datas[f] !== undefined) subProject.common_json[f] = datas[f];
+            }
+            updateData.common_json = JSON.stringify(subProject.common_json);
+            const result = await this.db.update(this.tableName, updateData);
+            return result.affectedRows === 1;
+        }
+
         async updateCommonJsonDaping06(subProject, projectData) {
             const categoryData = await this.ctx.service.category.getAllCategory(subProject);
             const projCommonJson = projectData.common_json ? JSON.parse(projectData.common_json) : null;

+ 41 - 1
app/view/contract/detail_modal.ejs

@@ -280,7 +280,7 @@
                 <h5 class="modal-title">移动合同至其它节点</h5>
             </div>
             <div class="modal-body">
-                <div class="mb-2">合同编号: <b class="mr-3" id="move-node"></b> 原所属编号: <b class="mr-3" id="move-parent-node"></b> 新所属编号: <b id="move-new-node"></b></div>
+                <div class="mb-2">合同编号: <b class="mr-3" id="move-node"></b> 原所属编号: <b class="mr-3 move-parent-node"></b> 新所属编号: <b class="move-new-node"></b></div>
                 <div class="modal-height-500" id="move-contract-spread"></div>
             </div>
             <div class="modal-footer">
@@ -290,6 +290,46 @@
         </div>
     </div>
 </div>
+<div class="modal fade" id="cons-move2" data-backdrop="static">
+    <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="row">
+                    <!-- 左侧默认节点 -->
+                    <div class="col-6">
+                        <div class="mb-2">新所属编号: <b class="move-new-node"></b></div>
+                        <div class="modal-height-500" id="move2-contract-spread">
+                        </div>
+                    </div>
+                    <!-- 右侧对应节点成员 -->
+                    <div class="col-6">
+                        <div class="mb-2">原编号: <b class="mr-3 move-parent-node"></b> 下所有合同</div>
+                        <div class="modal-height-500" style="overflow-y:auto;">
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr class="text-center">
+                                    <th><input class="" checked type="checkbox" id="select-move2-all" /></th>
+                                    <th>合同编号</th>
+                                    <th>合同名称</th>
+                                </tr>
+                                </thead>
+                                <tbody id="move2-contracts">
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            </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" id="move2-contract-btn">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% } %>
 
 

+ 110 - 0
app/view/contract/setting.ejs

@@ -0,0 +1,110 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>功能设置</h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <div class="row m-0 mt-3">
+                    <div class="col-8">
+                        <div class="card mb-3">
+                            <div class="card-header">
+                                <div class="float-left">合同设置</div>
+                                <div class="float-right" id="show-type-btn" style="display: none">
+                                    <button id="cancel-type-btn" class="btn btn-sm btn-secondary">取消</button>
+                                    <button id="set-type-btn" class="btn btn-sm btn-success">保存</button>
+                                </div>
+                            </div>
+                            <div class="card-body" id="contract-types-set">
+                                <nav class="nav nav-tabs" id="types-tabs">
+                                    <a class="nav-link nav-item <% if (types_from === 'subProject') { %>active<% } %>" data-toggle="tab" data-tab="subProject-types-tab" href="#subProject-types-tab" role="tab" type="subProject">项目</a>
+                                    <a class="nav-link nav-item <% if (types_from !== 'subProject') { %>active<% } %>" data-toggle="tab" data-tab="tender-types-tab" href="#tender-types-tab" role="tab" type="tender">标段</a>
+                                    <div class="ml-auto">
+                                        <a href="javascript:void(0);" style="vertical-align: sub;" id="addType">新增类型</a>
+                                    </div>
+                                </nav>
+                                <div class="tab-content my-2">
+                                    <div class="tab-pane <% if (types_from === 'subProject') { %>active<% } %>" id="subProject-types-tab" style="max-height: 400px;overflow: auto;">
+                                        <table class="table table-bordered">
+                                            <thead><tr class="text-center">
+                                                <th width="60%">名称</th>
+                                                <th>操作</th>
+                                            </tr>
+                                            </thead>
+                                            <tbody class="text-center" id="subProject-type-table">
+                                            <% for (const type of types) { %>
+                                                <tr>
+                                                    <td><input class="form-control form-control-sm" name="value" placeholder="请输入值" value="<%- type %>"></td>
+                                                    <td>
+                                                        <a href="javascript:void(0);" class="btn btn-sm text-danger remove-type-btn"><i class="fa fa-remove"></i></a>
+                                                    </td>
+                                                </tr>
+                                            <% } %>
+                                            </tbody>
+                                        </table>
+                                    </div>
+                                    <div class="tab-pane <% if (types_from !== 'subProject') { %>active<% } %>" id="tender-types-tab" style="max-height: 400px;overflow: auto;">
+                                        <table class="table table-bordered">
+                                            <thead><tr class="text-center">
+                                                <th width="60%">名称</th>
+                                                <th>操作</th>
+                                            </tr>
+                                            </thead>
+                                            <tbody class="text-center" id="tender-type-table">
+                                            <% for (const type of tender_types) { %>
+                                                <tr>
+                                                    <td><input class="form-control form-control-sm" name="value" placeholder="请输入值" value="<%- type %>"></td>
+                                                    <td>
+                                                        <a href="javascript:void(0);" class="btn btn-sm text-danger remove-type-btn"><i class="fa fa-remove"></i></a>
+                                                    </td>
+                                                </tr>
+                                            <% } %>
+                                            </tbody>
+                                        </table>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="card mb-3">
+                            <div class="card-header">
+                                <div class="float-left">审批设置</div>
+                            </div>
+                            <div class="card-body" id="contract-shenpi-set">
+                                <label class="mb-2"><i class="fa fa-list-ul"></i> 项目合同</label>
+                                <div class="form-group mb-1 ml-3">
+                                    <div class="form-check form-check-inline mr-3">
+                                        <input class="form-check-input" type="checkbox" id="openContractSubPorjectShenpi" <% if (ctx.subProject.page_show.openContractSubPorjectShenpi) { %>checked<% } %>>
+                                        <label class="form-check-label" for="openContractSubPorjectShenpi">开启「合同审批」功能</label>
+                                    </div>
+                                    <div class="form-check form-check-inline ml-3">
+                                        <input class="form-check-input" type="checkbox" id="openContractPaySubPorjectShenpi" <% if (ctx.subProject.page_show.openContractPaySubPorjectShenpi) { %>checked<% } %>>
+                                        <label class="form-check-label" for="openContractPaySubPorjectShenpi">开启「支付/回款审批」功能</label>
+                                    </div>
+                                </div>
+                                <label class="my-2"><i class="fa fa-list-ul"></i> 标段合同</label>
+                                <div class="form-group mb-1 ml-3">
+                                    <div class="form-check form-check-inline mr-3">
+                                        <input class="form-check-input" type="checkbox" id="openContractTenderShenpi" <% if (ctx.subProject.page_show.openContractTenderShenpi) { %>checked<% } %>>
+                                        <label class="form-check-label" for="openContractTenderShenpi">开启「合同审批」功能</label>
+                                    </div>
+                                    <div class="form-check form-check-inline ml-3">
+                                        <input class="form-check-input" type="checkbox" id="openContractPayTenderShenpi" <% if (ctx.subProject.page_show.openContractPayTenderShenpi) { %>checked<% } %>>
+                                        <label class="form-check-label" for="openContractPayTenderShenpi">开启「支付/回款审批」功能</label>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    const types_from = JSON.parse(unescape('<%- escape(JSON.stringify(types_from)) %>'));
+    let subProject_types = JSON.parse(unescape('<%- escape(JSON.stringify(types)) %>'));
+    let tender_types = JSON.parse(unescape('<%- escape(JSON.stringify(tender_types)) %>'));
+</script>

+ 9 - 1
app/view/contract/sub_menu.ejs

@@ -1,7 +1,15 @@
 <div class="panel-sidebar" id="sub-menu">
+    <% if (is_setting) { %>
+    <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="合同设置">合同设置</div>
+    <% } else { %>
     <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="<%- ctx.contract.name %>"><%- ctx.contract.name %></div>
+    <% } %>
     <div class="scrollbar-auto">
-        <% include ./sub_menu_list.ejs %>
+        <% if (is_setting) { %>
+            <% include ./sub_menu_setting_list.ejs %>
+        <% } else { %>
+            <% include ./sub_menu_list.ejs %>
+        <% } %>
         <div class="side-show"></div>
         <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
             <i class="fa fa-angle-left"></i>

+ 14 - 0
app/view/contract/sub_menu_setting_list.ejs

@@ -0,0 +1,14 @@
+<div class="nav-box">
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === thisUrl || ctx.url === thisUrl +  '?from=tender') { %>active<% } %>">
+            <a href="<%- thisUrl %>"><span class="ml-3">功能设置</span></a>
+        </li>
+    </ul>
+</div>
+<div class="nav-box">
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === thisUrl + '/shenpi') { %>active<% } %>">
+            <a href="<%- thisUrl %>/shenpi"><span class="ml-3">审批流程</span></a>
+        </li>
+    </ul>
+</div>

+ 11 - 0
config/web.js

@@ -1895,6 +1895,17 @@ const JsFiles = {
                 ],
                 mergeFile: 'contract_detail',
             },
+            setting: {
+                files: ['/public/js/echarts/echarts.min.js', '/public/js/decimal.min.js', '/public/js/moment/moment.min.js', '/public/js/component/menu.js'],
+                mergeFiles: [
+                    '/public/js/sub_menu.js',
+                    '/public/js/zh_calc.js',
+                    // '/public/js/datepicker/datepicker.min.js',
+                    // '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/contract_setting.js',
+                ],
+                mergeFile: 'contract_setting',
+            },
         },
         financial: {
             index: {