Browse Source

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

TonyKang 3 years ago
parent
commit
75825579d5
100 changed files with 3462 additions and 551 deletions
  1. 1 0
      app.js
  2. 1 0
      app/base/base_bills_service.js
  3. 6 1
      app/base/base_controller.js
  4. 1 0
      app/const/account_permission.js
  5. 4 0
      app/const/page_show.js
  6. 3 0
      app/const/sign.js
  7. 2 1
      app/const/tender_info.js
  8. 67 18
      app/controller/datacollect_controller.js
  9. 193 3
      app/controller/login_controller.js
  10. 178 8
      app/controller/material_controller.js
  11. 22 13
      app/controller/revise_controller.js
  12. 21 2
      app/controller/setting_controller.js
  13. 0 1
      app/controller/stage_controller.js
  14. 33 14
      app/controller/tender_controller.js
  15. 39 6
      app/extend/helper.js
  16. 1 0
      app/lib/analysis_excel.js
  17. 1 1
      app/middleware/advance_check.js
  18. 56 0
      app/middleware/api3management_check.js
  19. 4 1
      app/middleware/change_check.js
  20. 1 1
      app/middleware/ledger_audit_check.js
  21. 4 1
      app/middleware/material_check.js
  22. 1 1
      app/middleware/revise_audit_check.js
  23. 15 2
      app/middleware/revise_check.js
  24. 1 1
      app/middleware/stage_check.js
  25. 199 10
      app/public/css/main.css
  26. BIN
      app/public/images/juecedaping01.png
  27. BIN
      app/public/images/juecedaping02.png
  28. BIN
      app/public/images/juecedaping03.png
  29. BIN
      app/public/images/juecedaping04.png
  30. 2 1
      app/public/js/advance.js
  31. 2 1
      app/public/js/advance_audit.js
  32. 5 3
      app/public/js/budget_detail.js
  33. 4 4
      app/public/js/change_information.js
  34. 20 14
      app/public/js/change_information_approval.js
  35. 7 2
      app/public/js/change_information_show.js
  36. 4 2
      app/public/js/change_revise.js
  37. 38 2
      app/public/js/datacollect_scroll.js
  38. 56 1
      app/public/js/global.js
  39. 49 33
      app/public/js/ledger.js
  40. 37 45
      app/public/js/material.js
  41. 900 0
      app/public/js/material_checklist.js
  42. 13 11
      app/public/js/material_exponent.js
  43. 3 3
      app/public/js/material_file.js
  44. 89 61
      app/public/js/material_list.js
  45. 104 25
      app/public/js/revise.js
  46. 1 1
      app/public/js/revise_history.js
  47. 53 0
      app/public/js/revise_price.js
  48. 199 0
      app/public/js/setting_datacollect_tender.js
  49. 234 1
      app/public/js/shares/cs_tools.js
  50. 3 3
      app/public/js/shares/tender_list_order.js
  51. 18 4
      app/public/js/spreadjs_rela/spreadjs_zh.js
  52. 3 3
      app/public/js/sr_detail.js
  53. 18 36
      app/public/js/stage.js
  54. 4 1
      app/public/js/stage_compare.js
  55. 12 3
      app/public/js/tender_copy_setting.js
  56. 3 3
      app/public/js/tender_list_progress.js
  57. 0 1
      app/public/js/zh_calc.js
  58. 21 4
      app/router.js
  59. 25 0
      app/service/category.js
  60. 17 2
      app/service/change.js
  61. 10 1
      app/service/change_audit.js
  62. 13 6
      app/service/change_audit_list.js
  63. 1 0
      app/service/change_ledger.js
  64. 2 0
      app/service/change_pos.js
  65. 27 0
      app/service/change_revise_log.js
  66. 1 1
      app/service/datacollect_audit.js
  67. 100 0
      app/service/datacollect_tender.js
  68. 3 8
      app/service/ledger.js
  69. 25 0
      app/service/ledger_audit.js
  70. 5 5
      app/service/ledger_revise.js
  71. 2 2
      app/service/ledger_tag.js
  72. 1 0
      app/service/manager.js
  73. 31 7
      app/service/material.js
  74. 64 59
      app/service/material_audit.js
  75. 72 22
      app/service/material_bills.js
  76. 67 0
      app/service/material_checklist.js
  77. 4 4
      app/service/material_exponent.js
  78. 12 6
      app/service/material_list.js
  79. 12 12
      app/service/material_month.js
  80. 7 6
      app/service/notice_push.js
  81. 7 8
      app/service/pos.js
  82. 53 3
      app/service/project.js
  83. 28 0
      app/service/project_account.js
  84. 3 0
      app/service/report.js
  85. 24 1
      app/service/report_memory.js
  86. 2 2
      app/service/revise_audit.js
  87. 2 2
      app/service/revise_bills.js
  88. 7 8
      app/service/revise_pos.js
  89. 27 0
      app/service/revise_price_change.js
  90. 18 4
      app/service/stage.js
  91. 16 1
      app/service/stage_audit.js
  92. 1 1
      app/service/stage_bills.js
  93. 1 1
      app/service/stage_pos.js
  94. 2 2
      app/service/stage_shoufang.js
  95. 7 0
      app/service/tender.js
  96. 3 0
      app/view/advance/detail.ejs
  97. 2 22
      app/view/budget/detail.ejs
  98. 1 1
      app/view/budget/list.ejs
  99. 1 1
      app/view/change/information.ejs
  100. 0 0
      app/view/change/revise.ejs

+ 1 - 0
app.js

@@ -115,4 +115,5 @@ module.exports = app => {
 
 
     app.signPdfOss = app.oss.get('signPdf');
     app.signPdfOss = app.oss.get('signPdf');
     app.fujianOss = app.oss.get('fujian');
     app.fujianOss = app.oss.get('fujian');
+    app.hisOss = app.oss.get('his');
 };
 };

+ 1 - 0
app/base/base_bills_service.js

@@ -633,6 +633,7 @@ class BaseBillsSerivce extends TreeService {
                             sjcl_expr: pos.sjcl_expr ? pos.sjcl_expr : '',
                             sjcl_expr: pos.sjcl_expr ? pos.sjcl_expr : '',
                             qtcl_expr: pos.qtcl_expr ? pos.qtcl_expr : '',
                             qtcl_expr: pos.qtcl_expr ? pos.qtcl_expr : '',
                             add_stage: 0,
                             add_stage: 0,
+                            add_stage_order: 0,
                             add_times: 0,
                             add_times: 0,
                             ex_memo1: pos.ex_memo1,
                             ex_memo1: pos.ex_memo1,
                             ex_memo2: pos.ex_memo2,
                             ex_memo2: pos.ex_memo2,

+ 6 - 1
app/base/base_controller.js

@@ -36,6 +36,11 @@ class BaseController extends Controller {
             }
             }
         }
         }
         menuList.datacollect.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showDataCollect : false;
         menuList.datacollect.display = ctx.session && ctx.session.sessionProject ? ctx.session.sessionProject.showDataCollect : false;
+        if (ctx.session && ctx.session.sessionProject && ctx.session.sessionProject.page_show && ctx.session.sessionProject.page_show.openManagement) {
+            menuList.management.display = true;
+        } else {
+            menuList.management.display = false;
+        }
         // 菜单列表
         // 菜单列表
         ctx.menuList = menuList;
         ctx.menuList = menuList;
         ctx.showProject = false;
         ctx.showProject = false;
@@ -89,7 +94,7 @@ class BaseController extends Controller {
                 maintainConst,
                 maintainConst,
             };
             };
             await this.ctx.render('layout/layout.ejs', renderData);
             await this.ctx.render('layout/layout.ejs', renderData);
-        } catch(err) {
+        } catch (err) {
             this.log(err);
             this.log(err);
         }
         }
     }
     }

+ 1 - 0
app/const/account_permission.js

@@ -29,6 +29,7 @@ const permission = {
             { title: '创建标段', value: 1 },
             { title: '创建标段', value: 1 },
             { title: '查阅所有标段', value: 2 },
             { title: '查阅所有标段', value: 2 },
             { title: '维护签约清单', value: 3, hint: '开启该选项,台账审批通过后,可上传签约清单', hintIcon: 'fa-question-circle' },
             { title: '维护签约清单', value: 3, hint: '开启该选项,台账审批通过后,可上传签约清单', hintIcon: 'fa-question-circle' },
+            { title: '材差清单设置', value: 4, hint: '开启该选项,当前账号可设置允许调差的清单', hintIcon: 'fa-question-circle' },
         ],
         ],
     },
     },
     // cooperation: {
     // cooperation: {

+ 4 - 0
app/const/page_show.js

@@ -35,6 +35,10 @@ const defaultSetting = {
     openNetCaSign: 0,
     openNetCaSign: 0,
     openChangeRevise: 0,
     openChangeRevise: 0,
     openMaterialTax: 0,
     openMaterialTax: 0,
+    addDataCollect: 1,
+    closeWapYfSf: 0,
+    openManagement: 0,
+    openMaterialChecklist: 0,
 };
 };
 
 
 
 

+ 3 - 0
app/const/sign.js

@@ -13,7 +13,10 @@ const path = {
     api: 'http://106.52.243.222:9091/eseal',
     api: 'http://106.52.243.222:9091/eseal',
 };
 };
 
 
+/** 请求项目管理token所需秘钥 */
+const managementApiSecretKey = 'JL_CM_lksjdofuosdjflj01231209uljsf90@@#(lnm8';
 
 
 module.exports = {
 module.exports = {
     path,
     path,
+    managementApiSecretKey,
 };
 };

+ 2 - 1
app/const/tender_info.js

@@ -113,7 +113,8 @@ const defaultInfo = {
         stage: {
         stage: {
             realComplete: false,
             realComplete: false,
             correct: true,
             correct: true,
-        }
+        },
+        dayMode: false,
     },
     },
     chapter: [
     chapter: [
         {code: '100', name: '总则'},
         {code: '100', name: '总则'},

+ 67 - 18
app/controller/datacollect_controller.js

@@ -23,6 +23,7 @@ const sendToWormhole = require('stream-wormhole');
 const scheduleConst = require('../const/schedule');
 const scheduleConst = require('../const/schedule');
 const changeConst = require('../const/change');
 const changeConst = require('../const/change');
 const tenderInfoModel = require('../lib/tender_info');
 const tenderInfoModel = require('../lib/tender_info');
+const mapConst = require('../const/map');
 
 
 module.exports = app => {
 module.exports = app => {
     class DatacollectController extends app.BaseController {
     class DatacollectController extends app.BaseController {
@@ -45,12 +46,38 @@ module.exports = app => {
          */
          */
         async index(ctx) {
         async index(ctx) {
             try {
             try {
+                if (!ctx.session.sessionProject.showDataCollect) {
+                    throw '该功能已关闭或无法查看';
+                }
                 // 获取标段审批信息
                 // 获取标段审批信息
                 const tenderidList = [];
                 const tenderidList = [];
-                console.log(ctx.session.sessionProject.dataCollect);
                 const noticeList = await ctx.service.noticePush.getNoticeByDataCollect(ctx.session.sessionProject.id, tenderidList);
                 const noticeList = await ctx.service.noticePush.getNoticeByDataCollect(ctx.session.sessionProject.id, tenderidList);
+                // 获取分类
+                const categoryData = await this.ctx.service.category.getListByCategoryLevel(ctx.session.sessionProject.id);
+                // 默认坐标,否则则取办事处坐标
+                const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
+                projectData.data_collect_pages = projectData.data_collect_pages ? projectData.data_collect_pages.split(',') : [];
+                let map_json = {
+                    province: mapConst.map[0].province,
+                    lng: mapConst.map[0].lng,
+                    lat: mapConst.map[0].lat,
+                    level: 15,
+                };
+                if (projectData.map_json) {
+                    map_json = JSON.parse(projectData.map_json);
+                } else {
+                    const mapInfo = ctx.helper._.find(mapConst.map, { office: projectData.manager_office });
+                    if (mapInfo) {
+                        map_json.province = mapInfo.province;
+                        map_json.lng = mapInfo.lng;
+                        map_json.lat = mapInfo.lat;
+                    }
+                }
                 const renderData = {
                 const renderData = {
+                    projectData,
                     noticeList,
                     noticeList,
+                    categoryData,
+                    map_json,
                     acLedger: auditConst.ledger,
                     acLedger: auditConst.ledger,
                     acStage: auditConst.stage,
                     acStage: auditConst.stage,
                     acChange: auditConst.flow,
                     acChange: auditConst.flow,
@@ -72,36 +99,58 @@ module.exports = app => {
                 const responseData = { err: 0, msg: '', data: {} };
                 const responseData = { err: 0, msg: '', data: {} };
                 // const tenderidList = [];
                 // const tenderidList = [];
                 // const noticeList = await ctx.service.noticePush.getNoticeByDataCollect(ctx.session.sessionProject.id, tenderidList);
                 // const noticeList = await ctx.service.noticePush.getNoticeByDataCollect(ctx.session.sessionProject.id, tenderidList);
-                const tenderList = await ctx.service.tender.getList('', null, 1);
+                const dcTenders = await ctx.service.datacollectTender.getList(ctx.session.sessionProject.id);
+                const noTids = ctx.app._.map(dcTenders, 'tid');
+                let tenderList = await ctx.service.tender.getList('', null, 1);
+                tenderList = ctx.app._.filter(tenderList, function(item) {
+                    return ctx.app._.indexOf(noTids, item.id) === -1;
+                });
                 const thisMonth = new Date();
                 const thisMonth = new Date();
                 const [startMonth, endMonth] = ctx.helper.getStartEndMonth(thisMonth);
                 const [startMonth, endMonth] = ctx.helper.getStartEndMonth(thisMonth);
                 for (const t of tenderList) {
                 for (const t of tenderList) {
                     const tenderInfo = await ctx.service.tenderInfo.getTenderInfo(t.id);
                     const tenderInfo = await ctx.service.tenderInfo.getTenderInfo(t.id);
                     t.contract_price = tenderInfo.deal_param.contractPrice;
                     t.contract_price = tenderInfo.deal_param.contractPrice;
-
-                    if (t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck) {
-                        const sum = await ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
-                        t.total_price = sum.total_price;
-                        t.deal_tp = sum.deal_tp;
-                    }
+                    let bCalcTp = t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck;
                     t.advance_tp = await ctx.service.advance.getSumAdvance(t.id);
                     t.advance_tp = await ctx.service.advance.getSumAdvance(t.id);
 
 
                     if (t.ledger_status === auditConst.ledger.status.checked) {
                     if (t.ledger_status === auditConst.ledger.status.checked) {
-                        t.lastStage = await ctx.service.stage.getLastestStage(t.id, true);
-                        if (t.lastStage && t.lastStage.status === auditConst.stage.status.uncheck &&
-                            t.lastStage.user_id !== ctx.session.sessionUser.accountId) {
-                            t.lastStage = await ctx.service.stage.getLastestStage(t.id);
-                        }
-                        if (t.lastStage) await ctx.service.stage.checkStageGatherData(t.lastStage);
+                        t.lastStage = await ctx.service.stage.getLastestStage(t.id);
+                        if (t.lastStage) await ctx.service.stage.checkStageGatherData(t.lastStage, true);
                         t.completeStage = await ctx.service.stage.getLastestCompleteStage(t.id);
                         t.completeStage = await ctx.service.stage.getLastestCompleteStage(t.id);
+                        if ((!bCalcTp) && t.measure_type === measureType.gcl.value) {
+                            bCalcTp = t.lastStage && t.lastStage.status !== auditConst.stage.status.checked && !t.lastStage.readOnly;
+                        }
+                    }
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
+                        t.total_price = sum.total_price;
+                        t.deal_tp = sum.deal_tp;
                     }
                     }
                     t.material_tp = await ctx.service.material.getSumMaterial(t.id);
                     t.material_tp = await ctx.service.material.getSumMaterial(t.id);
                     // 获取本标段 本月计量期审批通过数目,变更令审批通过数目,台账修订通过数目,材料调差通过数目
                     // 获取本标段 本月计量期审批通过数目,变更令审批通过数目,台账修订通过数目,材料调差通过数目
-                    t.month_stage_num = await this.ctx.service.stageAudit.getNumByMonth(t.id, startMonth, endMonth);
-                    t.month_change_num = await this.ctx.service.changeAudit.getNumByMonth(t.id, startMonth, endMonth);
-                    t.month_revise_num = await this.ctx.service.reviseAudit.getNumByMonth(t.id, startMonth, endMonth);
-                    t.month_material_num = await this.ctx.service.materialAudit.getNumByMonth(t.id, startMonth, endMonth);
+                    t.month_stage_num = await ctx.service.stageAudit.getNumByMonth(t.id, startMonth, endMonth);
+                    t.month_change_num = await ctx.service.changeAudit.getNumByMonth(t.id, startMonth, endMonth);
+                    t.month_revise_num = await ctx.service.reviseAudit.getNumByMonth(t.id, startMonth, endMonth);
+                    t.month_material_num = await ctx.service.materialAudit.getNumByMonth(t.id, startMonth, endMonth);
+                    // 获取标段计量月统计及截止月累计计量
+                    const stageList = await ctx.service.stage.getStageByDataCollect(t.id);
+                    const month_stage = [];
+                    for (const s of stageList) {
+                        const monthOneStage = ctx.app._.find(month_stage, { yearmonth: s.s_time });
+                        if (monthOneStage) {
+                            monthOneStage.tp = ctx.helper.add(monthOneStage.tp, s.tp);
+                        } else {
+                            const data = {
+                                yearmonth: s.s_time,
+                                tp: s.tp,
+                                end_tp: s.end_tp,
+                            };
+                            month_stage.push(data);
+                        }
+                    }
+                    t.month_stage = month_stage;
                 }
                 }
+                // const tenderMapList = await ctx.service.tenderMap.getAllDataByCondition({ where: { tid: tender.id } });
                 responseData.data.tenderList = tenderList;
                 responseData.data.tenderList = tenderList;
                 ctx.body = responseData;
                 ctx.body = responseData;
             } catch (err) {
             } catch (err) {

+ 193 - 3
app/controller/login_controller.js

@@ -10,7 +10,7 @@
 const URL = require('url');
 const URL = require('url');
 const maintainConst = require('../const/maintain');
 const maintainConst = require('../const/maintain');
 const OAuth = require('co-wechat-oauth');
 const OAuth = require('co-wechat-oauth');
-
+const office = require('../const/cld_office')
 module.exports = app => {
 module.exports = app => {
 
 
     class LoginController extends app.BaseController {
     class LoginController extends app.BaseController {
@@ -154,7 +154,6 @@ module.exports = app => {
          */
          */
         async login(ctx) {
         async login(ctx) {
             let loginType = ctx.request.body.type;
             let loginType = ctx.request.body.type;
-
             try {
             try {
                 loginType = parseInt(loginType);
                 loginType = parseInt(loginType);
                 const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
                 const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
@@ -279,7 +278,6 @@ module.exports = app => {
         async port(ctx) {
         async port(ctx) {
             // 获取系统维护信息
             // 获取系统维护信息
             const maintainData = await ctx.service.maintain.getDataById(1);
             const maintainData = await ctx.service.maintain.getDataById(1);
-
             if (!ctx.app.config.is_debug) {
             if (!ctx.app.config.is_debug) {
                 await ctx.service.maintain.syncMaintainData();
                 await ctx.service.maintain.syncMaintainData();
             }
             }
@@ -369,6 +367,198 @@ module.exports = app => {
                 ctx.redirect('/login');
                 ctx.redirect('/login');
             }
             }
         }
         }
+
+        /**
+         * (项目管理)获取账号
+         * @param {Object} ctx - egg全局变量
+         */
+        async account(ctx) {
+            const data = ctx.data;
+            const response = {
+                code: 0,
+                data: 0,
+                msg: '',
+            };
+            try {
+                const project = await ctx.service.project.getProjectByCode(data.code);
+                if (!project) throw '未找到该项目';
+                const pa = await ctx.service.projectAccount.getAccountInfoByAccountWithPid(data.account, project.id);
+                if (!pa ) throw '该账号不存在,请联系管理员';
+                const manager = await ctx.service.manager.getDataById(project.manager_id)
+                const { is_admin: isAdmin, account_group: accountGroup, ...otherObj } = pa
+                response.data = {
+                  account: { ...otherObj, accountGroup, isAdmin},
+                  project: {
+                    code: project.code,
+                    name: project.name,
+                    categoryId: project.manager_office,
+                    category: office.list[project.manager_office],
+                    staff: manager.real_name
+                  }
+                }
+            } catch (error) {
+                console.log(error);
+                response.code = -1;
+                response.msg = error.toString();
+            }
+            ctx.body = response;
+        }
+
+        /**
+         * (项目管理)获取项目
+         * @param {Object} ctx - egg全局变量
+         */
+        async project(ctx) {
+            const data = ctx.data;
+            const response = {
+                code: 0,
+                data: 0,
+                msg: '',
+            };
+            try {
+                const project = await ctx.service.project.getProjectByCode(data.code);
+                if (!project) throw '未找到该项目';
+                response.data = project;
+            } catch (error) {
+                response.code = -1;
+                response.msg = error.toString();
+            }
+            ctx.body = response;
+        }
+
+        /**
+         * (项目管理)校验项目
+         * @param {Object} ctx - egg全局变量
+         */
+        async vertifyProject(ctx) {
+            const response = {
+                code: 0,
+                data: 0,
+                msg: '',
+            };
+            try {
+              const code = ctx.session.sessionProject.code
+              const accountData = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId)
+              if (!code || !accountData) {
+                throw new Error('参数错误')
+              }
+                const result = await ctx.service.project.verifyManagementProject(ctx.helper.createJWT({ code }));
+                const token = ctx.helper.createJWT({ code, account: accountData.account })
+                const redirect = `${app.config.managementPath}/auth?token=${token}`
+                response.data = { ...result, is_admin: accountData.is_admin, redirect, env: app.config.env};
+            } catch (error) {
+                response.code = -1;
+                response.msg = error.toString();
+            }
+            ctx.body = response;
+        }
+
+        /**
+         * (项目管理)新增项目
+         * @param {Object} ctx - egg全局变量
+         */
+        async addProject(ctx) {
+          const response = {
+              code: 0,
+              data: {},
+              msg: '',
+          };
+          try {
+              const result = await ctx.service.project.addProjectFromManagement()
+              if (!result) {
+                throw new Error('请求失败')
+              }
+              const { code = -1, data: { token = ''} = { token: ''}, msg = '请求失败' } = result
+              if ( code === 0 && token) {
+                response.data = {
+                  redirect: `${app.config.managementPath}/auth?token=${token}`,
+                }
+              } else {
+                throw new Error(msg)
+              }
+          } catch (error) {
+              response.code = -1;
+              response.msg = error.toString();
+          }
+          ctx.body = response;
+        }
+        
+        /**
+         * 项目管理授权页面
+         *
+         * @param {Object} ctx - egg全局页面
+         * @return {void}
+         */
+        async management(ctx) {
+          const data = ctx.data;
+          // 获取系统维护信息
+          const maintainData = await ctx.service.maintain.getDataById(1);
+          if (!ctx.app.config.is_debug) {
+              await ctx.service.maintain.syncMaintainData();
+          }
+          let account, project;
+          try {
+              if (ctx.session.loginError !== null) {
+                  throw ctx.session.loginError;
+              }
+              if (!data) {
+                  throw '参数有误';
+              }
+              project = await ctx.service.project.getDataByCondition({ code: data.code })
+              if (!project) {
+                throw '未找到该项目';
+              }
+              account = await ctx.service.projectAccount.getDataByCondition({ project_id: project.id, account: data.account });
+              if (!account) {
+                  throw '您无权限登录系统。';
+              }
+              if (account.enable !== 1) {
+                throw '该账号已被停用,请联系销售人员';
+            }
+            const result = await ctx.service.projectAccount.accountLogin({ project, accountData: account }, 3);
+            if (!result) {
+                throw '登录出错';
+            }
+            ctx.redirect('/dashboard');
+          } catch (error) {
+              // this.log(error);
+              console.log(error);
+              ctx.session.loginError = error;
+          }
+          const errorMessage = ctx.session.loginError;
+          // 显示完删除
+          ctx.session.loginError = null;
+          const renderData = {
+              maintainData,
+              maintainConst,
+              errorMessage,
+              projectData: project,
+              accountData: account,
+          };
+          await ctx.render('login/login_management.ejs', renderData);
+        }
+
+        /** 拉取项目下所有计量账号至项目管理 */
+        async syncProjectAccount(ctx) {
+          const response = {
+            code: 0,
+            data: [],
+            msg: '',
+          };
+          try {
+              const { code = ''} = ctx.data
+              if (!code) throw '参数错误';
+              const projectData = await ctx.service.project.getProjectByCode(code)
+              if (!projectData) throw '未找到项目';
+              const data = await ctx.service.projectAccount.getAllProjectAccountByPid(projectData.id)
+              response.data = data || []
+          } catch (error) {
+            response.code = -1
+            response.msg = error.toString()
+          }
+          ctx.body = response
+        }
+      
     }
     }
 
 
     return LoginController;
     return LoginController;

+ 178 - 8
app/controller/material_controller.js

@@ -79,6 +79,7 @@ module.exports = app => {
                     if (!openMaterialTax && s.material_tax === 1) {
                     if (!openMaterialTax && s.material_tax === 1) {
                         openMaterialTax = 1;
                         openMaterialTax = 1;
                     }
                     }
+                    s.decimal = s.decimal ? JSON.parse(s.decimal) : materialConst.decimal;
                 }
                 }
                 renderData.stages = stages;
                 renderData.stages = stages;
                 renderData.openMaterialTax = openMaterialTax;
                 renderData.openMaterialTax = openMaterialTax;
@@ -358,8 +359,8 @@ module.exports = app => {
 
 
                 // 取当前期截止上期含税金额
                 // 取当前期截止上期含税金额
                 renderData.material.m_tax_tp = renderData.material.m_tax_tp ? renderData.material.m_tax_tp : renderData.material.m_tp;
                 renderData.material.m_tax_tp = renderData.material.m_tax_tp ? renderData.material.m_tax_tp : renderData.material.m_tp;
-                renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order);
-                renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order);
+                renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
+                renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
                 // renderData.tax_pre_tp_hs = await ctx.service.material.getTaxPreTpHs(ctx.tender.id, ctx.material.order);
                 // renderData.tax_pre_tp_hs = await ctx.service.material.getTaxPreTpHs(ctx.tender.id, ctx.material.order);
 
 
                 renderData.months = ctx.material.months ? ctx.material.months.split(',') : [];
                 renderData.months = ctx.material.months ? ctx.material.months.split(',') : [];
@@ -444,6 +445,11 @@ module.exports = app => {
                 // 获取所选期数据并合并相加同类清单项
                 // 获取所选期数据并合并相加同类清单项
                 responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, ctx.material.stage_id);
                 responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, ctx.material.stage_id);
                 responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, ctx.material.stage_id, 'list');
                 responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, ctx.material.stage_id, 'list');
+                // 获取清单设置已选清单
+                const materialChecklistData = await ctx.service.materialChecklist.getAllDataByCondition({ where: { tid: ctx.tender.id } });
+                responseData.data.materialChecklistData = materialChecklistData.sort(function(a, b) {
+                    return ctx.helper.compareCode(a.b_code, b.b_code);
+                });
                 ctx.body = responseData;
                 ctx.body = responseData;
             } catch (err) {
             } catch (err) {
                 this.log(err);
                 this.log(err);
@@ -502,8 +508,8 @@ module.exports = app => {
                 }
                 }
 
 
                 // 取当前期截止上期含税金额
                 // 取当前期截止上期含税金额
-                renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order);
-                renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order);
+                renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
+                renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
                 renderData.materialType = materialConst;
                 renderData.materialType = materialConst;
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.exponent);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.exponent);
                 // 判断之前期有无调用过材料税
                 // 判断之前期有无调用过材料税
@@ -542,6 +548,42 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
+         *  调差操作 (form)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveDecimal(ctx) {
+            try {
+                const data = ctx.request.body;
+                if (ctx.material.status !== auditConst.status.uncheck && ctx.material.status !== auditConst.status.checkNo) {
+                    throw '当前调差期无法调整小数位数';
+                }
+                const newDecimalUp = parseInt(data.up);
+                const newDecimalTp = parseInt(data.tp);
+                console.log(newDecimalUp, newDecimalTp);
+                if (ctx.app._.isNaN(newDecimalUp) || newDecimalUp > 6 || newDecimalUp < 0) {
+                    throw '单价小数位数设置不能大于6或小于0';
+                }
+                if (ctx.app._.isNaN(newDecimalTp) || newDecimalTp > 6 || newDecimalTp < 0) {
+                    throw '金额小数位数设置不能大于6或小于0';
+                }
+                if (ctx.material.decimal.up === newDecimalUp && ctx.material.decimal.tp === newDecimalTp) {
+                    throw '小数位数设置未发生变化';
+                }
+                const result = await ctx.service.material.saveDecimal(newDecimalUp, newDecimalTp);
+                if (!result) {
+                    throw '小数位数设置失败';
+                }
+                this.setMessage('设置小数位数成功', this.messageType.SUCCESS);
+            } catch (err) {
+                console.log(err);
+                this.log(err);
+                ctx.session.postError = err.toString();
+            }
+            ctx.redirect(ctx.request.header.referer);
+        }
+
+        /**
          * 调差清单 - 工料操作 (Ajax)
          * 调差清单 - 工料操作 (Ajax)
          * @param ctx
          * @param ctx
          * @return {Promise<void>}
          * @return {Promise<void>}
@@ -554,6 +596,9 @@ module.exports = app => {
                     msg: '',
                     msg: '',
                     data: {},
                     data: {},
                 };
                 };
+                if (ctx.session.sessionProject.page_show.openMaterialChecklist && (data.type !== 'join' && data.type !== 'notjoin')) {
+                    throw '清单设置功能已启动,请前往清单设置页操作清单内容';
+                }
                 switch (data.type) {
                 switch (data.type) {
                     case 'add':
                     case 'add':
                         responseData.data = await ctx.service.materialList.add(data.postData);
                         responseData.data = await ctx.service.materialList.add(data.postData);
@@ -636,7 +681,7 @@ module.exports = app => {
                         responseData.data.m_tp = await ctx.service.materialBills.del(data.id);
                         responseData.data.m_tp = await ctx.service.materialBills.del(data.id);
                         break;
                         break;
                     case 'changeOrder':
                     case 'changeOrder':
-                        responseData.data = await ctx.service.materialBills.changeOrder(data.id1, data.id2);
+                        await ctx.service.materialBills.changeOrder(data.id1, data.id2);
                         break;
                         break;
                     case 'update':
                     case 'update':
                         if (data.updateData.code === '' || data.updateData.code === null) {
                         if (data.updateData.code === '' || data.updateData.code === null) {
@@ -672,7 +717,7 @@ module.exports = app => {
                         // 更新quantity值并重新返回计算本期金额,截止本期金额
                         // 更新quantity值并重新返回计算本期金额,截止本期金额
                         const updateData = {
                         const updateData = {
                             id: data.id,
                             id: data.id,
-                            quantity: quantity !== 0 ? this.ctx.helper.round(quantity, 3) : null,
+                            quantity: quantity !== 0 ? ctx.helper.round(quantity, ctx.material.decimal.qty) : null,
                             expr: data.expr,
                             expr: data.expr,
                         };
                         };
                         responseData.data = await ctx.service.materialBills.updateFYQuantity(updateData);
                         responseData.data = await ctx.service.materialBills.updateFYQuantity(updateData);
@@ -691,7 +736,7 @@ module.exports = app => {
                         break;
                         break;
                     default: throw '参数有误';
                     default: throw '参数有误';
                 }
                 }
-                if (this.ctx.material.material_tax) {
+                if (ctx.material.material_tax) {
                     responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
                     responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
                 }
                 }
                 ctx.body = responseData;
                 ctx.body = responseData;
@@ -716,8 +761,13 @@ module.exports = app => {
                 };
                 };
                 const monthList = await ctx.service.materialMonth.getListByMid(ctx.material.id);
                 const monthList = await ctx.service.materialMonth.getListByMid(ctx.material.id);
                 const mbList = await this._getMaterialBillsData(ctx);
                 const mbList = await this._getMaterialBillsData(ctx);
+                const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];
                 switch (data.type) {
                 switch (data.type) {
                     case 'add':
                     case 'add':
+                        // 判断是否已存在该月份
+                        if (ctx.app._.indexOf(material_month, data.updateData.yearmonth) !== -1) {
+                            throw '调差期已创建过本月的信息价,请刷新页面重新获取';
+                        }
                         const tp = await ctx.service.materialMonth.add(data.updateData, monthList, mbList);
                         const tp = await ctx.service.materialMonth.add(data.updateData, monthList, mbList);
                         const materialBillsData = await this._getMaterialBillsData(ctx);
                         const materialBillsData = await this._getMaterialBillsData(ctx);
                         const monthsList = await this._getMaterialMonthsData(ctx, materialBillsData);
                         const monthsList = await this._getMaterialMonthsData(ctx, materialBillsData);
@@ -727,6 +777,10 @@ module.exports = app => {
                         };
                         };
                         break;
                         break;
                     case 'del':
                     case 'del':
+                        // 判断是否已不存在该月份
+                        if (ctx.app._.intersection(data.updateData.del_yearmonth, material_month).length !== data.updateData.del_yearmonth.length) {
+                            throw '调差期已删除本月的信息价,请刷新页面重新获取';
+                        }
                         const tp2 = await ctx.service.materialMonth.del(data.updateData.del_yearmonth, monthList, mbList);
                         const tp2 = await ctx.service.materialMonth.del(data.updateData.del_yearmonth, monthList, mbList);
                         const materialBillsData2 = await this._getMaterialBillsData(ctx);
                         const materialBillsData2 = await this._getMaterialBillsData(ctx);
                         const monthsList2 = await this._getMaterialMonthsData(ctx, materialBillsData2);
                         const monthsList2 = await this._getMaterialMonthsData(ctx, materialBillsData2);
@@ -755,7 +809,7 @@ module.exports = app => {
                         break;
                         break;
                     default: throw '参数有误';
                     default: throw '参数有误';
                 }
                 }
-                if (this.ctx.material.material_tax) {
+                if (ctx.material.material_tax) {
                     responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
                     responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
                 }
                 }
                 responseData.data.materialBillsData = await this._getMaterialBillsData(ctx);
                 responseData.data.materialBillsData = await this._getMaterialBillsData(ctx);
@@ -1186,6 +1240,122 @@ module.exports = app => {
                 ctx.body = responseData;
                 ctx.body = responseData;
             }
             }
         }
         }
+
+        async _setChecklistPermission(ctx) {
+            // 清单设置权限判断
+            ctx.material.checklistPermission = false;
+            if (ctx.session.sessionProject.page_show.openMaterialChecklist && ctx.material.highOrder === ctx.material.order && ctx.material.status !== auditConst.status.checked) {
+                const permission = ctx.session.sessionUser.permission;
+                if ((permission.tender !== undefined && permission.tender.indexOf('4') !== -1) || (ctx.material.order === 1 && ctx.session.sessionUser.accountId === ctx.material.user_id && (ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo))) {
+                    ctx.material.checklistPermission = true;
+                }
+            }
+        }
+
+        /**
+         * 清单设置页
+         * @param {Object} ctx - 全局上下文
+         */
+        async checklist(ctx) {
+            try {
+                await this._getMaterialAuditViewData(ctx);
+                await this._setChecklistPermission(ctx);
+                ctx.material.readOnly = !ctx.material.checklistPermission;
+                const renderData = await this._getDefaultRenderData(ctx);
+                // 根据期判断需要获取的工料信息值表
+                const searchsql = { tid: ctx.tender.id };
+                let midList = [];
+                if (ctx.material.highOrder !== ctx.material.order) {
+                    midList = await ctx.service.material.getPreMidList(ctx.tender.id, ctx.material.order);
+                    searchsql.mid = midList;
+                }
+                searchsql.t_type = materialConst.t_type[0].value;
+                renderData.materialBillsData = await ctx.service.materialBills.getAllDataByCondition({ where: searchsql, orders: [['order', 'asc']] });
+                // 取对应期的截取上期的调差金额和应耗数量
+                if (ctx.material.highOrder !== ctx.material.order) {
+                    for (const [mindex, mb] of renderData.materialBillsData.entries()) {
+                        const result = await ctx.service.materialBillsHistory.getByMbId(ctx.material.id, ctx.material.order, mb.id);
+                        _.forEach(result, function(value, key) {
+                            if (key === 'mb_id') {
+                                renderData.materialBillsData[mindex].id = result ? result[key] : null;
+                            } else {
+                                renderData.materialBillsData[mindex][key] = result ? result[key] : null;
+                            }
+                        });
+                    }
+                }
+                // 取所有已被调用的工料清单表
+                // renderData.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
+                // renderData.materialNotJoinListData = await ctx.service.materialListNotjoin.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } });
+                renderData.materialType = JSON.stringify(materialConst);
+                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.checklist);
+                // 获取清单数据
+                // renderData.ledger = await ctx.service.ledger.getData(ctx.tender.id);
+                // renderData.pos = await ctx.service.pos.getPosData({ tid: ctx.tender.id });
+                // 获取所选期数据并合并相加同类清单项
+                // renderData.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, ctx.material.stage_id);
+                // renderData.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, ctx.material.stage_id, 'list');
+                await this.layout('material/checklist.ejs', renderData, 'material/checklist_modal.ejs');
+            } catch (err) {
+                this.log(err);
+                ctx.redirect('/tender/' + ctx.tender.id + '/measure/material');
+            }
+        }
+
+        /**
+         * 清单设置 - 编辑指数清单项 (Ajax)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveChecklistData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = {
+                    err: 0,
+                    msg: '',
+                    data: {},
+                };
+                await this._setChecklistPermission(ctx);
+                if (ctx.material.order !== ctx.material.highOrder) {
+                    throw '无法设置非最新期的清单设置数据';
+                }
+                // 权限控制
+                if (!ctx.material.checklistPermission && data.type !== 'resetChecklist') {
+                    throw '本期已审批完成或权限不足,无法设置清单数据';
+                }
+                switch (data.type) {
+                    case 'adds':
+                        responseData.data = await ctx.service.materialList.adds(data.postData, data.checklist);
+                        break;
+                    case 'dels':
+                        responseData.data = await ctx.service.materialList.dels(data.postData, data.checklist);
+                        break;
+                    case 'updates':
+                        if (data.updateData.quantity === '' || data.updateData.quantity === null) {
+                            throw '请输入数量';
+                        }
+                        // 判断数量是否为数字
+                        if (isNaN(data.updateData.quantity)) {
+                            throw '不能输入其它非数字类型字符';
+                        }
+                        responseData.data = await ctx.service.materialList.saves(data.updateData);
+                        break;
+                    case 'pastes':
+                        responseData.data = await ctx.service.materialList.savePastes(data.updateData);
+                        // 取所有工料表
+                        break;
+                    case 'resetChecklist':
+                        responseData.data = await ctx.service.materialChecklist.resetData(data.pushData, data.removeData, data.updateData);
+                        break;
+                    default: throw '参数有误';
+                }
+
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
     }
     }
 
 
     return MaterialController;
     return MaterialController;

+ 22 - 13
app/controller/revise_controller.js

@@ -461,7 +461,8 @@ module.exports = app => {
                         }
                         }
                     }
                     }
                 }
                 }
-                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos } };
+                const ledgerTags = await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
+                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos, tags: ledgerTags } };
             } catch (err) {
             } catch (err) {
                 ctx.helper.log(err);
                 ctx.helper.log(err);
                 this.ajaxErrorBody(err, '加载台账修订数据错误');
                 this.ajaxErrorBody(err, '加载台账修订数据错误');
@@ -496,11 +497,8 @@ module.exports = app => {
 
 
         async history(ctx) {
         async history(ctx) {
             try {
             try {
-                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id, false);
-                if (!revise) throw '台账修订数据有误';
+                const revise = ctx.revise;
 
 
-                // const reviseBills = await ctx.service.ledger.getData(ctx.tender.id);
-                // const revisePos = await ctx.service.pos.getPosData({tid: ctx.tender.id});
                 const [ledgerSpread, posSpread] = this._getSpreadSetting(revise);
                 const [ledgerSpread, posSpread] = this._getSpreadSetting(revise);
                 const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
                 const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
@@ -521,7 +519,6 @@ module.exports = app => {
                 const renderData = {
                 const renderData = {
                     measureType, audit, revise,
                     measureType, audit, revise,
                     ledgerSpread, posSpread,
                     ledgerSpread, posSpread,
-                    // reviseBills, revisePos,
                     readOnly: true,
                     readOnly: true,
                     historyRevise,
                     historyRevise,
                     auditHistory,
                     auditHistory,
@@ -556,15 +553,14 @@ module.exports = app => {
          */
          */
         async loadHistoryData(ctx) {
         async loadHistoryData(ctx) {
             try {
             try {
-                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id, false);
-                if (!revise) throw '台账修订数据有误';
-
-                const reviseBills = await ctx.service.ledger.getData(ctx.tender.id);
-                const revisePos = await ctx.service.pos.getPosData({ tid: ctx.tender.id });
+                const billsFile = await this.ctx.app.hisOss.get(ctx.app.config.hisOssPath + ctx.revise.bills_file);
+                const reviseBills = JSON.parse(billsFile.content);
+                const posFile = await this.ctx.app.hisOss.get(ctx.app.config.hisOssPath + ctx.revise.pos_file);
+                const revisePos = JSON.parse(posFile.content);
                 ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos } };
                 ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos } };
             } catch (error) {
             } catch (error) {
                 ctx.helper.log(error);
                 ctx.helper.log(error);
-                this.ajaxErrorBody(error, '获取台账修订数据错误,请刷新页面');
+                this.ajaxErrorBody(error, '获取台账修订数据错误');
             }
             }
         }
         }
 
 
@@ -1011,8 +1007,12 @@ module.exports = app => {
                 case 'dealBills': return await ctx.service.dealBills.getAllDataByCondition({where: {tender_id: ctx.tender.id}});
                 case 'dealBills': return await ctx.service.dealBills.getAllDataByCondition({where: {tender_id: ctx.tender.id}});
                 case 'spec':
                 case 'spec':
                     const spec = {zlj: stdConst.zlj, jrg: stdConst.jrg};
                     const spec = {zlj: stdConst.zlj, jrg: stdConst.jrg};
-                    spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;;
+                    spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
                     return spec;
                     return spec;
+                case 'tags':
+                    return await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
+                case 'price':
+                    return await this.ctx.service.revisePriceChange.getAllDataByCondition({ where: { rid: ctx.revise.id } });
             }
             }
         }
         }
 
 
