Files
ele-HeiXiu/PROJECT.md
YoungestSongMo a8ace232a4 feat: 任务列表UI重构 + 分页器/登录错误/请求拦截修复
【任务列表 UI 重构】(TaskHistory.tsx)
  - 列重新排序:任务ID(固定) → 创建时间 → 模型 → 输出类型 → 状态 → 提示词 → 时长 → 费用 → 供应商(隐藏) → 帧率/文件大小/标签/错误信息(隐藏) → 用户
  - 斑马纹行样式 + hover 增强 + 选中行高亮 + 暗色主题适配
  - 列可见性选择器(齿轮图标 Popover),持久化到 localStorage
  - 视频时长通过 VideoUiParams.duration 计算,非视频显示 "-"
  - 未知状态降级处理(resolveStatus → 显示原始 key)
  - 分页器固定预留 48px,避免 >20 条时分页器溢出可视区
  - 提示词搜索图标颜色用 CSS class 承载,避免 columns 依赖 token.colorPrimary 导致主题切换时 Table 重建

  【分页器修复】(antd-theme.ts)
  - Pagination 组件 token 添加 itemActiveColor: '#fff'
  - 激活页码数字与 #6366F1 主题背景形成对比,亮色/暗色均可见
  - 替代之前的 CSS !important hack

  【登录错误信息修复】(request.ts)
  - HTTP 401 拦截改为双重校验:status === 401 && data?.code === 401
  - 仅业务码也为 401 时才走 token 刷新流程
  - 其他业务码(如密码错误)透传后端 data.message,不再被 RefreshError 覆盖

  【全局中文 locale】(ThemeProvider.tsx)
  - ConfigProvider 添加 locale={zhCN},分页器显示"条/页"等中文
  - 避免逐个 Table 设置不完整 locale 导致 Pagination Select 退化为 Input

  【上下文稳定性】(HomeContent.tsx)
  - contextValue 用 useMemo 包裹,避免每次 render 新建对象导致无关重渲染
  - 配合 columns 依赖清理,减少主题切换时的级联更新

  【其他】
  - index.html CSP 策略增加 COS 域名白名单
  - OutputTypeMap 枚举值修复为 image='图片', video='视频', audio='音频'
  - TaskStatusMap STATUS_CONFIG 类型放宽为 Record<string,...> 兼容未知状态
  - 移除 computeDuration,替换为 getVideoDuration + formatDuration
  - LoginPage 移除未使用的 authState 依赖
2026-06-05 20:49:23 +08:00

15 KiB
Raw Blame History

项目概览

  • 本项目使用 Vite + React 19 + TypeScript + Electron 重构现有 Python Qt 桌面应用打造跨平台Windows/macOS的多窗口桌面程序。
  • 核心界面为单页应用SPA同时支持通过 Electron 打开独立窗口以承载子功能。

核心需求

  • 完整还原原有 Qt 应用的业务逻辑与视觉体验,并对交互进行现代化改造。

  • 必须支持 多窗口(主窗口 + 可动态创建的辅助窗口),窗口间需通过事件/消息进行低耦合通信。

  • 适配 Windows 与 macOS处理好快捷键、托盘、菜单、窗口边框等平台差异。

  • 采用 离线优先 架构,保障本地数据处理性能,合理使用本地存储(如 electron-store 或 SQLite

  • 所有对系统底层能力的调用必须通过 Electron 主进程,严禁在渲染进程直接使用 Node.js API除非通过 preload 安全暴露)。

技术架构

整体分层

  • 主进程Main ProcessElectron 主进程管理窗口生命周期、系统菜单、托盘、IPC 事件调度、本地文件/数据库操作。

  • 预加载脚本Preload桥接渲染进程与主进程使用 contextBridge 安全暴露有限 API。

  • 渲染进程Renderer基于 React 19 的 SPA主窗口与独立窗口的 React 入口,负责 UI 展示与用户交互。

  • 共享层Shared进程间共享的 TypeScript 类型、常量、工具函数、事件名称枚举。

