From 8cedf45628128e73e004bf001d7c5bba3c1c3ed5 Mon Sep 17 00:00:00 2001 From: yu <191972707@qq.com> Date: Thu, 29 Oct 2026 15:57:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E6=A0=BC=E5=BC=8F=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=95=88=E4=B8=8E=E8=A1=A8=E6=A0=BC=E6=A0=B7=E5=BC=8F=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E5=8D=95=E5=85=83=E6=A0=BC=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SetCellFormat V1/V2/V3:格式解析补厂商 JSON 键映射(FontColor/FontSize/ BoldAndItalic 位标志/BackgroundColor 带透明度/DigitalFormat.formatstring/ FontFormat 字体名),纯格式代码(如 0.00)回落为数字格式——此前全部被静默忽略 - ShowTableStyle:行级样式(row.font/fill+commit)在 exceljs 中会覆盖该行 已设置的单元格样式,改为逐单元格设置表头样式 - 经 18 节点覆盖流程实测:V3 红字宋体加粗、V2 蓝字、V1 数字格式 0.00 均落盘 --- src/main/capabilities/excel-common.ts | 41 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/capabilities/excel-common.ts b/src/main/capabilities/excel-common.ts index e61a1aa..cd8e9cd 100644 --- a/src/main/capabilities/excel-common.ts +++ b/src/main/capabilities/excel-common.ts @@ -625,13 +625,13 @@ function toArgb(color: string): string { return hex.length === 6 ? "FF" + hex : hex.padStart(8, "F"); } -function parseFormatSpec(raw: unknown): { bold?: boolean; italic?: boolean; underline?: boolean; fontSize?: number; color?: string; bgColor?: string; numFmt?: string } { - if (typeof raw === "object" && raw !== null) return raw as ReturnType; +function parseFormatSpec(raw: unknown): { bold?: boolean; italic?: boolean; underline?: boolean; fontSize?: number; color?: string; bgColor?: string; numFmt?: string; fontName?: string } { + if (typeof raw === "object" && raw !== null) return normalizeFormatSpec(raw as Record); const text = String(raw ?? "").trim(); if (!text) return {}; try { const parsed = JSON.parse(text) as Record; - if (typeof parsed === "object" && parsed) return parsed as ReturnType; + if (typeof parsed === "object" && parsed) return normalizeFormatSpec(parsed); } catch { /* fall through to keywords */ } const spec: ReturnType = {}; const lower = text.toLowerCase(); @@ -640,6 +640,26 @@ function parseFormatSpec(raw: unknown): { bold?: boolean; italic?: boolean; unde if (/下划线|underline/.test(lower)) spec.underline = true; const sizeMatch = text.match(/(\d+)号|font-size[::]\s*(\d+)/i); if (sizeMatch) spec.fontSize = Number(sizeMatch[1] || sizeMatch[2]); + // 无关键词命中时视为数字格式代码(如 "0.00"、"G/通用格式"、"yyyy-mm-dd") + if (!Object.keys(spec).length) spec.numFmt = text; + return spec; +} + +/** 兼容厂商格式 JSON(FontColor/BoldAndItalic/FontSize/BackgroundColor/DigitalFormat)与内部 camelCase 键 */ +function normalizeFormatSpec(parsed: Record): ReturnType { + const spec: ReturnType = {}; + const flags = Number(parsed.BoldAndItalic ?? 0); + if (flags & 1) spec.bold = true; + if (flags & 2) spec.italic = true; + if (parsed.FontFormat) spec.fontName = String(parsed.FontFormat); + if (parsed.FontSize !== undefined && parsed.FontSize !== null && String(parsed.FontSize).trim() !== "") spec.fontSize = Number(parsed.FontSize); + if (parsed.FontColor) spec.color = String(parsed.FontColor); + if (parsed.BackgroundColor) spec.bgColor = String(parsed.BackgroundColor).split(",")[0].trim(); + const digital = parsed.DigitalFormat as { formatstring?: unknown } | undefined; + if (digital?.formatstring && String(digital.formatstring).trim() !== "") spec.numFmt = String(digital.formatstring); + for (const key of ["bold", "italic", "underline", "fontSize", "color", "bgColor", "numFmt"] as const) { + if (parsed[key] !== undefined) (spec as Record)[key] = parsed[key]; + } return spec; } @@ -670,6 +690,7 @@ registerMany(["Excel_Cs_SetCellFormat", "Excel_Cs_SetCellFormat_V2", "Excel_Cs_S italic: spec.italic, underline: spec.underline, size: spec.fontSize, + name: spec.fontName ?? cell.font?.name, color: spec.color ? { argb: toArgb(spec.color) } : undefined }; } @@ -697,11 +718,15 @@ register("Excel_Cs_ExcelFilter", async (ctx, node, args) => { register("Excel_Cs_ShowTableStyle", async (ctx, node, args) => { const source = await loadWorkbook(args, node.id, node.componentId); const sheet = worksheetOf(source.workbook, args); - const headerRow = sheet.getRow(1); - headerRow.font = { ...headerRow.font, bold: true }; - headerRow.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFD9E8F5" } }; - headerRow.commit(); - sheet.autoFilter = { from: { row: 1, column: 1 }, to: { row: Math.max(1, sheet.rowCount), column: Math.max(1, sheet.columnCount) } }; + // 必须逐单元格设置:exceljs 的行级样式(row.font/row.fill + commit)会覆盖 + // 该行已设置的单元格样式(如先执行过的设置单元格格式) + const lastCol = Math.max(1, sheet.columnCount); + for (let c = 1; c <= lastCol; c += 1) { + const cell = sheet.getRow(1).getCell(c); + cell.font = { ...cell.font, bold: true }; + cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFD9E8F5" } }; + } + sheet.autoFilter = { from: { row: 1, column: 1 }, to: { row: Math.max(1, sheet.rowCount), column: lastCol } }; await saveWhenRequested(source, args, true); ctx.log("已应用表格样式(表头加粗 + 筛选)", "info", node.id); return { styled: true };