@@ -1057,6 +1057,15 @@ module.exports = app => {
             };
             };
             await this.layout('revise/bwtz.ejs', renderData);
             await this.layout('revise/bwtz.ejs', renderData);
         }
         }
+
+        async price(ctx) {
+            if (!ctx.revise) throw '台账修订数据有误';
+            const renderData = {
+                revise: ctx.revise,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.price)
+            };
+            await this.layout('revise/price.ejs', renderData);
+        }
     }
     }
 
 
     return ReviseController;
     return ReviseController;

+ 21 - 2
app/controller/setting_controller.js

@@ -763,7 +763,10 @@ module.exports = app => {
 
 
                 const result = await ctx.service.project.updateFunRela(projectId, ctx.request.body);
                 const result = await ctx.service.project.updateFunRela(projectId, ctx.request.body);
                 if (!result) throw '保存数据失败';
                 if (!result) throw '保存数据失败';
-                const result2 = await ctx.service.project.updatePageshow(projectId, ctx.request.body);
+                // this.ctx.session.sessionProject.page_show.openChangeRevise = data.openChangeRevise ? 1 : 0;
+                this.ctx.session.sessionProject.page_show.openMaterialTax = data.openMaterialTax ? 1 : 0;
+                this.ctx.session.sessionProject.page_show.openMaterialChecklist = data.openMaterialChecklist ? 1 : 0;
+                const result2 = await ctx.service.project.updatePageshow(projectId);
                 if (!result2) throw '保存数据失败';
                 if (!result2) throw '保存数据失败';
 
 
                 ctx.body = { err: 0, msg: '', data: null };
                 ctx.body = { err: 0, msg: '', data: null };
@@ -857,6 +860,7 @@ module.exports = app => {
                 await this._checkMenu(projectId);
                 await this._checkMenu(projectId);
                 const projectData = await ctx.service.project.getDataById(projectId);
                 const projectData = await ctx.service.project.getDataById(projectId);
                 if (projectData === null) throw '没有对应的项目数据';
                 if (projectData === null) throw '没有对应的项目数据';
+                projectData.data_collect_pages = projectData.data_collect_pages ? projectData.data_collect_pages.split(',') : [];
                 if (ctx.session.sessionUser.is_admin === 0) throw '没有访问权限';
                 if (ctx.session.sessionUser.is_admin === 0) throw '没有访问权限';
                 const dataCollectAudits = await ctx.service.datacollectAudit.getList(projectId);
                 const dataCollectAudits = await ctx.service.datacollectAudit.getList(projectId);
                 // 获取所有项目参与者
                 // 获取所有项目参与者
@@ -869,12 +873,16 @@ module.exports = app => {
                     return { groupName: item, groupList };
                     return { groupName: item, groupList };
                 });
                 });
                 const categoryData = await ctx.service.category.getAllCategory(ctx.session.sessionProject.id);
                 const categoryData = await ctx.service.category.getAllCategory(ctx.session.sessionProject.id);
+                const tenders = await ctx.service.tender.getList('', null, 1);
+                const dcTenders = await ctx.service.datacollectTender.getList(projectId);
                 await this.layout('setting/datacollect.ejs', {
                 await this.layout('setting/datacollect.ejs', {
                     projectData,
                     projectData,
                     dataCollectAudits,
                     dataCollectAudits,
                     accountList,
                     accountList,
                     accountGroup: accountGroupList,
                     accountGroup: accountGroupList,
                     categoryData,
                     categoryData,
+                    tenders,
+                    dcTenders,
                 }, 'setting/datacollect_modal.ejs');
                 }, 'setting/datacollect_modal.ejs');
             } catch (error) {
             } catch (error) {
                 ctx.helper.log(error);
                 ctx.helper.log(error);
@@ -896,7 +904,7 @@ module.exports = app => {
                 }
                 }
                 switch (data.type) {
                 switch (data.type) {
                     case 'show':
                     case 'show':
-                        responseData.data = await ctx.service.project.update({ data_collect: data.data_collect }, { id: projectId });
+                        responseData.data = await ctx.service.project.update({ data_collect: data.data_collect, data_collect_pages: data.data_collect_pages.join(',') }, { id: projectId });
                         ctx.session.sessionProject.dataCollect = data.data_collect;
                         ctx.session.sessionProject.dataCollect = data.data_collect;
                         ctx.session.sessionProject.showDataCollect = data.data_collect ? 1 : 0;
                         ctx.session.sessionProject.showDataCollect = data.data_collect ? 1 : 0;
                         break;
                         break;
@@ -938,6 +946,17 @@ module.exports = app => {
                         await ctx.service.datacollectAudit.delAudit(data.id);
                         await ctx.service.datacollectAudit.delAudit(data.id);
                         responseData.data = await ctx.service.datacollectAudit.getList(projectId);
                         responseData.data = await ctx.service.datacollectAudit.getList(projectId);
                         break;
                         break;
+                    case 'tender':
+                        if (ctx.session.sessionProject.page_show.addDataCollect !== parseInt(data.add_datacollect)) {
+                            ctx.session.sessionProject.page_show.addDataCollect = parseInt(data.add_datacollect);
+                            await ctx.service.project.updatePageshow(projectId);
+                        }
+                        await ctx.service.datacollectTender.updateList(projectId, data.tids);
+                        responseData.data = {
+                            dcTenders: await ctx.service.datacollectTender.getList(projectId),
+                            addDatacollect: ctx.session.sessionProject.page_show.addDataCollect,
+                        };
+                        break;
                     default: throw '参数有误';
                     default: throw '参数有误';
                 }
                 }
                 ctx.body = responseData;
                 ctx.body = responseData;

+ 0 - 1
app/controller/stage_controller.js

@@ -787,7 +787,6 @@ module.exports = app => {
                 const result = await ctx.service.stageDetailAtt.addFiles(this.ctx.stage, baseInfo, uploadFiles);
                 const result = await ctx.service.stageDetailAtt.addFiles(this.ctx.stage, baseInfo, uploadFiles);
                 ctx.body = { err: 0, mgs: '', data: result };
                 ctx.body = { err: 0, mgs: '', data: result };
             } catch (err) {
             } catch (err) {
-                console.log(err);
                 // 失败需要消耗掉stream 以防卡死
                 // 失败需要消耗掉stream 以防卡死
                 if (stream) await sendToWormhole(stream);
                 if (stream) await sendToWormhole(stream);
                 ctx.log(err);
                 ctx.log(err);

+ 33 - 14
app/controller/tender_controller.js

@@ -130,14 +130,9 @@ module.exports = app => {
                     const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(t.id);
                     const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(t.id);
                     t.contract_price = tenderInfo.deal_param.contractPrice;
                     t.contract_price = tenderInfo.deal_param.contractPrice;
 
 
-                    if (t.user_id === this.ctx.session.sessionUser.accountId && (
-                        t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
-                        const sum = await this.ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
-                        t.total_price = sum.total_price;
-                        t.deal_tp = sum.deal_tp;
-                    }
+                    let bCalcTp = t.user_id === this.ctx.session.sessionUser.accountId && (
+                        t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck);
                     t.advance_tp = await this.ctx.service.advance.getSumAdvance(t.id);
                     t.advance_tp = await this.ctx.service.advance.getSumAdvance(t.id);
-
                     if (t.ledger_status === auditConst.ledger.status.checked) {
                     if (t.ledger_status === auditConst.ledger.status.checked) {
                         t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, true);
                         t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, true);
                         if (t.lastStage && t.lastStage.status === auditConst.stage.status.uncheck &&
                         if (t.lastStage && t.lastStage.status === auditConst.stage.status.uncheck &&
@@ -146,6 +141,15 @@ module.exports = app => {
                         }
                         }
                         if (t.lastStage) await this.ctx.service.stage.checkStageGatherData(t.lastStage);
                         if (t.lastStage) await this.ctx.service.stage.checkStageGatherData(t.lastStage);
                         t.completeStage = await this.ctx.service.stage.getLastestCompleteStage(t.id);
                         t.completeStage = await this.ctx.service.stage.getLastestCompleteStage(t.id);
+                        if ((!bCalcTp) && t.measure_type === measureType.gcl.value) {
+                            bCalcTp = t.lastStage && t.lastStage.status !== auditConst.stage.status.checked && !t.lastStage.readOnly;
+                        }
+                    }
+
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
+                        t.total_price = sum.total_price;
+                        t.deal_tp = sum.deal_tp;
                     }
                     }
 
 
                     if (t.lastStage) {
                     if (t.lastStage) {
@@ -390,16 +394,22 @@ module.exports = app => {
         async tenderInfo(ctx) {
         async tenderInfo(ctx) {
             try {
             try {
                 const tender = ctx.tender.data;
                 const tender = ctx.tender.data;
-                if (tender.user_id === this.ctx.session.sessionUser.accountId && (
-                    tender.ledger_status === auditConst.ledger.status.checkNo || tender.ledger_status === auditConst.ledger.status.uncheck)) {
-                    const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
-                    tender.total_price = sum.total_price;
-                    tender.deal_tp = sum.deal_tp;
-                }
+                let bCalcTp = tender.user_id === this.ctx.session.sessionUser.accountId && (
+                    tender.ledger_status === auditConst.ledger.status.checkNo || tender.ledger_status === auditConst.ledger.status.uncheck);
                 const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
                 const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
                 const lastStage = stages.length > 0 ? stages[0] : null; // await ctx.service.stage.getLastestStage(ctx.tender.id);
                 const lastStage = stages.length > 0 ? stages[0] : null; // await ctx.service.stage.getLastestStage(ctx.tender.id);
                 if (lastStage) {
                 if (lastStage) {
                     await this.ctx.service.stage.checkStageGatherData(lastStage);
                     await this.ctx.service.stage.checkStageGatherData(lastStage);
+
+                    if ((!bCalcTp) && tender.measure_type === measureType.gcl.value) {
+                        bCalcTp = lastStage.status !== auditConst.stage.status.checked && !lastStage.readOnly;
+                    }
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
+                        tender.total_price = sum.total_price;
+                        tender.deal_tp = sum.deal_tp;
+                    }
+
                     tender.gather_tp = ctx.helper.add(lastStage.contract_tp, lastStage.qc_tp);
                     tender.gather_tp = ctx.helper.add(lastStage.contract_tp, lastStage.qc_tp);
                     tender.end_contract_tp = ctx.helper.add(lastStage.contract_tp, lastStage.pre_contract_tp);
                     tender.end_contract_tp = ctx.helper.add(lastStage.contract_tp, lastStage.pre_contract_tp);
                     tender.end_qc_tp = ctx.helper.add(lastStage.qc_tp, lastStage.pre_qc_tp);
                     tender.end_qc_tp = ctx.helper.add(lastStage.qc_tp, lastStage.pre_qc_tp);
@@ -436,6 +446,12 @@ module.exports = app => {
                         lastStage.auditors = await ctx.service.stageAudit.getFinalAuditGroup(lastStage.id, times);
                         lastStage.auditors = await ctx.service.stageAudit.getFinalAuditGroup(lastStage.id, times);
                     }
                     }
                 } else {
                 } else {
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
+                        tender.total_price = sum.total_price;
+                        tender.deal_tp = sum.deal_tp;
+                    }
+
                     if (tender.ledger_status !== auditConst.ledger.status.uncheck) {
                     if (tender.ledger_status !== auditConst.ledger.status.uncheck) {
                         const status_name = await this.ctx.service.ledgerAudit.getStatusName(tender.id, tender.ledger_times);
                         const status_name = await this.ctx.service.ledgerAudit.getStatusName(tender.id, tender.ledger_times);
                         tender.status_users = status_name ? status_name.name : '';
                         tender.status_users = status_name ? status_name.name : '';
@@ -446,6 +462,7 @@ module.exports = app => {
                         tender.status_users = status_name ? status_name.name : '';
                         tender.status_users = status_name ? status_name.name : '';
                     }
                     }
                 }
                 }
+
                 const tiModel = new tenderInfoModel(ctx);
                 const tiModel = new tenderInfoModel(ctx);
                 const gclChapter = await tiModel.gatherChapter();
                 const gclChapter = await tiModel.gatherChapter();
 
 
@@ -974,7 +991,6 @@ module.exports = app => {
                     await ctx.service.ledgerCooperation.changeAllStatus(status);
                     await ctx.service.ledgerCooperation.changeAllStatus(status);
                 }
                 }
                 // }
                 // }
-                // console.log(postData);
                 await ctx.service.tenderInfo.saveTenderInfo(ctx.tender.id, { shenpi: postData });
                 await ctx.service.tenderInfo.saveTenderInfo(ctx.tender.id, { shenpi: postData });
                 let auditList = [];
                 let auditList = [];
                 if (data.status === shenpiConst.sp_status.gdspl) {
                 if (data.status === shenpiConst.sp_status.gdspl) {
@@ -1137,6 +1153,9 @@ module.exports = app => {
                 if (ctx.stage) {
                 if (ctx.stage) {
                     const isAuditor = ctx.stage.users.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     const isAuditor = ctx.stage.users.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
+                } else if (ctx.revise) {
+                    const isAuditor = ctx.revise.reviseUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
+                    if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                 } else {
                 } else {
                     const isAuditor = ctx.tender.ledgerUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     const isAuditor = ctx.tender.ledgerUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';

+ 39 - 6
app/extend/helper.js

@@ -23,7 +23,8 @@ const UAParser = require('ua-parser-js');
 const math = require('mathjs');
 const math = require('mathjs');
 const syncApiConst = require('../const/sync_api');
 const syncApiConst = require('../const/sync_api');
 const crypto = require('crypto');
 const crypto = require('crypto');
-
+const jwt = require('jsonwebtoken');
+const sign = require('../const/sign');
 module.exports = {
 module.exports = {
     _,
     _,
 
 
@@ -430,7 +431,7 @@ module.exports = {
         } else if (!str2) {
         } else if (!str2) {
             return -1;
             return -1;
         }
         }
-
+        const numReg = /^[0-9]+$/;
         function compareSubCode(code1, code2) {
         function compareSubCode(code1, code2) {
             if (numReg.test(code1)) {
             if (numReg.test(code1)) {
                 if (numReg.test(code2)) {
                 if (numReg.test(code2)) {
@@ -443,10 +444,7 @@ module.exports = {
                 return 1;
                 return 1;
             }
             }
             return code1 === code2 ? 0 : (code1 < code2 ? -1 : 1); // code1.localeCompare(code2);
             return code1 === code2 ? 0 : (code1 < code2 ? -1 : 1); // code1.localeCompare(code2);
-
-
         }
         }
-        const numReg = /^[0-9]+$/;
         const aCodes = str1.split(symbol),
         const aCodes = str1.split(symbol),
             bCodes = str2.split(symbol);
             bCodes = str2.split(symbol);
         for (let i = 0, iLength = Math.min(aCodes.length, bCodes.length); i < iLength; ++i) {
         for (let i = 0, iLength = Math.min(aCodes.length, bCodes.length); i < iLength; ++i) {
@@ -889,7 +887,8 @@ module.exports = {
         for (let i = 0; i < l.length; i++) {
         for (let i = 0; i < l.length; i++) {
             t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
             t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
         }
         }
-        return t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+        const num = t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+        return num.replace('-,', '-');
     },
     },
 
 
     transFormToChinese(num) {
     transFormToChinese(num) {
@@ -1290,6 +1289,31 @@ module.exports = {
         return result;
         return result;
     },
     },
 
 
+    filterLastestData2(data, keyFields, timesField = 'times', orderField = 'order') {
+        const dataIndex = {};
+        for (const d of data) {
+            let key = 'd';
+            for (const kf of keyFields) {
+                key = key + '.' + (d[kf] || '');
+            }
+
+            if (!dataIndex[key]) dataIndex[key] = { index: 0, source: [] };
+            const di = dataIndex[key];
+            const curIndex = d[timesField] * timesLen + d[orderField];
+            if (curIndex === di.index) {
+                di.source.push(d);
+            } else if (curIndex > di.index) {
+                di.index = curIndex;
+                di.source = [d];
+            }
+        }
+        const result = [];
+        for (const prop in dataIndex) {
+            result.push(...dataIndex[prop].source);
+        }
+        return result;
+    },
+
     calcExpr(expr) {
     calcExpr(expr) {
         const validExpr = expr.replace('=', '').replace('%', '/100');
         const validExpr = expr.replace('=', '').replace('%', '/100');
         return math.eval(validExpr);
         return math.eval(validExpr);
@@ -1439,4 +1463,13 @@ module.exports = {
         const endMonth = moment(month).endOf('month').format('YYYY-MM-DD HH:mm:ss');
         const endMonth = moment(month).endOf('month').format('YYYY-MM-DD HH:mm:ss');
         return [startMonth, endMonth];
         return [startMonth, endMonth];
     },
     },
+
+    /**
+     * 创建json web token
+     * @param {Object} data - 签名数据
+     * @return {String} token
+     */
+    createJWT(data) {
+        return jwt.sign({ data }, sign.managementApiSecretKey, { expiresIn: '15s' });
+    },
 };
 };

+ 1 - 0
app/lib/analysis_excel.js

@@ -292,6 +292,7 @@ class ImportBaseTree {
             pos.lid = this.finalNode.id;
             pos.lid = this.finalNode.id;
             pos.tid = this.ctx.tender.id;
             pos.tid = this.ctx.tender.id;
             pos.add_stage = 0;
             pos.add_stage = 0;
+            pos.add_stage_order = 0;
             pos.add_times = 0;
             pos.add_times = 0;
             pos.in_time = new Date();
             pos.in_time = new Date();
             pos.porder = this.finalNode.pos.length + 1;
             pos.porder = this.finalNode.pos.length + 1;

+ 1 - 1
app/middleware/advance_check.js

@@ -56,7 +56,7 @@ module.exports = () => {
             if ((advance.status === status.uncheck || advance.status === status.checkNo) && this.tender.info.shenpi.advance !== shenpiConst.sp_status.sqspr) {
             if ((advance.status === status.uncheck || advance.status === status.checkNo) && this.tender.info.shenpi.advance !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.advance;
                 const shenpi_status = this.tender.info.shenpi.advance;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.advanceAudit.getAllDataByCondition({ where: { vid: advance.id, times: advance.times } });
+                const auditList = yield this.service.advanceAudit.getAllDataByCondition({ where: { vid: advance.id, times: advance.times }, orders: [['order', 'asc']] });
                 const auditIdList = _.map(auditList, 'audit_id');
                 const auditIdList = _.map(auditList, 'audit_id');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status } });
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status } });

+ 56 - 0
app/middleware/api3management_check.js

@@ -0,0 +1,56 @@
+'use strict';
+
+/**
+ *
+ * @author LanJianRong
+ * @date  2021-12-27
+ * @version
+ */
+const maintainConst = require('../const/maintain');
+const sign = require('../const/sign');
+const jwt = require('jsonwebtoken');
+module.exports = options => {
+    return function* api3managementCheck(next) {
+        try {
+            // 获取系统维护信息
+            const maintainData = yield this.service.maintain.getDataById(1);
+            if (maintainData.status === maintainConst.status.ongoing) {
+                throw '系统维护中~';
+            }
+            const token = this.query.auth;
+            if (!token) {
+                throw '参数有误';
+            }
+            try {
+                const decoded = jwt.verify(token, sign.managementApiSecretKey);
+                if (!decoded.data) throw '参数有误';
+                this.data = decoded.data;
+            } catch (error) {
+                throw error;
+            }
+            // const data = yield this.service.project.getProjectByCode(code.toString().trim());
+            // if (data === null) {
+            //     throw '不存在项目数据';
+            // }
+            // if (data.custom === 0) {
+            //     throw '无法通过接口登录本系统';
+            // }
+            // if (data.custom === 1 && data.can_api === 0) {
+            //     throw '接口已关闭,无法使用';
+            // }
+            // const encryptSign = crypto.createHash('md5').update(data.code + data.secret + time.toString()).digest('hex').toString();
+            // if (encryptSign !== sign) {
+            //     throw '参数验证失败';
+            // }
+            // this.projectData = data;
+            yield next;
+        } catch (err) {
+            this.body = {
+                code: -1,
+                msg: err.toString(),
+                data: null,
+            };
+            return;
+        }
+    };
+};

+ 4 - 1
app/middleware/change_check.js

@@ -61,8 +61,11 @@ module.exports = options => {
             } else { // 其他不可见
             } else { // 其他不可见
                 throw '您无权查看该数据';
                 throw '您无权查看该数据';
             }
             }
-
             this.change = change;
             this.change = change;
+            if ((change.status === status.uncheck || change.status === status.back || change.status === status.revise) && change.tp_decimal !== this.tender.info.decimal.tp) {
+                this.change.tp_decimal = this.tender.info.decimal.tp;
+                yield this.service.change.updateDecimalAndTp();
+            }
             yield next;
             yield next;
         } catch (err) {
         } catch (err) {
             console.log(err);
             console.log(err);

+ 1 - 1
app/middleware/ledger_audit_check.js

@@ -26,7 +26,7 @@ module.exports = options => {
             if ((this.tender.data.ledger_status === status.uncheck || this.tender.data.ledger_status === status.checkNo) && this.tender.info.shenpi.ledger !== shenpiConst.sp_status.sqspr) {
             if ((this.tender.data.ledger_status === status.uncheck || this.tender.data.ledger_status === status.checkNo) && this.tender.info.shenpi.ledger !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.ledger;
                 const shenpi_status = this.tender.info.shenpi.ledger;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.ledgerAudit.getAllDataByCondition({ where: { tender_id: this.tender.id, times: this.tender.data.ledger_times } });
+                const auditList = yield this.service.ledgerAudit.getAllDataByCondition({ where: { tender_id: this.tender.id, times: this.tender.data.ledger_times }, orders: [['audit_order', 'asc']] });
                 const auditIdList = _.map(auditList, 'audit_id');
                 const auditIdList = _.map(auditList, 'audit_id');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });

+ 4 - 1
app/middleware/material_check.js

@@ -128,7 +128,7 @@ module.exports = options => {
             if ((material.status === status.uncheck || material.status === status.checkNo) && this.tender.info.shenpi.material !== shenpiConst.sp_status.sqspr) {
             if ((material.status === status.uncheck || material.status === status.checkNo) && this.tender.info.shenpi.material !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.material;
                 const shenpi_status = this.tender.info.shenpi.material;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.materialAudit.getAllDataByCondition({ where: { mid: material.id, times: material.times } });
+                const auditList = yield this.service.materialAudit.getAllDataByCondition({ where: { mid: material.id, times: material.times }, orders: [['order', 'asc']] });
                 const auditIdList = _.map(auditList, 'aid');
                 const auditIdList = _.map(auditList, 'aid');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: material.tid, sp_type: shenpiConst.sp_type.material, sp_status: shenpi_status } });
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: material.tid, sp_type: shenpiConst.sp_type.material, sp_status: shenpi_status } });
@@ -163,6 +163,9 @@ module.exports = options => {
                 }));
                 }));
             }
             }
             // 重定向值标段管理
             // 重定向值标段管理
+            if (err === '您无权查看该数据') {
+                this.tender ? this.redirect('/tender/' + this.tender.id + '/measure/material') : this.redirect('/list');
+            }
             this.redirect(this.request.headers.referer);
             this.redirect(this.request.headers.referer);
         }
         }
     };
     };

+ 1 - 1
app/middleware/revise_audit_check.js

@@ -29,7 +29,7 @@ module.exports = options => {
             if ((revise.status === status.uncheck || revise.status === status.checkNo) && this.tender.info.shenpi.revise !== shenpiConst.sp_status.sqspr) {
             if ((revise.status === status.uncheck || revise.status === status.checkNo) && this.tender.info.shenpi.revise !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.revise;
                 const shenpi_status = this.tender.info.shenpi.revise;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.reviseAudit.getAllDataByCondition({ where: { rid: revise.id, times: revise.times } });
+                const auditList = yield this.service.reviseAudit.getAllDataByCondition({ where: { rid: revise.id, times: revise.times }, orders: [['audit_order', 'asc']] });
                 const auditIdList = _.map(auditList, 'audit_id');
                 const auditIdList = _.map(auditList, 'audit_id');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.revise, sp_status: shenpi_status } });
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.revise, sp_status: shenpi_status } });

+ 15 - 2
app/middleware/revise_check.js

@@ -8,6 +8,7 @@
  * @version
  * @version
  */
  */
 
 
+const auditConst = require('../const/audit').revise;
 module.exports = options => {
 module.exports = options => {
     /**
     /**
      * 标段校验 中间件
      * 标段校验 中间件
@@ -17,10 +18,22 @@ module.exports = options => {
      * @param {function} next - 中间件继续执行的方法
      * @param {function} next - 中间件继续执行的方法
      * @return {void}
      * @return {void}
      */
      */
-    return function* reviseAuditCheck(next) {
+    return function* reviseCheck(next) {
         try {
         try {
             // 获取revise
             // 获取revise
-            this.revise = yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
+            const revise = this.params.rid
+                ? yield this.service.ledgerRevise.getRevise(this.tender.id, this.params.rid)
+                : yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
+            if (!revise) throw '台账修订数据有误';
+            revise.reviseUsers = [revise.uid];
+            if (revise.status !== auditConst.status.uncheck) {
+                const times = revise.status === auditConst.status.checkNo ? revise.times - 1 : revise.times;
+                const auditors = yield this.service.reviseAudit.getAuditors(revise.id, times);
+                const auditorsId = this.helper._.map(auditors, 'audit_id');
+                revise.reviseUsers.push(...auditorsId);
+            }
+            revise.readOnly = revise.status === auditConst.status.uncheck || revise.status === auditConst.status.checkNo;
+            this.revise = revise;
             yield next;
             yield next;
         } catch (err) {
         } catch (err) {
             // 输出错误到日志
             // 输出错误到日志

+ 1 - 1
app/middleware/stage_check.js

@@ -138,7 +138,7 @@ module.exports = options => {
             if ((stage.status === status.uncheck || stage.status === status.checkNo) && this.tender.info.shenpi.stage !== shenpiConst.sp_status.sqspr) {
             if ((stage.status === status.uncheck || stage.status === status.checkNo) && this.tender.info.shenpi.stage !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.stage;
                 const shenpi_status = this.tender.info.shenpi.stage;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.stageAudit.getAllDataByCondition({ where: { sid: stage.id, times: stage.times } });
+                const auditList = yield this.service.stageAudit.getAllDataByCondition({ where: { sid: stage.id, times: stage.times }, orders: [['order', 'asc']] });
                 const auditIdList = _.map(auditList, 'aid');
                 const auditIdList = _.map(auditList, 'aid');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: stage.tid, sp_type: shenpiConst.sp_type.stage, sp_status: shenpi_status } });
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: stage.tid, sp_type: shenpiConst.sp_type.stage, sp_status: shenpi_status } });

+ 199 - 10
app/public/css/main.css

@@ -506,6 +506,17 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   border:none ;
   border:none ;
   border-bottom:2px solid #fff;
   border-bottom:2px solid #fff;
 }
 }
+.nav-tabs.nav-white-tabs.panel-card-tabs .nav-link{
+  color:#495057;
+}
+.nav-tabs.nav-white-tabs.panel-card-tabs .nav-link.active{
+  color:#495057;
+  border-bottom:2px solid #007bff;
+}
+.nav-tabs.nav-white-tabs.panel-card-tabs .nav-link:hover{
+  color:#007bff;
+  border-bottom:2px solid #007bff;
+}
 .panel-card-header {
 .panel-card-header {
   background-image: linear-gradient(to top, #586579, #2c3237 );
   background-image: linear-gradient(to top, #586579, #2c3237 );
 }
 }
@@ -785,6 +796,9 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   padding:1px;
   padding:1px;
   background:#fff;
   background:#fff;
 }
 }
+.c-body-white{
+  background: #e4e7ea;
+}
 .right-nav{
 .right-nav{
   width:36px
   width:36px
 }
 }
@@ -814,6 +828,14 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   height:250px;
   height:250px;
   overflow:auto
   overflow:auto
 }
 }
+.modal-height-150{
+  height: 150px;
+  overflow: auto;
+}
+.modal-height-max150{
+  max-height: 150px;
+  overflow: auto;
+}
 .modal-fullscreen{
 .modal-fullscreen{
   overflow: auto;
   overflow: auto;
 }
 }
@@ -1048,7 +1070,11 @@ label{
   width:120px;
   width:120px;
 }
 }
 .panel-sidebar .scrollbar-auto{
 .panel-sidebar .scrollbar-auto{
-  padding-top:0;
+  padding-top: 0;
+  /*padding-top:35px;*/
+}
+.panel-sidebar .show-back{
+  padding-top: 35px;
 }
 }
 .nav-list li a{
 .nav-list li a{
   padding-right:0px;
   padding-right:0px;
@@ -1512,6 +1538,11 @@ overflow-y: auto;
   font-size: 2.80rem;
   font-size: 2.80rem;
   position: relative;
   position: relative;
 }
 }
+.card .card-approve-title .card-approve-big{
+  position: absolute;
+  left: 45%;
+  bottom: -8px;
+}
 .card .card-approve-title small{
 .card .card-approve-title small{
   position: absolute;
   position: absolute;
   font-size: 0.15rem;
   font-size: 0.15rem;
@@ -1528,7 +1559,7 @@ overflow-y: auto;
   line-height: 200%;
   line-height: 200%;
 }
 }
 .border-bottom-grey-1{
 .border-bottom-grey-1{
-  border-bottom: 1px solid #464647;
+  border-bottom: 1px solid rgba(0,0,0,.125);
 }
 }
 .height-100{
 .height-100{
   height: 100%;
   height: 100%;
@@ -1551,7 +1582,7 @@ overflow-y: auto;
 .height-20{
 .height-20{
   height: 19%;
   height: 19%;
 }
 }
-#review_box{
+#review_box,#review_box2{
   height: 100%;
   height: 100%;
   overflow: hidden;
   overflow: hidden;
 }
 }
@@ -1564,7 +1595,7 @@ overflow-y: auto;
   height: -moz-calc(100% - 53px);
   height: -moz-calc(100% - 53px);
   height: calc(100% - 53px);
   height: calc(100% - 53px);
 }
 }
-#comment1, #comment2{
+#comment1, #comment2, #comment3, #comment4{
   margin: 0;
   margin: 0;
   padding: 0;
   padding: 0;
 }
 }
@@ -1577,16 +1608,17 @@ overflow-y: auto;
   width:100%;
   width:100%;
 }
 }
 .tablebox table th,.tablebox table td {
 .tablebox table th,.tablebox table td {
-  padding: 5px 0;
+  padding: 5px 10px;
 }
 }
 .tablebox table th {
 .tablebox table th {
   color:#fff;
   color:#fff;
+  /*background-color:#fff;*/
   background-color:#2C3034;
   background-color:#2C3034;
 }
 }
 .tablebox table tbody tr{
 .tablebox table tbody tr{
   background-color:#2C3034;
   background-color:#2C3034;
   color: #fff;
   color: #fff;
-  border-bottom: 1px solid #464647;
+  border-bottom: 1px solid rgba(0,0,0,.125);
 }
 }
 .left-small-card-content,.right-small-card-content{
 .left-small-card-content,.right-small-card-content{
   height: 12%;
   height: 12%;
@@ -1681,15 +1713,15 @@ overflow-y: auto;
   transform: translate(-50%, -45%);
   transform: translate(-50%, -45%);
 }
 }
 .left-login{
 .left-login{
-  width: 476px;
-  height: 513px;
+  width: 428px;
+  height: 462px;
   border-radius: 8px;
   border-radius: 8px;
   background: rgba(51, 119, 255, 0.9);
   background: rgba(51, 119, 255, 0.9);
   box-shadow: 6px 0px 6px rgba(0, 0, 0, 0.16);
   box-shadow: 6px 0px 6px rgba(0, 0, 0, 0.16);
 }
 }
 .right-login{
 .right-login{
-  width: 460px;
-  height: 465px;
+  width: 414px;
+  height: 418px;
   border-radius: 0 8px 8px 0;
   border-radius: 0 8px 8px 0;
   background: rgba(255, 255, 255, 1);
   background: rgba(255, 255, 255, 1);
 }
 }
@@ -1719,4 +1751,161 @@ overflow-y: auto;
   font-size: 14px;
   font-size: 14px;
   line-height: 18px;
   line-height: 18px;
   color: rgba(0, 0, 0, 0.6);
   color: rgba(0, 0, 0, 0.6);
+}
+.card-icon{
+  display: inline-block;
+  width: 4px;
+  height: 12px;
+  background: rgba(51, 119, 255, 1);
+}
+.agency-partheight{
+  height: calc((100vh - 155px) / 2);
+  /*background:rgba(82, 196, 26, 1);*/
+}
+.contant-height-one{
+  height: calc(((100vh - 165px) / 2) - 65px);
+  overflow-y: auto;
+}
+.contant-height-two{
+  height: calc(((100vh - 165px) / 2) - 178px);
+  overflow-y: auto;
+}
+.contant-height-three{
+  height: calc(((100vh - 165px) / 2) - 118px);
+  overflow-y: auto;
+}
+.btn-table{
+  width: 70px;
+  text-align: center;
+}
+.bg-new-red{
+  background: rgba(241, 82, 91, 0.08) !important;
+}
+.bg-new-orange{
+  background: rgba(250, 140, 22, 0.08) !important;
+}
+.bg-new-yellow{
+  background: rgba(251, 182, 45, 0.08) !important;
+}
+.bg-new-green{
+  background: rgba(82, 196, 26, 0.08) !important;
+}
+.bg-new-blue{
+  background: rgba(51, 119, 255, 0.08) !important;
+}
+.text-new-red{
+  color: rgba(241, 82, 91, 1) !important;
+}
+.text-new-orange{
+  color: rgba(250, 140, 22, 1) !important;
+}
+.text-new-yellow{
+  color: rgba(251, 182, 45, 1) !important;
+}
+.text-new-green{
+  color: rgba(82, 196, 26, 1) !important;
+}
+.text-new-blue{
+  color: rgba(51, 119, 255, 1) !important;
+}
+.text-width{
+  width: 66px;
+  text-align: center;
+}
+.table-middle td, .table-middle th{
+  padding: 0.6rem;
+}
+.table-middle .thead-light th {
+  color: #495057;
+  background-color: rgba(250, 250, 250, 1);
+  border-color: #dee2e6;
+}
+.table-middle thead th{
+  border-bottom: none;
+}
+.card-big-htext{
+  font-size: 18px;
+}
+.card-white{
+  background: rgba(255, 255, 255, 1) !important;
+  border-bottom: none;
+}
+.canyu-width{
+  height: 98px;
+}
+.canyu-bg-blue{
+  background: url(bg_participate_blue.png) no-repeat;
+  background-size: 100% 100%;
+}
+.canyu-bg-yellow{
+  background: url(bg_participate_orange.png) no-repeat;
+  background-size: 100% 100%;
+}
+.canyu-text{
+  font-size: 36px;
+}
+.list-text-vertical{
+  overflow:hidden; 
+  text-overflow:ellipsis; 
+  white-space:nowrap;
+}
+.about-text i{
+  margin-top: -5px;
+  display: inline-block;
+  width: 24px;
+  height: 24px;
+  vertical-align:middle;
+}
+.about-text i.about-qq{
+  background: url(about.png) no-repeat -8px -10px;
+}
+.about-text i.about-phone{
+  background: url(about.png) no-repeat -8px -40px;
+}
+.about-text i.about-tel{
+  background: url(about.png) no-repeat -8px -70px;
+}
+.about-text span{
+  font-size: 1.2rem;
+}
+/*@media (min-width: 768px){
+  .weixin-erweima img{
+    width:90%; 
+    height:auto;
+  }
+}*/
+.weixin-erweima img{
+  width:75%; 
+  height:auto;
+}
+.weixin-erweima span{
+  display: inline-block;
+  width: 75%;
+}
+.small-text{
+  font-size: 0.75rem !important;
+  font-weight: 400;
+}
+.chaosong{
+  margin: 0 0 0 70px;
+  height: 300px;
+}
+.inputErrow{
+-webkit-animation:shake 1s .2s ease both;
+-moz-animation:shake 1s .2s ease both;
+animation:shake 1s .2s ease both;}
+@-webkit-keyframes shake{
+0%,100%{-webkit-transform:translateX(0);}
+10%,30%,50%,70%, 90%{-webkit-transform:translateX(-10px);}
+20%,40%,60%,80%{-webkit-transform:translateX(10px);}
+}
+@-moz-keyframes shake{
+0%,100%{-moz-transform:translateX(0);}
+10%,30%,50%,70%, 90%{-moz-transform:translateX(-10px);}
+20%,40%,60%,80%{-moz-transform:translateX(10px);}
+}
+@keyframes shake{
+0%,100%{transform:translateX(0);}
+10%,30%,50%,70%, 90%{transform:translateX(-10px);}
+20%,40%,60%,80%{transform:translateX(10px);}
 }
 }

