فهرست منبع

支付审批部分提交

laiguoran 2 سال پیش
والد
کامیت
8b35c15cfb

+ 1 - 0
app/base/base_controller.js

@@ -36,6 +36,7 @@ class BaseController extends Controller {
             }
         }
         menuList.datacollect.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showDataCollect : false;
+        menuList.payment.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showPayment : false;
         if (ctx.session && ctx.session.sessionProject && ctx.session.sessionProject.page_show && ctx.session.sessionProject.page_show.openManagement) {
             menuList.management.display = true;
         } else {

+ 36 - 0
app/const/payment.js

@@ -0,0 +1,36 @@
+'use strict';
+
+/**
+ * 支付审批
+ *
+ * @author ELlisran
+ * @date 2019/10/20
+ * @version
+ */
+
+// 调差类型
+const audit_admin_permission = {
+    tender: 1,
+    folder: 1,
+    process: 1,
+};
+const audit_permission = {
+    tender: 0,
+    folder: 0,
+    process: 0,
+};
+const permission_list = [
+    { text: '新建标段', type: 'tender', value: 0 },
+    { text: '新建目录', type: 'folder', value: 0 },
+    { text: '设置审批流程', type: 'process', value: 0 },
+];
+const permission_type_array = ['tender', 'folder', 'process'];
+const permission_value_array = [0, 1];
+
+module.exports = {
+    audit_admin_permission,
+    audit_permission,
+    permission_list,
+    permission_type_array,
+    permission_value_array,
+};

+ 224 - 8
app/controller/payment_controller.js

@@ -1,4 +1,5 @@
 'use strict';
+const accountGroup = require('../const/account_group').group;
 module.exports = app => {
 
     class PaymentController extends app.BaseController {
@@ -14,21 +15,236 @@ module.exports = app => {
             // ctx.showTitle = true;
         }
         /**
+         * 支付审批列表页
+         *
+         * @param {Object} ctx - egg全局页面
+         * @return {void}
+         */
+        async index(ctx) {
+            try {
+                const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId);
+                if (!auditPermission) {
+                    throw '权限不足';
+                }
+                // 列表读取及目录读取
+
+                const renderData = {
+                    auditPermission,
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.index),
+                };
+                if (ctx.session.sessionUser.is_admin) {
+                    const projectId = ctx.session.sessionProject.id;
+                    const permissionAudits = await ctx.service.paymentPermissionAudit.getList(projectId);
+                    // 获取所有项目参与者
+                    const accountList = await ctx.service.projectAccount.getAllDataByCondition({
+                        where: { project_id: ctx.session.sessionProject.id, enable: 1 },
+                        columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
+                    });
+                    const accountGroupList = accountGroup.map((item, idx) => {
+                        const groupList = accountList.filter(item => item.account_group === idx);
+                        return { groupName: item, groupList };
+                    });
+                    renderData.permissionAudits = permissionAudits;
+                    renderData.accountList = accountList;
+                    renderData.accountGroup = accountGroupList;
+                }
+                await this.layout('payment/index.ejs', renderData, 'payment/modal.ejs');
+            } catch (err) {
+                console.log(err);
+                this.log(err);
+                ctx.redirect(this.menu.menu.dashboard.url);
+            }
+        }
+
+        async listLoad(ctx) {
+            const responseData = {
+                err: 0, msg: '', data: {},
+            };
+            // 先获取你创建的标段及参与的标段
+            const tenderList = await ctx.service.paymentTender.getList(ctx.session.sessionUser.accountId);
+            // 获取你创建的目录及对应目录下的所有目录
+            const folderList = await ctx.service.paymentFolder.getList(ctx.session.sessionUser.accountId, tenderList);
+            responseData.data.folderList = folderList;
+            responseData.data.tenderList = tenderList;
+            ctx.body = responseData;
+        }
+
+        async permissionSave(ctx) {
+            try {
+                if (ctx.session.sessionUser.is_admin === 0) throw '没有设置权限';
+                const projectId = ctx.session.sessionProject.id;
+                const responseData = {
+                    err: 0, msg: '', data: null,
+                };
+
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.type) {
+                    throw '提交数据错误';
+                }
+                let uids;
+                let result = false;
+                let auditList = [];
+                switch (data.type) {
+                    case 'add-audit':
+                        // 判断用户是单个还是数组
+                        uids = data.id instanceof Array ? data.id : [data.id];
+                        // 判断该用户的组是否已加入到表中,已加入则提示无需添加
+                        auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { pid: projectId, uid: uids } });
+                        const addAidList = ctx.helper._.difference(uids, ctx.helper._.map(auditList, 'uid'));
+                        if (addAidList.length === 0) {
+                            throw '用户已存在权限中,无需重复添加';
+                        }
+                        const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { id: addAidList } });
+                        await ctx.service.paymentPermissionAudit.saveAudits(projectId, accountList);
+                        responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId);
+                        break;
+                    case 'del-audit':
+                        uids = data.id instanceof Array ? data.id : [data.id];
+                        auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { id: uids } });
+                        if (auditList.length !== uids.length) {
+                            throw '该用户已不存在权限中,移除失败';
+                        }
+                        await ctx.service.paymentPermissionAudit.delAudit(uids);
+                        responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId);
+                        break;
+                    case 'save-permission-one':
+                        result = await ctx.service.paymentPermissionAudit.updateOnePermission(data.updateData);
+                        if (!result) {
+                            throw '修改权限失败';
+                        }
+                        break;
+                    case 'save-permission-all':
+                        result = await ctx.service.paymentPermissionAudit.updateAllPermission(projectId, data.permission_type, data.value);
+                        if (!result) {
+                            throw '修改权限失败';
+                        }
+                        responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId);
+                        break;
+                    default: throw '参数有误';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
+        async save(ctx) {
+            try {
+                const projectId = ctx.session.sessionProject.id;
+                const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId);
+                if (!auditPermission) {
+                    throw '权限不足';
+                }
+                const responseData = {
+                    err: 0, msg: '', data: {},
+                };
+
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.type) {
+                    throw '提交数据错误';
+                }
+                let type = '';
+                switch (data.type) {
+                    case 'add-folder':
+                        if (!auditPermission.folder) {
+                            throw '没有权限新建目录';
+                        }
+                        await ctx.service.paymentFolder.addFolder(projectId, ctx.session.sessionUser.accountId, data.parentId, data.name);
+                        break;
+                    case 'add-tender':
+                        if (!auditPermission.tender) {
+                            throw '没有权限新建标段';
+                        }
+                        await ctx.service.paymentTender.addTender(projectId, ctx.session.sessionUser.accountId, data.folderId, data.name);
+                        break;
+                    case 'edit-name':
+                        type = data.postData.type;
+                        const updateData = {
+                            name: data.postData.name,
+                        };
+                        const conditionData = {
+                            id: data.postData.id,
+                        };
+                        if (type === 'tender') {
+                            await ctx.service.paymentTender.update(updateData, conditionData);
+                        } else {
+                            await ctx.service.paymentFolder.update(updateData, conditionData);
+                        }
+                        break;
+                    case 'del':
+                        type = data.postData.type;
+                        if (type === 'tender') {
+                            await ctx.service.paymentTender.deleteTender(data.postData.id);
+                        } else {
+                            await ctx.service.paymentFolder.deleteFolder(data.postData.id);
+                        }
+                        break;
+                    default: throw '参数有误';
+                }
+                // 先获取你创建的标段及参与的标段
+                const tenderList = await ctx.service.paymentTender.getList(ctx.session.sessionUser.accountId);
+                // 获取你创建的目录及对应目录下的所有目录
+                const folderList = await ctx.service.paymentFolder.getList(ctx.session.sessionUser.accountId, tenderList);
+                responseData.data.folderList = folderList;
+                responseData.data.tenderList = tenderList;
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+        /**
          * 支付表单页面
          *
          * @param {Object} ctx - egg全局页面
          * @return {void}
          */
         async detail(ctx) {
-            console.log(ctx.params);
-            const id = parseInt(ctx.params.id);
-            if (!id) throw '参数错误';
-            const info = await ctx.service.paymentDetail.getDataById(id);
+            try {
+                const id = parseInt(ctx.params.id);
+                if (!id) throw '参数错误';
+                const info = await ctx.service.paymentDetail.getDataById(id);
 
-            const renderData = {
-                info,
-            };
-            await this.layout('payment/detail.ejs', renderData);
+                const renderData = {
+                    info,
+                };
+                await this.layout('payment/detail.ejs', renderData);
+            } catch (err) {
+                console.log(err);
+                this.log(err);
+                ctx.redirect(this.menu.menu.dashboard.url);
+            }
+        }
+
+        async process(ctx) {
+            try {
+                const id = parseInt(ctx.params.pid);
+                if (!id) throw '参数错误';
+                const info = await ctx.service.paymentTender.getDataById(id);
+                if (!info) throw '标段不存在';
+                // 获取报表表单列表
+                const rptProject = await ctx.service.rptTreeNode.getDataByCondition({ name: '01.支付审批报表' });
+                const rptProjectList = rptProject.items ? JSON.parse(rptProject.items) : [];
+                const rptTplList = [];
+                if (rptProjectList.length > 0) {
+                    for (const rpt of rptProjectList) {
+                        const rptInfo = await ctx.service.rptTpl.getDataById(rpt.ID);
+                        // 根据模板ID获取报表JSON
+                    }
+                }
+                const renderData = {
+                    info,
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.process),
+                    rptProjectList,
+                    rptTplList,
+                };
+                await this.layout('payment/process.ejs', renderData);
+            } catch (err) {
+                console.log(err);
+                this.log(err);
+                ctx.redirect(this.menu.menu.dashboard.url);
+            }
         }
     }
 

