瀏覽代碼

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

Tony Kang 3 月之前
父節點
當前提交
2feddf4666
共有 97 個文件被更改,包括 1503 次插入281 次删除
  1. 1 0
      app/base/base_controller.js
  2. 2 0
      app/const/sp_page_show.js
  3. 4 2
      app/const/spread.js
  4. 1 1
      app/const/tender_info.js
  5. 2 2
      app/controller/advance_controller.js
  6. 1 1
      app/controller/dashboard_controller.js
  7. 1 1
      app/controller/datacollect_controller.js
  8. 3 0
      app/controller/material_controller.js
  9. 67 12
      app/controller/spss_controller.js
  10. 32 0
      app/controller/sub_proj_controller.js
  11. 3 1
      app/controller/sub_proj_setting_controller.js
  12. 4 4
      app/controller/tender_controller.js
  13. 2 2
      app/public/js/advance_audit.js
  14. 2 2
      app/public/js/change_apply_information.js
  15. 1 1
      app/public/js/change_detail.js
  16. 1 1
      app/public/js/change_information.js
  17. 2 2
      app/public/js/change_plan_information.js
  18. 2 2
      app/public/js/change_project_information.js
  19. 10 3
      app/public/js/change_revise.js
  20. 1 1
      app/public/js/construction_info.js
  21. 2 2
      app/public/js/financial_pay_detail.js
  22. 2 2
      app/public/js/financial_transfer.js
  23. 2 2
      app/public/js/financial_transfer_tender.js
  24. 1 0
      app/public/js/gcl_gather.js
  25. 14 7
      app/public/js/ledger.js
  26. 2 2
      app/public/js/material_file.js
  27. 200 3
      app/public/js/measure_compare.js
  28. 5 0
      app/public/js/measure_material.js
  29. 1 1
      app/public/js/payment_detail.js
  30. 2 2
      app/public/js/payment_safe.js
  31. 4 4
      app/public/js/profile_cert.js
  32. 10 3
      app/public/js/revise.js
  33. 11 4
      app/public/js/revise_compare.js
  34. 11 3
      app/public/js/revise_history.js
  35. 2 2
      app/public/js/se_bonus.js
  36. 10 3
      app/public/js/settle_gather.js
  37. 10 3
      app/public/js/settle_ledger.js
  38. 10 3
      app/public/js/settle_select.js
  39. 248 0
      app/public/js/shares/cs_tools.js
  40. 4 0
      app/public/js/shares/export_excel.js
  41. 18 2
      app/public/js/shares/tender_select_multi.js
  42. 13 3
      app/public/js/shares/tenders2tree.js
  43. 40 2
      app/public/js/shares/tools_att.js
  44. 3 2
      app/public/js/shenpi.js
  45. 2 0
      app/public/js/sp_progress.js
  46. 21 1
      app/public/js/sp_setting_permission.js
  47. 3 3
      app/public/js/spss_gather_stage.js
  48. 43 33
      app/public/js/spss_gather_stage_extra.js
  49. 311 0
      app/public/js/spss_gather_stage_info.js
  50. 14 4
      app/public/js/sr_detail.js
  51. 41 23
      app/public/js/stage.js
  52. 11 2
      app/public/js/stage_compare.js
  53. 1 1
      app/public/js/stage_pay.js
  54. 2 2
      app/public/js/sub_project.js
  55. 1 0
      app/router.js
  56. 11 8
      app/service/advance_audit.js
  57. 4 1
      app/service/change_apply_audit.js
  58. 2 1
      app/service/change_audit.js
  59. 4 1
      app/service/change_plan_audit.js
  60. 4 1
      app/service/change_project_audit.js
  61. 2 1
      app/service/message.js
  62. 2 2
      app/service/project_account.js
  63. 2 1
      app/service/stage_audit.js
  64. 1 1
      app/view/advance/modal_audit.ejs
  65. 1 1
      app/view/change/apply_information_modal.ejs
  66. 1 1
      app/view/change/info_modal.ejs
  67. 7 7
      app/view/change/information_modal.ejs
  68. 1 1
      app/view/change/plan_information_modal.ejs
  69. 1 1
      app/view/change/project_information_modal.ejs
  70. 1 1
      app/view/construction/info_modal.ejs
  71. 1 1
      app/view/contract/detail_modal.ejs
  72. 3 3
      app/view/dashboard/msg_add.ejs
  73. 20 2
      app/view/dashboard/workspace.ejs
  74. 2 2
      app/view/financial/pay_detail_modal.ejs
  75. 1 1
      app/view/financial/transfer_modal.ejs
  76. 1 1
      app/view/financial/transfer_tender_modal.ejs
  77. 1 1
      app/view/ledger/explode_modal.ejs
  78. 1 1
      app/view/material/file_modal.ejs
  79. 68 26
      app/view/measure/compare.ejs
  80. 1 1
      app/view/payment/detail_modal.ejs
  81. 1 1
      app/view/payment_safe/modal.ejs
  82. 1 1
      app/view/shares/upload_att.ejs
  83. 32 0
      app/view/sp_setting/manage_modal.ejs
  84. 2 0
      app/view/sp_setting/permission.ejs
  85. 2 0
      app/view/sp_setting/user.ejs
  86. 21 9
      app/view/sp_setting/user_modal.ejs
  87. 13 8
      app/view/spss/info.ejs
  88. 20 0
      app/view/spss/gather_info_modal.ejs
  89. 1 4
      app/view/spss/spss_select_modal.ejs
  90. 6 6
      app/view/stage/audit_modal.ejs
  91. 2 2
      app/view/stage/modal.ejs
  92. 1 1
      app/view/stage/pay_modal.ejs
  93. 1 1
      app/view/stage_extra/bonus_modal.ejs
  94. 1 1
      app/view/stage_rela/detail_modal.ejs
  95. 1 1
      app/view/sub_proj/index.ejs
  96. 27 1
      app/view/sub_proj/progress_modal.ejs
  97. 11 15
      config/web.js

+ 1 - 0
app/base/base_controller.js

@@ -33,6 +33,7 @@ class BaseController extends Controller {
                     ctx.menu = menuList.budget;
                 }
             }
+            menuList.info.display = ctx.subProject.page_show.openInfo || false;
             menuList.datacollect.display = ctx.subProject.showDataCollect || false;
             menuList.file.display = ctx.subProject.page_show.openFile || false;
             menuList.contract.display = ctx.subProject.page_show.openContract || false;

+ 2 - 0
app/const/sp_page_show.js