BIN
app/public/images/juecedaping01.png


BIN
app/public/images/juecedaping02.png


BIN
app/public/images/juecedaping03.png


BIN
app/public/images/juecedaping04.png


+ 2 - 1
app/public/js/advance.js

@@ -262,7 +262,8 @@ $(document).ready(function () {
         for (let i = 0; i < l.length; i++) {
         for (let i = 0; i < l.length; i++) {
             t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
             t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
         }
         }
-        return t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+        const num = t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+        return num.replace('-,', '-');
     }
     }
 
 
     function transFormToChinese(num) {
     function transFormToChinese(num) {

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

@@ -442,5 +442,6 @@ function formatMoney(s, dot = ',', decimal = 2) {
     for (let i = 0; i < l.length; i++) {
     for (let i = 0; i < l.length; i++) {
         t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
         t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
     }
     }
-    return t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+    const num = t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
+    return num.replace('-,', '-');
 }
 }

+ 5 - 3
app/public/js/budget_detail.js

@@ -625,7 +625,7 @@ $(document).ready(() => {
             budgetTreeOpr.refreshTree(budgetSheet, refreshNode);
             budgetTreeOpr.refreshTree(budgetSheet, refreshNode);
             if (refreshNode.create && refreshNode.create.length > 0) {
             if (refreshNode.create && refreshNode.create.length > 0) {
                 budgetSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
                 budgetSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
-                SpreadJsObj.reloadRowsBackColor(budgetSheet, [sel.row, refreshNode.create[refreshNode.create.length - 1].index]);
+                SpreadJsObj.reloadRowsBackColor(budgetSheet, [sel.row, budgetTree.nodes.indexOf(mainNode), refreshNode.create[refreshNode.create.length - 1].index]);
             } else {
             } else {
                 const node = _.find(budgetTree.nodes, {code: stdNode.code, name: stdNode.name});
                 const node = _.find(budgetTree.nodes, {code: stdNode.code, name: stdNode.name});
                 if (node) {
                 if (node) {
@@ -640,6 +640,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
     const stdXmjSetting = {
         selector: '#std-xmj',
         selector: '#std-xmj',
         stdType: 'xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
         treeSetting: {
             id: 'chapter_id',
             id: 'chapter_id',
             pid: 'pid',
             pid: 'pid',
@@ -672,6 +673,7 @@ $(document).ready(() => {
     const stdGclSetting = {
     const stdGclSetting = {
         selector: '#std-gcl',
         selector: '#std-gcl',
         stdType: 'gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
         treeSetting: {
             id: 'bill_id',
             id: 'bill_id',
             pid: 'pid',
             pid: 'pid',
@@ -714,10 +716,10 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
             if (tab.attr('content') === '#std-xmj') {
-                if (!stdXmj) stdXmj = new stdLib(stdXmjSetting);
+                if (!stdXmj) stdXmj = $.stdLib(stdXmjSetting);
                 stdXmj.spread.refresh();
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
             } else if (tab.attr('content') === '#std-gcl') {
-                if (!stdGcl) stdGcl = new stdLib(stdGclSetting);
+                if (!stdGcl) stdGcl = $.stdLib(stdGclSetting);
                 stdGcl.spread.refresh();
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#search') {
             } else if (tab.attr('content') === '#search') {
                 if (!searchBudget) {
                 if (!searchBudget) {

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

@@ -180,8 +180,8 @@ $(document).ready(() => {
             // const cid = $('#changeId').val();
             // const cid = $('#changeId').val();
             // $('#downloadZip').attr('href', `/tender/${tid}/change/${cid}/download/compresse-file?fileIds=${JSON.stringify(fileIds)}`);
             // $('#downloadZip').attr('href', `/tender/${tid}/change/${cid}/download/compresse-file?fileIds=${JSON.stringify(fileIds)}`);
             // $('#downloadZip')[0].click();
             // $('#downloadZip')[0].click();
-            if (fileIds.length > 10) {
-              return toastr.warning(`最大允许10个文件(当前${fileIds.length}个)`);
+            if (fileIds.length > 20) {
+              return toastr.warning(`最大允许20个文件(当前${fileIds.length}个)`);
             }
             }
             const tid = $('#tenderId').val();
             const tid = $('#tenderId').val();
             const cid = $('#changeId').val();
             const cid = $('#changeId').val();
@@ -297,7 +297,7 @@ function findDecimal(unit) {
 // 生成附件列表
 // 生成附件列表
 function getAllList(currPageNum = 1) {
 function getAllList(currPageNum = 1) {
     // 每页最多几个附件
     // 每页最多几个附件
-    const pageCount = 15;
+    const pageCount = 20;
     // 附件总数
     // 附件总数
     const total = attData.length;
     const total = attData.length;
     // 总页数
     // 总页数
@@ -312,7 +312,7 @@ function getAllList(currPageNum = 1) {
     for(const [index,att] of currPageAttData.entries()) {
     for(const [index,att] of currPageAttData.entries()) {
         html += `<tr>
         html += `<tr>
         <td width="25"><input type="checkbox" class="check-file" file-id=${att.id}></td>
         <td width="25"><input type="checkbox" class="check-file" file-id=${att.id}></td>
-        <td>${((currPageNum-1)*15)+index+1}</td>
+        <td>${((currPageNum-1)*pageCount)+index+1}</td>
         <td><a href="javascript:void(0)" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a></td>
         <td><a href="javascript:void(0)" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a></td>
         <td>${moment(att.in_time * 1000).format('YYYY-MM-DD')}<br>${bytesToSize(att.filesize)}</td>
         <td>${moment(att.in_time * 1000).format('YYYY-MM-DD')}<br>${bytesToSize(att.filesize)}</td>
         <td>
         <td>

+ 20 - 14
app/public/js/change_information_approval.js

@@ -71,7 +71,7 @@ $(document).ready(() => {
         const newColTp = {
         const newColTp = {
             title: '|金额',
             title: '|金额',
             colSpan: '|1', rowSpan: '|1',
             colSpan: '|1', rowSpan: '|1',
-            field: 'sa_tp',
+            field: 'sa_tp_' + aid,
             hAlign: 2, width: 80, type: 'Number',
             hAlign: 2, width: 80, type: 'Number',
             readOnly: true
             readOnly: true
         };
         };
@@ -108,18 +108,23 @@ $(document).ready(() => {
             changeSpreadObj.countSum();
             changeSpreadObj.countSum();
         },
         },
         setAuditValue: function () {
         setAuditValue: function () {
-            const rowCount = changeSpreadSheet.getRowCount();
-            // 用户的数据合计
-            for (const j in aidList) {
-                for(let i = 0; i <= rowCount - 1; i++){
-                    const data = {
-                        unit_price: changeSpreadSheet.getValue(i, 5),
-                        amount: parseFloat(changeSpreadSheet.getValue(i, 10 + parseInt(j)*2)),
-                    };
-                    const sum = ZhCalc.round(ZhCalc.mul(data.unit_price, data.amount), totalPriceUnit);
-                    changeSpreadSheet.setValue(i, 11 + j*2, sum !== 0 ? sum : null);
+            for (const c  of changeList) {
+                for (const j of aidList) {
+                    c['sa_tp_' + j] = ZhCalc.round(ZhCalc.mul(c['audit_amount_' + j], c.unit_price), totalPriceUnit);
                 }
                 }
             }
             }
+            // const rowCount = changeSpreadSheet.getRowCount();
+            // // 用户的数据合计
+            // for (const j in aidList) {
+            //     for(let i = 0; i <= rowCount - 1; i++){
+            //         const data = {
+            //             unit_price: changeSpreadSheet.getValue(i, 5),
+            //             amount: parseFloat(changeSpreadSheet.getValue(i, 10 + parseInt(j)*2)),
+            //         };
+            //         const sum = ZhCalc.round(ZhCalc.mul(data.unit_price, data.amount), totalPriceUnit);
+            //         changeSpreadSheet.setValue(i, 11 + j*2, sum !== 0 ? sum : null);
+            //     }
+            // }
         },
         },
         resetXmjSpread: function(data = null) {
         resetXmjSpread: function(data = null) {
             const xmj = [];
             const xmj = [];
@@ -321,13 +326,13 @@ $(document).ready(() => {
             // 更新至服务器
             // 更新至服务器
             postData(window.location.pathname + '/save', { type:'paste_amount_rows', updateData: data }, function (result) {
             postData(window.location.pathname + '/save', { type:'paste_amount_rows', updateData: data }, function (result) {
                 changeList = result;
                 changeList = result;
-                SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
                 changeSpreadObj.setAuditValue();
                 changeSpreadObj.setAuditValue();
+                SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
                 changeSpreadObj.makeSjsFooter();
                 changeSpreadObj.makeSjsFooter();
                 changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
                 changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
             }, function () {
             }, function () {
-                SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 changeSpreadObj.setAuditValue();
                 changeSpreadObj.setAuditValue();
+                SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 return;
                 return;
             });
             });
         },
         },
@@ -335,8 +340,9 @@ $(document).ready(() => {
 
 
     SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
     SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
     SpreadJsObj.initSheet(changeSpreadSheet, changeSpreadSetting);
     SpreadJsObj.initSheet(changeSpreadSheet, changeSpreadSetting);
-    SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
     changeSpreadObj.setAuditValue();
     changeSpreadObj.setAuditValue();
+    SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
+    console.log(changeList);
     changeSpreadObj.makeSjsFooter();
     changeSpreadObj.makeSjsFooter();
     changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
     changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
     const userIndex = aidList.indexOf(parseInt(accountId));
     const userIndex = aidList.indexOf(parseInt(accountId));

+ 7 - 2
app/public/js/change_information_show.js

@@ -60,7 +60,7 @@ $(document).ready(() => {
         const newColTp = {
         const newColTp = {
             title: '|金额',
             title: '|金额',
             colSpan: '|1', rowSpan: '|1',
             colSpan: '|1', rowSpan: '|1',
-            field: 'sa_tp',
+            field: 'sa_tp_' + aid,
             hAlign: 2, width: 80, type: 'Number',
             hAlign: 2, width: 80, type: 'Number',
         };
         };
         changeSpreadSetting.cols.push(newColcount);
         changeSpreadSetting.cols.push(newColcount);
@@ -163,8 +163,13 @@ $(document).ready(() => {
 
 
     SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
     SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
     SpreadJsObj.initSheet(changeSpreadSheet, changeSpreadSetting);
     SpreadJsObj.initSheet(changeSpreadSheet, changeSpreadSetting);
+    for (const c  of changeList) {
+        for (const j of aidList) {
+            c['sa_tp_' + j] = ZhCalc.round(ZhCalc.mul(c['audit_amount_' + j], c.unit_price), totalPriceUnit);
+        }
+    }
     SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
     SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
-    changeSpreadObj.setAuditValue();
+    // changeSpreadObj.setAuditValue();
     changeSpreadObj.makeSjsFooter();
     changeSpreadObj.makeSjsFooter();
     changeSpreadObj.showHideAudit();
     changeSpreadObj.showHideAudit();
     changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
     changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));

+ 4 - 2
app/public/js/change_revise.js

@@ -2378,6 +2378,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
     const stdXmjSetting = {
         selector: '#std-xmj',
         selector: '#std-xmj',
         stdType: 'xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
         treeSetting: {
             id: 'chapter_id',
             id: 'chapter_id',
             pid: 'pid',
             pid: 'pid',
@@ -2409,6 +2410,7 @@ $(document).ready(() => {
     const stdGclSetting = {
     const stdGclSetting = {
         selector: '#std-gcl',
         selector: '#std-gcl',
         stdType: 'gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
         treeSetting: {
             id: 'bill_id',
             id: 'bill_id',
             pid: 'pid',
             pid: 'pid',
@@ -2451,12 +2453,12 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 }
                 stdXmj.spread.refresh();
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 }
                 stdGcl.spread.refresh();
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {
             } else if (tab.attr('content') === '#deal-bills') {

+ 38 - 2
app/public/js/datacollect_scroll.js

@@ -1,4 +1,5 @@
 window.onload = roll(50);
 window.onload = roll(50);
+window.onload = roll2(50);
 function roll(t) {
 function roll(t) {
     var ul1 = document.getElementById("comment1");
     var ul1 = document.getElementById("comment1");
     var ul2 = document.getElementById("comment2");
     var ul2 = document.getElementById("comment2");
@@ -23,6 +24,7 @@ function rollStart() {
     var ul1 = document.getElementById("comment1");
     var ul1 = document.getElementById("comment1");
     var ul2 = document.getElementById("comment2");
     var ul2 = document.getElementById("comment2");
     var ulbox = document.getElementById("review_box");
     var ulbox = document.getElementById("review_box");
+    // console.log(ulbox.scrollTop);
     // 正常滚动不断给scrollTop的值+1,当滚动高度大于列表内容高度时恢复为0
     // 正常滚动不断给scrollTop的值+1,当滚动高度大于列表内容高度时恢复为0
     if (ulbox.scrollTop >= ul1.scrollHeight) {
     if (ulbox.scrollTop >= ul1.scrollHeight) {
         ulbox.scrollTop = 0;
         ulbox.scrollTop = 0;
@@ -30,6 +32,36 @@ function rollStart() {
         ulbox.scrollTop++;
         ulbox.scrollTop++;
     }
     }
 }
 }
+function roll2(t) {
+    var ul3 = document.getElementById("comment3");
+    var ul4 = document.getElementById("comment4");
+    var ulbox2 = document.getElementById("review_box2");
+    ul4.innerHTML = ul3.innerHTML;
+    ulbox2.scrollTop = 0; // 开始无滚动时设为0
+    // var timer = setInterval(rollStart, t); // 设置定时器,参数t用在这为间隔时间(单位毫秒),参数t越小,滚动速度越快
+    var timer2 = setInterval(rollStart2, '40');
+    ulbox2.onmouseover = function () {
+        clearInterval(timer2);
+    }
+    // 鼠标移出div后继续滚动
+    ulbox2.onmouseout = function () {
+        // timer = setInterval(rollStart, t);
+        timer2 = setInterval(rollStart2, '40');
+    }
+}
+function rollStart2() {
+    // 上面声明的DOM对象为局部对象需要再次声明
+    var ul3 = document.getElementById("comment3");
+    var ul4 = document.getElementById("comment4");
+    var ulbox2 = document.getElementById("review_box2");
+    // console.log(ulbox2.scrollTop);
+    // 正常滚动不断给scrollTop的值+1,当滚动高度大于列表内容高度时恢复为0
+    if (ulbox2.scrollTop >= ul3.scrollHeight) {
+        ulbox2.scrollTop = 0;
+    } else {
+        ulbox2.scrollTop++;
+    }
+}
 
 
 // tableScroll('tableId', '100%', 30, 10);
 // tableScroll('tableId', '100%', 30, 10);
 var MyMarhq;
 var MyMarhq;
@@ -44,7 +76,7 @@ function tableScroll(tableid, hei, speed, len) {
         'height': hei + 'px'
         'height': hei + 'px'
     })
     })
     $(".tableid_").find('th').each(function(i) {
     $(".tableid_").find('th').each(function(i) {
-        $(this).css('width', $('#' + tableid).find('th:eq(' + i + ')').width());
+        $(this).css('width', $('#' + tableid).find('th:eq(' + i + ')').innerWidth());
     });
     });
     $(".tableid_").css({
     $(".tableid_").css({
         'position': 'absolute',
         'position': 'absolute',
@@ -60,7 +92,11 @@ function tableScroll(tableid, hei, speed, len) {
     })
     })
 
 
     if ($('#' + tableid).find('tbody tr').length > len) {
     if ($('#' + tableid).find('tbody tr').length > len) {
-        $('#' + tableid).find('tbody').html($('#' + tableid).find('tbody').html() + $('#' + tableid).find('tbody').html());
+        if ($('#' + tableid).find('tbody tr').length > 30) {
+            $('#' + tableid).find('tbody').html($('#' + tableid).find('tbody').html() + $('#' + tableid).find('tbody').html());
+        } else {
+            $('#' + tableid).find('tbody').html($('#' + tableid).find('tbody').html() + $('#' + tableid).find('tbody').html() + $('#' + tableid).find('tbody').html() + $('#' + tableid).find('tbody').html());
+        }
         $(".tableid_").css('top', 0);
         $(".tableid_").css('top', 0);
         $('#' + tableid).css('top', 0);
         $('#' + tableid).css('top', 0);
         var tblTop = 0;
         var tblTop = 0;

+ 56 - 1
app/public/js/global.js

@@ -116,6 +116,62 @@ $(function(){
             $(this).attr('href', $(this).attr('href') + '?sort=' + orders[0] + '&order=' + orders[1]);
             $(this).attr('href', $(this).attr('href') + '?sort=' + orders[0] + '&order=' + orders[1]);
         }
         }
     });
     });
+
+    $('#nav_management').click(function(e) {
+      e.preventDefault()
+      showWaitingView();
+      $.ajax({
+        type: 'GET',
+        url: '/management/proxy/project/vertify',
+        dataType: 'json',
+        cache: false,
+        timeout: 60000,
+        success: function ({code = -1, data: { exist, is_admin, redirect } = { exist: 0, is_admin: false}}) {
+          if (code === 0) {
+              if (!exist && !is_admin) {
+                toastr.error('「项目管理」系统不存在当前项目,请联系管理员进行处理。');
+              } else if(!exist && is_admin) {
+                $('#add-management').modal('show')
+              } else {
+                redirect && window.open(redirect)
+              }
+            }
+            closeWaitingView()
+          },
+          error: function(jqXHR, textStatus, errorThrown){
+            toastr.error('error: ' + textStatus + " " + errorThrown);
+            closeWaitingView();
+          }
+        })
+      });
+    $('#add-management .btn-primary').click(function() {
+      
+      $('#add-management').modal('hide')
+      $('#process-management').modal('show')
+      $.ajax({
+        tpye: 'post',
+        url: '/management/proxy/project/add',
+        dataType: 'json',
+        cache: false,
+        timeout: 60000,
+        // beforeSend: function(xhr) {
+        //   let csrfToken = Cookies.get('csrfToken_j');
+        //   xhr.setRequestHeader('x-csrf-token', csrfToken);
+        // },
+        success: function ({code = -1, data = {}}) {
+          if (code === 0) {
+            timer = setTimeout(() => {
+              $('#process-management .process-child').css('width', '100%')
+              setTimeout(() => {
+                const { redirect } = data
+                redirect && window.open(redirect)
+                $('#process-management').modal('hide')
+              }, 150);
+            }, 500);
+          }
+        }
+      })
+    })
 });
 });
 
 
 function checkShowLast (count) {
 function checkShowLast (count) {
@@ -935,7 +991,6 @@ const checkUtils = {
                 for (const p of posRange) {
                 for (const p of posRange) {
                     if (checkUtils.posOver(p)) return true;
                     if (checkUtils.posOver(p)) return true;
                 }
                 }
-                return false;
             }
             }
             if (data.is_tp) {
             if (data.is_tp) {
                 if (!data.total_price) return !!data.end_contract_tp;
                 if (!data.total_price) return !!data.end_contract_tp;

+ 49 - 33
app/public/js/ledger.js

@@ -414,6 +414,7 @@ $(document).ready(function() {
                         self.refreshTree(sheet, refreshNode);
                         self.refreshTree(sheet, refreshNode);
                         self.refreshOperationValid(sheet);
                         self.refreshOperationValid(sheet);
                         posOperationObj.loadCurPosData();
                         posOperationObj.loadCurPosData();
+                        billsTag.afterDeleteBills(refreshNode.delete);
                     });
                     });
                 });
                 });
             }
             }
@@ -878,16 +879,19 @@ $(document).ready(function() {
                 removeLocalCache(copyBlockTag);
                 removeLocalCache(copyBlockTag);
             }, null, true);
             }, null, true);
         },
         },
+        loadRelaData: function () {
+            posOperationObj.loadCurPosData();
+            posSearch.search($('#pos-keyword').val());
+            treeOperationObj.loadExprToInput(ledgerSpread.getActiveSheet());
+        },
         selectionChanged: function (e, info) {
         selectionChanged: function (e, info) {
             if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
             if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
                 SpreadJsObj.resetTopAndSelect(posSpread.getActiveSheet());
                 SpreadJsObj.resetTopAndSelect(posSpread.getActiveSheet());
-                posOperationObj.loadCurPosData();
-                posSearch.search($('#pos-keyword').val());
+                treeOperationObj.loadRelaData();
                 // 全选去除
                 // 全选去除
                 $('#dqjiedian').find('.check-all-file').prop('checked', false);
                 $('#dqjiedian').find('.check-all-file').prop('checked', false);
             }
             }
             SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
             SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
-            treeOperationObj.loadExprToInput(info.sheet);
         },
         },
         topRowChanged(e, info) {
         topRowChanged(e, info) {
             SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
             SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
@@ -1220,6 +1224,7 @@ $(document).ready(function() {
         selector: '#ledger-spread',
         selector: '#ledger-spread',
         build: function ($trigger, e) {
         build: function ($trigger, e) {
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
+            treeOperationObj.loadRelaData();
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         },
         items: {},
         items: {},
@@ -2293,7 +2298,10 @@ $(document).ready(function() {
             treeOperationObj.refreshTree(mainSheet, refreshNode);
             treeOperationObj.refreshTree(mainSheet, refreshNode);
             if (refreshNode.create && refreshNode.create.length > 0) {
             if (refreshNode.create && refreshNode.create.length > 0) {
                 mainSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
                 mainSheet.setSelection(refreshNode.create[refreshNode.create.length - 1].index, sel.col, sel.rowCount, sel.colCount);
-                SpreadJsObj.reloadRowsBackColor(mainSheet, [sel.row, refreshNode.create[refreshNode.create.length - 1].index]);
+                const refreshRow = [sel.row, refreshNode.create[refreshNode.create.length - 1].index];
+                const curIndex = mainTree.nodes.indexOf(mainNode);
+                if (sel.row !== curIndex && curIndex >= 0) refreshRow.push(curIndex);
+                SpreadJsObj.reloadRowsBackColor(mainSheet, refreshRow);
             } else {
             } else {
                 const node = _.find(ledgerTree.nodes, {code: stdNode.code, name: stdNode.name});
                 const node = _.find(ledgerTree.nodes, {code: stdNode.code, name: stdNode.name});
                 if (node) {
                 if (node) {
@@ -2309,6 +2317,7 @@ $(document).ready(function() {
     const stdXmjSetting = {
     const stdXmjSetting = {
         selector: '#std-xmj',
         selector: '#std-xmj',
         stdType: 'xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
         treeSetting: {
             id: 'chapter_id',
             id: 'chapter_id',
             pid: 'pid',
             pid: 'pid',
@@ -2340,6 +2349,7 @@ $(document).ready(function() {
     const stdGclSetting = {
     const stdGclSetting = {
         selector: '#std-gcl',
         selector: '#std-gcl',
         stdType: 'gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
         treeSetting: {
             id: 'bill_id',
             id: 'bill_id',
             pid: 'pid',
             pid: 'pid',
@@ -2383,14 +2393,12 @@ $(document).ready(function() {
             showSideTools(tab.hasClass('active'));
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
-                    //stdXmj.loadLib($('select', '#std-xmj').val());
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 }
                 stdXmj.spread.refresh();
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
-                    //stdGcl.loadLib($('select', '#std-gcl').val());
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 }
                 stdGcl.spread.refresh();
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {
             } else if (tab.attr('content') === '#deal-bills') {
@@ -2453,7 +2461,7 @@ $(document).ready(function() {
             } else if (tab.attr('content') === '#check-list') {
             } else if (tab.attr('content') === '#check-list') {
                 checkList.spread.refresh();
                 checkList.spread.refresh();
             } else if (tab.attr('content') === '#fujian') {
             } else if (tab.attr('content') === '#fujian') {
-              $('#showAttachment').hide()
+              $('#showAttachment').hide();
               const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
               const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
               getNodeList(node.id);
               getNodeList(node.id);
               getAllList();
               getAllList();
@@ -2926,7 +2934,7 @@ $(document).ready(function() {
                             }
                             }
                             qdSheet.setSelection(sel.row, sel.col, 1, 1);
                             qdSheet.setSelection(sel.row, sel.col, 1, 1);
                         },
                         },
-                    },
+                    }
                 }
                 }
             });
             });
             // 拉取签约清单数据
             // 拉取签约清单数据
@@ -2938,7 +2946,7 @@ $(document).ready(function() {
                 });
                 });
             }
             }
             // 双击签约清单,自动添加到清单编号窗口
             // 双击签约清单,自动添加到清单编号窗口
-            this.dealSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (e, info) {
+            this.dealSpread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
                 const deal = info.sheet.zh_data[info.row];
                 const deal = info.sheet.zh_data[info.row];
                 const qdSheet = self.qdSpread.getActiveSheet(), posSheet = self.posSpread.getActiveSheet();
                 const qdSheet = self.qdSpread.getActiveSheet(), posSheet = self.posSpread.getActiveSheet();
                 const sel = qdSheet.getSelections()[0];
                 const sel = qdSheet.getSelections()[0];
@@ -2957,30 +2965,38 @@ $(document).ready(function() {
                 }
                 }
                 qdSheet.setSelection(sel.row + 1, sel.col, 1, 1);
                 qdSheet.setSelection(sel.row + 1, sel.col, 1, 1);
             });
             });
-            this.qdSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
-                const billsCount = info.sheet.getRowCount(), posSheet = self.posSpread.getActiveSheet();
-                const count = posSheet.getColumnCount() - 2;
-                if (billsCount > count) {
-                    posSheet.setColumnCount(billsCount + 2);
-                    for (let i = count + 1; i <= billsCount; i++) {
-                        info.sheet.getCell(i - 1, 0, spreadNS.SheetArea.rowHeader).text('清单' + i);
+            this.qdSpread.bind(spreadNS.Events.ClipboardPasting, function (e, info) {
+                info.cancel = true;
+                const transpose = $('[name=batch-transpose]')[0].checked;
+                const pasteData = SpreadJsObj.analysisPasteText(info.pasteData.text, transpose);
+
+                const billsSheet = info.sheet, posSheet = self.posSpread.getActiveSheet();
+                const billsCount = info.sheet.getRowCount(), finalCount = info.cellRange.row + pasteData.length + 1;
+                SpreadJsObj.beginMassOperation(billsSheet);
+                if (finalCount > billsCount) {
+                    billsSheet.setRowCount(finalCount);
+                    posSheet.setColumnCount(finalCount + 2);
+                    for (let i = billsCount - 1; i <= finalCount; i++) {
+                        billsSheet.getCell(i - 1, 0, spreadNS.SheetArea.rowHeader).text('清单' + i);
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                     }
                     }
                 }
                 }
-                if (info.cellRange.col === 0 && info.cellRange.colCount === 1) {
-                    const dealBills = self.dealSpread.getActiveSheet().zh_data;
-                    if (dealBills && dealBills.length > 0) {
-                        for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
-                            const curRow = iRow + info.cellRange.row;
-                            const bills = _.find(dealBills, {code: info.sheet.getText(curRow, 0)});
-                            if (bills) {
-                                info.sheet.getCell(curRow, 1).value(bills.name);
-                                info.sheet.getCell(curRow, 2).value(bills.unit);
-                                info.sheet.getCell(curRow, 3).value(bills.unit_price);
-                            }
+                for (let iRow = 0; iRow < pasteData.length; iRow++) {
+                    const curRow = iRow + info.cellRange.row;
+                    pasteData[iRow].forEach((value, iCol) => {
+                        billsSheet.getCell(curRow, iCol + info.cellRange.col).value(value);
+                    });
+                    if ([0, 1].indexOf(info.cellRange.col) >= 0) {
+                        const dealBills = self.dealSpread.getActiveSheet().zh_data;
+                        const bills = _.find(dealBills, {code: billsSheet.getText(curRow, 0)});
+                        if (bills) {
+                            billsSheet.getCell(curRow, 1).value(bills.name);
+                            billsSheet.getCell(curRow, 2).value(bills.unit);
+                            billsSheet.getCell(curRow, 3).value(bills.unit_price);
                         }
                         }
                     }
                     }
                 }
                 }
+                SpreadJsObj.endMassOperation(billsSheet);
             });
             });
             this.posSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
             this.posSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
                 const billsCount = info.sheet.getColumnCount() - 2, qdSheet = self.qdSpread.getActiveSheet();
                 const billsCount = info.sheet.getColumnCount() - 2, qdSheet = self.qdSpread.getActiveSheet();
@@ -3622,7 +3638,7 @@ $(document).ready(function() {
       const filename = name.substring(0, name.lastIndexOf("."));
       const filename = name.substring(0, name.lastIndexOf("."));
       const fileext = name.substr(name.indexOf("."));
       const fileext = name.substr(name.indexOf("."));
       const filesize = file.size;
       const filesize = file.size;
-      if (filesize > 10 * 1024 * 1024) {
+      if (filesize > 30 * 1024 * 1024) {
           toastr.error('文件大小过大!');
           toastr.error('文件大小过大!');
           $('#change-att-btn').val('');
           $('#change-att-btn').val('');
           return false;
           return false;
@@ -3668,8 +3684,8 @@ $(document).ready(function() {
       });
       });
 
 
       if (fileIds.length) {
       if (fileIds.length) {
-        if (fileIds.length > 10) {
-          return toastr.warning(`最大允许10个文件(当前${fileIds.length}个)`)
+        if (fileIds.length > 20) {
+          return toastr.warning(`最大允许20个文件(当前${fileIds.length}个)`)
         }
         }
         toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
         toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
         $(this).attr('disabled', "true")
         $(this).attr('disabled', "true")
@@ -3754,7 +3770,7 @@ function getNodeList(node) {
 // 生成所有附件列表
 // 生成所有附件列表
 function getAllList(currPageNum = 1) {
 function getAllList(currPageNum = 1) {
   // 每页最多几个附件
   // 每页最多几个附件
-  const pageCount = 15;
+  const pageCount = 20;
   // 附件总数
   // 附件总数
   const total = attData.length;
   const total = attData.length;
   // 总页数
   // 总页数

+ 37 - 45
app/public/js/material.js

@@ -72,15 +72,15 @@ DatePickerCellType.prototype.updateEditor = function (editorContext, cellStyle,
 };
 };
 
 
 function resetTpTable() {
 function resetTpTable() {
-    $('#tp_set').find('td').eq(1).text(ZhCalc.round(m_tp, 2));
-    $('#tp_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(pre_tp, m_tp), 2));
+    $('#tp_set').find('td').eq(1).text(ZhCalc.round(m_tp, materialDecimal.tp));
+    $('#tp_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(pre_tp, m_tp), materialDecimal.tp));
     if (materialTax) {
     if (materialTax) {
-        $('#rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, 2));
-        $('#rate_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(m_tax_pre_tp, m_tax_tp), 2));
+        $('#tax_rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, materialDecimal.tp));
+        $('#tax_rate_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(m_tax_pre_tp, m_tax_tp), materialDecimal.tp));
     } else {
     } else {
         const rate = $('#changeRate').val();
         const rate = $('#changeRate').val();
-        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), 2);
-        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), 2);
+        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
     }
     }
@@ -129,7 +129,7 @@ $(document).ready(() => {
         {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 70, formatter: '@', readOnly: 'readOnly.isEdit'},
         {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 70, formatter: '@', readOnly: 'readOnly.isEdit'},
         {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
         {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
         {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.remark'},
         {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.remark'},
-        {title: '|价差', colSpan: '|1', rowSpan: '|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.msg_spread'},]
+        {title: '|价差', colSpan: '|1', rowSpan: '|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.msg_spread'},]
     );
     );
     if (materialTax) {
     if (materialTax) {
         materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
         materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
@@ -209,19 +209,19 @@ $(document).ready(() => {
     const materialCol = {
     const materialCol = {
         getValue: {
         getValue: {
             msg_spread: function (data) {
             msg_spread: function (data) {
-                return ZhCalc.round(ZhCalc.sub(data.msg_tp, data.basic_price), 3);
+                return ZhCalc.round(ZhCalc.sub(data.msg_tp, data.basic_price), materialDecimal.up);
             },
             },
             m_spread : function (data) {
             m_spread : function (data) {
                 const msg_spread = materialCol.getValue.msg_spread(data);
                 const msg_spread = materialCol.getValue.msg_spread(data);
                 const cor = msg_spread >= 0 ? ZhCalc.mul(data.basic_price, ZhCalc.div(data.m_up_risk, 100)) : ZhCalc.mul(data.basic_price, ZhCalc.div(data.m_down_risk, 100));
                 const cor = msg_spread >= 0 ? ZhCalc.mul(data.basic_price, ZhCalc.div(data.m_up_risk, 100)) : ZhCalc.mul(data.basic_price, ZhCalc.div(data.m_down_risk, 100));
-                return Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? ZhCalc.round(ZhCalc.sub(msg_spread, cor), 3) : ZhCalc.round(ZhCalc.add(msg_spread, cor), 3)) : 0;
+                return Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? ZhCalc.round(ZhCalc.sub(msg_spread, cor), materialDecimal.up) : ZhCalc.round(ZhCalc.add(msg_spread, cor), materialDecimal.up)) : 0;
             },
             },
             m_tp: function (data) {
             m_tp: function (data) {
-                return ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), 2);
+                return ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), materialDecimal.tp);
             },
             },
             m_tax_tp: function (data) {
             m_tax_tp: function (data) {
-                const m_tp = ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), 2);
-                return data.m_tax ? ZhCalc.round(ZhCalc.mul(m_tp, (1+ZhCalc.div(data.m_tax, 100))), 2) : m_tp;
+                const m_tp = ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), materialDecimal.tp);
+                return data.m_tax ? ZhCalc.round(ZhCalc.mul(m_tp, (1+ZhCalc.div(data.m_tax, 100))), materialDecimal.tp) : m_tp;
             }
             }
         },
         },
         readOnly: {
         readOnly: {
@@ -401,12 +401,10 @@ $(document).ready(() => {
                         return;
                         return;
                     }
                     }
                     let num = parseFloat(validText);
                     let num = parseFloat(validText);
-                    if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
-                        toastr.warning('已保留3位小数');
-                        validText = ZhCalc.round(num, 3);
-                        // toastr.error('请输入大于0并且小于3位小数的浮点数');
-                        // SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        // return;
+                    const reg = materialDecimal.up ? new RegExp("^\\d+(\\.\\d{1,"+ materialDecimal.up +"})?$") : new RegExp("^\\d+?$");
+                    if (validText !== null && (num < 0 || !reg.test(num))) {
+                        toastr.warning('已保留'+ materialDecimal.up +'位小数');
+                        validText = ZhCalc.round(num, materialDecimal.up);
                     }
                     }
                 }
                 }
                 if (col.field === 'msg_tp') {
                 if (col.field === 'msg_tp') {
@@ -416,12 +414,10 @@ $(document).ready(() => {
                         return;
                         return;
                     }
                     }
                     const num = parseFloat(validText);
                     const num = parseFloat(validText);
-                    if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
-                        toastr.warning('已保留3位小数');
-                        validText = ZhCalc.round(num, 3);
-                        // toastr.error('请输入大于0并且小于3位小数的浮点数');
-                        // SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        // return;
+                    const reg = materialDecimal.up ? new RegExp("^\\d+(\\.\\d{1,"+ materialDecimal.up +"})?$") : new RegExp("^\\d+?$");
+                    if (validText !== null && (num < 0 || !reg.test(num))) {
+                        toastr.warning('已保留'+ materialDecimal.up +'位小数');
+                        validText = ZhCalc.round(num, materialDecimal.up);
                     }
                     }
                 }
                 }
                 if (col.field === 'm_up_risk' || col.field === 'm_down_risk' || col.field === 'm_tax') {
                 if (col.field === 'm_up_risk' || col.field === 'm_down_risk' || col.field === 'm_tax') {
@@ -512,7 +508,7 @@ $(document).ready(() => {
                 codeError: {type: 'error', msg: '编号为纯数字时,不能为小数'},
                 codeError: {type: 'error', msg: '编号为纯数字时,不能为小数'},
                 numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
                 numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
                 riskCan: {type: 'error', msg: '只能粘贴0-100的正整数'},
                 riskCan: {type: 'error', msg: '只能粘贴0-100的正整数'},
-                numberCan: {type: 'warning', msg: '已保留3位小数'},
+                numberCan: {type: 'warning', msg: '已保留'+ materialDecimal.up +'位小数'},
             };
             };
             const range = info.cellRange;
             const range = info.cellRange;
             const sortData = info.sheet.zh_data || [];
             const sortData = info.sheet.zh_data || [];
@@ -581,11 +577,10 @@ $(document).ready(() => {
                         }
                         }
                         const num = parseFloat(validText);
                         const num = parseFloat(validText);
                         if (colSetting.field === 'basic_price' || colSetting.field === 'msg_tp') {
                         if (colSetting.field === 'basic_price' || colSetting.field === 'msg_tp') {
-                            if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
+                            const reg = materialDecimal.up ? new RegExp("^\\d+(\\.\\d{1,"+ materialDecimal.up +"})?$") : new RegExp("^\\d+?$");
+                            if (validText !== null && (num < 0 || !reg.test(num))) {
                                 toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
                                 toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
-                                validText = ZhCalc.round(num, 3);
-                                // bPaste = false;
-                                // continue;
+                                validText = ZhCalc.round(num, materialDecimal.up);
                             }
                             }
                         } else if (colSetting.field === 'm_up_risk' || colSetting.field === 'm_down_risk' || colSetting.field === 'm_tax') {
                         } else if (colSetting.field === 'm_up_risk' || colSetting.field === 'm_down_risk' || colSetting.field === 'm_tax') {
                             if (validText !== null && (num < 0 || num > 100 || !/^\d+$/.test(num))) {
                             if (validText !== null && (num < 0 || num > 100 || !/^\d+$/.test(num))) {
@@ -766,7 +761,7 @@ $(document).ready(() => {
                         hadnum++;
                         hadnum++;
                     }
                     }
                 }
                 }
-                const average_tp = hadnum !== 0 ? ZhCalc.round(ZhCalc.div(msg_tp, hadnum), 3) : ZhCalc.round(ZhCalc.div(msg_tp, months.length), 3);
+                const average_tp = hadnum !== 0 ? ZhCalc.round(ZhCalc.div(msg_tp, hadnum), materialDecimal.up) : ZhCalc.round(ZhCalc.div(msg_tp, months.length), materialDecimal.up);
                 return average_tp;
                 return average_tp;
             },
             },
         },
         },
@@ -812,12 +807,10 @@ $(document).ready(() => {
                         return;
                         return;
                     }
                     }
                     const num = parseFloat(validText);
                     const num = parseFloat(validText);
-                    if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
-                        // toastr.error('请输入大于0并且小于3位小数的浮点数');
-                        // SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        // return;
-                        toastr.warning('已保留3位小数');
-                        validText = ZhCalc.round(num, 3);
+                    const reg = materialDecimal.up ? new RegExp("^\\d+(\\.\\d{1,"+ materialDecimal.up +"})?$") : new RegExp("^\\d+?$");
+                    if (validText !== null && (num < 0 || !reg.test(num))) {
+                        toastr.warning('已保留'+ materialDecimal.up +'位小数');
+                        validText = ZhCalc.round(num, materialDecimal.up);
                     }
                     }
                     select[col.field] = validText;
                     select[col.field] = validText;
 
 
@@ -874,7 +867,7 @@ $(document).ready(() => {
             const hint = {
             const hint = {
                 cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
                 cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
                 numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
                 numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
-                numberCan: {type: 'warning', msg: '已保留3位小数'},
+                numberCan: {type: 'warning', msg: '已保留'+ materialDecimal.up +'位小数'},
             };
             };
             const range = info.cellRange;
             const range = info.cellRange;
             const sortData = info.sheet.zh_data || [];
             const sortData = info.sheet.zh_data || [];
@@ -922,11 +915,10 @@ $(document).ready(() => {
                             bPaste = false;
                             bPaste = false;
                             continue;
                             continue;
                         }
                         }
-                        if (validText !== null && (num < 0 || !/^\d+(\.\d{1,3})?$/.test(num))) {
+                        const reg = materialDecimal.up ? new RegExp("^\\d+(\\.\\d{1,"+ materialDecimal.up +"})?$") : new RegExp("^\\d+?$");
+                        if (validText !== null && (num < 0 || !reg.test(num))) {
                             toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
                             toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
-                            validText = ZhCalc.round(num, 3);
-                            // bPaste = false;
-                            // continue;
+                            validText = ZhCalc.round(num, materialDecimal.up);
                         }
                         }
                     }
                     }
                     materialMonthData[colSetting.field] = validText;
                     materialMonthData[colSetting.field] = validText;
@@ -1021,10 +1013,10 @@ $(document).ready(() => {
         $('#changeRate').change(function () {
         $('#changeRate').change(function () {
             const rate = parseInt($(this).val());
             const rate = parseInt($(this).val());
             postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
             postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
-                const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), 2);
-                const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), 2);
-                const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), 2);
-                const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), 2);
+                const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+                const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
+                const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
+                const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
                 $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
                 $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
                 $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
                 $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
                 $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
                 $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');

+ 900 - 0
app/public/js/material_checklist.js

@@ -0,0 +1,900 @@
+'use strict';
+
+/**
+ * 材料调差 - 调差清单设置
+ *
+ * @author EllisRan
+ * @date 2022/1/7
+ * @version
+ */
+
+function getStageId() {
+    return window.location.pathname.split('/')[5];
+}
+
+function findNotJoinLeafXmj(x, type = '') {
+    if (type === 'index') {
+        return notJoinList.findIndex(function (item) {
+            return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+        });
+    }
+    return notJoinList.find(function (item) {
+        return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+    });
+}
+
+function getPasteHint (str, row = '') {
+    let returnObj = str;
+    if (row) {
+        returnObj.msg = '清单第' + (row+1) + '行' + (str.msg ? str.msg : str);
+    }
+    return returnObj;
+}
+
+function makeChecklistData(lists, checklists) {
+    let html = '';
+    if (lists.length > 0) {
+        for(const [i,l] of lists.entries()) {
+            const checklistInfo = _.find(checklists, { b_code: l.b_code, name: l.name, unit: l.unit, unit_price: l.unit_price });
+            const isChecked = checklistInfo ? ' checked' : '';
+            const isDisabled = checklistInfo && checklistInfo.had_bills === 1 ? ' disabled' : '';
+            html += '<tr>\n' +
+                '                                    <td><div class="text-center custom-control custom-checkbox mb-2">\n' +
+                '                                            <input type="checkbox" id="lists_'+ i +'" value="'+ i +'" name="customCheckbox" class="custom-control-input"'+ isChecked + isDisabled +'>\n' +
+                '                                            <label class="custom-control-label" for="lists_'+ i +'"></label>\n' +
+                '                                        </div></td>\n' +
+                '                                    <td class="text-center">'+ (i+1) +'</td>\n' +
+                '                                    <td>'+ l.b_code +'</td>\n' +
+                '                                    <td>'+ l.name +'</td>\n' +
+                '                                    <td class="text-center">'+ (l.unit ? l.unit : '') +'</td>\n' +
+                '                                    <td class="text-right">'+ (l.unit_price ? l.unit_price : '') +'</td>\n' +
+                '                                    <td class="text-right">'+ (l.quantity ? l.quantity : '') +'</td>\n' +
+                '                                    <td class="text-right">'+ (l.total_price ? l.total_price : '') +'</td>\n' +
+                '                                </tr>';
+        }
+    }
+    $('#lists_data').html(html);
+}
+
+// 清单搜索隐藏清单table部分值
+function remakeChecklistData(lists, showListData = lists) {
+    // 先加载台账数据
+    if (lists.length > 0) {
+        for (const [index,gcl] of lists.entries()) {
+            const isShow = _.find(showListData, gcl);
+            $('#lists_data tr').eq(index).css('display', (isShow ? 'table-row' : 'none'));
+        }
+    }
+}
+
+$(document).ready(() => {
+    function TipCellType()
+    {
+    }
+    TipCellType.prototype = new GC.Spread.Sheets.CellTypes.ColumnHeader();
+    TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+        return { x: x, y: y, row: context.row, col: context.col, cellRect: cellRect, sheetArea: context.sheetArea, sheet: context.sheet };
+    };
+    TipCellType.prototype.processMouseEnter = function (hitInfo){
+        if (!this._toolTipElement) {
+            var div = document.createElement("div");
+            $(div).css("position", "absolute")
+                .css("border", "1px #C0C0C0 solid")
+                .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
+                .css("font", "9pt Arial")
+                .css("background", "#fff")
+                // .css("color", "#fff")
+                .css("z-index", "1000")
+                .css("padding", 5);
+            this._toolTipElement = div;
+        }
+        $(this._toolTipElement).text("单位数量:每一单位清单下所需工料消耗量。")
+            .css("top", hitInfo.y + 15)
+            .css("left", hitInfo.x - 15);
+        $(this._toolTipElement).hide();
+        // document.body.insertBefore(this._toolTipElement, null);
+        $('#material-spread-div').append(this._toolTipElement, null);
+        $(this._toolTipElement).show("fast");
+    };
+    TipCellType.prototype.processMouseLeave = function (hitInfo) {
+        if (this._toolTipElement) {
+            this._toolTipElement.remove();
+            this._toolTipElement = null;
+        }
+    };
+    autoFlashHeight();
+    // 清单table
+    const ledgerSpread = SpreadJsObj.createNewSpread($('#ledger-spread')[0]);
+    const ledgerSpreadSetting = {
+        cols: [
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 220, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 70, type: 'Number'},
+            {title: '工程量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 90, type: 'Number'},
+            {title: '台账金额', colSpan: '1', rowSpan: '2', field: 'total_price', hAlign: 2, width: 110, type: 'Number'},
+        ],
+        emptyRows: 0,
+        headRows: 1,
+        headRowHeight: [25, 25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+    };
+    SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
+
+    // 加载清单数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
+    postData(window.location.pathname + '/load', {}, function (result) {
+        ledger = result.ledger;
+        curLedgerData = result.curLedgerData;
+        pos = result.pos;
+        curPosData = result.curPosData;
+        materialListData = result.materialListData;
+        notJoinList = result.materialNotJoinListData;
+        materialChecklistData = result.materialChecklistData;
+        // 解析清单汇总数据
+        gclGatherModel.loadLedgerData(ledger, curLedgerData);
+        gclGatherModel.loadPosData(pos, curPosData);
+        gclGatherData = gclGatherModel.gatherGclData();
+        console.log(gclGatherData);
+        const hadBillsidList = _.uniq(_.map(materialListData, 'gcl_id'));
+        console.log(hadBillsidList);
+        // 对比清单设置和调差清单,还要和台账对比,显示已选清单列表 不同则更新到清单设置页中
+        const pushData = [];
+        const updateData = [];
+        for (const hb of hadBillsidList) {
+            const gcl = _.find(gclGatherData, function (item) {
+                return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, { gcl_id : hb }) !== -1;
+            });
+            if (gcl) {
+                const mc = _.find(materialChecklistData, { b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price });
+                // const newOrder = _.indexOf(gclGatherData, gcl);
+                // console.log(newOrder);
+                if (!mc && _.findIndex(pushData, { b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price }) === -1) {
+                    pushData.push({ b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price, quantity: (gcl.quantity ? gcl.quantity : null), total_price: (gcl.total_price ? gcl.total_price : null), had_bills: 1 });
+                }
+            }
+        }
+        const removeData = [];
+        for (const mc of materialChecklistData) {
+            const gcl = _.find(gclGatherData, { b_code: mc.b_code, name: mc.name, unit: mc.unit, unit_price: mc.unit_price });
+            // 判断是否已不存在工料清单,台账修改过后删除之
+            if (!gcl) {
+                removeData.push(mc.id);
+            }
+            // 更新had_bills值
+            if (mc.had_bills === 1) {
+                if (_.indexOf(hadBillsidList, gcl.leafXmjs ? gcl.leafXmjs[0].gcl_id : null) === -1) {
+                    updateData.push({ id: mc.id, mid: materialID, had_bills: 0 });
+                }
+            }
+        }
+        setChecklistData(pushData, removeData, updateData, true);
+    });
+    function setChecklistData(pushData, removeData, updateData = [], sendmsg = false) {
+        if (pushData.length > 0 || removeData.length > 0 || updateData.length > 0) {
+            postData(window.location.pathname + '/save', { type: 'resetChecklist', pushData, removeData, updateData }, function (result2) {
+                if (sendmsg && pushData.length > 0) {
+                    toastr.success('已同步历史调差清单数据至本页中');
+                }
+                if (sendmsg && removeData.length > 0) {
+                    toastr.warning('已删除部分与台账清单不匹配的清单数据');
+                }
+                materialChecklistData = result2;
+                showSjsData();
+            })
+        } else {
+            showSjsData();
+        }
+    }
+    function showSjsData() {
+        SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialChecklistData);
+        SpreadJsObj.resetTopAndSelect(ledgerSpread.getActiveSheet());
+        if (materialChecklistData.length > 0) {
+            const index = _.findIndex(gclGatherData, { b_code: materialChecklistData[0].b_code, name: materialChecklistData[0].name, unit: materialChecklistData[0].unit, unit_price: materialChecklistData[0].unit_price });
+            loadMaterialData(index, 0);
+        } else {
+            loadMaterialData(-1, 0);
+        }
+        const sheet = materialSpread.getActiveSheet();
+        sheet.suspendPaint();
+        sheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+        sheet.resumePaint();
+    }
+    // 调差清单工料table
+    const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
+    const materialSpreadSetting = {
+        cols: [
+            {title: '清单工料含量|编号', colSpan: '5|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '|名称', colSpan: '|1', rowSpan: '|1', field: 'name', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+            {title: '|单位', colSpan: '|1', rowSpan: '|1', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true},
+            {title: '|数量 �', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 80, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|计算式', colSpan: '1', rowSpan: '|1', field: 'expr', hAlign: 2, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [25, 25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+    };
+
+    const materialBase = {
+        isEdit: function (data) {
+            // 是否本期添加的工料
+            return data.order === stage_order;
+        }
+    };
+
+    const materialCol = {
+        readOnly: {
+            isEdit: function (data) {
+                return !(!readOnly && materialBase.isEdit(data));
+            },
+        },
+    };
+    SpreadJsObj.initSpreadSettingEvents(materialSpreadSetting, materialCol);
+    // 获取项目节数据
+    let materialList = [];
+    function loadMaterialData(iGclRow, iLXmjRow) {
+        const gcl = gclGatherData[iGclRow];
+        if (gcl && gcl.leafXmjs[iLXmjRow]) {
+            const xmj = gcl.leafXmjs[iLXmjRow];
+            materialList = [];
+            materialList = _.filter(materialListData, function (m) {
+                return m.gcl_id === xmj.gcl_id && m.xmj_id === xmj.id && ((xmj.mx_id !==undefined && m.mx_id === xmj.mx_id) || xmj.mx_id === undefined);
+            });
+            // for (const m of materialListData) {
+            //     if (m.gcl_id === xmj.gcl_id && m.xmj_id === xmj.id && ((xmj.mx_id !==undefined && m.mx_id === xmj.mx_id) || xmj.mx_id === undefined)) {
+            //         materialList.push(m);
+            //     }
+            // }
+            // 对清单调差工料table的单位数量进行改变
+            materialSpreadSetting.cols[materialSpreadSetting.cols.length - 2].title = '|' + gcl.unit + '数量 �';
+            SpreadJsObj.initSheet(materialSpread.getActiveSheet(), materialSpreadSetting);
+            SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialList);
+        } else {
+            materialSpreadSetting.cols[materialSpreadSetting.cols.length - 2].title = '数量 �';
+            SpreadJsObj.initSheet(materialSpread.getActiveSheet(), materialSpreadSetting);
+            SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, []);
+        }
+        SpreadJsObj.resetTopAndSelect(materialSpread.getActiveSheet());
+    }
+
+    // 对添加工料表格赋值
+    function changeMaterialTable() {
+        $('#materialBills tr').removeClass('table-secondary');
+        $('#materialBills').find('input').removeAttr('disabled');
+        $('#materialBills').find('input').prop('checked', false);
+        for (const ml of materialList) {
+            const mbIndex = _.findIndex(materialBillsData, {id : ml.mb_id });
+            if (mbIndex !== -1) {
+                $('#materialBills tr').eq(mbIndex).addClass('table-secondary');
+                $('#materialBills').find('input').eq(mbIndex).attr('disabled', true);
+                $('#materialBills').find('input').eq(mbIndex).prop('checked', true);
+            }
+        }
+    }
+    // 选中清单并添加
+    $('#set_checklist_btn').click(function () {
+        const select_checklist = $('#lists_data').find('input:checked:not(:disabled)');
+        const pushData = [];
+        for (const sc of select_checklist) {
+            const order = parseInt($(sc).val());
+            const checklistInfo = _.find(materialChecklistData, { b_code: gclGatherData[order].b_code, name: gclGatherData[order].name, unit: gclGatherData[order].unit, unit_price: gclGatherData[order].unit_price });
+            if (!checklistInfo) {
+                pushData.push({
+                    b_code: gclGatherData[order].b_code,
+                    name: gclGatherData[order].name,
+                    unit: gclGatherData[order].unit,
+                    unit_price: gclGatherData[order].unit_price,
+                    quantity: gclGatherData[order].quantity ? gclGatherData[order].quantity : null,
+                    total_price: gclGatherData[order].total_price ? gclGatherData[order].total_price : null,
+                    had_bills: 0,
+                })
+            }
+        }
+        const notSelect_checklist = $('#lists_data').find('input:not(:checked):not(:disabled)');
+        const removeData = [];
+        for (const nsc of notSelect_checklist) {
+            const order = parseInt($(nsc).val());
+            // const order = parseInt($(nsc).attr('data-index'));
+            const checklistInfo = _.find(materialChecklistData, { b_code: gclGatherData[order].b_code, name: gclGatherData[order].name, unit: gclGatherData[order].unit, unit_price: gclGatherData[order].unit_price });
+            if (checklistInfo) {
+               removeData.push(checklistInfo.id);
+            }
+        }
+        setChecklistData(pushData, removeData);
+        $('#addtclist').modal('hide');
+    });
+    // 筛选无调差工料清单
+    $('#notBills_checkList').click(function () {
+        const isCheck = $(this).is(':checked');
+        let newMaterialChecklistData = materialChecklistData;
+        if (isCheck) {
+            newMaterialChecklistData = _.filter(materialChecklistData, { had_bills: 0 });
+        }
+        SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, newMaterialChecklistData);
+        SpreadJsObj.resetTopAndSelect(ledgerSpread.getActiveSheet());
+        if (newMaterialChecklistData.length > 0) {
+            const index = _.findIndex(gclGatherData, { b_code: newMaterialChecklistData[0].b_code, name: newMaterialChecklistData[0].name, unit: newMaterialChecklistData[0].unit, unit_price: newMaterialChecklistData[0].unit_price });
+            loadMaterialData(index, 0);
+        } else {
+            loadMaterialData(-1, 0);
+        }
+    });
+    // 添加调差工料
+    $('#add_material_bill').click(function () {
+        // 获取已选工料
+        $('#materialBills').find('input:disabled').prop('checked', false);
+        const selectList = $('#materialBills').find('input:checked');
+        if (selectList.length === 0) {
+            toastr.warning('请选择调差工料');
+            $('#materialBills').find('input:disabled').prop('checked', true);
+            return false;
+        }
+        const mb_id = [];
+        for (let s = 0; s < selectList.length; s++) {
+            mb_id.push($('#materialBills').find('input:checked').eq(s).val());
+        }
+        // 获取当前项目节或部位明细id
+        const sheet = ledgerSpread.getActiveSheet();
+        const select = SpreadJsObj.getSelectObject(sheet);
+        const gclIndex = _.findIndex(gclGatherData, { b_code: select.b_code, name: select.name, unit: select.unit, unit_price: select.unit_price });
+        const gcl = gclGatherData[gclIndex].leafXmjs;
+        const index = materialChecklistData.indexOf(select);
+        const datas = [];
+        for (const xmj of gcl) {
+            const notx = findNotJoinLeafXmj(xmj);
+            const data = {
+                xmj_id: xmj.id,
+                gcl_id: xmj.gcl_id,
+                mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
+                gather_qty: xmj.gather_qty,
+                is_join: notx === undefined ? 1 : 0,
+            };
+            datas.push(data);
+        }
+        // 上传到数据库
+        console.log(datas, gcl);
+        postData(window.location.pathname + '/save', {type: 'adds', checklist: { id: select.id, had_bills: 1 }, postData: {xmjs: datas, mbIds: mb_id}}, function (result) {
+            materialListData = result;
+            materialChecklistData[index].had_bills = 1;
+            loadMaterialData(gclIndex, 0);
+            // SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+            $('#addgl').modal('hide');
+        });
+        $('#materialBills').find('input:disabled').prop('checked', true);
+    });
+    if (!readOnly) {
+        // material-spread右键功能
+        const materialSpreadObj = {
+            del: function () {
+                const materialSheet = materialSpread.getActiveSheet();
+                const materialSelect = SpreadJsObj.getSelectObject(materialSheet);
+                const sheet = ledgerSpread.getActiveSheet();
+                const select = SpreadJsObj.getSelectObject(sheet);
+                const index = materialChecklistData.indexOf(select);
+                const gclIndex = _.findIndex(gclGatherData, { b_code: select.b_code, name: select.name, unit: select.unit, unit_price: select.unit_price });
+                const gcl = gclGatherData[gclIndex].leafXmjs;
+                const datas = [];
+                for (const xmj of gcl) {
+                    const data = {
+                        xmj_id: xmj.id,
+                        gcl_id: xmj.gcl_id,
+                        mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
+                    };
+                    datas.push(data);
+                }
+                const xmj = gcl[0];
+                const materialCount = _.size(_.filter(materialListData, function (m) {
+                    return m.gcl_id === xmj.gcl_id && m.xmj_id === xmj.id && ((xmj.mx_id !==undefined && m.mx_id === xmj.mx_id) || xmj.mx_id === undefined);
+                }));
+                let checklist = false;
+                if (materialCount === 1) {
+                    checklist = {
+                        id: select.id,
+                        had_bills: 0,
+                    }
+                }
+                console.log(datas, materialSelect.mb_id, checklist);
+                postData(window.location.pathname + '/save', {type: 'dels', checklist, postData: { xmjs: datas, mb_id: materialSelect.mb_id }}, function (result) {
+                    materialListData = result;
+                    if (checklist) materialChecklistData[index].had_bills = checklist.had_bills;
+                    loadMaterialData(gclIndex, 0);
+                    // SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+                });
+            },
+            deletePress: function (sheet) {
+                return;
+            },
+            editStarting: function (e, info) {
+                const col = info.sheet.zh_setting.cols[info.col];
+                const select = SpreadJsObj.getSelectObject(info.sheet);
+                if (col.field === 'quantity') {
+                    if (select.expr && select.expr !== '') {
+                        info.sheet.getCell(info.row, info.col).text(select.expr);
+                    }
+                }
+            },
+            editEnded: function (e, info) {
+                if (info.sheet.zh_setting) {
+                    const select = SpreadJsObj.getSelectObject(info.sheet);
+                    const col = info.sheet.zh_setting.cols[info.col];
+                    const validText = info.editingText ? info.editingText.replace('\n', '') : null;
+                    let orgValue;
+                    if (col.field === 'quantity') {
+                        orgValue = validText && validText !== ''
+                            ? _.toNumber(validText) ? select.quantity : select.expr
+                            : (select.expr && select.expr !== '') ? select.expr : select.quantity;
+                    } else {
+                        orgValue = select[col.field];
+                    }
+                    if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === '' || validText === null))) {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    const exprQuantity = {
+                        expr: '',
+                        quantity: 0,
+                    };
+                    const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
+                    if (!valid) {
+                        toastr.error(msg);
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    if (isNaN(exprQuantity.quantity)) {
+                        toastr.error('不能输入其它非数字类型字符');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    const num = parseFloat(exprQuantity.quantity);
+                    if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
+                        toastr.warning('已保留6位小数');
+                        exprQuantity.quantity = ZhCalc.round(num, 6);
+                    }
+                    // 更新至服务器
+                    const ledgerSheet = ledgerSpread.getActiveSheet();
+                    const ledgerSelect = SpreadJsObj.getSelectObject(ledgerSheet);
+                    const gclIndex = _.findIndex(gclGatherData, { b_code: ledgerSelect.b_code, name: ledgerSelect.name, unit: ledgerSelect.unit, unit_price: ledgerSelect.unit_price });
+                    const gcl = gclGatherData[gclIndex].leafXmjs;
+                    const datas = [];
+                    for (const xmj of gcl) {
+                        const data = {
+                            xmj_id: xmj.id,
+                            gcl_id: xmj.gcl_id,
+                            mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
+                        };
+                        datas.push(data);
+                    }
+                    console.log(exprQuantity, datas, select.mb_id);
+                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id } }, function (result) {
+                        materialListData = result;
+                        loadMaterialData(gclIndex, 0);
+                        materialSpread.getActiveSheet().setSelection(info.row + 1, info.col, 1, 1);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    });
+                }
+            },
+            clipboardPasted(e, info) {
+                const hint = {
+                    cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
+                    numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
+                    numberCan: {type: 'warning', msg: '已保留6位小数'},
+                };
+                const range = info.cellRange;
+                const sortData = info.sheet.zh_data || [];
+                if (range.row + range.rowCount > sortData.length) {
+                    toastMessageUniq(hint.cellError);
+                    SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
+                    SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+                    return;
+                }
+                if (sortData.length > 0 && range.col + range.colCount > 5) {
+                    toastMessageUniq(hint.cellError);
+                    SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
+                    SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+                    return;
+                }
+                const data = [];
+                for (let iRow = 0; iRow < range.rowCount; iRow++) {
+                    let bPaste = true;
+                    const curRow = range.row + iRow;
+                    const materialData = { id: sortData[curRow].id, mb_id: sortData[curRow].mb_id };
+                    const hintRow = range.rowCount > 1 ? curRow : '';
+                    let sameCol = 0;
+                    for (let iCol = 0; iCol < range.colCount; iCol++) {
+                        const curCol = range.col + iCol;
+                        const colSetting = info.sheet.zh_setting.cols[curCol];
+                        if (!colSetting) continue;
+
+                        const validText = info.sheet.getText(curRow, curCol).replace('\n', '');
+                        const orgValue = sortData[curRow][colSetting.field];
+                        if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
+                            sameCol++;
+                            if (range.colCount === sameCol)  {
+                                bPaste = false;
+                            }
+                            continue;
+                        }
+                        const exprQuantity = {
+                            expr: '',
+                            quantity: 0,
+                        };
+                        const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
+                        if (!valid) {
+                            toastMessageUniq(getPasteHint(msg, hintRow));
+                            bPaste = false;
+                            continue;
+                        }
+                        if (isNaN(exprQuantity.quantity)) {
+                            toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
+                            bPaste = false;
+                            continue;
+                        }
+                        const num = parseFloat(exprQuantity.quantity);
+                        if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
+                            toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
+                            exprQuantity.quantity = ZhCalc.round(num, 6);
+                        }
+                        materialData.expr = exprQuantity.expr;
+                        materialData.quantity = exprQuantity.quantity;
+                    }
+                    if (bPaste) {
+                        data.push(materialData);
+                    } else {
+                        SpreadJsObj.reLoadRowData(info.sheet, curRow);
+                    }
+                }
+                if (data.length === 0) {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    return;
+                }
+                const ledgerSheet = ledgerSpread.getActiveSheet();
+                const ledgerSelect = SpreadJsObj.getSelectObject(ledgerSheet);
+                const gclIndex = _.findIndex(gclGatherData, { b_code: ledgerSelect.b_code, name: ledgerSelect.name, unit: ledgerSelect.unit, unit_price: ledgerSelect.unit_price });
+                const gcl = gclGatherData[gclIndex].leafXmjs;
+                const datas = [];
+                for (const xmj of gcl) {
+                    const data2 = {
+                        xmj_id: xmj.id,
+                        gcl_id: xmj.gcl_id,
+                        mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
+                    };
+                    datas.push(data2);
+                }
+                console.log(data, datas);
+                // 更新至服务器
+                postData(window.location.pathname + '/save', { type:'pastes', updateData: { xmjs: datas, pasteData: data } }, function (result) {
+                    materialListData = result;
+                    loadMaterialData(gclIndex, 0);
+                    materialSpread.getActiveSheet().setSelection(info.cellRange.row, info.cellRange.col, info.cellRange.rowCount, info.cellRange.colCount);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+            _checkExprValid(expr) {
+                if (!expr) return [true, null];
+                const param = [];
+                let num = '', base = '';
+                for (let i = 0, iLen = expr.length; i < iLen; i++) {
+                    if (/^[\d\.%]+/.test(expr[i])) {
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        num = num + expr[i];
+                    } else if (expr[i] === '(') {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            num = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'left', value: '('});
+                    } else if (expr[i] === ')') {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            num = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'right', value: ')'});
+                    } else if (/^[\+\-*\/]/.test(expr[i])) {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            num = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'calc', value: expr[i]});
+                    } else {
+                        return [false, '输入的表达式含有非法字符: ' + expr[i]];
+                    }
+                }
+                if (num !== '') {
+                    param.push({type: 'num', value: num});
+                    num = '';
+                }
+                if (base !== '') {
+                    param.push({type: 'base', value: base});
+                    base = '';
+                }
+                if (param.length === 0) return true;
+                if (param.length > 1) {
+                    if (param[0].value === '-') {
+                        param[1].value = '-' + param[1];
+                    }
+                    param.unshift();
+                }
+                const iLen = param.length;
+                let iLeftCount = 0, iRightCount = 0;
+                for (const [i, p] of param.entries()) {
+                    if (p.type === 'calc') {
+                        if (i === 0 || i === iLen - 1)
+                            return [false, '输入的表达式非法:计算符号' + p.value + '前后应有数字'];
+                    }
+                    if (p.type === 'num') {
+                        num = p.value.replace('%', '');
+                        if (p.value.length - num.length > 1)
+                            return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
+                        num = _.toNumber(num);
+                        if (num === undefined || num === null || _.isNaN(num))
+                            return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
+                        if (i > 0) {
+                            if (param[i - 1].type !== 'calc' && param[i - 1].type !== 'left') {
+                                return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
+                            } else if (param[i - 1].value === '/' && num === 0) {
+                                return [false, '输入的表达式非法:请勿除0'];
+                            }
+                        }
+                    }
+                    if (p.type === 'base') {
+                        if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
+                            return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
+                    }
+                    if (p.type === 'left') {
+                        iLeftCount += 1;
+                        if (i !== 0 && param[i-1].type !== 'calc')
+                            return [false, '输入的表达式非法:(前应有运算符'];
+                    }
+                    if (p.type === 'right') {
+                        iRightCount += 1;
+                        if (i !== iLen - 1 && param[i+1].type !== 'calc')
+                            return [false, '输入的表达式非法:)后应有运算符'];
+                        if (iRightCount > iLeftCount)
+                            return [false, '输入的表达式非法:")"前无对应的"("'];
+                    }
+                }
+                if (iLeftCount > iRightCount)
+                    return [false, '输入的表达式非法:"("后无对应的")"'];
+                return [true, ''];
+            },
+            _checkExpr: function (text, data) {
+                if (text) {
+                    const num = _.toNumber(text);
+                    if (num) {
+                        data.quantity = num;
+                        data.expr = '';
+                    } else {
+                        const expr = $.trim(text).replace('\t', '').replace('=', '').toLowerCase();
+                        const [valid, msg] = this._checkExprValid(expr);
+                        if (!valid) return [valid, msg];
+                        data.expr = expr;
+                        data.quantity = ZhCalc.calcExpr.calcExprStrRpn(expr);
+                    }
+                } else {
+                    data.quantity = 0;
+                    data.expr = '';
+                }
+                return [true, ''];
+            },
+        };
+        materialSpread.bind(spreadNS.Events.EditStarting, materialSpreadObj.editStarting);
+        materialSpread.bind(spreadNS.Events.EditEnded, materialSpreadObj.editEnded);
+        materialSpread.bind(spreadNS.Events.ClipboardPasted, materialSpreadObj.clipboardPasted);
+        SpreadJsObj.addDeleteBind(materialSpread, materialSpreadObj.deletePress);
+        $.contextMenu({
+            selector: '#material-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
+                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                'create': {
+                    name: '添加工料',
+                    icon: 'fa-sign-in',
+                    callback: function (key, opt) {
+                        // 获取已选清单
+                        changeMaterialTable();
+                        $('#addgl').modal('show');
+                    },
+                    disabled: function (key, opt) {
+                        const sheet = ledgerSpread.getActiveSheet();
+                        const select = SpreadJsObj.getSelectObject(sheet);
+                        if (!select) {
+                            return true;
+                        }
+                        return readOnly;
+                    }
+                },
+                'delete': {
+                    name: '删除工料',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        materialSpreadObj.del(materialSpread.getActiveSheet());
+                    },
+                    disabled: function (key, opt) {
+                        const sheet = materialSpread.getActiveSheet();
+                        const selection = sheet.getSelections();
+                        const sel = selection ? selection[0] : sheet.getSelections()[0];
+                        const select = SpreadJsObj.getSelectObject(sheet);
+                        if (!select) {
+                            return true;
+                        }
+                        if (!readOnly && sel.rowCount === 1 && select && materialBase.isEdit(select)) {
+                            return false;
+                        } else {
+                            return true;
+                        }
+                    }
+                },
+            }
+        });
+    }
+
+    // 切换清单行,读取所属项目节数据
+    ledgerSpread.getActiveSheet().bind(spreadNS.Events.SelectionChanged, function (e, info) {
+        if (info.oldSelections !== undefined) {
+            const iOldRow = info.oldSelections[0].row, iNewRow = info.newSelections[0].row;
+            if (iNewRow !== iOldRow) {
+                const sheet = ledgerSpread.getActiveSheet();
+                const select = SpreadJsObj.getSelectObject(sheet);
+                const index = _.findIndex(gclGatherData, { b_code: select.b_code, name: select.name, unit: select.unit, unit_price: select.unit_price });
+                loadMaterialData(index, 0);
+            }
+        }
+    });
+
+    $('#open_addtclist').click(function () {
+        $('#tclist_search').val('');
+        $('#tclist_search').siblings('a').hide();
+        makeChecklistData(gclGatherData, materialChecklistData);
+        $('#addtclist').modal('show');
+    });
+
+    // 回车提交
+    $('#tclist_search').on('keypress', function () {
+        if(window.event.keyCode === 13) {
+            $(this).blur();
+        }
+    });
+
+    $('#tclist_search').on('blur', function () {
+        const value = _.trim($(this).val());
+        let showListData = gclGatherData;
+        if (value !== '') {
+            $(this).siblings('a').show();
+            showListData = _.filter(gclGatherData, function (c) {
+                return (c.b_code && c.b_code.indexOf(value) !== -1) || (c.name && c.name.indexOf(value) !== -1);
+            })
+        } else {
+            $(this).siblings('a').hide();
+        }
+        remakeChecklistData(gclGatherData, showListData);
+    });
+
+    $('.remove-btn').on('click', function () {
+        $(this).hide();
+        $(this).siblings('input').val('');
+        remakeChecklistData(gclGatherData);
+    });
+
+    // 显示有调差工料清单
+    // $('#show_material_gcl').click(function () {
+    //     if ($(this).is(':checked')) {
+    //         const hadMaterialGclGatherData = [];
+    //         const hadGclIdList = [];
+    //         for (const ml of materialListData) {
+    //             if (hadGclIdList.indexOf(ml.gcl_id) === -1) {
+    //                 hadGclIdList.push(ml.gcl_id);
+    //             }
+    //         }
+    //         for (const gcl of gclGatherData) {
+    //             for (const index in gcl.leafXmjs) {
+    //                 const gcl_id = gcl.leafXmjs[index].gcl_id;
+    //                 if (hadGclIdList.indexOf(gcl_id) !== -1) {
+    //                     hadMaterialGclGatherData.push(gcl);
+    //                     break;
+    //                 }
+    //             }
+    //         }
+    //         gclGatherData = hadMaterialGclGatherData;
+    //     } else {
+    //         gclGatherModel.loadLedgerData(ledger, curLedgerData);
+    //         gclGatherModel.loadPosData(pos, curPosData);
+    //         gclGatherData = gclGatherModel.gatherGclData().filter(item => {
+    //             return item.qc_qty || item.contract_qty
+    //         });
+    //     }
+    //     SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
+    //     loadLeafXmjData(0);
+    //     loadMaterialData(0, 0);
+    //     SpreadJsObj.resetTopAndSelect(ledgerSpread.getActiveSheet());
+    //     SpreadJsObj.resetTopAndSelect(leafXmjSpread.getActiveSheet());
+    //     SpreadJsObj.resetTopAndSelect(materialSpread.getActiveSheet());
+    // });
+
+    $.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');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            ledgerSpread.refresh();
+            materialSpread.refresh();
+        }
+    });
+
+    $.divResizer({
+        select: '#right-spr',
+        callback: function () {
+            ledgerSpread.refresh();
+            materialSpread.refresh();
+            const width = (($('#right-view').width()/$('#right-view').parent('div').width())*100).toFixed();
+            setLocalCache('material_checklist_' + materialID, width);
+        }
+    });
+
+    // 展开收起工料并浏览器记住本期展开收起
+    $('a', '.right-nav').bind('click', function () {
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        if (!tab.hasClass('active')) {
+            $('a', '.side-menu').removeClass('active');
+            $('.tab-content .tab-select-show').removeClass('active');
+            tab.addClass('active');
+            tabPanel.addClass('active');
+            showSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#material-tab') {
+                const width = (($('#right-view').width()/$('#right-view').parent('div').width())*100).toFixed();
+                setLocalCache('material_checklist_' + materialID, width);
+            }
+        } else {
+            removeLocalCache('material_checklist_' + materialID);
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showSideTools(tab.hasClass('active'));
+        }
+        ledgerSpread.refresh();
+        materialSpread.refresh();
+    });
+    // 根据浏览器记录展开收起
+    if (getLocalCache('material_checklist_' + materialID)) {
+        const tab = $('.right-nav a[content="#material-tab"]'), tabPanel = $(tab.attr('content'));
+        $('a', '.side-menu').removeClass('active');
+        $('.tab-content .tab-select-show').removeClass('active');
+        tab.addClass('active');
+        tabPanel.addClass('active');
+        $('#right-view').width(getLocalCache('material_checklist_' + materialID) + '%');
+        showSideTools(tab.hasClass('active'));
+        ledgerSpread.refresh();
+        materialSpread.refresh();
+    }
+});

+ 13 - 11
app/public/js/material_exponent.js

@@ -14,10 +14,10 @@ function getPasteHint (str, row = '') {
 }
 }
 function resetExTpTable() {
 function resetExTpTable() {
     const rate = $('#changeRate').val();
     const rate = $('#changeRate').val();
-    const bqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), 2);
-    const jzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, bqhs), 2);
-    $('#tp_set').find('td').eq(3).text(ZhCalc.round(ex_tp, 2));
-    $('#tp_set').find('td').eq(4).text(ZhCalc.round(ZhCalc.add(ex_pre_tp, ex_tp), 2));
+    const bqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
+    const jzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, bqhs), materialDecimal.tp);
+    $('#tp_set').find('td').eq(3).text(ZhCalc.round(ex_tp, materialDecimal.tp));
+    $('#tp_set').find('td').eq(4).text(ZhCalc.round(ZhCalc.add(ex_pre_tp, ex_tp), materialDecimal.tp));
     $('#rate_set').find('td').eq(3).text(bqhs !== 0 ? bqhs : '');
     $('#rate_set').find('td').eq(3).text(bqhs !== 0 ? bqhs : '');
     $('#rate_set').find('td').eq(4).text(jzbqhs !== 0 ? jzbqhs : '');
     $('#rate_set').find('td').eq(4).text(jzbqhs !== 0 ? jzbqhs : '');
     // $('#ex_expr').html(ex_expr);
     // $('#ex_expr').html(ex_expr);
@@ -504,7 +504,7 @@ $(document).ready(() => {
         $('#calc_zdy').on('blur', function () {
         $('#calc_zdy').on('blur', function () {
             let newValue = parseFloat($(this).val());
             let newValue = parseFloat($(this).val());
             // 判断输入位数,并自动四舍五入
             // 判断输入位数,并自动四舍五入
-            newValue = ZhCalc.round(newValue, decimal.tp);
+            newValue = ZhCalc.round(newValue, materialDecimal.tp);
             $('#calc_zdy').val(newValue);
             $('#calc_zdy').val(newValue);
             if (isNaN(newValue)) {
             if (isNaN(newValue)) {
                 toastr.error('请输入正确的金额');
                 toastr.error('请输入正确的金额');
@@ -527,12 +527,14 @@ $(document).ready(() => {
         $('#changeRate').change(function () {
         $('#changeRate').change(function () {
             const rate = parseInt($(this).val());
             const rate = parseInt($(this).val());
             postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
             postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
-                const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), 2);
-                const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), 2);
-                const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), 2);
-                const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), 2);
-                $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
-                $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+                const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
+                const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
+                if (!materialTax) {
+                    const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+                    const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
+                    $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
+                    $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+                }
                 $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
                 $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
                 $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
                 $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
             });
             });

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

@@ -9,7 +9,7 @@
 
 
 $(document).ready(function () {
 $(document).ready(function () {
     // 每页最多几个附件
     // 每页最多几个附件
-    const pageCount = 15;
+    const pageCount = 20;
     // 全局fileData初始化
     // 全局fileData初始化
     let fileData = fileList || []
     let fileData = fileList || []
     // let currPageFileData = [];
     // let currPageFileData = [];
@@ -257,8 +257,8 @@ $(document).ready(function () {
         // console.log('fileIds', fileIds)
         // console.log('fileIds', fileIds)
 
 
         if (fileIds.length) {
         if (fileIds.length) {
-            if (fileIds.length > 10) {
-              return toastr.warning(`最大允许10个文件(当前${fileIds.length}个)`)
+            if (fileIds.length > 20) {
+              return toastr.warning(`最大允许20个文件(当前${fileIds.length}个)`)
             }
             }
             toastr.success('正在进行下载并压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             toastr.success('正在进行下载并压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             $(this).attr('disabled', "true");
             $(this).attr('disabled', "true");

+ 89 - 61
app/public/js/material_list.js

@@ -49,7 +49,7 @@ function calcOneBQJC(xmj) {
             jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(xmj.gather_qty, l.quantity), getMpSpreadByMBData(l.mb_id)));
             jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(xmj.gather_qty, l.quantity), getMpSpreadByMBData(l.mb_id)));
         }
         }
     }
     }
-    return ZhCalc.round(jiacha, 2);
+    return ZhCalc.round(jiacha, materialDecimal.tp);
 }
 }
 
 
 function getPasteHint (str, row = '') {
 function getPasteHint (str, row = '') {
@@ -71,7 +71,7 @@ function calculateJiaCha(data, index) {
             gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
             gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
             total_jiacha += jiacha;
             total_jiacha += jiacha;
         }
         }
-        gcld.total_jiacha = ZhCalc.round(total_jiacha, 2)
+        gcld.total_jiacha = ZhCalc.round(total_jiacha, materialDecimal.tp)
     } else {
     } else {
         for(const gcld of data) {
         for(const gcld of data) {
             let total_jiacha = 0;
             let total_jiacha = 0;
@@ -80,7 +80,7 @@ function calculateJiaCha(data, index) {
                 gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
                 gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
                 total_jiacha += jiacha;
                 total_jiacha += jiacha;
             }
             }
-            gcld.total_jiacha = ZhCalc.round(total_jiacha, 2)
+            gcld.total_jiacha = ZhCalc.round(total_jiacha, materialDecimal.tp)
         }
         }
     }
     }
 }
 }
@@ -160,7 +160,7 @@ $(document).ready(() => {
         if (gcl) {
         if (gcl) {
             for (const [index, xmj] of gcl.leafXmjs.entries()) {
             for (const [index, xmj] of gcl.leafXmjs.entries()) {
                 const jiacha = calcOneBQJC(xmj);
                 const jiacha = calcOneBQJC(xmj);
-                gcl.leafXmjs[index].jiacha = jiacha !== 0 ? ZhCalc.round(jiacha, 2) : null;
+                gcl.leafXmjs[index].jiacha = jiacha !== 0 ? ZhCalc.round(jiacha, materialDecimal.tp) : null;
             }
             }
             const leafXmjs = gcl.leafXmjs.filter(item => {
             const leafXmjs = gcl.leafXmjs.filter(item => {
                 return item.qc_qty || item.contract_qty
                 return item.qc_qty || item.contract_qty
@@ -209,12 +209,19 @@ $(document).ready(() => {
         curPosData = result.curPosData;
         curPosData = result.curPosData;
         materialListData = result.materialListData;
         materialListData = result.materialListData;
         notJoinList = result.materialNotJoinListData;
         notJoinList = result.materialNotJoinListData;
+        materialChecklistData = result.materialChecklistData;
         // 解析清单汇总数据
         // 解析清单汇总数据
         gclGatherModel.loadLedgerData(ledger, curLedgerData);
         gclGatherModel.loadLedgerData(ledger, curLedgerData);
         gclGatherModel.loadPosData(pos, curPosData);
         gclGatherModel.loadPosData(pos, curPosData);
         gclGatherData = gclGatherModel.gatherGclData().filter(item => {
         gclGatherData = gclGatherModel.gatherGclData().filter(item => {
             return item.qc_qty || item.contract_qty
             return item.qc_qty || item.contract_qty
         });
         });
+        if (openMaterialChecklist) {
+            // 取交集
+            gclGatherData = _.filter(gclGatherData, function (item) {
+                return _.find(materialChecklistData, { b_code: item.b_code, name: item.name, unit: item.unit, unit_price: item.unit_price });
+            });
+        }
         calculateJiaCha(gclGatherData);
         calculateJiaCha(gclGatherData);
         SpreadJsObj.initSheet(leafXmjSpread.getActiveSheet(), leafXmjSpreadSetting);
         SpreadJsObj.initSheet(leafXmjSpread.getActiveSheet(), leafXmjSpreadSetting);
         // 加载清单数据
         // 加载清单数据
@@ -266,7 +273,7 @@ $(document).ready(() => {
     const materialBase = {
     const materialBase = {
         isEdit: function (data) {
         isEdit: function (data) {
             // 是否本期添加的工料
             // 是否本期添加的工料
-            return data.order === stage_order;
+            return data.order === stage_order && !openMaterialChecklist;
         }
         }
     };
     };
 
 
@@ -286,6 +293,10 @@ $(document).ready(() => {
     let materialList = [];
     let materialList = [];
     function loadMaterialData(iGclRow, iLXmjRow) {
     function loadMaterialData(iGclRow, iLXmjRow) {
         const gcl = gclGatherData[iGclRow];
         const gcl = gclGatherData[iGclRow];
+        // const leafXmjs = gcl.leafXmjs.filter(item => {
+        //     return item.qc_qty || item.contract_qty
+        // });
+        // console.log(iLXmjRow, leafXmjs, materialListData);
         if (gcl && gcl.leafXmjs[iLXmjRow]) {
         if (gcl && gcl.leafXmjs[iLXmjRow]) {
             const xmj = gcl.leafXmjs[iLXmjRow];
             const xmj = gcl.leafXmjs[iLXmjRow];
             materialList = [];
             materialList = [];
@@ -294,6 +305,7 @@ $(document).ready(() => {
                     materialList.push(m);
                     materialList.push(m);
                 }
                 }
             }
             }
+            console.log(materialList);
             SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialList);
             SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialList);
         } else {
         } else {
             SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, []);
             SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, []);
@@ -314,7 +326,9 @@ $(document).ready(() => {
         const select = SpreadJsObj.getSelectObject(sheet);
         const select = SpreadJsObj.getSelectObject(sheet);
         const index = gclGatherData.indexOf(select);
         const index = gclGatherData.indexOf(select);
         if (index !== -1) {
         if (index !== -1) {
-            const xmj = gclGatherData[index].leafXmjs;
+            const xmj = gclGatherData[index].leafXmjs.filter(item => {
+                return item.qc_qty || item.contract_qty
+            });
             const leafXmjSheet = leafXmjSpread.getActiveSheet();
             const leafXmjSheet = leafXmjSpread.getActiveSheet();
             for (const [iRow,x] of xmj.entries()) {
             for (const [iRow,x] of xmj.entries()) {
                 const notx = findNotJoinLeafXmj(x);
                 const notx = findNotJoinLeafXmj(x);
@@ -416,15 +430,21 @@ $(document).ready(() => {
                 const leafXmjSheet = leafXmjSpread.getActiveSheet();
                 const leafXmjSheet = leafXmjSpread.getActiveSheet();
                 const leafXmjSelect = SpreadJsObj.getSelectObject(leafXmjSheet);
                 const leafXmjSelect = SpreadJsObj.getSelectObject(leafXmjSheet);
                 const iRow = gclGatherData[index].leafXmjs.indexOf(leafXmjSelect);
                 const iRow = gclGatherData[index].leafXmjs.indexOf(leafXmjSelect);
-                return [index, iRow, leafXmjSheet, leafXmjSelect];
+                const leafXmjs = gclGatherData[index].leafXmjs.filter(item => {
+                    return item.qc_qty || item.contract_qty
+                });
+                const nRow = leafXmjs.indexOf(leafXmjSelect);
+                return [index, iRow, nRow, leafXmjSheet, leafXmjSelect];
             },
             },
             checkJoinMaterial: function (type) {
             checkJoinMaterial: function (type) {
-                const [iGclRow, iRow, sheet, select] = leafXmjSpreadObj.getSelect();
+                const [iGclRow, iRow, nRow, sheet, select] = leafXmjSpreadObj.getSelect();
                 const color = type === 'join' ? '' : '#d6d8db';
                 const color = type === 'join' ? '' : '#d6d8db';
                 const data = {
                 const data = {
                     type: type,
                     type: type,
                     select: type === 'join' ? findNotJoinLeafXmj(select) : select,
                     select: type === 'join' ? findNotJoinLeafXmj(select) : select,
-                }
+                };
+                console.log(iGclRow, iRow, nRow, select);
+                console.log(materialList);
                 // 添加到
                 // 添加到
                 postData(window.location.pathname + '/save', data, function (result) {
                 postData(window.location.pathname + '/save', data, function (result) {
                     if (type === 'join') {
                     if (type === 'join') {
@@ -434,10 +454,10 @@ $(document).ready(() => {
                         notJoinList.push(result);
                         notJoinList.push(result);
                     }
                     }
                     gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
                     gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
-                    calculateJiaCha(gclGatherData, iGclRow)
-                    SpreadJsObj.reLoadRowData(sheet, iRow);
-                    sheet.getRange(iRow, -1, 1, -1).backColor(color);
-                    loadMaterialData(iGclRow, iRow);
+                    calculateJiaCha(gclGatherData, iGclRow);
+                    SpreadJsObj.reLoadRowData(sheet, nRow);
+                    sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                    loadMaterialData(iGclRow, 0);
                     SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                     SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                 });
                 });
             },
             },
@@ -930,57 +950,59 @@ $(document).ready(() => {
             //     SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
             //     SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
             // });
             // });
         });
         });
-        $.contextMenu({
-            selector: '#material-spread',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
-                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
-            },
-            items: {
-                'create': {
-                    name: '添加工料',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        // 获取已选清单
-                        changeMaterialTable();
-                        $('#addgl').modal('show');
-                    },
-                    disabled: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        // const notx = findNotJoinLeafXmj(select);
-                        if (!select) {
-                            return true;
-                        }
-                        // if (!readOnly && notx === undefined) {
-                        //     return false;
-                        // } else {
-                        //     return true;
-                        // }
-                        return readOnly;
-                    }
+        if (!openMaterialChecklist) {
+            $.contextMenu({
+                selector: '#material-spread',
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
+                    return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
                 },
                 },
-                'delete': {
-                    name: '删除工料',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        materialSpreadObj.del(materialSpread.getActiveSheet());
-                    },
-                    disabled: function (key, opt) {
-                        const sheet = materialSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        if (!select) {
-                            return true;
+                items: {
+                    'create': {
+                        name: '添加工料',
+                        icon: 'fa-sign-in',
+                        callback: function (key, opt) {
+                            // 获取已选清单
+                            changeMaterialTable();
+                            $('#addgl').modal('show');
+                        },
+                        disabled: function (key, opt) {
+                            const sheet = leafXmjSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            // const notx = findNotJoinLeafXmj(select);
+                            if (!select) {
+                                return true;
+                            }
+                            // if (!readOnly && notx === undefined) {
+                            //     return false;
+                            // } else {
+                            //     return true;
+                            // }
+                            return readOnly;
                         }
                         }
-                        if (!readOnly && select && materialBase.isEdit(select)) {
-                            return false;
-                        } else {
-                            return true;
+                    },
+                    'delete': {
+                        name: '删除工料',
+                        icon: 'fa-remove',
+                        callback: function (key, opt) {
+                            materialSpreadObj.del(materialSpread.getActiveSheet());
+                        },
+                        disabled: function (key, opt) {
+                            const sheet = materialSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            if (!select) {
+                                return true;
+                            }
+                            if (!readOnly && select && materialBase.isEdit(select)) {
+                                return false;
+                            } else {
+                                return true;
+                            }
                         }
                         }
-                    }
-                },
-            }
-        });
+                    },
+                }
+            });
+        }
     }
     }
 
 
     // 切换清单行,读取所属项目节数据
     // 切换清单行,读取所属项目节数据
@@ -1036,6 +1058,12 @@ $(document).ready(() => {
             gclGatherData = gclGatherModel.gatherGclData().filter(item => {
             gclGatherData = gclGatherModel.gatherGclData().filter(item => {
                 return item.qc_qty || item.contract_qty
                 return item.qc_qty || item.contract_qty
             });
             });
+            if (openMaterialChecklist) {
+                // 取交集
+                gclGatherData = _.filter(gclGatherData, function (item) {
+                    return _.find(materialChecklistData, { b_code: item.b_code, name: item.name, unit: item.unit, unit_price: item.unit_price });
+                });
+            }
         }
         }
         calculateJiaCha(gclGatherData);
         calculateJiaCha(gclGatherData);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);

+ 104 - 25
app/public/js/revise.js

@@ -57,6 +57,37 @@ $(document).ready(() => {
     const billsSheet = billsSpread.getActiveSheet();
     const billsSheet = billsSpread.getActiveSheet();
     sjsSettingObj.setFxTreeStyle(billsSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     sjsSettingObj.setFxTreeStyle(billsSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(billsSpreadSetting);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(billsSpreadSetting);
+
+    billsSpreadSetting.headColWidth = [50];
+    billsSpreadSetting.rowHeader = [
+        {
+            rowHeaderType: 'tag',
+            setting: {
+                indent: 14,
+                tagSize: 0.8,
+                tagFont: '8px 微软雅黑',
+                getColor: function (index, data) {
+                    if (!data) return;
+                    return billsTag.getBillsTagsColor(data.id);
+                },
+                getTagHtml: function (index, data) {
+                    if (!data) return;
+                    const getHtml = function (list) {
+                        if (!list || list.length === 0) return '';
+                        const html = [];
+                        for (const l of list) {
+                            html.push('<div class="row mr-1">');
+                            html.push(`<div class="col-auto pr-1 ${l.tagClass}">`, '<i class="fa fa-tag"></i>', '</div>');
+                            html.push('<div class="col p-0">', '<p>', l.comment, '</p>', '</div>');
+                            html.push('</div>');
+                        }
+                        return html.join('');
+                    };
+                    return getHtml(billsTag.getBillsTagsInfo(data.id));
+                }
+            },
+        },
+    ];
     SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
     SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
     const posSheet = posSpread.getActiveSheet();
     const posSheet = posSpread.getActiveSheet();
@@ -66,6 +97,21 @@ $(document).ready(() => {
 
 
     const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
     const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
 
 
+    const billsTag = $.billsTag({
+        selector: '#bills-tag',
+        relaSpread: billsSpread,
+        updateUrl: window.location.pathname + '/tag',
+        afterModify: function (nodes) {
+            SpreadJsObj.repaintNodesRowHeader(billsSpread.getActiveSheet(), nodes);
+        },
+        afterLocated:  function () {
+            posSpreadObj.loadCurPosData();
+        },
+        afterShow: function () {
+            billsSpread.refresh();
+            if (posSpread) posSpread.refresh();
+        },
+    });
     const errorList = $.cs_errorList({
     const errorList = $.cs_errorList({
         tabSelector: '#error-list-tab',
         tabSelector: '#error-list-tab',
         selector: '#error-list',
         selector: '#error-list',
@@ -293,6 +339,7 @@ $(document).ready(() => {
                     const rows = [];
                     const rows = [];
                     for (const u of data.update) {
                     for (const u of data.update) {
                         rows.push(tree.nodes.indexOf(u));
                         rows.push(tree.nodes.indexOf(u));
+                        billsTag.refreshBillsTagView(u);
                     }
                     }
                     SpreadJsObj.reLoadRowsData(sheet, rows);
                     SpreadJsObj.reLoadRowsData(sheet, rows);
                 }
                 }
@@ -311,14 +358,17 @@ $(document).ready(() => {
                 }
                 }
             });
             });
         },
         },
+        loadRelaData: function() {
+            billsTreeSpreadObj.refreshOperationValid(billsSheet);
+            SpreadJsObj.resetTopAndSelect(posSheet);
+            posSpreadObj.loadCurPosData();
+            SpreadJsObj.saveTopAndSelect(billsSheet, ckBillsSpread);
+            posSearch.search($('#pos-keyword').val());
+        },
         selectionChanged: function (e, info) {
         selectionChanged: function (e, info) {
             if (info.newSelections) {
             if (info.newSelections) {
                 if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
                 if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
-                    billsTreeSpreadObj.refreshOperationValid(info.sheet);
-                    SpreadJsObj.resetTopAndSelect(posSheet);
-                    posSpreadObj.loadCurPosData();
-                    SpreadJsObj.saveTopAndSelect(billsSheet, ckBillsSpread);
-                    posSearch.search($('#pos-keyword').val());
+                    billsTreeSpreadObj.loadRelaData();
                 }
                 }
             }
             }
             billsTreeSpreadObj.loadExprToInput(info.sheet);
             billsTreeSpreadObj.loadExprToInput(info.sheet);
@@ -391,6 +441,7 @@ $(document).ready(() => {
                             sheet.setSelection(sel.row, sel.col, 1, sel.colCount);
                             sheet.setSelection(sel.row, sel.col, 1, sel.colCount);
                         }
                         }
                         self.refreshOperationValid(sheet);
                         self.refreshOperationValid(sheet);
+                        billsTag.afterDeleteBills(refreshData.delete);
                     });
                     });
                 });
                 });
             } else {
             } else {
@@ -1009,10 +1060,12 @@ $(document).ready(() => {
             .keyup((e) => {if (e.keyCode === 13) item.batchInsert($input[0], root);})
             .keyup((e) => {if (e.keyCode === 13) item.batchInsert($input[0], root);})
             .on('input', function () {this.value = this.value.replace(/[^\d]/g, '');});
             .on('input', function () {this.value = this.value.replace(/[^\d]/g, '');});
     };
     };
+    const addTag = newTag({ledgerSheet: billsSpread.getActiveSheet(), billsTag});
     const billsContextMenuOptions = {
     const billsContextMenuOptions = {
         selector: '#bills-spread',
         selector: '#bills-spread',
         build: function ($trigger, e) {
         build: function ($trigger, e) {
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, billsSpread);
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, billsSpread);
+            billsTreeSpreadObj.loadRelaData();
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         },
         items: {}
         items: {}
@@ -1304,7 +1357,19 @@ $(document).ready(() => {
                 tenderSelect.showSelect(SpreadJsObj.getSelectObject(billsSheet));
                 tenderSelect.showSelect(SpreadJsObj.getSelectObject(billsSheet));
             }
             }
         };
         };
+        billsContextMenuOptions.items.sprImport = '----';
     }
     }
+    billsContextMenuOptions.items.tag = {
+        name: '书签',
+        callback: function (key, opt, menu, e) {
+            const node = SpreadJsObj.getSelectObject(billsSpread.getActiveSheet());
+            addTag.do(node);
+        },
+        disabled: function (key, opt) {
+            const node = SpreadJsObj.getSelectObject(billsSpread.getActiveSheet());
+            return !node;
+        }
+    };
     billsContextMenuOptions.items.sprTag = '----';
     billsContextMenuOptions.items.sprTag = '----';
     billsContextMenuOptions.items.showLast = {
     billsContextMenuOptions.items.showLast = {
         name: '显示至最底层',
         name: '显示至最底层',
@@ -1865,6 +1930,10 @@ $(document).ready(() => {
     postData(window.location.pathname + '/load', {}, function (result) {
     postData(window.location.pathname + '/load', {}, function (result) {
         billsTree.loadDatas(result.bills);
         billsTree.loadDatas(result.bills);
         treeCalc.calculateAll(billsTree);
         treeCalc.calculateAll(billsTree);
+        for (const t of result.tags) {
+            t.node = billsTree.datas.find(x => {return x.id === t.lid});
+        }
+        billsTag.loadDatas(result.tags);
         SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree);
         SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree);
         SpreadJsObj.loadTopAndSelect(billsSheet, ckBillsSpread);
         SpreadJsObj.loadTopAndSelect(billsSheet, ckBillsSpread);
 
 
@@ -2107,30 +2176,38 @@ $(document).ready(() => {
                 qdSheet.setSelection(sel.row + 1, sel.col, 1, 1);
                 qdSheet.setSelection(sel.row + 1, sel.col, 1, 1);
                 qdSheet.getParent().focus();
                 qdSheet.getParent().focus();
             });
             });
-            this.qdSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
-                const billsCount = info.sheet.getRowCount(), posSheet = self.posSpread.getActiveSheet();
-                const count = posSheet.getColumnCount() - 2;
-                if (billsCount > count) {
-                    posSheet.setColumnCount(billsCount + 2);
-                    for (let i = count + 1; i <= billsCount; i++) {
-                        info.sheet.getCell(i - 1, 0, spreadNS.SheetArea.rowHeader).text('清单' + i);
+            this.qdSpread.bind(spreadNS.Events.ClipboardPasting, function (e, info) {
+                info.cancel = true;
+                const transpose = $('[name=batch-transpose]')[0].checked;
+                const pasteData = SpreadJsObj.analysisPasteText(info.pasteData.text, transpose);
+
+                const billsSheet = info.sheet, posSheet = self.posSpread.getActiveSheet();
+                const billsCount = info.sheet.getRowCount(), finalCount = info.cellRange.row + pasteData.length + 1;
+                SpreadJsObj.beginMassOperation(billsSheet);
+                if (finalCount > billsCount) {
+                    billsSheet.setRowCount(finalCount);
+                    posSheet.setColumnCount(finalCount + 2);
+                    for (let i = billsCount - 1; i <= finalCount; i++) {
+                        billsSheet.getCell(i - 1, 0, spreadNS.SheetArea.rowHeader).text('清单' + i);
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                     }
                     }
                 }
                 }
-                if (info.cellRange.col === 0 && info.cellRange.colCount === 1) {
-                    const dealBills = self.dealSpread.getActiveSheet().zh_data;
-                    if (dealBills && dealBills.length > 0) {
-                        for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
-                            const curRow = iRow + info.cellRange.row;
-                            const bills = _.find(dealBills, {code: info.sheet.getText(curRow, 0)});
-                            if (bills) {
-                                info.sheet.getCell(curRow, 1).value(bills.name);
-                                info.sheet.getCell(curRow, 2).value(bills.unit);
-                                info.sheet.getCell(curRow, 3).value(bills.unit_price);
-                            }
+                for (let iRow = 0; iRow < pasteData.length; iRow++) {
+                    const curRow = iRow + info.cellRange.row;
+                    pasteData[iRow].forEach((value, iCol) => {
+                        billsSheet.getCell(curRow, iCol + info.cellRange.col).value(value);
+                    });
+                    if ([0, 1].indexOf(info.cellRange.col) >= 0) {
+                        const dealBills = self.dealSpread.getActiveSheet().zh_data;
+                        const bills = _.find(dealBills, {code: billsSheet.getText(curRow, 0)});
+                        if (bills) {
+                            billsSheet.getCell(curRow, 1).value(bills.name);
+                            billsSheet.getCell(curRow, 2).value(bills.unit);
+                            billsSheet.getCell(curRow, 3).value(bills.unit_price);
                         }
                         }
                     }
                     }
                 }
                 }
+                SpreadJsObj.endMassOperation(billsSheet);
             });
             });
             this.posSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
             this.posSpread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
                 const billsCount = info.sheet.getColumnCount() - 2, qdSheet = self.qdSpread.getActiveSheet();
                 const billsCount = info.sheet.getColumnCount() - 2, qdSheet = self.qdSpread.getActiveSheet();
@@ -2432,6 +2509,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
     const stdXmjSetting = {
         selector: '#std-xmj',
         selector: '#std-xmj',
         stdType: 'xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
         treeSetting: {
             id: 'chapter_id',
             id: 'chapter_id',
             pid: 'pid',
             pid: 'pid',
@@ -2463,6 +2541,7 @@ $(document).ready(() => {
     const stdGclSetting = {
     const stdGclSetting = {
         selector: '#std-gcl',
         selector: '#std-gcl',
         stdType: 'gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
         treeSetting: {
             id: 'bill_id',
             id: 'bill_id',
             pid: 'pid',
             pid: 'pid',
@@ -2505,12 +2584,12 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 }
                 stdXmj.spread.refresh();
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 }
                 stdGcl.spread.refresh();
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {
             } else if (tab.attr('content') === '#deal-bills') {

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

@@ -300,7 +300,7 @@ $(document).ready(() => {
     })('a[name=showLevel]', billsSheet);
     })('a[name=showLevel]', billsSheet);
 
 
     $('#reviseHistory').change(function () {
     $('#reviseHistory').change(function () {
-        postData(window.location.pathname + '/info', { rid: this.value }, function (result) {
+        postData('info', { rid: this.value }, function (result) {
             $('#user-name').val(result.user_name);
             $('#user-name').val(result.user_name);
             $('#content')[0].textContent = result.content;
             $('#content')[0].textContent = result.content;
             $('#end-time').val(result.end_time_str);
             $('#end-time').val(result.end_time_str);

+ 53 - 0
app/public/js/revise_price.js

@@ -0,0 +1,53 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+$(document).ready(() => {
+    autoFlashHeight();
+
+    const priceSpread = SpreadJsObj.createNewSpread($('#price-spread')[0]);
+    const priceSheet = priceSpread.getActiveSheet();
+
+    const priceSpreadSetting = {
+        cols: [
+            { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@', readOnly: true },
+            { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 210, formatter: '@', readOnly: true },
+            { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true },
+            { title: '当前单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number', readOnly: true },
+            { title: '变更后单价', colSpan: '1', rowSpan: '2', field: 'new_price', hAlign: 2, width: 80, type: 'Number' },
+            { title: '备注', colSpan: '1', rowSpan: '2', field: 'new_price', hAlign: 2, width: 150, formatter: '@' },
+        ],
+        emptyRows: 0,
+        headRows: 1,
+        headRowHeight: [32],
+        headColWidth: [30],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+    };
+    SpreadJsObj.initSheet(priceSheet, priceSpreadSetting);
+
+    $.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');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            priceSpread.refresh();
+        }
+    });
+});

+ 199 - 0
app/public/js/setting_datacollect_tender.js

@@ -0,0 +1,199 @@
+'use strict';
+
+/**
+ *
+ * @author LanJianRong
+ * @date 2020/11/13
+ * @version
+ */
+const tenderTree = [];
+let parentId = 0;
+// 查询方法
+function findNode (key, value, arr) {
+    for (const a of arr) {
+        if (a[key] && a[key] === value) {
+            return a;
+        }
+    }
+}
+// 分类数据排序
+function sortCategory() {
+    category.sort(function (a, b) {
+        return a.level ? (b.level ? a.level - b.level : -1) : a.id - b.id;
+    });
+}
+// 初始化TenderTree数据
+function initTenderTree () {
+    const levelCategory = category.filter(function (c) {
+        return c.level && c.level > 0;
+    });
+    function findCategoryNode(cid, value, array) {
+        for (const a of array) {
+            if (a.cid === cid && a.vid === value) {
+                return a;
+            }
+        }
+    }
+    function getCategoryNode(category, value, parent, i = null) {
+        const array = parent ?  parent.children : tenderTree;
+        let cate = findCategoryNode(category.id, value, array);
+        if (!cate) {
+            const cateValue = findNode('id', value, category.value);
+            if (!cateValue) return null;
+            cate = {
+                cid: category.id,
+                vid: value,
+                name: cateValue.value,
+                children: [],
+                level: i ? i : category.level,
+                sort_id: ++parentId,
+                sort: cateValue.sort,
+            };
+            array.push(cate);
+        }
+        return cate;
+    }
+    function loadTenderCategory (tender) {
+        let tenderCategory = null;
+        for (const [index,lc] of levelCategory.entries()) {
+            const tenderCate = findNode('cid', lc.id, tender.category);
+            if (tenderCate) {
+                tenderCategory = getCategoryNode(lc, tenderCate.value, tenderCategory);
+            } else {
+                if (index === 0 && tender.category) {
+                    for (const [i,c] of tender.category.entries()) {
+                        const cate = findNode('id', c.cid, category);
+                        tenderCategory = getCategoryNode(cate, c.value, tenderCategory, i+1);
+                    }
+                }
+                return tenderCategory;
+            }
+        }
+        return tenderCategory;
+    }
+    tenderTree.splice(0, tenderTree.length);
+    for (const t of tenders) {
+        t.valid = true;
+        delete t.level;
+        if (t.category && levelCategory.length > 0) {
+            const parent = loadTenderCategory(t);
+            if (parent) {
+                t.level = parent.level + 1;
+                parent.children.push(t);
+            } else {
+                tenderTree.push(t);
+            }
+        } else {
+            tenderTree.push(t);
+        }
+    }
+    sortTenderTree();
+}
+function recursiveGetTenderNodeHtml (node, arr, pid) {
+    // console.log(node, tender)
+    const html = [];
+    html.push('<tr pid="' + pid + '">');
+    // 名称
+    html.push('<td class="in-' + node.level + '">');
+    if (node.cid) {
+        html.push('<i class="fa fa-folder-o"></i> ', node.name);
+    } else {
+        html.push('<span class="text-muted mr-2">');
+        html.push(arr.indexOf(node) === arr.length - 1 ? '└' : '├');
+        html.push('</span>');
+        //html.push('<a href="/tender/' + node.id + '">', node[c.field], '</a>');
+        html.push('<a href="javascript: void(0)" id="' + node.id + '">', node.name, '</a>');
+    }
+    html.push('</td>');
+    // 创建人
+    html.push('<td>');
+    if (!node.cid) {
+        // html.push('<input data-tid="'+ node.id +'" type="radio"> '+ (node.copy_id === tender.copy_id ? 'checked' : '') + '/>');
+        html.push(`<input data-tid=${node.id} type="checkbox" ${_.findIndex(dcTenders, { tid: node.id }) === -1 ? 'checked' : ''}>`);
+    }
+    html.push('</td>');
+    html.push('</tr>');
+    if (node.children) {
+        for (const c of node.children) {
+            html.push(recursiveGetTenderNodeHtml(c, node.children, node.sort_id));
+        }
+    }
+    return html.join('');
+}
+// 根据TenderTree数据获取Html代码
+function getTenderTreeHtml () {
+    if (tenderTree.length > 0) {
+        const html = [];
+        // html.push('<table class="table table-hover table-bordered">');
+        // html.push('<thead>', '<tr>');
+        // html.push('<th>名称</th>');
+        // html.push('<th width="60">选择 <input type="checkbox" id="select-tender-all"></th>');
+        // html.push('</tr>', '</thead>');
+        parentId = 0;
+        for (const t of tenderTree) {
+            html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
+        }
+        // html.push('</table>');
+        return html.join('');
+    } else {
+        return EmptyTenderHtml.join('');
+    }
+}
+$(document).ready(function () {
+    sortCategory();
+    initTenderTree();
+    $('#tenderBtn').click(() => {
+        tenderListOrder.reOrderTenders('', '#copyModalContent', false);
+        // const html = getTenderTreeHtml();
+        // $('#copyModalContent').html(html);
+        $('#sort input[value="'+ addDataCollect +'"]').prop('checked', true);
+        if($('#copyModalContent input[type="checkbox"]:not(:checked)').length === 0) {
+            $('#select-tender-all').prop('checked', true);
+        } else {
+            $('#select-tender-all').prop('checked', false);
+        }
+        $('#sort').modal('show');
+    });
+
+    $('#tender_dataCollect_btn').click(function () {
+        // 获取是否新增展示到决策大屏
+        const add_datacollect = $('input[name="add_datacollect"]:checked').val();
+        const noTidList = [];
+        $("#copyModalContent input[type='checkbox']:not(:checked)").each(function () {
+           noTidList.push($(this).data('tid'));
+        });
+        const dcTidList = _.map(dcTenders, 'tid');
+        let is_list_update = true;
+        let is_collect_update = true;
+        if (_.isEqual(_.sortBy(dcTidList), _.sortBy(noTidList))) {
+            is_list_update = false;
+        }
+        if (parseInt(add_datacollect) === addDataCollect) {
+            is_collect_update = false;
+        }
+        if (is_list_update || is_collect_update) {
+            postData('/setting/datacollect/save', { type: 'tender', add_datacollect: parseInt(add_datacollect), tids: noTidList }, function (result) {
+                addDataCollect = result.addDataCollect;
+                dcTenders = result.dcTenders;
+                toastr.success('修改成功');
+            })
+        }
+        $('#sort').modal('hide');
+    });
+
+    $('#select-tender-all').click(function () {
+        const is_checked = $(this).is(':checked');
+        if(is_checked) {
+            $("#copyModalContent input[type='checkbox']").prop('checked', true);
+        } else {
+            $("#copyModalContent input[type='checkbox']").prop('checked', false);
+        }
+    });
+    $('body').on('click', "#copyModalContent input[type='checkbox']", function () {
+        if($('#copyModalContent input[type="checkbox"]:not(:checked)').length === 0) {
+            $('#select-tender-all').prop('checked', true);
+        } else {
+            $('#select-tender-all').prop('checked', false);
+        }
+    })
+});

+ 234 - 1
app/public/js/shares/cs_tools.js

@@ -783,6 +783,7 @@ const showSelectTab = function(select, spread, afterShow) {
             billsTags = [];
             billsTags = [];
             billsIndexes = {};
             billsIndexes = {};
             for (const d of datas) {
             for (const d of datas) {
+                if (!d.node) continue;
                 billsTags.push(d);
                 billsTags.push(d);
                 _addToBillsIndex(d);
                 _addToBillsIndex(d);
             }
             }
@@ -851,6 +852,19 @@ const showSelectTab = function(select, spread, afterShow) {
             }) : undefined;
             }) : undefined;
         };
         };
 
 
+        const afterDeleteBills = function (nodes) {
+            for (const node of nodes) {
+                const bi = billsIndexes[node.id];
+                if (!bi) continue;
+                delete billsIndexes[node.id];
+                for (const biTag of bi) {
+                    const delTag = billsTags.find(x => {return x.id === biTag.id});
+                    billsTags.splice(billsTags.indexOf(delTag), 1);
+                    $('#bills-tag-' + delTag.id).remove();
+                }
+            }
+        };
+
         $('body').on('click', '[name=bills-tag-locate]', function () {
         $('body').on('click', '[name=bills-tag-locate]', function () {
             const lid = parseInt(this.getAttribute('lid'));
             const lid = parseInt(this.getAttribute('lid'));
             SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), lid);
             SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), lid);
@@ -935,7 +949,7 @@ const showSelectTab = function(select, spread, afterShow) {
         $('#bills-tag-search').bind('click', () => {searchTagsAndShow();});
         $('#bills-tag-search').bind('click', () => {searchTagsAndShow();});
         $('#bills-tag-keyword').bind('keydown', e => {if (e.keyCode === 13) searchTagsAndShow();});
         $('#bills-tag-keyword').bind('keydown', e => {if (e.keyCode === 13) searchTagsAndShow();});
 
 
-        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo, refreshBillsTagView, }
+        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo, refreshBillsTagView, afterDeleteBills }
     };
     };
 
 
     $.sumLoadMiss = function (setting) {
     $.sumLoadMiss = function (setting) {
@@ -1074,4 +1088,223 @@ const showSelectTab = function(select, spread, afterShow) {
             };
             };
         }
         }
     };
     };
+
+    $.stdLib = function (setting) {
+        if (!setting.selector) return;
+        const obj = $(setting.selector);
+        const stdLibHtml = setting.libs.map(l => {
+            return `<option value="${l.id}" >${l.name}</option>`;
+        });
+        const relaSelect = {
+            showLevel: `std-${setting.stdType}-sl`,
+            searchText: `std-${setting.stdType}-st`,
+            searchResult: `std-${setting.stdType}-sr`,
+            searchPre: `std-${setting.stdType}-sp`,
+            searchNext: `std-${setting.stdType}-sn`,
+            searchClose: `std-${setting.stdType}-sc`,
+        };
+        obj.html(
+            '<div class="sjs-bar d-flex">\n' +
+            '    <div class="dropdown mr-1">\n' +
+            '        <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+            '             <i class="fa fa-list-ol"></i> 显示层级\n' +
+            '        </button>\n' +
+            '        <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">\n' +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="1" name="${relaSelect.showLevel}">第一层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="2" name="${relaSelect.showLevel}">第二层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="3" name="${relaSelect.showLevel}">第三层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="4" name="${relaSelect.showLevel}">第四层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="5" name="${relaSelect.showLevel}">第五层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="last" name="${relaSelect.showLevel}">最底层</a>\n` +
+            '        </div>\n' +
+            '    </div>' +
+            `    <div class=input-group input-group-sm pr-1"><select class="form-control form-control-sm">${stdLibHtml.join('')}</select></div>\n` +
+            '    <div class="ml-1">\n' +
+            '        <div class="dropdown">\n' +
+            '            <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+            '                <i class="fa fa-search"></i>\n' +
+            '            </button>\n' +
+            '            <div class="dropdown-menu dropdown-menu-right">\n' +
+            '                <div class="px-2 border-primary border-1 d-flex" style="width: 300px">\n' +
+            '                    <div class="d-inline-block">\n' +
+            '                        <div class="input-group input-group-sm mr-1">' +
+            `                            <input type="text" class="form-control" placeholder="输入编号/名称查找" id="${relaSelect.searchText}">\n` +
+            `                            <div class="input-group-append" ><span class="input-group-text" id="${relaSelect.searchResult}">结果:0</span></div>\n` +
+            '                            <div class="input-group-append" >\n' +
+            `                                <button class="btn btn-outline-secondary" type="button" title="上一个" id="${relaSelect.searchPre}"><i class="fa fa-angle-double-left"></i></button>\n` +
+            `                                <button class="btn btn-outline-secondary" type="button" title="下一个" id="${relaSelect.searchNext}"><i class="fa fa-angle-double-right"></i></button>\n` +
+            '                            </div>\n' +
+            '                        </div>\n' +
+            '                    </div>\n' +
+            `                    <div class="d-inline-block"><button class="btn btn-light text-danger btn-sm ml-1" type="button" id="${relaSelect.searchClose}"><i class="fa fa-remove"></i></button></div>\n` +
+            '                </div>\n' +
+            '            </div>\n' +
+            '        </div>\n' +
+            '    </div>' +
+            '</div>\n' +
+            `<div id="std-${setting.stdType}-spread" class="sjs-sh"></div>\n`
+        );
+        autoFlashHeight();
+        const pathTree = createNewPathTree('base', setting.treeSetting);
+
+        const spreadSetting = {
+            cols: [
+                {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@'},
+                {title: '单位', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+            ],
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            headColWidth: [30],
+            selectedBackColor: '#fffacd',
+            readOnly: true,
+            stdType: setting.stdType,
+        };
+        spreadSetting.cols.unshift(setting.stdType === 'xmj'
+            ? {title: '项目节编号', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'}
+            : {title: '清单编号', field: 'b_code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'});
+
+        const spread = SpreadJsObj.createNewSpread($(`#std-${setting.stdType}-spread`)[0]);
+        const sheet = spread.getActiveSheet();
+        SpreadJsObj.initSheet(sheet, spreadSetting);
+
+
+        if (setting.cellDoubleClick) sheet.bind(spreadNS.Events.CellDoubleClick, setting.cellDoubleClick);
+        sheet.bind(spreadNS.Events.SelectionChanged, function (e, info) {
+            if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
+                SpreadJsObj.saveTopAndSelect(info.sheet, cacheKey.node);
+            }
+        });
+        sheet.bind(spreadNS.Events.TopRowChanged, function (e, info) {
+            SpreadJsObj.saveTopAndSelect(info.sheet, cacheKey.node);
+        });
+
+        const cacheLib = [];
+        const cacheKey = {
+            lib: setting.page + '-' + setting.tid + '-' + setting.stdType,
+        };
+
+        $('select', setting.selector).change(function () {
+            loadLib(parseInt(this.value), true);
+        });
+        (function (select, sheet) {
+            $(select).click(function () {
+                if (!sheet.zh_tree) return;
+                const tag = $(this).attr('tag');
+                const tree = sheet.zh_tree;
+                setTimeout(() => {
+                    switch (tag) {
+                        case "1":
+                        case "2":
+                        case "3":
+                        case "4":
+                        case "5":
+                            tree.expandByLevel(parseInt(tag));
+                            SpreadJsObj.refreshTreeRowVisible(sheet);
+                            break;
+                        case "last":
+                            tree.expandByCustom(() => { return true; });
+                            SpreadJsObj.refreshTreeRowVisible(sheet);
+                            break;
+                    }
+                }, 100);
+            });
+        })(`a[name=${relaSelect.showLevel}]`, sheet);
+
+        const loadLib = function(listId, reload = false) {
+            cacheKey.node = cacheLib.lib + '-' + listId;
+            const locateMemory = function () {
+                if (!reload) {
+                    SpreadJsObj.loadTopAndSelect(sheet, cacheKey.node);
+                } else {
+                    removeLocalCache(cacheKey.node);
+                }
+            };
+            const cacheData = cacheLib.find(function (lib) {
+                return lib.id === listId;
+            });
+            if (cacheData) {
+                pathTree.loadDatas(cacheData.data);
+                SpreadJsObj.loadSheetData(sheet, 'tree', pathTree);
+                locateMemory();
+                setLocalCache(cacheKey.lib, listId);
+            } else {
+                postData(`/std-lib/get-data`, {stdType: setting.stdType, list_id: listId}, function (data) {
+                    cacheLib.push({id: listId, data: data});
+                    pathTree.loadDatas(data);
+                    SpreadJsObj.loadSheetData(sheet, 'tree', pathTree);
+                    locateMemory();
+                    setLocalCache(cacheKey.lib, listId);
+                });
+            }
+        };
+
+        const _loadCacheLib = function() {
+            let libId = getLocalCache(cacheKey.lib);
+            if (libId) {
+                $('select', setting.selector).val(libId);
+                loadLib(parseInt(libId));
+            } else {
+                loadLib(parseInt($('select', setting.selector).val()));
+            }
+        };
+        _loadCacheLib();
+
+        const searchObj = {
+            result: [],
+            cur: 0,
+            searchStdNode: function() {
+                const keyword = $(`#${relaSelect.searchText}`).val();
+                searchObj.result = keyword ? pathTree.nodes.filter(x => {
+                    return x.code.indexOf(keyword) >= 0 || x.b_code.indexOf(keyword) >= 0 || x.name.indexOf(keyword) >= 0;
+                }) : [];
+                // searchObj.result = [];
+                // for (const x of pathTree.nodes) {
+                //     if (x.code.indexOf(keyword) >= 0 || x.b_code.indexOf(keyword) >= 0 || x.name.indexOf(keyword) >= 0) {
+                //         searchObj.result.push(x);
+                //     }
+                // }
+                $(`#${relaSelect.searchResult}`)[0].innerText = `结果:${searchObj.result.length}`;
+                searchObj.cur = 0;
+                if (searchObj.result.length > 0) {
+                    SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]));
+                }
+            },
+            searchPre: function () {
+                if (searchObj.result.length === 0) return;
+                searchObj.cur = searchObj.cur === 0 ? searchObj.result.length - 1 : this.cur - 1;
+                SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]), true);
+            },
+            searchNext: function () {
+                if (searchObj.result.length === 0) return;
+                searchObj.cur = searchObj.cur === searchObj.result.length - 1 ? 0 : searchObj.cur + 1;
+                SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]), true);
+            },
+            clear: function () {
+                $(`#${relaSelect.searchText}`).val('');
+                $(`#${relaSelect.searchResult}`)[0].innerText = `结果:${0}`;
+                searchObj.result = [];
+                searchObj.cur = 0;
+            }
+        };
+        $(`#${relaSelect.searchText}`).change(searchObj.searchStdNode);
+        $(`#${relaSelect.searchPre}`).click(function (e) {
+            searchObj.searchPre();
+            e.stopPropagation();
+        });
+        $(`#${relaSelect.searchNext}`).click(function (e) {
+            searchObj.searchNext();
+            e.stopPropagation();
+        });
+        $(`#${relaSelect.searchClose}`).click(function (e) {
+            searchObj.clear();
+            e.stopPropagation();
+        });
+
+        return { spread }
+    };
 })(jQuery);
 })(jQuery);

