fix: 统一 Excel 工作簿共享存储,修复多组件互相覆盖

office.ts(内存句柄表)、office-file-extended.ts(每次重读磁盘)、
excel-common.ts(按路径独立缓存)、extended.ts(loadSheet 每次重建)
各自持有工作簿实例并整簿写回同一文件,后保存者会整体覆盖先保存者:
列宽/行高/合并被背景色冲掉、复制的 Sheet 被新建 Sheet 冲掉等。

- 新增 excel-store.ts:按路径共享同一 ExcelJS 实例,四个模块统一接入
- resolveWorkbook 返回流程变量持有的原始句柄对象,另存为改写 path
  能同步到后续节点(此前改在副本上,下游仍写旧路径)
- 另存为后以新路径重新登记实例并释放旧路径缓存
- ReadColumn 裁掉尾部空值(共享实例下触碰空行会撑大 rowCount)
- 新增 3 个共享存储回归测试(格式保持/复制Sheet保持/另存后续写)
This commit is contained in:
yu committed 2026-10-28 13:32:01 +08:00
1 parent 54571eff8d
commit 9de0eeaa88
6 files changed
+128 -24

No files matched your search

+3 -8
View File
@@ -2,11 +2,11 @@ import ExcelJS from "exceljs";
import path from "node:path";
import { register } from "../engine/registry";
import { RuntimeError, type CapabilityHandler } from "../engine/types";
import { acquireWorkbook, releaseWorkbook } from "./excel-store";
type WorkbookSource = { workbook: ExcelJS.Workbook; filePath: string };
type CopiedRange = { values: unknown[][]; styles: Partial<ExcelJS.Style>[][] };
const workbookCache = new Map<string, ExcelJS.Workbook>();
let copiedRange: CopiedRange | undefined;
function value(args: Record<string, unknown>, keys: string[], fallback: unknown = ""): unknown {
@@ -46,12 +46,7 @@ function requiredPath(candidate: unknown, nodeId: string, componentId: string):
async function loadWorkbook(args: Record<string, unknown>, nodeId: string, componentId: string): Promise<WorkbookSource> {
const filePath = requiredPath(value(args, ["workbook", "objExcel", "objExcelWorkBook", "file", "path"]), nodeId, componentId);
let workbook = workbookCache.get(filePath);
if (!workbook) {
workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(filePath);
workbookCache.set(filePath, workbook);
}
const workbook = await acquireWorkbook(filePath);
return { workbook, filePath };
}
@@ -558,7 +553,7 @@ const splitColumn: CapabilityHandler = async (_ctx, node, args) => {
const closeWorkbook: CapabilityHandler = async (_ctx, node, args) => {
const source = await loadWorkbook(args, node.id, node.componentId);
if (truthy(value(args, ["save", "isSave"]), true)) await source.workbook.xlsx.writeFile(source.filePath);
workbookCache.delete(source.filePath);
releaseWorkbook(source.filePath);
return source.filePath;
};