Просмотр исходного кода

支付审批功能迁移至子项目里

ellisran 2 месяцев назад
Родитель
Сommit
8ee6089b45

+ 1 - 1
app/base/base_controller.js

@@ -39,6 +39,7 @@ class BaseController extends Controller {
             menuList.contract.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.page_show.openContract : false;
             menuList.financial.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.page_show.openFinancial : false;
             menuList.budget.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showBudget : false;
+            menuList.payment.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showPayment : false;
             for (const index in menuList) {
                 const im = menuList[index];
                 if (!im.url) {
@@ -54,7 +55,6 @@ class BaseController extends Controller {
                 }
             }
         } else {
-            menuList.payment.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showPayment : false;
             menuList.management.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.page_show.openManagement : false;
         }
         ctx.menuList = menuList;

+ 40 - 52
app/controller/payment_controller.js

@@ -34,7 +34,7 @@ module.exports = app => {
                 if (!ctx.session.sessionProject.showPayment) {
                     throw '该功能已关闭或无法查看';
                 }
-                const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId);
+                const auditPermission = await ctx.service.subProjPermission.getPaymentPermission(ctx.subProject.permission.payment_permission);
                 if (!auditPermission) {
                     throw '权限不足';
                 }
@@ -46,12 +46,9 @@ module.exports = app => {
                 };
                 if (ctx.session.sessionUser.is_admin) {
                     const projectId = ctx.session.sessionProject.id;
-                    const permissionAudits = await ctx.service.paymentPermissionAudit.getList(projectId);
+                    const permissionAudits = await ctx.service.subProjPermission.getPaymentAuditList(ctx.subProject.id);
                     // 获取所有项目参与者
-                    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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                     const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: projectId } });
                     const accountGroupList = unitList.map(item => {
                         const groupList = accountList.filter(item1 => item1.company === item.name);
@@ -64,7 +61,12 @@ module.exports = app => {
                     renderData.permissionAudits = permissionAudits;
                     renderData.accountList = accountList;
                     renderData.accountGroup = accountGroupList;
+                    // 整理未分类的支付审批标段
+                    const noSpFolderList = await ctx.service.paymentFolder.getNoSpList(ctx.session.sessionProject.id);
+                    renderData.noSpFolderList = ctx.helper._.orderBy(noSpFolderList, ['in_time'], ['asc']);
                 }
+                const noSpTenderList = await ctx.service.paymentTender.getNoSpList(ctx.session.sessionProject.id);
+                renderData.noSpTenderList = ctx.helper._.orderBy(noSpTenderList, ['in_time'], ['asc']);
                 await this.layout('payment/index.ejs', renderData, 'payment/modal.ejs');
             } catch (err) {
                 console.log(err);
@@ -78,7 +80,7 @@ module.exports = app => {
             const responseData = {
                 err: 0, msg: '', data: {},
             };
-            const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId);
+            const auditPermission = await ctx.service.subProjPermission.getPaymentPermission(ctx.subProject.permission.payment_permission);
             if (!auditPermission) {
                 throw '权限不足';
             }
@@ -120,30 +122,33 @@ module.exports = app => {
                         // 判断用户是单个还是数组
                         uids = data.id instanceof Array ? data.id : [data.id];
                         // 判断该用户的组是否已加入到表中,已加入则提示无需添加
-                        auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { pid: projectId, uid: uids } });
+                        auditList = await ctx.service.subProjPermission.getPaymentAuditList(ctx.subProject.id, 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);
+                        // const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { id: addAidList } });
+                        await ctx.service.subProjPermission.savePaymentPermissionAudits(ctx.subProject.id, addAidList, 'add');
+                        responseData.data = await ctx.service.subProjPermission.getPaymentAuditList(ctx.subProject.id);
                         break;
                     case 'del-audit':
                         uids = data.id instanceof Array ? data.id : [data.id];
-                        auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { id: uids } });
+                        auditList = await ctx.service.subProjPermission.getPaymentAuditList(ctx.subProject.id, uids);
                         if (auditList.length !== uids.length) {
                             throw '该用户已不存在权限中,移除失败';
                         }
-                        await ctx.service.paymentPermissionAudit.delAudit(uids);
-                        responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId);
+                        await ctx.service.subProjPermission.savePaymentPermissionAudits(ctx.subProject.id, uids, 'del');
+                        responseData.data = await ctx.service.subProjPermission.getPaymentAuditList(ctx.subProject.id);
                         break;
                     case 'save-permission-one':
-                        result = await ctx.service.paymentPermissionAudit.updateOnePermission(data.updateData);
+                        result = await ctx.service.subProjPermission.updateOnePaymentPermission(ctx.subProject.id, data.updateData);
                         if (!result) {
                             throw '修改权限失败';
                         }
                         break;
+                    case 'bind-sp':
+                        result = await ctx.service.paymentTender.bindSp(data.tids);
+                        break;
                     // case 'save-permission-all':
                     //     result = await ctx.service.paymentPermissionAudit.updateAllPermission(projectId, data.permission_type, data.value);
                     //     if (!result) {
@@ -187,7 +192,7 @@ module.exports = app => {
                     throw '该功能已关闭或无法查看';
                 }
                 const projectId = ctx.session.sessionProject.id;
-                const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId);
+                const auditPermission = await ctx.service.subProjPermission.getPaymentPermission(ctx.subProject.permission.payment_permission);
                 if (!auditPermission) {
                     throw '权限不足';
                 }