+ 3 - 3
app/public/js/shares/tender_list_order.js

@@ -28,7 +28,7 @@ const tenderListOrder = (function () {
         // }
         // }
         return pinyin.compareWord(x, y);
         return pinyin.compareWord(x, y);
     }
     }
-    function reOrderTenders (orderStr) {
+    function reOrderTenders (orderStr, htmlClass = '.c-body', loadHide = true) {
         if (orderStr) {
         if (orderStr) {
             orderSetting = orderStr;
             orderSetting = orderStr;
             setLocalCache('zh-calc-tender-list-order', orderStr);
             setLocalCache('zh-calc-tender-list-order', orderStr);
@@ -51,8 +51,8 @@ const tenderListOrder = (function () {
             })
             })
         }
         }
         initTenderTree();
         initTenderTree();
-        $('.c-body').html(getTenderTreeHtml());
-        localHideList();
+        $(htmlClass).html(getTenderTreeHtml());
+        if (loadHide) localHideList();
     }
     }
     function getOrderButton(field) {
     function getOrderButton(field) {
         const orders = orderSetting.split('|');
         const orders = orderSetting.split('|');

+ 18 - 4
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -952,23 +952,37 @@ const SpreadJsObj = {
             }
             }
             copyData.push(rowText.join('\t'));
             copyData.push(rowText.join('\t'));
         }
         }
