diff --git a/public/template20260226001test010.xlsx b/public/template20260226001test010.xlsx new file mode 100644 index 0000000..eb34e3d Binary files /dev/null and b/public/template20260226001test010.xlsx differ diff --git a/public/基础参数及报表导出功能.js b/public/基础参数及报表导出功能.js new file mode 100644 index 0000000..ebb8d6e --- /dev/null +++ b/public/基础参数及报表导出功能.js @@ -0,0 +1,1846 @@ +let majorList = { + 0: { ref: 'E1', name: '交通运输工程通用专业', maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 1, hasCost: FALSE, hasArea: FALSE }, + 1: { ref: 'E1-1', name: '征地(用海)补偿', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目征地(用海)补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 2, hasCost: TRUE, hasArea: TRUE }, + 2: { ref: 'E1-2', name: '拆迁补偿', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于交通建设项目拆迁补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 3, hasCost: TRUE, hasArea: TRUE }, + 3: { ref: 'E1-3', name: '迁改工程', maxCoe: null, minCoe: null, defCoe: 2, desc: '适用于交通建设项目迁改工程的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 4, hasCost: TRUE, hasArea: FALSE }, + 4: { ref: 'E1-4', name: '工程建设其他费', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目的工程建设其他费的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 5, hasCost: TRUE, hasArea: FALSE }, + 5: { ref: 'E1-5', name: '预备费', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 6, hasCost: TRUE, hasArea: FALSE }, + 6: { ref: 'E1-6', name: '建设期贷款利息', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, order: 7, hasCost: TRUE, hasArea: FALSE }, + 7: { ref: 'E2', name: '公路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于公路工程的全过程造价咨询、分阶段造价咨询、投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 8, hasCost: FALSE, hasArea: FALSE }, + 8: { ref: 'E2-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 9, hasCost: TRUE, hasArea: FALSE }, + 9: { ref: 'E2-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 10, hasCost: TRUE, hasArea: FALSE }, + 10: { ref: 'E2-3', name: '路面工程', maxCoe: null, minCoe: null, defCoe: 0.8, desc: '适用于路面工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 11, hasCost: TRUE, hasArea: FALSE }, + 11: { ref: 'E2-4', name: '桥涵工程', maxCoe: null, minCoe: null, defCoe: 0.9, desc: '适用于桥梁涵洞工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 12, hasCost: TRUE, hasArea: FALSE }, + 12: { ref: 'E2-5', name: '隧道工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于隧道工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 13, hasCost: TRUE, hasArea: FALSE }, + 13: { ref: 'E2-6', name: '交叉工程', maxCoe: null, minCoe: null, defCoe: 1.1, desc: '适用于交叉工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 14, hasCost: TRUE, hasArea: FALSE }, + 14: { ref: 'E2-7', name: '机电工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于机电工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 15, hasCost: TRUE, hasArea: FALSE }, + 15: { ref: 'E2-8', name: '交通安全设施工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于交通安全设施工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 16, hasCost: TRUE, hasArea: FALSE }, + 16: { ref: 'E2-9', name: '绿化及环境保护工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于绿化工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 17, hasCost: TRUE, hasArea: FALSE }, + 17: { ref: 'E2-10', name: '房建工程', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: TRUE, isRailway: FALSE, isWaterway: FALSE, order: 18, hasCost: TRUE, hasArea: FALSE }, + 18: { ref: 'E3', name: '铁路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于铁路工程的投资估算、初步设计概算、清理概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 19, hasCost: FALSE, hasArea: FALSE }, + 19: { ref: 'E3-1', name: '大型临时设施和过渡工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于大型临时设施和过渡工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 20, hasCost: TRUE, hasArea: FALSE }, + 20: { ref: 'E3-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 21, hasCost: TRUE, hasArea: FALSE }, + 21: { ref: 'E3-3', name: '桥涵工程', maxCoe: null, minCoe: null, defCoe: 0.9, desc: '适用于桥涵工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 22, hasCost: TRUE, hasArea: FALSE }, + 22: { ref: 'E3-4', name: '隧道及明洞工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于隧道及明洞工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 23, hasCost: TRUE, hasArea: FALSE }, + 23: { ref: 'E3-5', name: '轨道工程', maxCoe: null, minCoe: null, defCoe: 0.3, desc: '适用于轨道工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 24, hasCost: TRUE, hasArea: FALSE }, + 24: { ref: 'E3-6', name: '通信、信号、信息及灾害监测工程', maxCoe: null, minCoe: null, defCoe: 2, desc: '适用于通信、信号、信息及防灾监测工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 25, hasCost: TRUE, hasArea: FALSE }, + 25: { ref: 'E3-7', name: '电力及电力牵引供电工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于电力及电力牵引供电工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 26, hasCost: TRUE, hasArea: FALSE }, + 26: { ref: 'E3-8', name: '房建工程(房屋建筑及附属工程)', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房屋建筑及附属工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 27, hasCost: TRUE, hasArea: FALSE }, + 27: { ref: 'E3-9', name: '装饰装修工程', maxCoe: null, minCoe: null, defCoe: 2.7, desc: '适用于装饰装修工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, order: 28, hasCost: TRUE, hasArea: FALSE }, + 28: { ref: 'E4', name: '水运工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于水运工程的投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 29, hasCost: FALSE, hasArea: FALSE }, + 29: { ref: 'E4-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1.1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 30, hasCost: TRUE, hasArea: FALSE }, + 30: { ref: 'E4-2', name: '土建工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于土建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 31, hasCost: TRUE, hasArea: FALSE }, + 31: { ref: 'E4-3', name: '机电与金属结构工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于机电与金属结构专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 32, hasCost: TRUE, hasArea: FALSE }, + 32: { ref: 'E4-4', name: '设备工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于设备工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 33, hasCost: TRUE, hasArea: FALSE }, + 33: { ref: 'E4-5', name: '附属房建工程(房屋建筑及附属工程)', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房屋建筑与水运附属工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: FALSE, isRailway: FALSE, isWaterway: TRUE, order: 34, hasCost: TRUE, hasArea: FALSE }, +}; + +let serviceList = { + 0: { ref: 'D1', name: '全过程造价咨询', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 1, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 1: { ref: 'D2', name: '分阶段造价咨询', maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 2, scale: null, onlyCostScale: null, amount: null, workDay: null }, + 2: { ref: 'D2-1', name: '前期阶段造价咨询', maxCoe: null, minCoe: null, defCoe: 0.5, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 3, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 3: { ref: 'D2-2-1', name: '实施阶段造价咨询(公路、水运)', maxCoe: null, minCoe: null, defCoe: 0.55, desc: '本系数适用于公路和水运工程。', isRoad: TRUE, isRailway: FALSE, isWaterway: TRUE, mutiple: FALSE, order: 4, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 4: { ref: 'D2-2-2', name: '实施阶段造价咨询(铁路)', maxCoe: null, minCoe: null, defCoe: 0.6, desc: '本系数适用于铁路工程。', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, mutiple: FALSE, order: 5, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 5: { ref: 'D3', name: '基本造价咨询', maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 6, scale: null, onlyCostScale: null, amount: null, workDay: null }, + 6: { ref: 'D3-1', name: '投资估算', maxCoe: null, minCoe: null, defCoe: 0.1, desc: '委托同一咨询人同时负责D3-1和D3-2时,D3-1和D3-2的合计调整系数为0.25。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 7, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 7: { ref: 'D3-2', name: '设计概算', maxCoe: null, minCoe: null, defCoe: 0.2, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 8, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 8: { ref: 'D3-3', name: '施工图预算', maxCoe: null, minCoe: null, defCoe: 0.25, desc: '委托同一咨询人同时负责D3-3和D3-4时,D3-3和D3-4的合计调整系数为0.3。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 9, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 9: { ref: 'D3-4', name: '招标工程量清单及清单预算(或最高投标限价)', maxCoe: null, minCoe: null, defCoe: 0.15, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 10, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 10: { ref: 'D3-5', name: '清理概算(仅限铁路)', maxCoe: null, minCoe: null, defCoe: 0.2, desc: '本系数适用于铁路工程。', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, mutiple: FALSE, order: 11, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 11: { ref: 'D3-6-1', name: '合同(工程)结算', maxCoe: null, minCoe: null, defCoe: 0.3, desc: '本系数适用于公路和水运工程。', isRoad: TRUE, isRailway: FALSE, isWaterway: TRUE, mutiple: FALSE, order: 12, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 12: { ref: 'D3-6-2', name: '合同(工程)结算', maxCoe: null, minCoe: null, defCoe: 0.2, desc: '本系数适用于铁路工程。', isRoad: FALSE, isRailway: TRUE, isWaterway: FALSE, mutiple: FALSE, order: 13, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 13: { ref: 'D3-7', name: '竣工决算', maxCoe: null, minCoe: null, defCoe: 0.1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 14, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 14: { ref: 'D4', name: '专项造价咨询', maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 15, scale: null, onlyCostScale: null, amount: null, workDay: null }, + 15: { ref: 'D4-1', name: '工程造价顾问', maxCoe: null, minCoe: null, defCoe: 1, desc: '本表系数适用于采用工作量计价法基准预算的调整系数。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 16, scale: FALSE, onlyCostScale: null, amount: TRUE, workDay: TRUE }, + 16: { ref: 'D4-2', name: '造价政策制(修)订', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 17, scale: FALSE, onlyCostScale: null, amount: TRUE, workDay: TRUE }, + 17: { ref: 'D4-3', name: '造价科学与技术研究', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 18, scale: FALSE, onlyCostScale: null, amount: TRUE, workDay: TRUE }, + 18: { ref: 'D4-4', name: '定额测定', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 19, scale: FALSE, onlyCostScale: null, amount: TRUE, workDay: TRUE }, + 19: { ref: 'D4-5', name: '造价信息咨询', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 20, scale: FALSE, onlyCostScale: null, amount: TRUE, workDay: TRUE }, + 20: { ref: 'D4-6', name: '造价鉴定', maxCoe: null, minCoe: null, defCoe: 0.5, desc: '本表系数适用于采用规模计价法基准预算的调整系数。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 21, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 21: { ref: 'D4-7', name: '工程成本测算', maxCoe: null, minCoe: null, defCoe: 0.1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 22, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 22: { ref: 'D4-8', name: '工程成本核算', maxCoe: null, minCoe: null, defCoe: 0.1, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 23, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 23: { ref: 'D4-9', name: '计算工程量', maxCoe: null, minCoe: null, defCoe: 0.2, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 24, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 24: { ref: 'D4-10', name: '工程变更费用咨询', maxCoe: null, minCoe: null, defCoe: 0.5, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 25, scale: TRUE, onlyCostScale: FALSE, amount: FALSE, workDay: TRUE }, + 25: { ref: 'D4-11', name: '调整估算', maxCoe: 0.2, minCoe: 0.1, defCoe: 0.15, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 26, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 26: { ref: 'D4-12', name: '调整概算', maxCoe: 0.3, minCoe: 0.15, defCoe: 0.225, desc: '本表系数适用于采用规模计价法基准预算的系数;依据其调整时期所在建设阶段和基础资料的不同,其系数取值不同。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 27, scale: TRUE, onlyCostScale: TRUE, amount: FALSE, workDay: TRUE }, + 27: { ref: 'D4-13', name: '造价检查', maxCoe: null, minCoe: null, defCoe: null, desc: '可按照服务工日数量×服务工日人工单价×综合预算系数;也可按照服务工日数量×服务工日综合预算单价。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 28, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 28: { ref: 'D4-14', name: '其他专项咨询', maxCoe: null, minCoe: null, defCoe: null, desc: '可参照相同或相似服务的系数。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 29, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 29: { ref: 'D4-15-1', name: '造价数据测试验证(估算)', maxCoe: null, minCoe: null, defCoe: 0.04, desc: '委托同一咨询人同时负责D3-1和D3-2时,D3-1和D3-2的合计调整系数为0.25。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 30, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 30: { ref: 'D4-15-2', name: '造价数据测试验证(概算)', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 31, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 31: { ref: 'D4-15-3', name: '造价数据测试验证(施工图预算)', maxCoe: null, minCoe: null, defCoe: 0.1, desc: '委托同一咨询人同时负责D3-3和D3-4时,D3-3和D3-4的合计调整系数为0.3。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 32, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 32: { ref: 'D4-15-4', name: '造价数据测试验证(招标工程量清单及清单预算(或最高投标限价))', maxCoe: null, minCoe: null, defCoe: 0.06, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 33, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 33: { ref: 'D4-15-5', name: '造价数据测试验证(清理概算(仅限铁路))', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '本系数适用于铁路工程。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 34, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 34: { ref: 'D4-15-6', name: '造价数据测试验证(合同(工程)结算)', maxCoe: null, minCoe: null, defCoe: 0.12, desc: '本系数适用于公路和水运工程。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 35, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 35: { ref: 'D4-15-7', name: '造价数据测试验证(合同(工程)结算)', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '本系数适用于铁路工程。', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 36, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, + 36: { ref: 'D4-15-8', name: '造价数据测试验证(竣工决算)', maxCoe: null, minCoe: null, defCoe: 0.04, desc: '', isRoad: TRUE, isRailway: TRUE, isWaterway: TRUE, mutiple: FALSE, order: 37, scale: FALSE, onlyCostScale: null, amount: FALSE, workDay: TRUE }, +}; + +let taskList = { + 0: { serviceID: 15, ref: 'C4-1', name: '工程造价日常顾问', basicParam: '服务月份数', required: TRUE, unit: '万元/月', conversion: 10000, maxPrice: 0.5, minPrice: 0.3, defPrice: 0.4, desc: '' }, + 1: { serviceID: 15, ref: 'C4-2', name: '工程造价专项顾问', basicParam: '服务项目的造价金额', required: TRUE, unit: '%', conversion: 0.01, maxPrice: null, minPrice: null, defPrice: 0.01, desc: '适用于涉及造价费用类的顾问' }, + 2: { serviceID: 16, ref: 'C5-1', name: '组织与调研工作', basicParam: '调研次数', required: TRUE, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' }, + 3: { serviceID: 16, ref: 'C5-2-1', name: '文件编写工作', basicParam: '文件份数', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 5, minPrice: 3, defPrice: 4, desc: '主编' }, + 4: { serviceID: 16, ref: 'C5-2-2', name: '文件编写工作', basicParam: '文件份数', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '参编' }, + 5: { serviceID: 16, ref: 'C5-3-1', name: '评审工作', basicParam: '评审次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' }, + 6: { serviceID: 16, ref: 'C5-3-2', name: '评审工作', basicParam: '评审次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' }, + 7: { serviceID: 16, ref: 'C5-3-3', name: '评审工作', basicParam: '评审次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' }, + 8: { serviceID: 17, ref: 'C6-1', name: '组织与调研工作', basicParam: '调研次数', required: TRUE, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' }, + 9: { serviceID: 17, ref: 'C6-2-1', name: '研究及编写报告', basicParam: '文件份数', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 50, minPrice: 20, defPrice: 35, desc: '国家级' }, + 10: { serviceID: 17, ref: 'C6-2-2', name: '研究及编写报告', basicParam: '文件份数', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 20, minPrice: 10, defPrice: 15, desc: '省部级' }, + 11: { serviceID: 17, ref: 'C6-2-3', name: '研究及编写报告', basicParam: '文件份数', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '其他级' }, + 12: { serviceID: 17, ref: 'C6-3-1', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 80, minPrice: 50, defPrice: 65, desc: '复杂标准' }, + 13: { serviceID: 17, ref: 'C6-3-2', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 50, minPrice: 20, defPrice: 35, desc: '较复杂标准' }, + 14: { serviceID: 17, ref: 'C6-3-3', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 20, minPrice: 10, defPrice: 15, desc: '一般标准' }, + 15: { serviceID: 17, ref: 'C6-3-4', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '简单标准' }, + 16: { serviceID: 17, ref: 'C6-4-1', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' }, + 17: { serviceID: 17, ref: 'C6-4-2', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' }, + 18: { serviceID: 17, ref: 'C6-4-3', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' }, + 19: { serviceID: 17, ref: 'C6-5-1', name: '培训与宣贯工作', basicParam: '项目数量', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '培训与宣贯材料' }, + 20: { serviceID: 17, ref: 'C6-5-2', name: '培训与宣贯工作', basicParam: '培训与宣贯次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '组织培训与宣贯' }, + 21: { serviceID: 18, ref: 'C7-1', name: '组织与调研工作', basicParam: '调研次数', required: TRUE, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' }, + 22: { serviceID: 18, ref: 'C7-2', name: '编制大纲', basicParam: '项目数量', required: TRUE, unit: '万元/个', conversion: 10000, maxPrice: 3, minPrice: 2, defPrice: 2.5, desc: '包括技术与定额子目研究' }, + 23: { serviceID: 18, ref: 'C7-3', name: '数据采集与测定', basicParam: '采集组数', required: TRUE, unit: '万元/组', conversion: 10000, maxPrice: 0.8, minPrice: 0.2, defPrice: 0.5, desc: '现场采集方式时计' }, + 24: { serviceID: 18, ref: 'C7-4-1', name: '数据整理与分析', basicParam: '定额子目条数', required: TRUE, unit: '万元/条', conversion: 10000, maxPrice: 0.3, minPrice: 0.1, defPrice: 0.2, desc: '简单定额' }, + 25: { serviceID: 18, ref: 'C7-4-2', name: '数据整理与分析', basicParam: '定额子目条数', required: TRUE, unit: '万元/条', conversion: 10000, maxPrice: 3, minPrice: 0.3, defPrice: 1.65, desc: '复杂定额' }, + 26: { serviceID: 18, ref: 'C7-5', name: '编写定额测定报告', basicParam: '项目数量', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 5, minPrice: 2, defPrice: 3.5, desc: '' }, + 27: { serviceID: 18, ref: 'C7-6-1', name: '编制定额文本和释义', basicParam: '基本费用', required: TRUE, unit: '万元/份', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '20条定额子目内' }, + 28: { serviceID: 18, ref: 'C7-6-2', name: '编制定额文本和释义', basicParam: '定额子目条数', required: TRUE, unit: '万元/条', conversion: 10000, maxPrice: 0.2, minPrice: 0.1, defPrice: 0.15, desc: '超过20条每增加1条' }, + 29: { serviceID: 18, ref: 'C7-7-1', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' }, + 30: { serviceID: 18, ref: 'C7-7-2', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' }, + 31: { serviceID: 18, ref: 'C7-7-3', name: '评审与验收工作', basicParam: '评审与验收次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' }, + 32: { serviceID: 18, ref: 'C7-8-1', name: '培训与宣贯工作', basicParam: '项目数量', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '培训与宣贯材料' }, + 33: { serviceID: 18, ref: 'C7-8-2', name: '培训与宣贯工作', basicParam: '培训与宣贯次数', required: FALSE, unit: '万元/次', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '组织培训与宣贯' }, + 34: { serviceID: 19, ref: 'C8-1', name: 'Q≤10条', basicParam: '价格信息数量', required: TRUE, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 500, desc: '' }, + 35: { serviceID: 19, ref: 'C8-2', name: '10条100条', basicParam: '价格信息数量', required: TRUE, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 100, desc: '' }, +}; + +let expertList = { + 0: { ref: 'C9-1-1', name: '技术员及其他', maxPrice: 800, minPrice: 600, defPrice: 700, manageCoe: 2.3 }, + 1: { ref: 'C9-1-2', name: '助理工程师', maxPrice: 1000, minPrice: 800, defPrice: 900, manageCoe: 2.3 }, + 2: { ref: 'C9-1-3', name: '中级工程师或二级造价工程师', maxPrice: 1500, minPrice: 1000, defPrice: 1250, manageCoe: 2.2 }, + 3: { ref: 'C9-1-4', name: '高级工程师或一级造价工程师', maxPrice: 1800, minPrice: 1500, defPrice: 1650, manageCoe: 2.1 }, + 4: { ref: 'C9-1-5', name: '正高级工程师或资深专家', maxPrice: 2500, minPrice: 2000, defPrice: 2250, manageCoe: 2 }, + 5: { ref: 'C9-2-1', name: '二级造价工程师且具备中级工程师资格', maxPrice: 1500, minPrice: 1200, defPrice: 1350, manageCoe: 2.2 }, + 6: { ref: 'C9-3-1', name: '一级造价工程师且具备中级工程师资格', maxPrice: 1800, minPrice: 1500, defPrice: 1650, manageCoe: 2.1 }, + 7: { ref: 'C9-3-2', name: '一级造价工程师且具备高级工程师资格', maxPrice: 2000, minPrice: 1800, defPrice: 1900, manageCoe: 2.05 }, +}; + +let costScaleCal = [ + { ref: 'C1-1', staLine: 0, endLine: 100, basic: { staPrice: 0, rate: 0.01 }, optional: { staPrice: 0, rate: 0.002 } }, + { ref: 'C1-2', staLine: 100, endLine: 300, basic: { staPrice: 10000, rate: 0.008 }, optional: { staPrice: 2000, rate: 0.0016 } }, + { ref: 'C1-3', staLine: 300, endLine: 500, basic: { staPrice: 26000, rate: 0.005 }, optional: { staPrice: 5200, rate: 0.001 } }, + { ref: 'C1-4', staLine: 500, endLine: 1000, basic: { staPrice: 36000, rate: 0.004 }, optional: { staPrice: 7200, rate: 0.0008 } }, + { ref: 'C1-5', staLine: 1000, endLine: 5000, basic: { staPrice: 56000, rate: 0.003 }, optional: { staPrice: 11200, rate: 0.0006 } }, + { ref: 'C1-6', staLine: 5000, endLine: 10000, basic: { staPrice: 176000, rate: 0.002 }, optional: { staPrice: 35200, rate: 0.0004 } }, + { ref: 'C1-7', staLine: 10000, endLine: 30000, basic: { staPrice: 276000, rate: 0.0016 }, optional: { staPrice: 55200, rate: 0.00032 } }, + { ref: 'C1-8', staLine: 30000, endLine: 50000, basic: { staPrice: 596000, rate: 0.0013 }, optional: { staPrice: 119200, rate: 0.00026 } }, + { ref: 'C1-9', staLine: 50000, endLine: 100000, basic: { staPrice: 856000, rate: 0.001 }, optional: { staPrice: 171200, rate: 0.0002 } }, + { ref: 'C1-10', staLine: 100000, endLine: 150000, basic: { staPrice: 1356000, rate: 0.0009 }, optional: { staPrice: 271200, rate: 0.00018 } }, + { ref: 'C1-11', staLine: 150000, endLine: 200000, basic: { staPrice: 1806000, rate: 0.0008 }, optional: { staPrice: 361200, rate: 0.00016 } }, + { ref: 'C1-12', staLine: 200000, endLine: 300000, basic: { staPrice: 2206000, rate: 0.0007 }, optional: { staPrice: 441200, rate: 0.00014 } }, + { ref: 'C1-13', staLine: 300000, endLine: 400000, basic: { staPrice: 2906000, rate: 0.0006 }, optional: { staPrice: 581200, rate: 0.00012 } }, + { ref: 'C1-14', staLine: 400000, endLine: 600000, basic: { staPrice: 3506000, rate: 0.0005 }, optional: { staPrice: 701200, rate: 0.0001 } }, + { ref: 'C1-15', staLine: 600000, endLine: 800000, basic: { staPrice: 4506000, rate: 0.0004 }, optional: { staPrice: 901200, rate: 0.00008 } }, + { ref: 'C1-16', staLine: 800000, endLine: 1000000, basic: { staPrice: 5306000, rate: 0.0003 }, optional: { staPrice: 1061200, rate: 0.00006 } }, + { ref: 'C1-17', staLine: 1000000, endLine: null, basic: { staPrice: 5906000, rate: 0.00025 }, optional: { staPrice: 1181200, rate: 0.00005 } }, +]; + +let areaScaleCal = [ + { ref: 'C2-1', staLine: 0, endLine: 50, basic: { staPrice: 0, rate: 200 }, optional: { staPrice: 0, rate: 40 } }, + { ref: 'C2-2', staLine: 50, endLine: 100, basic: { staPrice: 10000, rate: 160 }, optional: { staPrice: 2000, rate: 32 } }, + { ref: 'C2-3', staLine: 100, endLine: 500, basic: { staPrice: 18000, rate: 120 }, optional: { staPrice: 3600, rate: 24 } }, + { ref: 'C2-4', staLine: 500, endLine: 1000, basic: { staPrice: 66000, rate: 80 }, optional: { staPrice: 13200, rate: 16 } }, + { ref: 'C2-5', staLine: 1000, endLine: 5000, basic: { staPrice: 106000, rate: 60 }, optional: { staPrice: 21200, rate: 12 } }, + { ref: 'C2-6', staLine: 5000, endLine: null, basic: { staPrice: 346000, rate: 20 }, optional: { staPrice: 69200, rate: 4 } }, +]; + +function getBasicFeeFromScale(scaleValue, scaleType) { + let sv = Number(scaleValue); + if (isNaN(sv)) return null; + if (sv <= 0) return null; + let targetRange; + let res; + switch (scaleType) { + case 'cost': + targetRange = costScaleCal.find(f => f.staLine < sv && (sv <= f.endLine || f.endLine === null)); + res = { + basic: Math.round((targetRange.basic.staPrice + (sv - targetRange.staLine) * 10000 * targetRange.basic.rate) * 100) / 100, + optional: Math.round((targetRange.optional.staPrice + (sv - targetRange.staLine) * 10000 * targetRange.optional.rate) * 100) / 100, + basicFormula: targetRange.basic.staPrice ? `${numberFormatter(targetRange.basic.staPrice, 0)}+(${numberFormatter(sv * 10000, 0)}-${numberFormatter(targetRange.staLine * 10000, 0)})×${Math.round(targetRange.basic.rate * 1000 * 100) / 100}‰` : `${numberFormatter(sv * 10000, 0)}×${Math.round(targetRange.basic.rate * 1000 * 100) / 100}‰`, + optionalFormula: targetRange.optional.staPrice ? `${numberFormatter(targetRange.optional.staPrice, 0)}+(${numberFormatter(sv * 10000, 0)}-${numberFormatter(targetRange.staLine * 10000, 0)})×${Math.round(targetRange.optional.rate * 1000 * 100) / 100}‰` : `${numberFormatter(sv * 10000, 0)}×${Math.round(targetRange.optional.rate * 1000 * 100) / 100}‰`, + }; + break; + case 'area': + targetRange = areaScaleCal.find(f => f.staLine < sv && (sv <= f.endLine || f.endLine === null)); + res = { + basic: Math.round((targetRange.basic.staPrice + (sv - targetRange.staLine) * targetRange.basic.rate) * 100) / 100, + optional: Math.round((targetRange.optional.staPrice + (sv - targetRange.staLine) * targetRange.optional.rate) * 100) / 100, + basicFormula: targetRange.basic.staPrice ? `${numberFormatter(targetRange.basic.staPrice, 0)}+(${numberFormatter(sv, 0)}-${numberFormatter(targetRange.staLine, 0)})×${targetRange.basic.rate}` : `${numberFormatter(sv, 0)}×${targetRange.basic.rate}`, + optionalFormula: targetRange.optional.staPrice ? `${numberFormatter(targetRange.optional.staPrice, 0)}+(${numberFormatter(sv, 0)}-${numberFormatter(targetRange.staLine, 0)})×${targetRange.optional.rate}` : `${numberFormatter(sv, 0)}×${targetRange.optional.rate}`, + }; + break; + } + return res; +} + +let data1 = { + name: 'test001', + writer: '张三',// 编制人 + reviewer: '李四',// 复核人 + date: '2021-09-24',// 编制日期 + industry: 0,// 0为公路工程,1为铁路工程,2为水运工程 + fee: 10000, + scaleCost: 100000,// scale的cost的合计数 + scale: [// 规模信息 + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + serviceCoes: [// 项目咨询分类系数 + { + serviceid: 0, + coe: 1.1, + remark: '',// 用户输入的说明 + }, + { + serviceid: 1, + coe: 1.2, + remark: '',// 用户输入的说明 + }, + ], + majorCoes: [// 项目工程专业系数 + { + majorid: 0, + coe: 1.1, + remark: '',// 用户输入的说明 + }, + { + majorid: 1, + coe: 1.2, + remark: '',// 用户输入的说明 + }, + ], + contracts: [// 合同段信息 + { + name: 'A合同段', + serviceFee: 100000, + addtionalFee: 0, + reserveFee: 0, + fee: 10000, + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + serviceCoes: [// 合同段咨询分类系数 + { + serviceid: 0, + coe: 1.1, + remark: '',// 用户输入的说明 + }, + { + serviceid: 1, + coe: 1.2, + remark: '',// 用户输入的说明 + }, + ], + majorCoes: [// 合同段工程专业系数 + { + majorid: 0, + coe: 1.1, + remark: '',// 用户输入的说明 + }, + { + majorid: 1, + coe: 1.2, + remark: '',// 用户输入的说明 + }, + ], + services: [ + { + id: 0, + fee: 100000, + process: 0,// 工作环节,0为编制,1为审核 + method1: { // 投资规模法 + cost: 100000, + basicFee: 200, + basicFee_basic: 200, + basicFee_optional: 0, + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + basicFormula: '856,000+(1,000,000,000-500,000,000)×1‰', + basicFee_basic: 200, + optionalFormula: '171,200+(1,000,000,000-500,000,000)×0.2‰', + basicFee_optional: 0, + serviceCoe: 1.1, + majorCoe: 1.2, + processCoe: 1,// 工作环节系数(编审系数) + proportion: 0.5,// 工作占比 + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + method2: { // 用地规模法 + area: 1200, + basicFee: 200, + basicFee_basic: 200, + basicFee_optional: 0, + fee: 250000, + det: [ + { + major: 0, + area: 1200, + basicFee: 200, + basicFormula: '106,000+(1,200-1,000)×60', + basicFee_basic: 200, + optionalFormula: '21,200+(1,200-1,000)×12', + basicFee_optional: 0, + serviceCoe: 1.1, + majorCoe: 1.2, + processCoe: 1,// 工作环节系数(编审系数) + proportion: 0.5,// 工作占比 + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + method3: { // 工作量法 + basicFee: 200, + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + method4: { // 工时法 + person_num: 10, + work_day: 10, + fee: 250000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + }, + ], + addtional: [// 附加工作费 + { + type: 0,// 0为费率计取,1为工时法,2为数量单价 + coe: 0.03, + fee: 10000, + }, + { + type: 1,// 0为费率计取,1为工时法,2为数量单价 + fee: 10000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + { + type: 2,// 0为费率计取,1为工时法,2为数量单价 + fee: 10000, + det: [ + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + } + ], + reserve: [// 预留费 + { + type: 0,// 0为费率计取,1为工时法,2为数量单价 + coe: 0.03, + fee: 10000, + }, + { + type: 1,// 0为费率计取,1为工时法,2为数量单价 + fee: 10000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + { + type: 2,// 0为费率计取,1为工时法,2为数量单价 + fee: 10000, + det: [ + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + } + ], + }, + ], +}; +let data2 = { + name: 'test001', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + contracts: [ + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + }, + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method3: { // 工作量法 + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + ], + }, + }, + ], + }, + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + }, + ], + }, + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + }, + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method3: { // 工作量法 + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + ], + }, + }, + ], + }, + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + }, + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method3: { // 工作量法 + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + ], + }, + }, + ], + }, + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + }, + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method3: { // 工作量法 + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + ], + }, + }, + ], + }, + { + name: 'A合同段', + scale: [ + { + major: 0, + cost: 100000, + area: 200, + }, + { + major: 1, + cost: 100000, + area: 200, + }, + ], + services: [ + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + }, + { + id: 0, + method1: { // 投资规模法 + fee: 250000, + det: [ + { + major: 0, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + cost: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method2: { // 用地规模法 + fee: 250000, + det: [ + { + major: 0, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + { + major: 1, + area: 100000, + basicFee: 200, + serviceCoe: 1.1, + majorCoe: 1.2, + fee: 100000, + desc: '', + }, + ], + }, + method3: { // 工作量法 + fee: 250000, + det: [ + { + task: 0, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + { + task: 1, + price: 100000, + amount: 10, + basicFee: 200, + serviceCoe: 1.1, + fee: 100000, + desc: '', + }, + ], + }, + }, + ], + }, + ], +}; + +async function exportFile(fileName, data) { + if (window.showSaveFilePicker) { + const handle = await window.showSaveFilePicker({ + suggestedName: fileName, + types: [{ + description: "Excel 文件", + accept: { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"] } + }] + }); + // ecCom.WeaLoadingGlobal.start({ + // tip: "下载中,结束前请勿打开文件...", + // }); + try { + const workbook = await generateTemplate(data); + const buffer = await workbook.xlsx.writeBuffer(); + const writable = await handle.createWritable(); + await writable.write(buffer); + await writable.close(); + // ecCom.WeaLoadingGlobal.destroy(); + // antd.notification['success']({ + // message: '下载成功!', + // }); + } catch (err) { + console.log('err:' + err); + // ecCom.WeaLoadingGlobal.destroy(); + // antd.notification['error']({ + // message: '下载失败!', + // }); + } + } else { + const workbook = await generateTemplate(data); + const buffer = await workbook.xlsx.writeBuffer(); + const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + const url1 = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url1; + a.download = `${fileName}.xlsx`; + a.click(); + URL.revokeObjectURL(url1); + } +} + +async function generateTemplate(data) { + // 获取模板 + let templateExcel = 'template20260226001test010'; + let templateUrl = `/myExcelTemplate/${templateExcel}.xlsx`; + let buf = await (await fetch(templateUrl)).arrayBuffer(); + let workbook = new ExcelJS.Workbook(); + await workbook.xlsx.load(buf); + + // 生成表格 + let fm_sheet = workbook.getWorksheet('封面'); + let ml_sheet = workbook.getWorksheet('目录'); + let yz01_sheet = workbook.getWorksheet('预总01表'); + let f01_sheet = workbook.getWorksheet('辅01表'); + + let now = new Date(); + let year = now.getFullYear(); + let month = now.getMonth() + 1; + let day = now.getDate(); + + fm_sheet.getRow(2).getCell(1).value = data.name; + fm_sheet.getRow(11).getCell(4).value = `${year} 年 ${month} 月 ${day} 日`; + + let yz01Mod = (data.contracts.length + 1) % 4; + let yz01Num = (data.contracts.length + 1 - yz01Mod) / 4; + switch (yz01Mod) { + case 0: + yz01_sheet.spliceColumns(8, 15); + break; + case 1: + yz01_sheet.spliceColumns(8, 11); + break; + case 2: + yz01_sheet.spliceColumns(19, 4); + yz01_sheet.spliceColumns(8, 6); + break; + case 3: + yz01_sheet.spliceColumns(14, 9); + break; + } + if (yz01Num == 0) { + yz01_sheet.spliceColumns(1, 7); + } else { + if (yz01Num > 1) { + for (let i = 0; i < yz01Num - 1; i++) { + insertAndCopyColumn(7 * (i + 1) + 1, [1, 2, 3, 4, 5, 6, 7], yz01_sheet); + } + } + } + + let f01Mod = (data.contracts.length) % 3; + let f01Num = (data.contracts.length - f01Mod) / 3; + switch (f01Mod) { + case 0: + f01_sheet.spliceColumns(11, 14); + break; + case 1: + f01_sheet.spliceColumns(11, 8); + break; + case 2: + f01_sheet.spliceColumns(19, 6); + break; + } + if (f01Num == 0) { + f01_sheet.spliceColumns(1, 10); + } else { + if (f01Num > 1) { + for (let i = 0; i < f01Num - 1; i++) { + insertAndCopyColumn(10 * (i + 1) + 1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], f01_sheet); + } + } + for (let i = 0; i < f01Num; i++) { + f01_sheet.mergeCells(1, i * 10 + 1, 2, i * 10 + 1); + f01_sheet.mergeCells(1, i * 10 + 2, 2, i * 10 + 2); + f01_sheet.mergeCells(1, i * 10 + 3, 2, i * 10 + 3); + f01_sheet.mergeCells(1, i * 10 + 10, 2, i * 10 + 10); + f01_sheet.mergeCells(1, i * 10 + 4, 1, i * 10 + 5); + f01_sheet.getRow(1).getCell(i * 10 + 4).value = data.contracts[i * 3].name; + f01_sheet.mergeCells(1, i * 10 + 6, 1, i * 10 + 7); + f01_sheet.getRow(1).getCell(i * 10 + 6).value = data.contracts[i * 3 + 1].name; + f01_sheet.mergeCells(1, i * 10 + 8, 1, i * 10 + 9); + f01_sheet.getRow(1).getCell(i * 10 + 8).value = data.contracts[i * 3 + 2].name; + } + } + if (f01Mod > 0) { + f01_sheet.mergeCells(1, f01Num * 10 + 1, 2, f01Num * 10 + 1); + f01_sheet.mergeCells(1, f01Num * 10 + 2, 2, f01Num * 10 + 2); + f01_sheet.mergeCells(1, f01Num * 10 + 3, 2, f01Num * 10 + 3); + f01_sheet.mergeCells(1, f01Num * 10 + 2 * f01Mod + 4, 2, f01Num * 10 + 2 * f01Mod + 4); + f01_sheet.mergeCells(1, f01Num * 10 + 4, 1, f01Num * 10 + 5); + f01_sheet.getRow(1).getCell(f01Num * 10 + 4).value = data.contracts[f01Num * 3].name; + if (f01Mod == 2) { + f01_sheet.mergeCells(1, f01Num * 10 + 6, 1, f01Num * 10 + 7); + f01_sheet.getRow(1).getCell(f01Num * 10 + 6).value = data.contracts[f01Num * 3 + 1].name; + } + } + + let ml_slotRow = 13; + let ml_number = 1; + let allServices = []; + data.contracts.forEach((ci, index) => { + ci.method1 = []; + ci.method2 = []; + ci.method3 = []; + ci.method4 = []; + ci.services.forEach(si => { + if (si.method1) { + ci.method1.push(si.id); + } + if (si.method2) { + ci.method2.push(si.id); + } + if (si.method3) ci.method3.push(si.id); + if (si.method4) ci.method4.push(si.id); + }); + + let ml_sourceRows = [ml_sheet.getRow(6)]; + let sheet_1 = copyWorksheet(workbook, '预i-1表', `预${index + 1}-1表`); + sheet_1.headerFooter.oddHeader = sheet_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-1 表/g, `预 ${index + 1}-1 表`).replace(/第i合同/g, ci.name); + sheet_1.getRow(1).getCell(4).value = sheet_1.getRow(1).getCell(4).value.replace(/第i合同/g, ci.name); + let sheet_2; + let sheet_2_1; + let sheet_2_2; + let sheet_3; + let sheet_4; + let sheet_4_1; + if (ci.method1.length || ci.method2.length) { + ml_sourceRows.push(ml_sheet.getRow(7)); + sheet_2 = copyWorksheet(workbook, '预i-2表', `预${index + 1}-2表`); + sheet_2.headerFooter.oddHeader = sheet_2.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-2 表/g, `预 ${index + 1}-2 表`).replace(/第i合同/g, ci.name); + if (ci.method1.length) { + ml_sourceRows.push(ml_sheet.getRow(8)); + sheet_2_1 = copyWorksheet(workbook, '预i-2-1表', `预${index + 1}-2-1表`); + sheet_2_1.headerFooter.oddHeader = sheet_2_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-2-1 表/g, `预 ${index + 1}-2-1 表`).replace(/第i合同/g, ci.name); + } + if (ci.method2.length) { + ml_sourceRows.push(ml_sheet.getRow(9)); + sheet_2_2 = copyWorksheet(workbook, '预i-2-2表', `预${index + 1}-2-2表`); + sheet_2_2.headerFooter.oddHeader = sheet_2_2.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-2-2 表/g, `预 ${index + 1}-2-2 表`).replace(/第i合同/g, ci.name); + } + } + if (ci.method3.length) { + ml_sourceRows.push(ml_sheet.getRow(10)); + sheet_3 = copyWorksheet(workbook, '预i-3表', `预${index + 1}-3表`); + sheet_3.headerFooter.oddHeader = sheet_3.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-3 表/g, `预 ${index + 1}-3 表`).replace(/第i合同/g, ci.name); + } + if (ci.method4.length) { + ml_sourceRows.push(ml_sheet.getRow(11)); + ml_sourceRows.push(ml_sheet.getRow(12)); + sheet_4 = copyWorksheet(workbook, '预i-4表', `预${index + 1}-4表`); + sheet_4.headerFooter.oddHeader = sheet_4.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4 表/g, `预 ${index + 1}-4 表`).replace(/第i合同/g, ci.name); + sheet_4_1 = copyWorksheet(workbook, '预i-4-1表', `预${index + 1}-4-1表`); + sheet_4_1.headerFooter.oddHeader = sheet_4_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4-1 表/g, `预 ${index + 1}-4-1 表`).replace(/第i合同/g, ci.name); + let sumObj = ci.method4.reduce((a, b) => { + const m4 = ci.services.find(f => f.id == b).method4; + return { person_num: a.person_num + m4.person_num, work_day: a.work_day + m4.work_day, fee: a.fee + m4.fee }; + }, { person_num: 0, work_day: 0, fee: 0 }); + sheet_4.getRow(3).getCell(4).value = sumObj.person_num; + sheet_4.getRow(3).getCell(5).value = sumObj.work_day; + sheet_4.getRow(3).getCell(6).value = sumObj.fee; + sheet_4_1.getRow(4).getCell(4).value = '/'; + sheet_4_1.getRow(4).getCell(5).value = '/'; + sheet_4_1.getRow(4).getCell(6).value = '/'; + sheet_4_1.getRow(4).getCell(7).value = sumObj.person_num; + sheet_4_1.getRow(4).getCell(8).value = sumObj.work_day; + sheet_4_1.getRow(4).getCell(9).value = sumObj.fee + } + + cusInsertRowFunc(ml_slotRow, ml_sourceRows, ml_sheet, () => ml_slotRow++, (targetCell, sourceCell, colNumber) => { + if (colNumber == 1) { + targetCell.value = ml_number++; + } else if (colNumber == 2) { + targetCell.value = sourceCell.value.replaceAll('第i合同', ci.name); + } else if (colNumber == 3) { + targetCell.value = sourceCell.value.replaceAll('i', index + 1); + } else { + targetCell.value = sourceCell.value; + } + }); + + let num_2 = 1; + let num_2_1 = 1; + let num_2_2 = 1; + let num_3 = 1; + let num_4 = 1; + let num_4_1 = 1; + ci.services.forEach((sobj, sindex) => { + let allServicesX = allServices.find(s => s.id == sobj.id); + if (allServicesX) { + allServicesX.contracts[index] = sobj.fee; + } else { + allServices.push({ + id: sobj.id, + contracts: { + [index]: sobj.fee, + }, + }); + } + let serviceX = serviceList[sobj.id]; + cusInsertRowFunc(4 + sindex, [sheet_1.getRow(3)], sheet_1, (targetRow) => { + targetRow.getCell(1).value = sindex + 1; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = sobj.method1 ? sobj.method1.fee : ''; + targetRow.getCell(5).value = sobj.method2 ? sobj.method2.fee : ''; + targetRow.getCell(6).value = sobj.method3 ? sobj.method3.fee : ''; + targetRow.getCell(7).value = sobj.method4 ? sobj.method4.fee : ''; + targetRow.getCell(8).value = sobj.fee; + }); + if (sobj.method1 || sobj.method2) { + let det1 = sobj.method1 ? sobj.method1.det.map(m => m.major) : []; + let det2 = sobj.method2 ? sobj.method2.det.map(m => m.major) : []; + let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => a - b).map(m => { + return { + major: m, + mth1: det1.includes(m) ? sobj.method1.det[det1.indexOf(m)] : null, + mth2: det2.includes(m) ? sobj.method2.det[det2.indexOf(m)] : null, + }; + }); + + cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => { + targetRow.getCell(1).value = num_2++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = '/'; + targetRow.getCell(5).value = '/'; + if (sobj.method1) { + targetRow.getCell(6).value = sobj.method1.basicFee; + targetRow.getCell(7).value = sobj.method1.fee; + cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => { + targetRow.getCell(1).value = num_2_1++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = sobj.method1.cost; + targetRow.getCell(5).value = '/'; + targetRow.getCell(6).value = sobj.method1.basicFee_basic; + targetRow.getCell(7).value = '/'; + targetRow.getCell(8).value = sobj.method1.basicFee_optional; + targetRow.getCell(9).value = sobj.method1.basicFee; + }); + } + if (sobj.method2) { + targetRow.getCell(8).value = sobj.method2.basicFee; + targetRow.getCell(9).value = sobj.method2.fee; + cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => { + targetRow.getCell(1).value = num_2_2++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = sobj.method2.area; + targetRow.getCell(5).value = '/'; + targetRow.getCell(6).value = sobj.method2.basicFee_basic; + targetRow.getCell(7).value = '/'; + targetRow.getCell(8).value = sobj.method2.basicFee_optional; + targetRow.getCell(9).value = sobj.method2.basicFee; + }); + } + }); + allDet.forEach((m, mindex) => { + let majorX = majorList[m.major]; + cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => { + targetRow.getCell(1).value = num_2++; + targetRow.getCell(2).value = serviceX.ref + '-' + (mindex + 1); + targetRow.getCell(3).value = majorX.name; + if (m.mth1) { + targetRow.getCell(4).value = m.mth1.serviceCoe; + targetRow.getCell(5).value = m.mth1.majorCoe; + targetRow.getCell(6).value = m.mth1.basicFee; + targetRow.getCell(7).value = m.mth1.fee; + targetRow.getCell(8).value = 0; + targetRow.getCell(9).value = 0; + cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => { + targetRow.getCell(1).value = num_2_1++; + targetRow.getCell(2).value = serviceX.ref + '-' + (mindex + 1); + targetRow.getCell(3).value = majorX.name; + targetRow.getCell(4).value = m.mth1.cost; + targetRow.getCell(5).value = m.mth1.basicFormula; + targetRow.getCell(6).value = m.mth1.basicFee_basic; + targetRow.getCell(7).value = m.mth1.optionalFormula; + targetRow.getCell(8).value = m.mth1.basicFee_optional; + targetRow.getCell(9).value = m.mth1.basicFee; + }); + } else { + targetRow.getCell(4).value = m.mth2.serviceCoe; + targetRow.getCell(5).value = m.mth2.majorCoe; + targetRow.getCell(6).value = 0; + targetRow.getCell(7).value = 0; + targetRow.getCell(8).value = m.mth2.basicFee; + targetRow.getCell(9).value = m.mth2.fee; + cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => { + targetRow.getCell(1).value = num_2_2++; + targetRow.getCell(2).value = serviceX.ref + '-' + (mindex + 1); + targetRow.getCell(3).value = majorX.name; + targetRow.getCell(4).value = m.mth2.area; + targetRow.getCell(5).value = m.mth2.basicFormula; + targetRow.getCell(6).value = m.mth2.basicFee_basic; + targetRow.getCell(7).value = m.mth2.optionalFormula; + targetRow.getCell(8).value = m.mth2.basicFee_optional; + targetRow.getCell(9).value = m.mth2.basicFee; + }); + } + }); + }); + } + if (sobj.method3) { + cusInsertRowFunc(3 + num_3, [sheet_3.getRow(3)], sheet_3, (targetRow) => { + targetRow.getCell(1).value = num_3++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = '/'; + targetRow.getCell(5).value = '/'; + targetRow.getCell(6).value = '/'; + targetRow.getCell(7).value = sobj.method3.basicFee; + targetRow.getCell(8).value = '/'; + targetRow.getCell(9).value = sobj.method3.fee; + }); + sobj.method3.det.forEach((tobj, tindex) => { + const taskX = taskList[tobj.task]; + cusInsertRowFunc(3 + num_3, [sheet_3.getRow(3)], sheet_3, (targetRow) => { + targetRow.getCell(1).value = num_3++; + targetRow.getCell(2).value = taskX.ref; + targetRow.getCell(3).value = taskX.name + (taskX.desc ? `(${taskX.desc})` : ''); + targetRow.getCell(4).value = taskX.basicParam; + targetRow.getCell(5).value = tobj.price; + targetRow.getCell(6).value = tobj.amount; + targetRow.getCell(7).value = tobj.basicFee; + targetRow.getCell(8).value = tobj.serviceCoe; + targetRow.getCell(9).value = tobj.fee; + }); + }); + } + if (sobj.method4) { + cusInsertRowFunc(4 + num_4, [sheet_4.getRow(4)], sheet_4, (targetRow) => { + targetRow.getCell(1).value = num_4++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = sobj.method4.person_num; + targetRow.getCell(5).value = sobj.method4.work_day; + targetRow.getCell(6).value = sobj.method4.fee; + }); + cusInsertRowFunc(5 + num_4_1, [sheet_4_1.getRow(5)], sheet_4_1, (targetRow) => { + targetRow.getCell(1).value = num_4_1++; + targetRow.getCell(2).value = serviceX.ref; + targetRow.getCell(3).value = serviceX.name; + targetRow.getCell(4).value = '/'; + targetRow.getCell(5).value = '/'; + targetRow.getCell(6).value = '/'; + targetRow.getCell(7).value = sobj.method4.person_num; + targetRow.getCell(8).value = sobj.method4.work_day; + targetRow.getCell(9).value = sobj.method4.fee; + }); + sobj.method4.det.forEach((eobj, eindex) => { + const expertX = expertList[eobj.expert]; + cusInsertRowFunc(5 + num_4_1, [sheet_4_1.getRow(5)], sheet_4_1, (targetRow) => { + targetRow.getCell(1).value = num_4_1++; + targetRow.getCell(2).value = expertX.ref; + targetRow.getCell(3).value = expertX.name; + targetRow.getCell(4).value = `${expertX.minPrice}~${expertX.maxPrice}`; + targetRow.getCell(5).value = `${Math.round(expertX.minPrice * expertX.manageCoe)}~${Math.round(expertX.maxPrice * expertX.manageCoe)}`; + targetRow.getCell(6).value = eobj.price; + targetRow.getCell(7).value = eobj.person_num; + targetRow.getCell(8).value = eobj.work_day; + targetRow.getCell(9).value = eobj.fee; + targetRow.getCell(10).value = eobj.desc; + }); + }); + } + }); + }); + + allServices.sort((a, b) => a.id - b.id); + allServices.forEach((s, sindex) => { + const serviceX = serviceList[s.id]; + cusInsertRowFunc(3 + sindex, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => { + let siSum = 0; + for (let i = 0; i < yz01Num; i++) { + targetRow.getCell(i * 7 + 1).value = sindex + 1; + targetRow.getCell(i * 7 + 2).value = serviceX.ref; + targetRow.getCell(i * 7 + 3).value = serviceX.name; + targetRow.getCell(i * 7 + 4).value = s.contracts[i * 4]; + targetRow.getCell(i * 7 + 5).value = s.contracts[i * 4 + 1]; + targetRow.getCell(i * 7 + 6).value = s.contracts[i * 4 + 2]; + siSum = siSum + (Number(s.contracts[i * 4]) || 0 + Number(s.contracts[i * 4 + 1]) || 0 + Number(s.contracts[i * 4 + 2]) || 0); + if (i == yz01Num - 1 && yz01Mod == 0) { + targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(i * 7 + 7).value = s.contracts[i * 4 + 3]; + siSum = siSum + (Number(s.contracts[i * 4 + 3]) || 0); + } + } + if (yz01Mod) { + targetRow.getCell(yz01Num * 7 + 1).value = sindex + 1; + targetRow.getCell(yz01Num * 7 + 2).value = serviceX.ref; + targetRow.getCell(yz01Num * 7 + 3).value = serviceX.name; + if (yz01Mod == 1) { + targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(siSum, 2); + } else if (yz01Mod == 2) { + targetRow.getCell(yz01Num * 7 + 4).value = s.contracts[yz01Num * 4]; + siSum = siSum + (Number(s.contracts[yz01Num * 4]) || 0); + targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(yz01Num * 7 + 4).value = s.contracts[yz01Num * 4]; + targetRow.getCell(yz01Num * 7 + 5).value = s.contracts[yz01Num * 4 + 1]; + siSum = siSum + (Number(s.contracts[yz01Num * 4]) || 0 + Number(s.contracts[yz01Num * 4 + 1]) || 0); + targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2); + } + } + }); + }); + + ml_sheet.spliceRows(6, 6); + ml_sheet.spliceRows(6, 1); + + // 合并说明 + if (yz01Num) { + for (let i = 0; i < yz01Num; i++) { + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4].name}预算\n(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 1].name}预算\n(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 2].name}预算\n(元)`; + if (i == yz01Num - 1 && yz01Mod == 0) { + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `预算小计\n(元)`; + } else { + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 3].name}预算\n(元)`; + } + yz01_sheet.mergeCells(6, i * 7 + 2, 6, i * 7 + 7); + } + } + if (yz01Mod) { + for (let i = 0; i < yz01Mod; i++) { + if (i == yz01Mod - 1) { + yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `预算小计\n(元)`; + } else { + yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算\n(元)`; + } + } + yz01_sheet.mergeCells(6, yz01Num * 7 + 2, 6, yz01Num * 7 + 3 + yz01Mod); + } + ml_sheet.mergeCells(ml_slotRow - 7, 1, ml_slotRow - 7, 4); + + workbook.removeWorksheet('预i-1表'); + workbook.removeWorksheet('预i-2表'); + workbook.removeWorksheet('预i-2-1表'); + workbook.removeWorksheet('预i-2-2表'); + workbook.removeWorksheet('预i-3表'); + workbook.removeWorksheet('预i-4表'); + workbook.removeWorksheet('预i-4-1表'); + workbook.getWorksheet('辅01表').orderNo = ml_number + 2 + 10; + workbook.getWorksheet('辅02表').orderNo = ml_number + 3 + 10; + workbook.getWorksheet('辅03表').orderNo = ml_number + 4 + 10; + + workbook._worksheets.forEach(sheet => { + if (sheet) { + if (sheet.headerFooter.oddHeader) sheet.headerFooter.oddHeader = sheet.headerFooter.oddHeader.replace(/&([CLR])&/g, '&$1&"宋体"&'); + if (sheet.headerFooter.oddFooter) sheet.headerFooter.oddFooter = sheet.headerFooter.oddFooter.replace(/&([CLR])&/g, '&$1&"宋体"&'); + } + }); + + window.workbook = workbook; + + return workbook; +} + +function cusInsertRowFunc(insertRowNum, sourceRows, worksheet, RowFun, cellFun) { + // 插入行 + let newRows = []; + for (let i = 0; i < sourceRows.length; i++) { + newRows.push([]); + } + worksheet.insertRows(insertRowNum, newRows); + + for (let i = 0; i < sourceRows.length; i++) { + const sourceRow = sourceRows[i]; + const targetRowNum = insertRowNum + i; + const targetRow = worksheet.getRow(targetRowNum); + targetRow.height = undefined; + sourceRow.eachCell({ includeEmpty: true }, (cell, colNumber) => { + const targetCell = targetRow.getCell(colNumber); + // targetCell.value = cell.value; // 复制内容 + // 复制样式 + if (cell.style) { + targetCell.style = { ...cell.style }; + } + + if (cellFun) { + cellFun(targetCell, cell, colNumber, targetRow, sourceRow); + } + }); + if (RowFun) { + RowFun(targetRow, sourceRow, i); + } + } +} + +function copyWorksheet(workbook, sourceName, targetName) { + const source = workbook.getWorksheet(sourceName); + if (!source) throw new Error("Source sheet not found"); + + const target = workbook.addWorksheet(targetName, { + properties: { ...source.properties }, + pageSetup: { ...source.pageSetup }, + views: source.views ? JSON.parse(JSON.stringify(source.views)) : [], + }); + + /* 复制页眉页脚(关键补充) */ + if (source.headerFooter) { + target.headerFooter = JSON.parse( + JSON.stringify(source.headerFooter) + ); + } + + /* 复制合并单元格 */ + Object.keys(source._merges).forEach(range => { + let rangeModel = source._merges[range].model; + target.mergeCells(rangeModel.top, rangeModel.left, rangeModel.bottom, rangeModel.right); + }); + + /* 复制列(宽度、样式) */ + source.columns.forEach((col, i) => { + const targetCol = target.getColumn(i + 1); + targetCol.width = col.width; + targetCol.style = JSON.parse(JSON.stringify(col.style || {})); + }); + + /* 复制行 & 单元格 */ + source.eachRow({ includeEmpty: true }, (row, rowNumber) => { + const targetRow = target.getRow(rowNumber); + targetRow.height = undefined; + + row.eachCell({ includeEmpty: true }, (cell, colNumber) => { + const targetCell = targetRow.getCell(colNumber); + + // value(富文本/公式安全) + targetCell.value = cloneCellValue(cell.value); + + // style(必须深拷贝) + targetCell.style = JSON.parse(JSON.stringify(cell.style || {})); + }); + }); + + return target; +} + +function insertAndCopyColumn(insertAt, cols, ws) { + let insertAti = insertAt; + cols.forEach((col, index) => { + // 在 insertAti 位置插入空列 + ws.spliceColumns(insertAti, 0, []); + + // 插入后,col 可能需要偏移 + const srcColIndex = col >= insertAti ? col + 1 + index : col; + + // 复制列 + copyColumn(insertAti, srcColIndex, ws); + + insertAti++; + }); +} + +function copyColumn(toCol, fromCol, ws) { + const srcCol = ws.getColumn(fromCol); + const dstCol = ws.getColumn(toCol); + + // 列级属性 + dstCol.width = srcCol.width; + dstCol.hidden = srcCol.hidden; + dstCol.style = JSON.parse(JSON.stringify(srcCol.style || {})); + + // 单元格 + srcCol.eachCell({ includeEmpty: true }, (cell, rowNumber) => { + const dstCell = ws.getRow(rowNumber).getCell(toCol); + dstCell.value = cloneCellValue(cell.value); + dstCell.style = JSON.parse(JSON.stringify(cell.style || {})); + }); +} + +function cloneCellValue(value) { + if (value == null) return value; + + if (typeof value === "object") { + return JSON.parse(JSON.stringify(value)); + } + return value; +} + +function numberFormatter(num, decimalNum) { + if (num == null || String(num).trim().length == 0) return null; + let varArr = String(num).split("."); + let big = Number(varArr[0]).toLocaleString(); + if (decimalNum > 0) { + let decimal = varArr.length > 1 ? varArr[1] + '000000' : '000000'; + decimal = decimal.slice(0, decimalNum); + return big + '.' + decimal; + } else { + return big; + } +} \ No newline at end of file diff --git a/public/标准文件转代码Data.xlsx b/public/标准文件转代码Data.xlsx new file mode 100644 index 0000000..bc46a46 Binary files /dev/null and b/public/标准文件转代码Data.xlsx differ diff --git a/public/造价咨询服务计费报表模板.xlsx b/public/造价咨询服务计费报表模板.xlsx new file mode 100644 index 0000000..ae61d98 Binary files /dev/null and b/public/造价咨询服务计费报表模板.xlsx differ diff --git a/src/sql.ts b/src/sql.ts index 2cf75e9..457f432 100644 --- a/src/sql.ts +++ b/src/sql.ts @@ -13,19 +13,19 @@ const toFiniteNumber = (value: unknown) => { } export const industryTypeList = [ - {id:'0', name: '公路工程', type: 'isRoad' }, - {id:'1', name: '铁路工程', type: 'isRailway' }, - {id:'2', name: '水运工程', type: 'isWaterway' } + { id: '0', name: '公路工程', type: 'isRoad' }, + { id: '1', name: '铁路工程', type: 'isRailway' }, + { id: '2', name: '水运工程', type: 'isWaterway' } ] as const -export const majorList = { - 0: { code: 'E1', name: '交通运输工程通用专业',hideInIndustrySelector: true, maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 1, hasCost: false, hasArea: false }, +export const majorList = { + 0: { code: 'E1', name: '交通运输工程通用专业', hideInIndustrySelector: true, maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 1, hasCost: false, hasArea: false }, 1: { code: 'E1-1', name: '征地(用海)补偿', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目征地(用海)补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 2, hasCost: true, hasArea: true }, 2: { code: 'E1-2', name: '拆迁补偿', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于交通建设项目拆迁补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 3, hasCost: true, hasArea: true }, 3: { code: 'E1-3', name: '迁改工程', maxCoe: null, minCoe: null, defCoe: 2, desc: '适用于交通建设项目迁改工程的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 4, hasCost: true, hasArea: false }, 4: { code: 'E1-4', name: '工程建设其他费', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目的工程建设其他费的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 5, hasCost: true, hasArea: false }, 5: { code: 'E1-5', name: '预备费', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 6, hasCost: true, hasArea: false }, 6: { code: 'E1-6', name: '建设期贷款利息', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 7, hasCost: true, hasArea: false }, - 7: { code: 'E2', name: '公路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于公路工程的全过程造价咨询、分阶段造价咨询、投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: true, isRailway: false, isWaterway: false, order: 8, hasCost: false, hasArea: false ,industryId:'0' }, + 7: { code: 'E2', name: '公路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于公路工程的全过程造价咨询、分阶段造价咨询、投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: true, isRailway: false, isWaterway: false, order: 8, hasCost: false, hasArea: false, industryId: '0' }, 8: { code: 'E2-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 9, hasCost: true, hasArea: false }, 9: { code: 'E2-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 10, hasCost: true, hasArea: false }, 10: { code: 'E2-3', name: '路面工程', maxCoe: null, minCoe: null, defCoe: 0.8, desc: '适用于路面工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 11, hasCost: true, hasArea: false }, @@ -36,7 +36,7 @@ export const majorList = { 15: { code: 'E2-8', name: '交通安全设施工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于交通安全设施工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 16, hasCost: true, hasArea: false }, 16: { code: 'E2-9', name: '绿化及环境保护工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于绿化工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 17, hasCost: true, hasArea: false }, 17: { code: 'E2-10', name: '房建工程', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 18, hasCost: true, hasArea: false }, - 18: { code: 'E3', name: '铁路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于铁路工程的投资估算、初步设计概算、清理概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: true, isWaterway: false, order: 19, hasCost: false, hasArea: false ,industryId:'1' }, + 18: { code: 'E3', name: '铁路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于铁路工程的投资估算、初步设计概算、清理概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: true, isWaterway: false, order: 19, hasCost: false, hasArea: false, industryId: '1' }, 19: { code: 'E3-1', name: '大型临时设施和过渡工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于大型临时设施和过渡工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 20, hasCost: true, hasArea: false }, 20: { code: 'E3-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 21, hasCost: true, hasArea: false }, 21: { code: 'E3-3', name: '桥涵工程', maxCoe: null, minCoe: null, defCoe: 0.9, desc: '适用于桥涵工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 22, hasCost: true, hasArea: false }, @@ -46,7 +46,7 @@ export const majorList = { 25: { code: 'E3-7', name: '电力及电力牵引供电工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于电力及电力牵引供电工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 26, hasCost: true, hasArea: false }, 26: { code: 'E3-8', name: '房建工程(房屋建筑及附属工程)', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房屋建筑及附属工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 27, hasCost: true, hasArea: false }, 27: { code: 'E3-9', name: '装饰装修工程', maxCoe: null, minCoe: null, defCoe: 2.7, desc: '适用于装饰装修工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 28, hasCost: true, hasArea: false }, - 28: { code: 'E4', name: '水运工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于水运工程的投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: false, isWaterway: true, order: 29, hasCost: false, hasArea: false ,industryId:'2' }, + 28: { code: 'E4', name: '水运工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于水运工程的投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: false, isWaterway: true, order: 29, hasCost: false, hasArea: false, industryId: '2' }, 29: { code: 'E4-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1.1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 30, hasCost: true, hasArea: false }, 30: { code: 'E4-2', name: '土建工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于土建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 31, hasCost: true, hasArea: false }, 31: { code: 'E4-3', name: '机电与金属结构工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于机电与金属结构专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 32, hasCost: true, hasArea: false }, @@ -198,7 +198,7 @@ type BasicFeeFromScaleResult = { const industryTypeById = new Map( industryTypeList.flatMap(item => { return [[String(item.id).trim(), item.type]] - + }) ) /** @@ -244,7 +244,7 @@ const isPlainObject = (value: unknown): value is Record => Boolean(value) && typeof value === 'object' && !Array.isArray(value) const hasCodeLike = (value: Record) => - typeof value.code === 'string' + typeof value.code === 'string' const isDictLeafNode = (value: unknown): value is Record => isPlainObject(value) && hasCodeLike(value) && typeof value.name === 'string' @@ -287,7 +287,7 @@ const sortDictEntries = ( const orderDiff = getItemSortValue(a.item, a.rawId) - getItemSortValue(b.item, b.rawId) if (orderDiff !== 0) return orderDiff - const codeA = String(a.item?.code || a.id) + const codeA = String(a.item?.code || a.id) const codeB = String(b.item?.code || b.id) return codeA.localeCompare(codeB) }) @@ -548,10 +548,186 @@ export async function exportFile(fileName: string, data: any): Promise { // 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。 async function generateTemplate(data) { + // const downTextTmp = { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '常规' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: '下标' }] }; + + data.contracts[0].addtional = {// 附加工作费 + ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'C' }] }, + name: '附加工作', + fee: 10000, + det: [ + { + id: 0, + ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'F' }] }, + name: '人员驻场服务及其他附加工作', + fee: 10000, + m4: { + person_num: 10, + work_day: 3, + fee: 10000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + m5: { + fee: 10000, + det: [ + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + }, + { + id: 1, + ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'X' }] }, + name: '咨询服务协调工作', + fee: 10000, + m0: { + coe: 0.03, + fee: 10000, + }, + m4: { + person_num: 10, + work_day: 3, + fee: 10000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + m5: { + fee: 10000, + det: [ + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + }, + ] + }; + data.contracts[0].reserve = {// 预备费 + ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'Y' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'B' }] }, + name: '预备费', + fee: 10000, + m0: { + coe: 0.03, + fee: 10000, + }, + m4: { + person_num: 10, + work_day: 3, + fee: 10000, + det: [ + { + expert: 0, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + expert: 1, + price: 100000, + person_num: 10, + work_day: 3, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + }, + m5: { + fee: 10000, + det: [ + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + { + name: '×××项', + unit: '项', + amount: 10, + price: 100000, + fee: 100000, + remark: '',// 用户输入的说明 + }, + ], + } + }; + data.contracts[1].addtional = null; + data.contracts[1].reserve = null; + data.contracts[2].addtional = null; + data.contracts[2].reserve = null; + data.contracts[3].addtional = null; + data.contracts[3].reserve = null; + data.contracts[4].addtional = null; + data.contracts[4].reserve = null; + // data.contracts[5].addtional = null; + // data.contracts[5].reserve = null; try { // 获取模板 let templateExcel = 'template20260226001test010'; - let templateUrl = `https://oa.zwgczx.com/myExcelTemplate/${templateExcel}.xlsx`; + let templateUrl = `./public/${templateExcel}.xlsx`; let buf = await (await fetch(templateUrl)).arrayBuffer(); let workbook = new ExcelJS.Workbook(); await workbook.xlsx.load(buf); @@ -562,14 +738,20 @@ async function generateTemplate(data) { let yz01_sheet = workbook.getWorksheet('预总01表'); let f01_sheet = workbook.getWorksheet('辅01表'); - let now = new Date(); - let year = now.getFullYear(); - let month = now.getMonth() + 1; - let day = now.getDate(); - + // 更新封面 fm_sheet.getRow(2).getCell(1).value = data.name; - fm_sheet.getRow(11).getCell(4).value = `${year} 年 ${month} 月 ${day} 日`; + fm_sheet.getRow(8).getCell(4).value = data.writer; + fm_sheet.getRow(9).getCell(4).value = data.reviewer; + fm_sheet.getRow(10).getCell(4).value = data.company; + if (data.date) { + const dateArr = data.date.split('-'); + let year = dateArr[0]; + let month = Number(dateArr[1]); + let day = Number(dateArr[2]); + fm_sheet.getRow(11).getCell(4).value = `${year} 年 ${month} 月 ${day} 日`; + } + // 更新预总01表的列数 let yz01Mod = (data.contracts.length + 1) % 4; let yz01Num = (data.contracts.length + 1 - yz01Mod) / 4; switch (yz01Mod) { @@ -597,6 +779,7 @@ async function generateTemplate(data) { } } + // 更新辅01表的列数 let f01Mod = (data.contracts.length) % 3; let f01Num = (data.contracts.length - f01Mod) / 3; switch (f01Mod) { @@ -644,14 +827,18 @@ async function generateTemplate(data) { } } - let ml_slotRow = 13; + // 按合同段更新目录及相关表 + let ml_slotRow = 14; let ml_number = 1; let allServices = []; + let allAddtional = {}; + let allReserve = {}; data.contracts.forEach((ci, index) => { ci.method1 = []; ci.method2 = []; ci.method3 = []; ci.method4 = []; + // 按计价方式汇总服务数据对象 ci.services.forEach(si => { if (si.method1) { ci.method1.push(si.id); @@ -662,7 +849,22 @@ async function generateTemplate(data) { if (si.method3) ci.method3.push(si.id); if (si.method4) ci.method4.push(si.id); }); + const addtionalM4 = []; + const addtionalM5 = []; + if (ci.addtional) { + allAddtional[index] = ci.addtional; + ci.addtional.det.forEach(f => { + if (f.m4) addtionalM4.push(f); + if (f.m5) addtionalM5.push(f); + }); + } + if (addtionalM5.length) ci.method5 = { addtional: addtionalM5 }; + if (ci.reserve) allReserve[index] = ci.reserve; + const reserveM4 = ci.reserve?.m4; + const reserveM5 = ci.reserve?.m5; + if (reserveM5) ci.method5 = ci.method5 ? Object.assign({ reserve: reserveM5 }, ci.method5) : { reserve: reserveM5 }; + // 创建sheet let ml_sourceRows = [ml_sheet.getRow(6)]; let sheet_1 = copyWorksheet(workbook, '预i-1表', `预${index + 1}-1表`); sheet_1.headerFooter.oddHeader = sheet_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-1 表/g, `预 ${index + 1}-1 表`).replace(/第i合同/g, ci.name); @@ -673,6 +875,7 @@ async function generateTemplate(data) { let sheet_3; let sheet_4; let sheet_4_1; + let sheet_5; if (ci.method1.length || ci.method2.length) { ml_sourceRows.push(ml_sheet.getRow(7)); sheet_2 = copyWorksheet(workbook, '预i-2表', `预${index + 1}-2表`); @@ -693,19 +896,21 @@ async function generateTemplate(data) { sheet_3 = copyWorksheet(workbook, '预i-3表', `预${index + 1}-3表`); sheet_3.headerFooter.oddHeader = sheet_3.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-3 表/g, `预 ${index + 1}-3 表`).replace(/第i合同/g, ci.name); } - if (ci.method4.length) { + if (ci.method4.length || addtionalM4.length || reserveM4) { ml_sourceRows.push(ml_sheet.getRow(11)); ml_sourceRows.push(ml_sheet.getRow(12)); sheet_4 = copyWorksheet(workbook, '预i-4表', `预${index + 1}-4表`); sheet_4.headerFooter.oddHeader = sheet_4.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4 表/g, `预 ${index + 1}-4 表`).replace(/第i合同/g, ci.name); sheet_4_1 = copyWorksheet(workbook, '预i-4-1表', `预${index + 1}-4-1表`); sheet_4_1.headerFooter.oddHeader = sheet_4_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4-1 表/g, `预 ${index + 1}-4-1 表`).replace(/第i合同/g, ci.name); - let sumObj = ci.method4.reduce((a, b) => { - const m4 = ci.services.find(f => f.id == b)?.method4; + // 更新i-4和i-4-1表的小计行 + let sumArr = ci.method4.map(m => ci.services.find(f => f.id == m)?.method4).concat(addtionalM4.map(m => m.m4)); + if (reserveM4) sumArr.push(reserveM4); + let sumObj = sumArr.reduce((a, b) => { return { - person_num: addNumbers(a.person_num, toFiniteNumber(m4?.person_num)), - work_day: addNumbers(a.work_day, toFiniteNumber(m4?.work_day)), - fee: addNumbers(a.fee, toFiniteNumber(m4?.fee)) + person_num: addNumbers(a.person_num, toFiniteNumber(b?.person_num)), + work_day: addNumbers(a.work_day, toFiniteNumber(b?.work_day)), + fee: addNumbers(a.fee, toFiniteNumber(b?.fee)) }; }, { person_num: 0, work_day: 0, fee: 0 }); sheet_4.getRow(3).getCell(4).value = sumObj.person_num; @@ -718,7 +923,16 @@ async function generateTemplate(data) { sheet_4_1.getRow(4).getCell(8).value = sumObj.work_day; sheet_4_1.getRow(4).getCell(9).value = sumObj.fee } + if (ci.method5) { + ml_sourceRows.push(ml_sheet.getRow(13)); + sheet_5 = copyWorksheet(workbook, '预i-5表', `预${index + 1}-5表`); + sheet_5.headerFooter.oddHeader = sheet_5.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-5 表/g, `预 ${index + 1}-5 表`).replace(/第i合同/g, ci.name); + sheet_5.getRow(3).getCell(4).value = '/'; + sheet_5.getRow(3).getCell(5).value = '/'; + sheet_5.getRow(3).getCell(6).value = (ci.method5.addtional?.reduce((a, b) => a + b.m5.fee, 0) || 0) + (ci.method5.reserve?.fee || 0); + } + // 更新目录的第三部分 cusInsertRowFunc(ml_slotRow, ml_sourceRows, ml_sheet, () => ml_slotRow++, (targetCell, sourceCell, colNumber) => { if (colNumber == 1) { targetCell.value = ml_number++; @@ -731,12 +945,19 @@ async function generateTemplate(data) { } }); + // 根据服务更新相关表 let num_2 = 1; let num_2_1 = 1; let num_2_2 = 1; let num_3 = 1; let num_4 = 1; let num_4_1 = 1; + let num_5 = 1; + let m1Sum = 0; + let m2Sum = 0; + let m3Sum = 0; + let m4Sum = 0; + let serviceSum = 0; ci.services.forEach((sobj, sindex) => { let allServicesX = allServices.find(s => s.id == sobj.id); if (allServicesX) { @@ -749,31 +970,34 @@ async function generateTemplate(data) { }, }); } - let serviceX = getServiceDictItemById(sobj.id) || { code: '', name: '' }; + let serviceX = serviceList[sobj.id]; cusInsertRowFunc(4 + sindex, [sheet_1.getRow(3)], sheet_1, (targetRow) => { targetRow.getCell(1).value = sindex + 1; targetRow.getCell(2).value = serviceX.code; targetRow.getCell(3).value = serviceX.name; - targetRow.getCell(4).value = sobj.method1 ? sobj.method1.fee : ''; - targetRow.getCell(5).value = sobj.method2 ? sobj.method2.fee : ''; - targetRow.getCell(6).value = sobj.method3 ? sobj.method3.fee : ''; - targetRow.getCell(7).value = sobj.method4 ? sobj.method4.fee : ''; + if (sobj.method1) { + targetRow.getCell(4).value = sobj.method1.fee; + m1Sum += sobj.method1.fee; + } + if (sobj.method2) { + targetRow.getCell(5).value = sobj.method2.fee; + m2Sum += sobj.method2.fee; + } + if (sobj.method3) { + targetRow.getCell(6).value = sobj.method3.fee; + m3Sum += sobj.method3.fee; + } + if (sobj.method4) { + targetRow.getCell(7).value = sobj.method4.fee; + m4Sum += sobj.method4.fee; + } targetRow.getCell(8).value = sobj.fee; + serviceSum += sobj.fee; }); if (sobj.method1 || sobj.method2) { let det1 = sobj.method1 ? sobj.method1.det.map(m => m.major) : []; let det2 = sobj.method2 ? sobj.method2.det.map(m => m.major) : []; - const majorOrderMap = new Map(getMajorDictEntries().map((entry, idx) => [entry.id, idx])); - let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => { - const aId = String(a); - const bId = String(b); - const ao = majorOrderMap.get(aId) ?? majorOrderMap.get(getMajorIdAliasMap().get(aId) || ''); - const bo = majorOrderMap.get(bId) ?? majorOrderMap.get(getMajorIdAliasMap().get(bId) || ''); - if (ao != null && bo != null) return ao - bo; - if (ao != null) return -1; - if (bo != null) return 1; - return aId.localeCompare(bId); - }).map(m => { + let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => a - b).map(m => { return { major: m, mth1: det1.includes(m) ? sobj.method1.det[det1.indexOf(m)] : null, @@ -787,9 +1011,11 @@ async function generateTemplate(data) { targetRow.getCell(3).value = serviceX.name; targetRow.getCell(4).value = '/'; targetRow.getCell(5).value = '/'; + targetRow.getCell(6).value = '/'; + targetRow.getCell(7).value = '/'; if (sobj.method1) { - targetRow.getCell(6).value = sobj.method1.basicFee; - targetRow.getCell(7).value = sobj.method1.fee; + targetRow.getCell(8).value = sobj.method1.basicFee; + targetRow.getCell(9).value = sobj.method1.fee; cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => { targetRow.getCell(1).value = num_2_1++; targetRow.getCell(2).value = serviceX.code; @@ -803,8 +1029,8 @@ async function generateTemplate(data) { }); } if (sobj.method2) { - targetRow.getCell(8).value = sobj.method2.basicFee; - targetRow.getCell(9).value = sobj.method2.fee; + targetRow.getCell(10).value = sobj.method2.basicFee; + targetRow.getCell(11).value = sobj.method2.fee; cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => { targetRow.getCell(1).value = num_2_2++; targetRow.getCell(2).value = serviceX.code; @@ -819,7 +1045,7 @@ async function generateTemplate(data) { } }); allDet.forEach((m, mindex) => { - let majorX = getMajorDictItemById(m.major) || { name: '' }; + let majorX = majorList[m.major]; cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => { targetRow.getCell(1).value = num_2++; targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1); @@ -827,10 +1053,12 @@ async function generateTemplate(data) { if (m.mth1) { targetRow.getCell(4).value = m.mth1.serviceCoe; targetRow.getCell(5).value = m.mth1.majorCoe; - targetRow.getCell(6).value = m.mth1.basicFee; - targetRow.getCell(7).value = m.mth1.fee; - targetRow.getCell(8).value = 0; - targetRow.getCell(9).value = 0; + targetRow.getCell(6).value = m.mth1.processCoe; + targetRow.getCell(7).value = m.mth1.proportion; + targetRow.getCell(8).value = m.mth1.basicFee; + targetRow.getCell(9).value = m.mth1.fee; + targetRow.getCell(10).value = 0; + targetRow.getCell(11).value = 0; cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => { targetRow.getCell(1).value = num_2_1++; targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1); @@ -845,10 +1073,12 @@ async function generateTemplate(data) { } else { targetRow.getCell(4).value = m.mth2.serviceCoe; targetRow.getCell(5).value = m.mth2.majorCoe; - targetRow.getCell(6).value = 0; - targetRow.getCell(7).value = 0; - targetRow.getCell(8).value = m.mth2.basicFee; - targetRow.getCell(9).value = m.mth2.fee; + targetRow.getCell(6).value = m.mth2.processCoe; + targetRow.getCell(7).value = m.mth2.proportion; + targetRow.getCell(8).value = 0; + targetRow.getCell(9).value = 0; + targetRow.getCell(10).value = m.mth2.basicFee; + targetRow.getCell(11).value = m.mth2.fee; cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => { targetRow.getCell(1).value = num_2_2++; targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1); @@ -928,19 +1158,64 @@ async function generateTemplate(data) { }); } }); + let endRows = 1; + cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => { + targetRow.getCell(1).value = ci.services.length + endRows; + targetRow.getCell(2).value = ''; + targetRow.getCell(3).value = '小计'; + targetRow.getCell(4).value = numberFormatter(m1Sum, 2); + targetRow.getCell(5).value = numberFormatter(m2Sum, 2); + targetRow.getCell(6).value = numberFormatter(m3Sum, 2); + targetRow.getCell(7).value = numberFormatter(m4Sum, 2); + targetRow.getCell(8).value = numberFormatter(serviceSum, 2); + }); + if (ci.addtional) { + endRows++; + cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => { + targetRow.getCell(1).value = ci.services.length + endRows; + targetRow.getCell(2).value = ci.addtional.ref; + targetRow.getCell(3).value = ci.addtional.name; + targetRow.getCell(4).value = ''; + targetRow.getCell(5).value = ''; + targetRow.getCell(6).value = ''; + targetRow.getCell(7).value = ''; + targetRow.getCell(8).value = ci.addtional.fee; + }); + ci.addtional.det.forEach((addobj, addindex) => { + endRows++; + cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => { + targetRow.getCell(1).value = ci.services.length + endRows; + targetRow.getCell(2).value = addobj.ref; + targetRow.getCell(3).value = addobj.name; + let tmpArr = []; + if (addobj.m0) tmpArr.push(`按上述小计的${addobj.m0.coe}计得${addobj.m0.fee}元`); + if (addobj.m4) tmpArr.push(`按工时法计得${addobj.m4.fee}元`); + if (addobj.m5) tmpArr.push(`按数量单价计得${addobj.m5.fee}元`); + targetRow.getCell(4).value = tmpArr.join(';'); + targetRow.getCell(8).value = addobj.fee; + }); + }); + } + + sheet_1.spliceRows(3, 1); + sheet_1.getRow(ci.services.length + endRows + 3).getCell(1).value = ci.services.length + endRows + 1; + sheet_1.getRow(ci.services.length + endRows + 3).getCell(8).value = ci.fee; + sheet_1.mergeCells(2 + ci.services.length + endRows + 2, 2, 2 + ci.services.length + endRows + 2, 8); + sheet_1.getRow(2 + ci.services.length + endRows + 2).height = 100; + sheet_1.getRow(2 + ci.services.length + endRows + 2).getCell(2).border.right = { style: 'thin' }; + for (let i = 1; i <= endRows; i++) { + sheet_1.mergeCells(ci.services.length + 3 + i, 4, ci.services.length + 3 + i, 7); + if (sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment) { + sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment.horizontal = 'center'; + sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment.wrapText = true; + if (i != 1 && i != endRows) sheet_1.getRow(ci.services.length + 3 + i).getCell(9).style.font.size = 22; + } + } }); - const serviceOrderMap = new Map(getServiceDictEntries().map((entry, index) => [entry.id, index])); - allServices.sort((a, b) => { - const ao = serviceOrderMap.get(String(a.id)); - const bo = serviceOrderMap.get(String(b.id)); - if (ao != null && bo != null) return ao - bo; - if (ao != null) return -1; - if (bo != null) return 1; - return String(a.id).localeCompare(String(b.id)); - }); + allServices.sort((a, b) => a.id - b.id); allServices.forEach((s, sindex) => { - const serviceX = getServiceDictItemById(s.id) || { code: '', name: '' }; + const serviceX = serviceList[s.id]; cusInsertRowFunc(3 + sindex, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => { let siSum = 0; for (let i = 0; i < yz01Num; i++) { @@ -986,35 +1261,174 @@ async function generateTemplate(data) { } }); }); + let endRows = 0; + if (Object.keys(allAddtional).length) { + endRows++; + let firstNum = Object.keys(allAddtional)[0]; + cusInsertRowFunc(3 + allServices.length, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => { + let siSum = 0; + for (let i = 0; i < yz01Num; i++) { + targetRow.getCell(i * 7 + 1).value = allServices.length + 1; + targetRow.getCell(i * 7 + 2).value = allAddtional[firstNum].ref; + targetRow.getCell(i * 7 + 3).value = allAddtional[firstNum].name; + targetRow.getCell(i * 7 + 4).value = allAddtional[i * 4]?.fee; + targetRow.getCell(i * 7 + 5).value = allAddtional[i * 4 + 1]?.fee; + targetRow.getCell(i * 7 + 6).value = allAddtional[i * 4 + 2]?.fee; + siSum = addNumbers( + siSum, + toFiniteNumber(allAddtional[i * 4]?.fee), + toFiniteNumber(allAddtional[i * 4 + 1]?.fee), + toFiniteNumber(allAddtional[i * 4 + 2]?.fee) + ); + if (i == yz01Num - 1 && yz01Mod == 0) { + targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(i * 7 + 7).value = allAddtional[i * 4 + 3]?.fee; + siSum = addNumbers(siSum, toFiniteNumber(allAddtional[i * 4 + 3]?.fee)); + } + } + if (yz01Mod) { + targetRow.getCell(yz01Num * 7 + 1).value = allServices.length + 1; + targetRow.getCell(yz01Num * 7 + 2).value = allAddtional[firstNum].ref; + targetRow.getCell(yz01Num * 7 + 3).value = allAddtional[firstNum].name; + if (yz01Mod == 1) { + targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(siSum, 2); + } else if (yz01Mod == 2) { + targetRow.getCell(yz01Num * 7 + 4).value = allAddtional[yz01Num * 4]?.fee; + siSum = addNumbers(siSum, toFiniteNumber(allAddtional[yz01Num * 4]?.fee)); + targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(yz01Num * 7 + 4).value = allAddtional[yz01Num * 4]?.fee; + targetRow.getCell(yz01Num * 7 + 5).value = allAddtional[yz01Num * 4 + 1]?.fee; + siSum = addNumbers( + siSum, + toFiniteNumber(allAddtional[yz01Num * 4]?.fee), + toFiniteNumber(allAddtional[yz01Num * 4 + 1]?.fee) + ); + targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2); + } + } + }); + } + if (Object.keys(allReserve).length) { + endRows++; + let firstNum = Object.keys(allReserve)[0]; + cusInsertRowFunc(3 + allServices.length + endRows - 1, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => { + let siSum = 0; + for (let i = 0; i < yz01Num; i++) { + targetRow.getCell(i * 7 + 1).value = allServices.length + endRows; + targetRow.getCell(i * 7 + 2).value = allReserve[firstNum].ref; + targetRow.getCell(i * 7 + 3).value = allReserve[firstNum].name; + targetRow.getCell(i * 7 + 4).value = allReserve[i * 4]?.fee; + targetRow.getCell(i * 7 + 5).value = allReserve[i * 4 + 1]?.fee; + targetRow.getCell(i * 7 + 6).value = allReserve[i * 4 + 2]?.fee; + siSum = addNumbers( + siSum, + toFiniteNumber(allReserve[i * 4]?.fee), + toFiniteNumber(allReserve[i * 4 + 1]?.fee), + toFiniteNumber(allReserve[i * 4 + 2]?.fee) + ); + if (i == yz01Num - 1 && yz01Mod == 0) { + targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(i * 7 + 7).value = allReserve[i * 4 + 3]?.fee; + siSum = addNumbers(siSum, toFiniteNumber(allReserve[i * 4 + 3]?.fee)); + } + } + if (yz01Mod) { + targetRow.getCell(yz01Num * 7 + 1).value = allServices.length + endRows; + targetRow.getCell(yz01Num * 7 + 2).value = allReserve[firstNum].ref; + targetRow.getCell(yz01Num * 7 + 3).value = allReserve[firstNum].name; + if (yz01Mod == 1) { + targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(siSum, 2); + } else if (yz01Mod == 2) { + targetRow.getCell(yz01Num * 7 + 4).value = allReserve[yz01Num * 4]?.fee; + siSum = addNumbers(siSum, toFiniteNumber(allReserve[yz01Num * 4]?.fee)); + targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2); + } else { + targetRow.getCell(yz01Num * 7 + 4).value = allReserve[yz01Num * 4]?.fee; + targetRow.getCell(yz01Num * 7 + 5).value = allReserve[yz01Num * 4 + 1]?.fee; + siSum = addNumbers( + siSum, + toFiniteNumber(allReserve[yz01Num * 4]?.fee), + toFiniteNumber(allReserve[yz01Num * 4 + 1]?.fee) + ); + targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2); + } + } + }); + } + const yz01SumRow = yz01_sheet.getRow(allServices.length + endRows + 3); + for (let i = 0; i < yz01Num; i++) { + yz01SumRow.getCell(i * 7 + 1).value = allServices.length + endRows + 1; + yz01SumRow.getCell(i * 7 + 4).value = data.contracts[i * 4]?.fee; + yz01SumRow.getCell(i * 7 + 5).value = data.contracts[i * 4 + 1]?.fee; + yz01SumRow.getCell(i * 7 + 6).value = data.contracts[i * 4 + 2]?.fee; + if (i == yz01Num - 1 && yz01Mod == 0) { + yz01SumRow.getCell(i * 7 + 7).value = numberFormatter(data.fee, 2); + } else { + yz01SumRow.getCell(i * 7 + 7).value = data.contracts[i * 4 + 3]?.fee; + } + } + if (yz01Mod) { + yz01SumRow.getCell(yz01Num * 7 + 1).value = allServices.length + endRows + 1; + if (yz01Mod == 1) { + yz01SumRow.getCell(yz01Num * 7 + 4).value = numberFormatter(data.fee, 2); + } else if (yz01Mod == 2) { + yz01SumRow.getCell(yz01Num * 7 + 4).value = data.contracts[yz01Num * 4]?.fee; + yz01SumRow.getCell(yz01Num * 7 + 5).value = numberFormatter(data.fee, 2); + } else { + yz01SumRow.getCell(yz01Num * 7 + 4).value = data.contracts[yz01Num * 4]?.fee; + yz01SumRow.getCell(yz01Num * 7 + 5).value = data.contracts[yz01Num * 4 + 1]?.fee; + yz01SumRow.getCell(yz01Num * 7 + 6).value = numberFormatter(data.fee, 2); + } + } - ml_sheet.spliceRows(6, 6); + ml_sheet.spliceRows(6, 7); ml_sheet.spliceRows(6, 1); + yz01_sheet.spliceRows(2, 1); // 合并说明 + let yz01_lastCol; if (yz01Num) { for (let i = 0; i < yz01Num; i++) { - yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4].name}预算\n(元)`; - yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 1].name}预算\n(元)`; - yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 2].name}预算\n(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4].name}预算(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4 + 1).value = `${data.contracts[i * 4 + 1].name}预算(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4 + 2).value = `${data.contracts[i * 4 + 2].name}预算(元)`; if (i == yz01Num - 1 && yz01Mod == 0) { - yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `预算小计\n(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4 + 3).value = `预算小计(元)`; + yz01_lastCol = i * 7 + 4; } else { - yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 3].name}预算\n(元)`; + yz01_sheet.getRow(1).getCell(i * 7 + 4 + 3).value = `${data.contracts[i * 4 + 3].name}预算(元)`; } - yz01_sheet.mergeCells(6, i * 7 + 2, 6, i * 7 + 7); + yz01_sheet.mergeCells(allServices.length + endRows + 3, i * 7 + 2, allServices.length + endRows + 3, i * 7 + 7); + yz01_sheet.getRow(allServices.length + endRows + 3).getCell(i * 7 + 2).border.right = { style: 'thin' }; } } if (yz01Mod) { for (let i = 0; i < yz01Mod; i++) { if (i == yz01Mod - 1) { - yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `预算小计\n(元)`; + yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `预算小计(元)`; + yz01_lastCol = yz01Num * 7 + 4 + i; } else { - yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算\n(元)`; + yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算(元)`; } } - yz01_sheet.mergeCells(6, yz01Num * 7 + 2, 6, yz01Num * 7 + 3 + yz01Mod); + yz01_sheet.mergeCells(allServices.length + endRows + 3, yz01Num * 7 + 2, allServices.length + endRows + 3, yz01Num * 7 + 3 + yz01Mod); + yz01_sheet.getRow(allServices.length + endRows + 3).getCell(yz01Num * 7 + 2).border.right = { style: 'thin' }; } - ml_sheet.mergeCells(ml_slotRow - 7, 1, ml_slotRow - 7, 4); + yz01_sheet.getRow(allServices.length + endRows + 3).height = 100; + // for (let i = 1; i <= allServices.length + endRows + 3; i++) { + // yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).value = ' '; + // if (yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style.font) { + // yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style.font.size = i == 1 ? 22 : 20; + // } else { + // yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style = { font: { size: i == 1 ? 22 : 20 } }; + // // } + // // } + // yz01_sheet.pageSetup.printArea = `A1:${yz01_sheet.getRow(allServices.length + endRows + 3).getCell(yz01_lastCol)._address}`; + + ml_sheet.mergeCells(ml_slotRow - 8, 1, ml_slotRow - 8, 4); workbook.removeWorksheet('预i-1表'); workbook.removeWorksheet('预i-2表'); @@ -1023,9 +1437,10 @@ async function generateTemplate(data) { workbook.removeWorksheet('预i-3表'); workbook.removeWorksheet('预i-4表'); workbook.removeWorksheet('预i-4-1表'); - workbook.getWorksheet('辅01表').orderNo = ml_number + 2 + 10; - workbook.getWorksheet('辅02表').orderNo = ml_number + 3 + 10; - workbook.getWorksheet('辅03表').orderNo = ml_number + 4 + 10; + workbook.removeWorksheet('预i-5表'); + workbook.getWorksheet('辅01表').orderNo = ml_number + 2 + 11; + workbook.getWorksheet('辅02表').orderNo = ml_number + 3 + 11; + workbook.getWorksheet('辅03表').orderNo = ml_number + 4 + 11; workbook._worksheets.forEach(sheet => { if (sheet) { @@ -1063,7 +1478,7 @@ function cusInsertRowFunc(insertRowNum, sourceRows, worksheet, RowFun, cellFun) // targetCell.value = cell.value; // 复制内容 // 复制样式 if (cell.style) { - targetCell.style = { ...cell.style }; + targetCell.style = JSON.parse(JSON.stringify(cell.style)); } if (cellFun) { @@ -1082,16 +1497,14 @@ function copyWorksheet(workbook, sourceName, targetName) { if (!source) throw new Error("Source sheet not found"); const target = workbook.addWorksheet(targetName, { - properties: { ...source.properties }, - pageSetup: { ...source.pageSetup }, - views: source.views ? JSON.parse(JSON.stringify(source.views)) : [], + properties: JSON.parse(JSON.stringify(source.properties || {})), + pageSetup: JSON.parse(JSON.stringify(source.pageSetup || {})), + views: source.views ? JSON.parse(JSON.stringify(source.views || {})) : [], }); /* 复制页眉页脚(关键补充) */ if (source.headerFooter) { - target.headerFooter = JSON.parse( - JSON.stringify(source.headerFooter) - ); + target.headerFooter = JSON.parse(JSON.stringify(source.headerFooter)); } /* 复制合并单元格 */