109 lines
4.5 KiB
Markdown
109 lines
4.5 KiB
Markdown
# 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()` 内继续 `<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+ 行单文件;每页的改动范围限定在对应模块。
|