+ 18 - 0
app/middleware/session_auth.js

@@ -56,11 +56,29 @@ module.exports = options => {
                 }
             }
             this.session.sessionProject.showDataCollect = showDataCollect;
+            // 判断是否有权限查看支付审批
+            let showPayment = 0;
             if (sessionUser.is_admin) {
                 this.session.sessionProject.showBudget = true;
+                showPayment = 1;
             } else {
                 this.session.sessionProject.showBudget = yield this.service.budgetPermission.showBudget(sessionUser.accountId);
+                // const grounpInfo = yield this.service.paymentPermissionAudit.getGroupInfo(projectData.id, accountInfo.account_group);
+                // if (grounpInfo) {
+                //     showPayment = 1;
+                // } else {
+                const auditInfo = yield this.service.paymentPermissionAudit.getDataByCondition({ pid: projectData.id, uid: accountInfo.id });
+                if (auditInfo) {
+                    showPayment = 1;
+                }
+                // }
             }
+            this.session.sessionProject.showPayment = showPayment;
+            // if (sessionUser.is_admin) {
+            //     this.session.sessionProject.showBudget = true;
+            // } else {
+            //     this.session.sessionProject.showBudget = yield this.service.budgetPermission.showBudget(sessionUser.accountId);
+            // }
 
             // 同步消息
             yield this.service.notify.syncNotifyData();

+ 10 - 0
app/public/css/bootstrap/bootstrap-table-fixed-columns.min.css

