1939 lines
132 KiB
TypeScript
1939 lines
132 KiB
TypeScript
// @ts-nocheck
|
||
import { addNumbers, roundTo, toDecimal } from '@/lib/decimal'
|
||
import { formatThousands } from '@/lib/numberFormat'
|
||
import ExcelJS from "ExcelJS";
|
||
import { number } from 'motion-v/es';
|
||
// 统一数字千分位格式化,默认保留 2 位小数。
|
||
const numberFormatter = (value: unknown, fractionDigits = 2) =>
|
||
formatThousands(value, fractionDigits)
|
||
|
||
// 将任意输入安全转为有限数字;无效值统一按 0 处理。
|
||
const toFiniteNumber = (value: unknown) => {
|
||
const num = Number(value)
|
||
return Number.isFinite(num) ? num : 0
|
||
}
|
||
|
||
export const industryTypeList = [
|
||
{ 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 },
|
||
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' },
|
||
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 },
|
||
11: { code: 'E2-4', name: '桥涵工程', maxCoe: null, minCoe: null, defCoe: 0.9, desc: '适用于桥梁涵洞工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 12, hasCost: true, hasArea: false },
|
||
12: { code: 'E2-5', name: '隧道工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于隧道工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 13, hasCost: true, hasArea: false },
|
||
13: { code: 'E2-6', name: '交叉工程', maxCoe: null, minCoe: null, defCoe: 1.1, desc: '适用于交叉工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 14, hasCost: true, hasArea: false },
|
||
14: { code: 'E2-7', name: '机电工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于机电工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 15, hasCost: true, hasArea: false },
|
||
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' },
|
||
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 },
|
||
22: { code: 'E3-4', name: '隧道及明洞工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于隧道及明洞工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 23, hasCost: true, hasArea: false },
|
||
23: { code: 'E3-5', name: '轨道工程', maxCoe: null, minCoe: null, defCoe: 0.3, desc: '适用于轨道工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 24, hasCost: true, hasArea: false },
|
||
24: { code: 'E3-6', name: '通信、信号、信息及灾害监测工程', maxCoe: null, minCoe: null, defCoe: 2, desc: '适用于通信、信号、信息及防灾监测工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 25, hasCost: true, hasArea: false },
|
||
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' },
|
||
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 },
|
||
32: { code: 'E4-4', name: '设备工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于设备工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 33, hasCost: true, hasArea: false },
|
||
33: { code: 'E4-5', name: '附属房建工程(房屋建筑及附属工程)', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房屋建筑与水运附属工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 34, hasCost: true, hasArea: false },
|
||
};
|
||
|
||
|
||
|
||
|
||
export const serviceList = {
|
||
0: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: { code: '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: true, order: 30, scale: true, onlyCostScale: true, amount: false, workDay: true },
|
||
30: { code: 'D4-15-2', name: '造价数据测试验证(概算)', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '', isRoad: true, isRailway: true, isWaterway: true, mutiple: true, order: 31, scale: true, onlyCostScale: true, amount: false, workDay: true },
|
||
31: { code: '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: true, order: 32, scale: true, onlyCostScale: false, amount: false, workDay: true },
|
||
32: { code: 'D4-15-4', name: '造价数据测试验证(招标工程量清单及清单预算(或最高投标限价))', maxCoe: null, minCoe: null, defCoe: 0.06, desc: '', isRoad: true, isRailway: true, isWaterway: true, mutiple: true, order: 33, scale: true, onlyCostScale: false, amount: false, workDay: true },
|
||
33: { code: 'D4-15-5', name: '造价数据测试验证(清理概算(仅限铁路))', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '本系数适用于铁路工程。', isRoad: false, isRailway: true, isWaterway: false, mutiple: true, order: 34, scale: true, onlyCostScale: true, amount: false, workDay: true },
|
||
34: { code: 'D4-15-6', name: '造价数据测试验证(合同(工程)结算)', maxCoe: null, minCoe: null, defCoe: 0.12, desc: '本系数适用于公路和水运工程。', isRoad: true, isRailway: false, isWaterway: true, mutiple: true, order: 35, scale: true, onlyCostScale: false, amount: false, workDay: true },
|
||
35: { code: 'D4-15-7', name: '造价数据测试验证(合同(工程)结算)', maxCoe: null, minCoe: null, defCoe: 0.08, desc: '本系数适用于铁路工程。', isRoad: false, isRailway: true, isWaterway: false, mutiple: true, order: 36, scale: true, onlyCostScale: false, amount: false, workDay: true },
|
||
36: { code: 'D4-15-8', name: '造价数据测试验证(竣工决算)', maxCoe: null, minCoe: null, defCoe: 0.04, desc: '', isRoad: true, isRailway: true, isWaterway: true, mutiple: true, order: 37, scale: true, onlyCostScale: true, amount: false, workDay: true },
|
||
};
|
||
|
||
|
||
export const taskList = {
|
||
0: { serviceID: 15, code: 'C4-1', name: '工程造价日常顾问', basicParam: '服务月份数', required: true, unit: '万元/月', conversion: 10000, maxPrice: 0.5, minPrice: 0.3, defPrice: 0.4, desc: '' },
|
||
1: { serviceID: 15, code: 'C4-2', name: '工程造价专项顾问', basicParam: '服务项目的造价金额', required: true, unit: '%', conversion: 0.01, maxPrice: null, minPrice: null, defPrice: 0.01, desc: '适用于涉及造价费用类的顾问' },
|
||
2: { serviceID: 16, code: 'C5-1', name: '组织与调研工作', basicParam: '调研次数', required: true, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' },
|
||
3: { serviceID: 16, code: 'C5-2-1', name: '文件编写工作', basicParam: '文件份数', required: true, unit: '万元/份', conversion: 10000, maxPrice: 5, minPrice: 3, defPrice: 4, desc: '主编' },
|
||
4: { serviceID: 16, code: 'C5-2-2', name: '文件编写工作', basicParam: '文件份数', required: true, unit: '万元/份', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '参编' },
|
||
5: { serviceID: 16, code: 'C5-3-1', name: '评审工作', basicParam: '评审次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' },
|
||
6: { serviceID: 16, code: 'C5-3-2', name: '评审工作', basicParam: '评审次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' },
|
||
7: { serviceID: 16, code: 'C5-3-3', name: '评审工作', basicParam: '评审次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' },
|
||
8: { serviceID: 17, code: 'C6-1', name: '组织与调研工作', basicParam: '调研次数', required: true, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' },
|
||
9: { serviceID: 17, code: 'C6-2-1', name: '研究及编写报告', basicParam: '文件份数', required: true, unit: '万元/份', conversion: 10000, maxPrice: 50, minPrice: 20, defPrice: 35, desc: '国家级' },
|
||
10: { serviceID: 17, code: 'C6-2-2', name: '研究及编写报告', basicParam: '文件份数', required: true, unit: '万元/份', conversion: 10000, maxPrice: 20, minPrice: 10, defPrice: 15, desc: '省部级' },
|
||
11: { serviceID: 17, code: 'C6-2-3', name: '研究及编写报告', basicParam: '文件份数', required: true, unit: '万元/份', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '其他级' },
|
||
12: { serviceID: 17, code: 'C6-3-1', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: true, unit: '万元/份', conversion: 10000, maxPrice: 80, minPrice: 50, defPrice: 65, desc: '复杂标准' },
|
||
13: { serviceID: 17, code: 'C6-3-2', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: true, unit: '万元/份', conversion: 10000, maxPrice: 50, minPrice: 20, defPrice: 35, desc: '较复杂标准' },
|
||
14: { serviceID: 17, code: 'C6-3-3', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: true, unit: '万元/份', conversion: 10000, maxPrice: 20, minPrice: 10, defPrice: 15, desc: '一般标准' },
|
||
15: { serviceID: 17, code: 'C6-3-4', name: '标准与技术性指导文件的编制', basicParam: '文件与标准的数量', required: true, unit: '万元/份', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '简单标准' },
|
||
16: { serviceID: 17, code: 'C6-4-1', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' },
|
||
17: { serviceID: 17, code: 'C6-4-2', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' },
|
||
18: { serviceID: 17, code: 'C6-4-3', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' },
|
||
19: { serviceID: 17, code: 'C6-5-1', name: '培训与宣贯工作', basicParam: '项目数量', required: false, unit: '万元/次', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '培训与宣贯材料' },
|
||
20: { serviceID: 17, code: 'C6-5-2', name: '培训与宣贯工作', basicParam: '培训与宣贯次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '组织培训与宣贯' },
|
||
21: { serviceID: 18, code: 'C7-1', name: '组织与调研工作', basicParam: '调研次数', required: true, unit: '万元/次', conversion: 10000, maxPrice: 2, minPrice: 1, defPrice: 1.5, desc: '' },
|
||
22: { serviceID: 18, code: 'C7-2', name: '编制大纲', basicParam: '项目数量', required: true, unit: '万元/个', conversion: 10000, maxPrice: 3, minPrice: 2, defPrice: 2.5, desc: '包括技术与定额子目研究' },
|
||
23: { serviceID: 18, code: 'C7-3', name: '数据采集与测定', basicParam: '采集组数', required: true, unit: '万元/组', conversion: 10000, maxPrice: 0.8, minPrice: 0.2, defPrice: 0.5, desc: '现场采集方式时计' },
|
||
24: { serviceID: 18, code: 'C7-4-1', name: '数据整理与分析', basicParam: '定额子目条数', required: true, unit: '万元/条', conversion: 10000, maxPrice: 0.3, minPrice: 0.1, defPrice: 0.2, desc: '简单定额' },
|
||
25: { serviceID: 18, code: 'C7-4-2', name: '数据整理与分析', basicParam: '定额子目条数', required: true, unit: '万元/条', conversion: 10000, maxPrice: 3, minPrice: 0.3, defPrice: 1.65, desc: '复杂定额' },
|
||
26: { serviceID: 18, code: 'C7-5', name: '编写定额测定报告', basicParam: '项目数量', required: true, unit: '万元/份', conversion: 10000, maxPrice: 5, minPrice: 2, defPrice: 3.5, desc: '' },
|
||
27: { serviceID: 18, code: 'C7-6-1', name: '编制定额文本和释义', basicParam: '基本费用', required: true, unit: '万元/份', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '20条定额子目内' },
|
||
28: { serviceID: 18, code: '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, code: 'C7-7-1', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 20, minPrice: 8, defPrice: 14, desc: '大型评审' },
|
||
30: { serviceID: 18, code: 'C7-7-2', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 10, minPrice: 5, defPrice: 7.5, desc: '中型评审' },
|
||
31: { serviceID: 18, code: 'C7-7-3', name: '评审与验收工作', basicParam: '评审与验收次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 6, minPrice: 3, defPrice: 4.5, desc: '小型评审' },
|
||
32: { serviceID: 18, code: 'C7-8-1', name: '培训与宣贯工作', basicParam: '项目数量', required: false, unit: '万元/次', conversion: 10000, maxPrice: 3, minPrice: 1, defPrice: 2, desc: '培训与宣贯材料' },
|
||
33: { serviceID: 18, code: 'C7-8-2', name: '培训与宣贯工作', basicParam: '培训与宣贯次数', required: false, unit: '万元/次', conversion: 10000, maxPrice: 1, minPrice: 0.5, defPrice: 0.75, desc: '组织培训与宣贯' },
|
||
34: { serviceID: 19, code: 'C8-1', name: 'Q≤10条', basicParam: '价格信息数量', required: true, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 500, desc: '' },
|
||
35: { serviceID: 19, code: 'C8-2', name: '10条<Q≤30条', basicParam: '价格信息数量', required: true, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 400, desc: '' },
|
||
36: { serviceID: 19, code: 'C8-3', name: '30条<Q≤50条', basicParam: '价格信息数量', required: true, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 300, desc: '' },
|
||
37: { serviceID: 19, code: 'C8-4', name: '50条<Q≤100条', basicParam: '价格信息数量', required: true, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 200, desc: '' },
|
||
38: { serviceID: 19, code: 'C8-5', name: 'Q>100条', basicParam: '价格信息数量', required: true, unit: '元/条', conversion: 1, maxPrice: null, minPrice: null, defPrice: 100, desc: '' },
|
||
};
|
||
|
||
export const expertList = {
|
||
0: { code: 'C9-1-1', name: '技术员及其他', maxPrice: 800, minPrice: 600, defPrice: 700, manageCoe: 2.3 },
|
||
1: { code: 'C9-1-2', name: '助理工程师', maxPrice: 1000, minPrice: 800, defPrice: 900, manageCoe: 2.3 },
|
||
2: { code: 'C9-1-3', name: '中级工程师或二级造价工程师', maxPrice: 1500, minPrice: 1000, defPrice: 1250, manageCoe: 2.2 },
|
||
3: { code: 'C9-1-4', name: '高级工程师或一级造价工程师', maxPrice: 1800, minPrice: 1500, defPrice: 1650, manageCoe: 2.1 },
|
||
4: { code: 'C9-1-5', name: '正高级工程师或资深专家', maxPrice: 2500, minPrice: 2000, defPrice: 2250, manageCoe: 2 },
|
||
5: { code: 'C9-2-1', name: '二级造价工程师且具备中级工程师资格', maxPrice: 1500, minPrice: 1200, defPrice: 1350, manageCoe: 2.2 },
|
||
6: { code: 'C9-3-1', name: '一级造价工程师且具备中级工程师资格', maxPrice: 1800, minPrice: 1500, defPrice: 1650, manageCoe: 2.1 },
|
||
7: { code: 'C9-3-2', name: '一级造价工程师且具备高级工程师资格', maxPrice: 2000, minPrice: 1800, defPrice: 1900, manageCoe: 2.05 },
|
||
};
|
||
|
||
export const additionalWorkList = ['人员驻场服务及其他附加工作', '咨询服务协调工作'];
|
||
|
||
let costScaleCal = [
|
||
{ code: 'C1-1', staLine: 0, endLine: 100, basic: { staPrice: 0, rate: 0.01 }, optional: { staPrice: 0, rate: 0.002 } },
|
||
{ code: 'C1-2', staLine: 100, endLine: 300, basic: { staPrice: 10000, rate: 0.008 }, optional: { staPrice: 2000, rate: 0.0016 } },
|
||
{ code: 'C1-3', staLine: 300, endLine: 500, basic: { staPrice: 26000, rate: 0.005 }, optional: { staPrice: 5200, rate: 0.001 } },
|
||
{ code: 'C1-4', staLine: 500, endLine: 1000, basic: { staPrice: 36000, rate: 0.004 }, optional: { staPrice: 7200, rate: 0.0008 } },
|
||
{ code: 'C1-5', staLine: 1000, endLine: 5000, basic: { staPrice: 56000, rate: 0.003 }, optional: { staPrice: 11200, rate: 0.0006 } },
|
||
{ code: 'C1-6', staLine: 5000, endLine: 10000, basic: { staPrice: 176000, rate: 0.002 }, optional: { staPrice: 35200, rate: 0.0004 } },
|
||
{ code: 'C1-7', staLine: 10000, endLine: 30000, basic: { staPrice: 276000, rate: 0.0016 }, optional: { staPrice: 55200, rate: 0.00032 } },
|
||
{ code: 'C1-8', staLine: 30000, endLine: 50000, basic: { staPrice: 596000, rate: 0.0013 }, optional: { staPrice: 119200, rate: 0.00026 } },
|
||
{ code: 'C1-9', staLine: 50000, endLine: 100000, basic: { staPrice: 856000, rate: 0.001 }, optional: { staPrice: 171200, rate: 0.0002 } },
|
||
{ code: 'C1-10', staLine: 100000, endLine: 150000, basic: { staPrice: 1356000, rate: 0.0009 }, optional: { staPrice: 271200, rate: 0.00018 } },
|
||
{ code: 'C1-11', staLine: 150000, endLine: 200000, basic: { staPrice: 1806000, rate: 0.0008 }, optional: { staPrice: 361200, rate: 0.00016 } },
|
||
{ code: 'C1-12', staLine: 200000, endLine: 300000, basic: { staPrice: 2206000, rate: 0.0007 }, optional: { staPrice: 441200, rate: 0.00014 } },
|
||
{ code: 'C1-13', staLine: 300000, endLine: 400000, basic: { staPrice: 2906000, rate: 0.0006 }, optional: { staPrice: 581200, rate: 0.00012 } },
|
||
{ code: 'C1-14', staLine: 400000, endLine: 600000, basic: { staPrice: 3506000, rate: 0.0005 }, optional: { staPrice: 701200, rate: 0.0001 } },
|
||
{ code: 'C1-15', staLine: 600000, endLine: 800000, basic: { staPrice: 4506000, rate: 0.0004 }, optional: { staPrice: 901200, rate: 0.00008 } },
|
||
{ code: 'C1-16', staLine: 800000, endLine: 1000000, basic: { staPrice: 5306000, rate: 0.0003 }, optional: { staPrice: 1061200, rate: 0.00006 } },
|
||
{ code: 'C1-17', staLine: 1000000, endLine: null, basic: { staPrice: 5906000, rate: 0.00025 }, optional: { staPrice: 1181200, rate: 0.00005 } },
|
||
];
|
||
|
||
let areaScaleCal = [
|
||
{ code: 'C2-1', staLine: 0, endLine: 50, basic: { staPrice: 0, rate: 200 }, optional: { staPrice: 0, rate: 40 } },
|
||
{ code: 'C2-2', staLine: 50, endLine: 100, basic: { staPrice: 10000, rate: 160 }, optional: { staPrice: 2000, rate: 32 } },
|
||
{ code: 'C2-3', staLine: 100, endLine: 500, basic: { staPrice: 18000, rate: 120 }, optional: { staPrice: 3600, rate: 24 } },
|
||
{ code: 'C2-4', staLine: 500, endLine: 1000, basic: { staPrice: 66000, rate: 80 }, optional: { staPrice: 13200, rate: 16 } },
|
||
{ code: 'C2-5', staLine: 1000, endLine: 5000, basic: { staPrice: 106000, rate: 60 }, optional: { staPrice: 21200, rate: 12 } },
|
||
{ code: 'C2-6', staLine: 5000, endLine: null, basic: { staPrice: 346000, rate: 20 }, optional: { staPrice: 69200, rate: 4 } },
|
||
];
|
||
|
||
|
||
|
||
|
||
|
||
|
||
export type IndustryType = (typeof industryTypeList)[number]['type']
|
||
type DictItem = Record<string, any>
|
||
type DictEntry = { id: string; rawId: string; item: DictItem }
|
||
type DictByIdMap = Record<string, DictItem>
|
||
type BasicFeeFromScaleResult = {
|
||
basic: number
|
||
optional: number
|
||
basicFormula: string
|
||
optionalFormula: string
|
||
}
|
||
|
||
const industryTypeById = new Map(
|
||
industryTypeList.flatMap(item => {
|
||
return [[String(item.id).trim(), item.type]]
|
||
|
||
})
|
||
)
|
||
/**
|
||
* 根据行业的id获取对应专业字段(isRoad/isRailway/isWaterway)。
|
||
* @returns 对应行业字段;未命中时返回 null
|
||
*/
|
||
export const getIndustryTypeValue = (industryId: unknown): IndustryType | null =>
|
||
industryTypeById.get(String(industryId || '').trim()) || null
|
||
|
||
/**
|
||
* 判断字典项是否在指定行业下可用。
|
||
* @returns 是否可用
|
||
*/
|
||
export const isIndustryEnabledByType = (
|
||
item: DictItem | undefined,
|
||
typeValue: IndustryType | null
|
||
): boolean => Boolean(typeValue && item?.[typeValue] === true)
|
||
|
||
// 判断是否为“通用项”(三种行业都适用)。
|
||
const isGenericIndustryItem = (item: Record<string, any> | undefined) =>
|
||
Boolean(item?.isRoad && item?.isRailway && item?.isWaterway)
|
||
|
||
/**
|
||
* 判断专业ID(majorList 的 key)是否属于指定行业范围(可选是否包含通用项)。
|
||
* @returns 是否属于行业范围
|
||
*/
|
||
export const isMajorIdInIndustryScope = (
|
||
majorId: unknown,
|
||
industryCode: unknown,
|
||
includeGeneric = true
|
||
): boolean => {
|
||
const industryType = getIndustryTypeValue(industryCode)
|
||
if (!majorId || !industryType) return false
|
||
const id = String(majorId).trim()
|
||
const majorItem = getMajorDictEntries().find(entry => String(entry.id).trim() === id)?.item
|
||
if (isIndustryEnabledByType(majorItem, industryType)) return true
|
||
|
||
if (!includeGeneric) return false
|
||
return isGenericIndustryItem(majorItem)
|
||
}
|
||
|
||
const isPlainObject = (value: unknown): value is Record<string, any> =>
|
||
Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||
|
||
const hasCodeLike = (value: Record<string, any>) =>
|
||
typeof value.code === 'string'
|
||
|
||
const isDictLeafNode = (value: unknown): value is Record<string, any> =>
|
||
isPlainObject(value) && hasCodeLike(value) && typeof value.name === 'string'
|
||
|
||
// 递归提取字典树中的叶子节点(具有 code + name 的业务项)。
|
||
const collectDictLeafEntries = (
|
||
source: Record<string, any>,
|
||
prefix = ''
|
||
): Array<{ rawId: string; item: Record<string, any> }> => {
|
||
const result: Array<{ rawId: string; item: Record<string, any> }> = []
|
||
if (!isPlainObject(source)) return result
|
||
|
||
for (const [key, value] of Object.entries(source)) {
|
||
const rawId = prefix ? `${prefix}.${key}` : String(key)
|
||
if (isDictLeafNode(value)) {
|
||
result.push({ rawId, item: value })
|
||
continue
|
||
}
|
||
if (isPlainObject(value)) {
|
||
result.push(...collectDictLeafEntries(value, rawId))
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// 计算排序权重:优先用 order,再退化为 rawId 的数值。
|
||
const getItemSortValue = (item: Record<string, any>, rawId: string) => {
|
||
const order = Number(item?.order)
|
||
if (Number.isFinite(order)) return order
|
||
const rawIdNum = Number(rawId)
|
||
if (Number.isFinite(rawIdNum)) return rawIdNum
|
||
return Number.POSITIVE_INFINITY
|
||
}
|
||
|
||
// 按权重与编码排序,保证下拉展示顺序稳定。
|
||
const sortDictEntries = (
|
||
entries: Array<{ id: string; rawId: string; item: Record<string, any> }>
|
||
) =>
|
||
entries.sort((a, b) => {
|
||
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 codeB = String(b.item?.code || b.id)
|
||
return codeA.localeCompare(codeB)
|
||
})
|
||
|
||
// 将原始字典对象转换为扁平 entries 列表。
|
||
const buildDictEntries = (source: Record<string, any>) =>
|
||
sortDictEntries(
|
||
collectDictLeafEntries(source).map(({ rawId, item }) => {
|
||
return {
|
||
id: rawId,
|
||
rawId,
|
||
item
|
||
}
|
||
})
|
||
)
|
||
|
||
/**
|
||
* 获取专业字典的扁平化列表。
|
||
* @returns 专业字典条目列表
|
||
*/
|
||
export const getMajorDictEntries = (): DictEntry[] => buildDictEntries(majorList as Record<string, any>)
|
||
|
||
/**
|
||
* 获取服务字典的扁平化列表。
|
||
* @returns 服务字典条目列表
|
||
*/
|
||
export const getServiceDictEntries = (): DictEntry[] => buildDictEntries(serviceList as Record<string, any>)
|
||
|
||
|
||
/**
|
||
* 构建“专业ID -> 专业项”映射。
|
||
* @returns 专业项映射表
|
||
*/
|
||
export const getMajorDictById = (): DictByIdMap =>
|
||
Object.fromEntries(getMajorDictEntries().map(entry => [entry.id, entry.item]))
|
||
|
||
/**
|
||
* 构建“服务ID -> 服务项”映射。
|
||
* @returns 服务项映射表
|
||
*/
|
||
export const getServiceDictById = (): DictByIdMap =>
|
||
Object.fromEntries(getServiceDictEntries().map(entry => [entry.id, entry.item]))
|
||
|
||
/**
|
||
* 构建“专业编码(code) -> 专业ID”别名映射。
|
||
* @returns 编码到专业ID的别名映射
|
||
*/
|
||
export const getMajorIdAliasMap = (): Map<string, string> =>
|
||
new Map(
|
||
getMajorDictEntries().flatMap(entry => {
|
||
const code = String(entry.item?.code || '')
|
||
return code ? [[code, entry.id]] : []
|
||
})
|
||
)
|
||
|
||
/**
|
||
* 按 ID 或 code 获取专业项(优先 ID,找不到时按 code 别名回查)。
|
||
* @returns 匹配的专业项;未命中时返回 undefined
|
||
*/
|
||
export const getMajorDictItemById = (id: string | number): DictItem | undefined => {
|
||
const key = String(id)
|
||
const dict = getMajorDictById() as DictByIdMap
|
||
if (dict[key]) return dict[key]
|
||
const alias = getMajorIdAliasMap().get(key)
|
||
return alias ? dict[alias] : undefined
|
||
}
|
||
|
||
/**
|
||
* 按 ID 获取服务项。
|
||
* @returns 匹配的服务项;未命中时返回 undefined
|
||
*/
|
||
export const getServiceDictItemById = (id: string | number): DictItem | undefined => {
|
||
const key = String(id)
|
||
const dict = getServiceDictById() as DictByIdMap
|
||
return dict[key]
|
||
}
|
||
|
||
|
||
// 判断数值是否命中分段区间:(staLine, endLine]。
|
||
const inRange = (sv: number, staLine: number, endLine: number | null) =>
|
||
staLine < sv && (endLine == null || sv <= endLine)
|
||
|
||
// 按分段参数计算基础费用。
|
||
const calcScaleFee = (params: {
|
||
staPrice: number
|
||
sv: number
|
||
staLine: number
|
||
rate: number
|
||
multiplier?: number
|
||
}) => {
|
||
const multiplier = params.multiplier ?? 1
|
||
return roundTo(
|
||
toDecimal(params.staPrice).plus(
|
||
toDecimal(params.sv)
|
||
.minus(params.staLine)
|
||
.mul(multiplier)
|
||
.mul(params.rate)
|
||
)
|
||
)
|
||
}
|
||
|
||
// 将费率转成千分数文本(例如 0.012 -> 12‰)。
|
||
const scaleRatePermillage = (rate: number) => roundTo(toDecimal(rate).mul(1000), 2)
|
||
|
||
// 生成“基础费用”计算公式字符串,供前端展示。
|
||
const buildScaleFormula = (params: {
|
||
staPrice: number
|
||
sv: number
|
||
staLine: number
|
||
rate: number
|
||
multiplier?: number
|
||
showPermillage?: boolean
|
||
}) => {
|
||
const multiplier = params.multiplier ?? 1
|
||
const currentValue = toDecimal(params.sv).mul(multiplier).toNumber()
|
||
const staLineValue = toDecimal(params.staLine).mul(multiplier).toNumber()
|
||
const rateText = params.showPermillage ? `${scaleRatePermillage(params.rate)}‰` : params.rate
|
||
if (params.staPrice) {
|
||
return `${numberFormatter(params.staPrice, 0)}+(${numberFormatter(currentValue, 0)}-${numberFormatter(staLineValue, 0)})×${rateText}`
|
||
}
|
||
return `${numberFormatter(currentValue, 0)}×${rateText}`
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 根据规模值与规模类型,计算基础费用及对应公式(返回基础/附加两部分)。
|
||
* @returns 基础费用计算结果;输入非法或未命中区间时返回 null
|
||
*/
|
||
export function getBasicFeeFromScale(
|
||
scaleValue: unknown,
|
||
scaleType: 'cost' | 'area'
|
||
): BasicFeeFromScaleResult | null {
|
||
const sv = Number(scaleValue)
|
||
if (!Number.isFinite(sv) || sv <= 0) return null
|
||
|
||
if (scaleType === 'cost') {
|
||
const targetRange = costScaleCal.find(f => inRange(sv, f.staLine, f.endLine))
|
||
if (!targetRange) return null
|
||
return {
|
||
basic: calcScaleFee({
|
||
staPrice: targetRange.basic.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.basic.rate,
|
||
multiplier: 10000
|
||
}),
|
||
optional: calcScaleFee({
|
||
staPrice: targetRange.optional.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.optional.rate,
|
||
multiplier: 10000
|
||
}),
|
||
basicFormula: buildScaleFormula({
|
||
staPrice: targetRange.basic.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.basic.rate,
|
||
multiplier: 10000,
|
||
showPermillage: true
|
||
}),
|
||
optionalFormula: buildScaleFormula({
|
||
staPrice: targetRange.optional.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.optional.rate,
|
||
multiplier: 10000,
|
||
showPermillage: true
|
||
})
|
||
}
|
||
}
|
||
|
||
if (scaleType === 'area') {
|
||
const targetRange = areaScaleCal.find(f => inRange(sv, f.staLine, f.endLine))
|
||
if (!targetRange) return null
|
||
return {
|
||
basic: calcScaleFee({
|
||
staPrice: targetRange.basic.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.basic.rate
|
||
}),
|
||
optional: calcScaleFee({
|
||
staPrice: targetRange.optional.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.optional.rate
|
||
}),
|
||
basicFormula: buildScaleFormula({
|
||
staPrice: targetRange.basic.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.basic.rate
|
||
}),
|
||
optionalFormula: buildScaleFormula({
|
||
staPrice: targetRange.optional.staPrice,
|
||
sv,
|
||
staLine: targetRange.staLine,
|
||
rate: targetRange.optional.rate
|
||
})
|
||
}
|
||
}
|
||
|
||
return null
|
||
}
|
||
|
||
|
||
/**
|
||
* 导出入口:生成 Excel 并触发保存(优先使用 File System Access API)。
|
||
* @returns 导出流程完成后的 Promise
|
||
*/
|
||
export async function exportFile(fileName: string, data: any): Promise<void> {
|
||
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.hcode = url1;
|
||
a.download = `${fileName}.xlsx`;
|
||
a.click();
|
||
URL.revokeObjectURL(url1);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
|
||
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: '下标' }] };
|
||
console.log(data)
|
||
try {
|
||
// 获取模板
|
||
let templateExcel = 'template20260226001test010';
|
||
let templateUrl = `./${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表');
|
||
yz01_sheet.headerFooter.oddHeader = yz01_sheet.headerFooter.oddHeader.replace(/×××/g, data.name);
|
||
|
||
// 更新封面
|
||
fm_sheet.getRow(2).getCell(1).value = data.name;
|
||
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) {
|
||
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 ml_slotRow = 14;
|
||
let ml_number = 1;
|
||
let allServices = [];
|
||
let allAddtional = {};
|
||
let allReserve = {};
|
||
let allMajors = {};
|
||
data.scale?.forEach(sci => {
|
||
allMajors[sci.major] = { [data.contracts.length]: sci };
|
||
});
|
||
data.contracts.forEach((ci, index) => {
|
||
// 记录allMajors
|
||
ci.scale?.forEach(sci => {
|
||
if (allMajors[sci.major]) {
|
||
allMajors[sci.major][index] = sci;
|
||
} else {
|
||
allMajors[sci.major] = { [index]: sci };
|
||
}
|
||
});
|
||
|
||
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);
|
||
});
|
||
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);
|
||
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;
|
||
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表`);
|
||
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 || 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);
|
||
// 更新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(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 = numberFormatter(sumObj.person_num, 0);
|
||
sheet_4.getRow(3).getCell(5).value = numberFormatter(sumObj.work_day, 2);
|
||
sheet_4.getRow(3).getCell(6).value = numberFormatter(sumObj.fee, 2);
|
||
sheet_4_1.getRow(3).getCell(4).value = '/';
|
||
sheet_4_1.getRow(3).getCell(5).value = '/';
|
||
sheet_4_1.getRow(3).getCell(6).value = '/';
|
||
sheet_4_1.getRow(3).getCell(7).value = numberFormatter(sumObj.person_num, 0);
|
||
sheet_4_1.getRow(3).getCell(8).value = numberFormatter(sumObj.work_day, 2);
|
||
sheet_4_1.getRow(3).getCell(9).value = numberFormatter(sumObj.fee, 2);
|
||
}
|
||
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(3).value = '/';
|
||
sheet_5.getRow(3).getCell(4).value = '/';
|
||
sheet_5.getRow(3).getCell(5).value = '/';
|
||
sheet_5.getRow(3).getCell(6).value = numberFormatter((ci.method5.addtional?.reduce((a, b) => a + b.m5.fee, 0) || 0) + (ci.method5.reserve?.fee || 0), 2);
|
||
}
|
||
|
||
// 更新目录的第三部分
|
||
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;
|
||
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) {
|
||
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.code;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
if (sobj.method1) {
|
||
targetRow.getCell(4).value = numberFormatter(sobj.method1.fee, 2);
|
||
m1Sum += sobj.method1.fee;
|
||
}
|
||
if (sobj.method2) {
|
||
targetRow.getCell(5).value = numberFormatter(sobj.method2.fee, 2);
|
||
m2Sum += sobj.method2.fee;
|
||
}
|
||
if (sobj.method3) {
|
||
targetRow.getCell(6).value = numberFormatter(sobj.method3.fee, 2);
|
||
m3Sum += sobj.method3.fee;
|
||
}
|
||
if (sobj.method4) {
|
||
targetRow.getCell(7).value = numberFormatter(sobj.method4.fee, 2);
|
||
m4Sum += sobj.method4.fee;
|
||
}
|
||
targetRow.getCell(8).value = numberFormatter(sobj.fee, 2);
|
||
serviceSum += sobj.fee;
|
||
});
|
||
if (sobj.method1 || sobj.method2) {
|
||
cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => {
|
||
targetRow.getCell(1).value = num_2++;
|
||
targetRow.getCell(2).value = serviceX.code;
|
||
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(8).value = numberFormatter(sobj.method1.basicFee, 2);
|
||
targetRow.getCell(9).value = numberFormatter(sobj.method1.fee, 2);
|
||
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;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
targetRow.getCell(4).value = numberFormatter(sobj.method1.cost, 2);
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(sobj.method1.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = '/';
|
||
targetRow.getCell(8).value = numberFormatter(sobj.method1.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(sobj.method1.basicFee, 2);
|
||
});
|
||
}
|
||
if (sobj.method2) {
|
||
targetRow.getCell(10).value = numberFormatter(sobj.method2.basicFee, 2);
|
||
targetRow.getCell(11).value = numberFormatter(sobj.method2.fee, 2);
|
||
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;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
targetRow.getCell(4).value = numberFormatter(sobj.method2.area, 3);
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(sobj.method2.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = '/';
|
||
targetRow.getCell(8).value = numberFormatter(sobj.method2.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(sobj.method2.basicFee, 2);
|
||
});
|
||
}
|
||
});
|
||
if (serviceX.mutiple) {
|
||
const maxProNum = Math.max(sobj.method1 ? sobj.method1.proAmount : 0, sobj.method2 ? sobj.method2.proAmount : 0);
|
||
for (let pi = 1; pi <= maxProNum; pi++) {
|
||
const m1PI = sobj.method1 ? sobj.method1.det.filter(m => m.proNum == pi) : [];
|
||
const m2PI = sobj.method2 ? sobj.method2.det.filter(m => m.proNum == pi) : [];
|
||
let m1PISum = m1PI.reduce((a, b) => {
|
||
return {
|
||
cost: addNumbers(a.cost, toFiniteNumber(b.cost)),
|
||
basicFee_basic: addNumbers(a.basicFee_basic, toFiniteNumber(b.basicFee_basic)),
|
||
basicFee_optional: addNumbers(a.basicFee_optional, toFiniteNumber(b.basicFee_optional)),
|
||
basicFee: addNumbers(a.basicFee, toFiniteNumber(b.basicFee)),
|
||
fee: addNumbers(a.fee, toFiniteNumber(b.fee)),
|
||
}
|
||
}, { cost: 0, basicFee_basic: 0, basicFee_optional: 0, basicFee: 0, fee: 0 });
|
||
let m2PISum = m2PI.reduce((a, b) => {
|
||
return {
|
||
area: addNumbers(a.area, toFiniteNumber(b.area)),
|
||
basicFee_basic: addNumbers(a.basicFee_basic, toFiniteNumber(b.basicFee_basic)),
|
||
basicFee_optional: addNumbers(a.basicFee_optional, toFiniteNumber(b.basicFee_optional)),
|
||
basicFee: addNumbers(a.basicFee, toFiniteNumber(b.basicFee)),
|
||
fee: addNumbers(a.fee, toFiniteNumber(b.fee)),
|
||
}
|
||
}, { area: 0, basicFee_basic: 0, basicFee_optional: 0, basicFee: 0, fee: 0 });
|
||
cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => {
|
||
targetRow.getCell(1).value = num_2++;
|
||
targetRow.getCell(2).value = serviceX.code + '-' + pi;
|
||
targetRow.getCell(3).value = '项目' + pi;
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = '/';
|
||
targetRow.getCell(7).value = '/';
|
||
if (m1PI.length) {
|
||
targetRow.getCell(8).value = numberFormatter(m1PISum.basicFee, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m1PISum.fee, 2);
|
||
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 + '-' + pi;
|
||
targetRow.getCell(3).value = '项目' + pi;
|
||
targetRow.getCell(4).value = numberFormatter(m1PISum.cost, 2);
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(m1PISum.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = '/';
|
||
targetRow.getCell(8).value = numberFormatter(m1PISum.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m1PISum.basicFee, 2);
|
||
});
|
||
}
|
||
if (m2PI.length) {
|
||
targetRow.getCell(10).value = numberFormatter(m2PISum.basicFee, 2);
|
||
targetRow.getCell(11).value = numberFormatter(m2PISum.fee, 2);
|
||
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 + '-' + pi;
|
||
targetRow.getCell(3).value = '项目' + pi;
|
||
targetRow.getCell(4).value = numberFormatter(m2PISum.area, 3);
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(m2PISum.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = '/';
|
||
targetRow.getCell(8).value = numberFormatter(m2PISum.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m2PISum.basicFee, 2);
|
||
});
|
||
}
|
||
});
|
||
let det1 = m1PI.map(m => m.major);
|
||
let det2 = m2PI.map(m => m.major);
|
||
let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => majorList[a].order - majorList[b].order).map(m => {
|
||
let d1index = det1.indexOf(m);
|
||
let d2index = det2.indexOf(m);
|
||
return {
|
||
major: m,
|
||
mth1: d1index < 0 ? null : m1PI[d1index],
|
||
mth2: d2index < 0 ? null : m2PI[d2index],
|
||
};
|
||
});
|
||
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.code + '-' + pi + '-' + (mindex + 1);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
if (m.mth1) {
|
||
targetRow.getCell(4).value = numberFormatter(m.mth1.serviceCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(m.mth1.majorCoe, 3);
|
||
targetRow.getCell(6).value = numberFormatter(m.mth1.processCoe, 3);
|
||
targetRow.getCell(7).value = numberFormatter(m.mth1.proportion, 2);
|
||
targetRow.getCell(8).value = numberFormatter(m.mth1.basicFee, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth1.fee, 2);
|
||
targetRow.getCell(10).value = '/';
|
||
targetRow.getCell(11).value = '/';
|
||
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 + '-' + pi + '-' + (mindex + 1);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
targetRow.getCell(4).value = numberFormatter(m.mth1.cost, 2);
|
||
targetRow.getCell(5).value = m.mth1.basicFormula;
|
||
targetRow.getCell(6).value = numberFormatter(m.mth1.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = m.mth1.optionalFormula;
|
||
targetRow.getCell(8).value = numberFormatter(m.mth1.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth1.basicFee, 2);
|
||
});
|
||
} else {
|
||
targetRow.getCell(4).value = numberFormatter(m.mth2.serviceCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(m.mth2.majorCoe, 3);
|
||
targetRow.getCell(6).value = numberFormatter(m.mth2.processCoe, 3);
|
||
targetRow.getCell(7).value = numberFormatter(m.mth2.proportion, 2);
|
||
targetRow.getCell(8).value = '/';
|
||
targetRow.getCell(9).value = '/';
|
||
targetRow.getCell(10).value = numberFormatter(m.mth2.basicFee, 2);
|
||
targetRow.getCell(11).value = numberFormatter(m.mth2.fee, 2);
|
||
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 + '-' + pi + '-' + (mindex + 1);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
targetRow.getCell(4).value = numberFormatter(m.mth2.area, 3);
|
||
targetRow.getCell(5).value = m.mth2.basicFormula;
|
||
targetRow.getCell(6).value = numberFormatter(m.mth2.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = m.mth2.optionalFormula;
|
||
targetRow.getCell(8).value = numberFormatter(m.mth2.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth2.basicFee, 2);
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
} else {
|
||
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) => majorList[a].order - majorList[b].order).map(m => {
|
||
let d1index = det1.indexOf(m);
|
||
let d2index = det2.indexOf(m);
|
||
return {
|
||
major: m,
|
||
mth1: d1index < 0 ? null : sobj.method1.det[d1index],
|
||
mth2: d2index < 0 ? null : sobj.method2.det[d2index],
|
||
};
|
||
});
|
||
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.code + '-' + (mindex + 1);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
if (m.mth1) {
|
||
targetRow.getCell(4).value = numberFormatter(m.mth1.serviceCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(m.mth1.majorCoe, 3);
|
||
targetRow.getCell(6).value = numberFormatter(m.mth1.processCoe, 3);
|
||
targetRow.getCell(7).value = numberFormatter(m.mth1.proportion, 2);
|
||
targetRow.getCell(8).value = numberFormatter(m.mth1.basicFee, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth1.fee, 2);
|
||
targetRow.getCell(10).value = '/';
|
||
targetRow.getCell(11).value = '/';
|
||
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);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
targetRow.getCell(4).value = numberFormatter(m.mth1.cost, 2);
|
||
targetRow.getCell(5).value = m.mth1.basicFormula;
|
||
targetRow.getCell(6).value = numberFormatter(m.mth1.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = m.mth1.optionalFormula;
|
||
targetRow.getCell(8).value = numberFormatter(m.mth1.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth1.basicFee, 2);
|
||
});
|
||
} else {
|
||
targetRow.getCell(4).value = numberFormatter(m.mth2.serviceCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(m.mth2.majorCoe, 3);
|
||
targetRow.getCell(6).value = numberFormatter(m.mth2.processCoe, 3);
|
||
targetRow.getCell(7).value = numberFormatter(m.mth2.proportion, 2);
|
||
targetRow.getCell(8).value = '/';
|
||
targetRow.getCell(9).value = '/';
|
||
targetRow.getCell(10).value = numberFormatter(m.mth2.basicFee, 2);
|
||
targetRow.getCell(11).value = numberFormatter(m.mth2.fee, 2);
|
||
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);
|
||
targetRow.getCell(3).value = majorX.name;
|
||
targetRow.getCell(4).value = numberFormatter(m.mth2.area, 3);
|
||
targetRow.getCell(5).value = m.mth2.basicFormula;
|
||
targetRow.getCell(6).value = numberFormatter(m.mth2.basicFee_basic, 2);
|
||
targetRow.getCell(7).value = m.mth2.optionalFormula;
|
||
targetRow.getCell(8).value = numberFormatter(m.mth2.basicFee_optional, 2);
|
||
targetRow.getCell(9).value = numberFormatter(m.mth2.basicFee, 2);
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
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.code;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = '/';
|
||
targetRow.getCell(7).value = numberFormatter(sobj.method3.basicFee, 2);
|
||
targetRow.getCell(8).value = '/';
|
||
targetRow.getCell(9).value = numberFormatter(sobj.method3.fee, 2);
|
||
});
|
||
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.code;
|
||
targetRow.getCell(3).value = taskX.name + (taskX.desc ? `(${taskX.desc})` : '');
|
||
targetRow.getCell(4).value = taskX.basicParam;
|
||
targetRow.getCell(5).value = numberFormatter(tobj.price, 2);
|
||
targetRow.getCell(6).value = numberFormatter(tobj.amount, 2);
|
||
targetRow.getCell(7).value = numberFormatter(tobj.basicFee, 2);
|
||
targetRow.getCell(8).value = numberFormatter(tobj.serviceCoe, 3);
|
||
targetRow.getCell(9).value = numberFormatter(tobj.fee, 2);
|
||
});
|
||
});
|
||
}
|
||
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.code;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
targetRow.getCell(4).value = numberFormatter(sobj.method4.person_num, 0);
|
||
targetRow.getCell(5).value = numberFormatter(sobj.method4.work_day, 2);
|
||
targetRow.getCell(6).value = numberFormatter(sobj.method4.fee, 2);
|
||
});
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = serviceX.code;
|
||
targetRow.getCell(3).value = serviceX.name;
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = '/';
|
||
targetRow.getCell(7).value = numberFormatter(sobj.method4.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(sobj.method4.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(sobj.method4.fee, 2);
|
||
});
|
||
sobj.method4.det.forEach((eobj, eindex) => {
|
||
const expertX = expertList[eobj.expert];
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = expertX.code;
|
||
targetRow.getCell(3).value = expertX.name;
|
||
targetRow.getCell(4).value = `${expertX.minPrice}~${expertX.maxPrice}`;
|
||
targetRow.getCell(5).value = `${roundTo(toDecimal(toFiniteNumber(expertX.minPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}~${roundTo(toDecimal(toFiniteNumber(expertX.maxPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}`;
|
||
targetRow.getCell(6).value = numberFormatter(eobj.price, 2);
|
||
targetRow.getCell(7).value = numberFormatter(eobj.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(eobj.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(eobj.fee, 2);
|
||
targetRow.getCell(10).value = eobj.remark;
|
||
});
|
||
});
|
||
}
|
||
});
|
||
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.code;
|
||
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.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.code;
|
||
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 = numberFormatter(addobj.fee, 2);
|
||
if (addobj.m4) {
|
||
cusInsertRowFunc(4 + num_4, [sheet_4.getRow(4)], sheet_4, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4++;
|
||
targetRow.getCell(2).value = addobj.code;
|
||
targetRow.getCell(3).value = addobj.name;
|
||
targetRow.getCell(4).value = numberFormatter(addobj.m4.person_num, 0);
|
||
targetRow.getCell(5).value = numberFormatter(addobj.m4.work_day, 2);
|
||
targetRow.getCell(6).value = numberFormatter(addobj.m4.fee, 2);
|
||
});
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = addobj.code;
|
||
targetRow.getCell(3).value = addobj.name;
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = '/';
|
||
targetRow.getCell(7).value = numberFormatter(addobj.m4.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(addobj.m4.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(addobj.m4.fee, 2);
|
||
});
|
||
addobj.m4.det.forEach((eobj, eindex) => {
|
||
const expertX = expertList[eobj.expert];
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = expertX.code;
|
||
targetRow.getCell(3).value = expertX.name;
|
||
targetRow.getCell(4).value = `${expertX.minPrice}~${expertX.maxPrice}`;
|
||
targetRow.getCell(5).value = `${roundTo(toDecimal(toFiniteNumber(expertX.minPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}~${roundTo(toDecimal(toFiniteNumber(expertX.maxPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}`;
|
||
targetRow.getCell(6).value = numberFormatter(eobj.price, 2);
|
||
targetRow.getCell(7).value = numberFormatter(eobj.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(eobj.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(eobj.fee, 2);
|
||
targetRow.getCell(10).value = eobj.remark;
|
||
});
|
||
});
|
||
}
|
||
if (addobj.m5) {
|
||
cusInsertRowFunc(4 + num_5, [sheet_5.getRow(4)], sheet_5, (targetRow) => {
|
||
num_5++;
|
||
targetRow.getCell(1).value = addobj.code;
|
||
targetRow.getCell(2).value = addobj.name;
|
||
targetRow.getCell(3).value = '/';
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(addobj.m5.fee, 2);
|
||
});
|
||
const tmpJSS = JSON.stringify(addobj.code);
|
||
addobj.m5.det.forEach((eobj, eindex) => {
|
||
let code = JSON.parse(tmpJSS);
|
||
code.richText.push({ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '-' + (eindex + 1) });
|
||
cusInsertRowFunc(4 + num_5, [sheet_5.getRow(4)], sheet_5, (targetRow) => {
|
||
num_5++;
|
||
targetRow.getCell(1).value = code;
|
||
targetRow.getCell(2).value = eobj.name;
|
||
targetRow.getCell(3).value = eobj.unit;
|
||
targetRow.getCell(4).value = numberFormatter(eobj.amount, 3);
|
||
targetRow.getCell(5).value = numberFormatter(eobj.price, 2);
|
||
targetRow.getCell(6).value = numberFormatter(eobj.fee, 2);
|
||
targetRow.getCell(7).value = eobj.remark;
|
||
});
|
||
});
|
||
}
|
||
});
|
||
});
|
||
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 = '';
|
||
targetRow.getCell(3).value = '附加工作小计';
|
||
targetRow.getCell(4).value = '';
|
||
targetRow.getCell(5).value = '';
|
||
targetRow.getCell(6).value = '';
|
||
targetRow.getCell(7).value = '';
|
||
targetRow.getCell(8).value = numberFormatter(ci.addtional.fee, 2);
|
||
});
|
||
}
|
||
if (ci.reserve) {
|
||
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.reserve.code;
|
||
targetRow.getCell(3).value = ci.reserve.name;
|
||
let tmpArr = [];
|
||
if (ci.reserve.m0) tmpArr.push(`按上述小计及附加工作费之和的${ci.reserve.m0.coe}计得${ci.reserve.m0.fee}元`);
|
||
if (ci.reserve.m4) tmpArr.push(`按工时法计得${ci.reserve.m4.fee}元`);
|
||
if (ci.reserve.m5) tmpArr.push(`按数量单价计得${ci.reserve.m5.fee}元`);
|
||
targetRow.getCell(4).value = tmpArr.join(';');
|
||
targetRow.getCell(8).value = numberFormatter(ci.reserve.fee, 2);
|
||
});
|
||
if (ci.reserve.m4) {
|
||
cusInsertRowFunc(4 + num_4, [sheet_4.getRow(4)], sheet_4, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4++;
|
||
targetRow.getCell(2).value = ci.reserve.code;
|
||
targetRow.getCell(3).value = ci.reserve.name;
|
||
targetRow.getCell(4).value = numberFormatter(ci.reserve.m4.person_num, 0);
|
||
targetRow.getCell(5).value = numberFormatter(ci.reserve.m4.work_day, 2);
|
||
targetRow.getCell(6).value = numberFormatter(ci.reserve.m4.fee, 2);
|
||
});
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = ci.reserve.code;
|
||
targetRow.getCell(3).value = ci.reserve.name;
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = '/';
|
||
targetRow.getCell(7).value = numberFormatter(ci.reserve.m4.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(ci.reserve.m4.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(ci.reserve.m4.fee, 2);
|
||
});
|
||
ci.reserve.m4.det.forEach((eobj, eindex) => {
|
||
const expertX = expertList[eobj.expert];
|
||
cusInsertRowFunc(4 + num_4_1, [sheet_4_1.getRow(4)], sheet_4_1, (targetRow) => {
|
||
targetRow.getCell(1).value = num_4_1++;
|
||
targetRow.getCell(2).value = expertX.code;
|
||
targetRow.getCell(3).value = expertX.name;
|
||
targetRow.getCell(4).value = `${expertX.minPrice}~${expertX.maxPrice}`;
|
||
targetRow.getCell(5).value = `${roundTo(toDecimal(toFiniteNumber(expertX.minPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}~${roundTo(toDecimal(toFiniteNumber(expertX.maxPrice)).mul(toFiniteNumber(expertX.manageCoe)), 0)}`;
|
||
targetRow.getCell(6).value = numberFormatter(eobj.price, 2);
|
||
targetRow.getCell(7).value = numberFormatter(eobj.person_num, 0);
|
||
targetRow.getCell(8).value = numberFormatter(eobj.work_day, 2);
|
||
targetRow.getCell(9).value = numberFormatter(eobj.fee, 2);
|
||
targetRow.getCell(10).value = eobj.remark;
|
||
});
|
||
});
|
||
}
|
||
if (ci.reserve.m5) {
|
||
cusInsertRowFunc(4 + num_5, [sheet_5.getRow(4)], sheet_5, (targetRow) => {
|
||
num_5++;
|
||
targetRow.getCell(1).value = ci.reserve.code;
|
||
targetRow.getCell(2).value = ci.reserve.name;
|
||
targetRow.getCell(3).value = '/';
|
||
targetRow.getCell(4).value = '/';
|
||
targetRow.getCell(5).value = '/';
|
||
targetRow.getCell(6).value = numberFormatter(ci.reserve.m5.fee, 2);
|
||
});
|
||
const tmpJSS = JSON.stringify(ci.reserve.code);
|
||
ci.reserve.m5.det.forEach((eobj, eindex) => {
|
||
let code = JSON.parse(tmpJSS);
|
||
code.richText.push({ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '-' + (eindex + 1) });
|
||
cusInsertRowFunc(4 + num_5, [sheet_5.getRow(4)], sheet_5, (targetRow) => {
|
||
num_5++;
|
||
targetRow.getCell(1).value = code;
|
||
targetRow.getCell(2).value = eobj.name;
|
||
targetRow.getCell(3).value = eobj.unit;
|
||
targetRow.getCell(4).value = numberFormatter(eobj.amount, 3);
|
||
targetRow.getCell(5).value = numberFormatter(eobj.price, 2);
|
||
targetRow.getCell(6).value = numberFormatter(eobj.fee, 2);
|
||
targetRow.getCell(7).value = eobj.remark;
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
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 = numberFormatter(ci.fee, 2);
|
||
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' };
|
||
|
||
if (sheet_2) {
|
||
sheet_2.spliceRows(4, 1);
|
||
sheet_2.mergeCells(3 + num_2, 2, 3 + num_2, 11);
|
||
sheet_2.getRow(3 + num_2).height = 100;
|
||
sheet_2.getRow(3 + num_2).getCell(2).border.right = { style: 'thin' };
|
||
if (sheet_2_1) {
|
||
sheet_2_1.spliceRows(4, 1);
|
||
sheet_2_1.mergeCells(3 + num_2_1, 2, 3 + num_2_1, 9);
|
||
sheet_2_1.getRow(3 + num_2_1).height = 100;
|
||
sheet_2_1.getRow(3 + num_2_1).getCell(2).border.right = { style: 'thin' };
|
||
}
|
||
if (sheet_2_2) {
|
||
sheet_2_2.spliceRows(4, 1);
|
||
sheet_2_2.mergeCells(3 + num_2_2, 2, 3 + num_2_2, 9);
|
||
sheet_2_2.getRow(3 + num_2_2).height = 100;
|
||
sheet_2_2.getRow(3 + num_2_2).getCell(2).border.right = { style: 'thin' };
|
||
}
|
||
}
|
||
|
||
if (sheet_3) {
|
||
sheet_3.spliceRows(3, 1);
|
||
sheet_3.mergeCells(2 + num_3, 2, 2 + num_3, 9);
|
||
sheet_3.getRow(2 + num_3).height = 100;
|
||
sheet_3.getRow(2 + num_3).getCell(2).border.right = { style: 'thin' };
|
||
}
|
||
|
||
if (sheet_4) {
|
||
sheet_4.spliceRows(4, 1);
|
||
sheet_4.getRow(2).height = 20.25;
|
||
sheet_4_1.spliceRows(4, 1);
|
||
sheet_4_1.mergeCells(3 + num_4_1, 2, 3 + num_4_1, 10);
|
||
sheet_4_1.getRow(3 + num_4_1).height = 100;
|
||
sheet_4_1.getRow(3 + num_4_1).getCell(2).border.right = { style: 'thin' };
|
||
}
|
||
|
||
if (sheet_5) {
|
||
sheet_5.spliceRows(4, 1);
|
||
sheet_5.getRow(2).height = 20.25;
|
||
}
|
||
|
||
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(2).value) sheet_1.getRow(ci.services.length + 3 + i).getCell(9).style.font.size = 22;
|
||
}
|
||
}
|
||
});
|
||
|
||
allServices.sort((a, b) => serviceList[a.id].order - serviceList[b.id].order);
|
||
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.code;
|
||
targetRow.getCell(i * 7 + 3).value = serviceX.name;
|
||
targetRow.getCell(i * 7 + 4).value = numberFormatter(s.contracts[i * 4], 2);
|
||
targetRow.getCell(i * 7 + 5).value = numberFormatter(s.contracts[i * 4 + 1], 2);
|
||
targetRow.getCell(i * 7 + 6).value = numberFormatter(s.contracts[i * 4 + 2], 2);
|
||
siSum = addNumbers(
|
||
siSum,
|
||
toFiniteNumber(s.contracts[i * 4]),
|
||
toFiniteNumber(s.contracts[i * 4 + 1]),
|
||
toFiniteNumber(s.contracts[i * 4 + 2])
|
||
);
|
||
if (i == yz01Num - 1 && yz01Mod == 0) {
|
||
targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2);
|
||
} else {
|
||
targetRow.getCell(i * 7 + 7).value = numberFormatter(s.contracts[i * 4 + 3], 2);
|
||
siSum = addNumbers(siSum, toFiniteNumber(s.contracts[i * 4 + 3]));
|
||
}
|
||
}
|
||
if (yz01Mod) {
|
||
targetRow.getCell(yz01Num * 7 + 1).value = sindex + 1;
|
||
targetRow.getCell(yz01Num * 7 + 2).value = serviceX.code;
|
||
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 = numberFormatter(s.contracts[yz01Num * 4], 2);
|
||
siSum = addNumbers(siSum, toFiniteNumber(s.contracts[yz01Num * 4]));
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2);
|
||
} else {
|
||
targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(s.contracts[yz01Num * 4], 2);
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(s.contracts[yz01Num * 4 + 1], 2);
|
||
siSum = addNumbers(
|
||
siSum,
|
||
toFiniteNumber(s.contracts[yz01Num * 4]),
|
||
toFiniteNumber(s.contracts[yz01Num * 4 + 1])
|
||
);
|
||
targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
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].code;
|
||
targetRow.getCell(i * 7 + 3).value = allAddtional[firstNum].name;
|
||
targetRow.getCell(i * 7 + 4).value = numberFormatter(allAddtional[i * 4]?.fee, 2);
|
||
targetRow.getCell(i * 7 + 5).value = numberFormatter(allAddtional[i * 4 + 1]?.fee, 2);
|
||
targetRow.getCell(i * 7 + 6).value = numberFormatter(allAddtional[i * 4 + 2]?.fee, 2);
|
||
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 = numberFormatter(allAddtional[i * 4 + 3]?.fee, 2);
|
||
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].code;
|
||
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 = numberFormatter(allAddtional[yz01Num * 4]?.fee, 2);
|
||
siSum = addNumbers(siSum, toFiniteNumber(allAddtional[yz01Num * 4]?.fee));
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2);
|
||
} else {
|
||
targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(allAddtional[yz01Num * 4]?.fee, 2);
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(allAddtional[yz01Num * 4 + 1]?.fee, 2);
|
||
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].code;
|
||
targetRow.getCell(i * 7 + 3).value = allReserve[firstNum].name;
|
||
targetRow.getCell(i * 7 + 4).value = numberFormatter(allReserve[i * 4]?.fee, 2);
|
||
targetRow.getCell(i * 7 + 5).value = numberFormatter(allReserve[i * 4 + 1]?.fee, 2);
|
||
targetRow.getCell(i * 7 + 6).value = numberFormatter(allReserve[i * 4 + 2]?.fee, 2);
|
||
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 = numberFormatter(allReserve[i * 4 + 3]?.fee, 2);
|
||
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].code;
|
||
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 = numberFormatter(allReserve[yz01Num * 4]?.fee, 2);
|
||
siSum = addNumbers(siSum, toFiniteNumber(allReserve[yz01Num * 4]?.fee));
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2);
|
||
} else {
|
||
targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(allReserve[yz01Num * 4]?.fee, 2);
|
||
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(allReserve[yz01Num * 4 + 1]?.fee, 2);
|
||
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 = numberFormatter(data.contracts[i * 4]?.fee, 2);
|
||
yz01SumRow.getCell(i * 7 + 5).value = numberFormatter(data.contracts[i * 4 + 1]?.fee, 2);
|
||
yz01SumRow.getCell(i * 7 + 6).value = numberFormatter(data.contracts[i * 4 + 2]?.fee, 2);
|
||
if (i == yz01Num - 1 && yz01Mod == 0) {
|
||
yz01SumRow.getCell(i * 7 + 7).value = numberFormatter(data.fee, 2);
|
||
} else {
|
||
yz01SumRow.getCell(i * 7 + 7).value = numberFormatter(data.contracts[i * 4 + 3]?.fee, 2);
|
||
}
|
||
}
|
||
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 = numberFormatter(data.contracts[yz01Num * 4]?.fee, 2);
|
||
yz01SumRow.getCell(yz01Num * 7 + 5).value = numberFormatter(data.fee, 2);
|
||
} else {
|
||
yz01SumRow.getCell(yz01Num * 7 + 4).value = numberFormatter(data.contracts[yz01Num * 4]?.fee, 2);
|
||
yz01SumRow.getCell(yz01Num * 7 + 5).value = numberFormatter(data.contracts[yz01Num * 4 + 1]?.fee, 2);
|
||
yz01SumRow.getCell(yz01Num * 7 + 6).value = numberFormatter(data.fee, 2);
|
||
}
|
||
}
|
||
|
||
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}预算(元)`;
|
||
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 + 3).value = `预算小计(元)`;
|
||
yz01_lastCol = i * 7 + 4;
|
||
} else {
|
||
yz01_sheet.getRow(1).getCell(i * 7 + 4 + 3).value = `${data.contracts[i * 4 + 3].name}预算(元)`;
|
||
}
|
||
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 = `预算小计(元)`;
|
||
yz01_lastCol = yz01Num * 7 + 4 + i;
|
||
} else {
|
||
yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算(元)`;
|
||
}
|
||
}
|
||
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' };
|
||
}
|
||
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表');
|
||
workbook.removeWorksheet('预i-2-1表');
|
||
workbook.removeWorksheet('预i-2-2表');
|
||
workbook.removeWorksheet('预i-3表');
|
||
workbook.removeWorksheet('预i-4表');
|
||
workbook.removeWorksheet('预i-4-1表');
|
||
workbook.removeWorksheet('预i-5表');
|
||
|
||
// 编辑辅01/02/03表内容
|
||
// 辅01表
|
||
if (Object.keys(allMajors).length) {
|
||
let f01_sheet = workbook.getWorksheet('辅01表');
|
||
let f01Mod = (data.contracts.length + 1) % 3;
|
||
let f01Num = (data.contracts.length + 1 - 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);
|
||
if (f01Mod == 0 && i == f01Num - 1) {
|
||
f01_sheet.getRow(1).getCell(i * 10 + 8).value = '项目小计';
|
||
} else {
|
||
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 = f01Mod == 1 ? '项目小计' : 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 = '项目小计';
|
||
}
|
||
}
|
||
let num_f01 = 1;
|
||
Object.keys(allMajors).sort((a, b) => (a < 0 ? a : majorList[a].order) - (b < 0 ? b : majorList[b].order)).forEach(majorid => {
|
||
let scaleX = allMajors[majorid];
|
||
let code;
|
||
let name;
|
||
let hasCost;
|
||
let hasArea;
|
||
if (majorid == -1) {
|
||
code = '';
|
||
name = '总投资';
|
||
hasCost = true;
|
||
hasArea = false;
|
||
} else {
|
||
code = majorList[majorid].code;
|
||
name = majorList[majorid].name;
|
||
hasCost = majorList[majorid].hasCost;
|
||
hasArea = majorList[majorid].hasArea;
|
||
}
|
||
cusInsertRowFunc(3 + num_f01, [f01_sheet.getRow(3)], f01_sheet, (targetRow) => {
|
||
let rowNum = num_f01++;
|
||
for (let i = 0; i < f01Num; i++) {
|
||
targetRow.getCell(i * 10 + 1).value = rowNum;
|
||
targetRow.getCell(i * 10 + 2).value = code;
|
||
targetRow.getCell(i * 10 + 3).value = name;
|
||
if (hasCost) {
|
||
targetRow.getCell(i * 10 + 4).value = numberFormatter(scaleX[i * 3]?.cost, 2);
|
||
targetRow.getCell(i * 10 + 6).value = numberFormatter(scaleX[i * 3 + 1]?.cost, 2);
|
||
targetRow.getCell(i * 10 + 8).value = numberFormatter(scaleX[i * 3 + 2]?.cost, 2);
|
||
} else {
|
||
targetRow.getCell(i * 10 + 4).value = '/';
|
||
targetRow.getCell(i * 10 + 6).value = '/';
|
||
targetRow.getCell(i * 10 + 8).value = '/';
|
||
}
|
||
if (hasArea) {
|
||
targetRow.getCell(i * 10 + 5).value = numberFormatter(scaleX[i * 3]?.area, 3);
|
||
targetRow.getCell(i * 10 + 7).value = numberFormatter(scaleX[i * 3 + 1]?.area, 3);
|
||
targetRow.getCell(i * 10 + 9).value = numberFormatter(scaleX[i * 3 + 2]?.area, 3);
|
||
} else {
|
||
targetRow.getCell(i * 10 + 5).value = '/';
|
||
targetRow.getCell(i * 10 + 7).value = '/';
|
||
targetRow.getCell(i * 10 + 9).value = '/';
|
||
}
|
||
}
|
||
if (f01Mod > 0) {
|
||
targetRow.getCell(f01Num * 10 + 1).value = rowNum;
|
||
targetRow.getCell(f01Num * 10 + 2).value = code;
|
||
targetRow.getCell(f01Num * 10 + 3).value = name;
|
||
for (let i = 0; i < f01Mod; i++) {
|
||
if (hasCost) {
|
||
targetRow.getCell(f01Num * 10 + 4 + i * 2).value = numberFormatter(scaleX[f01Num * 3 + i]?.cost, 2);
|
||
} else {
|
||
targetRow.getCell(f01Num * 10 + 4 + i * 2).value = '/';
|
||
}
|
||
if (hasArea) {
|
||
targetRow.getCell(f01Num * 10 + 5 + i * 2).value = numberFormatter(scaleX[f01Num * 3 + i]?.area, 3);
|
||
} else {
|
||
targetRow.getCell(f01Num * 10 + 5 + i * 2).value = '/';
|
||
}
|
||
}
|
||
}
|
||
});
|
||
});
|
||
f01_sheet.spliceRows(3, 1);
|
||
// f01_sheet.getRow(2).height = 27;
|
||
f01_sheet.orderNo = ml_number + 2 + 12;
|
||
} else {
|
||
workbook.removeWorksheet('辅01表');
|
||
}
|
||
|
||
// 辅02/03表
|
||
if (data.serviceCoes?.length) {
|
||
let f02_sheet = workbook.getWorksheet('辅02表');
|
||
let num_f02 = 1;
|
||
data.serviceCoes.sort((a, b) => serviceList[a.serviceid].order - serviceList[b.serviceid].order).forEach(scoei => {
|
||
let serviceCoeX = serviceList[scoei.serviceid];
|
||
cusInsertRowFunc(2 + num_f02, [f02_sheet.getRow(2)], f02_sheet, (targetRow) => {
|
||
targetRow.getCell(1).value = num_f02++;
|
||
targetRow.getCell(2).value = serviceCoeX.code;
|
||
targetRow.getCell(3).value = serviceCoeX.name;
|
||
targetRow.getCell(4).value = numberFormatter(serviceCoeX.defCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(scoei.coe, 3);
|
||
targetRow.getCell(6).value = scoei.remark;
|
||
});
|
||
});
|
||
f02_sheet.spliceRows(2, 1);
|
||
f02_sheet.orderNo = ml_number + 3 + 12;
|
||
} else {
|
||
workbook.removeWorksheet('辅02表');
|
||
}
|
||
if (data.majorCoes?.length) {
|
||
let f03_sheet = workbook.getWorksheet('辅03表');
|
||
let num_f03 = 1;
|
||
data.majorCoes.sort((a, b) => (a < 0 ? a : majorList[a.majorid].order) - (b < 0 ? b : majorList[b.majorid].order)).forEach(mcoei => {
|
||
let majorCoeX = majorList[mcoei.majorid];
|
||
cusInsertRowFunc(2 + num_f03, [f03_sheet.getRow(2)], f03_sheet, (targetRow) => {
|
||
targetRow.getCell(1).value = num_f03++;
|
||
targetRow.getCell(2).value = majorCoeX.code;
|
||
targetRow.getCell(3).value = majorCoeX.name;
|
||
targetRow.getCell(4).value = numberFormatter(majorCoeX.defCoe, 3);
|
||
targetRow.getCell(5).value = numberFormatter(mcoei.coe, 3);
|
||
targetRow.getCell(6).value = mcoei.remark;
|
||
});
|
||
});
|
||
f03_sheet.spliceRows(2, 1);
|
||
f03_sheet.orderNo = ml_number + 4 + 12;
|
||
} else {
|
||
workbook.removeWorksheet('辅03表');
|
||
}
|
||
|
||
// 统一设置页眉页脚字体
|
||
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;
|
||
|
||
// 更新编制说明
|
||
const canvas = document.createElement("canvas");
|
||
const ctx = canvas.getContext("2d");
|
||
// ctx.font = "12pt 宋体";
|
||
// const maxTitleWidth = 336;
|
||
// const maxTextWidth = 720;
|
||
const pageMaxHei = 733;
|
||
// 20.25 25.5 33.75
|
||
const titleHeiDet = { fir: 11.25, els: 22.5 };
|
||
const textHeiDet = { fir: 6.75, els: 13.5 };
|
||
|
||
const descSheet = workbook.getWorksheet('编制说明');
|
||
descSheet.getRow(1).getCell(1).value = data.name;
|
||
let descRowNum = 5;
|
||
if (data.scale?.length) {
|
||
let engCosts = data.scale.filter(f => f.major > 6 && majorList[f.major].hasCost);
|
||
if (engCosts.length) {
|
||
descRowNum++;
|
||
let copyRowNum = descRowNum;
|
||
engCosts.forEach((sci, scindex) => {
|
||
descRowNum++;
|
||
cusInsertRowFunc(descRowNum, [descSheet.getRow(copyRowNum)], descSheet, (targetRow) => {
|
||
targetRow.getCell(1).value = ` ${scindex + 1}.${majorList[sci.major].name}${Number(sci.cost).toLocaleString()}万元${scindex == engCosts.length - 1 ? '。' : ';'}`;
|
||
});
|
||
});
|
||
descSheet.spliceRows(copyRowNum, 1);
|
||
} else {
|
||
descSheet.spliceRows(descRowNum, 2);
|
||
descSheet.getRow(descRowNum).getCell(1).value = ' (二)本项目征地拆迁费包括:';
|
||
descSheet.getRow(descRowNum + 2).getCell(1).value = ' (三)其他费用包括:';
|
||
}
|
||
let zcScales = data.scale.filter(f => [1, 2, 3].includes(f.major));
|
||
if (zcScales.length) {
|
||
descRowNum++;
|
||
let copyRowNum = descRowNum;
|
||
zcScales.forEach((sci, scindex) => {
|
||
descRowNum++;
|
||
cusInsertRowFunc(descRowNum, [descSheet.getRow(copyRowNum)], descSheet, (targetRow) => {
|
||
switch (sci.major) {
|
||
case 1:
|
||
let desc1 = [];
|
||
if (sci.area) desc1.push(`征地总面积约${Number(sci.area).toLocaleString()}亩`);
|
||
if (sci.cost) desc1.push(`征地补偿费用${Number(sci.cost).toLocaleString()}万元`);
|
||
targetRow.getCell(1).value = ` ${scindex + 1}.征地情况:${desc1.join(',')}。`;
|
||
break;
|
||
case 2:
|
||
let desc2 = [];
|
||
if (sci.area) desc2.push(`拆迁总面积约${Number(sci.area).toLocaleString()}亩`);
|
||
if (sci.cost) desc2.push(`拆迁补偿费用${Number(sci.cost).toLocaleString()}万元`);
|
||
targetRow.getCell(1).value = ` ${scindex + 1}.拆迁补偿情况:${desc2.join(',')}。`;
|
||
break;
|
||
case 3:
|
||
targetRow.getCell(1).value = ` ${scindex + 1}.迁改工程情况:费用${Number(sci.cost).toLocaleString()}万元。`;
|
||
break;
|
||
}
|
||
});
|
||
});
|
||
descSheet.spliceRows(copyRowNum, 1);
|
||
} else {
|
||
descSheet.spliceRows(descRowNum, 2);
|
||
descSheet.getRow(descRowNum).getCell(1).value = engCosts.length ? ' (三)其他费用包括:' : ' (二)其他费用包括:';
|
||
}
|
||
let otherCosts = data.scale.filter(f => [4, 5, 6].includes(f.major));
|
||
if (otherCosts.length) {
|
||
let desc = [];
|
||
otherCosts.forEach(sci => {
|
||
desc.push(`${majorList[sci.major].name}${Number(sci.cost).toLocaleString()}万元`);
|
||
});
|
||
descSheet.getRow(descRowNum).getCell(1).value = descSheet.getRow(descRowNum).getCell(1).value + `${desc.join(',')}。`;
|
||
descRowNum++;
|
||
} else {
|
||
descSheet.spliceRows(descRowNum, 1);
|
||
}
|
||
} else {
|
||
descSheet.spliceRows(descRowNum, 5);
|
||
descRowNum++;
|
||
}
|
||
console.log(descRowNum);
|
||
|
||
return workbook;
|
||
} catch (error) {
|
||
console.log(error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
|
||
// 在指定位置插入行,并按模板行复制样式,可选回调填充值。
|
||
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 = JSON.parse(JSON.stringify(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: 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));
|
||
}
|
||
|
||
/* 复制合并单元格 */
|
||
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;
|
||
}
|
||
|
||
|