diff --git a/src/main/capabilities/office-aliases.test.ts b/src/main/capabilities/office-aliases.test.ts index 249abda..f89e59a 100644 --- a/src/main/capabilities/office-aliases.test.ts +++ b/src/main/capabilities/office-aliases.test.ts @@ -1,6 +1,7 @@ import { readFile, mkdtemp, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; +import ExcelJS from "exceljs"; import { fileURLToPath } from "node:url"; import { afterEach, describe, expect, it } from "vitest"; import type { Catalog, CatalogComponent, FlowNode } from "../../shared/types"; @@ -84,6 +85,17 @@ describe("common Excel aliases", () => { expect(savedAs.path).toBe(path.resolve(directory, "rel-target.xlsx")); }); + it("combines the Excel_Cs_SaveAs directory path with the name field", async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-saveas-cs-")); dirs.push(directory); + const created = await run("Excel_NewExcel", { filePath: directory, name: "cs-origin.xlsx" }) as { path: string }; + const targetDir = path.join(directory, "nested"); + const savedAs = await run("Excel_Cs_SaveAs", { workbook: created, path: targetDir, name: "cs-target.xlsx" }) as { path: string }; + expect(savedAs.path).toBe(path.resolve(targetDir, "cs-target.xlsx")); + const reopened = new ExcelJS.Workbook(); + await reopened.xlsx.readFile(savedAs.path); + expect(reopened.worksheets.length).toBeGreaterThan(0); + }); + it("clears a range through the Excel_ClearRange cellPos key", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-excel-clear-")); dirs.push(directory); const created = await run("Excel_NewExcel", { filePath: directory, name: "clear.xlsx" }) as { path: string }; diff --git a/src/main/capabilities/office.ts b/src/main/capabilities/office.ts index 134b06d..9786cb2 100644 --- a/src/main/capabilities/office.ts +++ b/src/main/capabilities/office.ts @@ -178,9 +178,13 @@ const saveExcel: CapabilityHandler = async (_ctx, node, args) => { const saveAsExcel: CapabilityHandler = async (_ctx, node, args) => { const { handle, workbook } = await resolveWorkbook(args, node.id, node.componentId); - const raw = required(value(args, ["path", "file", "savePath", "filename", "saveFilePath"]), "另存为路径", node.id, node.componentId); + // CS 版(Excel_Cs_SaveAs)用 path=目录 + name=文件名;Legacy(Excel_SaveAs)用 filename=完整路径 + const rawName = text(args, ["name"]); + const raw = rawName + ? path.resolve(text(args, ["path", "file", "savePath"], ""), rawName) + : required(value(args, ["path", "file", "savePath", "filename", "saveFilePath"]), "另存为路径", node.id, node.componentId); // Legacy Excel_SaveAs 用 isAbsolutePath 标记 filename 是否为绝对路径,相对路径基于原文件目录 - const absolute = bool(value(args, ["isAbsolutePath"]), true); + const absolute = rawName ? true : bool(value(args, ["isAbsolutePath"]), true); const previousPath = handle.path; handle.path = absolute ? path.resolve(raw) : path.resolve(path.dirname(previousPath), raw); await fs.mkdir(path.dirname(handle.path), { recursive: true });