argus-cluster/specs/mvp/v3.9/ui_refactor_plan.md

4.5 KiB
Raw Blame History

v3.9 UI 重构方案(保持功能不变)

背景与问题

当前 src/mvp/py/argus/service/ui.py 单文件约 1400+ 行,包含:

  • 全局 CSS/JS长字符串
  • 布局渲染nav/page 拼接)
  • 11 个页面的 HTML + 大段内嵌 JS包含 TaskSpec 模板与表单逻辑)

导致:变更难定位、合并冲突多、缺少模块边界、复用困难、测试覆盖薄弱。

目标(功能不变)

  • 路由与页面行为完全不变URL、返回内容、按钮/表单行为、localStorage keymvp_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 仅做转发:

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() 内继续 <style>{BASE_CSS}</style><script>{BASE_JS}</script>
  • 只改变代码组织,不改变浏览器加载方式,风险最低。

方案 B推荐中期新增静态端点分发资源

新增:

  • GET /ui/assets/base.css
  • GET /ui/assets/base.js

页面改为 <link rel="stylesheet" href="/ui/assets/base.css"> + <script src="/ui/assets/base.js"></script>。 优点:减少 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+ 行单文件;每页的改动范围限定在对应模块。