4.5 KiB
4.5 KiB
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 仅做转发:
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.cssGET /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)
- 抽公共层:引入
argus/ui/assets/*、argus/ui/layout/*,保持 UI 输出完全一致;service/ui.py仍在但内部改为调用新 layout(或先不动)。 - 按页面迁移:逐个把 routes 迁移到
argus/ui/pages/*,每迁一个页面就加一个最小测试用例(200 + 关键文本存在)。 - 清理与稳定:
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+ 行单文件;每页的改动范围限定在对应模块。