发布候选:整合桌面端界面与发布稳定化里程碑
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled

This commit is contained in:
Cheng Zhou
2026-07-01 10:53:24 +08:00
parent b283cf1e5c
commit b491b6a146
132 changed files with 17337 additions and 2375 deletions
+331
View File
@@ -0,0 +1,331 @@
# CTMS 桌面端第一阶段详细方案
日期:2026-06-30
## 目标
第一阶段只交付 macOS 在线桌面客户端。桌面端使用 Tauri 承载现有 Vue/Vite 前端,连接已有 CTMS 服务端,不内嵌后端、不内嵌数据库、不做离线能力。
本阶段结束后,应能在 macOS 上启动 CTMS 桌面 App,配置 CTMS 服务端地址,完成登录,并执行现有 Web 端的常规在线业务流程。Web 端构建和现有 Docker/nginx 部署必须继续可用。
## 范围边界
本阶段必须做:
-`frontend/` 内加入 Tauri 工程结构。
- 复用现有 Vue 3、Vite、Element Plus、Pinia、Vue Router、Axios 前端代码。
- 让桌面端连接已有 CTMS 后端公开入口,推荐连接 nginx 入口而不是直接连接后端容器。
- 提供桌面端服务端地址配置能力。
- 抽出最小运行时适配层,避免业务页面直接依赖 Tauri API。
- 保持认证、权限、审计和业务数据持久化由 FastAPI 后端裁决。
- 产出 macOS 开发构建流程和后续签名、公证、DMG 发布路径。
本阶段明确不做:
- 离线登录、离线浏览、离线草稿、离线队列、离线同步。
- 本地 PostgreSQL、SQLite、IndexedDB 业务数据缓存或本地 API 镜像。
- 内嵌 Python/FastAPI 后端服务。
- 重写 CTMS 业务页面。
- Windows 安装包交付。
- 自动更新实现。
- token/session 安全存储迁移;该事项进入第二阶段。
## 当前代码影响点
现状:
- `frontend/src/api/axios.ts``frontend/src/api/authClient.ts``baseURL` 都是 `/`
- API 调用路径均为 `/api/v1/...`
- Web 端依赖 nginx 同域反代 `/api`
- Tauri 打包后页面运行在桌面 WebView 中,不能继续假设 `/api` 一定代表 CTMS 服务端。
- `frontend/src/utils/auth.ts` 当前使用 `localStorage` 保存 token。
- `frontend/src/session/sessionManager.ts` 依赖 `localStorage``sessionStorage``BroadcastChannel`
第一阶段的核心改动是先解决“桌面端如何知道并访问服务端地址”,同时尽量不触碰业务页面。
## 目标架构
```mermaid
flowchart LR
A["Tauri macOS App"] --> B["Bundled Vue/Vite Frontend"]
B --> C["Runtime Adapters"]
C --> D["Configured CTMS Server URL"]
D --> E["nginx / HTTPS entry"]
E --> F["FastAPI backend"]
F --> G["PostgreSQL"]
```
桌面端只负责本地窗口、运行时配置和少量平台能力。业务数据仍走服务端 API,权限和审计仍由后端完成。
## Tauri 工程方案
Tauri 目录放在现有前端工程内:
```text
frontend/
src-tauri/
tauri.conf.json
Cargo.toml
src/
main.rs
capabilities/
default.json
```
建议新增脚本:
```json
{
"scripts": {
"tauri": "tauri",
"desktop:dev": "tauri dev",
"desktop:build": "tauri build",
"desktop:bundle:dmg": "tauri build -- --bundles dmg"
}
}
```
Tauri 配置方向:
- `build.beforeDevCommand`: `npm run dev`
- `build.beforeBuildCommand`: `npm run build`
- `build.devUrl`: `http://localhost:5173`
- `build.frontendDist`: `../dist`
- 主窗口标题:`CTMS`
- 主窗口初始尺寸建议:`1440x900`
- 最小窗口尺寸建议:`1180x760`
- bundle identifier 待最终确认,临时建议:`cn.huapont.ctms.desktop`
第一阶段不加载远程 Web UI。Tauri 只加载本地打包出的前端资源,远程访问仅限 Axios 访问配置好的 CTMS 服务端。
## Vite 调整方案
当前 `vite.config.ts` 为 Docker 开发做了固定代理:
- dev server 端口:`5173`
- HMR client port`8888`
- `/api` 代理目标:`http://backend:8000`
为兼容 Web、Docker 和 Tauri,建议改成环境变量驱动:
- `VITE_DEV_API_PROXY_TARGET`:默认 `http://backend:8000`
- `VITE_HMR_CLIENT_PORT`Docker/nginx 开发时设为 `8888`,桌面端开发不设置。
- `TAURI_DEV_HOST`:按 Tauri/Vite 推荐方式兼容 Tauri dev。
Vite 配置需要补充:
- `server.strictPort: true`,避免 Tauri devUrl 与 Vite 实际端口不一致。
- `server.watch.ignored: ["**/src-tauri/**"]`,避免 Rust 目录变动触发不必要的前端监听。
- `clearScreen: false`,避免 Rust 编译错误被 Vite 清屏隐藏。
- `build.target` 按 Tauri 平台设置:Windows 使用 Chromium 目标,macOS 使用 Safari/WebKit 目标。
- `envPrefix` 保留 `VITE_`,并允许 `TAURI_ENV_*`
## 服务端地址配置
新增运行时适配层:
```text
frontend/src/runtime/
platform.ts
apiBaseUrl.ts
desktopServerConfig.ts
```
职责:
- `platform.ts`
- 判断当前是否运行在 Tauri。
- 判断目标平台是 Web、macOS 桌面端还是 Windows 桌面端。
- 业务页面不得直接读取 Tauri 全局对象。
- `desktopServerConfig.ts`
- 保存和读取桌面端服务端地址。
- 第一阶段可继续使用 `localStorage` 保存服务器地址;这不是业务数据,也不是离线能力。
- key 建议:`ctms_desktop_server_url`
- 仅接受 `http://localhost``http://127.0.0.1``https://...`。非本地生产服务不接受明文 HTTP。
- `apiBaseUrl.ts`
- Web 端返回 `/`,保持现有同域 `/api` 行为。
- 桌面端返回配置的服务端 origin,例如 `https://ctms.example.com/`
- 统一规范尾斜杠,避免拼接出错。
Axios 调整:
- `frontend/src/api/axios.ts` 使用 `resolveApiBaseUrl()` 初始化 `baseURL`
- `frontend/src/api/authClient.ts` 同步使用同一 baseURL。
- 当桌面端服务端地址变化时,需要更新两个 Axios 实例的 `defaults.baseURL`
- 现有 API path 继续保持 `/api/v1/...`,不修改业务 API 文件。
## 服务端配置入口
第一阶段需要一个轻量的桌面端服务端设置入口。
建议实现方式:
- 桌面端启动时,如果没有服务端地址,则在登录页前展示服务端设置界面。
- 登录页提供“服务器设置”入口,允许修改当前服务端地址。
- 保存前调用 `${serverUrl}/health` 做连通性检查。
- 连通性检查失败时允许用户重新输入,不自动降级到离线模式。
- Web 端不显示桌面端服务器设置入口。
建议新增文件:
```text
frontend/src/views/DesktopServerSettings.vue
frontend/src/router/desktopGuard.ts
frontend/src/runtime/desktopServerConfig.ts
```
路由策略:
- 保持现有 Web 路由结构。
- 桌面端未配置服务端时,将用户导向 `/desktop/server-settings`
- `/login` 页面中允许打开服务器设置。
- Web 端访问 `/desktop/server-settings` 时重定向到 `/login` 或显示不可用状态。
## 认证和会话策略
第一阶段保持现有认证机制:
- 登录仍使用后端登录公钥和加密登录流程。
- token 仍通过 `frontend/src/utils/auth.ts` 存储在 `localStorage`
- 会话超时、token keep-alive、401 refresh 仍沿用现有逻辑。
本阶段只允许做为 Tauri 接入所必需的最小改动:
- API baseURL 可切换。
- 服务端地址变化时清理当前 token 和项目上下文,要求重新登录。
- 不引入桌面安全存储;该事项归入第二阶段。
## Tauri 权限策略
第一阶段不需要文件系统、Shell、系统通知、自动更新或单实例插件。
权限原则:
- 只启用主窗口运行所需的最小 core capability。
- 不开放宽泛文件系统权限。
- 不开放 shell 执行能力。
- 不开放远程页面访问 Tauri command 的能力。
- 如确实需要读取 App 版本或平台信息,优先通过窄适配层处理,并明确 capability。
第一阶段建议不新增自定义 Tauri command。服务端地址配置可以先由前端 `localStorage` 完成。
## macOS 打包路径
开发构建:
```bash
cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:dev
```
生产构建:
```bash
cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:build
```
DMG 构建:
```bash
cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:bundle:dmg
```
正式分发前需要:
- Apple Developer 账号。
- macOS 代码签名证书。
- notarization 所需 App Store Connect API 或 Apple ID 凭据。
- 明确是否分发 DMG,第一阶段推荐 DMG。
第一阶段可以先产出未签名或 ad-hoc 签名的内部开发构建,但不能把它描述为正式可分发版本。
## 实施步骤
1. 初始化 Tauri
- 安装 `@tauri-apps/cli`
-`frontend/` 下生成 `src-tauri/`
- 固定基础配置:app name、window title、bundle identifier、devUrl、frontendDist。
2. 调整 Vite
- 引入 Tauri 兼容配置。
- 保持 Docker/nginx 开发代理不破坏。
- 使用环境变量控制代理和 HMR。
3. 新增运行时适配层
- 添加 `platform.ts`
- 添加 `apiBaseUrl.ts`
- 添加 `desktopServerConfig.ts`
- 新增单元测试覆盖 URL 规范化、Web/Tauri 分支和非法 URL 拒绝。
4. 改造 API client
- `axios.ts` 使用统一 baseURL。
- `authClient.ts` 使用统一 baseURL。
- 服务端地址变化后刷新 Axios baseURL。
- 保持 API path 和业务模块不变。
5. 添加桌面服务端设置界面
- 桌面端未配置服务端时拦截到设置页。
- 保存时校验 URL 和 `/health`
- 修改服务端地址时清理当前登录态和项目上下文。
6. 最小 Tauri 权限
- 检查 `capabilities/default.json`
- 移除第一阶段不需要的插件和权限。
- 不新增自定义 command,除非实现过程证明必要。
7. macOS 验证和文档
- 运行 Web 构建、类型检查、单元测试。
- 运行 Tauri dev。
- 验证 macOS 打包。
- 补充桌面端运行说明。
## 验收清单
功能验收:
- macOS 桌面 App 可以启动。
- 首次启动未配置服务端时进入服务器设置。
- 服务端地址保存前会校验 `/health`
- 配置有效服务端后可以登录。
- 登录后能进入项目列表和项目工作区。
- 现有权限控制、401 refresh、会话超时行为与 Web 端一致。
- 切换服务端地址会清理当前登录态。
工程验收:
- `npm run build` 通过。
- `npm run type-check` 通过。
- `npm run test:unit` 通过,或明确记录失败原因。
- `npm run desktop:dev` 可启动 macOS 窗口。
- `npm run desktop:build` 可完成构建。
- Web 端 Docker/nginx 访问不回归。
边界验收:
- 没有新增本地业务数据缓存。
- 没有内嵌后端服务。
- 没有本地数据库。
- 没有离线队列或同步机制。
- Tauri API 没有散落在业务页面中。
- Tauri capability 没有开放第一阶段不需要的文件系统或 shell 权限。
## 风险和决策点
- bundle identifier 需要正式确认,建议在第一阶段实现前由产品或组织负责人定稿。
- 桌面端连接公开 CTMS 服务时,生产环境应使用 HTTPS;本地开发可允许 localhost HTTP。
- 当前后端 CORS 是宽松配置。第一阶段可先不改后端,但正式分发前应评估是否收紧允许来源。
- token 第一阶段仍在 `localStorage`,这是有意识的阶段性选择;安全存储迁移必须排入第二阶段。
- macOS 正式分发需要 Apple Developer、签名和 notarization,不应等到最后一天处理。
## 参考资料
- Tauri 创建项目与向现有前端加入 Taurihttps://tauri.app/start/create-project/
- Tauri + Vite 配置:https://tauri.app/start/frontend/vite/
- Tauri capabilitieshttps://tauri.app/security/capabilities/
- Tauri DMG 分发:https://tauri.app/distribute/dmg/
- Tauri macOS 签名与公证:https://tauri.app/distribute/sign/macos/
- Tauri updater 资料,供第二阶段使用:https://tauri.app/plugin/updater/