优化报表导出功能

This commit is contained in:
ForeverSmiYng 2026-03-12 10:46:32 +08:00
parent f4c768df29
commit 398fca9265
2 changed files with 87 additions and 183 deletions

View File

@ -2,6 +2,7 @@
import { addNumbers, roundTo, toDecimal } from '@/lib/decimal' import { addNumbers, roundTo, toDecimal } from '@/lib/decimal'
import { formatThousands } from '@/lib/numberFormat' import { formatThousands } from '@/lib/numberFormat'
import ExcelJS from "ExcelJS"; import ExcelJS from "ExcelJS";
import { number } from 'motion-v/es';
// 统一数字千分位格式化,默认保留 2 位小数。 // 统一数字千分位格式化,默认保留 2 位小数。
const numberFormatter = (value: unknown, fractionDigits = 2) => const numberFormatter = (value: unknown, fractionDigits = 2) =>
formatThousands(value, fractionDigits) formatThousands(value, fractionDigits)
@ -151,8 +152,7 @@ export const expertList = {
7: { code: 'C9-3-2', name: '一级造价工程师且具备高级工程师资格', maxPrice: 2000, minPrice: 1800, defPrice: 1900, manageCoe: 2.05 }, 7: { code: 'C9-3-2', name: '一级造价工程师且具备高级工程师资格', maxPrice: 2000, minPrice: 1800, defPrice: 1900, manageCoe: 2.05 },
}; };
export const additionalWorkList export const additionalWorkList = ['人员驻场服务及其他附加工作', '咨询服务协调工作'];
=['人员驻场服务及其他附加工作','咨询服务协调工作']
let costScaleCal = [ let costScaleCal = [
{ code: 'C1-1', staLine: 0, endLine: 100, basic: { staPrice: 0, rate: 0.01 }, optional: { staPrice: 0, rate: 0.002 } }, { code: 'C1-1', staLine: 0, endLine: 100, basic: { staPrice: 0, rate: 0.01 }, optional: { staPrice: 0, rate: 0.002 } },
@ -552,182 +552,7 @@ export async function exportFile(fileName: string, data: any): Promise<void> {
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。 // 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
async function generateTemplate(data) { 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: '下标' }] }; // 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)
data.contracts[0].addtional = {// 附加工作费
code: { 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,
code: { 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,
code: { 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 = {// 预备费
code: { 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 { try {
// 获取模板 // 获取模板
let templateExcel = 'template20260226001test010'; let templateExcel = 'template20260226001test010';
@ -1780,7 +1605,7 @@ async function generateTemplate(data) {
} }
} }
let num_f01 = 1; let num_f01 = 1;
Object.keys(allMajors).sort((a, b) => majorList[a].order - majorList[b].order).forEach(majorid => { 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 scaleX = allMajors[majorid];
let code; let code;
let name; let name;
@ -1843,7 +1668,7 @@ async function generateTemplate(data) {
}); });
f01_sheet.spliceRows(3, 1); f01_sheet.spliceRows(3, 1);
// f01_sheet.getRow(2).height = 27; // f01_sheet.getRow(2).height = 27;
f01_sheet.orderNo = ml_number + 2 + 11; f01_sheet.orderNo = ml_number + 2 + 12;
} else { } else {
workbook.removeWorksheet('辅01表'); workbook.removeWorksheet('辅01表');
} }
@ -1864,14 +1689,14 @@ async function generateTemplate(data) {
}); });
}); });
f02_sheet.spliceRows(2, 1); f02_sheet.spliceRows(2, 1);
f02_sheet.orderNo = ml_number + 3 + 11; f02_sheet.orderNo = ml_number + 3 + 12;
} else { } else {
workbook.removeWorksheet('辅02表'); workbook.removeWorksheet('辅02表');
} }
if (data.majorCoes?.length) { if (data.majorCoes?.length) {
let f03_sheet = workbook.getWorksheet('辅03表'); let f03_sheet = workbook.getWorksheet('辅03表');
let num_f03 = 1; let num_f03 = 1;
data.majorCoes.sort((a, b) => majorList[a.majorid].order - majorList[b.majorid].order).forEach(mcoei => { 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]; let majorCoeX = majorList[mcoei.majorid];
cusInsertRowFunc(2 + num_f03, [f03_sheet.getRow(2)], f03_sheet, (targetRow) => { cusInsertRowFunc(2 + num_f03, [f03_sheet.getRow(2)], f03_sheet, (targetRow) => {
targetRow.getCell(1).value = num_f03++; targetRow.getCell(1).value = num_f03++;
@ -1883,7 +1708,7 @@ async function generateTemplate(data) {
}); });
}); });
f03_sheet.spliceRows(2, 1); f03_sheet.spliceRows(2, 1);
f03_sheet.orderNo = ml_number + 4 + 11; f03_sheet.orderNo = ml_number + 4 + 12;
} else { } else {
workbook.removeWorksheet('辅03表'); workbook.removeWorksheet('辅03表');
} }
@ -1898,6 +1723,85 @@ async function generateTemplate(data) {
window.workbook = workbook; 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; return workbook;
} catch (error) { } catch (error) {
console.log(error) console.log(error)