# `call-client` 迁移到 Tauri 技术文档 ## 1. 目标 将当前基于 `Electron + Vue 3 + TypeScript + electron-vite` 的桌面应用迁移为 `Tauri + Vue 3 + TypeScript`,在尽量保留现有前端业务代码的前提下,替换主进程、窗口管理、IPC、配置与日志等宿主能力。 迁移完成后应满足: - 保持现有登录、主叫号、票号列表、服务地址配置等业务功能不变 - 保持 Linux(麒麟)打包能力,优先支持 `x64` / `arm64` - 保持本地配置与日志的 XDG 规范行为 - 保持多窗口、原生确认框、菜单、前后端通信能力 - 为后续减小安装包体积、降低内存占用、提高跨平台一致性做准备 --- ## 2. 当前项目现状 当前项目目录与能力大致如下: - 前端:`Vue 3 + vue-router + element-plus + axios` - 宿主:`Electron` - 构建:`electron-vite + electron-builder` - 主进程入口:`src/main/index.ts` - 窗口创建:`src/main/window.ts` - 预加载桥接:`src/preload/index.ts` - 本地配置:`src/main/app-config.ts` - 文件日志:`src/main/file-logger.ts` - 渲染层类型声明:`src/renderer/src/env.d.ts` 当前渲染层大量依赖 `window.xxx` 能力: - `window.winControl` - `window.contextMenu` - `window.pauseMenu` - `window.session` - `window.appLogger` - `window.appConfig` - `window.nativeDialog` - `window.ticketToMain` - `window.mainTicketEvents` 这意味着迁移的核心不是 Vue 页面重写,而是把这些 Electron 注入能力改造成 Tauri 的命令、事件和窗口 API。 --- ## 3. 为什么适合迁移到 Tauri 当前项目业务逻辑主要集中在前端,宿主层职责相对清晰: - 管理窗口 - 提供原生菜单和对话框 - 管理会话状态 - 提供配置读写 - 提供文件日志 - 在多个窗口之间转发事件 这些能力都可以在 Tauri 中找到对应实现,因此该项目具备较好的迁移可行性。 适合迁移的原因: - 前端已是标准 Vite/Vue 结构,Tauri 可直接复用 - 本地能力边界清晰,便于逐项替换 - Linux 发行打包对 Tauri 更友好 - 当前没有深度依赖 Electron 的 `BrowserView`、`desktopCapturer`、`webContents` 高级能力 --- ## 4. Electron 到 Tauri 能力映射 ### 4.1 窗口 当前 Electron: - `createLoginWindow()` - `createMainWindow()` - `createTicketWindow()` - 运行时调用 `show()`、`focus()`、`restore()`、`minimize()` Tauri 对应方案: - 主窗口由 Tauri 启动时创建 - 其它窗口通过 `WebviewWindow` 或 Rust 端创建 - 窗口最小化、关闭、显示、聚焦使用 `@tauri-apps/api/window` 建议: - `login`、`main`、`ticketList` 改为具名 Tauri 窗口 - 窗口路由仍保留 `hash` 路由,降低前端改造成本 ### 4.2 IPC / 桥接 当前 Electron: - `ipcMain.handle` - `ipcRenderer.invoke` - `ipcRenderer.send/on` - `contextBridge.exposeInMainWorld` Tauri 对应方案: - `invoke()` 调用 Rust `#[tauri::command]` - `emit/listen` 做窗口间事件通信 - 直接在前端封装 `src/renderer/src/tauri-api/*` 替代 `window.xxx` 建议: - 不再保留 `window.xxx` 直挂模式 - 改为前端统一封装模块,例如: - `src/renderer/src/host/session.ts` - `src/renderer/src/host/config.ts` - `src/renderer/src/host/logger.ts` - `src/renderer/src/host/window.ts` - `src/renderer/src/host/menu.ts` ### 4.3 原生菜单 当前 Electron: - 主进程动态构建菜单 - 用于“办税员窗口 / 票号列表 / 退出程序” - 暂停菜单用于选择暂停原因 Tauri 对应方案: - Rust 菜单 API - 或前端自绘菜单 + Rust 命令 - 简单场景也可直接使用前端弹层替代原生菜单 建议: - “系统/上下文菜单”优先保留原生 - “暂停原因菜单”可以迁移成前端 `Element Plus` 下拉/弹窗,降低 Rust 复杂度 ### 4.4 原生确认框 当前 Electron: - `dialog.showMessageBox` Tauri 对应方案: - `@tauri-apps/plugin-dialog` 建议: - `window.nativeDialog.confirm()` 改为前端封装 `confirmNative()` - 接口签名保持一致,减少页面改动 ### 4.5 配置文件 当前 Electron: - `src/main/app-config.ts` - Linux 下遵循 `XDG_CONFIG_HOME` - 使用 JSON 文件持久化 Tauri 对应方案: - Rust 命令自己读写 JSON 文件 - 目录使用 `tauri::api::path` 或 Tauri 2 对应 path API 建议: - 继续保持当前配置文件结构不变 - 继续使用 `config.json` - 路径规则继续保持: - Linux:`$XDG_CONFIG_HOME/` 或 `~/.config/` - 其他平台:应用数据目录 ### 4.6 文件日志 当前 Electron: - `src/main/file-logger.ts` - Linux 遵循 `XDG_STATE_HOME` - 纯文本 - 100MB 轮转 - 7 天清理 Tauri 对应方案: - Rust 端实现同样的文件日志模块 建议: - 日志逻辑直接迁移到 Rust - 保持现有文件命名、轮转、保留策略不变 - 渲染层仍使用统一 `log(level, message)` 接口 ### 4.7 Session 状态 当前 Electron: - 主进程内存维护 `sessionState` - 渲染层通过 IPC 获取/设置 Tauri 对应方案: - Rust `State` 保存内存会话 - 通过 `command` 获取/设置 建议: - 维持现有结构: - `empUid` - `winUid` - `queueToken` ### 4.8 多窗口事件转发 当前 Electron: - `ticket:main-action` - `main:ticket-action` Tauri 对应方案: - 指定窗口 `emit_to` - 目标窗口 `listen` 建议: - 保持当前事件模型: - `ticket -> main` 呼叫 - `ticket -> main` 评价 - 仅把传输媒介从 Electron IPC 改为 Tauri Event --- ## 5. 迁移范围拆解 ### 5.1 前端可直接复用部分 这些部分原则上可以原样保留: - `src/renderer/src/views/*.vue` - `src/renderer/src/router/index.ts` - `src/renderer/src/api/index.ts` - `src/renderer/src/utils/service.ts` - 大部分 TypeScript 类型定义 - Axios 与后端接口封装 需要改动的地方主要是所有 `window.xxx` 调用。 ### 5.2 必须重写的部分 这些 Electron 专属模块需要全部替换: - `src/main/index.ts` - `src/main/window.ts` - `src/preload/index.ts` - `src/renderer/src/env.d.ts` 中的 Electron 全局声明 - `electron.vite.config.ts` - `electron-builder.yml` - `package.json` 中 Electron 构建脚本和依赖 ### 5.3 可迁移但建议重构的部分 - `pauseMenu` 建议从原生菜单改成前端弹窗 - `contextMenu` 可按实际需要决定是否保留原生 - `window.winControl.loginSuccess()` 可重构为前端路由 + 新窗口显示逻辑 --- ## 6. 推荐的 Tauri 目标结构 建议最终目录结构: ```text call-client/ ├─ src/ │ ├─ renderer/ │ │ └─ src/ │ │ ├─ api/ │ │ ├─ host/ │ │ │ ├─ session.ts │ │ │ ├─ config.ts │ │ │ ├─ logger.ts │ │ │ ├─ window.ts │ │ │ ├─ dialog.ts │ │ │ └─ events.ts │ │ ├─ router/ │ │ ├─ views/ │ │ └─ ... │ └─ shared/ ├─ src-tauri/ │ ├─ src/ │ │ ├─ main.rs │ │ ├─ commands/ │ │ │ ├─ session.rs │ │ │ ├─ config.rs │ │ │ ├─ logger.rs │ │ │ ├─ window.rs │ │ │ ├─ dialog.rs │ │ │ └─ events.rs │ │ └─ state.rs │ ├─ tauri.conf.json │ └─ Cargo.toml └─ package.json ``` --- ## 7. 前端接口替换清单 当前前端依赖的 Electron 注入接口,需要替换为 Tauri 封装: ### 7.1 `window.winControl` 当前能力: - `windowMinimize()` - `windowClose()` - `loginSuccess()` Tauri 替代: - `getCurrentWindow().minimize()` - `getCurrentWindow().close()` - 登录成功后触发: - 显示主窗口 - 关闭登录窗口 - 或仅路由切换,视最终窗口方案而定 ### 7.2 `window.contextMenu` 当前能力: - 打开上下文菜单 Tauri 替代: - Rust 菜单 - 或前端菜单组件 ### 7.3 `window.pauseMenu` 当前能力: - 弹出暂停原因菜单 - 回传用户选中的原因 建议替代: - 使用前端对话框/选择器,避免专门做 Rust 菜单事件回传 ### 7.4 `window.session` 当前能力: - `get()` - `set()` - `clear()` Tauri 替代: - `invoke('session_get')` - `invoke('session_set', { ... })` - `invoke('session_clear')` ### 7.5 `window.appLogger` 当前能力: - `log(level, message)` Tauri 替代: - `invoke('app_log', { level, message })` ### 7.6 `window.appConfig` 当前能力: - `getAll()` - `set(partial)` Tauri 替代: - `invoke('config_get_all')` - `invoke('config_merge', { partial })` ### 7.7 `window.nativeDialog` 当前能力: - `confirm({ title, message, okLabel, cancelLabel })` Tauri 替代: - 封装 `plugin-dialog` ### 7.8 `window.ticketToMain` / `window.mainTicketEvents` 当前能力: - 票号列表窗口通知主窗口执行呼叫/评价 Tauri 替代: - `emitTo('main', 'ticket-action', payload)` - 主窗口 `listen('ticket-action', ...)` --- ## 8. 后端 API 层迁移影响 后端 API 请求层基本不需要因为迁移到 Tauri 而重写。 现有: - `axios` - `src/renderer/src/api/index.ts` - `src/renderer/src/utils/service.ts` 保留原则: - 所有 `/auth/login`、`/call-terminal/*`、`/isRank`、`/getQueueCount` 保持不变 - 仅调整“token 获取来源”和“应用配置读取来源” 需要注意: - 目前 `service.ts` 从 `window.session.get()` 中拿 `queueToken` - 迁移后应改成 `host/session.ts` 封装 --- ## 9. 打包与发布迁移 当前: - 使用 `electron-builder` - 面向 `deb` / `AppImage` 迁移到 Tauri 后: - 使用 `tauri build` - Linux 侧通常可生成 `deb` / `AppImage` 建议: - 保留现有 `resources/call_icon.png` - 重新配置 Tauri 的: - 应用名 - 图标 - 窗口尺寸 - 标题栏/装饰策略 --- ## 10. 重点风险 ### 10.1 多窗口迁移复杂度 当前项目不是单窗口,而是至少有: - 登录窗口 - 主窗口 - 票号列表窗口 这在 Tauri 可以实现,但实现方式与 Electron 不同,需要提前设计窗口生命周期和事件路由。 ### 10.2 原生菜单差异 Electron 菜单 API 较成熟,Tauri 菜单方案和事件模型不同,暂停菜单与上下文菜单可能需要重构。 ### 10.3 文件系统逻辑要从 Node 改到 Rust 以下逻辑不能直接复用: - `fs` - `path` - `os` - `app.getPath()` 需要改写为 Rust。 ### 10.4 前端大量 `window.xxx` 依赖 虽然页面 UI 可复用,但所有页面中使用的宿主能力都需要替换接口。 建议先做适配层,不要在页面里直接写 Tauri API。 ### 10.5 开发流程变化 从: - `electron-vite dev` 改为: - `tauri dev` 工程脚本、CI、打包环境都要同步调整。 --- ## 11. 推荐迁移策略 建议使用“分阶段替换”,不要一次性推倒重来。 ### 阶段 1:建立 Tauri 空壳 目标: - 保留现有 Vue 前端 - 新建 `src-tauri` - 跑通 `tauri dev` - 页面能正常打开 产出: - `src-tauri/` - `tauri.conf.json` - 基础窗口配置 ### 阶段 2:建立宿主适配层 目标: - 新建前端 `host/*` 封装 - 暂时不改页面业务,只改调用入口 例如将: - `window.appConfig.getAll()` 替换为: - `hostConfig.getAll()` 这样后续无论是 Electron 还是 Tauri,都能通过适配层承接。 ### 阶段 3:迁移配置、日志、session 优先迁移最基础的宿主能力: - 配置文件 - 日志 - 会话状态 因为这些能力会被多个页面依赖。 ### 阶段 4:迁移窗口与事件 迁移: - 登录成功切主窗口 - 票号列表子窗口 - 主窗口与子窗口之间动作事件 ### 阶段 5:迁移原生菜单/对话框 迁移: - 确认框 - 上下文菜单 - 暂停菜单 此阶段可顺便评估哪些能力改成前端组件更合适。 ### 阶段 6:移除 Electron 依赖 删除: - `electron` - `electron-builder` - `electron-vite` - `src/main/*` - `src/preload/*` 并重写 `package.json` 脚本。 --- ## 12. 预计工作量 按当前项目规模估算: - 前端页面复用:高 - 宿主层重写:中到高 - 多窗口与事件:中 - 打包与环境:中 大致可按以下量级评估: - 基础可运行 Tauri 版本:1 到 2 天 - 功能完整迁移:3 到 7 天 - 打包与麒麟环境联调:1 到 3 天 实际取决于: - 是否保留原生菜单 - 是否保留多窗口 - 是否要求与当前行为完全一致 --- ## 13. 最小可行迁移方案 如果目标是“尽快落地”,建议先做最小版本: - 保留单主窗口 - `ticketList` 改为路由页/弹层,而不是独立窗口 - 暂停菜单改为前端弹窗 - 原生确认框使用 Tauri dialog 插件 - 配置、日志、session 用 Rust 命令重写 这样能明显降低迁移复杂度。 --- ## 14. 结论 该项目适合迁移到 Tauri,且前端业务代码可大量复用。真正的迁移重点在于: - 宿主能力替换 - 多窗口与事件通信重构 - 本地配置/日志/session 的 Rust 实现 - 打包链路从 Electron Builder 迁移到 Tauri Build 推荐实施顺序: 1. 先建立 Tauri 壳与前端适配层 2. 再迁移配置、日志、session 3. 再迁移窗口、事件、对话框、菜单 4. 最后移除 Electron --- ## 15. 下一步建议 如果你确认要开始迁移,下一份文档建议继续输出: - `TAURI-MIGRATION-TASKS.md` 内容包括: - 逐文件改造清单 - Electron API 到 Tauri API 映射表 - `src-tauri` 初始代码结构 - `package.json` 新脚本方案 - 每一步验收标准