# v3.9 UI 重构方案(保持功能不变) ## 背景与问题 当前 `src/mvp/py/argus/service/ui.py` 单文件约 1400+ 行,包含: - 全局 CSS/JS(长字符串) - 布局渲染(nav/page 拼接) - 11 个页面的 HTML + 大段内嵌 JS(包含 TaskSpec 模板与表单逻辑) 导致:变更难定位、合并冲突多、缺少模块边界、复用困难、测试覆盖薄弱。 ## 目标(功能不变) - **路由与页面行为完全不变**:URL、返回内容、按钮/表单行为、localStorage key(`mvp_token`/`mvp_sftp_password`)、API 调用路径保持不变。 - **不引入前端构建链/新依赖**(仍然用纯字符串/轻量模板函数)。 - 将 UI 拆分为可维护的多个文件(放到 `src/mvp/py/argus/ui/`)。 - 增加最小的单测(确保路由可访问、关键 DOM 标识存在)。 ## 非目标 - 不重做 UI 样式/交互;不引入 React/Vue;不改后端 API。 - 不新增鉴权逻辑(仍然是浏览器 localStorage + Bearer token)。 ## 拆分后的目录结构(建议) 新增包:`src/mvp/py/argus/ui/` ``` argus/ui/ __init__.py # register_ui_routes(app) 统一入口 assets/ base_css.py # BASE_CSS 常量 base_js.py # BASE_JS 常量(apiFetch/apiJson 等通用函数) layout/ nav.py # nav(active) + 链接配置 page.py # page(title, active, body, script, extra_head=...) pages/ login.py # /ui/login tasks.py # /ui/tasks task_new.py # /ui/tasks/new(模板常量 + 表单 JS) task_detail.py # /ui/tasks/{task_id} task_logs.py # /ui/tasks/{task_id}/logs serving.py # /ui/serving, /ui/serving/new, /ui/serving/{model_key} data.py # /ui/data admin.py # /ui/admin routes.py # 将各 pages.register(app) 聚合注册 ``` 兼容层(可选但推荐):保留 `src/mvp/py/argus/service/ui.py` 仅做转发: ```py from argus.ui import register_ui_routes ``` 这样可以避免一次性改动 `service/app.py` 的 import 路径,减少风险。 ## 页面拆分原则 每个 page 模块提供两个函数: - `render(...) -> HTMLResponse`:只负责拼接 body/script(不直接碰 FastAPI app)。 - `register(app: FastAPI) -> None`:只负责挂载路由(`@app.get(...)`)。 通用能力下沉: - `_BASE_CSS`/`_BASE_JS` 移到 `assets/`。 - `_nav()`、`_page()` 移到 `layout/`。 - 大块常量(TaskSpec 模板、UI 文案)放在页面模块同文件顶部,避免散落在函数内部。 ## 资源交付方式(两种可选) ### 方案 A(最稳):继续内联 CSS/JS,但拆到不同 Python 文件 - `page()` 内继续 ``、``。 - 只改变代码组织,不改变浏览器加载方式,风险最低。 ### 方案 B(推荐中期):新增静态端点分发资源 新增: - `GET /ui/assets/base.css` - `GET /ui/assets/base.js` 页面改为 `` + ``。 优点:减少 HTML 体积、浏览器缓存更好;缺点:需要确认反向代理/中间件不拦截这些路由。 建议 v3.9 先落地方案 A,稳定后再做方案 B。 ## 迁移步骤(建议分 3 次 PR) 1) **抽公共层**:引入 `argus/ui/assets/*`、`argus/ui/layout/*`,保持 UI 输出完全一致;`service/ui.py` 仍在但内部改为调用新 layout(或先不动)。 2) **按页面迁移**:逐个把 routes 迁移到 `argus/ui/pages/*`,每迁一个页面就加一个最小测试用例(200 + 关键文本存在)。 3) **清理与稳定**:`service/ui.py` 变为兼容转发;可选引入 `/ui/assets/*` 静态端点(方案 B)。 ## 测试策略(最小但有效) 新增 `src/mvp/py/tests/test_ui_pages.py`: - 创建 FastAPI app(复用现有测试的 app 初始化方式) - 请求下列页面,断言 `status_code == 200`: - `/ui/login`, `/ui/tasks`, `/ui/tasks/new`, `/ui/serving`, `/ui/data`, `/ui/admin` - 断言响应包含稳定锚点文本(例如 `Argus MVP`, `New Task`, `Tasks`),避免脆弱的全量快照。 ## 验收标准(Definition of Done) - 11 个 `/ui/*` 路由行为与输出不变(人工 smoke + 自动化最小测试)。 - `src/mvp/py/argus/service/ui.py` 不再包含大段 HTML/JS(仅兼容转发或极薄封装)。 - 新增/修改 UI 页面不需要触碰 1000+ 行单文件;每页的改动范围限定在对应模块。