fix: 对齐 Excel 新建/打开组件的目录字段键名

- newExcel 兼容 Excel_NewExcel 的 filePath 键(此前只读 path/folder,
  导致已填写文件路径仍报「Excel目录为空」)
- newExcel 支持 isMakedirs(是否创建该路径):False 且目录不存在时
  给出明确报错与建议;缺省时保持自动创建目录
- openExcel 兼容 Excel_OpenExcel / Excel_OpenExcelNew 的 filePath 键
- bool() 大小写不敏感,正确识别目录下拉框的 True/False
- 补充别名键名回归测试(4 例)
This commit is contained in:
yu 2026-10-28 10:55:47 +08:00
parent 5e9f0df57f
commit 877dab703f
2 changed files with 29 additions and 2 deletions

View File

@ -31,4 +31,22 @@ describe("common Excel aliases", () => {
await run("Excel_WriteCellNew", { workbook: handle, sheet: "Sheet1", row: 1, column: "A", content: "alias", save: "1" });
await expect(run("Excel_ReadCellNew", { workbook: handle, sheet: "Sheet1", row: 1, column: "A" })).resolves.toBe("alias");
});
it("accepts the Excel_NewExcel catalog keys (filePath / isMakedirs)", async () => {
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-new-")); dirs.push(directory);
const handle = await run("Excel_NewExcel", { filePath: directory, name: "catalog-keys.xlsx", isMakedirs: "True" }) as { path: string };
expect(handle.path).toBe(path.resolve(directory, "catalog-keys.xlsx"));
});
it("rejects a missing directory when isMakedirs is False", async () => {
const directory = path.join(await mkdtemp(path.join(os.tmpdir(), "rpa-excel-new-")), "missing");
dirs.push(directory);
await expect(run("Excel_NewExcel", { filePath: directory, name: "none.xlsx", isMakedirs: "False" })).rejects.toThrow("目录不存在");
});
it("opens a workbook through the Excel_OpenExcel filePath key", async () => {
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-open-")); dirs.push(directory);
const created = await run("Excel_NewExcel", { filePath: directory, name: "open-me.xlsx" }) as { path: string };
await expect(run("Excel_OpenExcel", { filePath: created.path })).resolves.toMatchObject({ path: created.path });
});
});

View File

@ -24,6 +24,7 @@ function text(args: Record<string, unknown>, keys: string[], fallback = ""): str
function bool(valueToRead: unknown, fallback = false): boolean {
if (valueToRead === undefined || valueToRead === null || valueToRead === "") return fallback;
if (typeof valueToRead === "string") return ["true", "1", "yes", "是", "开启"].includes(valueToRead.trim().toLowerCase());
return [true, "true", "1", 1, "是", "开启"].includes(valueToRead as never);
}
@ -101,9 +102,17 @@ function rowsFrom(valueToRead: unknown): unknown[][] {
}
const newExcel: CapabilityHandler = async (_ctx, node, args) => {
const folder = required(value(args, ["path", "folder"]), "Excel目录", node.id, node.componentId);
const folder = required(value(args, ["filePath", "path", "folder"]), "文件路径", node.id, node.componentId);
const name = text(args, ["name"], "新建工作簿.xlsx");
const filePath = path.resolve(folder, path.extname(name) ? name : `${name}.xlsx`);
const makedirs = bool(value(args, ["isMakedirs"]), true);
if (!makedirs) {
try {
await fs.access(path.dirname(filePath));
} catch {
throw new RuntimeError("validation_error", `目录不存在:${path.dirname(filePath)}`, { nodeId: node.id, componentId: node.componentId, recommendation: "将「是否创建该路径」设为 True,或先创建目录" });
}
}
if (!bool(value(args, ["override"]), true)) {
try {
await fs.access(filePath);
@ -120,7 +129,7 @@ const newExcel: CapabilityHandler = async (_ctx, node, args) => {
};
const openExcel: CapabilityHandler = async (_ctx, node, args) => {
const filePath = required(value(args, ["file", "path"]), "Excel文件", node.id, node.componentId);
const filePath = required(value(args, ["file", "filePath", "path"]), "Excel文件", node.id, node.componentId);
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(path.resolve(filePath));
return newHandle(path.resolve(filePath), workbook);