-        return copyData.join('\n');
+        return copyData.join('\r\n');
     },
     },
-    analysisPasteText: function (text) {
+    analysisPasteText: function (text, transpose = false) {
+        console.log(text);
         const result = [];
         const result = [];
         if (text === '') return result;
         if (text === '') return result;
 
 
-        const rows = text.split('\n');
+        const rows = text.split('\r\n');
+        if (rows[rows.length - 1] === '') rows.splice(rows.length - 1, 1);
         for (const r of rows) {
         for (const r of rows) {
             const cols = r.split('\t');
             const cols = r.split('\t');
             result.push(cols);
             result.push(cols);
         }
         }
-        return result;
+        return transpose ? SpreadJsObj.transposePasteData(result) : result;
     },
     },
     analysisPasteHtml: function (html) {
     analysisPasteHtml: function (html) {
         const result = [];
         const result = [];
         if (!html || html === '') return result;
         if (!html || html === '') return result;
     },
     },
+    transposePasteData: function (data) {
+        const result = [];
+        const rowCount = data.length, colCount = data.reduce((r, x) => { return r ? Math.max(r, x.length) : x.length; });
+        for (let c = 0; c < colCount; c++) {
+            const newRow = [];
+            for (let r = 0; r < rowCount; r++) {
+                newRow.push(data[r][c]);
+            }
+            result.push(newRow)
+        }
+        return result;
+    },
     /**
     /**
      * 树表结构,定位至指定的节点
      * 树表结构,定位至指定的节点
      * @param {GC.Spread.Sheets.Worksheet} sheet - 需要定位的sheet
      * @param {GC.Spread.Sheets.Worksheet} sheet - 需要定位的sheet

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

@@ -74,7 +74,7 @@ function customizeStageTreeSetting(setting, customDisplay) {
 // 生成所有附件列表
 // 生成所有附件列表
 function getAllList(currPageNum = 1) {
 function getAllList(currPageNum = 1) {
     // 每页最多几个附件
     // 每页最多几个附件
-    const pageCount = 15;
+    const pageCount = 20;
     // 附件总数
     // 附件总数
     const total = attData.length;
     const total = attData.length;
     // 总页数
     // 总页数
@@ -1217,8 +1217,8 @@ $(document).ready(() => {
         });
         });
 
 
         if (fileIds.length) {
         if (fileIds.length) {
-            if (fileIds.length > 10) {
-              return toastr.warning(`最大允许10个文件(当前${fileIds.length}个)`)
+            if (fileIds.length > 20) {
+              return toastr.warning(`最大允许20个文件(当前${fileIds.length}个)`)
             }
             }
             toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             $(this).attr('disabled', "true")
             $(this).attr('disabled', "true")

+ 18 - 36
app/public/js/stage.js

@@ -109,7 +109,7 @@ function initTreeColSettingEvents(setting) {
 // 生成所有附件列表
 // 生成所有附件列表
 function getAllList(currPageNum = 1) {
 function getAllList(currPageNum = 1) {
     // 每页最多几个附件
     // 每页最多几个附件
-    const pageCount = 15;
+    const pageCount = 20;
     // 附件总数
     // 附件总数
     const total = attData.length;
     const total = attData.length;
     // 总页数
     // 总页数
@@ -603,7 +603,9 @@ $(document).ready(() => {
             this.displayChanges = [];
             this.displayChanges = [];
             for (const c of this.changes) {
             for (const c of this.changes) {
                 const filterVisible = filterEmpty ? (c.vamount ? !checkZero(c.vamount) : false) : true;
                 const filterVisible = filterEmpty ? (c.vamount ? !checkZero(c.vamount) : false) : true;
-                const matchVisible = matchPosName && this.callData.pos ? c.b_bwmx === this.callData.pos.name : true;
+                const matchVisible = matchPosName && this.callData.pos
+                    ? (c.gcl_id === this.callData.bills.id && c.b_bwmx === this.callData.pos.name)
+                    : true;
                 if ((filterVisible && matchVisible) || (c.org_uamount)) {
                 if ((filterVisible && matchVisible) || (c.org_uamount)) {
                     this.displayChanges.push(c);
                     this.displayChanges.push(c);
                 }
                 }
@@ -961,17 +963,19 @@ $(document).ready(() => {
                 });
                 });
             }
             }
         },
         },
+        loadRelaData: function () {
+            const billsSheet = spSpread.getActiveSheet();
+            SpreadJsObj.resetTopAndSelect(billsSheet);
+            stagePosSpreadObj.loadCurPosData();
+            if (posSearch) posSearch.search();
+            SpreadJsObj.saveTopAndSelect(billsSheet, ckBillsSpread);
+        },
         selectionChanged: function (e, info) {
         selectionChanged: function (e, info) {
             if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
             if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
-                SpreadJsObj.resetTopAndSelect(spSpread.getActiveSheet());
-                stagePosSpreadObj.loadCurPosData();
-                if (posSearch) {
-                    posSearch.search();
-                }
+                stageTreeSpreadObj.loadRelaData();
                 // 全选去除
                 // 全选去除
                 $('#dqjiedian').find('.check-all-file').prop('checked', false);
                 $('#dqjiedian').find('.check-all-file').prop('checked', false);
             }
             }
-            SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
             stageTreeSpreadObj.loadExprToInput(info.sheet);
             stageTreeSpreadObj.loadExprToInput(info.sheet);
         },
         },
         deletePress(sheet) {
         deletePress(sheet) {
@@ -1471,6 +1475,7 @@ $(document).ready(() => {
         selector: '#stage-ledger',
         selector: '#stage-ledger',
         build: function ($trigger, e) {
         build: function ($trigger, e) {
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, slSpread);
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, slSpread);
+            stageTreeSpreadObj.loadRelaData();
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         },
         items: {
         items: {
@@ -1617,7 +1622,7 @@ $(document).ready(() => {
             const sheet = slSpread.getActiveSheet();
             const sheet = slSpread.getActiveSheet();
             const node = SpreadJsObj.getSelectObject(sheet);
             const node = SpreadJsObj.getSelectObject(sheet);
             if (node) {
             if (node) {
-                const posReadOnly = node.lock || (node.children && node.children.length > 0);
+                const posReadOnly = node.lock || (node.children && node.children.length > 0) || !node.b_code;
                 spSpread.getActiveSheet().zh_setting.readOnly = posReadOnly;
                 spSpread.getActiveSheet().zh_setting.readOnly = posReadOnly;
                 const posData = stagePos.ledgerPos[itemsPre + node.id] || [];
                 const posData = stagePos.ledgerPos[itemsPre + node.id] || [];
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', posData, posReadOnly);
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', posData, posReadOnly);
@@ -2021,23 +2026,11 @@ $(document).ready(() => {
 
 
     // 加载计量单元数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
     // 加载计量单元数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
     postData(window.location.pathname + '/load', { filter: 'ledger;pos;detail;change;tag;cooperation' }, function (result) {
     postData(window.location.pathname + '/load', { filter: 'ledger;pos;detail;change;tag;cooperation' }, function (result) {
-        result.ledgerData && console.log('ledger: ' + result.ledgerData.length);
-        result.posData && console.log('pos: ' + result.posData.length);
-        result.detailData && console.log('detail: ' + result.detailData.length);
-        result.detailAtt && console.log('detailAtt: ' + result.detailAtt.length);
-        result.changeData && console.log('change: ' + result.changeData.length);
-        result.tags && console.log('tag: ' + result.tags.length);
-        result.cooperation && console.log('cooperation: ' + result.cooperation.length);
         // 加载树结构
         // 加载树结构
-        console.time('loadLedger');
         stageTree.loadDatas(result.ledgerData);
         stageTree.loadDatas(result.ledgerData);
-        console.timeEnd('loadLedger');
         checkShowLast(result.ledgerData.length);
         checkShowLast(result.ledgerData.length);
-        console.time('calcLedger');
         treeCalc.calculateAll(stageTree);
         treeCalc.calculateAll(stageTree);
-        console.timeEnd('calcLedger');
         // 加载解锁相关
         // 加载解锁相关
-        console.time('loadCooperation');
         if (result.cooperation) {
         if (result.cooperation) {
             stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2], result.cooperationConfirm);
             stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2], result.cooperationConfirm);
             $('#cooperationCount').html(stageTree.pwd.length || '');
             $('#cooperationCount').html(stageTree.pwd.length || '');
@@ -2045,31 +2038,20 @@ $(document).ready(() => {
             setCooperationSelectHtml();
             setCooperationSelectHtml();
             reloadCooperationHtml();
             reloadCooperationHtml();
         }
         }
-        console.timeEnd('loadCooperation');
-        console.time('loadTag');
         for (const t of result.tags) {
         for (const t of result.tags) {
             t.node = stageTree.datas.find(x => {return x.id === t.lid});
             t.node = stageTree.datas.find(x => {return x.id === t.lid});
         }
         }
         billsTag.loadDatas(result.tags);
         billsTag.loadDatas(result.tags);
-        console.timeEnd('loadTag');
         // 加载部位明细
         // 加载部位明细
-        console.time('loadPos');
         stagePos.loadDatas(result.posData);
         stagePos.loadDatas(result.posData);
-        console.timeEnd('loadPos');
         stagePos.calculateAll();
         stagePos.calculateAll();
-        console.time('showLedger');
         SpreadJsObj.loadSheetData(slSpread.getActiveSheet(), 'tree', stageTree);
         SpreadJsObj.loadSheetData(slSpread.getActiveSheet(), 'tree', stageTree);
         SpreadJsObj.loadTopAndSelect(slSpread.getActiveSheet(), ckBillsSpread);
         SpreadJsObj.loadTopAndSelect(slSpread.getActiveSheet(), ckBillsSpread);
-        console.timeEnd('showLedger');
-        console.time('showPos');
         stagePosSpreadObj.loadCurPosData();
         stagePosSpreadObj.loadCurPosData();
         SpreadJsObj.resetTopAndSelect(spSpread.getActiveSheet());
         SpreadJsObj.resetTopAndSelect(spSpread.getActiveSheet());
-        console.timeEnd('showPos');
         // 加载中间计量
         // 加载中间计量
-        console.time('loadIm');
         stageIm.init(stage, imType, tenderInfo.decimal);
         stageIm.init(stage, imType, tenderInfo.decimal);
         stageIm.loadData(result.ledgerData, result.posData, result.detailData, result.changeData, result.detailAtt);
         stageIm.loadData(result.ledgerData, result.posData, result.detailData, result.changeData, result.detailAtt);
-        console.timeEnd('loadIm');
 
 
         errorList.loadHisErrorData();
         errorList.loadHisErrorData();
         checkList.loadHisCheckData();
         checkList.loadHisCheckData();
@@ -3757,7 +3739,7 @@ $(document).ready(() => {
                             const changeBills = SpreadJsObj.getSelectObject(self.changeBillsSheet);
                             const changeBills = SpreadJsObj.getSelectObject(self.changeBillsSheet);
                             if (changeBills.gcl_id) {
                             if (changeBills.gcl_id) {
                                 const node = stageTree.nodes.find(x => {return x.id === changeBills.gcl_id});
                                 const node = stageTree.nodes.find(x => {return x.id === changeBills.gcl_id});
-                                SpreadJsObj.locateTreeNode(slSpread.getActiveSheet(), node.ledger_id);
+                                SpreadJsObj.locateTreeNode(slSpread.getActiveSheet(), node.ledger_id, true);
                                 stagePosSpreadObj.loadCurPosData();
                                 stagePosSpreadObj.loadCurPosData();
                             } else {
                             } else {
                                 const cb = {
                                 const cb = {
@@ -4175,7 +4157,7 @@ $(document).ready(() => {
         const filename = name.substring(0, name.lastIndexOf("."));
         const filename = name.substring(0, name.lastIndexOf("."));
         const fileext = name.substr(name.indexOf("."));
         const fileext = name.substr(name.indexOf("."));
         const filesize = file.size;
         const filesize = file.size;
-        if (filesize > 10 * 1024 * 1024) {
+        if (filesize > 30 * 1024 * 1024) {
             toastr.error('文件大小过大!');
             toastr.error('文件大小过大!');
             $('#change-att-btn').val('');
             $('#change-att-btn').val('');
             return false;
             return false;
@@ -4221,8 +4203,8 @@ $(document).ready(() => {
         });
         });
 
 
         if (fileIds.length) {
         if (fileIds.length) {
-            if (fileIds.length > 10) {
-              return toastr.warning(`最大允许10个文件(当前${fileIds.length}个)`)
+            if (fileIds.length > 20) {
+              return toastr.warning(`最大允许20个文件(当前${fileIds.length}个)`)
             }
             }
             toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             toastr.success('正在进行压缩文件...', '', { timeOut: 0, extendedTimeOut: 0})
             $(this).attr('disabled', "true")
             $(this).attr('disabled', "true")

+ 4 - 1
app/public/js/stage_compare.js

@@ -150,6 +150,7 @@ $(document).ready(function () {
         selector: '#ledger-spread',
         selector: '#ledger-spread',
         build: function ($trigger, e) {
         build: function ($trigger, e) {
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
+            loadPosData();
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         },
         items: {
         items: {
@@ -194,7 +195,9 @@ $(document).ready(function () {
 
 
     // 获取部位明细数据
     // 获取部位明细数据
     function loadPosData(iRow) {
     function loadPosData(iRow) {
-        const node = ledgerSpread.getActiveSheet().zh_tree.nodes[iRow];
+        const node = iRow
+            ? (ledgerSpread.getActiveSheet().zh_tree ? ledgerSpread.getActiveSheet().zh_tree.nodes[iRow] : null)
+            : (SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet()));
         if (node) {
         if (node) {
             SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), SpreadJsObj.DataType.Data, scPos.getLedgerPos(node.id) || []);
             SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), SpreadJsObj.DataType.Data, scPos.getLedgerPos(node.id) || []);
         } else {
         } else {

+ 12 - 3
app/public/js/tender_copy_setting.js

@@ -16,6 +16,12 @@ function findNode (key, value, arr) {
         }
         }
     }
     }
 }
 }
+// 分类数据排序
+function sortCategory() {
+    category.sort(function (a, b) {
+        return a.level ? (b.level ? a.level - b.level : -1) : a.id - b.id;
+    });
+}
 // 初始化TenderTree数据
 // 初始化TenderTree数据
 function initTenderTree () {
 function initTenderTree () {
     const levelCategory = category.filter(function (c) {
     const levelCategory = category.filter(function (c) {
@@ -93,6 +99,7 @@ function initTenderTree () {
             tenderTree.push(t);
             tenderTree.push(t);
         }
         }
     }
     }
+    sortTenderTree();
 }
 }
 function recursiveGetTenderNodeHtml (node, arr, pid) {
 function recursiveGetTenderNodeHtml (node, arr, pid) {
     // console.log(node, tender)
     // console.log(node, tender)
@@ -147,10 +154,12 @@ function getTenderTreeHtml () {
     }
     }
 }
 }
 $(document).ready(function () {
 $(document).ready(function () {
-    initTenderTree()
+    sortCategory();
+    initTenderTree();
     $('#copyBtn').click(() => {
     $('#copyBtn').click(() => {
-        const html = getTenderTreeHtml();
-        $('#copyModalContent').html(html);
+        tenderListOrder.reOrderTenders('', '#copyModalContent', false);
+        // const html = getTenderTreeHtml();
+        // $('#copyModalContent').html(html);
         $('#bd-set-8').modal('show');
         $('#bd-set-8').modal('show');
     });
     });
 
 

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

@@ -299,9 +299,9 @@ function getProgressHtml(total, pre, cur) {
         let other = Math.max(ZhCalc.sub(ZhCalc.sub(total, pre), cur), 0);
         let other = Math.max(ZhCalc.sub(ZhCalc.sub(total, pre), cur), 0);
         let otherP = Math.max(100 - preP - curP, 0);
         let otherP = Math.max(100 - preP - curP, 0);
         const html = '<div class="progress">' +
         const html = '<div class="progress">' +
-            '<div class="progress-bar bg-success" style="width: ' + preP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="截止上期完成:¥' + pre + '">' + preP + '%</div>' +
-            '<div class="progress-bar bg-info" style="width: ' + curP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="本期完成:¥' + cur + '">' + curP + '%</div>' +
-            '<div class="progress-bar bg-gray" style="width: ' + otherP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="未完成:¥' + other + '">' + otherP + '%</div>' +
+            '<div class="progress-bar bg-success" style="width: ' + preP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="截止上期完成:¥' + (pre || 0) + '">' + preP + '%</div>' +
+            '<div class="progress-bar bg-info" style="width: ' + curP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="本期完成:¥' + (cur || 0) + '">' + curP + '%</div>' +
+            '<div class="progress-bar bg-gray" style="width: ' + otherP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="未完成:¥' + (other || 0) + '">' + otherP + '%</div>' +
             '</div>';
             '</div>';
         return html;
         return html;
     } else {
     } else {

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

@@ -272,7 +272,6 @@ const ZhCalc = (function () {
                     return Number(expr);
                     return Number(expr);
                 } else {
                 } else {
                     const rpnArr = this.parse2Rpn(expr);
                     const rpnArr = this.parse2Rpn(expr);
-                    console.log(rpnArr);
                     const result = this.evalRpn(rpnArr);
                     const result = this.evalRpn(rpnArr);
                     return result === Infinity ? null : result;
                     return result === Infinity ? null : result;
                 }
                 }

+ 21 - 4
app/router.js

@@ -19,6 +19,8 @@ module.exports = app => {
     const materialCheck = app.middlewares.materialCheck();
     const materialCheck = app.middlewares.materialCheck();
     // 第三方接口认证判断中间件
     // 第三方接口认证判断中间件
     const api2otherCheck = app.middlewares.api2otherCheck();
     const api2otherCheck = app.middlewares.api2otherCheck();
+    // 项目管理接口认证中间件
+    const api3managementCheck = app.middlewares.api3managementCheck();
     // 微信验证登录中间件
     // 微信验证登录中间件
     const wechatAuth = app.middlewares.wechatAuth();
     const wechatAuth = app.middlewares.wechatAuth();
     // 预付款中间件
     // 预付款中间件
@@ -37,12 +39,19 @@ module.exports = app => {
     app.get('/logout', 'loginController.logout');
     app.get('/logout', 'loginController.logout');
     app.post('/login', 'loginController.login');
     app.post('/login', 'loginController.login');
     app.post('/login/port', 'loginController.loginPort');
     app.post('/login/port', 'loginController.loginPort');
+    app.get('/login/management', api3managementCheck, 'loginController.management');
     app.get('/project/name', 'loginController.projectName');
     app.get('/project/name', 'loginController.projectName');
 
 
     app.get('/sign', 'signController.index');
     app.get('/sign', 'signController.index');
     app.post('/sign/save', 'signController.save');
     app.post('/sign/save', 'signController.save');
     app.post('/reset/password', 'loginController.resetPassword');
     app.post('/reset/password', 'loginController.resetPassword');
 
 
+    // 项目管理对计量接口相关
+    app.get('/management/account', api3managementCheck, 'loginController.account');
+    app.get('/management/account/sync', api3managementCheck, 'loginController.syncProjectAccount');
+    app.get('/management/project', api3managementCheck, 'loginController.project');
+    app.get('/management/proxy/project/vertify', sessionAuth, 'loginController.vertifyProject');
+    app.get('/management/proxy/project/add', sessionAuth, 'loginController.addProject');
     // 用户信息初始化相关
     // 用户信息初始化相关
     app.get('/boot', sessionAuth, 'bootController.index');
     app.get('/boot', sessionAuth, 'bootController.index');
     app.post('/boot', sessionAuth, 'bootController.boot');
     app.post('/boot', sessionAuth, 'bootController.boot');
@@ -217,11 +226,14 @@ module.exports = app => {
 
 
     app.get('/tender/:id/revise/compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.compare');
     app.get('/tender/:id/revise/compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.compare');
     app.get('/tender/:id/revise/gcl-compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.gclCompare');
     app.get('/tender/:id/revise/gcl-compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.gclCompare');
-    app.post('/tender/:id/revise/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.loadData');
+    app.post('/tender/:id/revise/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.loadData');
+    // 单价调整
+    app.get('/tender/:id/revise/price', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.price');
+
 
 
     // 查看修订数据
     // 查看修订数据
-    app.get('/tender/:id/revise/history', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.history');
-    app.post('/tender/:id/revise/history/load', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.loadHistoryData');
+    app.get('/tender/:id/revise/history/:rid', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.history');
+    app.post('/tender/:id/revise/history/:rid/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.loadHistoryData');
     app.post('/tender/:id/revise/history/info', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.historyInfo');
     app.post('/tender/:id/revise/history/info', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.historyInfo');
 
 
     // 修订审批
     // 修订审批
@@ -443,6 +455,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/material/add', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.add');
     app.post('/tender/:id/measure/material/add', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.add');
     app.post('/tender/:id/measure/material/delete', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.delete');
     app.post('/tender/:id/measure/material/delete', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.delete');
     app.post('/tender/:id/measure/material/auditors', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.materialAuditors');
     app.post('/tender/:id/measure/material/auditors', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.materialAuditors');
+    app.post('/tender/:id/measure/material/:order/save/decimal', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.saveDecimal');
     // 审批
     // 审批
     app.post('/tender/:id/measure/material/:order/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.addAudit');
     app.post('/tender/:id/measure/material/:order/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.addAudit');
     app.post('/tender/:id/measure/material/:order/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.deleteAudit');
     app.post('/tender/:id/measure/material/:order/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.deleteAudit');
@@ -460,7 +473,10 @@ module.exports = app => {
     app.get('/tender/:id/measure/material/:order/list', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.list');
     app.get('/tender/:id/measure/material/:order/list', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.list');
     app.post('/tender/:id/measure/material/:order/list/save', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.saveListsData');
     app.post('/tender/:id/measure/material/:order/list/save', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.saveListsData');
     app.post('/tender/:id/measure/material/:order/list/load', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.loadListsData');
     app.post('/tender/:id/measure/material/:order/list/load', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.loadListsData');
-
+    // 调差清单设置页
+    app.get('/tender/:id/measure/material/:order/checklist', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.checklist');
+    app.post('/tender/:id/measure/material/:order/checklist/load', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.loadListsData');
+    app.post('/tender/:id/measure/material/:order/checklist/save', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.saveChecklistData');
     // 附件
     // 附件
     app.get('/tender/:id/measure/material/:order/file', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.file');
     app.get('/tender/:id/measure/material/:order/file', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.file');
     app.post('/tender/:id/measure/material/:order/file/upload', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.upload');
     app.post('/tender/:id/measure/material/:order/file/upload', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.upload');
@@ -553,6 +569,7 @@ module.exports = app => {
 
 
     // 书签
     // 书签
     app.post('/tender/:id/ledger/tag', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.billsTag');
     app.post('/tender/:id/ledger/tag', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.billsTag');
+    app.post('/tender/:id/revise/info/tag', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'tenderController.billsTag');
     app.post('/tender/:id/measure/stage/:order/tag', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'tenderController.billsTag');
     app.post('/tender/:id/measure/stage/:order/tag', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'tenderController.billsTag');
 
 
     // 总分包
     // 总分包

+ 25 - 0
app/service/category.js

@@ -173,6 +173,31 @@ module.exports = app => {
             }
             }
         }
         }
 
 
+        /**
+         * 获取项目下全部分类数据
+         *
+         * @param {Number} pid - 标段id
+         * @returns {Promise<*>}
+         */
+        async getListByCategoryLevel(pid) {
+            let data = await this.getAllDataByCondition({ where: { pid }, orders: [['level', 'asc']] });
+            data = this._.filter(data, function(item) {
+                return item.level !== 0;
+            });
+            const values = await this.ctx.service.categoryValue.getAllDataByCondition({
+                where: { pid },
+                orders: [['sort', 'asc'], ['id', 'asc']],
+            });
+            // values 按名称排序
+            // values.sort((a, b) => a.value.localeCompare(b.value, 'zh-Hans-CN', { sensitivity: 'accent' }));
+            for (const d of data) {
+                d.value = values.filter(function (v) {
+                    return v.cid === d.id;
+                });
+            }
+            return data;
+        }
+
     }
     }
 
 
     return Category;
     return Category;