@@ -0,0 +1,10 @@
+/**
+  * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
+  *
+  * @version v1.21.3
+  * @homepage https://bootstrap-table.com
+  * @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
+  * @license MIT
+  */
+
+.fixed-columns,.fixed-columns-right{position:absolute;top:0;height:100%;background-color:#fff;box-sizing:border-box;z-index:1}.fixed-columns{left:0}.fixed-columns .fixed-table-body{overflow:hidden!important}.fixed-columns-right{right:0}.fixed-columns-right .fixed-table-body{overflow-x:hidden!important}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10 - 0
app/public/css/bootstrap/bootstrap-table.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10 - 0
app/public/js/bootstrap/bootstrap-table-fixed-columns.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10 - 0
app/public/js/bootstrap/bootstrap-table.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10 - 0
app/public/js/bootstrap/locales/bootstrap-table-zh-CN.min.js


+ 299 - 0
app/public/js/payment_index.js

@@ -0,0 +1,299 @@
+$(function () {
+    autoFlashHeight();
+    const EmptyTenderHtml = [
+        '<div class="jumbotron">',
+        '<h3 class="display-6">还没有标段及目录数据</h3>',
+        '</div>'
+    ];
+
+    function initTenderTree(folderList, tenderList) {
+        tenderTree = [];
+        const folders = folderList;
+        const tenders = tenderList;
+        function makeTenderTree(parent) {
+            if (parent.is_leaf) {
+                parent.children = _.filter(tenders, { folder_id: parent.id });
+                if (parent.children.length > 0) {
+                    parent.is_tender = true;
+                    parent.children.forEach((value, index) => {
+                       value.level = parent.level + 1;
+                    });
+                }
+            } else {
+                const children = _.filter(folders, { parent_id: parent.id });
+                parent.children = children;
+                if (children.length > 0) {
+                    for (const c of children) {
+                        makeTenderTree(c);
+                    }
+                }
+            }
+        }
+        const level0Folders = _.filter(folders, { level: 1 });
+        for (const l of level0Folders) {
+            makeTenderTree(l);
+            tenderTree.push(l);
+        }
+        console.log(tenderTree);
+    }
+
+    function recursiveGetTenderNodeHtml (node, arr, pid) {
+        const html = [];
+        html.push('<tr fid="' + (node.parent_id !== undefined ? node.id: 0) + '" pid="' + pid + '">');
+        // 名称
+        html.push('<td style="width: 40%" class="in-' + node.level + '">');
+        if (node.parent_id !== undefined) {
+            // html.push('<span onselectstart="return false" style="{-moz-user-select:none}" class="fold-switch mr-1" title="收起" cid="'+ node.sort_id +'"><i class="fa fa-minus-square-o"></i></span> <i class="fa fa-folder-o"></i> ', node.name);
+            html.push('<i class="fa fa-folder-o"></i> ', node.name);
+        } else {
+            html.push('<span class="text-muted mr-2">');
+            html.push(arr.indexOf(node) === arr.length - 1 ? '└' : '├');
+            html.push('</span>');
+            //html.push('<a href="/tender/' + node.id + '">', node[c.field], '</a>');
+            html.push('<a href="javascript: void(0)" id="' + node.id + '">', node.name, '</a>');
+        }
+        html.push('</td>');
+        // 创建人
+        html.push('<td style="width: 15%" class="text-center">', node.user_name ? node.user_name : '', '</td>');
+        // 创建时间
+        html.push('<td style="width: 15%">', node.in_time && node.parent_id === undefined ? moment(node.in_time).format('YYYY-MM-DD HH:mm:ss') : '', '</td>');
+        // 审批流程
+        html.push('<td style="width: 15%">');
+        if (node.parent_id === undefined && auditPermission.process) {
+            html.push('<a href="/payment/'+ node.id +'/process" target="_blank">设置</a>');
+        }
+        html.push('</td>');
+        // 操作
+        html.push('<td style="width: 15%">');
+        if (uid === node.uid || (auditPermission.tender && node.is_leaf) || (auditPermission.folder && node.parent_id !== undefined && !node.is_tender)) {
+            html.push('<div class="dropdown">\n' +
+                '                        <a href="#" class="dropdown-toggle text-primary" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+                '                          <i class="fa fa-bars"></i>\n' +
+                '                        </a>\n' +
+                '                        <div class="dropdown-menu">\n');
+            if (uid === node.uid) {
+                html.push('<a class="dropdown-item edit_name_btn" data-type="'+ (node.parent_id === undefined ? 'tender' : 'folder') +'" data-id="'+ node.id +'" href="javascript:void(0);"><i class="fa fa-edit mr-2"></i>重命名</a>\n');
+                if (!node.had_tender) {
+                    html.push('<a class="dropdown-item show_del_btn" data-type="'+ (node.parent_id === undefined ? 'tender' : 'folder') +'" data-id="'+ node.id +'" href="javascript:void(0);"><i class="fa fa-remove mr-2"></i>删除</a>\n');
+                }
+            }
+            if (uid === node.uid && ((auditPermission.tender && node.is_leaf) || (auditPermission.folder && node.parent_id !== undefined && !node.is_tender))) {
+                html.push('<div class="dropdown-divider"></div>\n');
+            }
+            if (auditPermission.folder && node.parent_id !== undefined && !node.is_tender) {
+                html.push('<a class="dropdown-item show_new_folder_btn" href="#add-folder" data-toggle="modal" data-target="#add-folder" data-parentName="'+ node.name +'" data-parentId="'+ node.id +'"><i class="fa fa-folder-o mr-2"></i>新建子目录</a>\n');
+            }
+            if (auditPermission.tender && node.is_leaf) {
+                html.push('<a class="dropdown-item show_new_tender_btn" href="javascript:void(0);"><i class="fa fa-folder-o mr-2"></i>新建标段</a>\n');
+            }
+            html.push('                        </div>\n' +
+                '                      </div>');
+        }
+        html.push('</td>');
+        html.push('</tr>');
+        if (node.children) {
+            for (const c of node.children) {
+                html.push(recursiveGetTenderNodeHtml(c, node.children, node.sort_id));
+            }
+        }
+        return html.join('');
+    }
+
+    // 根据TenderTree数据获取Html代码
+    function getTenderTreeHtml () {
+        if (tenderTree.length > 0) {
+            const html = [];
+            html.push('<table class="table table-hover table-bordered">');
+            html.push('<thead style="position: fixed;left:56px;top: 34px;">', '<tr>');
+            html.push('<th class="text-center" style="width: 40%">', '名称', '</th>');
+            html.push('<th class="text-center" style="width: 15%">', '创建人', '</th>');
+            html.push('<th class="text-center" style="width: 15%">', '创建时间', '</th>');
+            html.push('<th class="text-center" style="width: 15%">', '审批流程', '</th>');
+            html.push('<th class="text-center" style="width: 15%">', '操作', '</th>');
+            html.push('</tr>', '</thead>');
+            parentId = 0;
+            for (const t of tenderTree) {
+                html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
+            }
+            html.push('</table>');
+            return html.join('');
+        } else {
+            return EmptyTenderHtml.join('');
+        }
+    }
+
+    function makeList(folderList, tenderList) {
+        initTenderTree(folderList, tenderList);
+        $('.c-body').html(getTenderTreeHtml());
+        setTopTr();
+    }
+
+    // 首次加载展示目录
+    postData('/payment/load', {}, function (result) {
+        allFolders = result.folderList;
+        allTenders = result.tenderList;
+        makeList(result.folderList, result.tenderList);
+    });
+
+    $('body').on('click', '.show_new_folder_btn', function () {
+        if (parseInt($(this).attr('data-parentId')) === 0) {
+            $('#parent_folder').hide();
+            $('#parent_folder_name').val('');
+            $('#add-folder').find('.modal-title').text('新建目录');
+            $('#new_folder_name').siblings('label').text('目录名称');
+            $('#parent_id').val(0);
+        } else {
+            $('#parent_folder').show();
+            $('#parent_folder_name').val($(this).attr('data-parentName'));
+            $('#add-folder').find('.modal-title').text('新建子目录');
+            $('#new_folder_name').siblings('label').text('子目录名称');
+            $('#parent_id').val($(this).attr('data-parentId'));
+        }
+    });
+
+    function checkNameValid(_this) {
+        const name = _.trim(_this.val());
+        if(name === '') {
+            _this.addClass('is-invalid');
+            _this.siblings('.invalid-feedback').text('请输入名称');
+            return false;
+        }
+        if(name.length > 100) {
+            _this.addClass('is-invalid');
+            _this.siblings('.invalid-feedback').text('名称超过100个字,请缩减名称');
+            return false;
+        }
+        _this.removeClass('is-invalid');
+        _this.siblings('.invalid-feedback').text('');
+        return name;
+    }
+
+    $('#new_folder_btn').click(function () {
+        const name = checkNameValid($('#new_folder_name'));
+        if (name === false) {
+            return;
+        }
+        postData('/payment/save', { type: 'add-folder', parentId: parseInt($('#parent_id').val()), name }, function (result) {
+            allFolders = result.folderList;
+            allTenders = result.tenderList;
+            makeList(result.folderList, result.tenderList);
+            $('#add-folder').modal('hide');
+        })
+    });
+
+    $('body').on('click', '.edit_name_btn', function () {
+        const type = $(this).attr('data-type');
+        const id = parseInt($(this).attr('data-id'));
+        const info = type === 'tender' ? _.find(allTenders, { id }) : _.find(allFolders, { id });
+        if (!info) {
+            toastr.error('目录或标段不存在');
+            return;
+        }
+        $('#edit_name_input').val(info.name);
+        $('#edit-name').find('.modal-title').text(type === 'tender' ? '修改标段' : '修改目录');
+        $('#edit_name_id').val(info.id);
+        $('#edit_name_type').val(type);
+        $('#edit-name').modal('show');
+    });
+
+    $('#edit_name_btn').click(function () {
+        const name = checkNameValid($('#edit_name_input'));
+        if (name === false) {
+            return;
+        }
+        const data = {
+            type: $('#edit_name_type').val(),
+            id: $('#edit_name_id').val(),
+            name,
+        };
+        postData('/payment/save', { type: 'edit-name', postData: data }, function (result) {
+            allFolders = result.folderList;
+            allTenders = result.tenderList;
+            makeList(result.folderList, result.tenderList);
+            $('#edit-name').modal('hide');
+        });
+    });
+
+    // 选中行并标记色
+    $('body').on('click', '.c-body table tr', function () {
+        $('.c-body table tr').removeClass('table-warning');
+        $(this).addClass('table-warning');
+        const fid = parseInt($(this).attr('fid'));
+        const folderInfo = _.find(allFolders, { id: fid });
+        if (auditPermission.tender && folderInfo && folderInfo.is_leaf) {
+            $('#show_new_tender_btn').show();
+            $('#add_tender_folder_id').val(fid);
+            $('#add_tender_folder_name').val(folderInfo.name);
+            $('#add_tender_name').removeClass('is-invalid');
+            $('#add_tender_name').siblings('.invalid-feedback').text('');
+        } else {
+            $('#show_new_tender_btn').hide();
+        }
+    });
+
+    $('body').on('click', '.show_new_tender_btn', function () {
+        const fid = $('.c-body table').find('.table-warning').attr('fid');
+        if (!fid) {
+            toastr.error('请选中目录');
+            return;
+        }
+        const folderInfo = _.find(allFolders, { id: parseInt(fid) });
+        if (!folderInfo || folderInfo.is_leaf === 0) {
+            toastr.error('目录不存在或存在子目录不能新建标段');
+            return;
+        }
+        $('#add-tender').modal('show');
+    });
+
+    $('#new_tender_btn').click(function () {
+        const name = checkNameValid($('#add_tender_name'));
+        if (name === false) {
+            return;
+        }
+        postData('/payment/save', { type: 'add-tender', folderId: parseInt($('#add_tender_folder_id').val()), name }, function (result) {
+            allFolders = result.folderList;
+            allTenders = result.tenderList;
+            makeList(result.folderList, result.tenderList);
+            $('#add-tender').modal('hide');
+        });
+    });
+
+    $('body').on('click', '.show_del_btn', function () {
+        const type = $(this).attr('data-type');
+        const id = parseInt($(this).attr('data-id'));
+        const info = type === 'tender' ? _.find(allTenders, { id }) : _.find(allFolders, { id });
+        if (!info) {
+            toastr.error('目录或标段不存在');
+            return;
+        }
+        $('#edit_name_input').val(info.name);
+        $('#del-project').find('.modal-title').text(type === 'tender' ? '删除标段' : '删除目录');
+        $('#del-project').find('h6 span').text(info.name);
+        $('#del_id').val(info.id);
+        $('#del_type').val(type);
+        $('#del-project').modal('show');
+    });
+
+    $('#del_btn').click(function () {
+        const data = {
+            type: $('#del_type').val(),
+            id: $('#del_id').val(),
+        };
+        postData('/payment/save', { type: 'del', postData: data }, function (result) {
+            allFolders = result.folderList;
+            allTenders = result.tenderList;
+            makeList(result.folderList, result.tenderList);
+            $('#del-project').modal('hide');
+        });
+    });
+
+    $(window).resize(setTopTr);
+    // 设置表头固定并动态调整宽度高度
+    function setTopTr() {
+        for(let item = 0; item < $(".c-body table>thead>tr>th").length; item ++) {
+            $(".c-body table>thead>tr>th").eq(item).outerWidth($(".c-body table>tbody>tr:first").children('td').eq(item).outerWidth());
+        }
+        $('.c-body table').css('margin-top', $(".c-body table>thead").height() - 4);
+        // $('.c-body table').css('margin-top', -2);
+    }
+});

+ 3 - 0
app/public/js/payment_process.js

@@ -0,0 +1,3 @@
+$(function () {
+    autoFlashHeight();
+});

+ 6 - 4
app/router.js

@@ -710,10 +710,12 @@ module.exports = app => {
     app.post('/budget/:id/decimal', sessionAuth, budgetCheck, 'budgetController.decimal');
 
     // 支付审批
-    // app.get('/payment', sessionAuth, 'paymentController.index');
-    // app.post('/payment/permission/save', sessionAuth, 'paymentController.permissionSave');
-    app.get('/payment/:rid/detail/:id', sessionAuth, 'paymentController.detail');
-    // app.post('/payment/save', sessionAuth, 'paymentController.save');
+    app.get('/payment', sessionAuth, 'paymentController.index');
+    app.post('/payment/permission/save', sessionAuth, 'paymentController.permissionSave');
+    app.get('/payment/:pid/detail/:id', sessionAuth, 'paymentController.detail');
+    app.post('/payment/save', sessionAuth, 'paymentController.save');
+    app.post('/payment/load', sessionAuth, 'paymentController.listLoad');
+    app.get('/payment/:pid/process', sessionAuth, 'paymentController.process');
 
     // 企业微信回调
     app.get('/wx/work/callback/command', 'wechatController.command');

+ 123 - 0
app/service/payment_folder.js

@@ -0,0 +1,123 @@
+'use strict';
+
+/**
+ * 决策大屏用户查看权限-数据模型
+ *
+ * @author ellisran
+ * @date 2021/09/23
+ * @version
+ */
+const accountGroup = require('../const/account_group').group;
+const paymentConst = require('../const/payment');
+module.exports = app => {
+    class paymentFolder extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'payment_folder';
+        }
+
+        async addFolder(projectId, uid, parentId = 0, name) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                let level = 1;
+                let parent_path = '';
+                if (parentId !== 0) {
+                    const parentFolderInfo = await this.getDataById(parentId);
+                    if (!parentFolderInfo) throw '父目录不存在';
+                    level = parentFolderInfo.level + level;
+                    if (parentFolderInfo.is_leaf) {
+                        await transaction.update(this.tableName, { id: parentFolderInfo.id, is_leaf: 0 });
+                    }
+                    parent_path = parentFolderInfo.parent_path ? parentFolderInfo.parent_path + '-' + parentFolderInfo.id : parentFolderInfo.id;
+                }
+                const childrenCount = await transaction.count(this.tableName, { parent_id: parentId });
+                const order = childrenCount + 1;
+                const insertData = {
+                    pid: projectId,
+                    uid,
+                    name,
+                    parent_id: parentId,
+                    parent_path,
+                    level,
+                    order,
+                    is_leaf: 1,
+                    in_time: new Date(),
+                };
+                await transaction.insert(this.tableName, insertData);
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async deleteFolder(id) {
+            // 删除所有底下的目录
+            const transaction = await this.db.beginTransaction();
+            try {
+                const info = await this.getDataById(id);
+                let ids = [info.id];
+                if (info.parent_path) {
+                    const deleteData = await this.getDataByParentPath(this.tableName, info.parent_path + '-' + info.id + '%', transaction);
+                    if (deleteData.length > 0) {
+                        const delids = this._.map(deleteData, 'id');
+                        ids = [...ids, ...delids];
+                    }
+                }
+                await transaction.delete(this.tableName, { id: ids });
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async getDataByParentPath(tableName, parent_path, transaction = null) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('parent_path', {
+                value: this.db.escape(parent_path),
+                operate: 'Like',
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(tableName);
+            const resultData = transaction ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
+            return resultData;
+        }
+
+        async getList(uid, tenderList) {
+            let folderList = await this.getAllDataByCondition({ where: { uid } });
+            // 再找出标段对应的目录及自建的目录下的子目录
+            if (tenderList.length > 0) {
+                for (const t of tenderList) {
+                    if (this._.findIndex(folderList, { id: t.folder_id }) === -1) {
+                        const folderInfo = await this.getDataById(t.folder_id);
+                        folderList.push(folderInfo);
+                    }
+                }
+            }
+            if (folderList.length > 0) {
+                const leafFolderList = this._.filter(folderList, { is_leaf: 1 });
+                const parentFolderIdList = this._.map(this._.filter(folderList, { is_leaf: 0 }), 'id');
+                for (const lf of leafFolderList) {
+                    let parentPathArray = lf.parent_path !== '' ? lf.parent_path.split('-') : [];
+                    if (parentPathArray.length > 0) {
+                        parentPathArray = parentPathArray.map(function(data) {
+                            return +data;
+                        });// 字符串数组转整型数组
+                    }
+                    const notExistFolderIds = this._.difference(parentPathArray, parentFolderIdList);
+                    if (notExistFolderIds.length > 0) {
+                        const newFolderList = await this.getAllDataByCondition({ where: { id: notExistFolderIds } });
+                        console.log(newFolderList);
+                        folderList = [...folderList, ...newFolderList];
+                    }
+                }
+            }
+            return folderList;
+        }
+
+        // async getChildrenByParentId(parentId, transaction = null) {
+        //     const list = await this.getAllDataByCondition({ where: { parent_id: parentId } });
+        // }
+    }
+    return paymentFolder;
+};

+ 117 - 0
app/service/payment_permission_audit.js

@@ -0,0 +1,117 @@
+'use strict';
+
+/**
+ * 决策大屏用户查看权限-数据模型
+ *
+ * @author ellisran
+ * @date 2021/09/23
+ * @version
+ */
+const accountGroup = require('../const/account_group').group;
+const paymentConst = require('../const/payment');
+module.exports = app => {
+    class paymentPermissionAudit extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'payment_permission_audit';
+        }
+
+        async getGroupInfo(pid, groupid) {
+            const sql = 'SELECT * FROM ?? WHERE pid = ? AND groupid = ? AND uid is NULL';
+            const sqlParam = [this.tableName, pid, groupid];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        async saveAudits(pid, accountList) {
+            const pushData = [];
+            for (const a of accountList) {
+                const data = {
+                    pid,
+                    groupid: a.account_group,
+                    uid: a.id,
+                    create_time: new Date(),
+                };
+                pushData.push(data);
+            }
+            return pushData.length > 0 ? await this.db.insert(this.tableName, pushData) : false;
+        }
+
+        async saveGroup(pid, groupid) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                // 删除所在组的用户
+                await transaction.delete(this.tableName, { pid, groupid });
+                const data = {
+                    pid,
+                    groupid,
+                    create_time: new Date(),
+                };
+                await transaction.insert(this.tableName, data);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async delAudit(id) {
+            return await this.db.delete(this.tableName, { id });
+        }
+
+        async getOnePermission(is_admin, uid) {
+            if (is_admin) {
+                return paymentConst.audit_admin_permission;
+            }
+            const info = await this.getDataByCondition({ uid });
+            if (!info) return false;
+            info.permission_json = info.permission_json ? JSON.parse(info.permission_json) : paymentConst.audit_permission;
+            return info.permission_json;
+        }
+
+        async getList(pid) {
+            const list = await this.db.select(this.tableName, { where: { pid }, orders: [['id', 'desc']] });
+            for (const l of list) {
+                if (l.uid) {
+                    const accountInfo = await this.ctx.service.projectAccount.getDataById(l.uid);
+                    l.name = accountInfo.name;
+                    l.company = accountInfo.company;
+                    l.permission_json = l.permission_json ? JSON.parse(l.permission_json) : paymentConst.audit_permission;
+                } else {
+                    l.name = accountGroup[l.groupid];
+                }
+            }
+            return list;
+        }
+
+        async updateOnePermission(updateData) {
+            if (!updateData.id || !updateData.permission_json) {
+                return false;
+            }
+            updateData.permission_json = JSON.stringify(updateData.permission_json);
+            return await this.db.update(this.tableName, updateData);
+        }
+
+        async updateAllPermission(pid, type, value) {
+            if (this._.indexOf(paymentConst.permission_type_array, type) === -1 || this._.indexOf(paymentConst.permission_value_array, value) === -1) {
+                return false;
+            }
+            const permissionAudits = await this.getList(pid);
+            if (permissionAudits.length > 0) {
+                const updateList = [];
+                for (const pa of permissionAudits) {
+                    if (pa.permission_json[type] !== value) {
+                        pa.permission_json[type] = value;
+                        updateList.push({
+                            id: pa.id,
+                            permission_json: JSON.stringify(pa.permission_json),
+                        });
+                    }
+                }
+                if (updateList.length > 0) await this.db.updateRows(this.tableName, updateList);
+            }
+            return true;
+        }
+    }
+    return paymentPermissionAudit;
+};

+ 109 - 0
app/service/payment_tender.js

@@ -0,0 +1,109 @@
+'use strict';
+
+/**
+ * 决策大屏用户查看权限-数据模型
+ *
+ * @author ellisran
+ * @date 2021/09/23
+ * @version
+ */
+const accountGroup = require('../const/account_group').group;
+const paymentConst = require('../const/payment');
+module.exports = app => {
+    class paymentTender extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'payment_tender';
+        }
+
+        async getList(uid) {
+            const sql = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pt.`uid` = ?';
+            const params = [this.tableName, this.ctx.service.projectAccount.tableName, uid];
+            return this.db.query(sql, params);
+        }
+
+        async addTender(projectId, uid, folderId, name) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const folderInfo = await this.ctx.service.paymentFolder.getDataById(folderId);
+                if (!folderInfo || folderInfo.is_leaf === 0) {
+                    throw '目录不存在或存在子目录不能新建标段';
+                }
+                const insertData = {
+                    pid: projectId,
+                    uid,
+                    name,
+                    folder_id: folderId,
+                    in_time: new Date(),
+                };
+                await transaction.insert(this.tableName, insertData);
+                const updateData = [
+                    { id: folderInfo.id, had_tender: 1 },
+                ];
+                // 更新父节点had_tender值
+                if (folderInfo.parent_path) {
+                    const parentFolderIds = folderInfo.parent_path.split('-');
+                    for (const pf of parentFolderIds) {
+                        updateData.push({
+                            id: parseInt(pf),
+                            had_tender: 1,
+                        });
+                    }
+                }
+                await transaction.updateRows(this.ctx.service.paymentFolder.tableName, updateData);
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async deleteTender(id) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const tenderInfo = await this.getDataById(id);
+                if (!tenderInfo) {
+                    throw '标段不存在';
+                }
+                const folderInfo = await this.ctx.service.paymentFolder.getDataById(tenderInfo.folder_id);
+                if (!folderInfo) {
+                    throw '目录不存在';
+                }
+                // 判断folderInfo下是否还存在tender,不存在则把had_tender为0,并判断父节点是否需要也为0
+                const leafTenderCount = await transaction.count(this.tableName, { folder_id: folderInfo.id });
+                if (leafTenderCount === 1) {
+                    const updateDatas = [{
+                        id: folderInfo.id,
+                        had_tender: 0,
+                    }];
+                    if (folderInfo.parent_path) {
+                        const parentFolderIds = folderInfo.parent_path.split('-').reverse();
+                        for (const pfid of parentFolderIds) {
+                            const parentFolderId = parseInt(pfid);
+                            const leafFolderCount = await transaction.count(this.ctx.service.paymentFolder.tableName, { parent_id: parentFolderId, had_tender: 1 });
+                            if (leafFolderCount === 1) {
+                                updateDatas.push({
+                                    id: parentFolderId,
+                                    had_tender: 0,
+                                });
+                            } else {
+                                break;
+                            }
+                        }
+                    }
+                    await transaction.updateRows(this.ctx.service.paymentFolder.tableName, updateDatas);
+                }
+                await transaction.delete(this.tableName, { id });
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        // async getChildrenByParentId(parentId, transaction = null) {
+        //     const list = await this.getAllDataByCondition({ where: { parent_id: parentId } });
+        // }
+    }
+    return paymentTender;
+};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 650 - 640
app/view/payment/detail.ejs


