1
0
Files
nex/openspec/specs/desktop-app/spec.md
lanyuanxiaoyao 9105a36097 feat: 将"关于"从系统托盘原生对话框迁移到前端页面
移除系统托盘右键菜单中的"关于"选项及各平台原生对话框实现,
在前端新增 /about 路由和关于页面展示品牌信息,侧边栏增加关于导航入口
2026-04-24 23:17:22 +08:00

6.9 KiB
Raw Blame History

桌面应用

Purpose

TBD - 提供跨平台桌面应用支持,将后端服务与前端静态资源打包为单一可执行文件

Requirements

Requirement: 桌面应用启动

系统 SHALL 支持作为桌面应用启动,将后端服务与前端静态资源打包为单一可执行文件。

Scenario: 双击启动

  • WHEN 用户双击桌面应用可执行文件
  • THEN 系统使用 gofrs/flock 尝试获取排他文件锁
  • AND 锁文件路径为系统临时目录下的 nex-gateway.lock
  • AND 系统启动后端服务
  • AND 系统托盘图标出现
  • AND 浏览器自动打开 http://localhost:9826 显示管理界面

Scenario: 单实例检查

  • WHEN 用户尝试启动第二个实例
  • THEN 系统检测到已有实例持有文件锁
  • AND 显示错误提示"已有 Nex 实例运行"
  • AND 新实例退出

Scenario: 退出释放锁

  • WHEN 用户点击托盘菜单"退出"
  • THEN 系统释放文件锁
  • AND 应用进程退出

Requirement: 系统托盘

系统 SHALL 提供跨平台系统托盘功能,支持托盘图标和菜单。图标格式 SHALL 根据平台自动选择。