+ 17 - 2
app/service/change.js

@@ -105,6 +105,7 @@ module.exports = app => {
                     in_time: new Date(),
                     in_time: new Date(),
                     code,
                     code,
                     name,
                     name,
+                    tp_decimal: this.ctx.tender.info.decimal.tp,
                 };
                 };
                 const operate = await this.transaction.insert(this.tableName, change);
                 const operate = await this.transaction.insert(this.tableName, change);
 
 
@@ -1140,7 +1141,7 @@ module.exports = app => {
             const sql =
             const sql =
                 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' +
                 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' +
                 '    c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' +
                 '    c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' +
-                '    cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, ' +
+                '    cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, cb.gcl_id, ' +
                 '    scb.used_amount' +
                 '    scb.used_amount' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' +
                 '  Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' +
@@ -1188,7 +1189,7 @@ module.exports = app => {
             const sql =
             const sql =
                 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' +
                 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' +
                 '    c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' +
                 '    c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' +
-                '    cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, ' +
+                '    cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, cb.gcl_id, ' +
                 '    scb.used_amount' +
                 '    scb.used_amount' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  FROM ' + this.tableName + ' As c ' +
                 '  Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' +
                 '  Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' +
@@ -1623,6 +1624,20 @@ module.exports = app => {
                 cid,
                 cid,
             });
             });
         }
         }
+
+        async updateDecimalAndTp() {
+            // 判断是否可修改
+            // 判断t_type是否为费用
+            const transaction = await this.db.beginTransaction();
+            try {
+                await this.ctx.service.changeAuditList.calcCamountSum(transaction, true);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
     }
     }
 
 
     return Change;
     return Change;

+ 10 - 1
app/service/change_audit.js

@@ -234,6 +234,15 @@ module.exports = app => {
             const list = await this.db.query(sql, sqlParam);
             const list = await this.db.query(sql, sqlParam);
             return list;
             return list;
         }
         }
+        async getListGroupByTimesWithDetail(cid, times) {
+            const sql = 'SELECT *, pa.name, pa.company, pa.role, pa.mobile, pa.telephone FROM ' + this.tableName + ' ca ' +
+                '  Left Join ' + this.ctx.service.projectAccount.tableName + ' pa On ca.uid = pa.id' +
+                '  where id in (SELECT MAX(id) FROM ' + this.tableName +' WHERE cid = ? AND times = ? GROUP BY usite)' +
+                '  ORDER BY usite asc';
+            const sqlParam = [cid, times];
+            const list = await this.db.query(sql, sqlParam);
+            return list;
+        }
 
 
         /**
         /**
          * 获取比sort大的审批人列表
          * 获取比sort大的审批人列表
@@ -636,7 +645,7 @@ module.exports = app => {
         }
         }
 
 
         async getNumByMonth(tid, startMonth, endMonth) {
         async getNumByMonth(tid, startMonth, endMonth) {
-            const sql = 'SELECT COUNT(*) as num FROM ?? WHERE id in (SELECT b.id FROM (SELECT * FROM ?? WHERE tid = ? GROUP BY id ORDER BY usort DESC) as b GROUP BY b.cid) AND status = ? AND sin_time between ? and ?';
+            const sql = 'SELECT COUNT(*) as num FROM ?? WHERE id in (SELECT b.id FROM (SELECT * FROM ?? WHERE tid = ? AND usite != 0 GROUP BY id ORDER BY usort DESC) as b GROUP BY b.cid) AND status = ? AND sin_time between ? and ?';
             const sqlParam = [this.tableName, this.tableName, tid, auditConst.auditStatus.checked, startMonth, endMonth];
             const sqlParam = [this.tableName, this.tableName, tid, auditConst.auditStatus.checked, startMonth, endMonth];
             const result = await this.db.queryOne(sql, sqlParam);
             const result = await this.db.queryOne(sql, sqlParam);
             return result ? result.num : 0;
             return result ? result.num : 0;

+ 13 - 6
app/service/change_audit_list.js

@@ -297,7 +297,7 @@ module.exports = app => {
             }
             }
         }
         }
 
 
-        async calcCamountSum(transaction) {
+        async calcCamountSum(transaction, updateTpDecimal = false) {
             // const sql = 'SELECT SUM(ROUND(`camount`*`unit_price`, )) as total_price FROM ?? WHERE cid = ?';
             // const sql = 'SELECT SUM(ROUND(`camount`*`unit_price`, )) as total_price FROM ?? WHERE cid = ?';
             // const sqlParam = [this.tableName, this.change.cid];
             // const sqlParam = [this.tableName, this.change.cid];
             // const tp = await transaction.queryOne(sql, sqlParam);
             // const tp = await transaction.queryOne(sql, sqlParam);
@@ -313,6 +313,9 @@ module.exports = app => {
             const updateData = {
             const updateData = {
                 total_price,
                 total_price,
             };
             };
+            if (updateTpDecimal) {
+                updateData.tp_decimal = tp_decimal;
+            }
             const options = {
             const options = {
                 where: {
                 where: {
                     cid: this.ctx.change.cid,
                     cid: this.ctx.change.cid,
@@ -811,7 +814,7 @@ module.exports = app => {
                     await this._findParents(transaction, tid, r, result);
                     await this._findParents(transaction, tid, r, result);
                 }
                 }
                 // 插入到计量单元表,并删除变更的计量单元数据, 插入清单表,并删除变更的清单表
                 // 插入到计量单元表,并删除变更的计量单元数据, 插入清单表,并删除变更的清单表
-                await this._insertByChangeRevise(transaction, tid, result, result2);
+                await this._insertByChangeRevise(transaction, tid, cid, result, result2);
                 // 更新标段总金额
                 // 更新标段总金额
                 const sumSql = 'SELECT Sum(total_price) As total_price, Sum(deal_tp) As deal_tp' +
                 const sumSql = 'SELECT Sum(total_price) As total_price, Sum(deal_tp) As deal_tp' +
                     '  FROM ' + this.ctx.service.ledger.tableName + this.ctx.helper.whereSql({ tender_id: tid });
                     '  FROM ' + this.ctx.service.ledger.tableName + this.ctx.helper.whereSql({ tender_id: tid });
@@ -826,7 +829,7 @@ module.exports = app => {
 
 
         async _findParents(transaction, tid, id, result) {
         async _findParents(transaction, tid, id, result) {
             const info = await transaction.get(this.ctx.service.changeLedger.tableName, { tender_id: tid, ledger_id: id });
             const info = await transaction.get(this.ctx.service.changeLedger.tableName, { tender_id: tid, ledger_id: id });
-            if (info && this._.findIndex(result, { ledger_id: info.id }) === -1) {
+            if (info && this._.findIndex(result, { ledger_id: info.ledger_id }) === -1) {
                 result.push(info);
                 result.push(info);
                 await this._findParents(transaction, tid, info.ledger_pid, result);
                 await this._findParents(transaction, tid, info.ledger_pid, result);
             } else {
             } else {
@@ -834,7 +837,7 @@ module.exports = app => {
             }
             }
         }
         }
 
 
-        async _insertByChangeRevise(transaction, tid, ledgerList, posList) {
+        async _insertByChangeRevise(transaction, tid, cid, ledgerList, posList) {
             if (ledgerList.length > 0) {
             if (ledgerList.length > 0) {
                 const insertLedgerArr = [];
                 const insertLedgerArr = [];
                 for (const l of ledgerList) {
                 for (const l of ledgerList) {
@@ -848,6 +851,8 @@ module.exports = app => {
                     ];
                     ];
                     insertLedgerArr.push('(' + this.ctx.helper.getInArrStrSqlFilter(insertL) + ')');
                     insertLedgerArr.push('(' + this.ctx.helper.getInArrStrSqlFilter(insertL) + ')');
                     await transaction.delete(this.ctx.service.changeLedger.tableName, { id: l.id });
                     await transaction.delete(this.ctx.service.changeLedger.tableName, { id: l.id });
+                    // 日志添加
+                    await transaction.insert(this.ctx.service.changeReviseLog.tableName, { tid, cid, lid: l.id, name: l.name, create_time: new Date() });
                 }
                 }
                 const bSql = 'Insert Into ' +
                 const bSql = 'Insert Into ' +
                     this.ctx.service.ledger.tableName +
                     this.ctx.service.ledger.tableName +
@@ -863,7 +868,7 @@ module.exports = app => {
                 const insertPosArr = [];
                 const insertPosArr = [];
                 for (const p of posList) {
                 for (const p of posList) {
                     const insertp = [
                     const insertp = [
-                        p.id, p.tid, p.lid, p.name, p.drawing_code, p.quantity, p.add_stage, p.add_times,
+                        p.id, p.tid, p.lid, p.name, p.drawing_code, p.quantity, p.add_stage, p.add_stage_order, p.add_times,
                         p.add_user, p.sgfh_qty, p.sjcl_qty, p.qtcl_qty, p.crid, p.porder, p.position,
                         p.add_user, p.sgfh_qty, p.sjcl_qty, p.qtcl_qty, p.crid, p.porder, p.position,
                         p.sgfh_expr, p.sjcl_expr, p.qtcl_expr, p.real_qty,
                         p.sgfh_expr, p.sjcl_expr, p.qtcl_expr, p.real_qty,
                         p.gxby_status, p.dagl_status, p.dagl_url, p.gxby_limit, p.dagl_limit,
                         p.gxby_status, p.dagl_status, p.dagl_url, p.gxby_limit, p.dagl_limit,
@@ -871,11 +876,13 @@ module.exports = app => {
                     ];
                     ];
                     insertPosArr.push('(' + this.ctx.helper.getInArrStrSqlFilter(insertp) + ')');
                     insertPosArr.push('(' + this.ctx.helper.getInArrStrSqlFilter(insertp) + ')');
                     await transaction.delete(this.ctx.service.changePos.tableName, { id: p.id });
                     await transaction.delete(this.ctx.service.changePos.tableName, { id: p.id });
+                    // 日志添加
+                    await transaction.insert(this.ctx.service.changeReviseLog.tableName, { tid, cid, pid: p.id, name: p.name, create_time: new Date() });
                 }
                 }
                 const pSql =
                 const pSql =
                     'Insert Into ' +
                     'Insert Into ' +
                     this.ctx.service.pos.tableName +
                     this.ctx.service.pos.tableName +
-                    '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
+                    '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_stage_order, add_times, add_user,' +
                     '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position, ' +
                     '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position, ' +
                     '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                     '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                     '     gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit,' +
                     '     gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit,' +

+ 1 - 0
app/service/change_ledger.js

@@ -1220,6 +1220,7 @@ module.exports = app => {
                                 sjcl_expr: pos.sjcl_expr ? pos.sjcl_expr : '',
                                 sjcl_expr: pos.sjcl_expr ? pos.sjcl_expr : '',
                                 qtcl_expr: pos.qtcl_expr ? pos.qtcl_expr : '',
                                 qtcl_expr: pos.qtcl_expr ? pos.qtcl_expr : '',
                                 add_stage: 0,
                                 add_stage: 0,
+                                add_stage_order: 0,
                                 add_times: 0,
                                 add_times: 0,
                                 ex_memo1: pos.ex_memo1,
                                 ex_memo1: pos.ex_memo1,
                                 ex_memo2: pos.ex_memo2,
                                 ex_memo2: pos.ex_memo2,

+ 2 - 0
app/service/change_pos.js

@@ -40,6 +40,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;
@@ -382,6 +383,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;

+ 27 - 0
app/service/change_revise_log.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ * 变更新增部位插入记录表
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+
+    class ChangePos extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'change_revise_log';
+        }
+    }
+
+    return ChangePos;
+};

+ 1 - 1
app/service/datacollect_audit.js

@@ -55,7 +55,7 @@ module.exports = app => {
         }
         }
 
 
         async getList(pid) {
         async getList(pid) {
-            const list = await this.db.select(this.tableName, { pid });
+            const list = await this.db.select(this.tableName, { where: { pid } });
             for (const l of list) {
             for (const l of list) {
                 if (l.uid) {
                 if (l.uid) {
                     const accountInfo = await this.ctx.service.projectAccount.getDataById(l.uid);
                     const accountInfo = await this.ctx.service.projectAccount.getDataById(l.uid);

+ 100 - 0
app/service/datacollect_tender.js

@@ -0,0 +1,100 @@
+'use strict';
+
+/**
+ * 决策大屏标段管理-数据模型
+ *
+ * @author ellisran
+ * @date 2021/09/23
+ * @version
+ */
+// const accountGroup = require('../const/account_group').group;
+module.exports = app => {
+    class datacollectTender extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'datacollect_tender';
+        }
+
+        // async getGroupInfo(pid, groupid) {
+        //     const sql = 'SELECT * FROM ?? WHERE pid = ? AND groupid = ? AND uid is NULL';
+        //     const sqlParam = [this.tableName, pid, groupid];
+        //     return await this.db.queryOne(sql, sqlParam);
+        // }
+        //
+        // async saveAudit(pid, groupid, uid) {
+        //     const data = {
+        //         pid,
+        //         groupid,
+        //         uid,
+        //         create_time: new Date(),
+        //     };
+        //     return await this.db.insert(this.tableName, data);
+        // }
+        //
+        // async saveGroup(pid, groupid) {
+        //     const transaction = await this.db.beginTransaction();
+        //     try {
+        //         // 删除所在组的用户
+        //         await transaction.delete(this.tableName, { pid, groupid });
+        //         const data = {
+        //             pid,
+        //             groupid,
+        //             create_time: new Date(),
+        //         };
+        //         await transaction.insert(this.tableName, data);
+        //         await transaction.commit();
+        //         return true;
+        //     } catch (err) {
+        //         await transaction.rollback();
+        //         throw err;
+        //     }
+        // }
+        //
+        // async delAudit(id) {
+        //     return await this.db.delete(this.tableName, { id });
+        // }
+
+        async getList(pid) {
+            return await this.db.select(this.tableName, { where: { pid } });
+        }
+
+        async updateList(pid, tids) {
+            // 初始化事务
+            const transaction = await this.db.beginTransaction();
+            try {
+                const oldList = await this.getList(pid);
+                const oldIds = this._.map(oldList, 'tid');
+                const insertTids = this._.difference(tids, oldIds);
+                const delTids = this._.difference(oldIds, tids);
+                if (insertTids.length > 0) {
+                    const insertDatas = [];
+                    for (const i of insertTids) {
+                        insertDatas.push({
+                            pid,
+                            tid: i,
+                        });
+                    }
+                    await transaction.insert(this.tableName, insertDatas);
+                }
+                if (delTids.length > 0) {
+                    for (const d of delTids) {
+                        await transaction.delete(this.tableName, { pid, tid: d });
+                    }
+                }
+                transaction.commit();
+            } catch (e) {
+                console.log(e);
+                transaction.rollback();
+            }
+        }
+
+        async add(pid, tid) {
+            const data = {
+                pid,
+                tid,
+            };
+            return await this.db.insert(this.tableName, data);
+        }
+    }
+    return datacollectTender;
+};