+ 31 - 0
app/view/payment/index.ejs

@@ -0,0 +1,31 @@
+<div class="panel-content">
+    <div class="panel-title fluid">
+        <div class="title-main  d-flex justify-content-between">
+            <div>支付审批 <a href="payment-approval-settings.html" class="ml-1" data-toggle="tooltip" data-placement="top" title="模块配置"><i class="fa fa-cog"></i></a></div>
+            <div>
+                <% if (auditPermission.tender) { %>
+                <a href="javascript:void(0);" style="display: none" id="show_new_tender_btn" class="btn btn-sm btn-primary pull-right show_new_tender_btn">新建标段</a>
+                <% } %>
+                <% if (auditPermission.folder) { %>
+                <a href="#add-folder" data-toggle="modal" data-target="#add-folder" data-parentId="0" class="btn btn-sm btn-primary pull-right mr-2 show_new_folder_btn">新建目录</a>
+                <% } %>
+                <% if (ctx.session.sessionUser.is_admin) { %>
+                <a href="#authority-list" data-toggle="modal" data-target="#authority-list" class="btn btn-sm btn-outline-secondary pull-right mr-2">权限管理</a>
+                <% } %>
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="sjs-height-0" style="background-color: #fff">
+            <div class="c-body">
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    let tenderTree = [];
+    let allFolders = [];
+    let allTenders = [];
+    const uid = <%- ctx.session.sessionUser.accountId %>;
+    const auditPermission = JSON.parse(unescape('<%- escape(JSON.stringify(auditPermission)) %>'));
+</script>

