优化成果报表导出功能

This commit is contained in:
ForeverSmiYng 2026-03-18 11:13:39 +08:00
parent 5a11b7431f
commit e71a454d8c
4 changed files with 518 additions and 29 deletions

367
public/data.js Normal file
View File

@ -0,0 +1,367 @@
let data1 = {
name: 'test001',
writer: '张三',// 编制人
reviewer: '李四',// 复核人
company: '测试公司',// 公司名称
date: '2021-09-24',// 编制日期
industry: 0,// 0为公路工程1为铁路工程2为水运工程
fee: 10000,
scaleCost: 100000,// scale的cost的合计数
overview: '项目概况××××',
desc: ' 在履行造价咨询服务时宜根据咨询服务质量情况分级确定相应的处罚金额。其中考评得分在大于及等于85和小于90分时处罚金额为预算费用的10%其中考评得分在大于及等于80和小于85分时处罚金额为预算费用的20%其中考评得分在大于及等于75和小于80分时处罚金额为预算费用的30%其中考评得分在大于及等于70和小于75分时处罚金额为预算费用的40%其中考评得分小于70分时处罚金额为预算费用的50%以上。',
scale: [// 规模信息
{
major: 0,
cost: 100000,
area: 200,
},
{
major: 1,
cost: 100000,
area: 200,
},
],
serviceCoes: [// 项目咨询分类系数
{
serviceid: 0,
coe: 1.1,
remark: '',// 用户输入的说明
},
{
serviceid: 1,
coe: 1.2,
remark: '',// 用户输入的说明
},
],
majorCoes: [// 项目工程专业系数
{
majorid: 0,
coe: 1.1,
remark: '',// 用户输入的说明
},
{
majorid: 1,
coe: 1.2,
remark: '',// 用户输入的说明
},
],
contracts: [// 合同段信息
{
name: 'A合同段',
serviceFee: 100000,
addtionalFee: 0,
reserveFee: 0,
fee: 10000,
quality: '造价咨询服务的综合评价应达到“较好”或综合评分90分',
duration: '自xxxx年xx月开始至xxxx年xx月结束服务周期xx个月。',
scale: [
{
major: 0,
cost: 100000,
area: 200,
},
{
major: 1,
cost: 100000,
area: 200,
},
],
serviceCoes: [// 合同段咨询分类系数
{
serviceid: 0,
coe: 1.1,
remark: '',// 用户输入的说明
},
{
serviceid: 1,
coe: 1.2,
remark: '',// 用户输入的说明
},
],
majorCoes: [// 合同段工程专业系数
{
majorid: 0,
coe: 1.1,
remark: '',// 用户输入的说明
},
{
majorid: 1,
coe: 1.2,
remark: '',// 用户输入的说明
},
],
services: [
{
id: 0,
fee: 100000,
finalFee: 100000,
process: 0,// 工作环节0为编制1为审核
method1: { // 投资规模法
cost: 100000,
basicFee: 200,
basicFee_basic: 200,
basicFee_optional: 0,
fee: 250000,
proAmount: 3,
det: [
{
proNum: 1,
major: 0,
cost: 100000,
basicFee: 200,
basicFormula: '856,000+(1,000,000,000-500,000,000)×1‰',
basicFee_basic: 200,
optionalFormula: '171,200+(1,000,000,000-500,000,000)×0.2‰',
basicFee_optional: 0,
serviceCoe: 1.1,
majorCoe: 1.2,
processCoe: 1,// 工作环节系数(编审系数)
proportion: 0.5,// 工作占比
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
method2: { // 用地规模法
area: 1200,
basicFee: 200,
basicFee_basic: 200,
basicFee_optional: 0,
fee: 250000,
proAmount: 3,
det: [
{
proNum: 1,
major: 0,
area: 1200,
basicFee: 200,
basicFormula: '106,000+(1,200-1,000)×60',
basicFee_basic: 200,
optionalFormula: '21,200+(1,200-1,000)×12',
basicFee_optional: 0,
serviceCoe: 1.1,
majorCoe: 1.2,
processCoe: 1,// 工作环节系数(编审系数)
proportion: 0.5,// 工作占比
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
method3: { // 工作量法
basicFee: 200,
fee: 250000,
det: [
{
task: 0,
price: 100000,
amount: 10,
basicFee: 200,
serviceCoe: 1.1,
fee: 100000,
remark: '',// 用户输入的说明
},
{
task: 1,
price: 100000,
amount: 10,
basicFee: 200,
serviceCoe: 1.1,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
method4: { // 工时法
person_num: 10,
work_day: 10,
fee: 250000,
det: [
{
expert: 0,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
{
expert: 1,
price: 100000,
person_num: 10,
work_day: 3,
fee: 100000,
remark: '',// 用户输入的说明
},
],
},
tasks: [{ serviceid: 0, process: 0, text: ['abc', 'efg'] }, { serviceid: 1, process: 0, text: ['abc', 'efg'] }],// 工作内容
},
],
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: '',// 用户输入的说明
},
],
},
},
]
},
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: '',// 用户输入的说明
},
],
}
},
},
],
};