+ 3 - 8
app/service/ledger.js

@@ -520,7 +520,7 @@ module.exports = app => {
                     for (const [j, p] of data[i].pos.entries()) {
                     for (const [j, p] of data[i].pos.entries()) {
                         const inD = {
                         const inD = {
                             id: this.uuid.v4(), tid: tenderId, lid: qd.id,
                             id: this.uuid.v4(), tid: tenderId, lid: qd.id,
-                            add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
+                            add_stage: 0, add_stage_order: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                             in_time, porder: j + 1,
                             in_time, porder: j + 1,
                             name: p.name, drawing_code: p.drawing_code,
                             name: p.name, drawing_code: p.drawing_code,
                         };
                         };
@@ -609,7 +609,7 @@ module.exports = app => {
                     for (const [j, p] of data[i].pos.entries()) {
                     for (const [j, p] of data[i].pos.entries()) {
                         const inD = {
                         const inD = {
                             id: this.uuid.v4(), tid: tenderId, lid: qd.id,
                             id: this.uuid.v4(), tid: tenderId, lid: qd.id,
-                            add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
+                            add_stage: 0, add_stage_order: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                             in_time, porder: j + 1,
                             in_time, porder: j + 1,
                             name: p.name, drawing_code: p.drawing_code,
                             name: p.name, drawing_code: p.drawing_code,
                         };
                         };
@@ -686,8 +686,6 @@ module.exports = app => {
             const analysisExcel = new AnalysisExcel(this.ctx, this.setting);
             const analysisExcel = new AnalysisExcel(this.ctx, this.setting);
             const tempData = await this.ctx.service.tenderNodeTemplate.getData(templateId, true);
             const tempData = await this.ctx.service.tenderNodeTemplate.getData(templateId, true);
             const cacheTree = analysisExcel.analysisData(excelData, tempData, { filterZeroGcl: filter });
             const cacheTree = analysisExcel.analysisData(excelData, tempData, { filterZeroGcl: filter });
-            const cacheKey = keyPre + this.ctx.tender.id;
-            const orgMaxId = parseInt(await this.cache.get(cacheKey));
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
                 await transaction.delete(this.tableName, { tender_id: this.ctx.tender.id });
                 await transaction.delete(this.tableName, { tender_id: this.ctx.tender.id });
@@ -731,13 +729,10 @@ module.exports = app => {
                     await transaction.insert(this.ctx.service.pos.tableName, cacheTree.pos);
                     await transaction.insert(this.ctx.service.pos.tableName, cacheTree.pos);
                 }
                 }
                 await transaction.commit();
                 await transaction.commit();
-                this.cache.set(cacheKey, cacheTree.keyNodeId, 'EX', this.ctx.app.config.cacheTime);
+                this._cacheMaxLid(this.ctx.tender.id, cacheTree.keyNodeId);
                 return { bills: datas, pos: cacheTree.pos };
                 return { bills: datas, pos: cacheTree.pos };
             } catch (err) {
             } catch (err) {
                 await transaction.rollback();
                 await transaction.rollback();
-                if (orgMaxId) {
-                    this.cache.set(cacheKey, cacheTree.keyNodeId, 'EX', this.ctx.app.config.cacheTime);
-                }
                 throw err;
                 throw err;
             }
             }
         }
         }

+ 25 - 0
app/service/ledger_audit.js

@@ -242,6 +242,26 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
+         * 备份
+         * @param {Object} revise - 修订
+         * @returns {Promise<void>}
+         * @private
+         */
+        async backupLedgerHistoryFile() {
+            const timestamp = (new Date()).getTime();
+
+            const billsHis = `${this.ctx.session.sessionProject.id}/${this.ctx.tender.id}/bills${timestamp}.json`;
+            const bills = await this.ctx.service.ledger.getData(this.ctx.tender.id);
+            await this.ctx.app.hisOss.put(this.ctx.app.config.hisOssPath + billsHis, Buffer.from(JSON.stringify(bills), 'utf8'));
+
+            const posHis = `${this.ctx.session.sessionProject.id}/${this.ctx.tender.id}/pos${timestamp}.json`;
+            const pos = await this.ctx.service.pos.getAllDataByCondition({tid: this.ctx.tender.id});
+            await this.ctx.app.hisOss.put(this.ctx.app.config.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
+
+            return [billsHis, posHis];
+        }
+
+        /**
          * 开始审批
          * 开始审批
          *
          *
          * @param {Number} tenderId - 标段id
          * @param {Number} tenderId - 标段id
@@ -259,6 +279,9 @@ module.exports = app => {
             }
             }
             const sum = await this.ctx.service.ledger.addUp({ tender_id: tenderId /* , is_leaf: true*/ });
             const sum = await this.ctx.service.ledger.addUp({ tender_id: tenderId /* , is_leaf: true*/ });
 
 
+            // 拷贝备份台账数据
+            const [billsHis, posHis] = await this.backupLedgerHistoryFile();
+
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
                 await transaction.update(this.tableName, {
                 await transaction.update(this.tableName, {
@@ -271,6 +294,8 @@ module.exports = app => {
                     ledger_status: auditConst.status.checking,
                     ledger_status: auditConst.status.checking,
                     total_price: sum.total_price,
                     total_price: sum.total_price,
                     deal_tp: sum.deal_tp,
                     deal_tp: sum.deal_tp,
+                    bills_file: billsHis,
+                    pos_file: posHis,
                 });
                 });
 
 
                 // 添加短信通知-需要审批提醒功能
                 // 添加短信通知-需要审批提醒功能

+ 5 - 5
app/service/ledger_revise.js

@@ -30,7 +30,7 @@ module.exports = app => {
          * @returns {Promise<*>} - ledger_change下所有数据,并关联 project_account(读取提交人名称、单位、公司)
          * @returns {Promise<*>} - ledger_change下所有数据,并关联 project_account(读取提交人名称、单位、公司)
          */
          */
         async getReviseList (tid) {
         async getReviseList (tid) {
-            const sql = 'SELECT lc.id, lc.tid, lc.corder, lc.in_time, lc.uid, lc.begin_time, lc.end_time, lc.times, lc.status, lc.valid, lc.content,' +
+            const sql = 'SELECT lc.id, lc.tid, lc.corder, lc.in_time, lc.uid, lc.begin_time, lc.end_time, lc.times, lc.status, lc.valid, lc.content, lc.bills_file,' +
                 '    pa.name As user_name, pa.role As user_role, pa.company As user_company' +
                 '    pa.name As user_name, pa.role As user_role, pa.company As user_company' +
                 '  FROM ' + this.tableName + ' As lc' +
                 '  FROM ' + this.tableName + ' As lc' +
                 '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
                 '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
@@ -158,13 +158,13 @@ module.exports = app => {
         async backupReviseHistoryFile(revise) {
         async backupReviseHistoryFile(revise) {
             const timestamp = (new Date()).getTime();
             const timestamp = (new Date()).getTime();
 
 
-            const billsHis = '/revise/bills' + timestamp + '.json';
+            const billsHis = `${this.ctx.session.sessionProject.id}/${this.ctx.tender.id}/bills${timestamp}.json`;
             const bills = await this.ctx.service.reviseBills.getData(revise.tid);
             const bills = await this.ctx.service.reviseBills.getData(revise.tid);
-            await this.ctx.helper.saveBufferFile(JSON.stringify(bills), this.ctx.app.config.filePath + billsHis);
+            await this.ctx.app.hisOss.put(this.ctx.app.config.hisOssPath + billsHis, Buffer.from(JSON.stringify(bills), 'utf8'));
 
 
-            const posHis = '/revise/pos' + timestamp + '.json';
+            const posHis = `${this.ctx.session.sessionProject.id}/${this.ctx.tender.id}/pos${timestamp}.json`;
             const pos = await this.ctx.service.revisePos.getData(revise.tid);
             const pos = await this.ctx.service.revisePos.getData(revise.tid);
-            await this.ctx.helper.saveBufferFile(JSON.stringify(pos), this.ctx.app.config.filePath + posHis);
+            await this.ctx.app.hisOss.put(this.ctx.app.config.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
 
 
             return [billsHis, posHis];
             return [billsHis, posHis];
         }
         }

+ 2 - 2
app/service/ledger_tag.js

@@ -12,7 +12,7 @@ const validField = ['lid', 'share', 'color', 'comment'];
 
 
 module.exports = app => {
 module.exports = app => {
 
 
-    class StageBillsDgn extends app.BaseService {
+    class LedgerTag extends app.BaseService {
         /**
         /**
          * 构造函数
          * 构造函数
          *
          *
@@ -98,5 +98,5 @@ module.exports = app => {
         }
         }
     }
     }
 
 
-    return StageBillsDgn;
+    return LedgerTag;
 };
 };

+ 1 - 0
app/service/manager.js

@@ -22,6 +22,7 @@ module.exports = app => {
             super(ctx);
             super(ctx);
             this.tableName = 'manager';
             this.tableName = 'manager';
         }
         }
+
     }
     }
 
 
     return Manager;
     return Manager;

+ 31 - 7
app/service/material.js

@@ -10,6 +10,7 @@
 
 
 const auditConst = require('../const/audit').material;
 const auditConst = require('../const/audit').material;
 const projectLogConst = require('../const/project_log');
 const projectLogConst = require('../const/project_log');
+const materialConst = require('../const/material');
 module.exports = app => {
 module.exports = app => {
     class Material extends app.BaseService {
     class Material extends app.BaseService {
         /**
         /**
@@ -145,6 +146,7 @@ module.exports = app => {
                 stage_id: data.stage_id.join(','),
                 stage_id: data.stage_id.join(','),
                 s_order: data.s_order,
                 s_order: data.s_order,
                 material_tax: this.ctx.session.sessionProject.page_show.openMaterialTax,
                 material_tax: this.ctx.session.sessionProject.page_show.openMaterialTax,
+                decimal: preMaterial && preMaterial.decimal ? preMaterial.decimal : JSON.stringify(materialConst.decimal),
             };
             };
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
@@ -173,9 +175,9 @@ module.exports = app => {
                     // 复制调差清单工料关联表
                     // 复制调差清单工料关联表
                     await this.ctx.service.materialList.copyPreMaterialList(transaction, preMaterial, newMaterial);
                     await this.ctx.service.materialList.copyPreMaterialList(transaction, preMaterial, newMaterial);
                     // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
                     // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
-                    const [m_tp, m_tax_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id);
+                    const [m_tp, m_tax_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id, JSON.parse(newMaterial.decimal));
                     // 修改现行价格指数,并返回调差基数json
                     // 修改现行价格指数,并返回调差基数json
-                    const ex_calc = await this.ctx.service.materialExponent.updateNewMaterial(transaction, newMaterial.id, this.ctx, newMaterial.stage_id, preMaterial.ex_calc);
+                    const ex_calc = await this.ctx.service.materialExponent.updateNewMaterial(transaction, newMaterial.id, this.ctx, newMaterial.stage_id, preMaterial.ex_calc, JSON.parse(newMaterial.decimal));
                     // 计算得出本期总金额
                     // 计算得出本期总金额
                     const updateMaterialData = {
                     const updateMaterialData = {
                         id: newMaterial.id,
                         id: newMaterial.id,
@@ -312,8 +314,8 @@ module.exports = app => {
          * @param {int} order 调差期数
          * @param {int} order 调差期数
          * @return {Promise<*>}
          * @return {Promise<*>}
          */
          */
-        async getPreTpHs(tid, order) {
-            const sql = 'SELECT SUM(ROUND(`m_tp`*(1+ `rate`/100),2)) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
+        async getPreTpHs(tid, order, tp) {
+            const sql = 'SELECT SUM(ROUND(`m_tp`*(1+ `rate`/100),' + tp + ')) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
             const sqlParam = [this.tableName, tid, 0, order];
             const sqlParam = [this.tableName, tid, 0, order];
             const result = await this.db.queryOne(sql, sqlParam);
             const result = await this.db.queryOne(sql, sqlParam);
             return result.pre_tp_hs;
             return result.pre_tp_hs;
@@ -338,8 +340,8 @@ module.exports = app => {
          * @param {int} order 调差期数
          * @param {int} order 调差期数
          * @return {Promise<*>}
          * @return {Promise<*>}
          */
          */
-        async getExPreTpHs(tid, order) {
-            const sql = 'SELECT SUM(ROUND(`ex_tp`*(1+ `rate`/100),2)) AS `ex_pre_tp_hs` FROM ?? WHERE `tid` = ? AND `order` < ?';
+        async getExPreTpHs(tid, order, tp) {
+            const sql = 'SELECT SUM(ROUND(`ex_tp`*(1+ `rate`/100),' + tp + ')) AS `ex_pre_tp_hs` FROM ?? WHERE `tid` = ? AND `order` < ?';
             const sqlParam = [this.tableName, tid, order];
             const sqlParam = [this.tableName, tid, order];
             const result = await this.db.queryOne(sql, sqlParam);
             const result = await this.db.queryOne(sql, sqlParam);
             return result.ex_pre_tp_hs;
             return result.ex_pre_tp_hs;
@@ -359,7 +361,7 @@ module.exports = app => {
         }
         }
 
 
         async getSumMaterial(tid) {
         async getSumMaterial(tid) {
-            const sql = 'Select sum(m_tp + ex_tp) as tp From ' + this.tableName + ' where tid = ?';
+            const sql = 'Select sum(IFNULL(m_tp, 0) + IFNULL(ex_tp, 0)) as tp From ' + this.tableName + ' where tid = ?';
             const result = await this.db.queryOne(sql, [tid]);
             const result = await this.db.queryOne(sql, [tid]);
             return result ? result.tp : 0;
             return result ? result.tp : 0;
         }
         }
@@ -370,6 +372,28 @@ module.exports = app => {
             const result = await this.db.queryOne(sql, sqlParam);
             const result = await this.db.queryOne(sql, sqlParam);
             return result && result.count !== 0;
             return result && result.count !== 0;
         }
         }
+
+        async saveDecimal(newUp, newTp) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                await this.ctx.service.materialBills.resetDecimal(transaction, newUp, newTp);
+                this.ctx.material.decimal.up = newUp;
+                this.ctx.material.decimal.tp = newTp;
+                const m_tp = await this.ctx.service.materialBills.calcMaterialMTp(transaction);
+                const [ex_tp, ex_expr] = await this.ctx.service.materialExponent.calcMaterialExTp(transaction);
+                const updateData = {
+                    id: this.ctx.material.id,
+                    decimal: JSON.stringify(this.ctx.material.decimal),
+                };
+                await transaction.update(this.tableName, updateData);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                console.log(err);
+                await transaction.rollback();
+                return false;
+            }
+        }
     }
     }
 
 
     return Material;
     return Material;

+ 64 - 59
app/service/material_audit.js

@@ -231,55 +231,6 @@ module.exports = app => {
                 if (materialBillsData.length === 0 && this.ctx.material.ex_expr === null) {
                 if (materialBillsData.length === 0 && this.ctx.material.ex_expr === null) {
                     throw '请至少使用一种调差方式';
                     throw '请至少使用一种调差方式';
                 }
                 }
-                const mbhList = [];
-                for (const mb of materialBillsData) {
-                    if (mb.code === '') {
-                        throw '调差工料编号不能为空';
-                    }
-                    const newMbh = {
-                        tid: this.ctx.tender.id,
-                        mid: this.ctx.material.id,
-                        order: this.ctx.material.order,
-                        mb_id: mb.id,
-                        quantity: mb.quantity,
-                        expr: mb.expr,
-                        msg_tp: mb.msg_tp,
-                        msg_times: mb.msg_times,
-                        msg_spread: mb.msg_spread,
-                        m_up_risk: mb.m_up_risk,
-                        m_down_risk: mb.m_down_risk,
-                        m_spread: mb.m_spread,
-                        m_tp: mb.m_tp,
-                        pre_tp: mb.pre_tp,
-                        m_tax_tp: mb.m_tax_tp,
-                        tax_pre_tp: mb.tax_pre_tp,
-                        origin: mb.origin,
-                        is_summary: mb.is_summary,
-                        m_tax: mb.m_tax,
-                    };
-                    mbhList.push(newMbh);
-                }
-                if(mbhList.length !== 0) await transaction.insert(this.ctx.service.materialBillsHistory.tableName, mbhList);
-
-                const materialExponentData = await this.ctx.service.materialExponent.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
-                const mehList = [];
-                for (const me of materialExponentData) {
-                    const newMeh = {
-                        tid: this.ctx.tender.id,
-                        mid: this.ctx.material.id,
-                        order: this.ctx.material.order,
-                        me_id: me.id,
-                        type: me.type,
-                        weight_num: me.weight_num,
-                        basic_price: me.basic_price,
-                        basic_times: me.basic_times,
-                        m_price: me.m_price,
-                        calc_num: me.calc_num,
-                        is_summary: me.is_summary,
-                    };
-                    mehList.push(newMeh);
-                }
-                if(mehList.length !== 0) await transaction.insert(this.ctx.service.materialExponentHistory.tableName, mehList);
 
 
                 // 微信模板通知
                 // 微信模板通知
                 const materialInfo = await this.ctx.service.material.getDataById(materialId);
                 const materialInfo = await this.ctx.service.material.getDataById(materialId);
@@ -401,6 +352,60 @@ module.exports = app => {
                         id: materialId, status: checkData.checkType,
                         id: materialId, status: checkData.checkType,
                     });
                     });
 
 
+                    // 处理旧数据,防止重复插入到历史表
+                    await transaction.delete(this.ctx.service.materialBillsHistory.tableName, { tid: this.ctx.tender.id, order: this.ctx.material.order});
+                    const mbhList = [];
+                    const materialBillsData = await this.ctx.service.materialBills.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
+                    for (const mb of materialBillsData) {
+                        if (mb.code === '') {
+                            throw '调差工料编号不能为空';
+                        }
+                        const newMbh = {
+                            tid: this.ctx.tender.id,
+                            mid: this.ctx.material.id,
+                            order: this.ctx.material.order,
+                            mb_id: mb.id,
+                            quantity: mb.quantity,
+                            expr: mb.expr,
+                            msg_tp: mb.msg_tp,
+                            msg_times: mb.msg_times,
+                            msg_spread: mb.msg_spread,
+                            m_up_risk: mb.m_up_risk,
+                            m_down_risk: mb.m_down_risk,
+                            m_spread: mb.m_spread,
+                            m_tp: mb.m_tp,
+                            pre_tp: mb.pre_tp,
+                            m_tax_tp: mb.m_tax_tp,
+                            tax_pre_tp: mb.tax_pre_tp,
+                            origin: mb.origin,
+                            is_summary: mb.is_summary,
+                            m_tax: mb.m_tax,
+                        };
+                        mbhList.push(newMbh);
+                    }
+                    if(mbhList.length !== 0) await transaction.insert(this.ctx.service.materialBillsHistory.tableName, mbhList);
+                    // 处理旧数据,防止重复插入到历史表
+                    await transaction.delete(this.ctx.service.materialExponentHistory.tableName, { tid: this.ctx.tender.id, order: this.ctx.material.order});
+                    const materialExponentData = await this.ctx.service.materialExponent.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
+                    const mehList = [];
+                    for (const me of materialExponentData) {
+                        const newMeh = {
+                            tid: this.ctx.tender.id,
+                            mid: this.ctx.material.id,
+                            order: this.ctx.material.order,
+                            me_id: me.id,
+                            type: me.type,
+                            weight_num: me.weight_num,
+                            basic_price: me.basic_price,
+                            basic_times: me.basic_times,
+                            m_price: me.m_price,
+                            calc_num: me.calc_num,
+                            is_summary: me.is_summary,
+                        };
+                        mehList.push(newMeh);
+                    }
+                    if(mehList.length !== 0) await transaction.insert(this.ctx.service.materialExponentHistory.tableName, mehList);
+
                     // 微信模板通知
                     // 微信模板通知
                     const users = this._.uniq(this._.concat(this._.map(auditors, 'aid'), materialInfo.user_id));
                     const users = this._.uniq(this._.concat(this._.map(auditors, 'aid'), materialInfo.user_id));
                     const wechatData = {
                     const wechatData = {
@@ -482,16 +487,16 @@ module.exports = app => {
                 });
                 });
                 // 拷贝新一次审核流程列表
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, auditors);
                 await transaction.insert(this.tableName, auditors);
-                // 删除material_bills_history信息
-                await transaction.delete(this.ctx.service.materialBillsHistory.tableName, {
-                    tid: this.ctx.tender.id,
-                    order: this.ctx.material.order,
-                });
-                // 删除material_exponent_history信息
-                await transaction.delete(this.ctx.service.materialExponentHistory.tableName, {
-                    tid: this.ctx.tender.id,
-                    order: this.ctx.material.order,
-                });
+                // // 删除material_bills_history信息
+                // await transaction.delete(this.ctx.service.materialBillsHistory.tableName, {
+                //     tid: this.ctx.tender.id,
+                //     order: this.ctx.material.order,
+                // });
+                // // 删除material_exponent_history信息
+                // await transaction.delete(this.ctx.service.materialExponentHistory.tableName, {
+                //     tid: this.ctx.tender.id,
+                //     order: this.ctx.material.order,
+                // });
 
 
                 // 微信模板通知
                 // 微信模板通知
                 const begin_audit = await this.getDataByCondition({
                 const begin_audit = await this.getDataByCondition({

+ 72 - 22
app/service/material_bills.js

@@ -222,13 +222,13 @@ module.exports = app => {
          * @param mid
          * @param mid
          * @returns {Promise<number>}
          * @returns {Promise<number>}
          */
          */
-        async updateNewMaterial(transaction, tid, mid, ctx, stage_id) {
+        async updateNewMaterial(transaction, tid, mid, ctx, stage_id, decimal) {
             const materialBillsData = await this.getAllDataByCondition({ where: { tid } });
             const materialBillsData = await this.getAllDataByCondition({ where: { tid } });
             let m_tp = 0;
             let m_tp = 0;
             let m_tax_tp = 0;
             let m_tax_tp = 0;
             const materialCalculator = new MaterialCalculator(ctx, stage_id, ctx.tender.info);
             const materialCalculator = new MaterialCalculator(ctx, stage_id, ctx.tender.info);
             for (const mb of materialBillsData) {
             for (const mb of materialBillsData) {
-                const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator);
+                const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal);
                 m_tp = this.ctx.helper.add(m_tp, one_tp);
                 m_tp = this.ctx.helper.add(m_tp, one_tp);
                 m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);
                 m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);
             }
             }
@@ -242,16 +242,16 @@ module.exports = app => {
          * @param mb
          * @param mb
          * @returns {Promise<*>}
          * @returns {Promise<*>}
          */
          */
-        async calcQuantityByMB(transaction, mid, mb, materialCalculator) {
-            const [newmsg_spread, newm_spread] = await this.getSpread(mb, null);
+        async calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal) {
+            const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);
             if (mb.t_type === materialConst.t_type[0].value) {
             if (mb.t_type === materialConst.t_type[0].value) {
                 const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
                 const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
                 const sqlParam = [mid, mb.id];
                 const sqlParam = [mid, mb.id];
                 const mb_quantity = await transaction.queryOne(sql, sqlParam);
                 const mb_quantity = await transaction.queryOne(sql, sqlParam);
                 console.log(mb_quantity);
                 console.log(mb_quantity);
                 // 取历史期记录获取截止上期调差金额,并清空本期单价和时间,来源地,重新计算价差和有效价差
                 // 取历史期记录获取截止上期调差金额,并清空本期单价和时间,来源地,重新计算价差和有效价差
-                const newQuantity = this.ctx.helper.round(mb_quantity.quantity, 3);
-                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), 2);
+                const newQuantity = this.ctx.helper.round(mb_quantity.quantity, decimal.qty);
+                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp);
                 const updateData = {
                 const updateData = {
                     id: mb.id,
                     id: mb.id,
                     quantity: newQuantity,
                     quantity: newQuantity,
@@ -261,33 +261,33 @@ module.exports = app => {
                     m_spread: newm_spread,
                     m_spread: newm_spread,
                     origin: null,
                     origin: null,
                     m_tp: newTp,
                     m_tp: newTp,
-                    pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), 2) : mb.pre_tp,
-                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
-                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp), 2) : mb.tax_pre_tp,
+                    pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), decimal.tp) : mb.pre_tp,
+                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),
+                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp), decimal.tp) : mb.tax_pre_tp,
                 };
                 };
                 await transaction.update(this.tableName, updateData);
                 await transaction.update(this.tableName, updateData);
-                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), 2) : 0;
-                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2);
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), decimal.tp) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
                 return [m_tp, m_tax_tp];
                 return [m_tp, m_tax_tp];
             } else if (mb.t_type === materialConst.t_type[1].value) {
             } else if (mb.t_type === materialConst.t_type[1].value) {
                 const quantity = await materialCalculator.calculateExpr(mb.expr);
                 const quantity = await materialCalculator.calculateExpr(mb.expr);
-                const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, 3), newm_spread), 2) : null;
+                const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, decimal.qty), newm_spread), decimal.tp) : null;
                 const updateData = {
                 const updateData = {
                     id: mb.id,
                     id: mb.id,
-                    quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, 3) : null,
+                    quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, decimal.qty) : null,
                     msg_tp: null,
                     msg_tp: null,
                     msg_times: null,
                     msg_times: null,
                     msg_spread: newmsg_spread,
                     msg_spread: newmsg_spread,
                     m_spread: newm_spread,
                     m_spread: newm_spread,
                     origin: null,
                     origin: null,
                     m_tp: newTp,
                     m_tp: newTp,
-                    pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), 2) : mb.pre_tp,
-                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
-                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp), 2) : mb.tax_pre_tp,
+                    pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), decimal.tp) : mb.pre_tp,
+                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),
+                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp), decimal.tp) : mb.tax_pre_tp,
                 };
                 };
                 await transaction.update(this.tableName, updateData);
                 await transaction.update(this.tableName, updateData);
-                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), 2) : 0;
-                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2);
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), decimal.tp) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
                 return [m_tp, m_tax_tp];
                 return [m_tp, m_tax_tp];
             }
             }
         }
         }
@@ -297,11 +297,11 @@ module.exports = app => {
          * @param data
          * @param data
          * @returns {Promise<void>}
          * @returns {Promise<void>}
          */
          */
-        async getSpread(data, msg_tp) {
+        async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up) {
             data.msg_tp = msg_tp;
             data.msg_tp = msg_tp;
-            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, data.basic_price), 3);
+            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, data.basic_price), newDecimalUp);
             const cor = msg_spread >= 0 ? this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_down_risk, 100));
             const cor = msg_spread >= 0 ? this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_down_risk, 100));
-            const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), 3) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), 3)) : 0;
+            const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), newDecimalUp) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), newDecimalUp)) : 0;
             return [msg_spread, m_spread];
             return [msg_spread, m_spread];
         }
         }
 
 
@@ -317,7 +317,8 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
                 const mbInfo = await this.getDataById(data.id);
                 const mbInfo = await this.getDataById(data.id);
-                data.m_tp = this.ctx.helper.round(this.ctx.helper.mul(data.quantity, mbInfo.m_spread), 2);
+                data.m_tp = this.ctx.helper.round(this.ctx.helper.mul(data.quantity, mbInfo.m_spread), this.ctx.material.decimal.tp);
+                data.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(data.m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp);
                 await transaction.update(this.tableName, data);
                 await transaction.update(this.tableName, data);
                 let m_tp = this.ctx.material.m_tp;
                 let m_tp = this.ctx.material.m_tp;
                 if (mbInfo.quantity !== data.quantity) {
                 if (mbInfo.quantity !== data.quantity) {
@@ -353,6 +354,55 @@ module.exports = app => {
             await transaction.update(this.ctx.service.material.tableName, updateData2);
             await transaction.update(this.ctx.service.material.tableName, updateData2);
             return tp.total_price;
             return tp.total_price;
         }
         }
+
+        // 小数位变化更新单价和金额
+        async resetDecimal(transaction, newDecimalUp, newDecimalTp) {
+            const mbList = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] });
+            const updateList = [];
+            const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];
+            const updateMonthList = [];
+            for (const mb of mbList) {
+                const updateData = {
+                    id: mb.id,
+                };
+                if (newDecimalUp !== this.ctx.material.decimal.up) {
+                    let newmsg_tp = this.ctx.helper.round(mb.msg_tp, newDecimalUp);
+                    mb.msg_tp = newmsg_tp;
+                    // 判断是否有月信息价,如果有则msg_tp值由月信息价的平均单价获得,并更新月信息价单价
+                    if (material_month.length > 0) {
+                        const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: mb.id, mid: this.ctx.material.id } });
+                        if (monthList.length !== 0) {
+                            for (const m of monthList) {
+                                // 更新月信息单价小数位
+                                const newMonthMsgTP = this.ctx.helper.round(m.msg_tp, newDecimalUp);
+                                if (m.msg_tp && newMonthMsgTP !== m.msg_tp) {
+                                    m.msg_tp = newMonthMsgTP;
+                                    updateMonthList.push({ id: m.id, msg_tp: m.msg_tp });
+                                }
+                            }
+                            const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');
+                            const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
+                            newmsg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), newDecimalUp) : null;
+                            mb.msg_tp = newmsg_tp;
+                        }
+                    }
+                    const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);
+                    mb.basic_price = newbasic_price;
+                    const [newmsg_spread, newm_spread] = await this.getSpread(mb, mb.msg_tp, newDecimalUp);
+                    mb.m_spread = newm_spread;
+                    updateData.basic_price = newbasic_price;
+                    updateData.msg_tp = newmsg_tp;
+                    updateData.msg_spread = newmsg_spread;
+                    updateData.m_spread = newm_spread;
+                }
+                const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), newDecimalTp);
+                updateData.m_tp = newTp;
+                updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp);
+                updateList.push(updateData);
+            }
+            if (updateMonthList.length > 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList);
+            if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList);
+        }
     }
     }
 
 
     return MaterialBills;
     return MaterialBills;

+ 67 - 0
app/service/material_checklist.js

@@ -0,0 +1,67 @@
+'use strict';
+/**
+ * 清单设置 数据模型
+ * @author LanJianRong
+ * @date 2020/6/30
+ * @version
+ */
+
+module.exports = app => {
+    class MaterialChecklist extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_checklist';
+        }
+
+        async resetData(pushData, removeData, updateData) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                if (pushData.length > 0) {
+                    const insertDatas = [];
+                    for (const p of pushData) {
+                        p.mid = this.ctx.material.id;
+                        p.tid = this.ctx.tender.id;
+                        insertDatas.push(p);
+                    }
+                    await transaction.insert(this.tableName, insertDatas);
+                }
+                if (removeData.length > 0) {
+                    for (const r of removeData) {
+                        await transaction.delete(this.tableName, { id: r });
+                    }
+                }
+                if (updateData.length > 0) {
+                    await transaction.updateRows(this.tableName, updateData);
+                }
+                await transaction.commit();
+                const materialChecklistData = await this.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
+                const self = this;
+                return await materialChecklistData.sort(function(a, b) {
+                    return self.ctx.helper.compareCode(a.b_code, b.b_code);
+                });
+            } catch (err) {
+                console.log(err);
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async updateHadBills(transaction, id, had_bills) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            return await transaction.update(this.tableName, { id, had_bills });
+        }
+    }
+    return MaterialChecklist;
+};
+

+ 4 - 4
app/service/material_exponent.js

@@ -188,7 +188,7 @@ module.exports = app => {
         }
         }
 
 
         // 更改计算总指数金额并返回值和公式
         // 更改计算总指数金额并返回值和公式
-        async calcMaterialExTp(transaction, ex_calc = (this.ctx.material.ex_calc ? JSON.parse(this.ctx.material.ex_calc) : null), mid = null) {
+        async calcMaterialExTp(transaction, ex_calc = (this.ctx.material.ex_calc ? JSON.parse(this.ctx.material.ex_calc) : null), mid = null, decimal = (this.ctx.material.decimal ? this.ctx.material.decimal : materialConst.decimal)) {
             let basic_calc = 0;
             let basic_calc = 0;
             if (ex_calc) {
             if (ex_calc) {
                 for (const calc of ex_calc) {
                 for (const calc of ex_calc) {
@@ -213,7 +213,7 @@ module.exports = app => {
             }
             }
             expr += '-1]';
             expr += '-1]';
             expr = constant !== 0 ? expr : null;
             expr = constant !== 0 ? expr : null;
-            const ex_tp = constant !== 0 ? this.ctx.helper.round(this.ctx.helper.mul(basic_calc, this.ctx.helper.sub(this.ctx.helper.add(constant, sumByChange), 1)), 2) : null;
+            const ex_tp = constant !== 0 ? this.ctx.helper.round(this.ctx.helper.mul(basic_calc, this.ctx.helper.sub(this.ctx.helper.add(constant, sumByChange), 1)), decimal.tp) : null;
             await transaction.update(this.ctx.service.material.tableName, {
             await transaction.update(this.ctx.service.material.tableName, {
                 id: mid ? mid : this.ctx.material.id,
                 id: mid ? mid : this.ctx.material.id,
                 ex_tp,
                 ex_tp,
@@ -230,7 +230,7 @@ module.exports = app => {
          * @param mid
          * @param mid
          * @returns {Promise<number>}
          * @returns {Promise<number>}
          */
          */
-        async updateNewMaterial(transaction, mid, ctx, stage_id, ex_calc) {
+        async updateNewMaterial(transaction, mid, ctx, stage_id, ex_calc, decimal) {
             const stage_list = await ctx.service.stage.getStageMsgByStageId(stage_id);
             const stage_list = await ctx.service.stage.getStageMsgByStageId(stage_id);
             const calcBase = await ctx.service.stage.getMaterialCalcBase(stage_list, ctx.tender.info);
             const calcBase = await ctx.service.stage.getMaterialCalcBase(stage_list, ctx.tender.info);
             const old_ex_calc = ex_calc ? JSON.parse(ex_calc) : null;
             const old_ex_calc = ex_calc ? JSON.parse(ex_calc) : null;
@@ -241,7 +241,7 @@ module.exports = app => {
                 bq.value = calc.value;
                 bq.value = calc.value;
                 bq.select = oldcalc ? oldcalc.select : false;
                 bq.select = oldcalc ? oldcalc.select : false;
             }
             }
-            await this.calcMaterialExTp(transaction, new_ex_calc, mid);
+            await this.calcMaterialExTp(transaction, new_ex_calc, mid, decimal);
             return new_ex_calc;
             return new_ex_calc;
         }
         }
     }
     }

+ 12 - 6
app/service/material_list.js

@@ -216,13 +216,13 @@ module.exports = app => {
             const sqlParam = [this.ctx.material.id, mb_id];
             const sqlParam = [this.ctx.material.id, mb_id];
             const mb_quantity = await transaction.queryOne(sql, sqlParam);
             const mb_quantity = await transaction.queryOne(sql, sqlParam);
             console.log(mb_quantity);
             console.log(mb_quantity);
-            const newQuantity = this.ctx.helper.round(mb_quantity.quantity, 3);
-            const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, mbInfo.m_spread), 2);
+            const newQuantity = this.ctx.helper.round(mb_quantity.quantity, this.ctx.material.decimal.qty);
+            const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, mbInfo.m_spread), this.ctx.material.decimal.tp);
             const updateData = {
             const updateData = {
                 id: mb_id,
                 id: mb_id,
-                quantity: this.ctx.helper.round(mb_quantity.quantity, 3),
+                quantity: this.ctx.helper.round(mb_quantity.quantity, this.ctx.material.decimal.qty),
                 m_tp: newTp,
                 m_tp: newTp,
-                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), 2),
+                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp),
             };
             };
             await transaction.update(this.ctx.service.materialBills.tableName, updateData);
             await transaction.update(this.ctx.service.materialBills.tableName, updateData);
             // 计算本期总金额
             // 计算本期总金额
@@ -296,7 +296,7 @@ module.exports = app => {
          * 添加工料清单关联(多清单对应)
          * 添加工料清单关联(多清单对应)
          * @return {void}
          * @return {void}
          */
          */
-        async adds(datas) {
+        async adds(datas, checklist = false) {
             if (!this.ctx.tender || !this.ctx.material) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
                 throw '数据错误';
             }
             }
@@ -344,6 +344,9 @@ module.exports = app => {
                         throw '新增工料数据失败';
                         throw '新增工料数据失败';
                     }
                     }
                 }
                 }
