feat(word): Word_Save/Word_SaveAs 真实现(COM 落盘),替换路径回显占位
This commit is contained in:
parent
b18d5b1f0b
commit
4b5c73b752
@ -56,4 +56,27 @@ describe("Word extended capabilities", () => {
|
||||
await run("Word_WriteTable", { objWord: handle, data: [["name", "age"], ["Alice", "30"]] });
|
||||
await expect(run("Word_ReadTable", { objWord: handle, find_type: "content", table_content: "Alice" })).resolves.toEqual([["name", "age"], ["Alice", "30"]]);
|
||||
}, 180000);
|
||||
|
||||
it("saves and saves-as a Word document through real COM", async () => {
|
||||
if (process.platform !== "win32") return;
|
||||
const directory = await mkdtemp(path.join(os.tmpdir(), "rpa-word-saveas-")); directories.push(directory);
|
||||
const handle = await run("Word_New_V1", { filePath: directory, name: "source.docx" });
|
||||
await run("Word_Write", { objWord: handle, text: "另存前内容" });
|
||||
|
||||
await expect(run("Word_Save", { objWord: handle })).resolves.toEqual({ path: path.join(directory, "source.docx") });
|
||||
await expect(run("Word_Save", { objWord: { path: path.join(directory, "missing.docx") } })).rejects.toThrow("Word文件不存在");
|
||||
|
||||
const targetDir = path.join(directory, "out");
|
||||
const saved = await run("Word_SaveAs", { objWord: handle, fileAddr: targetDir, filename: "renamed" }) as { path: string };
|
||||
expect(saved.path).toBe(path.join(targetDir, "renamed.docx"));
|
||||
await expect(readFile(saved.path)).resolves.toBeTruthy();
|
||||
|
||||
const kept = await run("Word_SaveAs", { objWord: saved, fileAddr: directory }) as { path: string };
|
||||
expect(kept.path).toBe(path.join(directory, "renamed.docx"));
|
||||
await expect(readFile(kept.path)).resolves.toBeTruthy();
|
||||
|
||||
const relative = await run("Word_SaveAs", { objWord: kept, fileAddr: "sub", filename: "rel-target" }) as { path: string };
|
||||
expect(relative.path).toBe(path.join(directory, "sub", "rel-target.docx"));
|
||||
await expect(readFile(relative.path)).resolves.toBeTruthy();
|
||||
}, 180000);
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import path from "node:path";
|
||||
import { access, mkdir } from "node:fs/promises";
|
||||
import { register } from "../engine/registry";
|
||||
import { powershell, psString } from "../driver/windows/powershell";
|
||||
|
||||
@ -41,4 +42,31 @@ register("Word_Write", async (_ctx, _node, args) => {
|
||||
return { path: filePath } satisfies WordHandle;
|
||||
});
|
||||
|
||||
register(["Word_Save", "Word_SaveAs"], async (_ctx, _node, args) => ({ path: handlePath(args) } satisfies WordHandle));
|
||||
async function ensureFile(value: string): Promise<string> {
|
||||
try {
|
||||
await access(value);
|
||||
} catch {
|
||||
throw new Error(`Word文件不存在: ${value}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
register("Word_Save", async (_ctx, _node, args) => {
|
||||
const filePath = await ensureFile(ensure(handlePath(args), "Word文件路径"));
|
||||
// 打开即存:架构上每次操作独立开合 Word 实例,Save 负责兜底刷新并证明文件真实可写
|
||||
await powershell(wordScript(`$doc = $word.Documents.Open(${psString(filePath)}); $doc.Save()`));
|
||||
return { path: filePath } satisfies WordHandle;
|
||||
});
|
||||
|
||||
register("Word_SaveAs", async (_ctx, _node, args) => {
|
||||
const previousPath = await ensureFile(ensure(handlePath(args), "Word文件路径"));
|
||||
const rawDir = text(args, ["fileAddr", "path", "folder", "savePath"]);
|
||||
const rawName = text(args, ["filename", "name"]);
|
||||
// 目录空缺沿用原目录;目录相对时基于原文档目录解析;文件名空缺沿用原名(与 catalog 语义一致)
|
||||
const dir = rawDir ? path.resolve(path.dirname(previousPath), rawDir) : path.dirname(previousPath);
|
||||
const target = path.resolve(dir, rawName || path.basename(previousPath));
|
||||
const withExt = path.extname(target) ? target : `${target}.docx`;
|
||||
await mkdir(path.dirname(withExt), { recursive: true });
|
||||
await powershell(wordScript(`$doc = $word.Documents.Open(${psString(previousPath)}); $doc.SaveAs2(${psString(withExt)}); ${psString(withExt)}`));
|
||||
return { path: withExt } satisfies WordHandle;
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user