diff --git a/PROGRESS.md b/PROGRESS.md index 6142e32..d84a586 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-05-25(dev SPA 上传入口显示进度) +最后更新:2026-05-25(dev SPA 前端 CDN 资源本地化) --- @@ -23,6 +23,7 @@ ### 2026-05-25 +- **dev SPA 前端 CDN 资源本地化 + 升级稳定版**:`web/static/dev.html` 顶部 markdown 渲染依赖从 jsDelivr CDN 改成本地 `web/static/vendor/markdown/` 文件,避免内网/跨境访问 CDN 抖动导致 Markdown / XSS sanitizer / 代码高亮不可用。版本按 npm/latest 核对后固定为 `marked@16.2.1`(`marked.umd.js`)、`dompurify@3.2.6`、`highlight.js@11.11.1`(含 `github.min.css`),并新增 `tests/test_static_vendor.py` 标准库 unittest 回归检查:HTML 不再出现 `cdn.jsdelivr.net`,且 4 个本地 vendor 文件存在非空。`DESIGN.md` 不动(无架构变化);`RUN.md` 不动(运行方式无变化)。 - **dev SPA 三类上传入口显示进度**:`web/static/dev.html` 上传底层从 `fetch` 改为 `XMLHttpRequest` 以使用 `xhr.upload.onprogress`,保留 `/v1/files/upload` 后端 API 不变。`uploadFiles(files,{onProgress})` 统一服务 Ctrl+V 粘贴、右侧上传按钮、右侧拖拽上传;粘贴时 `#chat-hint` 显示 `上传中 N% · 文件名 · 已传/总量`,完成后仍切到可预览/可删除 chip;右侧上传按钮和拖拽入口共用 `#file-upload-status` 状态条,显示总进度条和完成/失败短提示,成功后刷新文件列表。`DESIGN.md` 不动(纯 dev SPA 上传交互);`RUN.md` 不动(运行方式无变化)。 - **dev SPA Ctrl+V 粘贴上传 chip 支持删除**:`web/static/dev.html` 粘贴上传成功后的 chip 改成 `paste-chip-wrap` 组合控件:文件名按钮继续预览,右侧 `×` 调 `POST /v1/files/delete` 删除该上传文件(`recursive:false`),删除后移除对应 chip、刷新右侧文件栏;若主/小预览当前正打开这个 rel,同步关闭对应预览。全部 chip 删除完后 `chat-hint` 显示"已删除粘贴文件"。`DESIGN.md` 不动(纯 dev SPA 交互);`RUN.md` 不动(运行方式无变化)。 - **dev SPA Ctrl+V 粘贴上传反馈改成可预览 chip**:`web/static/dev.html` `uploadFiles()` 成功时返回 `/v1/files/upload` 的 `saved[]` 元数据,粘贴文件后 `#chat-hint` 显示"已粘贴" + `.art-chip` 文件 chip + "可在右侧文件处查看",不再 4s 自动消失,下一次发送时由原有"发送中…"状态覆盖。chip 点击复用 `openFilePreview`;若主文件预览框已打开,改开新增的 `#mini-preview-modal` 小预览窗(支持 image/video/pdf/text/md,其它格式给下载兜底),避免覆盖用户当前正在看的主预览。`DESIGN.md` 不动(纯 dev SPA 交互);`RUN.md` 不动(运行方式无变化)。 diff --git a/tests/test_static_vendor.py b/tests/test_static_vendor.py new file mode 100644 index 0000000..0bc9057 --- /dev/null +++ b/tests/test_static_vendor.py @@ -0,0 +1,32 @@ +from pathlib import Path +import unittest + + +ROOT = Path(__file__).resolve().parents[1] +DEV_HTML = ROOT / "web" / "static" / "dev.html" +VENDOR_DIR = ROOT / "web" / "static" / "vendor" / "markdown" + + +class StaticVendorTests(unittest.TestCase): + def test_dev_html_uses_local_markdown_vendor_assets(self) -> None: + html = DEV_HTML.read_text(encoding="utf-8") + + self.assertNotIn("cdn.jsdelivr.net", html) + self.assertIn('src="vendor/markdown/marked.umd.js"', html) + self.assertIn('src="vendor/markdown/purify.min.js"', html) + self.assertIn('src="vendor/markdown/highlight.min.js"', html) + self.assertIn('href="vendor/markdown/github.min.css"', html) + + for name in ( + "marked.umd.js", + "purify.min.js", + "highlight.min.js", + "github.min.css", + ): + path = VENDOR_DIR / name + self.assertTrue(path.exists(), f"missing vendored asset: {path}") + self.assertGreater(path.stat().st_size, 0, f"empty vendored asset: {path}") + + +if __name__ == "__main__": + unittest.main() diff --git a/web/static/dev.html b/web/static/dev.html index e272e23..fb16d56 100644 --- a/web/static/dev.html +++ b/web/static/dev.html @@ -5,11 +5,11 @@