+                if (checklist) {
+                    await this.ctx.service.materialChecklist.updateHadBills(transaction, checklist.id, checklist.had_bills);
+                }
                 // 重算工料和总金额
                 // 重算工料和总金额
                 // const calcMBIdList = this._.uniq(mb_idList);
                 // const calcMBIdList = this._.uniq(mb_idList);
                 // if (calcMBIdList.length > 0) {
                 // if (calcMBIdList.length > 0) {
@@ -364,7 +367,7 @@ module.exports = app => {
          * @param {int} id 工料id
          * @param {int} id 工料id
          * @return {void}
          * @return {void}
          */
          */
-        async dels(datas) {
+        async dels(datas, checklist = false) {
             if (!this.ctx.tender || !this.ctx.material) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
                 throw '数据错误';
             }
             }
@@ -376,6 +379,9 @@ module.exports = app => {
                 }
                 }
                 // await transaction.delete(this.tableName, { id });
                 // await transaction.delete(this.tableName, { id });
                 await this.calcQuantityByML(transaction, datas.mb_id);
                 await this.calcQuantityByML(transaction, datas.mb_id);
+                if (checklist) {
+                    await this.ctx.service.materialChecklist.updateHadBills(transaction, checklist.id, checklist.had_bills);
+                }
                 await transaction.commit();
                 await transaction.commit();
                 // console.log(datas);
                 // console.log(datas);
                 return await this.getMaterialData(this.ctx.tender.id, this.ctx.material.id);
                 return await this.getMaterialData(this.ctx.tender.id, this.ctx.material.id);

+ 12 - 12
app/service/material_month.js

@@ -61,16 +61,16 @@ module.exports = app => {
                         if (monthList.length !== 0) {
                         if (monthList.length !== 0) {
                             const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                             const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                             const month_num = material_month.length - this.ctx.helper.arrayCount(this._.concat(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), one_month.msg_tp), [null, '', 0]);
                             const month_num = material_month.length - this.ctx.helper.arrayCount(this._.concat(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), one_month.msg_tp), [null, '', 0]);
-                            const new_msg_tp = this.ctx.helper.round(this.ctx.helper.div(this.ctx.helper.add(mb_msg_tp_sum, one_month.msg_tp), month_num), 3);
+                            const new_msg_tp = this.ctx.helper.round(this.ctx.helper.div(this.ctx.helper.add(mb_msg_tp_sum, one_month.msg_tp), month_num), this.ctx.material.decimal.up);
                             const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
                             const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
-                            const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
+                            const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), this.ctx.material.decimal.tp);
                             updateArray.push({
                             updateArray.push({
                                 id: mb.id,
                                 id: mb.id,
                                 msg_tp: new_msg_tp,
                                 msg_tp: new_msg_tp,
                                 msg_spread: newmsg_spread,
                                 msg_spread: newmsg_spread,
                                 m_spread: newm_spread,
                                 m_spread: newm_spread,
                                 m_tp: newTp,
                                 m_tp: newTp,
-                                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
+                                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), this.ctx.material.decimal.tp),
                             });
                             });
                         }
                         }
                     }
                     }
@@ -111,16 +111,16 @@ module.exports = app => {
                         });
                         });
                         const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                         const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
-                        const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
+                        const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), this.ctx.material.decimal.up) : null;
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
-                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
+                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), this.ctx.material.decimal.tp);
                         updateArray.push({
                         updateArray.push({
                             id: mb.id,
                             id: mb.id,
                             msg_tp: new_msg_tp,
                             msg_tp: new_msg_tp,
                             msg_spread: newmsg_spread,
                             msg_spread: newmsg_spread,
                             m_spread: newm_spread,
                             m_spread: newm_spread,
                             m_tp: newTp,
                             m_tp: newTp,
-                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
+                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), this.ctx.material.decimal.tp),
                         });
                         });
                     }
                     }
                     if (updateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, updateArray);
                     if (updateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, updateArray);
@@ -153,16 +153,16 @@ module.exports = app => {
                 if (monthList.length !== 0) {
                 if (monthList.length !== 0) {
                     const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');
                     const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');
                     const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
                     const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
-                    const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
+                    const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), this.ctx.material.decimal.up) : null;
                     const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mbInfo, new_msg_tp);
                     const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mbInfo, new_msg_tp);
-                    const newTp = this.ctx.helper.round(this.ctx.helper.mul(mbInfo.quantity, newm_spread), 2);
+                    const newTp = this.ctx.helper.round(this.ctx.helper.mul(mbInfo.quantity, newm_spread), this.ctx.material.decimal.tp);
                     await transaction.update(this.ctx.service.materialBills.tableName, {
                     await transaction.update(this.ctx.service.materialBills.tableName, {
                         id: mbInfo.id,
                         id: mbInfo.id,
                         msg_tp: new_msg_tp,
                         msg_tp: new_msg_tp,
                         msg_spread: newmsg_spread,
                         msg_spread: newmsg_spread,
                         m_spread: newm_spread,
                         m_spread: newm_spread,
                         m_tp: newTp,
                         m_tp: newTp,
-                        m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), 2),
+                        m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp),
                     });
                     });
                 }
                 }
                 const m_tp = await this.ctx.service.materialBills.calcMaterialMTp(transaction);
                 const m_tp = await this.ctx.service.materialBills.calcMaterialMTp(transaction);
@@ -207,16 +207,16 @@ module.exports = app => {
                     for (const mb of mbList) {
                     for (const mb of mbList) {
                         const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                         const mb_msg_tp_sum = this._.sumBy(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp');
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
-                        const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
+                        const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), this.ctx.material.decimal.up) : null;
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
-                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
+                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), this.ctx.material.decimal.tp);
                         mbUpdateArray.push({
                         mbUpdateArray.push({
                             id: mb.id,
                             id: mb.id,
                             msg_tp: new_msg_tp,
                             msg_tp: new_msg_tp,
                             msg_spread: newmsg_spread,
                             msg_spread: newmsg_spread,
                             m_spread: newm_spread,
                             m_spread: newm_spread,
                             m_tp: newTp,
                             m_tp: newTp,
-                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
+                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), this.ctx.material.decimal.tp),
                         });
                         });
                     }
                     }
                     if (mbUpdateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, mbUpdateArray);
                     if (mbUpdateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, mbUpdateArray);

+ 7 - 6
app/service/notice_push.js

@@ -54,7 +54,7 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
-         * 查询所有推送记录
+         * 查询所有推送记录,不重复数据
          * @param {Integer} pid - 项目id
          * @param {Integer} pid - 项目id
          * @param {Integer} uid - 查询人id
          * @param {Integer} uid - 查询人id
          */
          */
@@ -63,14 +63,15 @@ module.exports = app => {
             let notice = await this.db.select(this.tableName, {
             let notice = await this.db.select(this.tableName, {
                 where: wheres,
                 where: wheres,
                 orders: [['create_time', 'desc']],
                 orders: [['create_time', 'desc']],
-                limit: 10,
+                limit: 40,
                 offset: 0
                 offset: 0
-            })
+            });
+            notice = this._.uniqBy(notice, 'content');
             notice = notice.map(v => {
             notice = notice.map(v => {
-                const extra = JSON.parse(v.content)
-                delete v.content
+                const extra = JSON.parse(v.content);
+                delete v.content;
                 return { ...v, ...extra }
                 return { ...v, ...extra }
-            })
+            });
             return notice
             return notice
         }
         }
     }
     }

+ 7 - 8
app/service/pos.js

@@ -37,14 +37,11 @@ module.exports = app => {
 
 
         async getPosDataWithAddStageOrder(condition) {
         async getPosDataWithAddStageOrder(condition) {
             if (!condition.tid) throw '查询计量单元缺少必要信息';
             if (!condition.tid) throw '查询计量单元缺少必要信息';
-            const sql = 'SELECT p.id, p.tid, p.lid, p.name, p.quantity, p.position, p.drawing_code,' +
-                '    p.sgfh_qty, p.sjcl_qty, p.qtcl_qty, p.porder, p.add_stage, p.add_times, p.add_user, s.order As add_stage_order,' +
-                '    p.sgfh_expr, p.sjcl_expr, p.qtcl_expr, p.real_qty, p.gxby_status, p.gxby_url, p.dagl_status, p.dagl_url,' +
-                '    p.gxby_limit, p.dagl_limit, p.ex_memo1, p.ex_memo2, p.ex_memo3' +
-                '  FROM ' + this.departTableName(condition.tid) + ' p ' +
-                '  LEFT JOIN ' + this.ctx.service.stage.tableName + ' s' +
-                '  ON p.add_stage = s.id'
-                + this.ctx.helper.whereSql(condition, 'p');
+            const sql = 'SELECT id, tid, lid, name, quantity, position, drawing_code,' +
+                '    sgfh_qty, sjcl_qty, qtcl_qty, porder, add_stage, add_times, add_user, add_stage_order,' +
+                '    sgfh_expr, sjcl_expr, qtcl_expr, real_qty, gxby_status, gxby_url, dagl_status, dagl_url,' +
+                '    gxby_limit, dagl_limit, ex_memo1, ex_memo2, ex_memo3' +
+                '  FROM ' + this.departTableName(condition.tid) + this.ctx.helper.whereSql(condition);
             return await this.db.query(sql);
             return await this.db.query(sql);
         }
         }
 
 
@@ -84,6 +81,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;
@@ -104,6 +102,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;

+ 53 - 3
app/service/project.js

@@ -185,14 +185,64 @@ module.exports = app => {
             return sjsField;
             return sjsField;
         }
         }
 
 
-        async updatePageshow(id, data) {
-            this.ctx.session.sessionProject.page_show.openChangeRevise = data.openChangeRevise ? 1 : 0;
-            this.ctx.session.sessionProject.page_show.openMaterialTax = data.openMaterialTax ? 1 : 0;
+        async updatePageshow(id) {
             const result = await this.db.update(this.tableName, {
             const result = await this.db.update(this.tableName, {
                 id, page_show: JSON.stringify(this.ctx.session.sessionProject.page_show),
                 id, page_show: JSON.stringify(this.ctx.session.sessionProject.page_show),
             });
             });
             return result.affectedRows === 1;
             return result.affectedRows === 1;
         }
         }
+
+        /**
+         * 校验项目是否存在(项目管理)
+         * @param {String} token - token
+         * @return {Promise} Promise
+         */
+        verifyManagementProject(token) {
+            return new Promise((resolve, reject) => {
+                this.ctx.curl(`${app.config.managementProxyPath}/api/external/jl/calibration`, {
+                    method: 'POST',
+                    // dateType: 'json',
+                    encoding: 'utf8',
+                    data: {
+                        token,
+                    },
+                    // timeout: 2000,
+                }).then(({ status, data }) => {
+                    if (status === 200) {
+                        const result = JSON.parse(data.toString()).data;
+                        return resolve(result);
+                    }
+                    return reject(new Error('校验失败'));
+                }).catch(err => {
+                    console.log(err);
+                    return reject(err);
+                });
+            });
+        }
+
+        /**
+         * 创建项目和账号(项目管理)
+         * @return {Promise} Promise
+         */
+        async addProjectFromManagement() {
+            const token = this.ctx.helper.createJWT({ account: this.ctx.session.sessionUser.account, code: this.ctx.session.sessionProject.code });
+            return new Promise((resolve, reject) => {
+                this.ctx.curl(`${app.config.managementProxyPath}/api/external/jl/project/add`, {
+                    method: 'POST',
+                    encoding: 'utf8',
+                    data: { token },
+                }).then(({ status, data }) => {
+                    if (status === 200) {
+                        const result = JSON.parse(data.toString());
+                        return resolve(result);
+                    }
+                    return reject(new Error('添加失败'));
+                }).catch(err => {
+                    console.log(err);
+                    return reject(err);
+                });
+            });
+        }
     }
     }
 
 
     return Project;
     return Project;

+ 28 - 0
app/service/project_account.js

@@ -369,6 +369,24 @@ module.exports = app => {
             return info;
             return info;
         }
         }
 
 
+        async getAccountInfoByAccountWithPid(account, project_id) {
+            if (!account || !project_id) throw new Error('参数错误');
+            this.initSqlBuilder();
+            this.sqlBuilder.columns = ['account', 'name', 'company', 'role', 'is_admin', 'enable', 'telephone', 'mobile', 'account_group'];
+            this.sqlBuilder.setAndWhere('account', {
+                operate: '=',
+                value: `"${account}"`,
+            });
+            this.sqlBuilder.setAndWhere('project_id', {
+                operate: '=',
+                value: project_id,
+            });
+
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'select');
+            const info = await this.db.queryOne(sql, sqlParam);
+
+            return info;
+        }
         async getListByProjectId(columns = '', pid) {
         async getListByProjectId(columns = '', pid) {
             this.initSqlBuilder();
             this.initSqlBuilder();
             this.sqlBuilder.columns = columns !== '' ? columns : ['id', 'account', 'name', 'company', 'role', 'mobile', 'auth_mobile', 'telephone', 'enable', 'is_admin', 'account_group'];
             this.sqlBuilder.columns = columns !== '' ? columns : ['id', 'account', 'name', 'company', 'role', 'mobile', 'auth_mobile', 'telephone', 'enable', 'is_admin', 'account_group'];
@@ -795,6 +813,16 @@ module.exports = app => {
 
 
             return result;
             return result;
         }
         }
+
+        /**
+         * 获取项目下所有账号
+         * @param {String} project_id - 项目id
+         * @return {Promise<Array>} - 账号
+         */
+        async getAllProjectAccountByPid(project_id) {
+            const sql = 'Select `account`, `name`, `company`, `role`, `mobile`, `telephone`, `is_admin` as `isAdmin`, `account_group` as `accountGroup` From ' + this.tableName + ' where project_id = ?';
+            return await this.db.query(sql, [project_id]);
+        }
     }
     }
 
 
     return ProjectAccount;
     return ProjectAccount;

+ 3 - 0
app/service/report.js

@@ -271,6 +271,9 @@ module.exports = app => {
                     case 'mem_change_bills':
                     case 'mem_change_bills':
                         rst[filter] = await service.reportMemory.getChangeBillsData(params.tender_id, params.stage_id, memFieldKeys[filter]);
                         rst[filter] = await service.reportMemory.getChangeBillsData(params.tender_id, params.stage_id, memFieldKeys[filter]);
                         break;
                         break;
+                    case 'mem_change_audit':
+                        rst[filter] = await service.reportMemory.getChangeAuditData(params.tender_id, params.stage_id, memFieldKeys[filter]);
+                        break;
                     case 'mem_jh_im_change':
                     case 'mem_jh_im_change':
                         const jhHelper1 = new rptCustomData.jhHelper(this.ctx);
                         const jhHelper1 = new rptCustomData.jhHelper(this.ctx);
                         rst[filter] = await jhHelper1.convert(params.tender_id, params.stage_id, memFieldKeys[filter], customDefine.option);
                         rst[filter] = await jhHelper1.convert(params.tender_id, params.stage_id, memFieldKeys[filter], customDefine.option);

+ 24 - 1
app/service/report_memory.js

@@ -791,6 +791,16 @@ module.exports = app => {
 
 
         }
         }
 
 
+        async _generateChangeAudit() {
+            if (!!this.changeData.audit) return;
+
+            this.changeData.audit = [];
+            for (const c of this.changeData.change) {
+                const changeAudit = await this.ctx.service.changeAudit.getListGroupByTimes(c.cid, c.times);
+                this.changeData.audit.push(...changeAudit);
+            }
+        }
+
         async getChangeData(tid, sid, fields) {
         async getChangeData(tid, sid, fields) {
             try {
             try {
                 await this.ctx.service.tender.checkTender(tid);
                 await this.ctx.service.tender.checkTender(tid);
@@ -813,6 +823,18 @@ module.exports = app => {
             }
             }
         }
         }
 
 
+        async getChangeAuditData(tid, sid, fields) {
+            try {
+                await this.ctx.service.tender.checkTender(tid);
+
+                await this._generateChange(tid);
+                await this._generateChangeAudit();
+                return this.changeData.audit;
+            } catch (err) {
+                return [];
+            }
+        }
+
         async getStageJgcl(tid, sid, fields) {
         async getStageJgcl(tid, sid, fields) {
             try {
             try {
                 await this.ctx.service.tender.checkTender(tid);
                 await this.ctx.service.tender.checkTender(tid);
@@ -982,7 +1004,7 @@ module.exports = app => {
                     const material = this.ctx.helper._.find(materials, {order: material_order});
                     const material = this.ctx.helper._.find(materials, {order: material_order});
                     if (!material) return [];
                     if (!material) return [];
                     const sql = 'SELECT m.id, m.tid, m.mid, m.t_type, m.code, m.name, m.unit, m.spec, m.m_type,' +
                     const sql = 'SELECT m.id, m.tid, m.mid, m.t_type, m.code, m.name, m.unit, m.spec, m.m_type,' +
-                        '    m.basic_price, m.basic_times, m.remark, m.in_time,' +
+                        '    m.basic_price, m.basic_times, m.remark, m.in_time, m.m_tax, m.m_tax_tp, m.tax_pre_tp,' +
                         '    mh.quantity, mh.expr, mh.msg_tp, mh.msg_times, mh.msg_spread, mh.m_up_risk, mh.m_down_risk, mh.m_spread' +
                         '    mh.quantity, mh.expr, mh.msg_tp, mh.msg_times, mh.msg_spread, mh.m_up_risk, mh.m_down_risk, mh.m_spread' +
                         '  FROM ' + this.ctx.service.materialBills.tableName + ' m' +
                         '  FROM ' + this.ctx.service.materialBills.tableName + ' m' +
                         '  LEFT JOIN ' + this.ctx.service.materialBillsHistory.tableName + ' mh' +
                         '  LEFT JOIN ' + this.ctx.service.materialBillsHistory.tableName + ' mh' +
@@ -990,6 +1012,7 @@ module.exports = app => {
                         '  WHERE mh.mid = ?';
                         '  WHERE mh.mid = ?';
                     const sqlParam = [material.id];
                     const sqlParam = [material.id];
                     result = await this.ctx.app.mysql.query(sql, sqlParam);
                     result = await this.ctx.app.mysql.query(sql, sqlParam);
+                    console.log(result);
                 }
                 }
                 this._completeMaterialGl(result);
                 this._completeMaterialGl(result);
                 return result;
                 return result;

+ 2 - 2
app/service/revise_audit.js

@@ -322,12 +322,12 @@ module.exports = app => {
             const pSql =
             const pSql =
                 'Insert Into ' +
                 'Insert Into ' +
                 this.ctx.service.pos.tableName +
                 this.ctx.service.pos.tableName +
-                '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
+                '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_stage_order, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position, ' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position, ' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                 '     gxby_status, dagl_status, gxby_url, dagl_url, gxby_limit,  dagl_limit,' +
                 '     gxby_status, dagl_status, gxby_url, dagl_url, gxby_limit,  dagl_limit,' +
                 '     ex_memo1, ex_memo2, ex_memo3)' +
                 '     ex_memo1, ex_memo2, ex_memo3)' +
-                '  Select id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
+                '  Select id, tid, lid, name, drawing_code, quantity, add_stage, add_stage_order, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
                 '     gxby_status, dagl_status, gxby_url, dagl_url, gxby_limit,  dagl_limit,' +
                 '     gxby_status, dagl_status, gxby_url, dagl_url, gxby_limit,  dagl_limit,' +

+ 2 - 2
app/service/revise_bills.js

@@ -95,7 +95,7 @@ module.exports = app => {
                 for (const p of data[i].pos) {
                 for (const p of data[i].pos) {
                     const inP = {
                     const inP = {
                         id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
                         id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
-                        add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
+                        add_stage: 0, add_stage_order: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                         name: p.name, drawing_code: p.drawing_code, porder: p.porder,
                         name: p.name, drawing_code: p.drawing_code, porder: p.porder,
                     };
                     };
                     if (p.quantity) {
                     if (p.quantity) {
@@ -195,7 +195,7 @@ module.exports = app => {
                 for (const p of data[i].pos) {
                 for (const p of data[i].pos) {
                     const inP = {
                     const inP = {
                         id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
                         id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
-                        add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
+                        add_stage: 0, add_stage_order: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                         name: p.name, drawing_code: p.drawing_code, porder: p.porder,
                         name: p.name, drawing_code: p.drawing_code, porder: p.porder,
                     };
                     };
                     if (p.quantity) {
                     if (p.quantity) {

+ 7 - 8
app/service/revise_pos.js

@@ -24,14 +24,11 @@ module.exports = app => {
         }
         }
 
 
         async getPosData(condition) {
         async getPosData(condition) {
-            const sql = 'SELECT p.id, p.tid, p.lid, p.name, p.quantity, p.position, p.drawing_code, p.sgfh_qty, ' +
-                '    p.sjcl_qty, p.qtcl_qty, p.porder, p.add_stage, p.add_times, p.add_user, s.order As add_stage_order,' +
-                '    p.sgfh_expr, p.sjcl_expr, p.qtcl_expr, p.ex_memo1, p.ex_memo2, p.ex_memo3 ' +
-                '  FROM ' + this.tableName + ' p ' +
-                '  LEFT JOIN ' + this.ctx.service.stage.tableName + ' s' +
-                '  ON add_stage = s.id'
-                + this.ctx.helper.whereSql(condition, 'p') +
-                '  ORDER By p.porder ASC';
+            const sql = 'SELECT id, tid, lid, name, quantity, position, drawing_code, sgfh_qty, ' +
+                '    sjcl_qty, qtcl_qty, porder, add_stage, add_times, add_user, add_stage_order,' +
+                '    sgfh_expr, sjcl_expr, qtcl_expr, ex_memo1, ex_memo2, ex_memo3 ' +
+                '  FROM ' + this.tableName + this.ctx.helper.whereSql(condition) +
+                '  ORDER By porder ASC';
             return await this.db.query(sql);
             return await this.db.query(sql);
         }
         }
 
 
@@ -80,6 +77,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;
@@ -97,6 +95,7 @@ module.exports = app => {
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
+            data.add_stage_order = 0;
             data.add_times = 0;
             data.add_times = 0;
             data.in_time = new Date();
             data.in_time = new Date();
             data.add_user = this.ctx.session.sessionUser.accountId;
             data.add_user = this.ctx.session.sessionUser.accountId;

+ 27 - 0
app/service/revise_price_change.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class RevisePriceChange extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'revise_price_change';
+        }
+    }
+
+    return RevisePriceChange;
+};

+ 18 - 4
app/service/stage.js

@@ -68,7 +68,7 @@ module.exports = app => {
             return result;
             return result;
         }
         }
 
 
-        async doCheckStage(stage) {
+        async doCheckStage(stage, formDataCollect = false) {
             const status = auditConst.status;
             const status = auditConst.status;
             stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times);
             stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times);
             stage.curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
             stage.curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
@@ -91,7 +91,7 @@ module.exports = app => {
                 } else {
                 } else {
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
                 }
-            } else if (this.ctx.tender && this.ctx.tender.isTourist) { // 游客
+            } else if ((this.ctx.tender && this.ctx.tender.isTourist) || formDataCollect) { // 游客
                 stage.readOnly = true;
                 stage.readOnly = true;
                 stage.curTimes = stage.times;
                 stage.curTimes = stage.times;
                 if (stage.status === status.uncheck || stage.status === status.checkNo) {
                 if (stage.status === status.uncheck || stage.status === status.checkNo) {
@@ -218,10 +218,10 @@ module.exports = app => {
             return await this.db.query(sql, sqlParam);
             return await this.db.query(sql, sqlParam);
         }
         }
 
 
-        async checkStageGatherData(stage) {
+        async checkStageGatherData(stage, formDataCollect = false) {
             // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
             // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
             if (stage.status !== auditConst.status.checked) {
             if (stage.status !== auditConst.status.checked) {
-                await this.doCheckStage(stage);
+                await this.doCheckStage(stage, formDataCollect);
                 if (!stage.readOnly && stage.check_calc) {
                 if (!stage.readOnly && stage.check_calc) {
                     const tpData = await this.ctx.service.stageBills.getSumTotalPrice(stage);
                     const tpData = await this.ctx.service.stageBills.getSumTotalPrice(stage);
                     stage.contract_tp = tpData.contract_tp;
                     stage.contract_tp = tpData.contract_tp;
@@ -693,6 +693,20 @@ module.exports = app => {
             }
             }
             return list;
             return list;
         }
         }
+
+        async getStageByDataCollect(tenderId) {
+            const stages = await this.db.select(this.tableName, {
+                columns: ['s_time', 'contract_tp', 'qc_tp', 'pre_contract_tp', 'pre_qc_tp'],
+                where: { tid: tenderId },
+                orders: [['order', 'desc']],
+            });
+            for (const s of stages) {
+                s.tp = this.ctx.helper.add(s.contract_tp, s.qc_tp);
+                s.pre_tp = this.ctx.helper.add(s.pre_contract_tp, s.pre_qc_tp);
+                s.end_tp = this.ctx.helper.add(s.pre_tp, s.tp);
+            }
+            return stages;
+        }
     }
     }
 
 
     return Stage;
     return Stage;

+ 16 - 1
app/service/stage_audit.js

@@ -17,6 +17,7 @@ const shenpiConst = require('../const/shenpi');
 const payConst = require('../const/deal_pay');
 const payConst = require('../const/deal_pay');
 const pushType = require('../const/audit').pushType;
 const pushType = require('../const/audit').pushType;
 const syncApiConst = require('../const/sync_api');
 const syncApiConst = require('../const/sync_api');
+const measureType = require('../const/tender').measureType;
 
 
 module.exports = app => {
 module.exports = app => {
     class StageAudit extends app.BaseService {
     class StageAudit extends app.BaseService {
@@ -244,6 +245,16 @@ module.exports = app => {
             return true;
             return true;
         }
         }
 
 
+        async _updateTender(transaction) {
+            if (!this.ctx.tender) return;
+            if (this.ctx.tender.data.measure_type !== measureType.gcl.value) return;
+
+            const sum = await this.ctx.service.ledger.addUp({ tender_id: this.ctx.tender.id/* , is_leaf: true*/ });
+            await transaction.update(this.ctx.service.tender.tableName, {
+                id: this.ctx.tender.id, total_price: sum.total_price, deal_tp: sum.deal_tp
+            });
+        }
+
         /**
         /**
          * 开始审批
          * 开始审批
          *
          *
@@ -263,6 +274,7 @@ module.exports = app => {
 
 
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
+                await this._updateTender(transaction);
                 await transaction.update(this.tableName, {
                 await transaction.update(this.tableName, {
                     id: audit.id,
                     id: audit.id,
                     status: auditConst.status.checking,
                     status: auditConst.status.checking,
@@ -365,6 +377,7 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
 
 
             try {
             try {
+                await this._updateTender(transaction);
                 // 添加推送
                 // 添加推送
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const auditors = await this.getAuditGroupByListWithOwner(stageId, times);
                 const auditors = await this.getAuditGroupByListWithOwner(stageId, times);
@@ -548,6 +561,7 @@ module.exports = app => {
 
 
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
+                await this._updateTender(transaction);
                 // 添加推送
                 // 添加推送
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const records = [
                 const records = [
@@ -680,6 +694,7 @@ module.exports = app => {
             const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
             const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
             const transaction = await this.db.beginTransaction();
             const transaction = await this.db.beginTransaction();
             try {
             try {
+                await this._updateTender(transaction);
                 // 添加推送
                 // 添加推送
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid);
                 const records = [
                 const records = [
@@ -1246,6 +1261,7 @@ module.exports = app => {
                     order++;
                     order++;
                 }
                 }
 
 
+                await this._updateTender(transaction);
                 // 拷贝新一次审核流程列表
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, auditors);
                 await transaction.insert(this.tableName, auditors);
 
 
@@ -1264,7 +1280,6 @@ module.exports = app => {
                 const yfPay = stagePay.find(function(x) {
                 const yfPay = stagePay.find(function(x) {
                     return x.ptype === payConst.payType.yf;
                     return x.ptype === payConst.payType.yf;
                 });
                 });
-                console.log(stagePay);
                 const sfPay = stagePay.find(function(x) {
                 const sfPay = stagePay.find(function(x) {
                     return x.ptype === payConst.payType.sf;
                     return x.ptype === payConst.payType.sf;
                 });
                 });

+ 1 - 1
app/service/stage_bills.js

@@ -110,7 +110,7 @@ module.exports = app => {
                 '  Where tid = ? and sid = ? ' + filterSql;
                 '  Where tid = ? and sid = ? ' + filterSql;
 
 
             const result = await this.db.query(sql, [tid, sid]);
             const result = await this.db.query(sql, [tid, sid]);
-            const stageBills = this.ctx.helper.filterLastestData(result, ['lid']);
+            const stageBills = this.ctx.helper.filterLastestData2(result, ['lid']);
             if (!lid || lid instanceof Array) return stageBills;
             if (!lid || lid instanceof Array) return stageBills;
             return stageBills[0];
             return stageBills[0];
         }
         }

+ 1 - 1
app/service/stage_pos.js

@@ -164,7 +164,7 @@ module.exports = app => {
             for (const d of datas) {
             for (const d of datas) {
                 const p = {
                 const p = {
                     id: this.uuid.v4(), tid: this.ctx.tender.id, lid: d.lid, name: d.name, porder: d.porder, position: d.position,
                     id: this.uuid.v4(), tid: this.ctx.tender.id, lid: d.lid, name: d.name, porder: d.porder, position: d.position,
-                    add_stage: this.ctx.stage.id,
+                    add_stage: this.ctx.stage.id, add_stage_order: this.ctx.stage.order,
                     add_times: this.ctx.stage.curTimes,
                     add_times: this.ctx.stage.curTimes,
                     add_user: this.ctx.session.sessionUser.accountId,
                     add_user: this.ctx.session.sessionUser.accountId,
                 };
                 };

+ 2 - 2
app/service/stage_shoufang.js

@@ -42,7 +42,7 @@ module.exports = app => {
                 const qr_png = await qr.image(text || '', { type: 'png', size: size || 5, margin: margin || 1 });
                 const qr_png = await qr.image(text || '', { type: 'png', size: size || 5, margin: margin || 1 });
                 const qrcodePath = 'app/public/upload/' + this.ctx.tender.id + '/stage/shoufang/qrcode/' + result.insertId + '.png';
                 const qrcodePath = 'app/public/upload/' + this.ctx.tender.id + '/stage/shoufang/qrcode/' + result.insertId + '.png';
                 // await this.ctx.helper.saveStreamFile(qr_png, path.resolve(this.app.baseDir, 'app/' + qrcodePath));
                 // await this.ctx.helper.saveStreamFile(qr_png, path.resolve(this.app.baseDir, 'app/' + qrcodePath));
-                await this.ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + qrcodePath, qr_png);
+                await this.ctx.app.fujianOss.put(this.ctx.app.config.fujianOssFolder + qrcodePath, qr_png);
                 await transaction.update(this.tableName, { id: result.insertId, qrcode: qrcodePath });
                 await transaction.update(this.tableName, { id: result.insertId, qrcode: qrcodePath });
                 await transaction.commit();
                 await transaction.commit();
                 return result;
                 return result;
@@ -72,7 +72,7 @@ module.exports = app => {
                 // if (fs.existsSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode))) {
                 // if (fs.existsSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode))) {
                 //     await fs.unlinkSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode));
                 //     await fs.unlinkSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode));
                 // }
                 // }
-                await this.ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + sfInfo.qrcode);
+                await this.ctx.app.fujianOss.delete(this.ctx.app.config.fujianOssFolder + sfInfo.qrcode);
                 await transaction.delete(this.ctx.service.stageShoufangAtt.tableName, { sfid });
                 await transaction.delete(this.ctx.service.stageShoufangAtt.tableName, { sfid });
                 await transaction.delete(this.tableName, { id: sfid });
                 await transaction.delete(this.tableName, { id: sfid });
                 await transaction.commit();
                 await transaction.commit();

+ 7 - 0
app/service/tender.js

@@ -253,6 +253,11 @@ module.exports = app => {
                 if (tender) {
                 if (tender) {
                     tender.category = tender.category && tender.category !== '' ? JSON.parse(tender.category) : null;
                     tender.category = tender.category && tender.category !== '' ? JSON.parse(tender.category) : null;
                 }
                 }
+
+                // 是否加入到决策大屏中
+                if (sessionProject.page_show.addDataCollect === 0) {
+                    await this.ctx.service.datacollectTender.add(sessionProject.id, operate.insertId);
+                }
                 return tender;
                 return tender;
             } catch (error) {
             } catch (error) {
                 await this.transaction.rollback();
                 await this.transaction.rollback();
@@ -365,6 +370,8 @@ module.exports = app => {
 
 
                 await transaction.delete(this.ctx.service.advanceFile.tableName, { tid: id });
                 await transaction.delete(this.ctx.service.advanceFile.tableName, { tid: id });
 
 
+                await transaction.delete(this.ctx.service.datacollectTender.tableName, { pid: this.ctx.session.sessionProject.id, tid: id });
+
                 // 记录删除日志
                 // 记录删除日志
                 await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.tender, projectLogConst.status.delete, tenderMsg.name, id);
                 await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.tender, projectLogConst.status.delete, tenderMsg.name, id);
                 await transaction.commit();
                 await transaction.commit();

+ 3 - 0
app/view/advance/detail.ejs

@@ -94,16 +94,19 @@
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                                 <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
                                                 <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
                                                 <small class="text-muted"><%- item.role %></small>
                                                 <small class="text-muted"><%- item.role %></small>
+                                                <span class="pull-right">原报</span>
                                             </li>
                                             </li>
                                             <% } else if(idx === auditors.length -1 && idx !== 0) { %>
                                             <% } else if(idx === auditors.length -1 && idx !== 0) { %>
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                                 <i class="fa fa fa-stop-circle"></i> <%- item.name %>
                                                 <i class="fa fa fa-stop-circle"></i> <%- item.name %>
                                                 <small class="text-muted"><%- item.role %></small>
                                                 <small class="text-muted"><%- item.role %></small>
+                                                <span class="pull-right">终审</span>
                                             </li>
                                             </li>
                                             <% } else {%>
                                             <% } else {%>
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                             <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
                                                 <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
                                                 <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
                                                 <small class="text-muted"><%- item.role %></small>
                                                 <small class="text-muted"><%- item.role %></small>
+                                                <span class="pull-right"><%- ctx.helper.transFormToChinese(idx) -%>审</span>
                                             </li>
                                             </li>
                                             <% } %>
                                             <% } %>
                                             <% }) %>
                                             <% }) %>

+ 2 - 22
app/view/budget/detail.ejs

@@ -67,31 +67,9 @@
                         </div>
                         </div>
                     </div>
                     </div>
                     <div id="std-xmj" class="tab-pane tab-select-show">
                     <div id="std-xmj" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-2">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const [i, c] of stdChapters.entries()) { %>
-                                    <option value="<%- c.id %>" <%- (i===0 ? ' selected' : '') %>><%- c.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-xmj-spread" class="sjs-sh-2">
-                        </div>
                     </div>
                     </div>
                     <% if (needGcl) { %>
                     <% if (needGcl) { %>
                     <div id="std-gcl" class="tab-pane tab-select-show">
                     <div id="std-gcl" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-3">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const [i, b] of stdBills.entries()) { %>
-                                    <option value="<%- b.id %>" <%- (i===0 ? ' selected' : '') %>><%- b.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-gcl-spread" class="sjs-sh-3">
-                        </div>
                     </div>
                     </div>
                     <% } %>
                     <% } %>
                 </div>
                 </div>
@@ -115,6 +93,8 @@
     </div>
     </div>
 </div>
 </div>
 <script>
 <script>
+    const stdChapters = JSON.parse(unescape('<%- escape(JSON.stringify(stdChapters)) %>'));
+    const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
     const readOnly = <%- ctx.budget.readOnly %>;
     const readOnly = <%- ctx.budget.readOnly %>;
     const needGcl = <%- needGcl %>;
     const needGcl = <%- needGcl %>;
     const spreadSetting = JSON.parse('<%- JSON.stringify(spreadSetting) %>');
     const spreadSetting = JSON.parse('<%- JSON.stringify(spreadSetting) %>');

+ 1 - 1
app/view/budget/list.ejs

@@ -1,7 +1,7 @@
 <div class="panel-content">
 <div class="panel-content">
     <div class="panel-title fluid">
     <div class="panel-title fluid">
         <div class="title-main  d-flex justify-content-between">
         <div class="title-main  d-flex justify-content-between">
-            <div>概算投资</div>
+            <div>动态决算</div>
             <% if (ctx.session.sessionUser.is_admin) { %>
             <% if (ctx.session.sessionUser.is_admin) { %>
             <div class="ml-auto">
             <div class="ml-auto">
                 <a href="#add-budget" name="add" data-toggle="modal" data-target="#add-budget" class="btn btn-sm btn-primary pull-right">新建项目</a>
                 <a href="#add-budget" name="add" data-toggle="modal" data-target="#add-budget" class="btn btn-sm btn-primary pull-right">新建项目</a>

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

@@ -326,7 +326,7 @@
                         </div>
                         </div>
                     </div>
                     </div>
                     <div class="tab-pane" id="bgfujian">
                     <div class="tab-pane" id="bgfujian">
-                        <div class="sjs-sh-1">
+                        <div class="sjs-sh-1" style="overflow: auto">
                             <div class="p-2">
                             <div class="p-2">
                                 <table class="table table-bordered" style="word-break:break-all; table-layout: fixed">
                                 <table class="table table-bordered" style="word-break:break-all; table-layout: fixed">
                                     <thead>
                                     <thead>

+ 0 - 0
app/view/change/revise.ejs


Some files were not shown because too many files changed in this diff