diff --git a/public/template20260226001test010.xlsx b/public/template20260226001test010.xlsx index e986e96..9076364 100644 Binary files a/public/template20260226001test010.xlsx and b/public/template20260226001test010.xlsx differ diff --git a/src/sql.ts b/src/sql.ts index 2862a66..c6b6b9c 100644 --- a/src/sql.ts +++ b/src/sql.ts @@ -644,6 +644,7 @@ async function generateTemplate(data) { let allAddtional = {}; let allReserve = {}; let allMajors = {}; + let allServiceMajors = new Set(); data.scale?.forEach(sci => { allMajors[sci.major] = { [data.contracts.length]: sci }; }); @@ -999,6 +1000,7 @@ async function generateTemplate(data) { }; }); allDet.forEach((m, mindex) => { + allServiceMajors.add(m.major); let majorX = majorList[m.major]; cusInsertRowFunc(4 + num_2, [sheet_2.getRow(4)], sheet_2, (targetRow) => { targetRow.getCell(1).value = num_2++; @@ -1762,17 +1764,25 @@ async function generateTemplate(data) { // 更新编制说明 const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); - // ctx.font = "12pt 宋体"; - // const maxTitleWidth = 336; - // const maxTextWidth = 720; - const pageMaxHei = 733; + // 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; + let descRowNum = 1; + let titleArr = paragraphLineBreakFor1112(data.name, ctx, 0); + descSheet.getRow(descRowNum).getCell(1).value = titleArr[0]; + descRowNum++; + if (titleArr.length > 1) { + for (let i = 1; i < titleArr.length; i++) { + cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => { + descRowNum++; + targetRow.getCell(1).value = titleArr[i]; + }); + } + } + descRowNum += 3; if (data.scale?.length) { let engCosts = data.scale.filter(f => f.major > 6 && majorList[f.major].hasCost); if (engCosts.length) { @@ -1827,8 +1837,18 @@ async function generateTemplate(data) { 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(',')}。`; + let text = descSheet.getRow(descRowNum).getCell(1).value + `${desc.join(',')}。`; + let textArr = paragraphLineBreakFor1112(text, ctx); + descSheet.getRow(descRowNum).getCell(1).value = textArr[0]; descRowNum++; + if (textArr.length > 1) { + for (let i = 1; i < textArr.length; i++) { + cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => { + descRowNum++; + targetRow.getCell(1).value = textArr[i]; + }); + } + } } else { descSheet.spliceRows(descRowNum, 1); } @@ -1836,6 +1856,38 @@ async function generateTemplate(data) { descSheet.spliceRows(descRowNum, 5); descRowNum++; } + descRowNum++; + if (allServiceMajors.size > 0) { + if (allServiceMajors.has(7) || allServiceMajors.has(18) || allServiceMajors.has(28)) { + descSheet.getRow(descRowNum).getCell(1).value = descSheet.getRow(descRowNum).getCell(1).value + '本次委托包括全部工程及费用。'; + descRowNum++; + } else { + let majorTexts = []; + let hasOther = false; + allServiceMajors.forEach(mid => { + if (mid > 6) { + majorTexts.push(majorList[mid].name); + } else { + hasOther = true; + } + }); + let text = descSheet.getRow(descRowNum).getCell(1).value + '本项目的' + majorTexts.join('、') + (hasOther ? '及其他专项工程。' : '。'); + let textArr = paragraphLineBreakFor1112(text, ctx); + descSheet.getRow(descRowNum).getCell(1).value = textArr[0]; + descRowNum++; + if (textArr.length > 1) { + for (let i = 1; i < textArr.length; i++) { + cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => { + descRowNum++; + targetRow.getCell(1).value = textArr[i]; + }); + } + } + } + } else { + descSheet.getRow(descRowNum).getCell(1).value = descSheet.getRow(descRowNum).getCell(1).value + '×××××。'; + } + return workbook; } catch (error) { console.log(error) @@ -1843,6 +1895,83 @@ async function generateTemplate(data) { } } +function paragraphLineBreakFor1112(paragraph, ctx, type = 1) {// 仅适用于内容为11或12号字体的段落 + // // number,最后判断是否数字 + // const numberNoBreak1 = /\d[\d,]*(?:\.\d+)?$/; + // const numberNoBreak2 = /^[\d,]*\.*\d+/; + // // number&unit + // const numberUnitNoBreak1 = /\d[\d,]*(?:\.\d+)?\s*(?:[a-zA-Z](?:[a-zA-Z\d·/]*[a-zA-Z\d])?)?$/; + // const numberUnitNoBreak2 = /^[\d,]*(?:\.\d+)?\s*[a-zA-Z](?:[a-zA-Z\d·/]*[a-zA-Z\d])?/; + // // 英文单词 + // const ewordNoBreak1 = /[a-zA-Z]+$/; + // const ewordNoBreak2 = /^[a-zA-Z]+/; + /* + 西文字符串 + */ + const matchASCIIChar1 = /[\x21-\x7E]+$/; + const matchASCIIChar2 = /^[\x21-\x7E]+/; + /* + 行首禁则 + 1.不能为段落第一个字符 + 2.将上一行最后1~2个字符转至下一行 + 3.上一行最后1~2个字符如符合数字、英文单词、公式等规则,应整个下移至本行 + */ + const forbidLineSta1 = /^[,,.。、::;;!!??)\]\})〕]}〉》」』】〗〙〛”’」』﹂﹄%‰℃°—–~·]/; + const forbidLineSta2 = /[,,.。、::;;!!??)\]\})〕]}〉》」』】〗〙〛”’」』﹂﹄%‰℃°—–~·]$/; + /* + 行尾禁则 + 1.不能为段落最后一个字符(即后续内容不能为空) + 2.将本行最后1~2个字符转至下一行 + */ + const forbidLineEnd = /[¥$€£@([{(〔[{〈《「『【〖〘〚“‘「『﹁﹃—–~·]+$/; + + ctx.font = "12pt 宋体"; + const maxWidth = type == 1 ? 720 : 336; + const minChar = Math.ceil(maxWidth / 8); + let text = paragraph; + let res = []; + // let enterRows = new Set(); + while (ctx.measureText(text).width > maxWidth) { + let t1 = text.slice(0, minChar); + let t1PX = ctx.measureText(t1).width; + while (t1PX > maxWidth) { + let t1MinChar = Math.floor((t1PX - maxWidth) / 16) || 1; + t1 = t1.slice(0, -1 * t1MinChar); + t1PX = ctx.measureText(t1).width; + } + let t2 = text.slice(t1.length); + if (matchASCIIChar1.test(t1) && matchASCIIChar2.test(t2)) { + let strASCII1 = t1.match(matchASCIIChar1)[0]; + if (strASCII1.length < t1.length) { + t1 = t1.slice(0, -1 * strASCII1.length); + t2 = text.slice(t1.length); + // enterRows.add(res.length); + } + } + if (forbidLineSta1.test(t2)) { + if (forbidLineSta2.test(t1)) { + t1 = t1.slice(0, -2); + } else { + t1 = t1.slice(0, -1); + } + t2 = text.slice(t1.length); + // enterRows.add(res.length); + } + if (forbidLineEnd.test(t1)) { + let endTrans = t1.match(forbidLineEnd)[0]; + t1 = t1.slice(0, -1 * (Math.min(endTrans.length, 2))); + t2 = text.slice(t1.length); + // enterRows.add(res.length); + } + res.push(t1); + text = text.slice(t1.length); + } + res.push(text); + // [...enterRows].forEach(ri => { + // res[ri] = res[ri] + '\n'; + // }); + return res; +} // 在指定位置插入行,并按模板行复制样式,可选回调填充值。 function cusInsertRowFunc(insertRowNum, sourceRows, worksheet, RowFun, cellFun) { @@ -1967,6 +2096,4 @@ function cloneCellValue(value) { return JSON.parse(JSON.stringify(value)); } return value; -} - - +} \ No newline at end of file