前端架构原则

  • 组件化:以函数组件 + Hooks 为唯一组件形式UI 拆分为展示组件与容器组件。

  • 单向数据流:全局状态使用 Context + Provider 模式AppContext / ThemeContext / SettingsContext 遵循 Provider → Context → Comsumer 单向流动。组件内部状态使用 useState/useReducer不污染全局 Context。

  • 事件驱动EDA

    1. 主进程与渲染进程通信基于 Electron IPCipcMain/ipcRenderer定义明确的事件通道与载荷类型。

    2. 渲染进程内跨组件通信优先使用 Context需要解耦的场景使用自定义事件总线src/utils/event-bus.ts 所有 emit 调用自动记录到日志文件用于审计追踪。

    3. 自定义错误体系RequestError / RefreshError通过事件总线解耦请求拦截器抛出自定义错误 → 全局捕获 → emit 事件 → UI 层响应。

    4. 窗口间通信统一通过主进程转发(或使用 MessagePort 等 Electron 支持的机制),保持窗口独立性。

  • 路由与导航:主窗口为 单页应用,使用 React Router v7+ 管理页面切换,支持嵌套路由。

  • 辅助窗口(设置、预览、导入导出等)为独立 BrowserWindow加载独立的 HTML 入口(可根据路由参数或 windowId 决定内部路由),不与主窗口共享 DOM。

目录结构

├── electron/                # Electron 主进程
│   ├── main.ts              # 入口:窗口创建 / IPC 注册 / 生命周期
│   ├── preload.ts           # 预加载脚本contextBridge
│   └── main/
│       ├── updater.ts       # 自定义更新API 版本检查 + OSS 下载 + NSIS 安装)
│       ├── logger.ts        # 主进程日志核心JSON Lines 写入 / 轮转 / 清理)
│       ├── log-ipc.ts       # 渲染进程日志 IPC 通道接收
│       ├── net-request.ts   # Electron net.request 的 axios 风格封装
│       ├── menu/index.ts    # 系统菜单
│       └── utils/           # 平台判断 / 图标路径
├── src/                     # 渲染进程React 19 SPA
│   ├── main.tsx             # React 挂载点 + 全局错误捕获
│   ├── App.tsx              # 根组件(路由 + 登录弹窗)
│   ├── components/          # 通用 UI 组件 + Provider
│   │   ├── AppProvider.tsx  # 全局状态platform / edition / login
│   │   ├── ThemeProvider.tsx # 主题状态light / dark
│   │   ├── SettingsProvider.tsx # 设置状态(存储路径等)
│   │   ├── Layout.tsx       # 页面壳NavBar + Outlet
│   │   └── navbar/          # 导航栏 + 公告抽屉
│   ├── contexts/            # Context 定义app / settings / theme
│   ├── hooks/               # 自定义 HooksuseUpdater / useTheme
│   ├── pages/               # 页面组件
│   │   ├── home/            # 首页仪表盘
│   │   ├── login/           # 登录 / 注册页
│   │   └── settings/        # 设置面板(主题 / 存储 / 更新)
│   ├── router/index.tsx     # HashRouter 路由配置
│   ├── services/            # HTTP 请求封装
│   │   ├── request.ts       # Axios 封装 + 拦截器 + Token 刷新
│   │   ├── types.ts         # 自定义错误类型RequestError / RefreshError
│   │   ├── auth-token.ts    # refresh_token 管理
│   │   └── modules/         # API 模块auth / announcement
│   ├── theme/               # 主题系统
│   │   ├── tokens.ts        # 设计令牌
│   │   └── globals.css      # Tailwind + 全局样式
│   └── utils/               # 纯函数工具
│       ├── event-bus.ts     # 事件总线on / off / emit + 日志钩子)
│       ├── logger.ts        # 渲染进程日志器IPC 转发 / DEV 控制台)
│       ├── ipc.ts           # 安全 IPC 守卫safeIpcOn / send / invoke
│       ├── platform.ts      # 平台判定
│       └── device.ts        # 设备 ID 生成
├── shared/                  # 主进程 & 渲染进程共享
│   ├── types/               # 类型定义API / IPC / update / logging
│   ├── constants/           # 常量IPC 通道 / version / app
│   └── utils/               # 共享工具
│       ├── index.ts         # debounce / throttle / compareVersions
│       └── sanitize.ts      # 日志脱敏工具ID / 邮箱 / 手机 / 名称)
├── scripts/                 # 构建脚本
│   ├── build.mjs            # 构建总管
│   ├── clean.mjs            # 清理产物
│   ├── upload-oss.mjs       # OSS 上传
│   ├── publish-release.mjs  # 发布到 API
│   └── generate-update-info.mjs # 生成更新元信息
├── package.json             # 含 electron-builder 打包配置
├── vite.config.ts
├── tsconfig.json
└── tailwind.config.ts

