# KOKA开卷 · CAJ → PDF — 自动化操作说明 站点:https://koka-caj2pdf.pages.dev 性质:纯静态,文件不上传,转换在浏览器内完成。无需登录。 ## 一次操作只需四步 1. 打开站点。 2. 选文件:`#fileInput`(隐藏的 multiple input,用 setInputFiles 直接赋值,不必点按钮)。 3. 等转换:轮询 `window.__cajState()`,当 `done + failed + cancelled === total` 且 `total > 0` 即完成。 4. 下载:点 `#zipBtn`,接住浏览器 download 事件(打包成 zip)。 ## 硬性规则 - 一次最多 100 个文件(`__cajState().batchLimit`)。超出部分会被忽略并给出提示。 - 队列容量是按「当前队列内文件数」计算的。下一批前先点 `#resetBtn` 清空。 - 并发为 2,无需调节,脚本只负责等待。 - 结果只在页面内存/OPFS,关闭页面即丢失。 - 失败项:点 `#retryFailedBtn` 重试;也可逐行 `[data-action="retry"]`。 - 站点无后端、无 API,不要尝试 POST 文件。 ## 稳定选择器 | 用途 | 选择器 | | --- | --- | | 文件输入(hidden, multiple) | `#fileInput` | | 汇总条 | `#summary`,带 `data-total` `data-done` `data-failed` `data-cancelled` `data-packing` | | 每行 | `li.row[data-status][data-name]` | | 重试失败 | `#retryFailedBtn` | | 打包下载 | `#zipBtn` | | 清空队列 | `#resetBtn` | | 版本号 | `#version` | 就绪判据(任选其一,推荐第 1 条): ```js window.__cajState().done + window.__cajState().failed + window.__cajState().cancelled === window.__cajState().total ``` ```js const s = document.querySelector('#summary').dataset; s.total > 0 && Number(s.done) + Number(s.failed) + Number(s.cancelled) === Number(s.total) ``` ## Playwright 参考脚本(可直接照抄) ```js import { chromium } from "playwright"; const browser = await chromium.launch(); const page = await browser.newPage({ acceptDownloads: true }); await page.goto("https://koka-caj2pdf.pages.dev/"); // 一批最多 100 个 await page.setInputFiles("#fileInput", ["a.caj", "b.kdh", "c.c8"]); await page.waitForFunction( () => { const s = window.__cajState?.(); return s && s.total > 0 && s.done + s.failed + s.cancelled === s.total; }, null, { timeout: 0 }, ); const download = page.waitForEvent("download"); await page.click("#zipBtn"); await (await download).saveAs("out.zip"); await page.close(); await browser.close(); ``` 多批处理:每批转换并下载后 `await page.click("#resetBtn")`,再 `setInputFiles` 下一批。 ## 失败排查 - 一直不满足就绪判据:查 `#notice` 的文本(打包错误会显示在这里)。 - `#zipBtn` 为 disabled:说明没有已完成的条目,检查 `__cajState().done`。 - 单条失败:读该行的 `data-status="failed"` 与行内状态文案。