@@ -246,8 +251,7 @@ module.exports = app => {
                         if (!ctx.session.sessionUser.is_admin) {
                             throw '您无权操作';
                         }
-                        const projectInfo = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
-                        const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes);
+                        const modes = ctx.subProject.payment_setting ? JSON.parse(ctx.subProject.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes);
                         const checked = data.checked;
                         if (modes[data.mode_type]) {
                             const detailCount = await ctx.service.paymentDetail.getCountByPidType(ctx.session.sessionProject.id, modes[data.mode_type].value);
@@ -265,7 +269,7 @@ module.exports = app => {
                         } else {
                             throw '该模块不存在';
                         }
-                        await ctx.service.project.defaultUpdate({ id: ctx.session.sessionProject.id, payment_setting: JSON.stringify(modes) });
+                        await ctx.service.subProject.defaultUpdate({ id: ctx.subProject.id, payment_setting: JSON.stringify(modes) });
                         break;
                     case 'info':
                         await ctx.service.paymentTenderInfo.saveTenderInfo(data.postData.id, data.postData.info);
@@ -290,8 +294,7 @@ module.exports = app => {
                 if (!ctx.session.sessionUser.is_admin) {
                     throw '您无权打开此页';
                 }
-                const projectInfo = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
-                const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes);
+                const modes = ctx.subProject.payment_setting ? JSON.parse(ctx.subProject.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes);
                 for (const m in modes) {
                     const detailCount = await ctx.service.paymentDetail.getCountByPidType(ctx.session.sessionProject.id, modes[m].value);
                     modes[m].can_check = !detailCount;
@@ -306,7 +309,7 @@ module.exports = app => {
                 console.log(err);
                 this.log(err);
                 ctx.session.postError = err.toString();
-                ctx.redirect('/payment');
+                ctx.redirect(`/sp/${ctx.subProject.id}/payment`);
             }
         }
 
@@ -431,7 +434,7 @@ module.exports = app => {
                     moment,
                     whiteList: ctx.app.config.multipart.whitelist,
                     uidList,
-                    preUrl: '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id,
+                    preUrl: '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id,
                     OSS_PATH: ctx.app.config.fujianOssPath,
                 };
                 renderData.nextDetail = await ctx.service.paymentDetail.getDataByCondition({ tr_id: ctx.trInfo.id, order: ctx.detail.order + 1 });
@@ -503,10 +506,7 @@ module.exports = app => {
                 if ((ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.detail.uid) {
                     // data.accountGroup = accountGroup;
                     // 获取所有项目参与者
-                    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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                     renderData.accountList = accountList;
                     const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
                     const accountGroupList = unitList.map(item => {
@@ -521,7 +521,7 @@ module.exports = app => {
                 this.log(err);
                 ctx.session.postError = err.toString();
                 if (ctx.detail.tender_id && ctx.detail.tr_id) {
-                    ctx.redirect('/payment' + ctx.detail.tender_id + '/list/' + ctx.detail.tr_id);
+                    ctx.redirect('/sp/' + ctx.subProject.id + '/payment' + ctx.detail.tender_id + '/list/' + ctx.detail.tr_id);
                 }
                 ctx.redirect(this.menu.menu.dashboard.url);
             }
@@ -626,7 +626,7 @@ module.exports = app => {
                 if (!result) {
                     throw '删除报表表单详情失败,请重试';
                 }
-                ctx.redirect('/payment/' + ctx.paymentTender.id + '/list/' + detailInfo.tr_id);
+                ctx.redirect('/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/list/' + detailInfo.tr_id);
             } catch (err) {
                 this.log(err);
                 ctx.session.postError = err.toString();
@@ -714,10 +714,7 @@ module.exports = app => {
                 //     }
                 // }
                 // 获取所有项目参与者
-                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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                 const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
                 const accountGroupList = unitList.map(item => {
                     const groupList = accountList.filter(item1 => item1.company === item.name);
@@ -738,7 +735,7 @@ module.exports = app => {
                 console.log(err);
                 this.log(err);
                 ctx.session.postError = err.toString();
-                ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/payment');
+                ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/sp/' + ctx.subProject.id + '/payment');
             }
         }
 
@@ -803,10 +800,7 @@ module.exports = app => {
 
                 // 获取列表
                 const trDetailList = await ctx.service.paymentDetail.getValidDetails(trInfo.id);
-                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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                 if (trDetailList.length > 0) {
                     for (const s of trDetailList) {
                         // s.curAuditor = null;
@@ -831,7 +825,7 @@ module.exports = app => {
                     accountGroup: [],
                     accountList: [],
                     paymentConst,
-                    preUrl: '/payment/' + ctx.paymentTender.id + '/list/' + trInfo.id,
+                    preUrl: '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/list/' + trInfo.id,
                     categoryData,
                     tenderInfo,
                 };
@@ -905,10 +899,7 @@ module.exports = app => {
                     }
                     if (renderData.rptMsg) {
                         // 获取所有项目参与者
-                        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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                         const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
                         const accountGroupList = unitList.map(item => {
                             const groupList = accountList.filter(item1 => item1.company === item.name);
@@ -923,7 +914,7 @@ module.exports = app => {
                 console.log(err);
                 this.log(err);
                 ctx.session.postError = err.toString();
-                ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/payment');
+                ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/sp/' + ctx.subProject.id + '/payment');
             }
         }
 
@@ -1075,7 +1066,7 @@ module.exports = app => {
                     fileData.orginpath = ctx.app.config.fujianOssPath + filepath;
                     delete fileData.filepath;
                     if (!ctx.helper.canPreview(fileData.fileext)) {
-                        fileData.filepath = `/payment/${original_data.tender_id}/detail/${original_data.td_id}/file/${fileData.id}/download`;
+                        fileData.filepath = `/sp/${ctx.subProject.id}/payment/${original_data.tender_id}/detail/${original_data.td_id}/file/${fileData.id}/download`;
                     } else {
                         fileData.filepath = ctx.app.config.fujianOssPath + filepath;
                         fileData.viewpath = ctx.app.config.fujianOssPath + filepath;
@@ -1191,7 +1182,7 @@ module.exports = app => {
                     moment,
                     whiteList: ctx.app.config.multipart.whitelist,
                     uidList,
-                    preUrl: '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id,
+                    preUrl: '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id,
                     OSS_PATH: ctx.app.config.fujianOssPath,
                     stdBills,
                 };
@@ -1200,10 +1191,7 @@ module.exports = app => {
                 renderData.content = content;
                 if ((ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.detail.uid) {
                     // 获取所有项目参与者
-                    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 accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
                     renderData.accountList = accountList;
                     const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
                     const accountGroupList = unitList.map(item => {
@@ -1217,7 +1205,7 @@ module.exports = app => {
                 this.log(err);
                 this.ctx.postError(err, '读取安全生产费错误');
                 if (ctx.detail.tender_id && ctx.detail.tr_id) {
-                    ctx.redirect('/payment' + ctx.detail.tender_id + '/list');
+                    ctx.redirect('/sp/' + ctx.subProject.id + '/payment' + ctx.detail.tender_id + '/list');
                 } else {
                     ctx.redirect(this.menu.menu.dashboard.url);
                 }
@@ -1237,7 +1225,7 @@ module.exports = app => {
                 this.log(err);
                 this.ctx.postError(err, '读取安全生产费错误');
                 if (ctx.detail.tender_id && ctx.detail.tr_id) {
-                    ctx.redirect('/payment' + ctx.detail.tender_id + '/list');
+                    ctx.redirect('/sp/' + ctx.subProject.id + '/payment' + ctx.detail.tender_id + '/list');
                 } else {
                     ctx.redirect(this.menu.menu.dashboard.url);
                 }

+ 1 - 1
app/middleware/payment_detail_check.js

@@ -138,7 +138,7 @@ module.exports = options => {
                 if (this.helper.isWap(this.request)) {
                     this.redirect('/wap/list');
                 } else {
-                    err === '您无权查看该内容' ? this.redirect(this.request.headers.referer) : this.redirect('/payment');
+                    err === '您无权查看该内容' ? this.redirect(this.request.headers.referer) : this.redirect('/sp/' + this.subProject.id + '/payment');
                 }
             }
         }

+ 7 - 7
app/middleware/payment_tender_check.js

@@ -26,17 +26,17 @@ module.exports = options => {
             if (!this.session.sessionProject.showPayment) {
                 throw '该功能已关闭或无法查看';
             }
-            if (!this.params.id) {
+            if (!this.params.pid) {
                 throw '当前未打开标段';
             }
-            const tender = yield this.service.paymentTender.getDataById(this.params.id);
-            if (tender.pid !== this.session.sessionProject.id) throw '您无权查看该项目';
-            const projectInfo = yield this.service.project.getDataById(this.session.sessionProject.id);
-            const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : _.cloneDeep(paymentConst.setting_modes);
+            const tender = yield this.service.paymentTender.getDataById(this.params.pid);
+            if (tender.pid !== this.session.sessionProject.id || tender.spid !== this.subProject.id) throw '您无权查看该项目';
+            // const projectInfo = yield this.service.project.getDataById(this.subProject.id);
+            const modes = this.subProject.payment_setting ? JSON.parse(this.subProject.payment_setting) : _.cloneDeep(paymentConst.setting_modes);
             for (const m in paymentConst.setting_modes) {
                 if (!modes[m]) modes[m] = _.cloneDeep(paymentConst.setting_modes[m]);
             }
-            const auditPermission = yield this.service.paymentPermissionAudit.getOnePermission(this.session.sessionUser.is_admin, this.session.sessionUser.accountId);
+            const auditPermission = yield this.service.subProjPermission.getPaymentPermission(this.subProject.permission.payment_permission);
             if (!auditPermission) {
                 throw '权限不足';
             }
@@ -78,7 +78,7 @@ module.exports = options => {
                     this.redirect('/wap/list');
                 } else {
                     this.postError(err, '未知错误');
-                    err === '该功能已关闭或无法查看' ? this.redirect('/dashboard') : (err === '您无权查看该内容' ? this.redirect(this.request.headers.referer) : this.redirect('/payment'));
+                    err === '该功能已关闭或无法查看' ? this.redirect('/dashboard') : (err === '您无权查看该内容' ? this.redirect(this.request.headers.referer) : this.redirect('/sp/' + this.subProject.id + '/payment'));
                 }
             }
         }

+ 1 - 1
app/middleware/session_auth.js

@@ -87,7 +87,7 @@ module.exports = options => {
             } else {
                 this.session.sessionProject.showBudget = this.session.sessionProject.page_show.openBudget ? yield this.service.subProjPermission.showBudget(sessionUser.accountId) : false;
                 if (this.session.sessionProject.page_show.openPayment) {
-                    const auditInfo = yield this.service.paymentPermissionAudit.getDataByCondition({ pid: projectData.id, uid: accountInfo.id });
+                    const auditInfo = yield this.service.subProjPermission.showPayment(sessionUser.accountId);
                     if (auditInfo) {
                         showPayment = 1;
                     }

+ 5 - 5
app/public/js/payment_detail.js

@@ -82,7 +82,7 @@ $(function () {
             tesRpttData.items[0].interact_cells[index].link = link !== '' ? parseInt(link) : '';
             tesRpttData.items[0].interact_cells[index].Value = tesRpttData.items[0].interact_cells[index].Prefix ? tesRpttData.items[0].interact_cells[index].Prefix + chineseNum : chineseNum;
             const _self = $(this);
-            postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_rpt', report_json: tesRpttData }, function (result) {
+            postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_rpt', report_json: tesRpttData }, function (result) {
                 $('#rpt-form input[data-index="'+ index +'"]').val(chineseNum);
                 auditRptPrintHelper.showPage();
                 _self.parents('.show-link-dropdown').dropdown('toggle');
@@ -180,7 +180,7 @@ $(function () {
             if (content_index !== -1) {
                 tesRpttData.items[0].signature_audit_cells[content_index].Value = rptAudit.signature_msg.content ? rptAudit.signature_msg.content : '';
             }
-            postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_sign', signature_msg: rptAudit.signature_msg }, function (result) {
+            postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_sign', signature_msg: rptAudit.signature_msg }, function (result) {
                 auditRptPrintHelper.showPage();
                 // 更新签署进度图表展示
                 $('#rpt_audit_sign td').eq(3).html(rptAudit.signature_msg.sign_path !== null ? '<i class="fa fa-check text-success"></i>' : '');
@@ -201,7 +201,7 @@ $(function () {
         clearTimeout(timer);
         timer = setTimeout(() => {
             tesRpttData.items[0].interact_cells[index].Value = tesRpttData.items[0].interact_cells[index].Prefix ? tesRpttData.items[0].interact_cells[index].Prefix + newVal : newVal;
-            postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_rpt', report_json: tesRpttData }, function (result) {
+            postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'update_rpt', report_json: tesRpttData }, function (result) {
                 auditRptPrintHelper.showPage();
             });
             clearTimeout(timer);
@@ -290,7 +290,7 @@ $(function () {
 
     $('#attList').on('click', '.file-atn', function() {
         const id = $(this).attr('f-id');
-        postData(`/payment/${tenderId}/detail/${detailId}/file/${id}/download`, {}, (data) => {
+        postData(`'/sp/${spid}/payment/${tenderId}/detail/${detailId}/file/${id}/download`, {}, (data) => {
             const { filepath } = data;
             $('#file-upload').attr('href', filepath);
             $('#file-upload')[0].click();
@@ -372,7 +372,7 @@ function getAllList(currPageNum = 1) {
         <td><a href="${att.filepath}" target="_blank" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a></td>
         <td>${moment(att.upload_time).format("YYYY-MM-DD HH:mm:ss")}<br>${bytesToSize(att.filesize)}</td>
         <td>
-            <a href="/payment/${tenderId}/detail/${detailId}/file/${att.id}/download" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>`
+            <a href="'/sp/${spid}/payment/${tenderId}/detail/${detailId}/file/${att.id}/download" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>`
         html += (att.uid === accountId && (detailStatus === auditConst.status.checked ? Boolean(att.extra_upload) : true)) ?
             `<a href="javascript:void(0)" class="mr-2 delete-file" data-attid="${att.id}" title="删除附件"><span class="fa fa-trash text-danger"></span></a>` : '';
         html += `</td>`;

+ 3 - 3
app/public/js/payment_detail_audit.js

@@ -113,7 +113,7 @@ $(document).ready(function () {
     $('dl').on('click', 'dd', function () {
         const id = parseInt($(this).data('id'));
         if (id) {
-            postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'add_audit', auditorId: id }, (datas) => {
+            postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'add_audit', auditorId: id }, (datas) => {
                 remakeShenpiHtml(datas);
             });
         }
@@ -121,7 +121,7 @@ $(document).ready(function () {
     // 删除审批人
     $('body').on('click', '#auditors li>a', function () {
         const li = $(this).parent();
-        postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'del_audit', auditorId: parseInt(li.attr('auditorId')) }, (result) => {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'del_audit', auditorId: parseInt(li.attr('auditorId')) }, (result) => {
             li.remove();
             for (const rst of result) {
                 const aLi = $('li[auditorId=' + rst.aid + ']');
@@ -194,7 +194,7 @@ $(document).ready(function () {
 
     // 同步报表角色
     $('#follow_rpt_audit_btn').click(function () {
-        postData('/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'follow_rpt_audit' }, (datas) => {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/detail/' + detailId + '/save', { type: 'follow_rpt_audit' }, (datas) => {
             toastr.success('同步成功');
             remakeShenpiHtml(datas);
         });

+ 10 - 10
app/public/js/payment_index.js

@@ -12,7 +12,7 @@ $(function () {
         const tenders = tenderList;
         function makeTenderTree(parent) {
             if (parent.is_leaf) {
-                parent.children = _.filter(tenders, { folder_id: parent.id });
+                parent.children = _.filter(tenders, { folder_id: parent.folder_id });
                 if (parent.children.length > 0) {
                     parent.is_tender = true;
                     parent.children.forEach((value, index) => {
@@ -20,7 +20,7 @@ $(function () {
                     });
                 }
             } else {
-                const children = _.filter(folders, { parent_id: parent.id });
+                const children = _.filter(folders, { parent_id: parent.folder_id });
                 parent.children = children;
                 if (children.length > 0) {
                     for (const c of children) {
@@ -50,7 +50,7 @@ $(function () {
             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="/payment/'+ node.id +'/list" target="_blank" id="' + node.id + '">', node.name, '</a>');
+            html.push('<a href="/sp/'+ spid +'/payment/'+ node.id +'/list" target="_blank" id="' + node.id + '">', node.name, '</a>');
             if (node.have_notice){
                 html.push('<i class="fa fa-bell text-warning float-right mt-1" data-toggle="tooltip" data-placement="bottom" title="待处理提醒"></i>');
             }
@@ -63,7 +63,7 @@ $(function () {
         // 审批流程
         html.push('<td style="width: 15%" class="text-center">');
         if (node.parent_id === undefined && auditPermission.admin && (node.uid === uid || is_admin)) {
-            html.push('<a href="/payment/'+ node.id +'/process" target="_blank">设置</a>');
+            html.push('<a href="/sp/'+ spid +'/payment/'+ node.id +'/process" target="_blank">设置</a>');
         }
         html.push('</td>');
         // 操作
@@ -88,7 +88,7 @@ $(function () {
                 html.push('<div class="dropdown-divider"></div>\n');
             }
             if (auditPermission.admin && 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');
+                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.folder_id +'"><i class="fa fa-folder-o mr-2"></i>新建子文件夹</a>\n');
             }
             if (auditPermission.admin && 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');
@@ -137,7 +137,7 @@ $(function () {
     }
 
     // 首次加载展示目录
-    postData('/payment/list/load', {}, function (result) {
+    postData('/sp/'+ spid +'/payment/list/load', {}, function (result) {
         allFolders = result.folderList;
         allTenders = result.tenderList;
         makeList(result.folderList, result.tenderList);
@@ -181,7 +181,7 @@ $(function () {
         if (name === false) {
             return;
         }
-        postData('/payment/save', { type: 'add-folder', parentId: parseInt($('#parent_id').val()), name }, function (result) {
+        postData('/sp/'+ spid +'/payment/save', { type: 'add-folder', parentId: parseInt($('#parent_id').val()), name }, function (result) {
             allFolders = result.folderList;
             allTenders = result.tenderList;
             makeList(result.folderList, result.tenderList);
@@ -214,7 +214,7 @@ $(function () {
             id: $('#edit_name_id').val(),
             name,
         };
-        postData('/payment/save', { type: 'edit-name', postData: data }, function (result) {
+        postData('/sp/'+ spid +'/payment/save', { type: 'edit-name', postData: data }, function (result) {
             allFolders = result.folderList;
             allTenders = result.tenderList;
             makeList(result.folderList, result.tenderList);
@@ -258,7 +258,7 @@ $(function () {
         if (name === false) {
             return;
         }
-        postData('/payment/save', { type: 'add-tender', folderId: parseInt($('#add_tender_folder_id').val()), name }, function (result) {
+        postData('/sp/'+ spid +'/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);
@@ -287,7 +287,7 @@ $(function () {
             type: $('#del_type').val(),
             id: $('#del_id').val(),
         };
-        postData('/payment/save', { type: 'del', postData: data }, function (result) {
+        postData('/sp/'+ spid +'/payment/save', { type: 'del', postData: data }, function (result) {
             allFolders = result.folderList;
             allTenders = result.tenderList;
             makeList(result.folderList, result.tenderList);

+ 7 - 7
app/public/js/payment_list.js

@@ -119,7 +119,7 @@ $(function () {
                 return;
             }
         }
-        postData('/payment/' + tenderId + '/list/' + trId + '/save', { type: 'rpt_audit', rpt_audit }, function (result) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/list/' + trId + '/save', { type: 'rpt_audit', rpt_audit }, function (result) {
             toastr.success('设置成功');
             old_rpt_audit = _.cloneDeep(rpt_audit);
             if (result.is_first) {
@@ -154,11 +154,11 @@ $(function () {
             return false;
         }
         console.log($('#add-detail-time').val());
-        postData('/payment/' + tenderId + '/list/' + trId + '/save', { type: 'add-detail', code: _.trim($('#add-detail-code').val()), s_time: $('#add-detail-time').val() }, function (result) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/list/' + trId + '/save', { type: 'add-detail', code: _.trim($('#add-detail-code').val()), s_time: $('#add-detail-time').val() }, function (result) {
             if (result.type) {
-                window.location.href = '/payment/' + tenderId + '/safe/' + result.id + '/bills';
+                window.location.href = '/sp/' + spid + '/payment/' + tenderId + '/safe/' + result.id + '/bills';
             } else {
-                window.location.href = '/payment/' + tenderId + '/detail/' + result.id;
+                window.location.href = '/sp/' + spid + '/payment/' + tenderId + '/detail/' + result.id;
             }
         });
     });
@@ -168,7 +168,7 @@ $(function () {
         const data = {
             order: $(this).attr('m-order'),
         };
-        postData('/payment/' + tenderId + '/list/'+ trId + '/auditors', data, function (result) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/list/'+ trId + '/auditors', data, function (result) {
             const { auditHistory, auditors, user } = result
             let auditorsHTML = ''
             let historyHTML = ''
@@ -440,7 +440,7 @@ $(function () {
         }
         init() {
             const self = this;
-            postData(`/list/load2`, { type: 'all'}, result => {
+            postData(`/sp/${spid}/list/load2`, { type: 'all'}, result => {
                 self.selectTree = Tender2Tree.convert(category, result.tenders);
                 SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.selectTree);
             });
@@ -634,7 +634,7 @@ function postAttr () {
         },
     };
     const tenderId = window.location.pathname.split('/')[2];
-    postData('/payment/info/save', { type: 'info', postData: { id: tenderId, info} }, function (data) {
+    postData('/sp/' + spid + '/payment/info/save', { type: 'info', postData: { id: tenderId, info} }, function (data) {
         property.deal_info = info.deal_info;
         property.construction_unit = info.construction_unit;
         property.tech_param = info.tech_param;

+ 9 - 9
app/public/js/payment_process.js

@@ -19,7 +19,7 @@ $(function () {
                 name: $(this).attr('data-name'),
             }); //向数组中添加元素
         });
-        postData('/payment/' + tenderId + '/process/save', { type: 'add-rpt', rpt_list: checkArray }, function (result) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', { type: 'add-rpt', rpt_list: checkArray }, function (result) {
             const html = [];
             for (const data of result) {
                 html.push(`<tr data-id="${data.id}">\n`);
@@ -204,7 +204,7 @@ $(function () {
             tr_id: trInfo.id,
             status: trInfo.sp_status,
         };
-        postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
             setLcShowHtml(trInfo.sp_status, trInfo.id, data);
         });
     }
@@ -241,7 +241,7 @@ $(function () {
             tr_id: this_tr_id,
             status: this_status
         };
-        postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
             const trInfo = _.find(tenderRptList, { id: this_tr_id });
             trInfo.sp_status = this_status;
             setLcShowHtml(this_status, this_tr_id, data);
@@ -279,7 +279,7 @@ $(function () {
             type: 'add-audit',
         };
         const _self = $(this);
-        postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
             if (this_status === sp_status.gdspl) {
                 _self.parents('ul').append('<li class="pl-3"><a href="javascript:void(0);" class="add-audit"><i class="fa fa-plus"></i> 添加流程</a></li>');
             }
@@ -317,7 +317,7 @@ $(function () {
             uid: id,
             type: 'update-report',
         };
-        postData('/payment/' + tenderId + '/process/save', prop, function (result) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (result) {
             tenderRptList = result.list;
             if (result.updateRows) {
                 toastr.warning('上报人不能同时作为审批人,审批流已移除 ' + user.name);
@@ -347,7 +347,7 @@ $(function () {
         //     type: 'add-audit',
         // };
         // const _self = $(this);
-        // postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+        // postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
         //     if (this_status === sp_status.gdspl) {
         //         _self.parents('ul').append('<li class="pl-3"><a href="javascript:void(0);" class="add-audit"><i class="fa fa-plus"></i> 添加流程</a></li>');
         //     }
@@ -380,7 +380,7 @@ $(function () {
             type: 'del-audit',
         };
         const _self = $(this);
-        postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+        postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
             if (this_status === sp_status.gdspl) {
                 const _selflc = _self.parents('.lc-show');
                 _self.parents('li').remove();
@@ -553,7 +553,7 @@ $(function () {
                 $(this).parents('.form-group').siblings('.alert-warning').text(spt.name + ':' + spt.msg);
                 // 拼接post json
                 const prop = { type: 'change-status', tr_id, status };
-                postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+                postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
                     self.rptInfo.sp_status = status;
                     self.rptInfo.auditData = data;
                     self.setLcShowHtml();
@@ -584,7 +584,7 @@ $(function () {
 
                 const prop = { status, tr_id, audit_id: id, type: 'add-audit' };
                 const _self = $(this);
-                postData('/payment/' + tenderId + '/process/save', prop, function (data) {
+                postData('/sp/' + spid + '/payment/' + tenderId + '/process/save', prop, function (data) {
                     if (status === sp_status.gdspl) {
                         _self.parents('ul').append('<li class="pl-3"><a href="javascript:void(0);" class="add-audit"><i class="fa fa-plus"></i> 添加流程</a></li>');
                     }

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

@@ -2,7 +2,7 @@ $(function () {
     autoFlashHeight();
 
     $('#mode-form input').on('click', function () {
-        postData('/payment/save', { type: 'mode-setting', mode_type: $(this).attr('mode-type'), checked: $(this).is(':checked') }, function (result) {
+        postData('/sp/' + spid + '/payment/save', { type: 'mode-setting', mode_type: $(this).attr('mode-type'), checked: $(this).is(':checked') }, function (result) {
             toastr.success('已配置');
         })
     });

+ 31 - 32
app/router.js

@@ -369,6 +369,37 @@ module.exports = app => {
     app.post('/sp/:id/budget/:btype/upload-excel/:ueType', sessionAuth, subProjectCheck, budgetCheck, 'budgetController.detailUploadExcel');
     app.post('/sp/:id/budget/decimal', sessionAuth, subProjectCheck, budgetCheck, 'budgetController.decimal');
 
+    // 支付审批
+    app.get('/sp/:id/payment', sessionAuth, subProjectCheck, 'paymentController.index');
+    app.get('/sp/:id/payment/setting', sessionAuth, subProjectCheck, 'paymentController.setting');
+    app.post('/sp/:id/payment/permission/save', sessionAuth, subProjectCheck, 'paymentController.permissionSave');
+    app.post('/sp/:id/payment/info/save', sessionAuth, subProjectCheck, 'paymentController.paymentInfoSave');
+    app.get('/sp/:id/payment/:pid/detail/:did', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.detail');
+    app.post('/sp/:id/payment/:pid/detail/:did/save', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.detailSave');
+    app.post('/sp/:id/payment/save', sessionAuth, subProjectCheck, 'paymentController.save');
+    app.post('/sp/:id/payment/list/load', sessionAuth, subProjectCheck, 'paymentController.listLoad');
+    app.get('/sp/:id/payment/:pid/process', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.process');
+    app.post('/sp/:id/payment/:pid/process/save', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.processSave');
+    app.get('/sp/:id/payment/:pid/list', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.rptList');
+    app.get('/sp/:id/payment/:pid/list/:trid', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.rptList');
+    app.post('/sp/:id/payment/:pid/list/:trid/save', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.rptSave');
+    app.post('/sp/:id/payment/:pid/list/:trid/delete', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.deleteDetail');
+    app.post('/sp/:id/payment/:pid/list/:trid/auditors', sessionAuth, subProjectCheck, paymentTenderCheck, 'paymentController.detailAuditors');
+    app.post('/sp/:id/payment/:pid/detail/:did/audit/start', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.startAudit');
+    app.post('/sp/:id/payment/:pid/detail/:did/audit/check', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.checkAudit');
+    // 附件
+    app.post('/sp/:id/payment/:pid/detail/:did/file/upload', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.uploadDetailFile');
+    app.post('/sp/:id/payment/:pid/detail/:did/file/delete', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.deleteDetailFile');
+    app.get('/sp/:id/payment/:pid/detail/:did/file/:fid/download', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.downloadDetailFile');
+    // 安全生产费
+    app.get('/sp/:id/payment/:pid/safe/:did/bills', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeBills');
+    app.get('/sp/:id/payment/:pid/safe/:did/compare', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeCompare');
+    app.post('/sp/:id/payment/:pid/safe/:did/load', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeLoad');
+    app.post('/sp/:id/payment/:pid/safe/:did/update', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeUpdate');
+    app.post('/sp/:id/payment/:pid/safe/:did/decimal', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeDecimal');
+    app.post('/sp/:id/payment/:pid/safe/:did/file/upload', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.uploadDetailFile');
+    app.post('/sp/:id/payment/:pid/safe/:did/file/delete', sessionAuth, subProjectCheck, paymentTenderCheck, paymentDetailCheck, 'paymentController.deleteDetailFile');
+
     // **资金监管 todo 接入项目内部
     // app.get('/financial', sessionAuth, 'financialController.index');
     // app.post('/financial/audit/save', sessionAuth, financialCheck, 'financialController.auditSave');
@@ -1027,38 +1058,6 @@ module.exports = app => {
     app.post('/wap/shoufang/editfile', 'wapController.shoufangEditFile');
     app.get('/wap/shoufang/download/file/:fid', 'wapController.shoufangDownloadFile');
 
-    // 支付审批
-    app.get('/payment', sessionAuth, 'paymentController.index');
-    app.get('/payment/setting', sessionAuth, 'paymentController.setting');
-    app.post('/payment/permission/save', sessionAuth, 'paymentController.permissionSave');
-    app.post('/payment/info/save', sessionAuth, 'paymentController.paymentInfoSave');
-    app.get('/payment/:id/detail/:did', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.detail');
-    app.post('/payment/:id/detail/:did/save', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.detailSave');
-    app.post('/payment/save', sessionAuth, 'paymentController.save');
-    app.post('/payment/list/load', sessionAuth, 'paymentController.listLoad');
-    app.get('/payment/:id/process', sessionAuth, paymentTenderCheck, 'paymentController.process');
-    app.post('/payment/:id/process/save', sessionAuth, paymentTenderCheck, 'paymentController.processSave');
-    app.get('/payment/:id/list', sessionAuth, paymentTenderCheck, 'paymentController.rptList');
-    app.get('/payment/:id/list/:trid', sessionAuth, paymentTenderCheck, 'paymentController.rptList');
-    app.post('/payment/:id/list/:trid/save', sessionAuth, paymentTenderCheck, 'paymentController.rptSave');
-    app.post('/payment/:id/list/:trid/delete', sessionAuth, paymentTenderCheck, 'paymentController.deleteDetail');
-    app.post('/payment/:id/list/:trid/auditors', sessionAuth, paymentTenderCheck, 'paymentController.detailAuditors');
-    app.post('/payment/:id/detail/:did/audit/start', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.startAudit');
-    app.post('/payment/:id/detail/:did/audit/check', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.checkAudit');
-    // 附件
-    app.post('/payment/:id/detail/:did/file/upload', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.uploadDetailFile');
-    app.post('/payment/:id/detail/:did/file/delete', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.deleteDetailFile');
-    app.get('/payment/:id/detail/:did/file/:fid/download', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.downloadDetailFile');
-    // 安全生产费
-    app.get('/payment/:id/safe/:did/bills', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeBills');
-    app.get('/payment/:id/safe/:did/compare', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeCompare');
-    app.post('/payment/:id/safe/:did/load', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeLoad');
-    app.post('/payment/:id/safe/:did/update', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeUpdate');
-    app.post('/payment/:id/safe/:did/decimal', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.safeDecimal');
-    app.post('/payment/:id/safe/:did/file/upload', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.uploadDetailFile');
-    app.post('/payment/:id/safe/:did/file/delete', sessionAuth, paymentTenderCheck, paymentDetailCheck, 'paymentController.deleteDetailFile');
-
-
     // 企业微信回调
     app.get('/wx/work/callback/command', 'wechatController.command');
     app.post('/wx/work/callback/command', 'wechatController.postCommand');

+ 1 - 1
app/service/payment_detail.js

@@ -352,7 +352,7 @@ module.exports = app => {
         async doCheckDetail(id) {
             const status = auditConst.status;
             const accountId = this.ctx.session.sessionUser.accountId;
-            const auditPermission = await this.service.paymentPermissionAudit.getOnePermission(this.ctx.session.sessionUser.is_admin, accountId);
+            const auditPermission = await this.ctx.service.subProjPermission.getPaymentPermission(this.ctx.subProject.permission.payment_permission);
             if (!auditPermission) throw '权限不足';
 
             const detail = await this.getDataById(id);

+ 1 - 1
app/service/payment_detail_att.js

@@ -56,7 +56,7 @@ module.exports = app => {
             return result.map(item => {
                 item.orginpath = this.ctx.app.config.fujianOssPath + item.filepath;
                 if (!this.ctx.helper.canPreview(item.fileext)) {
-                    item.filepath = `/payment/${item.tender_id}/detail/${item.td_id}/file/${item.id}/download`;
+                    item.filepath = `'/sp/${this.ctx.subProject.id}/payment/${item.tender_id}/detail/${item.td_id}/file/${item.id}/download`;
                 } else {
                     item.filepath = this.ctx.app.config.fujianOssPath + item.filepath;
                     item.viewpath = item.filepath;

+ 2 - 6
app/service/payment_detail_audit.js

@@ -400,16 +400,12 @@ module.exports = app => {
                 const rptAuditList = await this.ctx.service.paymentRptAudit.getAllDataByCondition({ where: { td_id: detailId } });
                 const auditIdList = this._.map(auditList, 'aid');
                 const rptAuditIdList = this._.map(rptAuditList, 'uid');
-                const permissionAuditList = await this.ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { pid: this.ctx.session.sessionProject.id } });
+                const permissionAuditList = await this.ctx.service.subProjPermission.getPaymentAuditList(this.ctx.subProject.id);
                 const paIdList = this._.map(permissionAuditList, 'uid');
                 const detailIdList = this._.union(auditIdList, rptAuditIdList);
                 const newAudits = this._.difference(detailIdList, paIdList);
                 if (newAudits.length > 0) {
-                    const accountList = await this.ctx.service.projectAccount.getAllDataByCondition({
-                        where: { project_id: this.ctx.session.sessionProject.id, id: newAudits },
-                        columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
-                    });
-                    await this.ctx.service.paymentPermissionAudit.saveAudits(this.ctx.session.sessionProject.id, accountList, transaction);
+                    await this.ctx.service.subProjPermission.savePaymentPermissionAudits(this.ctx.subProject.id, newAudits, 'add', transaction);
                 }
                 // todo 更新标段tender状态 ?
                 await transaction.commit();

+ 47 - 11
app/service/payment_folder.js

@@ -19,14 +19,14 @@ module.exports = app => {
         async addFolder(projectId, uid, parentId = 0, name) {
             const transaction = await this.db.beginTransaction();
             try {
-                const tenderCount = await this.ctx.service.paymentTender.count({ folder_id: parentId });
+                const tenderCount = await this.ctx.service.paymentTender.count({ spid: this.ctx.subProject.id, folder_id: parentId });
                 if (tenderCount > 0) {
                     throw '文件夹下存在标段无法创建子文件夹';
                 }
                 let level = 1;
                 let parent_path = '';
                 if (parentId !== 0) {
-                    const parentFolderInfo = await this.getDataById(parentId);
+                    const parentFolderInfo = await this.getDataByCondition({ spid: this.ctx.subProject.id, folder_id: parentId });
                     if (!parentFolderInfo) throw '父文件夹不存在';
                     level = parentFolderInfo.level + level;
                     if (parentFolderInfo.is_leaf) {
@@ -34,12 +34,16 @@ module.exports = app => {
                     }
                     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 childrenCount = await transaction.select(this.tableName, { where: { spid: this.ctx.subProject.id, parent_id: parentId }, orders: [['order', 'desc']] });
+                const order = childrenCount && childrenCount.length > 0 ? childrenCount[0].order + 1 : 1;
+                const maxFolderId = await this.getMaxId(this.ctx.subProject.id);
                 const insertData = {
+                    id: this.uuid.v4(),
                     pid: projectId,
+                    spid: this.ctx.subProject.id,
                     uid,
                     name,
+                    folder_id: maxFolderId + 1,
                     parent_id: parentId,
                     parent_path,
                     level,
@@ -65,7 +69,7 @@ module.exports = app => {
                 }
                 let ids = [info.id];
                 if (info.parent_id === 0) {
-                    const childList = await this.getAllDataByCondition({ where: { parent_id: info.id } });
+                    const childList = await this.getAllDataByCondition({ where: { spid: this.ctx.subProject.id, parent_id: info.id } });
                     if (childList.length > 0) {
                         ids = [...ids, ...this._.map(childList, 'id')];
                         for (const c of childList) {
@@ -84,7 +88,7 @@ module.exports = app => {
                     }
                 }
                 // 判断是否存在标段,有则无法删除目录
-                const tenderCount = await this.ctx.service.paymentTender.count({ folder_id: ids });
+                const tenderCount = await this.ctx.service.paymentTender.count({ spid: this.ctx.subProject.id, folder_id: ids });
                 if (tenderCount > 0) {
                     throw '文件夹下存在标段,无法删除';
                 }
@@ -98,6 +102,10 @@ module.exports = app => {
 
         async getDataByParentPath(tableName, parent_path, transaction = null) {
             this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('spid', {
+                value: this.ctx.subProject.id,
+                operate: '=',
+            });
             this.sqlBuilder.setAndWhere('parent_path', {
                 value: this.db.escape(parent_path),
                 operate: 'Like',
@@ -115,14 +123,14 @@ module.exports = app => {
             });
             let folderList = [];
             if (auditPermission.view_all) {
-                folderList = await this.getAllDataByCondition({ where: { pid: this.ctx.session.sessionProject.id } });
+                folderList = await this.getAllDataByCondition({ where: { spid: this.ctx.subProject.id } });
             } else {
-                folderList = await this.getAllDataByCondition({ where: { uid } });
+                folderList = await this.getAllDataByCondition({ where: { spid: this.ctx.subProject.id, 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);
+                        if (this._.findIndex(folderList, { folder_id: t.folder_id }) === -1) {
+                            const folderInfo = await this.getDataByCondition({ spid: this.ctx.subProject.id, folder_id: t.folder_id });
                             folderList.push(folderInfo);
                         }
                     }
@@ -148,7 +156,7 @@ module.exports = app => {
                         }
                     }
                     if (allNotExistFolderIds.length > 0) {
-                        const newFolderList = await this.getAllDataByCondition({ where: { id: allNotExistFolderIds } });
+                        const newFolderList = await this.getAllDataByCondition({ where: { spid: this.ctx.subProject.id, folder_id: allNotExistFolderIds } });
                         folderList = [...folderList, ...newFolderList];
                     }
                 }
@@ -163,6 +171,34 @@ module.exports = app => {
             return folderList;
         }
 
+        async getNoSpList(pid) {
+            // 获取所有项目参与者
+            const accountList = await this.ctx.service.projectAccount.getAllDataByCondition({
+                where: { project_id: this.ctx.session.sessionProject.id, enable: 1 },
+                columns: ['id', 'name'],
+            });
+            const folderList = await this.getAllDataByCondition({ where: { pid, spid: '' } });
+            if (folderList.length > 0) {
+                // folderList = this._.uniqBy(folderList, 'id');
+                for (const f of folderList) {
+                    const userInfo = this._.find(accountList, { id: f.uid });
+                    f.user_name = userInfo ? userInfo.name : '';
+                }
+            }
+            return folderList;
+        }
+
+        async getMaxId(spid, needFlag = false) {
+            const result = await this.db.queryOne(`select max(folder_id) as max_id from ${this.tableName} where spid = ?`, [spid]);
+            const maxId = result ? result.max_id : 0;
+            if (needFlag) {
+                const oldResult = await this.db.queryOne(`select max(folder_id) as max_id from ${this.tableName} where pid = ? AND spid = ?`, [this.ctx.session.sessionProject.id, '']);
+                const oldMaxId = oldResult ? oldResult.max_id : 0;
+                return maxId > oldMaxId ? maxId : oldMaxId;
+            }
+            return maxId;
+        }
+
         // async getChildrenByParentId(parentId, transaction = null) {
         //     const list = await this.getAllDataByCondition({ where: { parent_id: parentId } });
         // }

+ 1 - 1
app/service/payment_permission_audit.js

@@ -66,7 +66,7 @@ module.exports = app => {
             return await this.db.delete(this.tableName, { id });
         }
 
-        async getOnePermission(is_admin, uid) {
+        async getOnePermission(is_admin, spid, uid) {
             if (is_admin) {
                 return paymentConst.audit_admin_permission;
             }

+ 107 - 6
app/service/payment_tender.js

@@ -19,13 +19,12 @@ module.exports = app => {
 
         async getList(uid, auditPermission) {
             if (auditPermission.view_all) {
-                const sql1 = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pid = ?';
-                const params1 = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.session.sessionProject.id];
+                const sql1 = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pt.`pid` = ? AND pt.`spid` = ?';
+                const params1 = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.session.sessionProject.id, this.ctx.subProject.id];
                 return await this.db.query(sql1, params1);
             }
             const typeValues = [];
-            const projectInfo = await this.ctx.service.project.getDataById(this.ctx.session.sessionProject.id);
-            const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : this._.cloneDeep(paymentConst.setting_modes);
+            const modes = this.ctx.subProject.payment_setting ? JSON.parse(this.ctx.subProject.payment_setting) : this._.cloneDeep(paymentConst.setting_modes);
             for (const m in paymentConst.setting_modes) {
                 if (!modes[m]) modes[m] = this._.cloneDeep(paymentConst.setting_modes[m]);
                 if (modes[m].checked) {
@@ -35,14 +34,14 @@ module.exports = app => {
             if (typeValues.length === 0) {
                 return -1;
             }
-            const sql = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pid = ? AND (pt.`uid` = ? ' +
+            const sql = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pid = ? AND spid = ? AND (pt.`uid` = ? ' +
                 'OR pt.`id` in (SELECT pr.`tender_id` FROM ?? as pr WHERE pr.`uid` = ? AND pr.`type` IN (' + this.ctx.helper.getInArrStrSqlFilter(typeValues) + '))' +
                 'OR pt.`id` in (SELECT pd.`tender_id` FROM ?? as pd WHERE pd.`uid` = ?)' +
                 'OR pt.`id` in (SELECT pda.`tender_id` FROM ?? as pda LEFT JOIN ?? as pd ON pda.`tender_id` = pd.`tender_id` ' +
                 'WHERE pd.`status` != ' + auditConst.status.uncheck + ' AND pda.`aid` = ?)' +
                 'OR pt.`id` in (SELECT pra.`tender_id` FROM ?? as pra LEFT JOIN ?? as pd ON pra.`tender_id` = pd.`tender_id` ' +
                 'WHERE pd.`status` != ' + auditConst.status.uncheck + ' AND pd.`status` !=' + auditConst.status.checkNo + ' AND pra.`uid` = ?))';
-            const params = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.session.sessionProject.id, uid,
+            const params = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.session.sessionProject.id, this.ctx.subProject.id, uid,
                 this.ctx.service.paymentTenderRpt.tableName, uid,
                 this.ctx.service.paymentDetail.tableName, uid,
                 this.ctx.service.paymentDetailAudit.tableName, this.ctx.service.paymentDetail.tableName, uid,
@@ -50,6 +49,13 @@ module.exports = app => {
             return await this.db.query(sql, params);
         }
 
+        async getNoSpList(pid, spIsNull = true) {
+            const spSql = spIsNull ? ' AND pt.`spid` = ?' : ' AND pt.`spid` != ?';
+            const sql1 = 'SELECT pt.*, pa.name as user_name FROM ?? as pt LEFT JOIN ?? as pa ON pt.`uid` = pa.`id` WHERE pt.`pid` = ?' + spSql;
+            const params1 = [this.tableName, this.ctx.service.projectAccount.tableName, pid, ''];
+            return await this.db.query(sql1, params1);
+        }
+
         async addTender(projectId, uid, folderId, name) {
             const transaction = await this.db.beginTransaction();
             try {
@@ -59,6 +65,7 @@ module.exports = app => {
                 }
                 const insertData = {
                     pid: projectId,
+                    spid: this.ctx.subProject.id,
                     uid,
                     name,
                     folder_id: folderId,
@@ -147,6 +154,100 @@ module.exports = app => {
         async doCheckTender(id) {
             return await this.service.paymentTender.getDataById(id);
         }
+
+        async bindSp(tids) {
+            const noSpTenderList = await this.getNoSpList(this.ctx.session.sessionProject.id);
+            const noSpFolderList = await this.ctx.service.paymentFolder.getNoSpList(this.ctx.session.sessionProject.id);
+            const transaction = await this.db.beginTransaction();
+            try {
+                const hadSpTenderList = await this.getNoSpList(this.ctx.session.sessionProject.id, false);
+                if (tids.length === noSpTenderList.length && hadSpTenderList.length === 0) {
+                    // 一次性迁移所有可以不用复制folder数据,也不用调整tender数据,直接更新spid
+                    await transaction.update(this.tableName, { spid: this.ctx.subProject.id }, { where: { pid: this.ctx.session.sessionProject.id } });
+                    await transaction.update(this.ctx.service.paymentFolder.tableName, { spid: this.ctx.subProject.id }, { where: { pid: this.ctx.session.sessionProject.id } });
+                } else {
+                    const hadSpTenderIds = hadSpTenderList.map(item => item.id);
+                    // tids里过滤掉hadSpTenderIds存在的值
+                    const filterTids = tids.filter(item => !hadSpTenderIds.includes(item));
+                    if (filterTids.length > 0) {
+                        const folderList = await this.ctx.service.paymentFolder.getAllDataByCondition({ where: { spid: this.ctx.subProject.id } });
+                        // 需要复制一份folder数据,且比对folderList,如果存在则不复制,且可能需要调整id,parent_id,parent_path, order值
+                        const allNotExistFolderIds = [];
+                        for (const tid of filterTids) {
+                            const tender = this._.find(noSpTenderList, { id: tid });
+                            if (tender) {
+                                const parentFolder = this._.find(noSpFolderList, { folder_id: tender.folder_id });
+                                if (parentFolder) {
+                                    const spParentFolder = this._.find(folderList, { folder_id: tender.folder_id });
+                                    if (!spParentFolder) allNotExistFolderIds.push(tender.folder_id);
+                                    const parentPathArray = parentFolder.parent_path ? this._.map(parentFolder.parent_path.split('-'), this._.toInteger) : [];
+                                    if (parentPathArray.length > 0) {
+                                        for (const id of parentPathArray) {
+                                            const spFolder = this._.find(folderList, { folder_id: id });
+                                            if (!spFolder && !this._.includes(allNotExistFolderIds, id)) {
+                                                allNotExistFolderIds.push(id);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        const newFolderList = [];
+                        if (allNotExistFolderIds.length > 0) {
+                            const allNotExistFolderList = this._.orderBy(this._.filter(noSpFolderList, item => this._.includes(allNotExistFolderIds, item.folder_id)), ['in_time'], ['asc']);
+                            for (const f of allNotExistFolderList) {
+                                newFolderList.push({
+                                    id: this.uuid.v4(),
+                                    pid: this.ctx.session.sessionProject.id,
+                                    spid: this.ctx.subProject.id,
+                                    uid: f.uid,
+                                    name: f.name,
+                                    folder_id: f.folder_id,
+                                    parent_id: f.parent_id,
+                                    parent_path: f.parent_path,
+                                    level: f.level,
+                                    order: f.order,
+                                    is_leaf: f.is_leaf,
+                                    had_tender: f.had_tender,
+                                    in_time: f.in_time,
+                                });
+                            }
+                        }
+                        await transaction.update(this.tableName, { spid: this.ctx.subProject.id }, { where: { id: filterTids } });
+                        if (newFolderList.length > 0) await transaction.insert(this.ctx.service.paymentFolder.tableName, newFolderList);
+                    }
+                }
+                // 权限也要迁移至本子项目
+                const ppAudits = await this.ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { pid: this.ctx.session.sessionProject.id } });
+                for (const audit of ppAudits) {
+                    if (audit.uid) {
+                        const spAudit = await this.ctx.service.subProjPermission.getDataByCondition({ spid: this.ctx.subProject.id, uid: audit.uid });
+                        const payment_permission = [1];
+                        const one_pp = audit.permission_json ? JSON.parse(audit.permission_json) : null;
+                        if (one_pp) {
+                            if (one_pp.admin) payment_permission.push(2);
+                            if (one_pp.view_all) payment_permission.push(3);
+                        }
+                        const new_payment_permission = payment_permission.join(',');
+                        console.log(spAudit, new_payment_permission);
+                        if (spAudit && spAudit.payment_permission !== new_payment_permission) {
+                            await transaction.update(this.ctx.service.subProjPermission.tableName, { id: spAudit.id, payment_permission: new_payment_permission });
+                        } else if (!spAudit) {
+                            const a = await this.ctx.service.projectAccount.getDataById(audit.uid);
+                            if (a) {
+                                const sp_permission = { id: this.uuid.v4(), spid: this.ctx.subProject.id, pid: this.ctx.session.sessionProject.id, uid: audit.uid, self_category_level: a.self_category_level, payment_permission: new_payment_permission };
+                                await transaction.insert(this.ctx.service.subProjPermission.tableName, sp_permission);
+                            }
+                        }
+                    }
+                }
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+            return true;
+        }
     }
     return paymentTender;
 };

+ 1 - 1
app/service/payment_tender_rpt.js

@@ -237,7 +237,7 @@ module.exports = app => {
                 const result1 = await this.ctx.service.paymentDetail.updateReport(transaction, tr_id, data.uid);
                 // 判断固定审批流或固定终审是否存在上报人,有则移除
                 const result2 = await this.ctx.service.paymentShenpiAudit.removeAuditByReport(transaction, tr_id, data.uid);
-                await this.ctx.service.paymentPermissionAudit.saveAudits(this.ctx.session.sessionProject.id, [userInfo], transaction);
+                await this.ctx.service.subProjPermission.savePaymentPermissionAudits(this.ctx.subProject.id, [data.uid], 'add', transaction);
                 await transaction.commit();
                 let tenderRptList = await this.getProcessList(this.ctx.paymentTender.id);
                 tenderRptList = this._.filter(tenderRptList, { type: 0, is_del: 0 });

+ 2 - 2
app/service/project_account.js

@@ -1080,7 +1080,7 @@ module.exports = app => {
             if (filter) filterInfo.push({ filter, tableName: 'pa' });
             const filterSql = this._getFilterSql(filterInfo);
             const sql = `SELECT pa.*, spp.id AS permission_id, 
-                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission 
+                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission, spp.payment_permission
                 FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY spp.create_time DESC';
             const result = await this.db.query(sql);
             return result;
@@ -1093,7 +1093,7 @@ module.exports = app => {
             const limit = this.ctx.pageSize ? this.ctx.pageSize : this.app.config.pageSize;
             const offset = limit * (this.ctx.page - 1);
             const sql = `SELECT pa.*, spp.id AS permission_id, 
-                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission 
+                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission, spp.payment_permission 
                 FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY spp.create_time DESC LIMIT ?, ?';
             const result = await this.db.query(sql, [offset, limit]);
             return result;

+ 79 - 0
app/service/sub_proj_permission.js

@@ -62,6 +62,11 @@ module.exports = app => {
                     view: { title: '查看', value: 1 },
                     att: { title: '上传附件', value: 3 },
                 },
+                payment: {
+                    view: { title: '查看', value: 1 },
+                    admin: { title: '模块管理员', value: 2 },
+                    view_all: { title: '查看所有标段', value: 3 },
+                }
             };
             this.PermissionBlock = [
                 { key: 'datacollect', name: '决策大屏', field: 'datacollect_permission' },
@@ -81,6 +86,7 @@ module.exports = app => {
                         { key: 'fund_pay', name: '资金支付', field: 'fund_pay_permission' },
                     ]
                 },
+                { key: 'payment', name: '支付审批', field: 'payment_permission' },
             ];
             for (const p of this.PermissionBlock) {
                 if (p.children) {
@@ -125,6 +131,7 @@ module.exports = app => {
                 contract_permission: this.ctx.helper.mapAllSubField(this.PermissionConst.contract, 'value'),
                 fund_pay_permission: this.ctx.helper.mapAllSubField(this.PermissionConst.fund_pay, 'value'),
                 fund_trans_permission: this.ctx.helper.mapAllSubField(this.PermissionConst.fund_trans, 'value'),
+                payment_permission: this.ctx.helper.mapAllSubField(this.PermissionConst.payment, 'value'),
             }
         }
 
@@ -139,6 +146,9 @@ module.exports = app => {
         async showFile(uid) {
             return await this.showSubTab(uid, 'file');
         }
+        async showPayment(uid) {
+            return await this.showSubTab(uid, 'payment');
+        }
 
         parsePermission(data) {
             const _ = this.ctx.helper._;
@@ -153,6 +163,7 @@ module.exports = app => {
                 x.fund_pay_permission = x.fund_pay_permission ? _.map(x.fund_pay_permission.split(','), _.toInteger) : [];
                 x.fund_trans_permission = x.fund_trans_permission ? _.map(x.fund_trans_permission.split(','), _.toInteger) : [];
                 x.filing_type = x.filing_type ? _.map(x.filing_type.split(','), _.toInteger): [];
+                x.payment_permission = x.payment_permission ? _.map(x.payment_permission.split(','), _.toInteger) : [];
             });
         }
 
@@ -446,6 +457,74 @@ module.exports = app => {
             };
             return permission;
         }
+
+        async getPaymentAuditList(spid, uid = null) {
+            const uidSql = uid ? 'AND uid in (' + uid.join(',') + ')' : '';
+            const sql = `SELECT * FROM ?? WHERE spid = ? AND payment_permission <> ''` + uidSql;
+            const sqlParams = [this.tableName, spid];
+            const result = await this.db.query(sql, sqlParams);
+            const list = [];
+            for (const r of result) {
+                const permission = await this.getPaymentPermission(this._.map(r.payment_permission.split(','), this._.toInteger));
+                const accountInfo = await this.ctx.service.projectAccount.getDataById(r.uid);
+                list.push({
+                    id: r.id,
+                    name: accountInfo.name,
+                    company: accountInfo.company,
+                    uid: r.uid,
+                    permission_json: permission,
+                });
+            }
+            return list;
+        }
+
+        async getPaymentPermission(pp) {
+            if (!pp || pp.length === 0) return false;
+            const permission = {
+                admin: pp.indexOf(2) !== -1,
+                view_all: pp.indexOf(3) !== -1,
+            };
+            return permission;
+        }
+
+        async savePaymentPermissionAudits(spid, uids, operation = 'add', transaction= null) {
+            const updateArr = [];
+            const spAudits = await this.getAllDataByCondition({ where: { spid: spid, uid: uids } });
+            for (const a of spAudits) {
+                if (operation === 'add' && a.payment_permission !== '') continue;
+                updateArr.push({
+                    id: a.id,
+                    payment_permission: operation === 'add' ? '1' : (operation === 'del' ? '' : a.payment_permission),
+                });
+            }
+            if (updateArr.length > 0) transaction ? await transaction.updateRows(this.tableName, updateArr) : await this.db.updateRows(this.tableName, updateArr);
+        }
+
+        async updateOnePaymentPermission(spid, updateData) {
+            if (!updateData.uid || !updateData.permission_json) {
+                return false;
+            }
+            const spAudit = await this.getDataByCondition({ spid: spid, uid: updateData.uid });
+            if (spAudit) {
+                const newPermission = await this.getNewPaymentPermission(spAudit.payment_permission, updateData.permission_json);
+                return await this.db.update(this.tableName, { id: spAudit.id, payment_permission: newPermission });
+            }
+            return false;
+        }
+
+        async getNewPaymentPermission(permission, newPermission) {
+            const oldPermission = await this.getPaymentPermission(this._.map(permission.split(','), this._.toInteger));
+            if (newPermission.admin !== undefined) {
+                oldPermission.admin = newPermission.admin;
+            }
+            if (newPermission.view_all !== undefined) {
+                oldPermission.view_all = newPermission.view_all;
+            }
+            const permissionArr = [1];
+            if (oldPermission.admin) permissionArr.push(2);
+            if (oldPermission.view_all) permissionArr.push(3);
+            return permissionArr.join(',');
+        }
     }
 
     return subProjPermission;

+ 2 - 2
app/view/payment/detail.ejs

@@ -11,7 +11,7 @@
 <div class="panel-content">
     <div class="panel-title fluid">
         <div class="title-main  d-flex justify-content-between">
-            <div><a class="mr-2" href="/payment/<%- ctx.paymentTender.id %>/list/<%- trInfo.id %>"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %> / <%- trInfo.rpt_name %> / <%- ctx.detail.code %></div>
+            <div><a class="mr-2" href="/sp/<%- ctx.subProject.id %>/payment/<%- ctx.paymentTender.id %>/list/<%- trInfo.id %>"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %> / <%- trInfo.rpt_name %> / <%- ctx.detail.code %></div>
             <div>
                 <% if ((ctx.detail.status == auditConst.status.uncheck || ctx.detail.status == auditConst.status.checkNo) && trInfo.is_change) { %>
                 <span class="text-danger pull-right">报表内容已发生变化,请删除并重新生成详情</span>
@@ -131,7 +131,7 @@
                                                         <td><a href="javascript: void(0);" class="file-atn" f-id="<%- att.id %>"><%- att.filename %><%- att.fileext %></a></td>
                                                         <td><%- moment(att.upload_time).format("YYYY-MM-DD HH:mm:ss") %><br><%- ctx.helper.bytesToSize(att.filesize) %></td>
                                                         <td>
-                                                            <a href="/payment/<%- ctx.paymentTender.id %>/detail/<%- ctx.detail.id %>/file/<%- att.id %>/download" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>
+                                                            <a href="/sp/<%- ctx.subProject.id %>/payment/<%- ctx.paymentTender.id %>/detail/<%- ctx.detail.id %>/file/<%- att.id %>/download" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>
                                                             <% if (att.uid === ctx.session.sessionUser.accountId && (ctx.detail.status === auditConst.status.checked ? Boolean(att.extra_upload) : true )) { %>
                                                                 <a href="javascript:void(0)" class="mr-2 delete-file" data-attid="<%- att.id %>" title="删除附件"><span class="fa fa-trash text-danger"></span></a>
                                                             <% } %>

+ 8 - 3
app/view/payment/index.ejs

@@ -1,13 +1,18 @@
 <div class="panel-content">
     <div class="panel-title fluid">
         <div class="title-main  d-flex justify-content-between">
-            <div>支付审批 <% if (ctx.session.sessionUser.is_admin) { %><a href="/payment/setting" class="ml-1" data-toggle="tooltip" data-placement="top" title="模块配置"><i class="fa fa-cog"></i></a><% } %></div>
+            <div>支付审批 <% if (ctx.session.sessionUser.is_admin) { %><a href="/sp/<%- ctx.subProject.id %>/payment/setting" class="ml-1" data-toggle="tooltip" data-placement="top" title="模块配置"><i class="fa fa-cog"></i></a><% } %></div>
             <div>
-                <% if (auditPermission.admin) { %>
+                <% if (ctx.session.sessionUser.is_admin && noSpTenderList.length > 0) { %>
+                    <a href="#nosp-list" data-toggle="modal" data-target="#nosp-list" class="btn btn-sm btn-primary pull-right mr-2">关联标段</a>
+                <% } %>
+            </div>
+            <div>
+                <% if (auditPermission.admin && noSpTenderList.length === 0) { %>
                 <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>
                 <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) { %>
+                <% if (ctx.session.sessionUser.is_admin && noSpTenderList.length === 0) { %>
                 <a href="#authority-list" data-toggle="modal" data-target="#authority-list" class="btn btn-sm btn-outline-secondary pull-right mr-2">权限管理</a>
                 <% } %>
             </div>

+ 10 - 10
app/view/payment/list.ejs

@@ -2,7 +2,7 @@
     <div class="panel-title fluid">
         <div class="title-main  d-flex justify-content-between">
             <div>
-                <a class="mr-2" href="/payment"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %>
+                <a class="mr-2" href="/sp/<%- ctx.subProject.id %>/payment"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %>
             </div>
             <div>
                 <a href="#bd-attr" data-toggle="modal" data-target="#bd-attr" class="btn btn-sm btn-outline-primary pull-right ml-2">标段属性</a>
@@ -27,7 +27,7 @@
                     <div class="col-3">
                         <div class="list-group">
                             <% for (const tr of tenderRptList) { %>
-                            <a href="/payment/<%- ctx.paymentTender.id %>/list/<%- tr.id %>"
+                            <a href="/sp/<%- ctx.subProject.id %>/payment/<%- ctx.paymentTender.id %>/list/<%- tr.id %>"
                                class="list-group-item list-group-item-action <% if (trInfo.id === tr.id) { %>active<% } %>">
                                 <%- tr.rpt_name %><% if (tr.have_notice) { %><i class="fa fa-bell text-warning float-right mt-1" data-toggle="tooltip" data-placement="bottom" title="待处理提醒"></i><% } %>
                             </a>
@@ -53,9 +53,9 @@
                                     <tr>
                                         <td class="text-center">第<%- info.order %>期</td>
                                         <% if (info.type) { %>
-                                        <td class="text-center"><a href="/payment/<%- info.tender_id %>/safe/<%- info.id %>/bills"><%- info.code %></a></td>
+                                        <td class="text-center"><a href="/sp/<%- ctx.subProject.id %>/payment/<%- info.tender_id %>/safe/<%- info.id %>/bills"><%- info.code %></a></td>
                                         <% } else { %>
-                                        <td class="text-center"><a href="/payment/<%- info.tender_id %>/detail/<%- info.id %>"><%- info.code %></a></td>
+                                        <td class="text-center"><a href="/sp/<%- ctx.subProject.id %>/payment/<%- info.tender_id %>/detail/<%- info.id %>"><%- info.code %></a></td>
                                         <% } %>
                                         <td class="text-center"><%- info.user_name %></td>
                                         <td class="text-center"><%- info.s_time %></td>
@@ -68,21 +68,21 @@
                                         <td class="text-center">
                                             <% if (info.status === auditConst.status.uncheck && info.uid === ctx.session.sessionUser.accountId) { %>
                                                 <% if (info.type) { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } else { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } %>
                                             <% } else if (info.status === auditConst.status.checkNo && info.curAuditor && info.uid === ctx.session.sessionUser.accountId) { %>
                                                 <% if (info.type) { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } else { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } %>
                                             <% } else if (info.status === auditConst.status.checking && info.curAuditor && info.curAuditor.aid === ctx.session.sessionUser.accountId) { %>
                                                 <% if (info.type) { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/safe/' + info.id + '/bills' %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } else { %>
-                                                <a href="<%- '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
+                                                <a href="<%- '/sp/' + ctx.subProject.id + '/payment/' + ctx.paymentTender.id + '/detail/' + info.id %>" class="btn <%- auditConst.statusButtonClass[info.status] %> btn-sm"><%- auditConst.statusButton[info.status] %></a>
                                                 <% } %>
                                             <% } else { %>
                                                 <span class="<%- auditConst.auditProgressClass[info.status] %>"><%- auditConst.auditProgress[info.status] %></span>

+ 167 - 15
app/view/payment/modal.ejs

@@ -167,13 +167,13 @@
                     <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-center"><input type="checkbox" name="uid[]" value="<%- pa.uid %>"></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="admin" value="<%- pa.id %>" <% if (pa.permission_json.admin) { %>checked<% } %>></td>
-                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="view_all" value="<%- pa.id %>" <% if (pa.permission_json.view_all) { %>checked<% } %>></td>
-                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="<%- pa.id %>">移除</a></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="admin" value="<%- pa.uid %>" <% if (pa.permission_json.admin) { %>checked<% } %>></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="view_all" value="<%- pa.uid %>" <% if (pa.permission_json.view_all) { %>checked<% } %>></td>
+                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="<%- pa.uid %>">移除</a></td>
                     </tr>
                     <% } %>
                     </tbody>
@@ -205,12 +205,43 @@
         </div>
     </div>
 </div>
+<% if (noSpTenderList.length > 0) { %>
+<div class="modal fade" id="nosp-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" style="position: relative;overflow: auto;max-height: 800px;padding-top: 0;margin-top: 1rem;">
+                <style>
+                    .c-NoSpBody .table thead th {
+                        border: none;
+                        outline-width: 1px;
+                        outline-style: solid;
+                        outline-color: #dee2e6;
+                    }
+                </style>
+                <div class="c-NoSpBody">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-primary" id="bind-spBtn">确定</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>
+    <% if (noSpTenderList.length > 0) { %>
+    const noSpTenderList = JSON.parse(unescape('<%- escape(JSON.stringify(noSpTenderList)) %>'));
+    const noSpFolderList = JSON.parse(unescape('<%- escape(JSON.stringify(noSpFolderList)) %>'));
+    <% } %>
     $(function () {
         // $("#permission-audit-table").bootstrapTable('destroy').bootstrapTable({
         //     fixedColumns: true,
@@ -285,7 +316,7 @@
             const groupName = $(this).data('groupname');
             console.log(groupName);
             if (!isNaN(id) && id !== 0) {
-                postData('/payment/permission/save', { type: 'add-audit', id: id }, function (result) {
+                postData('/sp/' + spid + '/payment/permission/save', { type: 'add-audit', id: id }, function (result) {
                     permissionAudits = result;
                     setList(permissionAudits);
                 })
@@ -296,7 +327,7 @@
                 const addAidList = _.difference(groupAidList, groupPAList);
                 console.log(groupAidList, groupPAList, addAidList);
                 if (addAidList.length > 0) {
-                    postData('/payment/permission/save', { type: 'add-audit', id: addAidList }, function (result) {
+                    postData('/sp/' + spid + '/payment/permission/save', { type: 'add-audit', id: addAidList }, function (result) {
                         // toastr.success(`成功添加 位用户`);
                         permissionAudits = result;
                         setList(permissionAudits);
@@ -311,13 +342,13 @@
             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-center"><input type="checkbox" name="uid[]" value="${pa.uid}"></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="admin" value="${pa.id}" ${pa.permission_json.admin ? 'checked' : ''}></td>
-                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="view_all" value="${pa.id}" ${pa.permission_json.view_all ? 'checked' : ''}></td>
-                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="${pa.id}">移除</a></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="admin" value="${pa.uid}" ${pa.permission_json.admin ? 'checked' : ''}></td>
+                        <td class="text-center"><input type="checkbox" class="permission-checkbox" data-type="view_all" value="${pa.uid}" ${pa.permission_json.view_all ? 'checked' : ''}></td>
+                        <td class="text-center"><a href="javascript:void(0);" class="text-danger del-permission-audit-a" data-id="${pa.uid}">移除</a></td>
                     </tr>`;
             }
             $('#permission-audit-list').html(list);
@@ -363,7 +394,7 @@
 
         $('#del-audit-btn').click(function () {
             let uids = $('#del-audit-ids').val();
-            postData('/payment/permission/save', { type: 'del-audit', id: uids.split(',') }, function (result) {
+            postData('/sp/' + spid + '/payment/permission/save', { type: 'del-audit', id: uids.split(',') }, function (result) {
                 // toastr.success(`成功添加 位用户`);
                 $('#del-permission-audit').modal('hide');
                 permissionAudits = result;
@@ -376,7 +407,7 @@
         $('body').on('click', '.permission-checkbox', function () {
             const type = $(this).attr('data-type');
             const value = $(this).is(':checked') ? 1 : 0;
-            const userInfo = _.find(permissionAudits, { id: parseInt($(this).val()) });
+            const userInfo = _.find(permissionAudits, { uid: parseInt($(this).val()) });
             if (!userInfo) {
                 toastr.error('用户不存在');
             }
@@ -386,10 +417,10 @@
                 $(this).parents('tr').find('input[data-type="view_all"]').prop('checked', value);
             }
             const updateInfo = {
-                id: userInfo.id,
+                uid: userInfo.uid,
                 permission_json: userInfo.permission_json,
             }
-            postData('/payment/permission/save', { type: 'save-permission-one', updateData: updateInfo }, function (result) {
+            postData('/sp/' + spid + '/payment/permission/save', { type: 'save-permission-one', updateData: updateInfo }, function (result) {
                 // toastr.success(`成功添加 位用户`);
             })
         });
@@ -398,12 +429,133 @@
         //     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) {
+        //     postData('/sp/' + spid + '/payment/permission/save', { type: 'save-permission-all', permission_type: type, value }, function (result) {
         //         // toastr.success(`成功添加 位用户`);
         //         permissionAudits = result;
         //         setList(permissionAudits);
         //     })
         // })
+
+        <% if (noSpTenderList.length > 0) { %>
+        let noSpTenderTree = [];
+        let noSpParentId = 0;
+        function initNoSpTenderTree(folderList, tenderList) {
+            noSpTenderTree = [];
+            const folders = folderList;
+            const tenders = tenderList;
+            function makeNoSpTenderTree(parent) {
+                if (parent.is_leaf) {
+                    parent.children = _.filter(tenders, { folder_id: parent.folder_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.folder_id });
+                    parent.children = children;
+                    if (children.length > 0) {
+                        for (const c of children) {
+                            makeNoSpTenderTree(c);
+                        }
+                    }
+                }
+            }
+            const level0Folders = _.filter(folders, { level: 1 });
+            for (const l of level0Folders) {
+                makeNoSpTenderTree(l);
+                noSpTenderTree.push(l);
+            }
+            console.log(noSpTenderTree);
+        }
+
+        function recursiveGetNoSpTenderNodeHtml (node, arr, pid) {
+            const html = [];
+            html.push('<tr fid="' + (node.parent_id !== undefined ? node.id: 0) + '" pid="' + pid + '">');
+            // 选择框
+            html.push('<td style="width: 5%;text-align: center;">');
+            if (node.parent_id === undefined) {
+                html.push('<input type="checkbox" name="tender[]" value="' + node.id + '">');
+            }
+            html.push('</td>');
+            // 名称
+            html.push('<td 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(node.name);
+            }
+            html.push('</td>');
+            // 创建人
+            html.push('<td style="width: 15%" class="text-center">', node.user_name ? node.user_name : '', '</td>');
+            // 创建时间
+            html.push('<td style="width: 20%" class="text-center">', node.in_time && node.parent_id === undefined ? moment(node.in_time).format('YYYY-MM-DD HH:mm:ss') : '', '</td>');
+            html.push('</tr>');
+            if (node.children) {
+                for (const c of node.children) {
+                    html.push(recursiveGetNoSpTenderNodeHtml(c, node.children, node.sort_id));
+                }
+            }
+            return html.join('');
+        }
+
+        // 根据TenderTree数据获取Html代码
+        function getNoSpTenderTreeHtml () {
+            if (noSpTenderTree.length > 0) {
+                const html = [];
+                html.push('<table class="table table-hover table-bordered">');
+                html.push('<thead style="position: sticky;left:56px;top: 0;">', '<tr>');
+                html.push('<th class="text-center" style="width: 5%;">', '<input type="checkbox" id="select-all-tender" />', '</th>');
+                html.push('<th class="text-center">', '名称', '</th>');
+                html.push('<th class="text-center" style="width: 15%">', '创建人', '</th>');
+                html.push('<th class="text-center" style="width: 20%">', '创建时间', '</th>');
+                html.push('</tr>', '</thead>');
+                noSpParentId = 0;
+                for (const t of noSpTenderTree) {
+                    html.push(recursiveGetNoSpTenderNodeHtml(t, noSpTenderTree, ''));
+                }
+                html.push('</table>');
+                return html.join('');
+            } else {
+                return '';
+            }
+        }
+
+        function makeNoSpList(folderList, tenderList) {
+            initNoSpTenderTree(folderList, tenderList);
+            $('.c-NoSpBody').html(getNoSpTenderTreeHtml());
+            $('[data-toggle="tooltip"]').tooltip()
+        }
+
+        makeNoSpList(noSpFolderList, noSpTenderList);
+
+        $('body').on('click', '#select-all-tender', function () {
+            const checked = $(this).is(':checked');
+            $('.c-NoSpBody table').find('input[type="checkbox"]').prop('checked', checked);
+        });
+
+        $("#bind-spBtn").click(function () {
+            const checkedTender = $('.c-NoSpBody table tbody').find('input[type="checkbox"]:checked');
+            const tenderIds = [];
+            checkedTender.each(function () {
+                tenderIds.push(parseInt($(this).val()));
+            });
+            if (tenderIds.length === 0) {
+                toastr.error('请选择需要关联的标段');
+                return;
+            }
+            console.log(tenderIds);
+            postData('/sp/' + spid + '/payment/permission/save', { type: 'bind-sp', tids: tenderIds }, function (result) {
+                window.location.reload();
+            })
+        })
+        <% } %>
     })
 </script>
 <% } %>

+ 1 - 1
app/view/payment/process.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
     <div class="panel-title fluid">
         <div class="title-main  d-flex justify-content-between">
-            <div><a class="mr-2" href="/payment"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %> / 标段设置</div>
+            <div><a class="mr-2" href="/sp/<%- ctx.subProject.id %>/payment"><i class="fa fa-chevron-left"></i> 返回</a><%- ctx.paymentTender.name %> / 标段设置</div>
         </div>
     </div>
     <div class="content-wrap">

+ 9 - 18
config/menu.js

@@ -46,15 +46,6 @@ const projectMenu = {
         caption: '项目汇总',
         controller: 'spgather',
     },
-    payment: {
-        name: '支付审批',
-        icon: 'fa-handshake-o',
-        display: true,
-        url: '/payment',
-        caption: '支付审批',
-        children: null,
-        controller: 'payment',
-    },
     management: {
         name: '项目管理系统',
         icon: 'fa-cubes',
@@ -135,15 +126,15 @@ const menu = {
         caption: '动态投资',
         controller: 'budget',
     },
-    // construction: {
-    //     name: '施工日志',
-    //     icon: 'fa-pencil-square-o',
-    //     display: true,
-    //     // url: '/construction',
-    //     caption: '施工日志',
-    //     children: null,
-    //     controller: 'construction',
-    // },
+    payment: {
+        name: '支付审批',
+        icon: 'fa-handshake-o',
+        display: true,
+        // url: '/payment',
+        caption: '支付审批',
+        children: null,
+        controller: 'payment',
+    },
     financial: {
         name: '资金监管',
         icon: 'fa-money',

+ 19 - 2
db_script/sub_project.js

@@ -30,11 +30,28 @@ const createDefaultSubProject = async function (project) {
     await querySql(sql, sqlParam);
     // 所有标段归属到改项目下
     await querySql('UPDATE zh_tender SET spid = ? WHERE project_id = ?', [subProject.id, project.id]);
+    // 所有支付审批标段归属到该项目下
+    await querySql('UPDATE zh_payment_tender SET spid = ? WHERE pid = ?', [subProject.id, project.id]);
+    await querySql('UPDATE zh_payment_folder SET spid = ? WHERE pid = ?', [subProject.id, project.id]);
+    const ppAudits = await querySql('SELECT * FROM zh_payment_permission_audit where pid = ?', [project.id]);
+    // 添加用户payment_setting权限
     // 项目下所有用户都在子项目下新增用户权限
     console.log('Insert default sub_project user permission');
     for (const u of users) {
         if (manager && u.id === manager.id) continue;
         const sp_permission = { id: uuid.v4(), spid: subProject.id, pid: project.id, uid: u.id, self_category_level: u.self_category_level};
+        if (ppAudits.length > 0) {
+            const ppAudit = ppAudits.find(x => { return x.uid === u.id; });
+            if (ppAudit) {
+                const payment_permission = [1];
+                const one_pp = ppAudit.permission_json ? JSON.parse(ppAudit.permission_json) : null;
+                if (one_pp) {
+                    if (one_pp.admin) payment_permission.push(2);
+                    if (one_pp.view_all) payment_permission.push(3);
+                }
+                sp_permission.payment_permission = payment_permission.join(',');
+            }
+        }
         const [spSql, spSqlParam] = getInsertSql('zh_sub_project_permission', sp_permission);
         await querySql(spSql, spSqlParam);
     }
@@ -75,8 +92,8 @@ const doComplete = async function(code) {
             // page_show可以后台设置,如果迁移至子项目下,后台已有的功能设置将作废,需要做针对子项目的项目设置
             // todo rpt_authority rpt_items rpt_level rpt_nature 是否拷贝?
             // 拷贝sql必须放在这里,不能放在update.sql,必须先执行上一步创建默认子项目
-            console.log('Copy sub_project properties: page_show, fun_rela, data_collect, data_collect_pages, fun_set');
-            await querySql('Update zh_sub_project sp LEFT JOIN zh_project p ON sp.project_id = p.id SET sp.page_show = p.page_show, sp.fun_rela = p.fun_rela, sp.data_collect = p.data_collect, sp.data_collect_pages = p.data_collect_pages, sp.fun_set = p.fun_set WHERE sp.is_folder = 0 and is_delete = 0; ');
+            console.log('Copy sub_project properties: page_show, fun_rela, data_collect, data_collect_pages, fun_set, payment_setting');
+            await querySql('Update zh_sub_project sp LEFT JOIN zh_project p ON sp.project_id = p.id SET sp.page_show = p.page_show, sp.fun_rela = p.fun_rela, sp.data_collect = p.data_collect, sp.data_collect_pages = p.data_collect_pages, sp.fun_set = p.fun_set, sp.payment_setting = p.payment_setting WHERE sp.is_folder = 0 and is_delete = 0; ');
             // 拷贝标段自定义类别设置
             const subProj = await querySql('SELECT * FROM zh_sub_project where project_id = ? and is_folder = 0 and is_delete = 0;', [p.id]);
             // 不使用Insert Into SELECT, 避免死锁

+ 2 - 2
db_script/sub_project_permission.js

@@ -74,10 +74,10 @@ const doComplete = async function(spid) {
                 if (a.permission_edit) {
                     contract_permission.push(1);
                 }
-                if (a.permission_show_unit) {
+                if (a.permission_show_node) {
                     contract_permission.push(3);
                 }
-                if (a.permission_show_node) {
+                if (a.permission_show_unit) {
                     contract_permission.push(4);
                 }
                 if (!a.permission_show_node && !a.permission_show_unit) {

+ 14 - 2
sql/update.sql

@@ -12,7 +12,8 @@ ADD COLUMN `page_show` varchar(5000) CHARACTER SET utf8 COLLATE utf8_unicode_ci
 ADD COLUMN `fun_rela` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '功能设置(json.stringify)' AFTER `page_show`,
 ADD COLUMN `data_collect` tinyint(1) NOT NULL DEFAULT 0 COMMENT '决策大屏是否显示及对应大屏编号' AFTER `fun_rela`,
 ADD COLUMN `data_collect_pages` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '需要展示的大屏字符串,以,分隔' AFTER `data_collect`,
-ADD COLUMN `fun_set` varchar(5000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '项目设置页内容json' AFTER `data_collect_pages`;
+ADD COLUMN `fun_set` varchar(5000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '项目设置页内容json' AFTER `data_collect_pages`,
+ADD COLUMN `payment_setting` JSON NULL DEFAULT NULL COMMENT '支付审批模块设置' AFTER `fun_set`;
 
 ALTER TABLE `zh_category`
 ADD COLUMN `spid` varchar(36) NOT NULL DEFAULT '' COMMENT '子项目id(uuid)' AFTER `pid`;
@@ -37,7 +38,8 @@ ADD COLUMN `info_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '项目概
 ADD COLUMN `fund_trans_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '资金划拨,权限id列表(\',\'分隔)' AFTER `info_permission`,
 ADD COLUMN `fund_pay_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '资金支付,权限id列表(\',\'分隔)' AFTER `fund_trans_permission`,
 ADD COLUMN `contract_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '合同管理,权限id列表(\',\'分隔)' AFTER `fund_pay_permission`,
-ADD COLUMN `datacollect_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '决策大屏,权限id列表(\',\'分隔)' AFTER `contract_permission`;
+ADD COLUMN `datacollect_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '决策大屏,权限id列表(\',\'分隔)' AFTER `contract_permission`,
+ADD COLUMN `payment_permission` varchar(255) NOT NULL DEFAULT '' COMMENT '支付审批,权限id列表(\',\'分隔)' AFTER `datacollect_permission`;
 
 ALTER TABLE `zh_file_reference_list`
 ADD COLUMN `file_type` tinyint(4) UNSIGNED NOT NULL DEFAULT 1 COMMENT '文件类型' AFTER `remark`,
@@ -57,6 +59,14 @@ ADD COLUMN `spid` varchar(36) NOT NULL DEFAULT '' COMMENT 'zh_sub_project.id' AF
 ADD COLUMN `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' AFTER `info`,
 ADD COLUMN `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间' AFTER `create_time`;
 
+ALTER TABLE `zh_payment_tender`
+ADD COLUMN `spid` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '子项目id' AFTER `pid`;
+
+ALTER TABLE `zh_payment_folder`
+MODIFY COLUMN `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL FIRST,
+ADD COLUMN `spid` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '子项目id' AFTER `pid`,
+ADD COLUMN `folder_id` int(11) NOT NULL DEFAULT 0 COMMENT '节点id' AFTER `name`;
+
 ------------------------------------
 -- 表数据
 ------------------------------------
@@ -64,3 +74,5 @@ ADD COLUMN `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
 UPDATE zh_project_log pl LEFT JOIN zh_tender t ON pl.tid = t.id SET pl.spid = IF(ISNULL(t.spid),'',t.spid);
 
 Update zh_project_col_set SET pid = id;
+
+Update zh_payment_folder SET folder_id = id;