View File

@ -152,7 +152,8 @@ export const expertList = {
};
export const additionalWorkList = [
{ id:'1',
{
id: '1',
code: {
richText: [
{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' },
@ -161,7 +162,8 @@ export const additionalWorkList = [
},
name: '人员驻场服务及其他附加工作'
},
{id:'2',
{
id: '2',
code: {
richText: [
{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' },
@ -736,7 +738,7 @@ export async function exportFile(fileName: string, data: any | (() => Promise<an
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
async function generateTemplate(data) {
data.contracts[0].services[0].tasks = ['依据本项目在招标阶段确认的设计图纸工程量,结合工程量清单计量支付规则,对设计工程量进行复核,包括构件工程量、明细表工程量和汇总表工程量,同时与相关方核对工程量', '依据核对后确认的设计图纸数量,细化与合并招标工程量清单或合同工程量清单,建立各维度清单间的数据链接,与相关单位完成核对与确认', '依据确定的招标工程量清单或合同工程量清单,拆解与合并相应的清单费用,与相关单位完成核对与确认', '现场勘查与测量现场实施工程量'];
// data.contracts[0].services[0].tasks = [{ 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)
// 编制说明 → 工作内容的前后默认项
@ -2096,6 +2098,7 @@ async function generateTemplate(data) {
// 合同段划分
descSheet.spliceRows(descRowNum, 1);
// 咨询服务类型
if (data.contracts[0].services.length) {
let serviceText = ' (二)咨询服务类型:' + data.contracts[0].services.slice(0, -1).map(si => serviceList[si.id].name).join('、') + (data.contracts[0].services.length > 1 ? '和' : '') + serviceList[data.contracts[0].services.slice(-1)[0].id].name + '。';
let serviceTextArr = paragraphLineBreakFor1112(serviceText, ctx);
serviceTextArr.forEach(ti => {
@ -2104,8 +2107,109 @@ async function generateTemplate(data) {
targetRow.getCell(1).value = ti;
});
});
// 工作内容及要求
descSheet.spliceRows(descRowNum, 1);
} else {
descSheet.getRow(descRowNum).getCell(1).value = ' (二)咨询服务类型:×××××。';
descRowNum++;
}
// 工作内容及要求
let ci = data.contracts[0];
let ciTastNum = 1;
let ciTaskTitle = ` (三)${ci.name}工作内容及要求`;
let ciTaskTitleArr = paragraphLineBreakFor1112(ciTaskTitle, ctx);
ciTaskTitleArr.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
});
});
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ' 1.工作内容包括:';
});
if (ci.hasPreTexts) {
prefixTexts.forEach(ti => {
let texts = paragraphLineBreakFor1112(` ${ciTastNum}${ti}`, ctx);
texts.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
ciTastNum++;
});
});
});
}
ci.services.forEach((si, sindex) => {
let siTextArr = paragraphLineBreakFor1112(` ${ciTastNum}${si.process == null ? '' : (si.process == 1 ? '审核' : '编制')}${serviceList[si.id].name},具体工作内容包括:`, ctx);
siTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
ciTastNum++;
});
});
if (si.tasks?.length) {
si.tasks.forEach((sti, stindex) => {
let stiTextArr = paragraphLineBreakFor1112(` ${stindex + 1}${sti}`, ctx);
stiTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
});
});
});
} else {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ' 1×××××。';
});
}
});
if (ci.addtional && ci.addtional.det.length) {
ci.addtional.det.forEach(ai => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ` ${ciTastNum}${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
ciTastNum++;
});
if (ai.tasks?.length) {
ai.tasks.forEach((ati, atindex) => {
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1}${ati}`, ctx);
atiTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
});
});
});
} else {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ' 1×××××。';
});
}
});
}
if (ci.hasSufTexts) {
suffixTexts.forEach(ti => {
let texts = paragraphLineBreakFor1112(` ${ciTastNum}${ti}`, ctx);
texts.forEach(ti => {
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ti;
ciTastNum++;
});
});
});
}
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ` 2.质量标准:${ci.quality || '×××××'}${/$/.test(ci.quality) ? '' : '。'}`;
});
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
descRowNum++;
targetRow.getCell(1).value = ` 3.服务工期:${ci.duration || '×××××'}${/$/.test(ci.duration) ? '' : '。'}`;
});
} else {
descSheet.getRow(descRowNum).getCell(1).value = descSheet.getRow(descRowNum).getCell(1).value.replace(/×××/g, data.contracts.length);
let descRowNum1 = descRowNum + 1;
@ -2143,7 +2247,11 @@ async function generateTemplate(data) {
});
// 咨询服务类型
descRowNum2 = descRowNum1 + descRowNum2 + 1;
let ciServiceText = ` ${cindex + 1}.${ci.name}` + ci.services.slice(0, -1).map(si => serviceList[si.id].name).join('、') + (ci.services.length > 1 ? '和' : '') + serviceList[ci.services.slice(-1)[0].id].name + '。';
if (ci.services.length) {
var ciServiceText = ` ${cindex + 1}.${ci.name}` + ci.services.slice(0, -1).map(si => serviceList[si.id].name).join('、') + (ci.services.length > 1 ? '和' : '') + serviceList[ci.services.slice(-1)[0].id].name + '。';
} else {
var ciServiceText = ` ${cindex + 1}.${ci.name}:×××××。`;
}
let ciServiceTextArr = paragraphLineBreakFor1112(ciServiceText, ctx);
ciServiceTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum2, [descSheet.getRow(descRowNum2 - 1)], descSheet, (targetRow) => {
@ -2164,7 +2272,7 @@ async function generateTemplate(data) {
});
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
targetRow.getCell(1).value = ` 1.工作内容包括:`;
targetRow.getCell(1).value = ' 1.工作内容包括:';
});
if (ci.hasPreTexts) {
prefixTexts.forEach(ti => {
@ -2179,7 +2287,7 @@ async function generateTemplate(data) {
});
}
ci.services.forEach((si, sindex) => {
let siTextArr = paragraphLineBreakFor1112(` ${ciTastNum}${si.process == 1 ? '审核' : '编制'}${serviceList[si.id].name},具体工作内容包括:`, ctx);
let siTextArr = paragraphLineBreakFor1112(` ${ciTastNum}${si.process == null ? '' : (si.process == 1 ? '审核' : '编制')}${serviceList[si.id].name},具体工作内容包括:`, ctx);
siTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
@ -2187,7 +2295,8 @@ async function generateTemplate(data) {
ciTastNum++;
});
});
si.tasks?.forEach((sti, stindex) => {
if (si.tasks?.length) {
si.tasks.forEach((sti, stindex) => {
let stiTextArr = paragraphLineBreakFor1112(` ${stindex + 1}${sti}`, ctx);
stiTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
@ -2196,6 +2305,12 @@ async function generateTemplate(data) {
});
});
});
} else {
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
targetRow.getCell(1).value = ' 1×××××。';
});
}
});
if (ci.addtional && ci.addtional.det.length) {
ci.addtional.det.forEach(ai => {
@ -2204,7 +2319,8 @@ async function generateTemplate(data) {
targetRow.getCell(1).value = ` ${ciTastNum}${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
ciTastNum++;
});
ai.tasks?.forEach((ati, atindex) => {
if (ai.tasks?.length) {
ai.tasks.forEach((ati, atindex) => {
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1}${ati}`, ctx);
atiTextArr.forEach(ti => {
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
@ -2213,6 +2329,12 @@ async function generateTemplate(data) {
});
});
});
} else {
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
targetRow.getCell(1).value = ' 1×××××。';
});
}
});
}
if (ci.hasSufTexts) {
@ -2229,11 +2351,11 @@ async function generateTemplate(data) {
}
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
targetRow.getCell(1).value = ` 2.质量标准:${ci.quality || '×××'}${/$/.test(ci.quality) ? '' : '。'}`;
targetRow.getCell(1).value = ` 2.质量标准:${ci.quality || '×××××'}${/$/.test(ci.quality) ? '' : '。'}`;
});
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
descRowNum3++;
targetRow.getCell(1).value = ` 3.服务工期:${ci.duration || '×××'}${/$/.test(ci.duration) ? '' : '。'}`;
targetRow.getCell(1).value = ` 3.服务工期:${ci.duration || '×××××'}${/$/.test(ci.duration) ? '' : '。'}`;
});
});
descRowNum = descRowNum3;