@@ -15,6 +15,7 @@ const pageStatus = {
 };
 // 模块管理开关
 const managerPageControl = [
+    { title: '项目概况', name: 'openInfo', value: pageStatus.show, type: 'checkbox' },
     { title: '决策大屏', name: 'openDataCollect', value: pageStatus.show, type: 'checkbox', tip: '开启后,前台配置用户权限后方可显示' },
     { title: '合同管理', name: 'openContract', value: pageStatus.show, type: 'checkbox' },
     { title: '资料归集', name: 'openFile', value: pageStatus.show, type: 'checkbox' },
@@ -105,6 +106,7 @@ const defaultSetting = {
     openChangePlan: 0,
     openChangeWhiteList: 0,
     openChangeState: 0,
+    openInfo: 1,
 };
 
 module.exports = {

+ 4 - 2
app/const/spread.js

@@ -672,10 +672,11 @@ const BaseSpreadColSetting = {
                 {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
             ],
             end_calc: [
-                {title: '截止本期计量|合同', colSpan: '4|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+                {title: '截止本期计量|合同', colSpan: '5|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
                 {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'end_qc_qty', hAlign: 2, width: 80, type: 'Number', readOnly: true},
                 {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'end_qc_minus_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
                 {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'end_gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+                {title: '|合同完成率(%)', colSpan: '|1', rowSpan: '|1', field: 'end_contract_percent', hAlign: 2, width: 65, readOnly: true, type: 'Number'},
             ],
             postil: [{title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 80, formatter: '@', cellType: 'autoTip'},],
             drawing_code: [{title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', textIndent: 1}],
@@ -830,10 +831,11 @@ const BaseSpreadColSetting = {
                 {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
             ],
             end_calc: [
-                {title: '截止本期计量|合同', colSpan: '4|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+                {title: '截止本期计量|合同', colSpan: '5|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
                 {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'end_qc_qty', hAlign: 2, width: 80, type: 'Number', readOnly: true},
                 {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'end_qc_minus_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
                 {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'end_gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+                {title: '|合同完成率(%)', colSpan: '|1', rowSpan: '|1', field: 'end_contract_percent', hAlign: 2, width: 65, readOnly: true, type: 'Number'},
             ],
             postil: [{title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 80, formatter: '@', cellType: 'autoTip'},],
             drawing_code: [{title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', textIndent: 1}],

+ 1 - 1
app/const/tender_info.js

@@ -206,7 +206,7 @@ const defaultInfo = {
             minusNoValue: true,
         },
         sum_load: {
-            ignoreParent: false,
+            ignoreParent: true,
         },
         stage_rela: {
             show: false,

+ 2 - 2
app/controller/advance_controller.js

@@ -297,7 +297,7 @@ module.exports = app => {
                 }
                 const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: ctx.tender.id, sp_type: shenpiConst.sp_type.advance, sp_status: shenpiConst.sp_status.gdzs });
                 const is_gdzs = shenpiInfo && ctx.tender.info.shenpi.advance === shenpiConst.sp_status.gdzs ? 1 : 0;
-                const result = await ctx.service.advanceAudit.addAuditor(ctx.tender.id, ctx.advance.id, audit_id, ctx.advance.times, is_gdzs);
+                const result = await ctx.service.advanceAudit.addAuditor(ctx.tender.id, ctx.advance.id, audit_id, ctx.advance.times, ctx.advance.type, is_gdzs);
                 if (!result) {
                     throw '添加审核人失败';
                 }
@@ -388,7 +388,7 @@ module.exports = app => {
                     }
                 }
 
-                await ctx.service.advanceAudit.check(ctx.advance.id, data, ctx.advance.times);
+                await ctx.service.advanceAudit.check(ctx.advance.id, data, ctx.advance.times, ctx.advance.type);
 
                 ctx.redirect(ctx.request.header.referer);
             } catch (err) {

+ 1 - 1
app/controller/dashboard_controller.js

@@ -139,7 +139,7 @@ module.exports = app => {
             // 获取版本信息
             const versionList = await ctx.service.version.getAllDataByCondition({ orders: [['id', 'desc']], limit: 5, offset: 0 });
             // 获取项目通知
-            const msgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, '', 10);
+            const msgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, ctx.helper._.map(subProjects, 'id'), 10);
             // 获取系统通知
             const sysMsgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, '', 1, 0, 2);
             // 获取系统维护信息

+ 1 - 1
app/controller/datacollect_controller.js

@@ -67,7 +67,7 @@ module.exports = app => {
                 if (ctx.params.index) {
                     ctx.subProject.data_collect = parseInt(ctx.params.index);
                 }
-                const is_dz2 = ['P0505', 'P0506', 'P1201', 'P1202', 'GY18Y', 'GYJJ1', 'P1103'].indexOf(ctx.session.sessionProject.code) !== -1
+                const is_dz2 = ['P0505', 'P0506', 'P1201', 'P1202', 'GY18Y', 'GYJJ1', 'P1103', 'KLG25'].indexOf(ctx.session.sessionProject.code) !== -1
                     && ctx.subProject.data_collect_pages.includes('6') && ctx.subProject.data_collect === 6;
                 const renderData = {
                     projectData,

+ 3 - 0
app/controller/material_controller.js

@@ -241,6 +241,9 @@ module.exports = app => {
                 if (doingMaterial) {
                     throw '存在待上报或审批中的调差期,请勿重复生成';
                 }
+                if (data.is_stage_self && data.stage_id.length > 12) {
+                    throw '独立调差下最多选择12个计量期';
+                }
                 // 参考变更令的做法,在创建新一期预付款时,需要copy前一个预付款报表的签名信息
                 const lastMaterial = await ctx.service.material.getLastestMaterial(ctx.tender.id, true);
                 const newMaterial = await ctx.service.material.addMaterial(ctx.tender.id, data);

+ 67 - 12
app/controller/spss_controller.js

@@ -32,9 +32,9 @@ module.exports = app => {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
                 const renderData = {
                     categoryData,
-                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.info)
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherInfo)
                 };
-                await this.layout('spss/info.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/gather_info.ejs', renderData, 'spss/gather_info_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -105,8 +105,59 @@ module.exports = app => {
             }
         }
 
-        async _loadInfoData(tender) {
+        async _loadStageTpData(info, tender, stage, loadPre = true) {
+            if (!stage) return;
+            if (stage.readOnly && stage.status === status.uncheck) return;
+            if (loadPre) {
+                info.pre_contract_tp = stage.pre_contract_tp;
+                info.pre_qc_tp = stage.pre_qc_tp;
+                info.pre_yf_tp = stage.pre_yf_tp;
+                info.pre_sf_tp = stage.pre_sf_tp;
+            }
+            if (!stage.readOnly) await this.ctx.service.stage.checkStageGatherData(stage, this.ctx.session.sessionUser.is_admin);
 
+            info.contract_tp = this.ctx.helper.add(stage.contract_tp, info.contract_tp);
+            info.qc_tp = this.ctx.helper.add(stage.qc_tp, info.qc_tp);
+            info.contract_pc_tp = this.ctx.helper.add(stage.contract_pc_tp, info.contract_pc_tp);
+            info.qc_pc_tp = this.ctx.helper.add(stage.qc_pc_tp, info.qc_pc_tp);
+            info.pc_tp = this.ctx.helper.add(stage.pc_tp, info.pc_tp);
+            info.yf_tp = this.ctx.helper.add(stage.yf_tp, info.yf_tp);
+            info.sf_tp = this.ctx.helper.add(stage.sf_tp, info.sf_tp);
+        }
+        async _loadStagesTpData(info, tender, stages, preStage, endStage) {
+            if (preStage) {
+                info.pre_contract_tp = this.ctx.helper.sum([preStage.contract_tp, preStage.pre_contract_tp, preStage.contract_pc_tp]);
+                info.pre_contract_tp = this.ctx.helper.sum([preStage.qc_tp, preStage.pre_qc_tp, preStage.qc_pc_tp]);
+                info.pre_yf_tp = this.ctx.helper.add(preStage.yf_tp, preStage.pre_yf_tp);
+                info.pre_sf_tp = this.ctx.helper.add(preStage.sf_tp, preStage.pre_sf_tp);
+            }
+            for (const stage of stages) {
+                await this.ctx.service.stage.doCheckStage(stage);
+                await this._loadStageTpData(info, tender, stage, false);
+            }
+        }
+        async _loadInfoData(tender, filter) {
+            const info = { measure_type_str: '' };
+            if (tender.measure_type === measureType.tz.value) info.measure_type_str = measureType.tz.title;
+            if (tender.measure_type === measureType.gcl.value) info.measure_type_str = measureType.gcl.title;
+            await this.ctx.service.tenderCache.loadTenderCache(tender, this.ctx.session.sessionUser.accountId);
+            info.contract_price = tender.contract_price;
+            info.advance_tp = tender.advance_tp;
+            info.change_tp = tender.change_tp;
+            info.progress = tender.progress;
+            if (filter.type === 'stage') {
+                await this._loadStageTpData(info, tender, filter.stage);
+            } else {
+                await this._loadStagesTpData(info, tender, filter.stages, filter.preStage, filter.endStage);
+            }
+            info.pre_gather_tp = this.ctx.helper.add(info.pre_contract_tp, info.pre_qc_tp);
+            info.gather_tp = this.ctx.helper.sum([info.contract_tp, info.qc_tp, info.pc_tp]);
+            info.end_contract_tp = this.ctx.helper.sum([info.contract_tp, info.contract_pc_tp, info.pre_contract_tp]);
+            info.end_qc_tp = this.ctx.helper.sum([info.qc_tp, info.qc_pc_tp, info.pre_qc_tp]);
+            info.end_gather_tp = this.ctx.helper.add(info.gather_tp, info.pre_gather_tp);
+            info.end_sf_tp = this.ctx.helper.add(info.sf_tp, info.pre_sf_tp);
+            info.end_yf_tp = this.ctx.helper.add(info.yf_tp, info.pre_yf_tp);
+            return info;
         }
         async _loadLedgerData(tender) {
             const bills = await this.ctx.service.ledger.getAllDataByCondition({
@@ -459,12 +510,16 @@ module.exports = app => {
         async _loadTenderData(tid, filter, stageInfo) {
             this.ctx.tender = null;
             const tender = await this.ctx.service.tender.checkTender(tid);
-            const result = { id: tender.id, name: tender.name };
+            const result = { id: tender.id, name: tender.name, category: tender.category };
             let stageFilter = null;
             for (const f of filter) {
                 switch (f) {
                     case 'info':
-                        result.info = await this._loadInfoData(tender);
+                        if (!stageFilter) {
+                            stageFilter = await this._filterStages(tender, stageInfo);
+                            result.stage_filter = stageFilter.filter;
+                        }
+                        result.info = await this._loadInfoData(tender, stageFilter);
                         break;
                     case 'ledger':
                         if (filter.indexOf('stage') < 0) [result.bills, result.pos] = await this._loadLedgerData(tender);
@@ -472,49 +527,49 @@ module.exports = app => {
                     case 'stage':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         [result.bills, result.pos] = await this._loadStageLedgerData(tender, stageFilter);
                         break;
                     case 'jgcl':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.jgcl = await this._loadJgclData(tender, stageFilter);
                         break;
                     case 'yjcl':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.yjcl = await this._loadYjclData(tender, stageFilter);
                         break;
                     case 'bonus':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.bonus = await this._loadBonusData(tender, stageFilter);
                         break;
                     case 'safeProd':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.safeProd = await this._loadSafeProdData(tender, stageFilter);
                         break;
                     case 'tempLand':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.tempLand = await this._loadTempLandData(tender, stageFilter);
                         break;
                     case 'other':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
-                            result.filter = stageFilter.filter;
+                            result.stage_filter = stageFilter.filter;
                         }
                         result.other = await this._loadOtherData(tender, stageFilter);
                         break;

+ 32 - 0
app/controller/sub_proj_controller.js

@@ -441,6 +441,38 @@ module.exports = app => {
             }
         }
 
+        async uploadBigFile(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.type || !data.rela_id || !data.fileInfo) throw '缺少参数';
+
+                let result;
+                const fileInfo = path.parse(data.fileInfo.filename);
+                switch(data.type) {
+                    case 'begin':
+                        const create_time = Date.parse(new Date()) / 1000;
+                        result = {
+                            filename: `sp/progress/${ctx.subProject.id}/${ctx.moment().format('YYYYMMDD')}/${create_time + '_' + fileInfo.ext}`,
+                        };
+                        result.filepath = ctx.app.config.fujianOssFolder + result.filename;
+                        result.oss = await ctx.helper.getOssToken(ctx.app.fujianOss);
+                        break;
+                    case 'end':
+                        const user = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+                        const uploadFiles = [{
+                            filepath: data.filepath, rela_id: data.rela_id,
+                            filename: fileInfo.name, fileext: fileInfo.ext, filesize: data.fileInfo.filesize,
+                        }];
+                        result = await ctx.service.subProjFile.addFiles(ctx.subProject.id, ctx.request.url.split('/')[3], uploadFiles, user);
+                        break;
+                }
+                ctx.body = {err: 0, msg: '', data: result };
+            } catch (error) {
+                ctx.log(error);
+                ctx.body = this.ajaxErrorBody(error, '上传附件失败,请重试');
+            }
+        }
+
         async deleteFile(ctx) {
             try{
                 const data = JSON.parse(ctx.request.body.data);

+ 3 - 1
app/controller/sub_proj_setting_controller.js

@@ -258,6 +258,7 @@ module.exports = app => {
                     company: filter.company,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.setting.sp_permission),
                     permissionBlock: ctx.service.subProjPermission.PermissionBlock,
+                    accountList,
                 };
                 await this.layout('sp_setting/user.ejs', renderData, 'sp_setting/user_modal.ejs');
             } catch (error) {
@@ -305,6 +306,7 @@ module.exports = app => {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.setting.sp_permission),
                     permissionBlock: ctx.service.subProjPermission.PermissionBlock,
                     permissionConst: permissionConst[ctx.query.ptype],
+                    accountList,
                 };
                 await this.layout('sp_setting/permission.ejs', renderData, 'sp_setting/user_modal.ejs');
             } catch (error) {
@@ -430,7 +432,7 @@ module.exports = app => {
                 const categoryData = await ctx.service.category.getAllCategory(ctx.subProject);
                 const tenders = await ctx.service.tender.getList('', null, 1);
                 const dcTenders = await ctx.service.datacollectTender.getList(ctx.subProject.project_id, ctx.subProject.id);
-                const is_dz2 = ['P0505', 'P0506', 'P1201', 'P1202', 'GY18Y', 'GYJJ1', 'P1103'].indexOf(ctx.session.sessionProject.code) !== -1 ? 6 : false;
+                const is_dz2 = ['P0505', 'P0506', 'P1201', 'P1202', 'GY18Y', 'GYJJ1', 'P1103', 'KLG25'].indexOf(ctx.session.sessionProject.code) !== -1 ? 6 : false;
                 const renderData = {
                     dataCollectAudits,
                     accountList,

+ 4 - 4
app/controller/tender_controller.js

@@ -76,7 +76,7 @@ module.exports = app => {
                     subProject,
                     buildStatus: tenderConst.buildStatus,
                 };
-                renderData.selfCategoryLevel = await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
+                renderData.selfCategoryLevel = this.ctx.subProject.permission.self_category_level; // await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
                 renderData.is_finish = false;
                 await this.layout(view, renderData, modal);
             } catch (err) {
@@ -115,7 +115,7 @@ module.exports = app => {
                     subProject,
                     buildStatus: tenderConst.buildStatus,
                 };
-                renderData.selfCategoryLevel = await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
+                renderData.selfCategoryLevel = this.ctx.subProject.permission.self_category_level; // await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
                 renderData.is_finish = true;
                 await this.layout(view, renderData, modal);
             } catch (err) {
@@ -142,7 +142,7 @@ module.exports = app => {
                 renderData.auditConst = auditConst;
                 renderData.uid = this.ctx.session.sessionUser.accountId;
                 renderData.pid = this.ctx.session.sessionProject.id;
-                renderData.selfCategoryLevel = await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
+                renderData.selfCategoryLevel = this.ctx.subProject.permission.self_category_level; // await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
                 renderData.is_finish = false;
                 renderData.colSet = this.colSet;
                 renderData.buildStatus = tenderConst.buildStatus;
@@ -172,7 +172,7 @@ module.exports = app => {
                 renderData.auditConst = auditConst;
                 renderData.uid = this.ctx.session.sessionUser.accountId;
                 renderData.pid = this.ctx.session.sessionProject.id;
-                renderData.selfCategoryLevel = await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
+                renderData.selfCategoryLevel = this.ctx.subProject.permission.self_category_level; // await this.ctx.service.projectAccount.getSelfCategoryLevel(this.ctx.session.sessionUser.accountId);
                 renderData.is_finish = true;
                 renderData.colSet = this.colSet;
                 renderData.buildStatus = tenderConst.buildStatus;

+ 2 - 2
app/public/js/advance_audit.js

@@ -439,8 +439,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext) === -1) {

+ 2 - 2
app/public/js/change_apply_information.js

@@ -835,8 +835,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

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

@@ -77,7 +77,7 @@ $(document).ready(() => {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('文件大小过大!');
                 return false;
             }

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

@@ -145,7 +145,7 @@ $(document).ready(() => {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('文件大小过大!');
                 return false;
             }

+ 2 - 2
app/public/js/change_plan_information.js

@@ -984,8 +984,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 2 - 2
app/public/js/change_project_information.js

@@ -198,8 +198,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 10 - 3
app/public/js/change_revise.js

@@ -4350,9 +4350,9 @@ $(document).ready(() => {
                 dealBills.spread.refresh();
             } else if (tab.attr('content') === '#search') {
                 if (!searchLedger) {
-                    searchLedger = $.billsSearch({
+                    searchLedger = $.ledgerSearch({
                         selector: '#search',
-                        searchSpread: billsSpread,
+                        ledger: { billsTree: billsTree, pos: pos },
                         searchOver: true,
                         searchEmpty: true,
                         resultSpreadSetting: {
@@ -4375,8 +4375,15 @@ $(document).ready(() => {
                             selectedBackColor: '#fffacd',
                             readOnly: true,
                         },
-                        afterLocated: function () {
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
                             posSpreadObj.loadCurPosData();
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
                         },
                         customSearch: [
                             {

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

@@ -157,7 +157,7 @@ $(function () {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('文件大小过大!');
                 return false;
             }

+ 2 - 2
app/public/js/financial_pay_detail.js

@@ -728,8 +728,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 2 - 2
app/public/js/financial_transfer.js

@@ -173,8 +173,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 2 - 2
app/public/js/financial_transfer_tender.js

@@ -190,8 +190,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 1 - 0
app/public/js/gcl_gather.js

@@ -134,6 +134,7 @@ const gclGatherModel = (function () {
      */
     function newGclNode(node) {
         const gcl = {
+            id: node.id,
             b_code: node.b_code,
             name: node.name,
             unit: node.unit,

+ 14 - 7
app/public/js/ledger.js

@@ -122,6 +122,7 @@ $(document).ready(function() {
         id: 'id', ledgerId: 'lid',
     });
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
+    const posSheet = posSpread.getActiveSheet();
 
     // 初始化 附属工程量
     const ancGcl = createAncillaryGcl({ id: 'id', masterId: 'lid', sort: [['g_order', 'asc']] });
@@ -3066,9 +3067,9 @@ $(document).ready(function() {
                 dealBills.spread.refresh();
             } else if (tab.attr('content') === '#search') {
                 if (!searchLedger) {
-                    searchLedger = $.billsSearch({
+                    searchLedger = $.ledgerSearch({
                         selector: '#search',
-                        searchSpread: ledgerSpread,
+                        ledger: { billsTree: ledgerTree, pos: pos },
                         resultSpreadSetting: {
                             cols: [
                                 {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@'},
@@ -3089,9 +3090,15 @@ $(document).ready(function() {
                             selectedBackColor: '#fffacd',
                             readOnly: true,
                         },
-                        afterLocated: function () {
-                            posOperationObj.loadCurPosData();
-                            ancGclObj.loadCurAncillaryGcl();
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(ledgerSheet, cur.lid, true);
+                            treeOperationObj.loadRelaData();
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
                         },
                         calcSum: function (result) {
                             const sum = { name: '合计' };
@@ -4708,7 +4715,7 @@ $(document).ready(function() {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('存在上传文件大小过大!');
                 return false;
             }
@@ -4887,7 +4894,7 @@ $(document).ready(function() {
       const filename = name.substring(0, name.lastIndexOf("."));
       const fileext = name.substr(name.indexOf("."));
       const filesize = file.size;
-      if (filesize > 30 * 1024 * 1024) {
+      if (filesize > 50 * 1024 * 1024) {
           toastr.error('文件大小过大!');
           $('#change-att-btn').val('');
           return false;

+ 2 - 2
app/public/js/material_file.js

@@ -358,8 +358,8 @@ function validateFiles(files) {
         return false
     }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 30) {
-            toastr.error('文件大小限制为30MB');
+        if (file.size > 1024 * 1024 * 50) {
+            toastr.error('文件大小限制为50MB');
             return false
         }
         if (whiteList.indexOf('.' + file.ext) === -1) {

+ 200 - 3
app/public/js/measure_compare.js

@@ -267,7 +267,7 @@ function calculateStagePosData(datas) {
 }
 
 $(document).ready(() => {
-    let spec;
+    let spec, ledgerSearch, gclSearch;
     autoFlashHeight();
     initSpreadSettingWithRoles([]);
     const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
@@ -334,6 +334,25 @@ $(document).ready(() => {
             leafXmjSpread.refresh();
         }
     });
+    // 工具栏resizer
+    $.divResizer({
+        select: '#tz-right-spr',
+        callback: function () {
+            billsSpread.refresh();
+            posSpread.refresh();
+            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+            if (ledgerSearch) ledgerSearch.spread.refresh();
+        }
+    });
+    $.divResizer({
+        select: '#gcl-right-spr',
+        callback: function () {
+            gclSpread.refresh();
+            leafXmjSpread.refresh();
+            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+            if (gclSearch) gclSearch.spread.refresh();
+        }
+    });
 
     const cTree = createNewPathTree('master', {
         id: 'ledger_id',
@@ -517,21 +536,199 @@ $(document).ready(() => {
         });
     })('a[name=showLevel]', billsSheet);
 
+    // 展开收起工具栏
+    const showTzSideTools = function (show) {
+        const left = $('#tz-left-view'), right = $('#tz-right-view'), parent = left.parent();
+        if (show) {
+            right.show();
+            autoFlashHeight();
+            /**
+             * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
+             * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
+             * 故需要通过最终的parent.width再计算一次left.width
+             *
+             * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
+             * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
+             *
+             */
+                //left.css('width', parent.width() - right.outerWidth());
+                //left.css('width', parent.width() - right.outerWidth());
+            const percent = 100 - right.outerWidth() /parent.width() * 100;
+            left.css('width', percent + '%');
+        } else {
+            left.width(parent.width());
+            right.hide();
+        }
+    };
+    const showGclSideTools = function (show) {
+        const left = $('#gcl-left-view'), right = $('#gcl-right-view'), parent = left.parent();
+        if (show) {
+            right.show();
+            autoFlashHeight();
+            /**
+             * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
+             * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
+             * 故需要通过最终的parent.width再计算一次left.width
+             *
+             * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
+             * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
+             *
+             */
+                //left.css('width', parent.width() - right.outerWidth());
+                //left.css('width', parent.width() - right.outerWidth());
+            const percent = 100 - right.outerWidth() /parent.width() * 100;
+            left.css('width', percent + '%');
+        } else {
+            left.width(parent.width());
+            right.hide();
+        }
+    };
+    $('a', '#tz-side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            // const close = $('.active', '#side-menu').length === 0;
+            $('a', '#tz-side-menu').removeClass('active');
+            $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
+            tab.addClass('active');
+            tabPanel.addClass('active');
+            // $('.tab-content .tab-pane').removeClass('active');
+            showTzSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#tz-search') {
+                if (!ledgerSearch) {
+                    ledgerSearch = $.ledgerSearch({
+                        selector: '#tz-search',
+                        ledger: { billsTree: cTree, pos: cPos },
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@'},
+                                {title: '清单编号', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '名称', field: 'name', width: 150, hAlign: 0, formatter: '@'},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@'},
+                                {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                            readOnly: true,
+                        },
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
+                            loadPosData();
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
+                        },
+                    });
+                }
+                ledgerSearch.spread.refresh();
+            }
+        } else { // 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showTzSideTools(tab.hasClass('active'));
+        }
+        billsSpread.refresh();
+        posSpread.refresh();
+    });
+    $('a', '#gcl-side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            // const close = $('.active', '#side-menu').length === 0;
+            $('a', '#gcl-side-menu').removeClass('active');
+            $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
+            tab.addClass('active');
+            tabPanel.addClass('active');
+            // $('.tab-content .tab-pane').removeClass('active');
+            showGclSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#gcl-search') {
+                if (!gclSearch) {
+                    gclSearch = $.gclSearch({
+                        selector: '#gcl-search',
+                        gcl: { bills: gclGatherData, getBillsXmj: function(node){ return node.leafXmjs; } },
+                        searchField: { bills: ['b_code', 'name'], xmj: ['code', 'dwgc', 'fbgc', 'fxgc', 'jldy', 'bwmx'], },
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '清单编号', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '项目节编号', field: 'code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '名称', field: 'name', width: 120, hAlign: 0, formatter: '@'},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@'},
+                                {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
+                                {title: '单位工程', colSpan: '1', rowSpan: '2', field: 'dwgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '分部工程', colSpan: '1', rowSpan: '2', field: 'fbgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '分项工程', colSpan: '1', rowSpan: '2', field: 'fxgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '细目', colSpan: '1', rowSpan: '2', field: 'jldy', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '计量单元', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 80, formatter: '@'},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                            readOnly: true,
+                        },
+                        locate: function(cur) {
+                            if (!cur.bid) return;
+
+                            const bIndex = gclSheet.zh_data.findIndex(x => { return x.id === cur.bid; });
+                            SpreadJsObj.locateRow(gclSheet, bIndex);
+                            loadLeafXmjData();
+                            if (cur.xid && cur.xid !== -1) {
+                                const xIndex = leafXmjSheet.zh_data.findIndex(x => { return x.id === cur.xid; });
+                                SpreadJsObj.locateRow(leafXmjSheet, xIndex);
+                            }
+                        },
+                    });
+                }
+                gclSearch.spread.refresh();
+            }
+        } else { // 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showGclSideTools(tab.hasClass('active'));
+        }
+        gclSpread.refresh();
+        leafXmjSpread.refresh();
+    });
+
     $('#exportExcel').click(function () {
         const exportLedger = function () {
-            const data = [];
+            const data = [], groupData = [];
             if (!billsSheet.zh_tree) return;
+            billsSheet.zh_tree.recursiveExe(function(node) {
+                if (node.children && node.children.length > 0) {
+                    node._export_group = _.sum(node.children.map(x => { return x._export_group; })) + node.children.length;
+                } else {
+                    const posRange = cPos.getLedgerPos(node.id);
+                    node._export_group = posRange ? posRange.length : 0;
+                }
+            });
             for (const node of billsSheet.zh_tree.nodes) {
                 data.push(node);
                 const posRange = cPos.getLedgerPos(node.id);
                 if (posRange && posRange.length > 0) {
+                    if (node._export_group) groupData.push({ code: node.code, b_code: node.b_code, start: data.length, count: node._export_group });
                     for (const pr of posRange) {
                         data.push(pr);
                     }
                 }
             }
 
-            SpreadExcelObj.exportSimpleXlsxSheet(exportBillsSpreadSetting, data, $('.sidebar-title').attr('data-original-title') + "-多期比较.xlsx");
+            SpreadExcelObj.exportSimpleXlsxSheet(exportBillsSpreadSetting, data, $('.sidebar-title').attr('data-original-title') + "-多期比较.xlsx", groupData);
         };
         const exportGcl = function () {
             const data = [];

+ 5 - 0
app/public/js/measure_material.js

@@ -242,6 +242,11 @@ $(function () {
             stage_id.push(parseInt($(this).val()));
         });
         const is_stage_self = parseInt($('input[name="is_stage_self"]:checked').val());
+        if (is_stage_self && stage_id.length > 12) {
+            toastr.error('独立调差下最多选择12个计量期');
+            $(this).removeAttr('disabled');
+            return false;
+        }
         const newMaterialData = {
             s_order: $('#s_order').val(),
             period: $('#add-qi input[name="period"]').val(),

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

@@ -241,7 +241,7 @@ $(function () {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('文件大小过大!');
                 return false;
             }

+ 2 - 2
app/public/js/payment_safe.js

@@ -753,8 +753,8 @@ $(document).ready(function() {
                     toastr.error('未选择上传文件。');
                     return false;
                 }
-                if (file.size > 30 * 1024 * 1024) {
-                    toastr.error('上传文件大小超过30MB。');
+                if (file.size > 50 * 1024 * 1024) {
+                    toastr.error('上传文件大小超过50MB。');
                     return false;
                 }
                 const fileext = '.' + file.name.toLowerCase().split('.').splice(-1)[0];

+ 4 - 4
app/public/js/profile_cert.js

@@ -254,8 +254,8 @@ $(document).ready(function() {
             return
         }
         const filesize = file.size;
-        if (filesize > 30 * 1024 * 1024) {
-            toastr.error('上传的文件大小不能超过30MB!');
+        if (filesize > 50 * 1024 * 1024) {
+            toastr.error('上传的文件大小不能超过50MB!');
             $(this).val('');
             return false;
         }
@@ -290,8 +290,8 @@ $(document).ready(function() {
             return
         }
         const filesize = file.size;
-        if (filesize > 30 * 1024 * 1024) {
-            toastr.error('上传的文件大小不能超过30MB!');
+        if (filesize > 50 * 1024 * 1024) {
+            toastr.error('上传的文件大小不能超过50MB!');
             $(this).val('');
             return false;
         }

+ 10 - 3
app/public/js/revise.js

@@ -2946,9 +2946,9 @@ $(document).ready(() => {
                 bgBills.spread.refresh();
             } else if (tab.attr('content') === '#search') {
                 if (!searchLedger) {
-                    searchLedger = $.billsSearch({
+                    searchLedger = $.ledgerSearch({
                         selector: '#search',
-                        searchSpread: billsSpread,
+                        ledger: { billsTree, pos },
                         resultSpreadSetting: {
                             cols: [
                                 {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@'},
@@ -2969,8 +2969,15 @@ $(document).ready(() => {
                             selectedBackColor: '#fffacd',
                             readOnly: true,
                         },
-                        afterLocated: function () {
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
                             posSpreadObj.loadCurPosData();
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
                         },
                         calcSum: function (result) {
                             const sum = { name: '合计' };

+ 11 - 4
app/public/js/revise_compare.js

@@ -338,9 +338,9 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search') {
                 if (!searchLedger) {
-                    searchLedger = $.billsSearch({
+                    searchLedger = $.ledgerSearch({
                         selector: '#search',
-                        searchSpread: billsSpread,
+                        ledger: { billsTree: billsTree, getLedgerPos: function (node){ return node.pos; } },
                         resultSpreadSetting: {
                             cols: [
                                 {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@', readOnly: true},
@@ -357,9 +357,16 @@ $(document).ready(() => {
                             font: '12px 微软雅黑',
                             selectedBackColor: '#fffacd',
                         },
-                        afterLocated: function () {
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
                             posSpreadObj.loadCurPosData();
-                        }
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
+                        },
                     });
                 }
                 searchLedger.spread.refresh();

+ 11 - 3
app/public/js/revise_history.js

@@ -306,9 +306,10 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
                 if (!searchLedger) {
-                    searchLedger = $.billsSearch({
+                    searchLedger = $.ledgerSearch({
                         selector: '#search',
                         searchSpread: billsSpread,
+                        ledger: { billsTree: billsTree, pos: pos },
                         resultSpreadSetting: {
                             cols: [
                                 {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@'},
@@ -329,9 +330,16 @@ $(document).ready(() => {
                             selectedBackColor: '#fffacd',
                             readOnly: true,
                         },
-                        afterLocated: function () {
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
                             posSpreadObj.loadCurPosData();
-                        }
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
+                        },
                     });
                 }
                 searchLedger.spread.refresh();

+ 2 - 2
app/public/js/se_bonus.js

@@ -179,8 +179,8 @@ $(document).ready(() => {
                     toastr.error('未选择上传文件。');
                     return false;
                 }
-                if (file.size > 30 * 1024 * 1024) {
-                    toastr.error('上传文件大小超过30MB。');
+                if (file.size > 50 * 1024 * 1024) {
+                    toastr.error('上传文件大小超过50MB。');
                     return false;
                 }
                 const fileext = '.' + file.name.toLowerCase().split('.').splice(-1)[0];

+ 10 - 3
app/public/js/settle_gather.js

@@ -176,9 +176,9 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
-                searchLedger = $.billsSearch({
+                searchLedger = $.ledgerSearch({
                     selector: '#search',
-                    searchSpread: slSpread,
+                    ledger: { billsTree: settleTree, pos: settlePos },
                     searchOver: true,
                     searchEmpty: true,
                     keyId: 'tree_id',
@@ -201,8 +201,15 @@ $(document).ready(() => {
                         selectedBackColor: '#fffacd',
                         readOnly: true,
                     },
-                    afterLocated: function () {
+                    locate: function(cur) {
+                        if (!cur.lid) return;
+
+                        SpreadJsObj.locateTreeNode(slSheet, cur.lid, true);
                         settlePosObj.loadCurPosData();
+                        if (cur.pid && cur.pid !== -1) {
+                            const pIndex = spSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                            SpreadJsObj.locateRow(spSheet, pIndex);
+                        }
                     },
                 });
                 searchLedger.spread.refresh();

+ 10 - 3
app/public/js/settle_ledger.js

@@ -281,9 +281,9 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
-                searchLedger = $.billsSearch({
+                searchLedger = $.ledgerSearch({
                     selector: '#search',
-                    searchSpread: slSpread,
+                    ledger: { billsTree: settleTree, pos: settlePos },
                     searchOver: true,
                     searchEmpty: true,
                     keyId: 'tree_id',
@@ -306,8 +306,15 @@ $(document).ready(() => {
                         selectedBackColor: '#fffacd',
                         readOnly: true,
                     },
-                    afterLocated: function () {
+                    locate: function(cur) {
+                        if (!cur.lid) return;
+
+                        SpreadJsObj.locateTreeNode(slSheet, cur.lid, true);
                         settlePosObj.loadCurPosData();
+                        if (cur.pid && cur.pid !== -1) {
+                            const pIndex = spSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                            SpreadJsObj.locateRow(spSheet, pIndex);
+                        }
                     },
                 });
                 searchLedger.spread.refresh();

+ 10 - 3
app/public/js/settle_select.js

@@ -408,9 +408,9 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
-                searchLedger = $.billsSearch({
+                searchLedger = $.ledgerSearch({
                     selector: '#search',
-                    searchSpread: slSpread,
+                    ledger: { billsTree: settleTree, pos: settlePos },
                     searchOver: true,
                     searchEmpty: true,
                     resultSpreadSetting: {
@@ -432,8 +432,15 @@ $(document).ready(() => {
                         selectedBackColor: '#fffacd',
                         readOnly: true,
                     },
-                    afterLocated: function () {
+                    locate: function(cur) {
+                        if (!cur.lid) return;
+
+                        SpreadJsObj.locateTreeNode(slSheet, cur.lid, true);
                         settlePosObj.loadCurPosData();
+                        if (cur.pid && cur.pid !== -1) {
+                            const pIndex = spSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                            SpreadJsObj.locateRow(spSheet, pIndex);
+                        }
                     },
                     customSearch: [
                         {

+ 248 - 0
app/public/js/shares/cs_tools.js

@@ -765,6 +765,254 @@ const showSelectTab = function(select, spread, afterShow) {
         });
         return {spread: resultSpread};
     };
+    $.ledgerSearch = function (setting) {
+        if (!setting.selector || !setting.ledger || !setting.resultSpreadSetting) return;
+        if (!setting.ledger.billsTree) return;
+        if (!setting.ledger.pos && !setting.ledger.getLedgerPos) return;
+        if (!setting.searchRangeStr) setting.searchRangeStr = '项目节编号/清单编号/名称/台账数量';
+        if (!setting.keyId) setting.keyId = 'ledger_id';
+        const ledger = setting.ledger;
+        const resultId = setting.id + '-search-result';
+        const obj = $(setting.selector);
+        let filter = [];
+        if (setting.searchOver || setting.searchEmpty) {
+            filter.push('<select class="input-group-text" id="search-filter">');
+            filter.push('<option value="">台账</option>');
+            if (setting.customSearch) {
+                for (const cs of setting.customSearch) {
+                    if (cs.valid) filter.push('<option value="' + cs.key + '">' + cs.title + '</option>');
+                }
+            }
+            filter.push('</select>');
+        }
+        obj.html(
+            '                        <div class="sjs-bar">\n' +
+            '                            <div class="input-group input-group-sm pb-1">\n' +
+            '                                <div class="input-group-prepend">\n' +
+            filter.join('') +
+            '                                </div>' +
+            '                                <input id="searchKeyword" type="text" class="form-control" autocomplete="off" placeholder="可查找 ' + setting.searchRangeStr + '" aria-label="Recipient\'s username" aria-describedby="button-addon2">\n' +
+            '                                <div class="input-group-append">\n' +
+            '                                    <button class="btn btn-outline-secondary" type="button"">搜索</button>\n' +
+            '                                </div>\n' +
+            '                            </div>\n' +
+            '                        </div>\n' +
+            '                        <div id="' + resultId + '" class="sjs-sh">\n' +
+            '                        </div>'
+        );
+        autoFlashHeight();
+        const resultSpread = SpreadJsObj.createNewSpread($('#' + resultId)[0]);
+        SpreadJsObj.initSheet(resultSpread.getActiveSheet(), setting.resultSpreadSetting);
+        let searchResult = [];
+        const defaultCheck = function(node, keyword) {
+            const keyNum = _.toNumber(keyword);
+            return (node.code && node.code.indexOf(keyword) > -1) ||
+                (node.b_code && node.b_code.indexOf(keyword) > -1) ||
+                (node.name && node.name.indexOf(keyword) > -1) ||
+                (!_.isNaN(keyNum) && checkZero(ZhCalc.sub(keyNum, node.quantity)));
+        };
+        const getCheckFun = function (key) {
+            const cs = setting.customSearch.find(function (x) {return x.key === key});
+            return cs ? [cs.billsCheck || cs.check, cs.posCheck] : [null, null];
+        };
+        const search = function () {
+            const filter = $('#search-filter').val();
+            const [billsCheck, posCheck] = filter ? getCheckFun(filter) : [null, null];
+            searchCustom(billsCheck || defaultCheck, posCheck || defaultCheck);
+        };
+        const get18Bw = function(tree, data) {
+            let parent = tree.getParent(data);
+            while (parent && (!parent.code || /^[a-zA-Z]/.test(parent.code || ''))) {
+                parent = tree.getParent(parent);
+            }
+            return parent ? parent.name : '';
+        };
+        const get08Bw = function(tree, data) {
+            let parent = tree.getParent(data);
+            let lastXmj = '', level4Xmj = '';
+            while (parent) {
+                if (parent.code && !lastXmj) lastXmj = parent.name;
+                if (parent.code && parent.level === 4) level4Xmj = parent.name;
+                parent = tree.getParent(parent);
+            }
+            return level4Xmj || lastXmj;
+        };
+        const getBw = function (data) {
+            if (!data.b_code) return '';
+
+            const sortTree = ledger.billsTree;
+            if (!sortTree.checkCodeType) return '';
+
+            if (sortTree.checkCodeType() === '18') {
+                return get18Bw(sortTree, data)
+            } else {
+                return get08Bw(sortTree, data);
+            }
+        };
+        const searchCustom = function (billsCheckFun, posCheckFun) {
+            const keyword = $('#searchKeyword', obj).val();
+
+            searchResult = [];
+            for (const node of ledger.billsTree.nodes) {
+                if (billsCheckFun(node, keyword)) {
+                    const convertData = { lid: node[ledger.billsTree.setting.id], pid: -1 };
+                    for (const col of setting.resultSpreadSetting.cols) {
+                        if (col.field === 'bw') {
+                            convertData.bw = getBw(node);
+                        } else {
+                            convertData[col.field] = node[col.field];
+                        }
+                    }
+                    searchResult.push(convertData);
+                }
+                const posRange = ledger.pos ? ledger.pos.getLedgerPos(node.id) : ledger.getLedgerPos(node);
+                if (!posRange || posRange.length === 0) continue;
+                for (const p of posRange) {
+                    if (posCheckFun(p, keyword)) {
+                        const convertData = { lid: node[ledger.billsTree.setting.id], pid: p[ledger.pos.setting.id] };
+                        for (const col of setting.resultSpreadSetting.cols) {
+                            convertData[col.field] = p[col.field];
+                        }
+                        searchResult.push(convertData);
+                    }
+                }
+            }
+            calculateCompletePercent(searchResult);
+            calculateSum();
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const calculateSum = function () {
+            if (!searchResult || searchResult.length === 0 || !setting.calcSum) return;
+
+            const sum = setting.calcSum(searchResult);
+            if (sum) searchResult.unshift(sum);
+        };
+        const calculateCompletePercent = function (searchResult) {
+            if (!searchResult) return;
+            for (const sr of searchResult) {
+                const base = ZhCalc.add(sr.total_price, sr.end_qc_tp);
+                sr.complete_percent = base !== 0 ? ZhCalc.mul(ZhCalc.div(sr.end_gather_tp, base), 100, 2) : 0;
+            }
+        };
+
+        $('input', obj).bind('keydown', function (e) {
+            if (e.keyCode == 13) search();
+        });
+        $('button', obj).bind('click', () => {search()});
+        resultSpread.getActiveSheet().bind(spreadNS.Events.CellDoubleClick, function (e, info) {
+            const sheet = info.sheet;
+            const data = sheet.zh_data;
+            if (!data) { return }
+
+            const curBills = data[info.row];
+            if (!curBills) return;
+            setting.locate(curBills);
+        });
+        return {spread: resultSpread};
+    };
+    $.gclSearch = function(setting) {
+        if (!setting.selector || !setting.gcl || !setting.resultSpreadSetting) return;
+        if (!setting.gcl.bills) return;
+        if (!setting.gcl.xmj && !setting.gcl.getBillsXmj) return;
+        if (!setting.searchRangeStr) setting.searchRangeStr = '清单编号/名称/项目节编号/单位/分部/分项工程/细目/计量单元';
+        if (!setting.keyId) setting.keyId = 'ledger_id';
+        const gcl = setting.gcl;
+        const resultId = setting.id + '-search-result';
+        const obj = $(setting.selector);
+        let filter = [];
+        if (setting.searchOver || setting.searchEmpty) {
+            filter.push('<select class="input-group-text" id="search-filter">');
+            filter.push('<option value="">清单</option>');
+            if (setting.customSearch) {
+                for (const cs of setting.customSearch) {
+                    if (cs.valid) filter.push('<option value="' + cs.key + '">' + cs.title + '</option>');
+                }
+            }
+            filter.push('</select>');
+        }
+        obj.html(
+            '                        <div class="sjs-bar">\n' +
+            '                            <div class="input-group input-group-sm pb-1">\n' +
+            '                                <div class="input-group-prepend">\n' +
+            filter.join('') +
+            '                                </div>' +
+            '                                <input id="searchKeyword" type="text" class="form-control" autocomplete="off" placeholder="可查找 ' + setting.searchRangeStr + '" aria-label="Recipient\'s username" aria-describedby="button-addon2">\n' +
+            '                                <div class="input-group-append">\n' +
+            '                                    <button class="btn btn-outline-secondary" type="button"">搜索</button>\n' +
+            '                                </div>\n' +
+            '                            </div>\n' +
+            '                        </div>\n' +
+            '                        <div id="' + resultId + '" class="sjs-sh">\n' +
+            '                        </div>'
+        );
+        autoFlashHeight();
+        const resultSpread = SpreadJsObj.createNewSpread($('#' + resultId)[0]);
+        SpreadJsObj.initSheet(resultSpread.getActiveSheet(), setting.resultSpreadSetting);
+        let searchResult = [];
+        const defaultCheck = function(node, keyword, fields) {
+            for (const f of fields) {
+                if (node[f] && node[f].indexOf(keyword) > -1) return true;
+            }
+            return false;
+        };
+        const getCheckFun = function (key) {
+            const cs = setting.customSearch.find(function (x) {return x.key === key});
+            return cs ? [cs.billsCheck, cs.xmjCheck] : [null, null];
+        };
+        const search = function () {
+            const filter = $('#search-filter').val();
+            const [billsCheck, xmjCheck] = filter ? getCheckFun(filter) : [null, null];
+            searchCustom(billsCheck || defaultCheck, xmjCheck || defaultCheck);
+        };
+        const searchCustom = function (billsCheckFun, xmjCheckFun) {
+            const keyword = $('#searchKeyword', obj).val();
+
+            searchResult = [];
+            for (const node of gcl.bills) {
+                if (billsCheckFun(node, keyword, setting.searchField.bills)) {
+                    const convertData = { bid: node.id, xid: -1 };
+                    for (const col of setting.resultSpreadSetting.cols) {
+                        convertData[col.field] = node[col.field];
+                    }
+                    searchResult.push(convertData);
+                }
+                const xmjRange = gcl.xmj ? gcl.xmj.getBillsXmj(node.id) : gcl.getBillsXmj(node);
+                if (!xmjRange || xmjRange.length === 0) continue;
+                for (const x of xmjRange) {
+                    if (xmjCheckFun(x, keyword, setting.searchField.xmj)) {
+                        const convertData = { bid: node.id, xid: x.id };
+                        for (const col of setting.resultSpreadSetting.cols) {
+                            convertData[col.field] = x[col.field];
+                        }
+                        searchResult.push(convertData);
+                    }
+                }
+            }
+            // calculateSum();
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const calculateSum = function () {
+            if (!searchResult || searchResult.length === 0 || !setting.calcSum) return;
+
+            const sum = setting.calcSum(searchResult);
+            if (sum) searchResult.unshift(sum);
+        };
+
+        $('input', obj).bind('keydown', function (e) {
+            if (e.keyCode == 13) search();
+        });
+        $('button', obj).bind('click', () => {search()});
+        resultSpread.getActiveSheet().bind(spreadNS.Events.CellDoubleClick, function (e, info) {
+            const sheet = info.sheet;
+            const data = sheet.zh_data;
+            if (!data) { return }
+
+            const curBills = data[info.row];
+            if (!curBills) return;
+            setting.locate(curBills);
+        });
+        return {spread: resultSpread};
+    };
 
     $.xmjSearch = function (setting) {
         if (!setting.selector || !setting.searchSpread) return;

+ 4 - 0
app/public/js/shares/export_excel.js

@@ -68,6 +68,10 @@ const SpreadExcelObj = (function() {
                 } else if (setting.font) {
                     cell.font(setting.font);
                 }
+                if (col.formatter) {
+                    cell.formatter(col.formatter);
+                    cell.value(cell.text());
+                }
                 cell.hAlign(col.hAlign).vAlign(1);
             }
             if (autoFit) sheet.autoFitRow(curRow);

+ 18 - 2
app/public/js/shares/tender_select_multi.js

@@ -27,8 +27,6 @@ const TenderSelectMulti = function (setting) {
         resultSpread: null,
         resultSheet: null,
         tenderSourceTree: null,
-        orgHistroy: {},
-        trHistory: {},
         trArray: [],
         _rebuildStageSelect: function () {
             if (tsObj.setting.type === 'compare') {
@@ -67,6 +65,23 @@ const TenderSelectMulti = function (setting) {
             SpreadJsObj.reLoadSheetData(tsObj.resultSheet);
             this._rebuildStageSelect();
         },
+        _getStageSelectHtml: function (valid) {
+            const html = [];
+            for (let i = 1; i <= valid; i++) {
+                html.push(`<option value="${i}">第${i}期</option>`);
+            }
+            return html.join('');
+        },
+        refreshStageGather: function() {
+            if (setting.type !== 'gather' || setting.dataType !== 'stage') return;
+
+            const minStage = _.min(_.map(this.trArray, 'stageCount'));
+            $('#gather-stage').html(this._getStageSelectHtml(minStage));
+
+            const maxStage = _.max(_.map(this.trArray, 'stageCount'));
+            $('#gather-stage-begin').html(this._getStageSelectHtml(maxStage));
+            $('#gather-stage-end').html(this._getStageSelectHtml(maxStage));
+        },
         tsButtonClicked: function (e, info) {
             if (!info.sheet.zh_setting) return;
 
@@ -106,6 +121,7 @@ const TenderSelectMulti = function (setting) {
                 }
                 SpreadJsObj.reLoadRowData(info.sheet, info.row, 1);
             }
+            tsObj.refreshStageGather();
             tsObj.reloadResultData();
         },
         trEditEnded: function (e, info) {

+ 13 - 3
app/public/js/shares/tenders2tree.js

@@ -17,7 +17,7 @@ const Tender2Tree = (function () {
         rootId: -1,
         fullPath: 'full_path',
     };
-    const tenderTree = createNewPathTree('gather', treeSetting);
+    let tenderTree;
 
     // 查询方法
     function findNode (key, value, arr) {
@@ -73,11 +73,21 @@ const Tender2Tree = (function () {
         return tenderCategory;
     }
 
-    function convert (category, tenders, ledgerAuditConst, stageAuditConst, loadFun) {
+    function convert (category, tenders, ledgerAuditConst, stageAuditConst, loadFun, selfLevel = '', force = false) {
+        tenderTree = createNewPathTree('gather', treeSetting);
         tenderTree.clearDatas();
 
+        let selfLevelSort = selfLevel ? selfLevel.split(',') : [];
+        selfLevelSort = selfLevelSort.filter(x => {
+            return category.find(c => { return c.id + '' === x; });
+        });
+        category.forEach(cate => {
+            cate.is_self = force || selfLevelSort.length > 0;
+            cate.self_level = selfLevelSort.indexOf(cate.id + '') + 1;
+            cate.show_level = cate.is_self ? cate.self_level : cate.level;
+        });
         const levelCategory = category.filter(function (c) {
-            return c.level && c.level > 0;
+            return  c.show_level && c.show_level > 0; // c.level && c.level > 0;
         });
 
         for (const t of tenders) {

+ 40 - 2
app/public/js/shares/tools_att.js

@@ -25,7 +25,8 @@
             '        <li class="nav-item ml-auto pt-1">\n' +
             '            <a href="javascript:void(0);" id="batch-download" class="btn btn-sm btn-primary" type="curr">批量下载</a>\n' +
             '            <span id="showPage" style="display: none"><a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="att-cur-page">1</span>/<span id="att-total-page">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a></span>\n' +
-            (setting.readOnly ? '' : '            <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>\n') +
+            (setting.readOnly ? '' : '            <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-2">上传</a>\n') +
+            (setting.readOnly || !setting.bigValid ? '' : '            <a href="#add-big-file" data-toggle="modal" data-target="#add-big-file"  class="btn btn-sm btn-outline-primary ml-2">上传大文件</a>\n') +
             '        </li>\n' +
             '    </ul>\n' +
             '</div>\n' +
@@ -204,7 +205,7 @@
                     return false;
                 }
                 const filesize = file.size;
-                if (filesize > 30 * 1024 * 1024) {
+                if (filesize > 50 * 1024 * 1024) {
                     toastr.error('存在上传文件大小过大!');
                     return false;
                 }
@@ -233,6 +234,43 @@
             });
             $('#upload-file').val('');
         });
+        $('#add-big-file').on('show.bs.modal', function() {
+            $('#upload-big-file-hint').hide();
+            $('#upload-big-file')[0].value = '';
+            if ($('#add-big-file-ok').hasClass('btn-warning')) $('#add-big-file-ok').removeClass('btn-warning').addClass('btn-primary');
+        });
+        $('#add-big-file-ok').click(() => {
+            if (!curNode) {
+                toastr.error('请先选择台账节点');
+                return false;
+            }
+            const input = $('#upload-big-file');
+            const file = input[0].files[0];
+            if (file.size > 500 * 1024 * 1024) {
+                toastr.error('上传文件大小超过500MB。');
+                return false;
+            }
+            const fileext = '.' + file.name.toLowerCase().split('.').splice(-1)[0];
+            if (whiteList.indexOf(fileext) === -1) {
+                toastr.error('仅支持office文档、图片、压缩包格式,请勿上传' + fileext + '格式文件。');
+                return false;
+            }
+            const data = {};
+            data[setting.masterKey] = curNode[setting.key];
+            AliOss.uploadBigFile(file, setting.uploadBigUrl, data,
+                { progressObj: $('#upload-big-file-progress'), resumeObj: $('#add-big-file-resume'), stopObj: $('#add-big-file-stop') },
+                function(result) {
+                    result.forEach(d => {
+                        d.node = curNode;
+                        allAtts.push(d);
+                        _addToNodeIndex(d, true);
+                    });
+                    refreshAllAttHtml();
+                    refreshCurAttHtml();
+                    $('#upload-big-file').val('');
+                    $('#add-big-file').modal('hide');
+                });
+        });
         $('body').on('click', 'a[name=att-locate]', function () {
             const fid = this.getAttribute('file-id');
             const att = findFile(allAtts, fid);

+ 3 - 2
app/public/js/shenpi.js

@@ -886,12 +886,13 @@ $(document).ready(function () {
             this._refreshAssTree();
         }
         initLedgerTree(uid) {
-            if (this.loaded) return;
+            if (this.loaded && this.tid && this.tid === cur_tenderid) return;
             this.spread.refresh();
             const self = this;
 
             postData('/tender/' + cur_tenderid + '/shenpi/ass/load', {}, function (data) {
                 self.loaded = true;
+                self.tid = cur_tenderid;
                 self.assList = data.auditAssList;
                 self.tree.loadDatas(data.ledgerList);
                 SpreadJsObj.loadSheetData(self.sheet, SpreadJsObj.DataType.Tree, self.tree);
@@ -1014,7 +1015,7 @@ $(document).ready(function () {
             });
 
             $('#union').on('shown.bs.modal', function() {
-               self.spread.refresh();
+                self.spread.refresh();
             });
             $('#union-ok').click(function() {
                 const data = self.getUnionAuditLedgerData();

+ 2 - 0
app/public/js/sp_progress.js

@@ -496,9 +496,11 @@ $(document).ready(() => {
         masterKey: 'rela_id',
         uploadUrl: 'progress/file/upload',
         deleteUrl: 'progress/file/delete',
+        uploadBigUrl: 'progress/file/upload/big',
         checked: false,
         zipName: `阶段进度-附件.zip`,
         readOnly: readOnly,
+        bigValid: true,
         fileIdType: 'string',
         fileInfo: {
             user_name: 'user_name',

+ 21 - 1
app/public/js/sp_setting_permission.js

@@ -2,18 +2,32 @@ $(document).ready(() => {
     autoFlashHeight();
     // 选择账号
     const refreshUnitUsersHtml = function () {
+        const keyword = $('#sb-keyword').val();
         const select = $('#sel-batch-unit').val();
         const selectGroup = accountGroup.find(x => { return x.name === select; });
         const html = [];
         if (selectGroup) {
-            for (const u of selectGroup.groupList) {
+            const filter = keyword ? selectGroup.groupList.filter(x => {
+                return x.role.indexOf(keyword) >= 0 || x.name.indexOf(keyword) >= 0;
+            }) : selectGroup.groupList;
+            for (const u of filter) {
                 html.push(`<tr class="text-center">`);
                 html.push(`<td><input type="checkbox" name="sel-batch-check" id="${u.id}" unit="${selectGroup.name}" ${(u.select ? 'checked' : '')} ${u.sp_exist ? 'disabled' : ''}></td>`);
                 html.push(`<td>${u.name}</td>`);
                 html.push(`<td>${u.role}</td>`);
+                html.push(`<td>${u.company}</td>`);
                 html.push('<tr>');
             }
         }
+        const noCompanyAccount = accountList.filter(x => { return !x.company; });
+        for (const u of noCompanyAccount) {
+            html.push(`<tr class="text-center table-secondary">`);
+            html.push(`<td><input type="checkbox" name="sel-batch-check" id="${u.id}" unit="${selectGroup.name}" ${(u.select ? 'checked' : '')} disabled></td>`);
+            html.push(`<td>${u.name}</td>`);
+            html.push(`<td>${u.role}</td>`);
+            html.push(`<td>${u.company}</td>`);
+            html.push('<tr>');
+        }
         $('#sel-batch-users').html(html.join(''));
     };
     $('#sel-batch').on('show.bs.modal', function() {
@@ -25,6 +39,12 @@ $(document).ready(() => {
     $('#sel-batch-unit').change(function() {
         refreshUnitUsersHtml();
     });
+    $('#sb-search').click(function() {
+        refreshUnitUsersHtml();
+    });
+    $('#sb-keyword').change(function() {
+        refreshUnitUsersHtml();
+    });
     $('body').on('click', '[name=sel-batch-check]', function() {
         const select = $('#sel-batch-unit').val();
         const selectGroup = accountGroup.find(x => { return x.name === select; });

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

@@ -163,7 +163,7 @@ $(document).ready(() => {
         },
         rebuildSpreadSetting(tenders) {
             if(tenders.length > 0) {
-                if (tenders[0].filter.indexOf('~') > 0) {
+                if (tenders[0].stage_filter.indexOf('~') > 0) {
                     $('[datatype=end]').hide();
                 } else {
                     $('[datatype=end]').show();
@@ -174,13 +174,13 @@ $(document).ready(() => {
             for (const [i, tender] of tenders.entries()) {
                 for (const col of billsSpreadSetting.extraCols) {
                     const newCol = JSON.parse(JSON.stringify(col));
-                    if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.filter);
+                    if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.stage_filter);
                     if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
                     billsSpreadSetting.cols.push(newCol);
                 }
                 for (const col of posSpreadSetting.extraCols) {
                     const newCol = JSON.parse(JSON.stringify(col));
-                    if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.filter);
+                    if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.stage_filter);
                     if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
                     posSpreadSetting.cols.push(newCol)
                 }

+ 43 - 33
app/public/js/spss_gather_stage_extra.js

@@ -68,11 +68,11 @@ $(document).ready(() => {
         },
         bonus: {
             cols: [
-                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@'},
-                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@', cellType: 'tree'},
+                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter_str', hAlign: 1, width: 100, formatter: '@'},
                 {title: '类型', colSpan: '1', rowSpan: '1', field: 'b_type', hAlign: 1, width: 80, formatter: '@'},
-                {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
-                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 80, formatter: '@'},
+                {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 80},
+                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 100, formatter: 'yyyy-MM-dd'},
             ],
             emptyRows: 0,
             headRows: 1,
@@ -113,14 +113,14 @@ $(document).ready(() => {
         },
         tempLand: {
             cols: [
-                {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 320, formatter: '@'},
-                {title: '汇总', colSpan: '1', rowSpan: '2', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 320, formatter: '@', cellType: 'tree'},
+                {title: '汇总', colSpan: '1', rowSpan: '2', field: 'filter_str', hAlign: 1, width: 100, formatter: '@'},
                 {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 80, formatter: '@'},
                 {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
-                {title: '本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty', hAlign: 1, width: 80, formatter: '@'},
-                {title: '|数量', colSpan: '|1', rowSpan: '|1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
-                {title: '截止本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qty', hAlign: 1, width: 80, formatter: '@'},
-                {title: '|数量', colSpan: '|1', rowSpan: '|1', field: 'end_tp', hAlign: 1, width: 80, formatter: '@'},
+                {title: '本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty', hAlign: 2, width: 80, formatter: '@'},
+                {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'tp', hAlign: 2, width: 80, formatter: '@'},
+                {title: '截止本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qty', hAlign: 2, width: 80, formatter: '@'},
+                {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_tp', hAlign: 2, width: 80, formatter: '@'},
             ],
             emptyRows: 0,
             headRows: 2,
@@ -132,13 +132,13 @@ $(document).ready(() => {
         },
         other: {
             cols: [
-                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@'},
-                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@', cellType: 'tree'},
+                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter_str', hAlign: 1, width: 100, formatter: '@'},
                 {title: '类型', colSpan: '1', rowSpan: '1', field: 'o_type', hAlign: 1, width: 80, formatter: '@'},
-                {title: '金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 1, width: 80, formatter: '@'},
-                {title: '本期', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
-                {title: '截止本期', colSpan: '1', rowSpan: '1', field: 'end_tp', hAlign: 1, width: 80, formatter: '@'},
-                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 80, formatter: '@'},
+                {title: '金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 80},
+                {title: '本期', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 80},
+                {title: '截止本期', colSpan: '1', rowSpan: '1', field: 'end_tp', hAlign: 2, width: 80},
+                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 100, formatter: 'yyyy-MM-dd'},
             ],
             emptyRows: 0,
             headRows: 1,
@@ -157,10 +157,10 @@ $(document).ready(() => {
         seData: 'cur',
         jgcl: [],
         yjcl: [],
-        bonus: [],
-        other: [],
+        bonus: createNewPathTree('gather', {id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, fullPath: 'full_path'}),
+        other: createNewPathTree('gather', {id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, fullPath: 'full_path'}),
         safeProd: [],
-        tempLand: [],
+        tempLand: createNewPathTree('gather', {id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, fullPath: 'full_path'}),
         gatherJgcl(tenders) {
             this.jgcl = [];
             for (const [i, t] of tenders.entries()) {
@@ -223,18 +223,24 @@ $(document).ready(() => {
             }
         },
         gatherBonus(tenders) {
-            this.bonus = [];
+            this.bonus.clearDatas();
             for (const [i, t] of tenders.entries()) {
-                this.bonus.push({ tid: t.id, name: t.name, filter: t.filter });
-                this.bonus.push(...t.bonus);
+                const tenderNode = this.bonus.addNode({ tid: t.id, name: t.name, filter_str: t.filter });
+                for (const b of t.bonus) {
+                    this.bonus.addNode(b, tenderNode);
+                }
             }
+            this.bonus.sortTreeNode(true);
         },
         gatherOther(tenders) {
-            this.other = [];
+            this.other.clearDatas();
             for (const [i, t] of tenders.entries()) {
-                this.other.push({ tid: t.id, name: t.name, filter: t.filter });
-                this.other.push(...t.other);
+                const tenderNode = this.other.addNode({ tid: t.id, name: t.name, filter_str: t.stage_filter });
+                for (const o of t.other) {
+                    this.other.addNode(o, tenderNode);
+                }
             }
+            this.other.sortTreeNode(true);
         },
         gatherSafeProd(tenders) {
             this.safeProd = [];
@@ -265,10 +271,12 @@ $(document).ready(() => {
             }
         },
         gatherTempLand(tenders) {
-            this.tempLand = [];
+            this.tempLand.clearDatas();
             for (const [i, t] of tenders.entries()) {
-                this.tempLand.push({ tid: t.id, name: t.name, filter: t.filter });
-                this.tempLand.push(...t.tempLand);
+                const tenderNode = this.tempLand.addNode({ tid: t.id, name: t.name, filter_str: t.filter });
+                for (const tl of t.tempLand) {
+                    this.tempLand.addNode(tl, tenderNode);
+                }
                 // const endfix = '_' + (i + 1);
                 // for (const data of t.tempLand) {
                 //     if (!data.unit) data.unit = '';
@@ -293,6 +301,7 @@ $(document).ready(() => {
                 //     tl['sum_end_tp'] = ZhCalc.add(tl['sum_end_tp'], data.end_tp);
                 // }
             }
+            this.tempLand.sortTreeNode(true);
         },
         gatherStageExtraData(tenders) {
             this.tenderCount = tenders.length;
@@ -311,7 +320,7 @@ $(document).ready(() => {
                 for (const [i, tender] of tenders.entries()) {
                     for (const col of spreadSetting.extraCols) {
                         const newCol = JSON.parse(JSON.stringify(col));
-                        if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.filter);
+                        if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.stage_filter);
                         if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
                         spreadSetting.cols.push(newCol);
                     }
@@ -380,7 +389,8 @@ $(document).ready(() => {
         },
         loadSheetData() {
             SpreadJsObj.initSheet(dataSheet, spreadSetting[this.seType]);
-            SpreadJsObj.loadSheetData(dataSheet, SpreadJsObj.DataType.Data, this[this.seType]);
+            const isTree = spreadSetting[this.seType].cols.find(x => { return x.cellType === 'tree'; });
+            SpreadJsObj.loadSheetData(dataSheet, isTree ? SpreadJsObj.DataType.Tree : SpreadJsObj.DataType.Data, this[this.seType]);
             SpreadJsObj.locateRow(dataSheet, 0);
         },
         refreshStageExtraData(type) {
@@ -423,10 +433,10 @@ $(document).ready(() => {
         const sheets = [];
         sheets.push({ name: '甲供材料', setting: spreadSetting.jgcl, data: stageExtra.jgcl });
         sheets.push({ name: '永久材料', setting: spreadSetting.yjcl, data: stageExtra.yjcl });
-        sheets.push({ name: '奖罚金', setting: spreadSetting.bonus, data: stageExtra.bonus });
+        sheets.push({ name: '奖罚金', setting: spreadSetting.bonus, data: stageExtra.bonus.nodes });
         sheets.push({ name: '安全生产', setting: spreadSetting.safeProd, data: stageExtra.safeProd });
-        sheets.push({ name: '临时占地', setting: spreadSetting.tempLand, data: stageExtra.tempLand });
-        sheets.push({ name: '其他', setting: spreadSetting.other, data: stageExtra.other });
+        sheets.push({ name: '临时占地', setting: spreadSetting.tempLand, data: stageExtra.tempLand.nodes });
+        sheets.push({ name: '其他', setting: spreadSetting.other, data: stageExtra.other.nodes });
         SpreadExcelObj.exportSimpleXlsxSheets(sheets, "计量汇总-其他台账.xlsx");
     });
     $.subMenu({

+ 311 - 0
app/public/js/spss_gather_stage_info.js

@@ -0,0 +1,311 @@
+$(document).ready(() => {
+    autoFlashHeight();
+    const infoSpreadSetting = {
+        cols: [
+            {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 235, formatter: '@', cellType: 'tree'},
+            {title: '计量模式', colSpan: '1', rowSpan: '1', field: 'measure_type_str', hAlign: 1, width: 80, formatter: '@'},
+            {title: '标段状态', colSpan: '1', rowSpan: '1', field: 'progress_str', hAlign: 1, width: 110, formatter: '@'},
+            {title: '汇总', colSpan: '1', rowSpan: '1', field: 'stage_filter', hAlign: 1, width: 100, formatter: '@'},
+            {title: '签约合同价', colSpan: '1', rowSpan: '1', field: 'contract_price', hAlign: 2, width: 80, type: 'Number'},
+            {title: '0号台账', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 80, type: 'Number'},
+            {title: '本期合同', colSpan: '1', rowSpan: '1', field: 'contract_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '本期变更', colSpan: '1', rowSpan: '1', field: 'qc_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '本期完成', colSpan: '1', rowSpan: '1', field: 'gather_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '截止本期合同', colSpan: '1', rowSpan: '1', field: 'end_contract_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '截止本期变更', colSpan: '1', rowSpan: '1', field: 'end_qc_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '截止本期完成', colSpan: '1', rowSpan: '1', field: 'end_gather_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '本期应付', colSpan: '1', rowSpan: '1', field: 'yf_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '截止本期应付', colSpan: '1', rowSpan: '1', field: 'end_yf_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '本期实付', colSpan: '1', rowSpan: '1', field: 'sf_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '截止本期实付', colSpan: '1', rowSpan: '1', field: 'end_sf_tp', hAlign: 2, width: 80, type: 'Number'},
+        ],
+        emptyRows: 0,
+        headRows: 1,
+        headRowHeight: [32],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+    };
+
+    const infoSpread = SpreadJsObj.createNewSpread($('#info-spread')[0]);
+    const infoSheet = infoSpread.getActiveSheet();
+    SpreadJsObj.initSheet(infoSheet, infoSpreadSetting);
+    let infoTree;
+
+    const infoObj = {
+        tenders: [],
+        rebuildInfoTree: function(categoryLevel) {
+            infoTree = Tender2Tree.convert(category, this.tenders, null, null, function(node, tender) {
+                node.measure_type_str = tender.info.measure_type_str;
+                node.progress = tender.info.progress;
+                node.progress_str = `${node.progress.title}(${node.progress.status})`;
+                node.stage_filter = tender.stage_filter;
+                node.contract_price = tender.info.contract_price;
+                node.total_price = tender.total_price;
+                node.contract_tp = tender.info.contract_tp;
+                node.qc_tp = tender.info.qc_tp;
+                node.gather_tp = tender.info.gather_tp;
+                node.end_contract_tp = tender.info.end_contract_tp;
+                node.end_qc_tp = tender.info.end_qc_tp;
+                node.end_gather_tp = tender.info.end_gather_tp;
+                node.yf_tp = tender.info.yf_tp;
+                node.end_yf_tp = tender.info.end_yf_tp;
+                node.sf_tp = tender.info.sf_tp;
+                node.end_sf_tp = tender.info.end_sf_tp;
+            }, categoryLevel, true);
+        },
+        refreshInfoTree: function(categoryLevel) {
+            this.rebuildInfoTree(categoryLevel);
+            SpreadJsObj.loadSheetData(infoSheet, SpreadJsObj.DataType.Tree, infoTree, true);
+        },
+        loadTenders: function(tenders) {
+            this.tenders = tenders;
+            const categoryLevel = infoCate.getCategoryLevel();
+            this.refreshInfoTree(categoryLevel);
+        }
+    };
+
+    const tenderSelect = TenderSelectMulti({
+        title: '汇总标段',
+        type: 'gather',
+        dataType: 'stage',
+        afterSelect: function(select) {
+            const data = { filter: 'info', tender: select };
+            postData(`/sp/${spid}/spss/load`, data, function(result) {
+                infoObj.loadTenders(result);
+            });
+        },
+    });
+    $('#gather-select').click(tenderSelect.showSelect);
+
+    $('#export-excel').click(function() {
+        if (!infoTree || infoTree.nodes.length === 0) {
+            toastr.warning('无可导出数据');
+            return;
+        }
+        SpreadExcelObj.exportSimpleXlsxSheet(infoSpreadSetting, infoTree.nodes, "计量汇总-其他台账.xlsx");
+    });
+    // 显示层次
+    (function (select, sheet) {
+        $(select).click(function () {
+            if (!sheet.zh_tree) return;
+            const tag = $(this).attr('tag');
+            const tree = sheet.zh_tree;
+            switch (tag) {
+                case "1":
+                case "2":
+                    tree.expandByLevel(parseInt(tag));
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+                    break;
+                case "last":
+                    tree.expandByCustom(() => { return true; });
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+                    break;
+            }
+        });
+    })('a[name=showLevel]', infoSheet);
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+                $('.c-body table thead').css('left', '56px');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+                $('.c-body table thead').css('left', '176px');
+            }
+            autoFlashHeight();
+            infoSpread.refresh();
+        }
+    });
+
+    const infoCate = (function(setting) {
+        const levelTreeSetting = {
+            view: {
+                selectedMulti: false
+            },
+            data: {
+                simpleData: {
+                    idKey: 'lid',
+                    pIdKey: 'lpId',
+                    rootPId: 0,
+                    enable: true,
+                }
+            },
+            edit: {
+                enable: true,
+                showRemoveBtn: false,
+                showRenameBtn: false,
+                drag: {
+                    autoExpandTrigger: true,
+                    isCopy: false,
+                    isMove:  true,
+                    prev: false,
+                    next: false,
+                    inner: true,
+                }
+            },
+            callback: {
+                beforeDrop: function (treeId, treeNodes, targetNode, moveType, isCopy) {
+                    if (targetNode !== null && targetNode.lid !== 1) {
+                        const parent = targetNode.getParentNode();
+                        if (parent && parent.lid === 1) {
+                            return false;
+                        }
+                    }
+                    for (var i=0,l=treeNodes.length; i<l; i++) {
+                        if (treeNodes[i].drag === false) {
+                            return false;
+                        }
+                        if (!targetNode && treeNodes[i].dropRoot === false) {
+                            return false;
+                        }
+                        if(treeNodes[i].isParent === true && targetNode.lid !== 1){
+                            return false;
+                        }
+                    }
+                    return true;
+                },
+                onDrop: function onDropNode(event, treeId, treeNodes, targetNode, moveType) {
+                    const zTree = $.fn.zTree.getZTreeObj(treeId);
+                    function resetFixNode(id) {
+                        const node = zTree.getNodeByParam('lid', id);
+                        node.isParent = true;
+                        zTree.updateNode(node, false);
+                        zTree.expandNode(node, true);
+                    }
+                    function moveChildren(children, node) {
+                        if (!children || children.length === 0) { return }
+                        for (const c of children) {
+                            moveChildren(c.children, node);
+                            zTree.moveNode(node, c, 'inner');
+                        }
+                    }
+                    resetFixNode(1);
+                    resetFixNode(2);
+                    if (targetNode !== null && targetNode.lid === 1 && treeNodes[0].children && treeNodes[0].children.length !== 0) {
+                        moveChildren(treeNodes[0].children, zTree.getNodeByParam('lid', 1));
+                    } else if (targetNode !== null && targetNode.lid !== 1) {
+                        if (targetNode.children.length >= 2) {
+                            for (const c of targetNode.children) {
+                                if (c.lid !== treeNodes[0].lid) {
+                                    zTree.moveNode(treeNodes[0], c, 'inner');
+                                }
+                            }
+                        }
+                    }
+                },
+            }
+        };
+        const levelNodes =[];
+        const default_category_level = setting.defaultCategoryLevel;
+        let selfLevelSort;
+        function createTree(key) {
+            const zTree = $.fn.zTree.getZTreeObj(key);
+            if (zTree) zTree.destroy();
+            $.fn.zTree.init($(`#${key}`), levelTreeSetting, levelNodes);
+        }
+        function findNode (key, value, arr) {
+            for (const a of arr) {
+                if (a[key] && a[key] === value) {
+                    return a;
+                }
+            }
+        }
+        function getPId(level) {
+            if (level !== 1) {
+                const p = findNode('show_level', level - 1, levelNodes);
+                if (p) {
+                    return p.lid
+                } else {
+                    return 1;
+                }
+            } else {
+                return 2;
+            }
+        }
+        function loadSelfCategoryLevel(selfLevel, force = false){
+            selfLevelSort = selfLevel ? selfLevel.split(',') : [];
+            selfLevelSort = selfLevelSort.filter(x => {
+                return category.find(c => { return c.id + '' === x; });
+            });
+            category.forEach(cate => {
+                cate.is_self = force || selfLevelSort.length > 0;
+                cate.self_level = selfLevelSort.indexOf(cate.id + '') + 1;
+            });
+        }
+        function sortCategory() {
+            category.forEach(cate => {
+                cate.show_level = cate.is_self ? cate.self_level : cate.level;
+            });
+            category.sort(function (a, b) {
+                return a.show_level ? (b.show_level ? a.show_level - b.show_level : -1) : a.id - b.id;
+            });
+        }
+        function initCategoryLevelNode() {
+            levelNodes.length = 0;
+            levelNodes.push(
+                { lid:1, lpId:0, name:"可用类别", open:true, isParent: true, drag: false},
+                { lid:2, lpId:0, name:"已用类别", open:true, isParent: true, drag: false}
+            );
+            for (const c of category) {
+                const cate = JSON.parse(JSON.stringify(c));
+                cate.lid = levelNodes.length + 1;
+                cate.open = true;
+                cate.dropRoot = false;
+                if (!cate.show_level) {
+                    cate.lpId = 1;
+                    levelNodes.push(cate);
+                } else {
+                    cate.lpId = getPId(cate.show_level);
+                    levelNodes.push(cate);
+                }
+            }
+        }
+        const setSelfCategoryLevel = function(level, force) {
+            loadSelfCategoryLevel(level, force);
+            sortCategory();
+            initCategoryLevelNode();
+        };
+        setSelfCategoryLevel(default_category_level);
+        createTree('treeLevel-info');
+        const getCategoryLevel = function () {
+            const zTree = $.fn.zTree.getZTreeObj('treeLevel-info');
+            const selfLevel = [];
+            for (const c of category) {
+                const node = zTree.getNodeByParam('id', c.id);
+                const parent = node.getParentNode();
+                if (parent.lid != 1) {
+                    selfLevel.push({id: c.id, level: node.getPath().length - 1});
+                }
+            }
+            const selfLevelStr = selfLevel.sort((x, y) => { return x.level - y.level; }).map(x => {return x.id; }).join(',');
+            return selfLevelStr;
+        };
+        $('#info-cate-ok').click(function () {
+            const categoryLevel = getCategoryLevel();
+            setSelfCategoryLevel(categoryLevel, true);
+            setting.afterCate(categoryLevel);
+            $('#info-cate').modal('hide');
+        });
+        $('#info-cate').on('show.bs.modal', function () {
+            createTree('treeLevel-info');
+        });
+        $('#info-cate-reset').click(function () {
+            setSelfCategoryLevel(default_category_level);
+            createTree('treeLevel-info');
+        });
+        return { getCategoryLevel }
+    })({
+        afterCate: function(gatherCate) {
+            infoObj.refreshInfoTree(gatherCate);
+        },
+        defaultCategoryLevel: selfCategoryLevel,
+    });
+});

+ 14 - 4
app/public/js/sr_detail.js

@@ -215,6 +215,7 @@ $(document).ready(() => {
 
     // 初始化 台账 spread
     const slSpread = SpreadJsObj.createNewSpread($('#stage-ledger')[0]);
+    const slSheet = slSpread.getActiveSheet();
     customizeStageTreeSetting(ledgerSpreadSetting, customColDisplay());
     const ratioCol = ledgerSpreadSetting.cols.find(x => {return x.field === 'end_final_1_percent' || x.field === 'end_correct_1_percent'});
     if (ratioCol) ratioCol.field = tenderInfo.display.stage.correct ? 'end_correct_1_percent' : 'end_final_1_percent';
@@ -288,6 +289,7 @@ $(document).ready(() => {
 
     // 初始化 计量单元 Spread
     const spSpread = SpreadJsObj.createNewSpread($('#stage-pos')[0]);
+    const spSheet = spSpread.getActiveSheet();
     const spCol = _.find(posSpreadSetting.cols, {field: 'qc_qty'});
     spCol.cellType = 'activeImageBtn';
     spCol.normalImg = '#ellipsis-icon';
@@ -843,7 +845,7 @@ $(document).ready(() => {
                         return false;
                     }
                     const filesize = file.size;
-                    if (filesize > 30 * 1024 * 1024) {
+                    if (filesize > 50 * 1024 * 1024) {
                         toast('存在上传文件大小过大!', 'error');
                         return false;
                     }
@@ -1057,9 +1059,9 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
-                searchLedger = $.billsSearch({
+                searchLedger = $.ledgerSearch({
                     selector: '#search',
-                    searchSpread: slSpread,
+                    ledger: { billsTree: stageTree, pos: stagePos },
                     searchOver: true,
                     searchEmpty: true,
                     resultSpreadSetting: {
@@ -1082,8 +1084,16 @@ $(document).ready(() => {
                         font: '12px 微软雅黑',
                         selectedBackColor: '#fffacd',
                     },
-                    afterLocated: function () {
+                    locate: function(cur) {
+                        if (!cur.lid) return;
+
+                        SpreadJsObj.locateTreeNode(slSheet, cur.lid, true);
                         stagePosSpreadObj.loadCurPosData();
+                        // stageTreeSpreadObj.loadRelaData();
+                        if (cur.pid && cur.pid !== -1) {
+                            const pIndex = spSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                            SpreadJsObj.locateRow(spSheet, pIndex);
+                        }
                     },
                     customSearch: [
                         {

+ 41 - 23
app/public/js/stage.js

@@ -359,6 +359,7 @@ $(document).ready(() => {
         pos.end_gather_qty = ZhCalc.add(pos.pre_gather_qty, pos.gather_qty);
         pos.sum = ZhCalc.add(pos.end_qc_qty, pos.quantity);
         pos.end_gather_percent = ZhCalc.mul(ZhCalc.div(pos.end_gather_qty, pos.sum), 100, 2);
+        pos.end_contract_percent = ZhCalc.mul(ZhCalc.div(pos.end_contract_qty, pos.quantity), 100, 2);
         pos.estimate_qty = !checkZero(pos.real_qty)
             ? ZhCalc.sub(ZhCalc.sub(pos.real_qty, pos.quantity), pos.end_qc_qty)
             : null;
@@ -733,6 +734,7 @@ $(document).ready(() => {
 
     // 初始化 台账 spread
     const slSpread = SpreadJsObj.createNewSpread($('#stage-ledger')[0]);
+    const slSheet = slSpread.getActiveSheet();
     customizeStageTreeSetting(ledgerSpreadSetting, customColDisplay());
     // 数量变更列,添加按钮
     const qcColShowImage = function (data) {
@@ -841,6 +843,7 @@ $(document).ready(() => {
 
     // 初始化 计量单元 Spread
     const spSpread = SpreadJsObj.createNewSpread($('#stage-pos')[0]);
+    const spSheet = spSpread.getActiveSheet();
     const posQcColShowImage = function (data) {
         return data !== undefined && data !== null;
     };
@@ -1474,7 +1477,15 @@ $(document).ready(() => {
             });
         },
         exportExcel: function (filename, nodes, withPos = true) {
-            const exportNodesData = function (data, nodes) {
+            stageTree.recursiveExe(function(node) {
+                if (node.children && node.children.length > 0) {
+                    node._export_group = _.sum(node.children.map(x => { return x._export_group; })) + node.children.length;
+                } else {
+                    const posRange = stagePos.getLedgerPos(node.id);
+                    node._export_group = posRange ? posRange.length : 0;
+                }
+            });
+            const exportNodesData = function (data, nodes, groupData) {
                 for (const node of nodes) {
                     data.push({
                         code: node.code, b_code: node.b_code, name: node.name, unit: node.unit,
@@ -1492,28 +1503,28 @@ $(document).ready(() => {
                         contract_expr_str: node.calc_expr ? TreeExprCalc.expr2ExprStr(node.calc_expr) : '',
                     });
                     if (node.children && node.children.length > 0) {
-                        exportNodesData(data, node.children);
+                        exportNodesData(data, node.children, groupData);
                     } else {
                         if (!withPos) continue;
                         const posRange = stagePos.getLedgerPos(node.id);
-                        if (posRange && posRange.length > 0) {
-                            for (const [i, p] of posRange.entries()) {
-                                data.push({
-                                    pos_code: (i + 1) + '', name: p.name,
-                                    quantity: p.quantity,
-                                    contract_qty: p.contract_qty, qc_qty: p.qc_qty, gather_qty: p.gather_qty,
-                                    end_contract_qty: p.end_contract_qty, end_qc_qty: p.end_qc_qty, end_gather_qty: p.end_gather_qty,
-                                    qc_minus_qty: p.qc_minus_qty, end_qc_minus_qty: p.end_qc_minus_qty,
-                                    drawing_code: p.drawing_code, memo: p.memo, postil: p.postil, position: p.position,
-                                });
-                            }
+                        if (!posRange || posRange.length === 0) continue;
+                        if (node._export_group) groupData.push({ code: node.code, b_code: node.b_code, start: data.length, count: node._export_group });
+                        for (const [i, p] of posRange.entries()) {
+                            data.push({
+                                pos_code: (i + 1) + '', name: p.name,
+                                quantity: p.quantity,
+                                contract_qty: p.contract_qty, qc_qty: p.qc_qty, gather_qty: p.gather_qty,
+                                end_contract_qty: p.end_contract_qty, end_qc_qty: p.end_qc_qty, end_gather_qty: p.end_gather_qty,
+                                qc_minus_qty: p.qc_minus_qty, end_qc_minus_qty: p.end_qc_minus_qty,
+                                drawing_code: p.drawing_code, memo: p.memo, postil: p.postil, position: p.position,
+                            });
                         }
                     }
                 }
             };
-            const data = [];
-            exportNodesData(data, nodes ? nodes : stageTree.children);
-            SpreadExcelObj.exportSimpleXlsxSheet(exportExcelSetting, data, filename);
+            const data = [], groupData = [];
+            exportNodesData(data, nodes ? nodes : stageTree.children, groupData);
+            SpreadExcelObj.exportSimpleXlsxSheet(exportExcelSetting, data, filename, groupData);
         }
     };
     slSpread.bind(spreadNS.Events.EditEnded, stageTreeSpreadObj.editEnded);
@@ -3336,7 +3347,7 @@ $(document).ready(() => {
                         return false;
                     }
                     const filesize = file.size;
-                    if (filesize > 30 * 1024 * 1024) {
+                    if (filesize > 50 * 1024 * 1024) {
                         toast('存在上传文件大小过大!', 'error');
                         return false;
                     }
@@ -4599,9 +4610,9 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#search' && !searchLedger) {
-                searchLedger = $.billsSearch({
+                searchLedger = $.ledgerSearch({
                     selector: '#search',
-                    searchSpread: slSpread,
+                    ledger: { billsTree: stageTree, pos: stagePos },
                     searchOver: true,
                     searchEmpty: true,
                     resultSpreadSetting: {
@@ -4625,8 +4636,15 @@ $(document).ready(() => {
                         selectedBackColor: '#fffacd',
                         readOnly: true,
                     },
-                    afterLocated: function () {
-                        stagePosSpreadObj.loadCurPosData();
+                    locate: function(cur) {
+                        if (!cur.lid) return;
+
+                        SpreadJsObj.locateTreeNode(slSheet, cur.lid, true);
+                        stageTreeSpreadObj.loadRelaData();
+                        if (cur.pid && cur.pid !== -1) {
+                            const pIndex = spSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                            SpreadJsObj.locateRow(spSheet, pIndex);
+                        }
                     },
                     customSearch: [
                         {
@@ -4738,7 +4756,7 @@ $(document).ready(() => {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toastr.error('存在上传文件大小过大!');
                 return false;
             }
@@ -4920,7 +4938,7 @@ $(document).ready(() => {
         const filename = name.substring(0, name.lastIndexOf("."));
         const fileext = name.substr(name.indexOf("."));
         const filesize = file.size;
-        if (filesize > 30 * 1024 * 1024) {
+        if (filesize > 50 * 1024 * 1024) {
             toastr.error('文件大小过大!');
             $('#change-att-btn').val('');
             return false;

+ 11 - 2
app/public/js/stage_compare.js

@@ -326,19 +326,28 @@ $(document).ready(function () {
     })('a[name=showLevel]', ledgerSpread.getActiveSheet());
 
     $('#exportExcel').click(function () {
-        const data = [];
+        const data = [], groupData = [];
         if (!ledgerSheet.zh_tree) return;
+        ledgerSheet.zh_tree.recursiveExe(function(node) {
+            if (node.children && node.children.length > 0) {
+                node._export_group = _.sum(node.children.map(x => { return x._export_group; })) + node.children.length;
+            } else {
+                const posRange = scPos.getLedgerPos(node.id);
+                node._export_group = posRange ? posRange.length : 0;
+            }
+        });
         for (const node of ledgerSheet.zh_tree.nodes) {
             data.push(node);
             const posRange = scPos.getLedgerPos(node.id);
             if (posRange && posRange.length > 0) {
+                if (node._export_group) groupData.push({ code: node.code, b_code: node.b_code, start: data.length, count: node._export_group });
                 for (const pr of posRange) {
                     data.push(pr);
                 }
             }
         }
 
-        SpreadExcelObj.exportSimpleXlsxSheet(ledgerSpreadSetting, data, $('.sidebar-title').attr('data-original-title') + "-审核比较.xlsx");
+        SpreadExcelObj.exportSimpleXlsxSheet(ledgerSpreadSetting, data, $('.sidebar-title').attr('data-original-title') + "-审核比较.xlsx", groupData);
     });
     $('[name=compareType]').click(function () {
         $('[name=compareType]').removeClass('active');

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

@@ -1284,7 +1284,7 @@ $(document).ready(() => {
                 return false;
             }
             const filesize = file.size;
-            if (filesize > 30 * 1024 * 1024) {
+            if (filesize > 50 * 1024 * 1024) {
                 toast('存在上传文件大小过大!', 'error');
                 return false;
             }

+ 2 - 2
app/public/js/sub_project.js

@@ -58,8 +58,8 @@ $(document).ready(function() {
                     }
                 }
                 // 操作
-                html.push(`<td>`);
                 if (canEdit) {
+                html.push(`<td>`);
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="edit">编辑</button>');
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="up"><i class="fa fa-arrow-up"></i></button>');
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="down"><i class="fa fa-arrow-down"></i></button>');
@@ -76,8 +76,8 @@ $(document).ready(function() {
                             html.push('<button class="btn btn-outline-danger btn-sm ml-1" name="del">删除</button>');
                         }
                     }
-                }
                 html.push('</td>');
+                }
                 return html.join('');
             },
             getNodeTrHtml: function (node, tree) {

+ 1 - 0
app/router.js

@@ -249,6 +249,7 @@ module.exports = app => {
     app.get('/sp/:id/progress', sessionAuth, subProjectCheck, 'subProjController.progress');
     app.post('/sp/:id/progress/update', sessionAuth, subProjectCheck, 'subProjController.progressUpdate');
     app.post('/sp/:id/progress/file/upload', sessionAuth, subProjectCheck, 'subProjController.uploadFile');
+    app.post('/sp/:id/progress/file/upload/big', sessionAuth, subProjectCheck, 'subProjController.uploadBigFile');
     app.post('/sp/:id/progress/file/delete', sessionAuth, subProjectCheck, 'subProjController.deleteFile');
     // 推进记录
     app.get('/sp/:id/push', sessionAuth, subProjectCheck, 'subProjController.push');

+ 11 - 8
app/service/advance_audit.js

@@ -70,7 +70,7 @@ module.exports = app => {
          * @param {Number} times - 第几次审批
          * @return {Boolean} 是否插入成功
          */
-        async addAuditor(tid, vid, audit_id, times = 1, is_gdzs = 0) {
+        async addAuditor(tid, vid, audit_id, times = 1, type, is_gdzs = 0) {
             const transaction = await this.db.beginTransaction();
             try {
                 let newOrder = await this.getNewOrder(vid, times);
@@ -80,6 +80,7 @@ module.exports = app => {
                 const record = {
                     tid,
                     vid,
+                    type,
                     audit_id,
                     times,
                     order: newOrder,
@@ -419,7 +420,7 @@ module.exports = app => {
             }
         }
 
-        async _checkNoPre(pid, advanceId, checkData, times) {
+        async _checkNoPre(pid, advanceId, checkData, times, type) {
             const time = new Date();
             // 整理当前流程审核人状态更新
             const audit = await this.getDataByCondition({ vid: advanceId, times, status: auditConst.status.checking });
@@ -453,6 +454,7 @@ module.exports = app => {
                 const newAuditors = {
                     tid: audit.tid,
                     vid: audit.vid,
+                    type,
                     audit_id: preAuditor.audit_id,
                     times: audit.times,
                     order: audit.order + 1,
@@ -463,6 +465,7 @@ module.exports = app => {
                 const uncheckNewAuditors = {
                     tid: audit.tid,
                     vid: audit.vid,
+                    type,
                     audit_id: audit.audit_id,
                     times: audit.times,
                     order: audit.order + 2,
@@ -509,7 +512,7 @@ module.exports = app => {
          * @param {Number} times - 第几次审批
          * @return {Promise<void>}
          */
-        async check(advanceId, checkData, times = 1) {
+        async check(advanceId, checkData, times = 1, type) {
             if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo && checkData.checkType !== auditConst.status.checkNoPre) {
                 throw '提交数据错误';
             }
@@ -522,7 +525,7 @@ module.exports = app => {
                     await this._checkNo(pid, advanceId, checkData, times);
                     break;
                 case auditConst.status.checkNoPre:
-                    await this._checkNoPre(pid, advanceId, checkData, times);
+                    await this._checkNoPre(pid, advanceId, checkData, times, type);
                     break;
                 default:
                     throw '无效审批操作';
@@ -550,7 +553,7 @@ module.exports = app => {
                 const checkAgainAuditors = [];
                 audits.forEach(x => {
                     checkAgainAuditors.push({
-                        tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: x.type,
+                        tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: advance.type,
                         times: x.times, order: maxOrder + 1,
                         status: auditConst.status.checkAgain,
                         create_time: time, end_time: time, opinion: '',
@@ -559,7 +562,7 @@ module.exports = app => {
                 const checkingAuditors = [];
                 audits.forEach(x => {
                     checkingAuditors.push({
-                        tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: x.type,
+                        tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: advance.type,
                         times: x.times, order: maxOrder + 2,
                         status: auditConst.status.checking,
                         create_time: time,
@@ -742,7 +745,7 @@ module.exports = app => {
                 let order = 1;
                 for (const aid of newIdList) {
                     newAuditors.push({
-                        tid: advance.tid, vid: advance.id, audit_id: aid,
+                        tid: advance.tid, vid: advance.id, type: advance.type, audit_id: aid,
                         times: advance.times, order, status: auditConst.status.uncheck,
                     });
                     order++;
@@ -771,7 +774,7 @@ module.exports = app => {
 
                 // 添加终审
                 const newAuditor = {
-                    tid: advance.tid, vid: advance.id, audit_id: lastId,
+                    tid: advance.tid, vid: advance.id, type: advance.type, audit_id: lastId,
                     times: advance.times, order, status: auditConst.status.uncheck,
                 };
                 await transaction.insert(this.tableName, newAuditor);

+ 4 - 1
app/service/change_apply_audit.js

@@ -1233,7 +1233,10 @@ module.exports = app => {
                 const auditors = await this.getAuditGroupByList(caId, times);
                 const now_audit = this._.find(auditors, { aid: data.old_aid });
                 if (data.operate !== 'del') {
-                    const exist = await this.getDataByCondition({ caid: caId, times, aid: data.new_aid });
+                    // const exist = await this.getDataByCondition({ caid: caId, times, aid: data.new_aid });
+                    // if (exist) throw '该审核人已存在,请勿重复添加';
+                    const groupAuditors = this._.flattenDeep(this.ctx.change.userGroups);
+                    const exist = this._.find(groupAuditors, { aid: data.new_aid });
                     if (exist) throw '该审核人已存在,请勿重复添加';
                 }
                 if (data.operate === 'add') {

+ 2 - 1
app/service/change_audit.js

@@ -1287,7 +1287,8 @@ module.exports = app => {
                 const auditors = await this.getAuditGroupByList(cid, times);
                 const now_audit = this._.find(auditors, { uid: data.old_aid });
                 if (data.operate !== 'del') {
-                    const exist = await this.getDataByCondition({ cid, times, uid: data.new_aid });
+                    const groupAuditors = this._.flattenDeep(this.ctx.change.userGroups);
+                    const exist = this._.find(groupAuditors, { uid: data.new_aid });
                     if (exist) throw '该审核人已存在,请勿重复添加';
                 }
                 if (data.operate === 'add') {

+ 4 - 1
app/service/change_plan_audit.js

@@ -1304,7 +1304,10 @@ module.exports = app => {
                 const auditors = await this.getAuditGroupByList(cpId, times);
                 const now_audit = this._.find(auditors, { aid: data.old_aid });
                 if (data.operate !== 'del') {
-                    const exist = await this.getDataByCondition({ cpid: cpId, times, aid: data.new_aid });
+                    // const exist = await this.getDataByCondition({ cpid: cpId, times, aid: data.new_aid });
+                    // if (exist) throw '该审核人已存在,请勿重复添加';
+                    const groupAuditors = this._.flattenDeep(this.ctx.change.userGroups);
+                    const exist = this._.find(groupAuditors, { aid: data.new_aid });
                     if (exist) throw '该审核人已存在,请勿重复添加';
                 }
                 if (data.operate === 'add') {

+ 4 - 1
app/service/change_project_audit.js

@@ -1369,7 +1369,10 @@ module.exports = app => {
                 const auditors = await this.getAuditGroupByList(cpId, times);
                 const now_audit = this._.find(auditors, { aid: data.old_aid });
                 if (data.operate !== 'del') {
-                    const exist = await this.getDataByCondition({ cpid: cpId, times, aid: data.new_aid });
+                    // const exist = await this.getDataByCondition({ cpid: cpId, times, aid: data.new_aid });
+                    // if (exist) throw '该审核人已存在,请勿重复添加';
+                    const groupAuditors = this._.flattenDeep(this.ctx.change.userGroups);
+                    const exist = this._.find(groupAuditors, { aid: data.new_aid });
                     if (exist) throw '该审核人已存在,请勿重复添加';
                 }
                 if (data.operate === 'add') {

+ 2 - 1
app/service/message.js

@@ -148,7 +148,8 @@ module.exports = app => {
          * @return {Boolean} - 返回修改结果
          */
         async getMsgList(projectId, spid = '', limit = 5, offset = 0, type = 1) {
-            const sqSql = spid ? ' AND (`spid` = "' + spid + '" OR `spid` = "")' : '';
+            const spids = spid ? (spid instanceof Array ? spid : [spid]) : '';
+            const sqSql = spids ? ' AND (`spid` in (' + this.ctx.helper.getInArrStrSqlFilter(spids) + ') OR `spid` = "")' : '';
             if (type === 1) {
                 const sql = 'SELECT * FROM ?? WHERE `project_id` = ?' + sqSql + ' AND `type` = ? ORDER BY CONCAT(`istop`,`release_time`) DESC LIMIT ?,?';
                 const sqlParam = [this.tableName, projectId, type, offset, limit];

+ 2 - 2
app/service/project_account.js

@@ -1081,7 +1081,7 @@ module.exports = app => {
             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.payment_permission
-                FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY pa.company ASC, spp.create_time DESC';
+                FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY pa.company ASC, spp.uid DESC';
             const result = await this.db.query(sql);
             return result;
         }
@@ -1094,7 +1094,7 @@ module.exports = app => {
             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.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 ?, ?';
+                FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY spp.uid DESC LIMIT ?, ?';
             const result = await this.db.query(sql, [offset, limit]);
             return result;
         }

+ 2 - 1
app/service/stage_audit.js

@@ -2105,7 +2105,8 @@ module.exports = app => {
                 const auditors = await this.getAuditGroupByList(stageId, times);
                 const now_audit = this._.find(auditors, { aid: data.old_aid });
                 if (data.operate !== 'del') {
-                    const exist = await this.getDataByCondition({ sid: stageId, times, aid: data.new_aid });
+                    const groupAuditors = this._.flattenDeep(this.ctx.stage.userGroups);
+                    const exist = this._.find(groupAuditors, { aid: data.new_aid });
                     if (exist) throw '该审核人已存在,请勿重复添加';
                 }
                 if (data.operate === 'add') {

+ 1 - 1
app/view/advance/modal_audit.ejs

@@ -26,7 +26,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <!-- <p><a href="javascript: void(0);" class="btn btn-primary" id="file-modal-target">选择文件</a></p> -->
                 <input type="file" id="file-modal" multiple="multiple">
             </div>

+ 1 - 1
app/view/change/apply_information_modal.ejs

@@ -10,7 +10,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="file-modal">单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</label>
+                    <label for="file-modal">单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</label>
                     <!-- <p><a href="javascript: void(0);" class="btn btn-primary" id="file-modal-target">选择文件</a></p> -->
                     <input type="file" id="file-modal" multiple="multiple">
                 </div>

+ 1 - 1
app/view/change/info_modal.ejs

@@ -920,7 +920,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <p><input value="选择文件" type="file" id="upload-file" multiple /></p>
             </div>
             <div class="modal-footer">

+ 7 - 7
app/view/change/information_modal.ejs

@@ -312,9 +312,9 @@
                                 <% } %>
                                 <div class="<%- idx < ctx.change.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                         <% his.forEach((group, index) => { %>
-                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                                 <% if (group.endYear) { %>
                                                     <div class="timeline-item-date">
                                                         <%- group.endYear %>
@@ -467,9 +467,9 @@
                                 <% } %>
                                 <div class="<%- idx < ctx.change.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                         <% his.forEach((group, index) => { %>
-                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                                 <% if (group.endYear) { %>
                                                     <div class="timeline-item-date">
                                                         <%- group.endYear %>
@@ -636,9 +636,9 @@
                                 <% } %>
                                 <div class="<%- idx < ctx.change.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.change.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                         <% his.forEach((group, index) => { %>
-                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1 && ctx.change.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                            <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.change.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                                 <% if (his.endYear) { %>
                                                     <div class="timeline-item-date">
                                                         <%- group.endYear %>
@@ -861,7 +861,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <p><input value="选择文件" type="file" id="upload-file" multiple /></p>
             </div>
             <div class="modal-footer">

+ 1 - 1
app/view/change/plan_information_modal.ejs

@@ -10,7 +10,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="file-modal">单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</label>
+                    <label for="file-modal">单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</label>
                     <!-- <p><a href="javascript: void(0);" class="btn btn-primary" id="file-modal-target">选择文件</a></p> -->
                     <input type="file" id="file-modal" multiple="multiple">
                 </div>

+ 1 - 1
app/view/change/project_information_modal.ejs

@@ -9,7 +9,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <!-- <p><a href="javascript: void(0);" class="btn btn-primary" id="file-modal-target">选择文件</a></p> -->
                 <input type="file" id="file-modal" multiple="multiple">
             </div>

+ 1 - 1
app/view/construction/info_modal.ejs

@@ -10,7 +10,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <p><input value="选择文件" type="file" id="upload-file" multiple /></p>
             </div>
             <div class="modal-footer">

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

@@ -201,7 +201,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group upload-permission">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <br>
                     <input type="file" class="" multiple>
                 </div>

+ 3 - 3
app/view/dashboard/msg_add.ejs

@@ -25,7 +25,7 @@
                                     <label>附件</label>
                                     <input type="hidden" value="<%= msgInfo.id === undefined ? 0 : msgInfo.id %>" id="mid">
                                     <div class="form-group upload-permission">
-                                        <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                                        <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                                         <br>
                                         <input type="file" class="" multiple>
                                     </div>
@@ -149,8 +149,8 @@
             return false
         }
         return files.every(file => {
-            if (file.size > 1024 * 1024 * 30) {
-                toastr.error('文件大小限制为30MB');
+            if (file.size > 1024 * 1024 * 50) {
+                toastr.error('文件大小限制为50MB');
                 return false
             }
             if (whiteList.indexOf('.' + file.ext.toLowerCase()) === -1) {

+ 20 - 2
app/view/dashboard/workspace.ejs

@@ -593,6 +593,7 @@
     })
 </script>
 <script type="text/javascript">
+    let _param = '';
     const option = {
         color: ['rgba(38, 217, 217,0.7)','rgba(78, 139, 229,0.7)','rgba(78, 229, 139,0.7)','rgba(108, 78, 229,0.7)','rgba(164, 229, 78,0.7)','rgba(199, 78, 229,0.7)','rgba(229, 92, 174,0.7)','rgba(229, 214, 78,0.7)','rgba(241, 87, 96,0.7)','rgba(242, 179, 82,0.7)'],
         //backgroundColor: '#343a40 ',
@@ -600,6 +601,9 @@
             trigger: 'axis',
             axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                 type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+            },
+            formatter: function (p) {
+                _param = p
             }
         },
         legend: {},
@@ -825,7 +829,8 @@
                 contract_tp:[],
                 qc_tp:[],
             };
-            for(const t of tenderList) {
+            const newTenders = tenderList.filter(t => t.stage_count > 0);
+            for(const t of newTenders) {
                 chart_option_name.push(t.name);
                 chart_option2_data.total_price.push(t.total_price ? t.total_price : 0);
                 chart_option2_data.contract_tp.push(t.end_contract_tp ? t.end_contract_tp : 0);
@@ -836,7 +841,7 @@
             // 图表数据赋值
             const option2 = myChart.getOption();
             option2.dataZoom[0].start = 0;
-            option2.dataZoom[0].end = computedPosition(tenderList.length);
+            option2.dataZoom[0].end = computedPosition(newTenders.length);
             option2.xAxis[0].data = chart_option_name;
             option2.series[0].data = chart_option2_data.total_price;
             option2.series[1].data = chart_option2_data.contract_tp;
@@ -850,6 +855,19 @@
             myChart.setOption(option2);
         }
 
+        // 处理点击事件并且弹出数据名称
+        myChart.getZr().on('click', function (p) {
+            const pointInPixel = [p.offsetX, p.offsetY];
+            if (myChart.containPixel('grid', pointInPixel)) {
+                const params = _param && _param[0] ? _param[0] : null;
+                if (params !== null) {
+                    const tender = tenders.filter(t => t.stage_count > 0)[params.dataIndex];
+                    console.log(tender);
+                    window.open(`/sp/${tender.spid}/datacollect`);
+                }
+            }
+        });
+
         // 计算显示滚动条长度
         function computedPosition(xArrayLength) {
             if (xArrayLength >= 8) {

+ 2 - 2
app/view/financial/pay_detail_modal.ejs

@@ -10,7 +10,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:f0MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <!-- <p><a href="javascript: void(0);" class="btn btn-primary" id="file-modal-target">选择文件</a></p> -->
                 <input type="file" id="file-modal" multiple="multiple">
             </div>
@@ -31,7 +31,7 @@
             <div class="modal-body">
                 <% if (financialPay.filePermission) { %>
                 <div class="form-group upload-permission">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <br>
                     <input type="file" class="" multiple>
                 </div>

+ 1 - 1
app/view/financial/transfer_modal.ejs

@@ -40,7 +40,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group upload-permission">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <br>
                     <input type="file" class="" multiple>
                 </div>

+ 1 - 1
app/view/financial/transfer_tender_modal.ejs

@@ -88,7 +88,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group upload-permission">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <br>
                     <input type="file" class="" multiple>
                 </div>

+ 1 - 1
app/view/ledger/explode_modal.ejs

@@ -266,7 +266,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
             </div>

+ 1 - 1
app/view/material/file_modal.ejs

@@ -9,7 +9,7 @@
       </button>
         </div>
         <div class="modal-body">
-          <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+          <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                   <p>
                       <input id="upload-fujian-file" type="file" multiple="multiple">
                       <!-- <a href="javascript: void(0);" id="upload-fujian" class="btn btn-primary">选择文件</a> -->

+ 68 - 26
app/view/measure/compare.ejs

@@ -64,42 +64,84 @@
         <div class="c-body">
             <div class="tab-content" id="compareType">
                 <div class="tab-pane" id="tz">
-                    <div class="sjs-height-1" id="bills-spread">
-                    </div>
-                    <div class="bcontent-wrap" id="main-bottom">
-                        <div id="main-resize" class="resize-y"  r-Type="height" div1="#bills-spread" div2="#main-bottom" store-id="compare-main" store-version="1.0.0" min="100"></div>
-                        <div class="bc-bar mb-1">
-                            <ul class="nav nav-tabs">
-                                <li class="nav-item">
-                                    <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">计量单元</a>
-                                </li>
-                            </ul>
+                    <div class="content-wrap row pr-46" style="background: #e4e7ea;">
+                        <div class="c-header p-0 col-12">
                         </div>
-                        <div class="tab-content">
-                            <div class="tab-pane active" id="xmujie">
-                                <div class="sp-wrap" id="pos-spread">
+                        <div class="row w-100 sub-content">
+                            <div class="c-body" id="tz-left-view" style="width: 100%">
+                                <div class="sjs-height-1" id="bills-spread">
+                                </div>
+                                <div class="bcontent-wrap" id="main-bottom">
+                                    <div id="main-resize" class="resize-y"  r-Type="height" div1="#bills-spread" div2="#main-bottom" store-id="compare-main" store-version="1.0.0" min="100"></div>
+                                    <div class="bc-bar mb-1">
+                                        <ul class="nav nav-tabs">
+                                            <li class="nav-item">
+                                                <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">计量单元</a>
+                                            </li>
+                                        </ul>
+                                    </div>
+                                    <div class="tab-content">
+                                        <div class="tab-pane active" id="xmujie">
+                                            <div class="sp-wrap" id="pos-spread">
+                                            </div>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
+                            <div class="c-body" id="tz-right-view" style="display: none; width: 33%;">
+                                <div class="resize-x" id="right-spr" r-Type="width" div1="#tz-left-view" div2="#tz-right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                                <div class="tab-content">
+                                    <div id="tz-search" class="tab-pane"></div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="side-menu side-memu-tz">
+                            <ul class="nav flex-column right-nav" id="tz-side-menu">
+                                <li>
+                                    <a class="nav-link" content="#tz-search" href="javascript: void(0);">查找定位</a>
+                                </li>
+                            </ul>
                         </div>
                     </div>
                 </div>
                 <div class="tab-pane active" id="gcl">
-                    <div class="sjs-height-1" id="gcl-spread">
-                    </div>
-                    <div class="bcontent-wrap" id="leafxmj-bottom">
-                        <div id="gcl-resize" class="resize-y" r-Type="height" div1="#gcl-spread" div2="#leafxmj-bottom" store-id="compare-stages-gcl" store-version="1.0.0" min="100"></div>
-                        <div class="bc-bar mb-1">
-                            <ul class="nav nav-tabs">
-                                <li class="nav-item">
-                                    <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">所属项目节</a>
-                                </li>
-                            </ul>
+                    <div class="content-wrap row pr-46" style="background: #e4e7ea;">
+                        <div class="c-header p-0 col-12">
                         </div>
-                        <div class="tab-content">
-                            <div class="tab-pane active">
-                                <div class="sp-wrap" id="leaf-xmj-spread">
+                        <div class="row w-100 sub-content">
+                            <div class="c-body" id="gcl-left-view" style="width: 100%">
+                                <div class="sjs-height-1" id="gcl-spread">
+                                </div>
+                                <div class="bcontent-wrap" id="leafxmj-bottom">
+                                    <div id="gcl-resize" class="resize-y" r-Type="height" div1="#gcl-spread" div2="#leafxmj-bottom" store-id="compare-stages-gcl" store-version="1.0.0" min="100"></div>
+                                    <div class="bc-bar mb-1">
+                                        <ul class="nav nav-tabs">
+                                            <li class="nav-item">
+                                                <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">所属项目节</a>
+                                            </li>
+                                        </ul>
+                                    </div>
+                                    <div class="tab-content">
+                                        <div class="tab-pane active">
+                                            <div class="sp-wrap" id="leaf-xmj-spread">
+                                            </div>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
+                            <div class="c-body" id="gcl-right-view" style="display: none; width: 33%;">
+                                <div class="resize-x" id="right-spr" r-Type="width" div1="#gcl-left-view" div2="#gcl-right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                                <div class="tab-content">
+                                    <div id="gcl-search" class="tab-pane"></div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="side-menu gcl-side-memu">
+                            <ul class="nav flex-column right-nav" id="gcl-side-menu">
+                                <li>
+                                    <a class="nav-link" content="#gcl-search" href="javascript: void(0);">查找定位</a>
+                                </li>
+                            </ul>
                         </div>
                     </div>
                 </div>

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

@@ -150,7 +150,7 @@
                 </button>
             </div>
             <div class="modal-body">
-                <p>单个文件大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
+                <p>单个文件大小限制:50MB,支持office等文档格式、图片格式、压缩包格式</p>
                 <p><input value="选择文件" type="file" id="upload-file" multiple /></p>
             </div>
             <div class="modal-footer">

+ 1 - 1
app/view/payment_safe/modal.ejs

@@ -8,7 +8,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
             </div>

+ 1 - 1
app/view/shares/upload_att.ejs

@@ -7,7 +7,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="formGroupExampleInput">大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
             </div>

+ 32 - 0
app/view/sp_setting/manage_modal.ejs

@@ -184,6 +184,38 @@
         </div>
     </div>
 </div>
+<div class="modal fade" id="union" data-backdrop="static">
+    <div class="modal-dialog modal-xl" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">协同审批</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-6">
+                        <div class="modal-height-500" style="overflow: auto;">
+                            <table class="table table-hover table-bordered">
+                                <thead class="text-center" >
+                                <tr><th>姓名</th><th>单位</th><th>协同处理</th></tr>
+                                </thead>
+                                <tbody id="union_table">
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                    <div class="col-6">
+                        <div class="modal-height-500" style="overflow: auto;" id="union-spread">
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-sm btn-primary" id="union-ok">保存</button>
+            </div>
+        </div>
+    </div>
+</div>
 <!--弹出编辑标段-->
 <div class="modal fade" id="edit-bd" data-backdrop="static">
     <div class="modal-dialog" role="document">

+ 2 - 0
app/view/sp_setting/permission.ejs

@@ -4,6 +4,7 @@
         <div class="title-main">
             <h2>账号管理
                 <a href="#sel-batch" data-toggle="modal" data-target="#sel-batch" class="btn btn-primary btn-sm pull-right mr-1">选择账号</a>
+                <a href="/setting/user" class="btn btn-primary btn-sm pull-right mr-1">新增账号</a>
             </h2>
         </div>
     </div>
@@ -103,6 +104,7 @@
 </div>
 <script>
     const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
+    const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
     const permissionConst = JSON.parse(unescape('<%- escape(JSON.stringify(permissionConst)) %>'));
     const reCalcHeight = function () {
         $('#sp-pageshow-content').height($(window).height() - 187);

+ 2 - 0
app/view/sp_setting/user.ejs

@@ -4,6 +4,7 @@
         <div class="title-main">
             <h2>账号管理
                 <a href="#sel-batch" data-toggle="modal" data-target="#sel-batch" class="btn btn-primary btn-sm pull-right mr-1">选择账号</a>
+                <a href="/setting/user" class="btn btn-primary btn-sm pull-right mr-1">新增账号</a>
             </h2>
         </div>
     </div>
@@ -65,4 +66,5 @@
 </div>
 <script>
     const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
+    const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
 </script>

+ 21 - 9
app/view/sp_setting/user_modal.ejs

@@ -1,21 +1,33 @@
 <div class="modal fade" id="sel-batch" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
             <div class="modal-header">
                 <h5 class="modal-title">选择账号</h5>
             </div>
             <div class="modal-body">
-                <div class="form-inline mb-2">
-                    <label for="inputPassword2" class="">单位:</label>
-                    <select class="form-control form-control-sm" style="width:300px" id="sel-batch-unit">
-                        <% for (const g of accountGroup) { %>
-                        <option value="<%- g.name %>"><%- g.name %></option>
-                        <% } %>
-                    </select>
+                <div class="d-flex justify-content-between mb-2">
+                    <div class="col">
+                        <div class="form-inline">
+                            <label for="inputPassword2" class="">单位:</label>
+                            <select class="form-control form-control-sm" style="width:300px" id="sel-batch-unit">
+                                <% for (const g of accountGroup) { %>
+                                <option value="<%- g.name %>"><%- g.name %></option>
+                                <% } %>
+                            </select>
+                        </div>
+                    </div>
+                    <div class="col-5">
+                        <div class="input-group input-group-sm">
+                            <input type="text" class="form-control" placeholder="姓名/职位 搜索" aria-label="姓名/职位 搜索" id="sb-keyword" aria-describedby="sb-search">
+                            <div class="input-group-append">
+                                <button class="btn btn-outline-primary" type="button" id="sb-search"><i class="fa fa-search"></i></button>
+                            </div>
+                        </div>
+                    </div>
                 </div>
                 <div class="modal-height-500-scroll">
                     <table class="table table-bordered">
-                        <thead><tr class="text-center"><th width="15%"><input type="checkbox" id="sel-batch-all"></th><th width="30%">用户</th><th width="40%">职位</th></tr></thead>
+                        <thead><tr class="text-center"><th width="15%"><input type="checkbox" id="sel-batch-all"></th><th width="20%">用户</th><th width="30%">职位</th><th>单位</th></tr></thead>
                         <tbody id="sel-batch-users"></tbody>
                     </table>
                 </div>

+ 13 - 8
app/view/spss/info.ejs

@@ -6,13 +6,16 @@
             <div class="title-main  d-flex justify-content-between">
                 <div>
                     <div class="d-inline-block mr-2">
+                        <div class="btn-group">
+                            <button href="#info-cate" class="btn btn-sm btn-light text-primary" data-toggle="modal" data-target="#info-cate"><i class="fa fa-sitemap fa-rotate-270"></i> 类别设置</button>
+                        </div>
                         <!--展开/收起-->
                         <div class="btn-group">
                             <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" id="zhankai" aria-expanded="false">显示层级</button>
-                            <div class="dropdown-menu" aria-labelledby="zhankai" style="will-change: transform;">
-                                <a class="dropdown-item" href="#">第一层</a>
-                                <a class="dropdown-item" href="#">第二层</a>
-                                <a class="dropdown-item" href="#">最底层</a>
+                            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                                <a class="dropdown-item" name="showLevel" tag="1" href="javascript:void(0);">第一层</a>
+                                <a class="dropdown-item" name="showLevel" tag="2" href="javascript:void(0);">第二层</a>
+                                <a class="dropdown-item" name="showLevel" tag="last" href="javascript:void(0);">最底层</a>
                             </div>
                         </div>
                     </div>
@@ -25,9 +28,11 @@
         </div>
     </div>
     <div class="content-wrap">
-        <div class="sjs-height-0" style="background-color: #fff">
-            <div class="c-body">
-            </div>
+        <div class="sjs-height-0" style="background-color: #fff" id="info-spread">
         </div>
     </div>
-</div>
+</div>
+<script>
+    const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
+    const selfCategoryLevel = '<%- ctx.subProject.permission.self_category_level %>';
+</script>

+ 20 - 0
app/view/spss/gather_info_modal.ejs

@@ -0,0 +1,20 @@
+<% include ./spss_select_modal.ejs %>
+<div class="modal fade" id="info-cate" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">分类设置</h5>
+            </div>
+            <div class="modal-body">
+                <div class="modal-height-300">
+                    <ul id="treeLevel-info" class="ztree"></ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary btn-sm" id="info-cate-reset">重置</button>
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary btn-sm" id="info-cate-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 1 - 4
app/view/spss/spss_select_modal.ejs

@@ -108,7 +108,4 @@
             </div>
         </div>
     </div>
-</div>
-<script>
-    const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
-</script>
+</div>

+ 6 - 6
app/view/stage/audit_modal.ejs

@@ -156,7 +156,7 @@
                                 <% } %>
                                 <div class="<%- idx < ctx.stage.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                    <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                         <% his.forEach((group, index) => { %>
                                         <% if (index === 0) { %>
                                         <li class="timeline-list-item pb-2">
@@ -188,7 +188,7 @@
                                             </div>
                                         </li>
                                         <% } %>
-                                        <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                        <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                             <% if (group.endYear) { %>
                                             <div class="timeline-item-date">
                                                 <%- group.endYear %>
@@ -335,7 +335,7 @@
                                 <% } %>
                             <div class="<%- idx < ctx.stage.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                 <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                     <% his.forEach((group, index) => { %>
                                     <% if (index === 0) { %>
                                     <li class="timeline-list-item pb-2">
@@ -367,7 +367,7 @@
                                         </div>
                                     </li>
                                     <% } %>
-                                    <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                    <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                         <% if (group.endYear) { %>
                                         <div class="timeline-item-date">
                                             <%- group.endYear %>
@@ -516,7 +516,7 @@
                             <% } %>
                             <div class="<%- idx < ctx.stage.auditHistory.length - 1 ? 'fold-card' : '' %>">
                                 <div class="text-center text-muted"><%- idx+1 %>#</div>
-                                <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                <ul class="timeline-list list-unstyled mt-2 <% if (idx === ctx.stage.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                     <% his.forEach((group, index) => { %>
                                     <% if (index === 0) { %>
                                     <li class="timeline-list-item pb-2">
@@ -548,7 +548,7 @@
                                         </div>
                                     </li>
                                     <% } %>
-                                    <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1 && ctx.stage.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                    <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === ctx.stage.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                         <% if (his.endYear) { %>
                                         <div class="timeline-item-date">
                                             <%- group.endYear %>

+ 2 - 2
app/view/stage/modal.ejs

@@ -206,7 +206,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
             </div>
@@ -625,7 +625,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <% if (!ctx.tender.isTourist || (ctx.tender.isTourist && ctx.tender.touristPermission.file) || stage.filePermission) { %>
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <% } %>
                     <div class="d-flex">
                         <% if (!ctx.tender.isTourist || (ctx.tender.isTourist && ctx.tender.touristPermission.file) || stage.filePermission) { %>

+ 1 - 1
app/view/stage/pay_modal.ejs

@@ -77,7 +77,7 @@
             <div class="modal-body">
                 <% if (uploadPermission) { %>
                 <div class="form-group">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
                 <% } %>

+ 1 - 1
app/view/stage_extra/bonus_modal.ejs

@@ -8,7 +8,7 @@
             <div class="modal-body">
                 <% if (ctx.stage.filePermission) { %>
                 <div class="form-group" id="upload-file-panel">
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
                 <% } %>

+ 1 - 1
app/view/stage_rela/detail_modal.ejs

@@ -29,7 +29,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <% if (!ctx.tender.isTourist || (ctx.tender.isTourist && ctx.tender.touristPermission.file) || stage.filePermission) { %>
-                    <label for="formGroupExampleInput">单个文件大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
+                    <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-im-file" multiple>
                     <% } %>
                 </div>

+ 1 - 1
app/view/sub_proj/index.ejs

@@ -21,7 +21,7 @@
                 </div>
                 <% } else { %>
                 <table class="table table-bordered">
-                    <tr class="text-center"><th style="min-width: 200px">项目名称</th><th>概预算标准</th><th>创建时间</th><th>标段个数</th><th>管理单位</th><th>操作</th></tr>
+                    <tr class="text-center"><th style="min-width: 300px">项目名称</th><th width="8%">概预算标准</th><th width="8%">创建时间</th><th width="5%">标段个数</th><th width="20%">管理单位</th><% if (ctx.session.sessionUser.is_admin) { %><th width="20%">操作</th><% } %></tr>
                     <tbody id="projectList">
                     </tbody>
                 </table>

+ 27 - 1
app/view/sub_proj/progress_modal.ejs

@@ -1,2 +1,28 @@
 <% include ../shares/delete_hint_modal.ejs %>
-<% include ../shares/upload_att.ejs %>
+<% include ../shares/upload_att.ejs %>
+<div class="modal fade" id="add-big-file" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">上传附件</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group text-danger" style="display: none" id="upload-big-file-hint">
+                </div>
+                <div class="form-group">
+                    <label for="formGroupExampleInput">文件大小限制:500MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
+                    <input type="file" class="" id="upload-big-file">
+                </div>
+                <div class="form-group progress">
+                    <div id="upload-big-file-progress" class="progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary btn-sm" id="add-big-file-stop" style="display: none">暂停</button>
+                <button type="button" class="btn btn-primary btn-sm" id="add-big-file-resume" style="display: none">重新上传</button>
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary btn-sm" id="add-big-file-ok">确认</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 11 - 15
config/web.js

@@ -754,6 +754,7 @@ const JsFiles = {
                     '/public/js/shares/sjs_setting.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
+                    '/public/js/shares/cs_tools.js',
                     '/public/js/gcl_gather.js',
                     '/public/js/measure_compare.js',
                 ],
@@ -1885,15 +1886,15 @@ const JsFiles = {
             },
         },
         spss: {
-            info: {
+            gatherInfo: {
                 files: [
                     '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
                     '/public/js/spreadjs/sheets/v11/interop/gc.spread.excelio.11.2.2.min.js',
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/ztree/jquery.ztree.core.js', '/public/js/ztree/jquery.ztree.exedit.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -1905,9 +1906,9 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
-                    '/public/js/spss_info.js',
+                    '/public/js/spss_gather_stage_info.js',
                 ],
-                mergeFile: 'spss_info',
+                mergeFile: 'spss_gather_stage_info',
             },
             gatherLedger: {
                 files: [
@@ -1916,8 +1917,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -1940,8 +1940,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -1964,8 +1963,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -1988,8 +1986,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -2012,8 +2009,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
-                    '/public/js/datepicker/datepicker.min.js',
-                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',