Scenario: 托盘图标显示

  • WHEN 桌面应用启动成功
  • THEN 系统根据平台加载正确的图标格式
  • AND 在 Windows 上加载 ICO 格式图标(assets/icon.ico
  • AND 在 macOS 和 Linux 上加载 PNG 格式图标(assets/icon.png
  • AND 托盘图标 tooltip 显示"AI Gateway"

Scenario: 托盘菜单显示

  • WHEN 用户点击托盘图标(左键或右键)
  • THEN 显示托盘菜单
  • AND 菜单包含"打开管理界面"选项
  • AND 菜单包含"状态: 运行中"选项(禁用状态)
  • AND 菜单包含"端口: 9826"选项(禁用状态)
  • AND 菜单包含"退出"选项

Scenario: 打开管理界面

  • WHEN 用户点击托盘菜单"打开管理界面"
  • THEN 系统在浏览器中打开 http://localhost:9826

Scenario: 浏览器打开失败

  • WHEN 系统无法打开浏览器(浏览器未安装等)
  • THEN 托盘菜单仍可正常使用
  • AND 用户可手动访问 http://localhost:9826

Scenario: 退出应用

  • WHEN 用户点击托盘菜单"退出"
  • THEN 系统优雅关闭后端服务
  • AND 托盘图标消失
  • AND 应用进程退出

Requirement: 静态文件服务

系统 SHALL 通过 Gin 同时服务 API 和前端静态资源。

Scenario: API 请求路由

  • WHEN 请求路径以 /api//v1/ 开头
  • THEN 请求由现有业务 handler 处理

Scenario: 静态资源路由

  • WHEN 请求路径为 /assets/*
  • THEN 返回嵌入的前端静态资源文件

Scenario: SPA 路由回退

  • WHEN 请求路径不匹配任何 API 或静态资源路由
  • THEN 返回 index.html(支持前端 SPA 路由)

Requirement: 端口冲突检测

系统 SHALL 在启动前检测端口是否可用。

Scenario: 端口可用

  • WHEN 端口 9826 未被占用
  • THEN 服务正常启动

Scenario: 端口被占用

  • WHEN 端口 9826 已被其他程序占用
  • THEN 显示错误提示"端口 9826 已被占用"
  • AND 应用退出

Requirement: 跨平台构建

系统 SHALL 支持跨平台构建和打包。构建 target SHALL 按平台分离,产物文件名 SHALL 使用 nex-{os}-{arch}[.exe] 格式。

Scenario: macOS 构建

  • WHEN 执行 desktop-build-mac 构建命令
  • THEN 生成 nex-mac-arm64nex-mac-amd64 可执行文件
  • AND 可打包为 .app bundle

Scenario: Windows 构建

  • WHEN 执行 desktop-build-win 构建命令
  • THEN 生成 nex-win-amd64.exe 可执行文件
  • AND 使用 -H=windowsgui linker flag 隐藏控制台窗口

Scenario: Linux 构建

  • WHEN 执行 desktop-build-linux 构建命令
  • THEN 生成 nex-linux-amd64 可执行文件

Requirement: macOS .app 打包

系统 SHALL 支持打包为 macOS .app bundle。

Scenario: .app 结构

  • WHEN 执行打包脚本
  • THEN 生成 Nex.app 目录结构
  • AND 包含 Contents/Info.plist 元数据
  • AND 包含 Contents/MacOS/nex 可执行文件
  • AND 包含 Contents/Resources/icon.icns 图标
  • AND Info.plistLSUIElementtrue(不显示 Dock 图标)

Requirement: Windows 原生对话框

系统 SHALL 在 Windows 上使用 user32.dllMessageBoxW API 显示错误对话框,替代 msg * 命令。

Scenario: 错误提示对话框

  • WHEN 应用在 Windows 上遇到启动错误(端口占用、配置加载失败等)
  • THEN 使用 MessageBoxW 显示模态对话框
  • AND 对话框标题栏显示应用名称
  • AND 对话框包含错误描述文本
  • AND 对话框显示错误图标MB_ICONERROR

Scenario: 非 Windows 平台不受影响

  • WHEN 应用运行在 macOS 或 Linux 上
  • THEN 错误对话框仍使用平台原有实现osascript / zenity

Requirement: Linux 对话框降级策略

系统 SHALL 在 Linux 上按优先级检测并使用可用的对话框工具,确保在不同桌面环境下都能显示对话框。

Scenario: zenity 可用

  • WHEN 系统检测到 zenity 命令可用
  • THEN 使用 zenity 显示 GTK 风格对话框
  • AND 错误对话框使用 zenity --error 命令
  • AND 信息对话框使用 zenity --info 命令

Scenario: kdialog 可用

  • WHEN zenity 不可用且 kdialog 命令可用
  • THEN 使用 kdialog 显示 KDE 风格对话框
  • AND 错误对话框使用 kdialog --error 命令
  • AND 信息对话框使用 kdialog --msgbox 命令

Scenario: notify-send 可用

  • WHEN zenity 和 kdialog 均不可用且 notify-send 命令可用
  • THEN 使用 notify-send 显示系统通知
  • AND 错误通知使用 -u critical 参数
  • AND 信息通知使用默认参数

Scenario: xmessage 可用

  • WHEN zenity、kdialog、notify-send 均不可用且 xmessage 命令可用
  • THEN 使用 xmessage 显示基础 X11 对话框
  • AND 对话框居中显示(-center 参数)

Scenario: 无对话框工具可用

  • WHEN 所有对话框工具均不可用
  • THEN 降级到标准错误输出
  • AND 输出格式为 错误: <title>: <message>

Scenario: 工具检测缓存

  • WHEN 应用启动
  • THEN 系统检测一次可用对话框工具
  • AND 检测结果缓存在包级变量
  • AND 后续对话框调用直接使用缓存结果,不重复检测

Requirement: macOS AppleScript 字符转义

系统 SHALL 对 AppleScript 对话框中的特殊字符进行转义,确保脚本正确执行。

Scenario: 转义反斜杠

  • WHEN 对话框消息包含反斜杠字符 \
  • THEN 转义为 \\

Scenario: 转义双引号

  • WHEN 对话框消息包含双引号字符 "
  • THEN 转义为 \"

Scenario: 多行文本处理

  • WHEN 对话框消息包含换行符 \n
  • THEN AppleScript 正确显示多行文本