多窗口与平台判定

  • windowManager.ts 负责统一创建 BrowserWindow根据环境变量/参数加载不同入口(如 src/main/index.html 或 src/sub/settings/index.html

  • src/utils/platform.ts 提供 isMacOS、isWindows 等函数(基于 navigator.userAgent 或 preload 暴露的 process.platform。在主进程的 electron/main/utils/platform.ts 中直接使用 Node.js API。

  • 打包配置 (package.json build 字段) 须针对平台设置不同的图标、签名策略、安装包格式。

代码风格

TypeScript

  • 所有语句必须以分号 ; 结尾,缺失分号将被视为错误。

  • 启用 strict 模式,禁止隐式 any优先使用 interface 定义对象类型,复杂类型可适度使用 type。

  • 文件名使用小写短横线连接kebab-case如 use-window-state.ts组件文件名与组件名保持一致PascalCase如 ThemeAdapter.tsx。

  • 导入顺序:第三方库 → 项目内共享模块 → 相对路径模块,中间用空行分隔。

React

  • 只允许函数组件与 Hooks禁止使用类组件。

  • 每个组件必须有明确的 Props 类型,使用 React.FC 或直接标注函数参数类型(推荐直接标注)。

  • 事件处理函数命名以 handle 开头(如 handleClick自定义 Hook 以 use 开头。

  • 避免直接操作 DOM除非封装在自定义 Hook 中(如焦点管理)。

  • 使用 React.memo、useMemo、useCallback 优化性能,但不要过早优化。

状态管理

  • 使用 React Context + Provider 模式管理全局状态按领域拆分AppContext平台/登录、ThemeContext主题、 SettingsContext设置项。避免引入 Redux 等重量级方案。

  • Provider 组件在 main.tsx 中按层级嵌套挂载: AppProvider → ThemeProvider → SettingsProvider → AntdApp → App

  • 各模块通过自定义 Hook 消费useAppContext / useTheme / useSettingsHook 内部做 null 检查。

日志系统

  • 双端日志主进程直接写文件electron/main/logger.ts渲染进程通过 IPC send 上报src/utils/logger.ts。 两端暴露一致的 APIlogger.debug / info / warn / error(category, message, error?, context?)

  • 文件存储JSON Lines 格式(每行一个 JSON路径 {userData}/logs/app-YYYY-MM-DD.log 每日轮转 + 7 天自动清理。

  • 事件总线联动event-bus.ts 暴露 setEventLogListener 钩子logger 注册后所有 emit 自动记录 DEBUG 日志。

  • 错误日志request.ts 拦截器根据错误类型自动分级记录AUTH_EXPIRED → debug5xx → error其余 → warn

  • 401 判断策略HTTP 401 拦截处双重校验——同时检查 HTTP 状态码和响应体中的业务码 data.code。 仅 status === 401 && data?.code === 401 才走 token 刷新流程;其他业务码(如密码错误)穿透到正常错误处理, 透传后端的 data.message。这确保登录接口返回的"账号或密码错误"不被 RefreshError("登录已过期") 覆盖。

  • 脱敏shared/utils/sanitize.ts 在日志写入前自动处理 ID哈希、邮箱/手机/名称/Token 等字段。

样式与主题

  • 优先使用 Tailwind 工具类 完成布局与常规样式,自定义设计令牌应映射为 Tailwind 扩展(在 tailwind.config.ts 中配置 theme.extend

  • Ant Design 组件样式通过 ConfigProvider 的 theme 属性覆盖,确保与 Tailwind 主题令牌同步。 ConfigProvider 同时配置 locale={zhCN} 实现全局中文(分页器"条/页"等无需逐个组件设置)。 在 src/theme/ 中创建 antd-theme.ts导出主题配置对象引用 tokens.ts 中的设计变量。 组件级 token如 Pagination.itemActiveColor / itemActiveBg在 sharedComponents 中统一管理, 亮色/暗色主题共享,避免 CSS !important hack。

  • 禁止在组件中硬编码颜色、字号等设计令牌,一律使用主题变量或 Tailwind 类名。

  • 全局样式文件 globals.css 只引入 Tailwind 指令和必要的重置样式,不堆积组件样式。

事件与 IPC

  • 所有 IPC 通道名称定义在 shared/constants/ipc-channels.ts 中,分为三类: MAIN_TO_RENDERER / RENDERER_TO_MAIN / BIDIRECTIONAL。

  • 渲染进程通过 src/utils/ipc.ts 中的安全守卫访问 IPChasIpc 检查 → safeIpcOn / send / invoke 非 Electron 环境下静默跳过,保证浏览器预览不崩溃。

  • 主进程事件处理函数需做好错误捕获与日志记录,渲染进程调用 IPC 时使用 try-catch 并处理超时。

  • 窗口间通信走主进程转发:发送窗口 safeIpcSend主进程接收后定位目标窗口并 webContents.send。

开发与构建命令

  • 开发模式npm run dev 或 yarn dev同时启动 Vite 与 Electron支持热重载

  • 构建npm run build 编译渲染进程 → 打包 Electron 应用。

  • 代码检查npm run lintESLint + Prettier规则已配置为强制分号、单引号等

  • 类型检查npm run typechecktsc --noEmit

自动更新系统

架构

客户端 (Electron 主进程)
  checkForUpdates()
    ├─ ① HeiXiuProvider.getLatestVersion()  → 调用自有版本检查 API
    │    └─ hasUpdate=false → 直接 IPC 通知 UI不经过 electron-updater
    └─ ② hasUpdate=true → electron-updater.checkForUpdates()
         ├─ HeiXiuProvider.getLatestVersion() → TTL 缓存命中,不重复请求
         ├─ emit 'update-available'(含 releaseNotes→ UI 展示版本信息
         └─ 用户点击"下载更新" → downloadUpdate()
              ├─ 差分下载(对比 .blockmap仅下载变更区块
              ├─ SHA512 校验
              └─ 下载完成 → 用户点击"安装更新" → NSIS/DMG/AppImage 执行
模块 位置 职责
HeiXiuProvider electron/main/updater.ts 自定义 Provider调用自有 API无更新返回 APP_VERSION
checkForUpdates electron/main/updater.ts 预检版本 → 无更新直发 IPC / 有更新交 electron-updater
downloadUpdate electron/main/updater.ts 用户确认后触发下载(从 checkForUpdates 分离)
netRequest electron/main/net-request.ts Electron net.request 的 axios 风格封装
useUpdater src/hooks/use-updater.ts 渲染进程更新状态 Hook单例 IPC 监听)
UpdateSetting src/pages/settings/UpdateSetting.tsx 设置页更新区块(含"查看详情"弹窗)
server.py test-server/server.py 本地测试服务器,扫描 release/ 目录,语义版本排序

环境变量加载机制(主进程)

加载顺序后者覆盖前者OS 环境变量始终优先):

① OS 环境变量set KEY=VALUE && .\app.exe  ← 最高优先级
② .env.local不进 git个人覆盖用
③ .env.{mode}dev→.env.developmentbuild→.env.production
④ updater.ts 硬编码默认值https://www.heixiu.com
文件 何时生效 进 git 用途
.env.development npm run dev 本地开发API → 测试服务器)
.env.production npm run build:xxx 构建时参考API → 生产服务器)
.env.local 始终(后加载) 个人特殊配置(打包后连本地测试)

.env.production.env.local 不打包进 ASAR。打包后无这些文件时自动使用代码默认值。

测试工作流

# 1. 构建两个版本
npm run build:win                         # → release/0.0.3/
# 改 package.json version = "0.0.4"
npm run build:win                         # → release/0.0.4/

# 2. 启动测试服务器
cd test-server && python server.py --release-dir ../release --port 8000

# 3. 启动旧版本客户端
set UPDATE_API_URL=http://127.0.0.1:8000 && .\release\0.0.3\win-unpacked\船长·HeiXiu.exe
# → 5 秒后自动检测到 0.0.4 → 差分下载 → 提示安装

相关文档:UpdateA.mdtest-server/README.md

与其他 AI 协作的补充说明

  • 所有生成的代码片段必须放在完整的文件上下文中,并注明所属文件路径。

  • 若涉及跨平台逻辑,必须同时给出 Windows 与 macOS 的兼容实现或判断分支。

  • 新增窗口时,需同步说明窗口入口、预加载脚本、主进程创建逻辑及 IPC 通道注册。

  • 修改主题令牌时,需同步更新 tokens.ts、tailwind.config.ts 及 antd-theme.ts确保三处一致。