+ 408 - 0
app/view/payment/modal.ejs

@@ -0,0 +1,408 @@
+<% if (auditPermission.folder) { %>
+<!-- 弹窗新建目录 -->
+<div class="modal fade" id="add-folder" 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">
+                <div class="form-group" id="parent_folder" style="display: none">
+                    <label for="parent_folder_name">父目录名称</label>
+                    <input type="text" class="form-control form-control-sm" id="parent_folder_name" readonly>
+                </div>
+                <div class="form-group">
+                    <label for="new_folder_name">目录名称</label>
+                    <input type="text" class="form-control form-control-sm" id="new_folder_name" placeholder="请输入目录名称" required>
+                    <div class="invalid-feedback">
+                        <!--名称超过100个字,请缩减名称-->
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" id="parent_id" value="0">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-primary" id="new_folder_btn">确定添加</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } %>
+<div class="modal fade" id="edit-name" 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">
+                <form>
+                    <div class="form-group">
+                        <label for="edit_name_input">名称</label>
+                        <input type="text" class="form-control form-control-sm" id="edit_name_input" placeholder="请输入名称" required>
+                        <div class="invalid-feedback">
+                            <!--名称超过100个字,请缩减名称-->
+                        </div>
+                    </div>
+                </form>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" id="edit_name_id" />
+                <input type="hidden" id="edit_name_type" />
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-primary" id="edit_name_btn">确定修改</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% if (auditPermission.tender) { %>
+<!-- 弹窗新建标段 -->
+<div class="modal fade" id="add-tender" 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">
+                <div class="form-group">
+                    <label for="add_tender_folder_name">目录名称</label>
+                    <input type="text" class="form-control form-control-sm" id="add_tender_folder_name" readonly>
+                </div>
+                <div class="form-group">
+                    <label for="add_tender_name">标段名称</label>
+                    <input type="text" class="form-control form-control-sm" id="add_tender_name" placeholder="请输入标段名称" required>
+                    <div class="invalid-feedback">
+                        <!--名称超过100个字,请缩减名称-->
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" id="add_tender_folder_id" />
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-primary" id="new_tender_btn">确定添加</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } %>
+<!-- 弹窗删除项目 -->
+<div class="modal fade" id="del-project" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">删除标段</h5>
+            </div>
+            <div class="modal-body">
+                <h6>确认删除 <span></span>?</h6>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" id="del_id" />
+                <input type="hidden" id="del_type" />
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-danger" id="del_btn">确定删除</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<% if (ctx.session.sessionUser.is_admin) { %>
+    <link href="/public/css/bootstrap/bootstrap-table.min.css" rel="stylesheet">
+    <link href="/public/css/bootstrap/bootstrap-table-fixed-columns.min.css" rel="stylesheet">
+        <style>
+            /*.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer) {*/
+                /*border-bottom: 0;*/
+            /*}*/
+            /*table {*/
+                /*table-layout: fixed;*/
+            /*}*/
+        </style>
+<!-- 弹窗编辑项目 -->
+<div class="modal fade" id="authority-list" 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="d-flex flex-row bg-graye">
+                    <div class="p-2">
+                        <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton"
+                                data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                            添加用户
+                        </button>
+                        <div class="dropdown-menu dropdown-menu-left" aria-labelledby="dropdownMenuButton" style="width:220px">
+                            <div class="mb-2 p-2"><input class="form-control form-control-sm" placeholder="姓名/手机 检索"
+                                                         id="gr-search" autocomplete="off"></div>
+                            <dl class="list-unstyled book-list">
+                                <% accountGroup.forEach((group, idx) => { %>
+                                    <dt><a href="javascript: void(0);" class="acc-btn" data-groupid="<%- idx %>"
+                                           data-type="hide"><i class="fa fa-plus-square"></i></a> <%- group.groupName %></dt>
+                                    <div class="dd-content" data-toggleid="<%- idx %>">
+                                        <dd class="border-bottom p-2 mb-0" data-groupid="<%- idx %>"><p class="mb-0 d-flex"><span class="text-primary">该单位下所有组员</span></p></dd>
+                                        <% group.groupList.forEach(item => { %>
+                                            <dd class="border-bottom p-2 mb-0 " data-id="<%- item.id %>">
+                                                <p class="mb-0 d-flex"><span class="text-primary"><%- item.name %></span><span
+                                                            class="ml-auto"><%- item.mobile %></span></p>
+                                                <span class="text-muted"><%- item.role %></span>
+                                            </dd>
+                                        <% });%>
+                                    </div>
+                                <% }) %>
+                            </dl>
+                        </div>
+                    </div>
+                    <div class="p-2"><a href="javascript:void(0)" id="del-permission-audits-btn">批量删除</a></div>
+                </div>
+                <div style="height:300px">
+                <table id="permission-audit-table" class="table table-bordered" data-height="300" data-toggle="table">
+                    <thead>
+                    <tr>
+                        <th class="text-center">选择</th>
+                        <th class="text-center">用户名</th>
+                        <th class="text-center">单位</th>
+                        <th class="text-center">添加时间</th>
+                        <th class="text-center"><input type="checkbox" class="permission-all-checkbox" data-type="tender"> 新建标段</th>
+                        <th class="text-center"><input type="checkbox" class="permission-all-checkbox" data-type="folder"> 新建目录</th>
+                        <th class="text-center"><input type="checkbox" class="permission-all-checkbox" data-type="process"> 设置审批流程</th>
+                        <th class="text-center">操作</th>
+                    </tr>
+                    </thead>
+                    <tbody id="permission-audit-list">
+                    <% for (const pa of permissionAudits) { %>
+                    <tr>
+                        <td class="text-center"><input type="checkbox" name="uid[]" value="<%- pa.id %>"></td>
+                        <td class="text-left"><%- pa.name %></td>
+                        <td class="text-left"><%- pa.company %></td>
+                        <td class="text-left"><%- ctx.helper.formatFullDate(pa.create_time) %></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="tender" value="<%- pa.id %>" <% if (pa.permission_json.tender) { %>checked<% } %>></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="folder" value="<%- pa.id %>" <% if (pa.permission_json.folder) { %>checked<% } %>></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="process" value="<%- pa.id %>" <% if (pa.permission_json.process) { %>checked<% } %>></td>
+                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="<%- pa.id %>">移除</a></td>
+                    </tr>
+                    <% } %>
+                    </tbody>
+                </table>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-outline-dark" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!-- 弹窗删除权限用户 -->
+<div class="modal fade" id="del-permission-audit" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">删除用户</h5>
+            </div>
+            <div class="modal-body">
+                <h6>确认删除当前所选用户?</h6>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" id="del-audit-ids" />
+                <button type="button" class="btn btn-sm btn-danger" id="del-audit-btn">确定删除</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } %>
+<% if (ctx.session.sessionUser.is_admin) { %>
+    <script src="/public/js/bootstrap/bootstrap-table.min.js"></script>
+    <script src="/public/js/bootstrap/locales/bootstrap-table-zh-CN.min.js"></script>
+    <script src="/public/js/bootstrap/bootstrap-table-fixed-columns.min.js"></script>
+<script>
+    $(function () {
+        // $("#permission-audit-table").bootstrapTable('destroy').bootstrapTable({
+        //     fixedColumns: true,
+        //     // height:200
+        //     // fixedNumber: 1 //固定列数
+        // });
+        let timer = null
+        let oldSearchVal = null
+        let permissionAudits = JSON.parse(unescape('<%- escape(JSON.stringify(permissionAudits)) %>'));
+        const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
+        const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
+        $('#gr-search').bind('input propertychange', function(e) {
+            oldSearchVal = e.target.value
+            timer && clearTimeout(timer)
+            timer = setTimeout(() => {
+                const newVal = $('#gr-search').val()
+                let html = ''
+                if (newVal && newVal === oldSearchVal) {
+                    accountList.filter(item => item && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
+                        html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                        <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                class="ml-auto">${item.mobile || ''}</span></p>
+                        <span class="text-muted">${item.role || ''}</span>
+                    </dd>`
+                    })
+                    $('.book-list').empty()
+                    $('.book-list').append(html)
+                } else {
+                    if (!$('.acc-btn').length) {
+                        accountGroup.forEach((group, idx) => {
+                            if (!group) return
+                            html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
+                        </a> ${group.groupName}</dt>
+                        <div class="dd-content" data-toggleid="${idx}">
+                        <dd class="border-bottom p-2 mb-0" data-groupid="${idx}"><p class="mb-0 d-flex"><span class="text-primary">该单位下所有组员</span></p></dd>`
+                            group.groupList.forEach(item => {
+                                    html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                                    <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                            class="ml-auto">${item.mobile || ''}</span></p>
+                                    <span class="text-muted">${item.role || ''}</span>
+                                </dd>`
+                            });
+                            html += '</div>'
+                        })
+                        $('.book-list').empty()
+                        $('.book-list').append(html)
+                    }
+                }
+            }, 400);
+        });
+        // 添加到成员中
+        $('.book-list').on('click', 'dt', function () {
+            const idx = $(this).find('.acc-btn').attr('data-groupid')
+            const type = $(this).find('.acc-btn').attr('data-type')
+            if (type === 'hide') {
+                $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
+                    $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o')
+                    $(this).find('.acc-btn').attr('data-type', 'show')
+
+                })
+            } else {
+                $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
+                    $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square')
+                    $(this).find('.acc-btn').attr('data-type', 'hide')
+                })
+            }
+            return false
+        });
+        // 添加到成员中
+        $('dl').on('click', 'dd', function () {
+            const id = parseInt($(this).data('id'));
+            const groupid = parseInt($(this).data('groupid'));
+            if (!isNaN(id) && id !== 0) {
+                postData('/payment/permission/save', { type: 'add-audit', id: id }, function (result) {
+                    permissionAudits = result;
+                    setList(permissionAudits);
+                })
+            } else if (!isNaN(groupid) && groupid !== 0) {
+                const groupAuditList = _.filter(accountList, { account_group: groupid });
+                const groupAidList = _.map(groupAuditList, 'id');
+                const groupPAList = _.map(_.filter(permissionAudits, { groupid }), 'id');
+                const addAidList = _.difference(groupAidList, groupPAList);
+                console.log(addAidList);
+                if (addAidList.length > 0) {
+                    postData('/payment/permission/save', { type: 'add-audit', id: addAidList }, function (result) {
+                        // toastr.success(`成功添加 位用户`);
+                        permissionAudits = result;
+                        setList(permissionAudits);
+                    })
+                } else {
+                    toastr.warning('暂无用户添加');
+                }
+            }
+        });
+
+        function setList(datas) {
+            let list = '';
+            for (const pa of datas) {
+                list += `<tr>
+                        <td class="text-center"><input type="checkbox" name="uid[]" value="${pa.id}"></td>
+                        <td class="text-left">${pa.name}</td>
+                        <td class="text-left">${pa.company}</td>
+                        <td class="text-left">${moment(pa.create_time).format('YYYY-MM-DD HH:mm:ss')}</td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="tender" value="${pa.id}" ${pa.permission_json.tender ? 'checked' : ''}></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="folder" value="${pa.id}" ${pa.permission_json.folder ? 'checked' : ''}></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="process" value="${pa.id}" ${pa.permission_json.process ? 'checked' : ''}></td>
+                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="${pa.id}">移除</a></td>
+                    </tr>`;
+            }
+            $('#permission-audit-list').html(list);
+            $("#permission-audit-table").bootstrapTable('resetView');
+        }
+        let first = 1;
+        $('#authority-list').on('shown.bs.modal', function () {
+            if (first) {
+                const option = {
+                    fixedColumns: true,
+                    fixedNumber: 1, //固定列数
+                    locale: 'zh-CN',
+                }
+                // if (permissionAudits.length === 0) {
+                //     option.formatName = function () {
+                //         return '暂无数据';
+                //     }
+                // }
+                $("#permission-audit-table").bootstrapTable('destroy').bootstrapTable(option);
+                first = 0;
+            }
+        })
+
+        $('#del-permission-audits-btn').click(function () {
+            const checkArray = [];
+            $('#permission-audit-list input[name="uid[]"]:checked').each(function() {
+                checkArray.push(parseInt($(this).val())); //向数组中添加元素
+            });
+            console.log(checkArray);
+            if (checkArray.length === 0) {
+                toastr.warning('暂无用户被选中');
+            } else {
+                $('#del-audit-ids').val(checkArray.join(','));
+                $('#del-permission-audit').modal('show');
+            }
+        });
+
+        $('body').on('click', '.del-permission-audit-a', function () {
+            $('#del-audit-ids').val($(this).attr('data-id'));
+            $('#del-permission-audit').modal('show');
+        });
+
+        $('#del-audit-btn').click(function () {
+            let uids = $('#del-audit-ids').val();
+            postData('/payment/permission/save', { type: 'del-audit', id: uids.split(',') }, function (result) {
+                // toastr.success(`成功添加 位用户`);
+                $('#del-permission-audit').modal('hide');
+                permissionAudits = result;
+                setList(permissionAudits);
+
+            })
+        });
+
+        // 权限勾选
+        $('body').on('click', '.permission-checkbox', function () {
+            console.log($(this).attr('data-type'), $(this).val(), $(this).is(':checked'));
+            const type = $(this).attr('data-type');
+            const value = $(this).is(':checked') ? 1 : 0;
+            const userInfo = _.find(permissionAudits, { id: parseInt($(this).val()) });
+            if (!userInfo) {
+                toastr.error('用户不存在');
+            }
+            userInfo.permission_json[type] = value;
+            const updateInfo = {
+                id: userInfo.id,
+                permission_json: userInfo.permission_json,
+            }
+            postData('/payment/permission/save', { type: 'save-permission-one', updateData: updateInfo }, function (result) {
+                // toastr.success(`成功添加 位用户`);
+            })
+        });
+
+        $('body').on('click', '.permission-all-checkbox', function () {
+            console.log($(this).attr('data-type'), $(this).is(':checked'));
+            const type = $(this).attr('data-type');
+            const value = $(this).is(':checked') ? 1 : 0;
+            postData('/payment/permission/save', { type: 'save-permission-all', permission_type: type, value }, function (result) {
+                // toastr.success(`成功添加 位用户`);
+                permissionAudits = result;
+                setList(permissionAudits);
+            })
+        })
+    })
+</script>
+<% } %>

+ 381 - 0
app/view/payment/process.ejs

@@ -0,0 +1,381 @@
+<div class="panel-content">
+    <div class="panel-title fluid">
+        <div class="title-main  d-flex justify-content-between">
+            <div>支付审批/审批流程</div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <div class="m-3">
+                    <ul class="nav nav-tabs" id="myTab" role="tablist">
+                        <li class="nav-item">
+                            <a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">常规审批流程</a>
+                        </li>
+                        <li class="nav-item">
+                            <a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">表单审批流程</a>
+                        </li>
+                    </ul>
+                    <div class="tab-content" id="myTabContent">
+                        <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
+                            <div class="row mt-3">
+                                <div class="col-8 mt-3">
+                                    <div class="card">
+                                        <div class="card-body">
+                                            <h5 class="card-title">安全生成费</h5>
+                                            <div class="form-group">
+                                                <div class="form-check form-check-inline">
+                                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox3" value="option1">
+                                                    <label class="form-check-label" for="inlineCheckbox16">授权审批流</label>
+                                                </div>
+                                                <div class="form-check form-check-inline">
+                                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox4" value="option1" checked>
+                                                    <label class="form-check-label" for="inlineCheckbox16">固定审批流</label>
+                                                </div>
+                                            </div>
+                                            <div class="alert alert-warning mb-0 mt-3" role="alert">固定审批流:审批流程固定,上报人只能按照设置好的审批流程进行。</div>
+                                            <div class="d-flex justify-content-start align-items-center mt-3">
+                                                <div class="mr-2"><a href="#">一审</a></div>
+                                                <div>
+                                                    <select class="form-control form-control-sm" id="exampleFormControlSelect1">
+                                                        <option>选择审批人</option>
+                                                    </select>
+                                                </div>
+                                            </div>
+                                            <div class="d-flex justify-content-start align-items-center mt-3">
+                                                <div class="mr-2"><a href="#">一审</a></div>
+                                                <div class="mr-2">邓莹洁</div>
+                                                <div><i class="fa fa-remove text-danger" aria-hidden="true"></i></div>
+                                            </div>
+                                            <div class="d-flex justify-content-start align-items-center mt-3">
+                                                <div class="mr-2"><a href="#"><i class="fa fa-plus" aria-hidden="true"></i></a></div>
+                                                <div><a href="#">添加流程</a></div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div class="col-8 mt-3">
+                                    <div class="card">
+                                        <div class="card-body">
+                                            <h5 class="card-title">安全生成费</h5>
+                                            <div class="form-group">
+                                                <div class="form-check form-check-inline">
+                                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox5" value="option1">
+                                                    <label class="form-check-label" for="inlineCheckbox16">授权审批流</label>
+                                                </div>
+                                                <div class="form-check form-check-inline">
+                                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox6" value="option1" checked>
+                                                    <label class="form-check-label" for="inlineCheckbox16">固定审批流</label>
+                                                </div>
+                                            </div>
+                                            <div class="alert alert-warning mb-0 mt-3" role="alert">固定终审:结束审批流为固定人,终审前的审批流程由上报人设置,即授权审批人。</div>
+                                            <div class="d-flex justify-content-start align-items-center mt-3">
+                                                <div class="mr-2"><a href="#">终审</a></div>
+                                                <div>
+                                                    <select class="form-control form-control-sm" id="exampleFormControlSelect1">
+                                                        <option>选择审批人</option>
+                                                    </select>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
+                            <div class="row">
+                                <div class="col-4">
+                                    <div class="my-3"><a href="#">添加表单</a></div>
+                                    <table class="table table-bordered">
+                                        <thead>
+                                        <tr>
+                                            <th>名称</th>
+                                            <th>添加人</th>
+                                            <th>表单角色</th>
+                                        </tr>
+                                        </thead>
+                                        <tbody>
+                                        <tr>
+                                            <td>指挥部工程结算款</td>
+                                            <td>管理员</td>
+                                            <td>6</td>
+                                        </tr>
+                                        <tr>
+                                            <td>指挥部工程结算付款</td>
+                                            <td>管理员</td>
+                                            <td>6</td>
+                                        </tr>
+                                        <tr>
+                                            <td>指挥部监理、设计等预付款</td>
+                                            <td>管理员</td>
+                                            <td>7</td>
+                                        </tr>
+                                        <tr>
+                                            <td>指挥部监理、设计等结算款</td>
+                                            <td>邓莹洁</td>
+                                            <td>4</td>
+                                        </tr>
+                                        <tr>
+                                            <td>招标文件合同送审单</td>
+                                            <td>邓莹洁</td>
+                                            <td>4</td>
+                                        </tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                                <div class="col-8">
+                                    <ul class="nav nav-tabs my-2" id="myTab" role="tablist">
+                                        <li class="nav-item">
+                                            <a class="nav-link active" id="home-tab" data-toggle="tab" href="#role" role="tab" aria-controls="role" aria-selected="true">表单角色</a>
+                                        </li>
+                                        <li class="nav-item">
+                                            <a class="nav-link" id="profile-tab" data-toggle="tab" href="#process" role="tab" aria-controls="process" aria-selected="false">审批流程</a>
+                                        </li>
+                                    </ul>
+                                    <div class="tab-content" id="myTabContent">
+                                        <div class="tab-pane fade show active" id="role" role="tabpanel" aria-labelledby="home-tab">
+                                            <div class="row">
+                                                <div class="col-6">
+                                                    <table class="table table-bordered">
+                                                        <thead>
+                                                        <tr>
+                                                            <th>序号</th>
+                                                            <th>表单角色</th>
+                                                            <th>不参与审批</th>
+                                                            <th>签字签章</th>
+                                                        </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                        <tr>
+                                                            <td>1</td>
+                                                            <td>监理公司</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>2</td>
+                                                            <td>造价咨询单位</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>3</td>
+                                                            <td>经办人</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>4</td>
+                                                            <td>合同管理人</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>5</td>
+                                                            <td>相关科室负责人</td>
+                                                            <td><input type="checkbox" checked></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>6</td>
+                                                            <td>计划财务科科长</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>7</td>
+                                                            <td>分管领导</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        </tbody>
+                                                    </table>
+                                                </div>
+                                                <div class="col-6">
+                                                    <table class="table table-bordered">
+                                                        <thead>
+                                                        <tr>
+                                                            <th>序号</th>
+                                                            <th>表单角色</th>
+                                                            <th>不参与审批</th>
+                                                            <th>签字签章</th>
+                                                            <th>操作</th>
+                                                        </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                        <tr>
+                                                            <td>1</td>
+                                                            <td>监理公司</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>2</td>
+                                                            <td>造价咨询单位</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>3</td>
+                                                            <td>经办人</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>4</td>
+                                                            <td>合同管理人</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>5</td>
+                                                            <td>相关科室负责人</td>
+                                                            <td><input type="checkbox" checked></td>
+                                                            <td><span class="mr-2">张三</span><a href="#">更改</a></td>
+                                                            <td><a href="#">预览</a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>6</td>
+                                                            <td>计划财务科科长</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>7</td>
+                                                            <td>分管领导</td>
+                                                            <td><input type="checkbox"></td>
+                                                            <td></td>
+                                                            <td></td>
+                                                        </tr>
+                                                        </tbody>
+                                                    </table>
+                                                </div>
+                                            </div>
+                                        </div>
+                                        <div class="tab-pane fade" id="process" role="tabpanel" aria-labelledby="profile-tab">
+                                            <div class="row">
+                                                <div class="col-6">
+                                                    <table class="table table-bordered">
+                                                        <thead>
+                                                        <tr>
+                                                            <th>审批流程</th>
+                                                            <th>表单角色</th>
+                                                            <th><b class="text-danger">*&nbsp;</b>审批人</th>
+                                                            <th>更换顺序</th>
+                                                        </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                        <tr>
+                                                            <td>一审</td>
+                                                            <td>监理公司</td>
+                                                            <td><select class="form-control form-control-sm"><option>请选择审批人</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>二审</td>
+                                                            <td>造价咨询单位</td>
+                                                            <td><select class="form-control form-control-sm"><option>李四</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>三审</td>
+                                                            <td>经办人</td>
+                                                            <td><select class="form-control form-control-sm"><option>王五</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>四审</td>
+                                                            <td>合同管理人</td>
+                                                            <td><select class="form-control form-control-sm"><option>老六</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>五审</td>
+                                                            <td>计划财务科科长</td>
+                                                            <td><select class="form-control form-control-sm"><option>邓莹洁</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>六审</td>
+                                                            <td>分管领导</td>
+                                                            <td><select class="form-control form-control-sm"><option>仁温书</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        </tbody>
+                                                    </table>
+                                                    <div class="my-3"><a href="#">添加流程</a></div>
+                                                </div>
+                                                <div class="col-6">
+                                                    <table class="table table-bordered">
+                                                        <thead>
+                                                        <tr>
+                                                            <th>审批流程</th>
+                                                            <th>表单角色</th>
+                                                            <th><b class="text-danger">*&nbsp;</b>审批人</th>
+                                                            <th>更换顺序</th>
+                                                        </tr>
+                                                        </thead>
+                                                        <tbody>
+                                                        <tr>
+                                                            <td>一审</td>
+                                                            <td>监理公司</td>
+                                                            <td><select class="form-control form-control-sm"><option>请选择审批人</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>二审</td>
+                                                            <td>造价咨询单位</td>
+                                                            <td><select class="form-control form-control-sm"><option>李四</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>三审</td>
+                                                            <td>经办人</td>
+                                                            <td><select class="form-control form-control-sm"><option>王五</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>四审</td>
+                                                            <td>合同管理人</td>
+                                                            <td><select class="form-control form-control-sm"><option>老六</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>五审</td>
+                                                            <td>计划财务科科长</td>
+                                                            <td><select class="form-control form-control-sm"><option>邓莹洁</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>六审</td>
+                                                            <td>分管领导</td>
+                                                            <td><select class="form-control form-control-sm"><option>仁温书</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        <tr>
+                                                            <td>七审</td>
+                                                            <td>主管领导(新添加的流程)</td>
+                                                            <td><select class="form-control form-control-sm"><option>请选择审批人</option></select></td>
+                                                            <td><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a><a href="" class="btn btn-sm btn-link text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></td>
+                                                        </tr>
+                                                        </tbody>
+                                                    </table>
+                                                    <div class="my-3"><a href="#">添加流程</a></div>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 8 - 0
config/menu.js

@@ -56,6 +56,14 @@ const menu = {
         caption: '项目管理',
         children: null,
     },
+    payment: {
+        name: '支付审批',
+        icon: 'fa-handshake-o',
+        display: true,
+        url: '/payment',
+        caption: '支付审批',
+        children: null,
+    },
     // sum: {
     //     name: '总分包',
     //     icon: 'fa-sitemap',

+ 22 - 3
config/web.js

@@ -1071,9 +1071,28 @@ const JsFiles = {
                     '/public/js/path_tree.js',
                     '/public/js/budget_detail.js',
                 ],
-                mergeFile: 'budget_detail.js'
-            }
-        }
+                mergeFile: 'budget_detail.js',
+            },
+        },
+        payment: {
+            index: {
+                files: [
+                    '/public/js/ztree/jquery.ztree.core.js', '/public/js/ztree/jquery.ztree.exedit.js',
+                    '/public/js/moment/moment.min.js',
+                ],
+                mergeFiles: [
+                    '/public/js/payment_index.js',
+                ],
+                mergeFile: 'index',
+            },
+            process: {
+                files: [],
+                mergeFiles: [
+                    '/public/js/payment_process.js',
+                ],
+                mergeFile: 'process',
+            },
+        },
     },
 };