更新导出成果报表功能

This commit is contained in:
ForeverSmiYng 2026-03-07 16:25:21 +08:00
parent 303f54bb71
commit 21d3f0379c
5 changed files with 2344 additions and 85 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -13,19 +13,19 @@ const toFiniteNumber = (value: unknown) => {
}
export const industryTypeList = [
{id:'0', name: '公路工程', type: 'isRoad' },
{id:'1', name: '铁路工程', type: 'isRailway' },
{id:'2', name: '水运工程', type: 'isWaterway' }
{ id: '0', name: '公路工程', type: 'isRoad' },
{ id: '1', name: '铁路工程', type: 'isRailway' },
{ id: '2', name: '水运工程', type: 'isWaterway' }
] as const
export const majorList = {
0: { code: 'E1', name: '交通运输工程通用专业',hideInIndustrySelector: true, maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 1, hasCost: false, hasArea: false },
0: { code: 'E1', name: '交通运输工程通用专业', hideInIndustrySelector: true, maxCoe: null, minCoe: null, defCoe: null, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 1, hasCost: false, hasArea: false },
1: { code: 'E1-1', name: '征地(用海)补偿', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目征地(用海)补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 2, hasCost: true, hasArea: true },
2: { code: 'E1-2', name: '拆迁补偿', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于交通建设项目拆迁补偿的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 3, hasCost: true, hasArea: true },
3: { code: 'E1-3', name: '迁改工程', maxCoe: null, minCoe: null, defCoe: 2, desc: '适用于交通建设项目迁改工程的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 4, hasCost: true, hasArea: false },
4: { code: 'E1-4', name: '工程建设其他费', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于交通建设项目的工程建设其他费的施工图预算、招标工程量清单及清单预算(或最高投标限价)、清理概算(仅限铁路工程)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: true, isWaterway: true, order: 5, hasCost: true, hasArea: false },
5: { code: 'E1-5', name: '预备费', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 6, hasCost: true, hasArea: false },
6: { code: 'E1-6', name: '建设期贷款利息', maxCoe: null, minCoe: null, defCoe: 1, desc: '', isRoad: true, isRailway: true, isWaterway: true, order: 7, hasCost: true, hasArea: false },
7: { code: 'E2', name: '公路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于公路工程的全过程造价咨询、分阶段造价咨询、投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: true, isRailway: false, isWaterway: false, order: 8, hasCost: false, hasArea: false ,industryId:'0' },
7: { code: 'E2', name: '公路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于公路工程的全过程造价咨询、分阶段造价咨询、投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: true, isRailway: false, isWaterway: false, order: 8, hasCost: false, hasArea: false, industryId: '0' },
8: { code: 'E2-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 9, hasCost: true, hasArea: false },
9: { code: 'E2-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 10, hasCost: true, hasArea: false },
10: { code: 'E2-3', name: '路面工程', maxCoe: null, minCoe: null, defCoe: 0.8, desc: '适用于路面工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 11, hasCost: true, hasArea: false },
@ -36,7 +36,7 @@ export const majorList = {
15: { code: 'E2-8', name: '交通安全设施工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于交通安全设施工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 16, hasCost: true, hasArea: false },
16: { code: 'E2-9', name: '绿化及环境保护工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于绿化工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 17, hasCost: true, hasArea: false },
17: { code: 'E2-10', name: '房建工程', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: true, isRailway: false, isWaterway: false, order: 18, hasCost: true, hasArea: false },
18: { code: 'E3', name: '铁路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于铁路工程的投资估算、初步设计概算、清理概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: true, isWaterway: false, order: 19, hasCost: false, hasArea: false ,industryId:'1' },
18: { code: 'E3', name: '铁路工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于铁路工程的投资估算、初步设计概算、清理概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: true, isWaterway: false, order: 19, hasCost: false, hasArea: false, industryId: '1' },
19: { code: 'E3-1', name: '大型临时设施和过渡工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于大型临时设施和过渡工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 20, hasCost: true, hasArea: false },
20: { code: 'E3-2', name: '路基工程', maxCoe: null, minCoe: null, defCoe: 1.2, desc: '适用于路基工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 21, hasCost: true, hasArea: false },
21: { code: 'E3-3', name: '桥涵工程', maxCoe: null, minCoe: null, defCoe: 0.9, desc: '适用于桥涵工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 22, hasCost: true, hasArea: false },
@ -46,7 +46,7 @@ export const majorList = {
25: { code: 'E3-7', name: '电力及电力牵引供电工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于电力及电力牵引供电工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 26, hasCost: true, hasArea: false },
26: { code: 'E3-8', name: '房建工程(房屋建筑及附属工程)', maxCoe: null, minCoe: null, defCoe: 2.5, desc: '适用于房屋建筑及附属工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 27, hasCost: true, hasArea: false },
27: { code: 'E3-9', name: '装饰装修工程', maxCoe: null, minCoe: null, defCoe: 2.7, desc: '适用于装饰装修工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: true, isWaterway: false, order: 28, hasCost: true, hasArea: false },
28: { code: 'E4', name: '水运工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于水运工程的投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: false, isWaterway: true, order: 29, hasCost: false, hasArea: false ,industryId:'2' },
28: { code: 'E4', name: '水运工程专业', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于水运工程的投资估算、初步设计概算、竣工决算和调整估算、调整概算(含征地拆迁和工程建设其他费)', isRoad: false, isRailway: false, isWaterway: true, order: 29, hasCost: false, hasArea: false, industryId: '2' },
29: { code: 'E4-1', name: '临时工程', maxCoe: null, minCoe: null, defCoe: 1.1, desc: '适用于临时工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 30, hasCost: true, hasArea: false },
30: { code: 'E4-2', name: '土建工程', maxCoe: null, minCoe: null, defCoe: 1, desc: '适用于土建工程专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算、竣工决算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 31, hasCost: true, hasArea: false },
31: { code: 'E4-3', name: '机电与金属结构工程', maxCoe: null, minCoe: null, defCoe: 1.5, desc: '适用于机电与金属结构专业的施工图预算、招标工程量清单及清单预算(或最高投标限价)、合同(工程)结算和造价鉴定、计算工程量、工程变更费用咨询、工程成本测(核)算', isRoad: false, isRailway: false, isWaterway: true, order: 32, hasCost: true, hasArea: false },
@ -548,10 +548,186 @@ export async function exportFile(fileName: string, data: any): Promise<void> {
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
async function generateTemplate(data) {
// const downTextTmp = { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '常规' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: '下标' }] };
data.contracts[0].addtional = {// 附加工作费
ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'C' }] },
name: '附加工作',
fee: 10000,
det: [
{
id: 0,
ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'F' }] },
name: '人员驻场服务及其他附加工作',
fee: 10000,
m4: {
person_num: 10,
work_day: 3,
fee: 10000,
det: [
{
expert: 0,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
{
expert: 1,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
m5: {
fee: 10000,
det: [
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
},
{
id: 1,
ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'X' }] },
name: '咨询服务协调工作',
fee: 10000,
m0: {
coe: 0.03,
fee: 10000,
},
m4: {
person_num: 10,
work_day: 3,
fee: 10000,
det: [
{
expert: 0,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
{
expert: 1,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
m5: {
fee: 10000,
det: [
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
},
]
};
data.contracts[0].reserve = {// 预备费
ref: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'Y' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'B' }] },
name: '预备费',
fee: 10000,
m0: {
coe: 0.03,
fee: 10000,
},
m4: {
person_num: 10,
work_day: 3,
fee: 10000,
det: [
{
expert: 0,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
{
expert: 1,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
m5: {
fee: 10000,
det: [
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
{
name: '×××项',
unit: '项',
amount: 10,
price: 100000,
fee: 100000,
remark: '',// 用户输入的说明
},
],
}
};
data.contracts[1].addtional = null;
data.contracts[1].reserve = null;
data.contracts[2].addtional = null;
data.contracts[2].reserve = null;
data.contracts[3].addtional = null;
data.contracts[3].reserve = null;
data.contracts[4].addtional = null;
data.contracts[4].reserve = null;
// data.contracts[5].addtional = null;
// data.contracts[5].reserve = null;
try {
// 获取模板
let templateExcel = 'template20260226001test010';
let templateUrl = `https://oa.zwgczx.com/myExcelTemplate/${templateExcel}.xlsx`;
let templateUrl = `./public/${templateExcel}.xlsx`;
let buf = await (await fetch(templateUrl)).arrayBuffer();
let workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(buf);
@ -562,14 +738,20 @@ async function generateTemplate(data) {
let yz01_sheet = workbook.getWorksheet('预总01表');
let f01_sheet = workbook.getWorksheet('辅01表');
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let day = now.getDate();
// 更新封面
fm_sheet.getRow(2).getCell(1).value = data.name;
fm_sheet.getRow(8).getCell(4).value = data.writer;
fm_sheet.getRow(9).getCell(4).value = data.reviewer;
fm_sheet.getRow(10).getCell(4).value = data.company;
if (data.date) {
const dateArr = data.date.split('-');
let year = dateArr[0];
let month = Number(dateArr[1]);
let day = Number(dateArr[2]);
fm_sheet.getRow(11).getCell(4).value = `${year}${month}${day}`;
}
// 更新预总01表的列数
let yz01Mod = (data.contracts.length + 1) % 4;
let yz01Num = (data.contracts.length + 1 - yz01Mod) / 4;
switch (yz01Mod) {
@ -597,6 +779,7 @@ async function generateTemplate(data) {
}
}
// 更新辅01表的列数
let f01Mod = (data.contracts.length) % 3;
let f01Num = (data.contracts.length - f01Mod) / 3;
switch (f01Mod) {
@ -644,14 +827,18 @@ async function generateTemplate(data) {
}
}
let ml_slotRow = 13;
// 按合同段更新目录及相关表
let ml_slotRow = 14;
let ml_number = 1;
let allServices = [];
let allAddtional = {};
let allReserve = {};
data.contracts.forEach((ci, index) => {
ci.method1 = [];
ci.method2 = [];
ci.method3 = [];
ci.method4 = [];
// 按计价方式汇总服务数据对象
ci.services.forEach(si => {
if (si.method1) {
ci.method1.push(si.id);
@ -662,7 +849,22 @@ async function generateTemplate(data) {
if (si.method3) ci.method3.push(si.id);
if (si.method4) ci.method4.push(si.id);
});
const addtionalM4 = [];
const addtionalM5 = [];
if (ci.addtional) {
allAddtional[index] = ci.addtional;
ci.addtional.det.forEach(f => {
if (f.m4) addtionalM4.push(f);
if (f.m5) addtionalM5.push(f);
});
}
if (addtionalM5.length) ci.method5 = { addtional: addtionalM5 };
if (ci.reserve) allReserve[index] = ci.reserve;
const reserveM4 = ci.reserve?.m4;
const reserveM5 = ci.reserve?.m5;
if (reserveM5) ci.method5 = ci.method5 ? Object.assign({ reserve: reserveM5 }, ci.method5) : { reserve: reserveM5 };
// 创建sheet
let ml_sourceRows = [ml_sheet.getRow(6)];
let sheet_1 = copyWorksheet(workbook, '预i-1表', `${index + 1}-1表`);
sheet_1.headerFooter.oddHeader = sheet_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-1 表/g, `${index + 1}-1 表`).replace(/第i合同/g, ci.name);
@ -673,6 +875,7 @@ async function generateTemplate(data) {
let sheet_3;
let sheet_4;
let sheet_4_1;
let sheet_5;
if (ci.method1.length || ci.method2.length) {
ml_sourceRows.push(ml_sheet.getRow(7));
sheet_2 = copyWorksheet(workbook, '预i-2表', `${index + 1}-2表`);
@ -693,19 +896,21 @@ async function generateTemplate(data) {
sheet_3 = copyWorksheet(workbook, '预i-3表', `${index + 1}-3表`);
sheet_3.headerFooter.oddHeader = sheet_3.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-3 表/g, `${index + 1}-3 表`).replace(/第i合同/g, ci.name);
}
if (ci.method4.length) {
if (ci.method4.length || addtionalM4.length || reserveM4) {
ml_sourceRows.push(ml_sheet.getRow(11));
ml_sourceRows.push(ml_sheet.getRow(12));
sheet_4 = copyWorksheet(workbook, '预i-4表', `${index + 1}-4表`);
sheet_4.headerFooter.oddHeader = sheet_4.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4 表/g, `${index + 1}-4 表`).replace(/第i合同/g, ci.name);
sheet_4_1 = copyWorksheet(workbook, '预i-4-1表', `${index + 1}-4-1表`);
sheet_4_1.headerFooter.oddHeader = sheet_4_1.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-4-1 表/g, `${index + 1}-4-1 表`).replace(/第i合同/g, ci.name);
let sumObj = ci.method4.reduce((a, b) => {
const m4 = ci.services.find(f => f.id == b)?.method4;
// 更新i-4和i-4-1表的小计行
let sumArr = ci.method4.map(m => ci.services.find(f => f.id == m)?.method4).concat(addtionalM4.map(m => m.m4));
if (reserveM4) sumArr.push(reserveM4);
let sumObj = sumArr.reduce((a, b) => {
return {
person_num: addNumbers(a.person_num, toFiniteNumber(m4?.person_num)),
work_day: addNumbers(a.work_day, toFiniteNumber(m4?.work_day)),
fee: addNumbers(a.fee, toFiniteNumber(m4?.fee))
person_num: addNumbers(a.person_num, toFiniteNumber(b?.person_num)),
work_day: addNumbers(a.work_day, toFiniteNumber(b?.work_day)),
fee: addNumbers(a.fee, toFiniteNumber(b?.fee))
};
}, { person_num: 0, work_day: 0, fee: 0 });
sheet_4.getRow(3).getCell(4).value = sumObj.person_num;
@ -718,7 +923,16 @@ async function generateTemplate(data) {
sheet_4_1.getRow(4).getCell(8).value = sumObj.work_day;
sheet_4_1.getRow(4).getCell(9).value = sumObj.fee
}
if (ci.method5) {
ml_sourceRows.push(ml_sheet.getRow(13));
sheet_5 = copyWorksheet(workbook, '预i-5表', `${index + 1}-5表`);
sheet_5.headerFooter.oddHeader = sheet_5.headerFooter.oddHeader.replace(/×××/g, ci.name).replace(/预 i-5 表/g, `${index + 1}-5 表`).replace(/第i合同/g, ci.name);
sheet_5.getRow(3).getCell(4).value = '/';
sheet_5.getRow(3).getCell(5).value = '/';
sheet_5.getRow(3).getCell(6).value = (ci.method5.addtional?.reduce((a, b) => a + b.m5.fee, 0) || 0) + (ci.method5.reserve?.fee || 0);
}
// 更新目录的第三部分
cusInsertRowFunc(ml_slotRow, ml_sourceRows, ml_sheet, () => ml_slotRow++, (targetCell, sourceCell, colNumber) => {
if (colNumber == 1) {
targetCell.value = ml_number++;
@ -731,12 +945,19 @@ async function generateTemplate(data) {
}
});
// 根据服务更新相关表
let num_2 = 1;
let num_2_1 = 1;
let num_2_2 = 1;
let num_3 = 1;
let num_4 = 1;
let num_4_1 = 1;
let num_5 = 1;
let m1Sum = 0;
let m2Sum = 0;
let m3Sum = 0;
let m4Sum = 0;
let serviceSum = 0;
ci.services.forEach((sobj, sindex) => {
let allServicesX = allServices.find(s => s.id == sobj.id);
if (allServicesX) {
@ -749,31 +970,34 @@ async function generateTemplate(data) {
},
});
}
let serviceX = getServiceDictItemById(sobj.id) || { code: '', name: '' };
let serviceX = serviceList[sobj.id];
cusInsertRowFunc(4 + sindex, [sheet_1.getRow(3)], sheet_1, (targetRow) => {
targetRow.getCell(1).value = sindex + 1;
targetRow.getCell(2).value = serviceX.code;
targetRow.getCell(3).value = serviceX.name;
targetRow.getCell(4).value = sobj.method1 ? sobj.method1.fee : '';
targetRow.getCell(5).value = sobj.method2 ? sobj.method2.fee : '';
targetRow.getCell(6).value = sobj.method3 ? sobj.method3.fee : '';
targetRow.getCell(7).value = sobj.method4 ? sobj.method4.fee : '';
if (sobj.method1) {
targetRow.getCell(4).value = sobj.method1.fee;
m1Sum += sobj.method1.fee;
}
if (sobj.method2) {
targetRow.getCell(5).value = sobj.method2.fee;
m2Sum += sobj.method2.fee;
}
if (sobj.method3) {
targetRow.getCell(6).value = sobj.method3.fee;
m3Sum += sobj.method3.fee;
}
if (sobj.method4) {
targetRow.getCell(7).value = sobj.method4.fee;
m4Sum += sobj.method4.fee;
}
targetRow.getCell(8).value = sobj.fee;
serviceSum += sobj.fee;
});
if (sobj.method1 || sobj.method2) {
let det1 = sobj.method1 ? sobj.method1.det.map(m => m.major) : [];
let det2 = sobj.method2 ? sobj.method2.det.map(m => m.major) : [];
const majorOrderMap = new Map(getMajorDictEntries().map((entry, idx) => [entry.id, idx]));
let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => {
const aId = String(a);
const bId = String(b);
const ao = majorOrderMap.get(aId) ?? majorOrderMap.get(getMajorIdAliasMap().get(aId) || '');
const bo = majorOrderMap.get(bId) ?? majorOrderMap.get(getMajorIdAliasMap().get(bId) || '');
if (ao != null && bo != null) return ao - bo;
if (ao != null) return -1;
if (bo != null) return 1;
return aId.localeCompare(bId);
}).map(m => {
let allDet = [...(new Set([...det1, ...det2]))].sort((a, b) => a - b).map(m => {
return {
major: m,
mth1: det1.includes(m) ? sobj.method1.det[det1.indexOf(m)] : null,
@ -787,9 +1011,11 @@ async function generateTemplate(data) {
targetRow.getCell(3).value = serviceX.name;
targetRow.getCell(4).value = '/';
targetRow.getCell(5).value = '/';
targetRow.getCell(6).value = '/';
targetRow.getCell(7).value = '/';
if (sobj.method1) {
targetRow.getCell(6).value = sobj.method1.basicFee;
targetRow.getCell(7).value = sobj.method1.fee;
targetRow.getCell(8).value = sobj.method1.basicFee;
targetRow.getCell(9).value = sobj.method1.fee;
cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => {
targetRow.getCell(1).value = num_2_1++;
targetRow.getCell(2).value = serviceX.code;
@ -803,8 +1029,8 @@ async function generateTemplate(data) {
});
}
if (sobj.method2) {
targetRow.getCell(8).value = sobj.method2.basicFee;
targetRow.getCell(9).value = sobj.method2.fee;
targetRow.getCell(10).value = sobj.method2.basicFee;
targetRow.getCell(11).value = sobj.method2.fee;
cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => {
targetRow.getCell(1).value = num_2_2++;
targetRow.getCell(2).value = serviceX.code;
@ -819,7 +1045,7 @@ async function generateTemplate(data) {
}
});
allDet.forEach((m, mindex) => {
let majorX = getMajorDictItemById(m.major) || { name: '' };
let majorX = majorList[m.major];
cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => {
targetRow.getCell(1).value = num_2++;
targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1);
@ -827,10 +1053,12 @@ async function generateTemplate(data) {
if (m.mth1) {
targetRow.getCell(4).value = m.mth1.serviceCoe;
targetRow.getCell(5).value = m.mth1.majorCoe;
targetRow.getCell(6).value = m.mth1.basicFee;
targetRow.getCell(7).value = m.mth1.fee;
targetRow.getCell(8).value = 0;
targetRow.getCell(9).value = 0;
targetRow.getCell(6).value = m.mth1.processCoe;
targetRow.getCell(7).value = m.mth1.proportion;
targetRow.getCell(8).value = m.mth1.basicFee;
targetRow.getCell(9).value = m.mth1.fee;
targetRow.getCell(10).value = 0;
targetRow.getCell(11).value = 0;
cusInsertRowFunc(4 + num_2_1, [sheet_2_1.getRow(4)], sheet_2_1, (targetRow) => {
targetRow.getCell(1).value = num_2_1++;
targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1);
@ -845,10 +1073,12 @@ async function generateTemplate(data) {
} else {
targetRow.getCell(4).value = m.mth2.serviceCoe;
targetRow.getCell(5).value = m.mth2.majorCoe;
targetRow.getCell(6).value = 0;
targetRow.getCell(7).value = 0;
targetRow.getCell(8).value = m.mth2.basicFee;
targetRow.getCell(9).value = m.mth2.fee;
targetRow.getCell(6).value = m.mth2.processCoe;
targetRow.getCell(7).value = m.mth2.proportion;
targetRow.getCell(8).value = 0;
targetRow.getCell(9).value = 0;
targetRow.getCell(10).value = m.mth2.basicFee;
targetRow.getCell(11).value = m.mth2.fee;
cusInsertRowFunc(4 + num_2_2, [sheet_2_2.getRow(4)], sheet_2_2, (targetRow) => {
targetRow.getCell(1).value = num_2_2++;
targetRow.getCell(2).value = serviceX.code + '-' + (mindex + 1);
@ -928,19 +1158,64 @@ async function generateTemplate(data) {
});
}
});
let endRows = 1;
cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => {
targetRow.getCell(1).value = ci.services.length + endRows;
targetRow.getCell(2).value = '';
targetRow.getCell(3).value = '小计';
targetRow.getCell(4).value = numberFormatter(m1Sum, 2);
targetRow.getCell(5).value = numberFormatter(m2Sum, 2);
targetRow.getCell(6).value = numberFormatter(m3Sum, 2);
targetRow.getCell(7).value = numberFormatter(m4Sum, 2);
targetRow.getCell(8).value = numberFormatter(serviceSum, 2);
});
if (ci.addtional) {
endRows++;
cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => {
targetRow.getCell(1).value = ci.services.length + endRows;
targetRow.getCell(2).value = ci.addtional.ref;
targetRow.getCell(3).value = ci.addtional.name;
targetRow.getCell(4).value = '';
targetRow.getCell(5).value = '';
targetRow.getCell(6).value = '';
targetRow.getCell(7).value = '';
targetRow.getCell(8).value = ci.addtional.fee;
});
ci.addtional.det.forEach((addobj, addindex) => {
endRows++;
cusInsertRowFunc(ci.services.length + 3 + endRows, [sheet_1.getRow(3)], sheet_1, (targetRow) => {
targetRow.getCell(1).value = ci.services.length + endRows;
targetRow.getCell(2).value = addobj.ref;
targetRow.getCell(3).value = addobj.name;
let tmpArr = [];
if (addobj.m0) tmpArr.push(`按上述小计的${addobj.m0.coe}计得${addobj.m0.fee}`);
if (addobj.m4) tmpArr.push(`按工时法计得${addobj.m4.fee}`);
if (addobj.m5) tmpArr.push(`按数量单价计得${addobj.m5.fee}`);
targetRow.getCell(4).value = tmpArr.join(';');
targetRow.getCell(8).value = addobj.fee;
});
});
}
sheet_1.spliceRows(3, 1);
sheet_1.getRow(ci.services.length + endRows + 3).getCell(1).value = ci.services.length + endRows + 1;
sheet_1.getRow(ci.services.length + endRows + 3).getCell(8).value = ci.fee;
sheet_1.mergeCells(2 + ci.services.length + endRows + 2, 2, 2 + ci.services.length + endRows + 2, 8);
sheet_1.getRow(2 + ci.services.length + endRows + 2).height = 100;
sheet_1.getRow(2 + ci.services.length + endRows + 2).getCell(2).border.right = { style: 'thin' };
for (let i = 1; i <= endRows; i++) {
sheet_1.mergeCells(ci.services.length + 3 + i, 4, ci.services.length + 3 + i, 7);
if (sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment) {
sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment.horizontal = 'center';
sheet_1.getRow(ci.services.length + 3 + i).getCell(4).style.alignment.wrapText = true;
if (i != 1 && i != endRows) sheet_1.getRow(ci.services.length + 3 + i).getCell(9).style.font.size = 22;
}
}
});
const serviceOrderMap = new Map(getServiceDictEntries().map((entry, index) => [entry.id, index]));
allServices.sort((a, b) => {
const ao = serviceOrderMap.get(String(a.id));
const bo = serviceOrderMap.get(String(b.id));
if (ao != null && bo != null) return ao - bo;
if (ao != null) return -1;
if (bo != null) return 1;
return String(a.id).localeCompare(String(b.id));
});
allServices.sort((a, b) => a.id - b.id);
allServices.forEach((s, sindex) => {
const serviceX = getServiceDictItemById(s.id) || { code: '', name: '' };
const serviceX = serviceList[s.id];
cusInsertRowFunc(3 + sindex, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => {
let siSum = 0;
for (let i = 0; i < yz01Num; i++) {
@ -986,35 +1261,174 @@ async function generateTemplate(data) {
}
});
});
let endRows = 0;
if (Object.keys(allAddtional).length) {
endRows++;
let firstNum = Object.keys(allAddtional)[0];
cusInsertRowFunc(3 + allServices.length, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => {
let siSum = 0;
for (let i = 0; i < yz01Num; i++) {
targetRow.getCell(i * 7 + 1).value = allServices.length + 1;
targetRow.getCell(i * 7 + 2).value = allAddtional[firstNum].ref;
targetRow.getCell(i * 7 + 3).value = allAddtional[firstNum].name;
targetRow.getCell(i * 7 + 4).value = allAddtional[i * 4]?.fee;
targetRow.getCell(i * 7 + 5).value = allAddtional[i * 4 + 1]?.fee;
targetRow.getCell(i * 7 + 6).value = allAddtional[i * 4 + 2]?.fee;
siSum = addNumbers(
siSum,
toFiniteNumber(allAddtional[i * 4]?.fee),
toFiniteNumber(allAddtional[i * 4 + 1]?.fee),
toFiniteNumber(allAddtional[i * 4 + 2]?.fee)
);
if (i == yz01Num - 1 && yz01Mod == 0) {
targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2);
} else {
targetRow.getCell(i * 7 + 7).value = allAddtional[i * 4 + 3]?.fee;
siSum = addNumbers(siSum, toFiniteNumber(allAddtional[i * 4 + 3]?.fee));
}
}
if (yz01Mod) {
targetRow.getCell(yz01Num * 7 + 1).value = allServices.length + 1;
targetRow.getCell(yz01Num * 7 + 2).value = allAddtional[firstNum].ref;
targetRow.getCell(yz01Num * 7 + 3).value = allAddtional[firstNum].name;
if (yz01Mod == 1) {
targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(siSum, 2);
} else if (yz01Mod == 2) {
targetRow.getCell(yz01Num * 7 + 4).value = allAddtional[yz01Num * 4]?.fee;
siSum = addNumbers(siSum, toFiniteNumber(allAddtional[yz01Num * 4]?.fee));
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2);
} else {
targetRow.getCell(yz01Num * 7 + 4).value = allAddtional[yz01Num * 4]?.fee;
targetRow.getCell(yz01Num * 7 + 5).value = allAddtional[yz01Num * 4 + 1]?.fee;
siSum = addNumbers(
siSum,
toFiniteNumber(allAddtional[yz01Num * 4]?.fee),
toFiniteNumber(allAddtional[yz01Num * 4 + 1]?.fee)
);
targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2);
}
}
});
}
if (Object.keys(allReserve).length) {
endRows++;
let firstNum = Object.keys(allReserve)[0];
cusInsertRowFunc(3 + allServices.length + endRows - 1, [yz01_sheet.getRow(2)], yz01_sheet, (targetRow) => {
let siSum = 0;
for (let i = 0; i < yz01Num; i++) {
targetRow.getCell(i * 7 + 1).value = allServices.length + endRows;
targetRow.getCell(i * 7 + 2).value = allReserve[firstNum].ref;
targetRow.getCell(i * 7 + 3).value = allReserve[firstNum].name;
targetRow.getCell(i * 7 + 4).value = allReserve[i * 4]?.fee;
targetRow.getCell(i * 7 + 5).value = allReserve[i * 4 + 1]?.fee;
targetRow.getCell(i * 7 + 6).value = allReserve[i * 4 + 2]?.fee;
siSum = addNumbers(
siSum,
toFiniteNumber(allReserve[i * 4]?.fee),
toFiniteNumber(allReserve[i * 4 + 1]?.fee),
toFiniteNumber(allReserve[i * 4 + 2]?.fee)
);
if (i == yz01Num - 1 && yz01Mod == 0) {
targetRow.getCell(i * 7 + 7).value = numberFormatter(siSum, 2);
} else {
targetRow.getCell(i * 7 + 7).value = allReserve[i * 4 + 3]?.fee;
siSum = addNumbers(siSum, toFiniteNumber(allReserve[i * 4 + 3]?.fee));
}
}
if (yz01Mod) {
targetRow.getCell(yz01Num * 7 + 1).value = allServices.length + endRows;
targetRow.getCell(yz01Num * 7 + 2).value = allReserve[firstNum].ref;
targetRow.getCell(yz01Num * 7 + 3).value = allReserve[firstNum].name;
if (yz01Mod == 1) {
targetRow.getCell(yz01Num * 7 + 4).value = numberFormatter(siSum, 2);
} else if (yz01Mod == 2) {
targetRow.getCell(yz01Num * 7 + 4).value = allReserve[yz01Num * 4]?.fee;
siSum = addNumbers(siSum, toFiniteNumber(allReserve[yz01Num * 4]?.fee));
targetRow.getCell(yz01Num * 7 + 5).value = numberFormatter(siSum, 2);
} else {
targetRow.getCell(yz01Num * 7 + 4).value = allReserve[yz01Num * 4]?.fee;
targetRow.getCell(yz01Num * 7 + 5).value = allReserve[yz01Num * 4 + 1]?.fee;
siSum = addNumbers(
siSum,
toFiniteNumber(allReserve[yz01Num * 4]?.fee),
toFiniteNumber(allReserve[yz01Num * 4 + 1]?.fee)
);
targetRow.getCell(yz01Num * 7 + 6).value = numberFormatter(siSum, 2);
}
}
});
}
const yz01SumRow = yz01_sheet.getRow(allServices.length + endRows + 3);
for (let i = 0; i < yz01Num; i++) {
yz01SumRow.getCell(i * 7 + 1).value = allServices.length + endRows + 1;
yz01SumRow.getCell(i * 7 + 4).value = data.contracts[i * 4]?.fee;
yz01SumRow.getCell(i * 7 + 5).value = data.contracts[i * 4 + 1]?.fee;
yz01SumRow.getCell(i * 7 + 6).value = data.contracts[i * 4 + 2]?.fee;
if (i == yz01Num - 1 && yz01Mod == 0) {
yz01SumRow.getCell(i * 7 + 7).value = numberFormatter(data.fee, 2);
} else {
yz01SumRow.getCell(i * 7 + 7).value = data.contracts[i * 4 + 3]?.fee;
}
}
if (yz01Mod) {
yz01SumRow.getCell(yz01Num * 7 + 1).value = allServices.length + endRows + 1;
if (yz01Mod == 1) {
yz01SumRow.getCell(yz01Num * 7 + 4).value = numberFormatter(data.fee, 2);
} else if (yz01Mod == 2) {
yz01SumRow.getCell(yz01Num * 7 + 4).value = data.contracts[yz01Num * 4]?.fee;
yz01SumRow.getCell(yz01Num * 7 + 5).value = numberFormatter(data.fee, 2);
} else {
yz01SumRow.getCell(yz01Num * 7 + 4).value = data.contracts[yz01Num * 4]?.fee;
yz01SumRow.getCell(yz01Num * 7 + 5).value = data.contracts[yz01Num * 4 + 1]?.fee;
yz01SumRow.getCell(yz01Num * 7 + 6).value = numberFormatter(data.fee, 2);
}
}
ml_sheet.spliceRows(6, 6);
ml_sheet.spliceRows(6, 7);
ml_sheet.spliceRows(6, 1);
yz01_sheet.spliceRows(2, 1);
// 合并说明
let yz01_lastCol;
if (yz01Num) {
for (let i = 0; i < yz01Num; i++) {
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4].name}预算\n(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 1].name}预算\n(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 2].name}预算\n(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4].name}预算(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4 + 1).value = `${data.contracts[i * 4 + 1].name}预算(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4 + 2).value = `${data.contracts[i * 4 + 2].name}预算(元)`;
if (i == yz01Num - 1 && yz01Mod == 0) {
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `预算小计\n(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4 + 3).value = `预算小计(元)`;
yz01_lastCol = i * 7 + 4;
} else {
yz01_sheet.getRow(1).getCell(i * 7 + 4).value = `${data.contracts[i * 4 + 3].name}预算\n(元)`;
yz01_sheet.getRow(1).getCell(i * 7 + 4 + 3).value = `${data.contracts[i * 4 + 3].name}预算(元)`;
}
yz01_sheet.mergeCells(6, i * 7 + 2, 6, i * 7 + 7);
yz01_sheet.mergeCells(allServices.length + endRows + 3, i * 7 + 2, allServices.length + endRows + 3, i * 7 + 7);
yz01_sheet.getRow(allServices.length + endRows + 3).getCell(i * 7 + 2).border.right = { style: 'thin' };
}
}
if (yz01Mod) {
for (let i = 0; i < yz01Mod; i++) {
if (i == yz01Mod - 1) {
yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `预算小计\n(元)`;
yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `预算小计(元)`;
yz01_lastCol = yz01Num * 7 + 4 + i;
} else {
yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算\n(元)`;
yz01_sheet.getRow(1).getCell(yz01Num * 7 + 4 + i).value = `${data.contracts[yz01Num * 4 + i].name}预算(元)`;
}
}
yz01_sheet.mergeCells(6, yz01Num * 7 + 2, 6, yz01Num * 7 + 3 + yz01Mod);
yz01_sheet.mergeCells(allServices.length + endRows + 3, yz01Num * 7 + 2, allServices.length + endRows + 3, yz01Num * 7 + 3 + yz01Mod);
yz01_sheet.getRow(allServices.length + endRows + 3).getCell(yz01Num * 7 + 2).border.right = { style: 'thin' };
}
ml_sheet.mergeCells(ml_slotRow - 7, 1, ml_slotRow - 7, 4);
yz01_sheet.getRow(allServices.length + endRows + 3).height = 100;
// for (let i = 1; i <= allServices.length + endRows + 3; i++) {
// yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).value = ' ';
// if (yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style.font) {
// yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style.font.size = i == 1 ? 22 : 20;
// } else {
// yz01_sheet.getRow(i).getCell(yz01_lastCol + 1).style = { font: { size: i == 1 ? 22 : 20 } };
// // }
// // }
// yz01_sheet.pageSetup.printArea = `A1:${yz01_sheet.getRow(allServices.length + endRows + 3).getCell(yz01_lastCol)._address}`;
ml_sheet.mergeCells(ml_slotRow - 8, 1, ml_slotRow - 8, 4);
workbook.removeWorksheet('预i-1表');
workbook.removeWorksheet('预i-2表');
@ -1023,9 +1437,10 @@ async function generateTemplate(data) {
workbook.removeWorksheet('预i-3表');
workbook.removeWorksheet('预i-4表');
workbook.removeWorksheet('预i-4-1表');
workbook.getWorksheet('辅01表').orderNo = ml_number + 2 + 10;
workbook.getWorksheet('辅02表').orderNo = ml_number + 3 + 10;
workbook.getWorksheet('辅03表').orderNo = ml_number + 4 + 10;
workbook.removeWorksheet('预i-5表');
workbook.getWorksheet('辅01表').orderNo = ml_number + 2 + 11;
workbook.getWorksheet('辅02表').orderNo = ml_number + 3 + 11;
workbook.getWorksheet('辅03表').orderNo = ml_number + 4 + 11;
workbook._worksheets.forEach(sheet => {
if (sheet) {
@ -1063,7 +1478,7 @@ function cusInsertRowFunc(insertRowNum, sourceRows, worksheet, RowFun, cellFun)
// targetCell.value = cell.value; // 复制内容
// 复制样式
if (cell.style) {
targetCell.style = { ...cell.style };
targetCell.style = JSON.parse(JSON.stringify(cell.style));
}
if (cellFun) {
@ -1082,16 +1497,14 @@ function copyWorksheet(workbook, sourceName, targetName) {
if (!source) throw new Error("Source sheet not found");
const target = workbook.addWorksheet(targetName, {
properties: { ...source.properties },
pageSetup: { ...source.pageSetup },
views: source.views ? JSON.parse(JSON.stringify(source.views)) : [],
properties: JSON.parse(JSON.stringify(source.properties || {})),
pageSetup: JSON.parse(JSON.stringify(source.pageSetup || {})),
views: source.views ? JSON.parse(JSON.stringify(source.views || {})) : [],
});
/* 复制页眉页脚(关键补充) */
if (source.headerFooter) {
target.headerFooter = JSON.parse(
JSON.stringify(source.headerFooter)
);
target.headerFooter = JSON.parse(JSON.stringify(source.headerFooter));
}
/* 复制合并单元格 */