# 更新日志

> 每次发版前修改此文件，`npm run build:win` 打包后会自动读取生成 update-info.json。
---

## 0.0.28（2026-06-29）

**项目架构重构（VCHSM 五层模块化）+ 公告 Badge 提醒**

### 架构重构

- **VCHSM 模块化**：`pages/` + `services/modules/` 分散模式 → 统一 `modules/` 五层架构
  - **V**iews — 页面组件（纯 JSX 结构）
  - **C**ontrollers — 控制器（交互逻辑 + API 调用）
  - **H**ooks — 自定义 Hook（组件间复用逻辑）
  - **S**ettings — 配置层（常量映射、字段配置、注册表）
  - **M**odel — 数据模型（纯 TS 类型/接口）
- **7 个业务模块**：navbar / announcement / auth / home / account / canvas / settings
- **Home 模块三栏嵌套**：left（输入）/ center（预览）/ right（模型/任务），每栏独立 VCHSM
- **Account 模块子功能分目录**：info / vip / recharge / billing / orders / wechat-work
- **应用壳抽离**：`src/app/` 目录（入口 + Provider + 布局 + 路由分发）
- **跨模块共享**：`src/shared/` 目录（components / hooks / services / utils / infrastructure / theme）
- **导入路径全面更新**：~500+ 处引用同步，TypeScript 编译零错误

### 公告

- **Badge 角标提醒**：antd `Badge` 组件包裹 NavItem，未读公告数量实时显示
- **缓存与轮询**：`useAnnouncements` Hook — localStorage 缓存已读 ID + 每 15 分钟轮询对比
- **标记已读**：打开公告抽屉时自动将当前公告 ID 写入 localStorage，角标消除

### 日志系统

- **全量审计修复**：~60+ 处 try/catch 补充 `logger.warn()` 记录
- **存储路径可配置**：`setLogDirResolver()` / `setDataDirResolver()` 函数注入模式
- **15 个日志分类**：request / auth / updater / event / app / ui / ipc / safe-storage / storage / canvas / canvas-window / …

---

## 0.0.27（2026-06-24）

**无限画布 UI 重构 + 预览键盘控制 + 拖拽体验优化**

### 无限画布

- **双栏布局重构**：AntD Layout（Sider + Content），左侧导航 + 右侧画布，页面级别渲染预览组件解耦 DOM
- **CanvasSidebar**：项目/集数选择器 + 镜头搜索 + 镜头列表（滚动条 + 底部固定刷新按钮）+ 工作区切换
- **CategoryTabs 双模式**：Assets 阶段 → 全部/角色/道具/场景/收藏；其他阶段 → 所有[阶段名]/收藏/待审核/通过/返修/已弃用
- **分类数量徽标**：每个标签显示数据计数，"收藏"标签额外显示媒体类型细分（视频/图片/音频）
- **Ctrl/Cmd + 拖拽平移**：替代 Space 键修饰，释放 Space 给媒体控制；`pointerEvents: none` 防止拖拽时误抓缩略图
- **画布锁**：预览打开时 `previewActiveRef` 双守卫阻止穿透缩放/拖拽
- **无限画布入口按钮**：StageTabs 右侧按钮，调用 `OPEN_CANVAS_WINDOW` IPC

### 预览键盘控制

- **Space 暂停/播放**：capture 阶段拦截 + `stopPropagation`，避免与原生 `<video controls>` 双重触发
- **← → 快退/快进**：capture 阶段直接设置 `currentTime`，步长 ±0.5 秒
- **↑ ↓ 音量**：透传给原生 controls 处理

### 主进程

- **local-media:// Range 头转发**：协议 handler 只提取并转发 `Range` 请求头到 `net.fetch`，确保音视频 seek 返回正确的 206 Partial Content

### UI 调整

- 全局字号上调（侧栏、工具栏、标签、状态栏等）
- CanvasSidebar 滚动条定制 + 主题色适配
- ProjectSelector / EpisodeSelector 宽度自适应

---
## 0.0.26（2026-06-23）

**无限画布滚轮缩放 + 项目管理入口 + 文件拖拽**

### 无限画布（企业版项目管理）

- **滚轮缩放视口**：纯滚轮 10%/tick 快速缩放，Ctrl/Cmd+滚轮 3%/tick 精细控制，范围 2%~1600%
- **鼠标拖拽平移** + **Ctrl/Cmd+0 重置缩放** + **ZoomOverlay 百分比指示器**
- **预览事件穿透防护**：预览打开时锁定底层视口（`previewActiveRef` 双守卫）
- **预览内独立缩放**：图片灯箱支持滚轮缩放(2%~800%) + 拖拽平移 + 百分比指示器
- **原生文件拖拽**：缩略图/预览 `webContents.startDrag()` → Photoshop/资源管理器等外部应用
- **local-media:// 协议**：支持 UNC 网络路径 + 本地路径安全加载

### 主进程

- **画布窗口 `before-input-event`**：拦截 Chromium 页面级缩放，滚轮事件完整到达渲染层
- **`canvas-ipc.ts`**：文件扫描/缩略图生成/文件操作/sidecar 读写/startDrag 等 15+ IPC handler
- **数据源抽象**：`ICanvasDataSource` 接口，离线 `LocalFileDataSource` + 未来在线模式平滑切换

### Bug 修复

- **passive event listener**：React `onWheel` → window 级原生 `{ passive: false }` listener
- **Zustand v5 `getState()` 批处理旧值**：双 `ref`（`currentZoomRef` + `setZoomRef`）读写，绕过原生事件中的批处理快照

---
## 0.0.25（2026-06-22）

**业务错误 Modal 引导 + 左侧栏 UI 增强**

### 业务错误 Modal 引导体系

- **HTTP 402 + code 1001 → 余额不足 Modal**：`request.ts` 拦截器双条件精确匹配，`App.tsx` 弹 Modal 引导"去充值"
- **HTTP 403 + code 4040 → 软件到期 Modal**：拦截 403+4040，弹 Modal 引导"去购买 VIP"
- **`BusinessErrorEvent` 事件总线类型**：标准化 `{ code, message }` 负载，新增 `BALANCE_INSUFFICIENT` 和 `SUBSCRIPTION_EXPIRED` 事件
- **`RequestError.displayed` 标记**：Modal 已展示的错误标记 `displayed=true`，`ModelInputForm.doSubmit` 读取标记跳过 `message.error` 重复 toast
- **防御性兜底**：HTTP 200 + code 1001 也入拦截器（兼容后端行为变体）

### 左侧栏 UI 增强

- **模型列表 emoji 渲染**：从后端 `ui_config.badge` / `meta_config.icon` 提取 emoji 显示在模型名称前
- **标题栏色条加深**：模型选择器 + 任务记录标题栏加 `borderLeft: 3px` 色条 + `colorFillSecondary` 背景 + 图标染色
- **任务列表分页器固定**：`Pagination` 独立到表格外部，`pagination={false}` on Table，分页器始终固定在底部
- **水平滚动条固定**：独立 `div` + 双向 `scroll` 事件同步 + MutationObserver，不随垂直滚动移动
- **统一滚动条样式**：`::-webkit-scrollbar` 暗色/亮色双套，纵向 6px、横向 6px，风格统一
- **表头取消加粗**：`.ant-table-thead > tr > th { font-weight: normal }`
- **模型列表与任务列表间距**：`paddingBottom: 4` / `paddingTop: 4`

---
## 0.0.24（2026-06-22）

**去除构建时版本变量 + 窗口标题动态版控 + 退出登录保留缓存**

### 版控体系重构

- **去除构建时 `EDITION` 环境变量**：`--personal`/`--enterprise` 参数从 `build.mjs` 移除，`vite.config.ts` 不再注入 `process.env.EDITION`，`.env.*` 清理相应行
- **统一的安装包文件名**：`船长-HeiXiu-{os}-{版本号}-Setup.{ext}`（移除 `${env.EDITION}`）
- **`package.json` 简化**：移除 3 条 `:enterprise` 构建脚本
- **`scripts/*.mjs` 统一**：`upload-oss`/`generate-update-info`/`publish-release` 不再接受 `edition` 参数

### 窗口标题动态版控

- **新格式**：`船长-HeiXiu-{os}-{版本号}`（未登录）/ `船长-HeiXiu-{os}-{版本号}·{版控}`（登录后）
- **运行时链路**：`AppProvider` 根据 `user.account_type` 派生 `edition` → `useEffect` → `window.appRuntime.setWindowEdition()` → IPC `set-window-title` → 主进程 `buildWindowTitle` → `mainWindow.setTitle`
- **Edtion 类型守卫**：`src/vite-env.d.ts` + `electron/electron-env.d.ts` 双端类型声明
- **更新检查 API** 移除 `edition` 查询参数

### 本地存储生命周期修正

- **退出登录不再自动清缓存**：`AppProvider.logout()` 移除 `clearUserStorage()` 调用。数据已按 `user_id` 隔离，同一用户重新登录缓存直接命中
- **`clearUserStorage` 竞态修复**：添加 `isOpen()` 前置守卫，防止数据库未初始化时执行 SQL；移除尾部 `closeDatabase()`，确保退出→重新登录周期内数据库持续可用
- **手动清理保留**：`DataManageSetting` 的「清理缓存」按钮仍可主动触发

---
## 0.0.23（2026-06-22）

**三栏等比缩放修复 + 代码重组**

### 三栏布局修复

- **约束逻辑修正**：双遍最小值约束改为 clamp + 超限兜底，修复窗口缩小至 1036px 以下时中列被挤出视口
- **双触发器**：`ResizeObserver` + `window.resize` 事件双重驱动，防止 React 批量更新吞掉重绘
- **三栏等比缩放**：旧算法只保 left:right 比例，中列被动吸收剩余；新算法通过 `prevWidthRef` 反推中列上次宽度，三栏按各自占比同步缩放——窗口从半屏拉到全屏保持 ≈1:1:1

### 代码重组（第二轮）

- **src/utils/**：11 文件精简为 7 文件 —— `env.ts`(platform+device)、`bus.ts`(event-bus+ipc+logger)、`display.ts`(display+logo+type)、`media-upload.ts`
- **controls/**：14 文件精简为 6 文件 —— `simple-widgets.tsx`(6合1)、`upload-widgets.tsx`(ImageInput+VideoInput 去重)、`list-upload-widgets.tsx`(ImageListInput+AudioListInput)
- **FormField 提升**：从 `auth/components/` 提升到 `src/components/ui/`，`FieldConfig` 类型同步移到 `ui/types.ts`
- **data-sync 归位**：从 `settings/sections/` 移到 `infrastructure/storage/`
- **electron/main/ 分组**：3 个 IPC handler（log-ipc/safe-storage-ipc/storage-ipc）收拢到 `ipc/` 子目录
- **shell/ → frame/**：`src/components/shell/` 重命名为 `frame/`，更直观表达"应用框架"
- **storage/ 分层**：15 文件平铺 → `core/`（4）+ `stores/`（5）+ `services/`（4）+ 入口

### 文档

- 37 个文件夹全部生成 README.md（不进 Git）
- PROJECT.md 目录树同步更新

---
## 0.0.22（2026-06-18）

**三栏布局比例缩放 + SeedanceContent 视频参考上传 + 本地存储基建**

### 三栏布局：比例自适应缩放

- ResizeObserver 改为**等比例分配**策略（替代固定默认值恢复）：窗口 Snap/最大化/手动缩放时左-中-右三栏按当前比例同步缩放
- 修复拖拽期间窗口缩放竞态：`handleMouseUp` 即时清除 `draggingRef` + `needsRecalcRef` 延迟补算，解决拖拽中最大化后放开鼠标布局卡死
- 使用 `containerRef.current` 动态读取 DOM（替代闭包捕获 mount 时 `el`），避免 Provider 重渲染后读到旧 DOM

### Seedance2Content 内容编排

- `SeedanceContent` 从占位文本重构为完整内容编排控件：文本描述 + 参考图片/视频/音频三条上传通道
- 根据 `param_schema[].spec.image_files / video_files / audio_files` 动态渲染对应上传区域，**不依赖 widget 名称的隐式约定**
- 内部值类型 `{ text, imageUrls[], videoUrls[], audioUrls[] }` → 表单 JSON 字符串 → 提交时序列化为 API `ContentItem[]`（`text` / `image_url` / `video_url` / `audio_url` 判别联合）
- `useModelUI` 新增 `widgetName` 字段 + `spec` 媒体文件计数传参（`imageFiles`/`videoFiles`/`audioFiles`/`uploadProvider`）
- `ModelInputForm.doSubmit` 新增 `seedance2Content` 分支序列化逻辑

### 图片上传兼容视频文件

- `ImageInput` / `ImageListInput`：`buildAccept` 根据 `file_filter` 自动区分 `image/` vs `video/` 前缀（原硬编码 `image/` 导致视频文件不可选）
- `createMediaBeforeUpload` 根据 `filters` 动态放行 `video/*` MIME
- 公共模块 `media-upload-utils.ts`：`VIDEO_EXTENSIONS` + `buildAccept()` + `createMediaBeforeUpload()` 三组件共享

### 本地存储基建（sql.js + safeStorage）

- **数据库**：sql.js（WASM SQLite）渲染进程内存数据库，DDL 7 张表（task_records / order_records / param_history / media_cache / sync_cursor / app_settings / _schema_version）
- **加密**：safeStorage（OS DPAPI/Keychain）加密持久化，base64 编解码管线
- **IPC 文件操作**：8 个双向 IPC 通道（FILE_WRITE/READ/DELETE/MAKE_DIR/SHOW_ITEM_IN_FOLDER/GET_DATA_DIR/FILE_SIZE/FILE_EXISTS），`resolveSafe()` 路径穿越防护
- **数据目录**：`<userData>/heixiu-data/`（沙箱内），含 `heixiu.db`（加密镜像）+ `media-cache/<userId>/<date>/`
- **用户隔离**：JWT `user_id` 区分数据，`getTodayKey()` 日期分桶
- **同步策略**：本地优先 + 手动触发（"加载历史数据"按钮），游标分页（`sync_cursor` 表），每批 100 条
- **设置集成**：`DataManageSetting` 卡片（缓存统计 + 加载历史数据 + 保存到磁盘 + 清理缓存）

### 媒体输出预览优化

- `<img>/<video>` 直接加载远程 URL（无 CORS 限制），移除阻塞式 axios 下载
- 类型检测：URL 扩展名正则 + `output_type` 补充（CDN 无扩展名链接）
- `<Image fallback>` 加载失败占位图

### 其他

- 修复 `errorMessageRef` 在渲染期间写入（react-hooks/refs 警告）
- CSP 添加 `wasm-unsafe-eval` 支持 WebAssembly + `https:` CDN 媒体源

---
## 0.0.21（2026-06-15）

**文件结构重组：components/ pages/ 按职责分层**

### components/ → 三层拆分

- `providers/`（状态管理）：AppProvider / ThemeProvider / SettingsProvider
- `shell/`（应用外壳）：Layout / PageDispatcher / navbar/
- `ui/`（通用原子）：FloatingPanel / LegalTextModal

### pages/ → 重命名消除歧义

- `headers/` → `panels/`（NavBar 面板页，非 HTTP headers）
- `login/` → `auth/`（含登录/注册/忘记密码/修改密码）
- `settings/blocks/` → `sections/`
- `home/components/useUI/` → `home/controls/`

### home/ → 四层子结构

- `panels/` — 布局壳（LeftPanel / CenterPanel / RightPanel）
- `features/` — 功能面板（Banner / ModelInput / ModelSelector / Output / TaskHistory）
- `controls/` — 表单控件库（12 个控件 + Widget 注册表）
- `hooks/` — 纯 Hook（useModelUI）

### 其他

- HomeContext 从 HomeContent.tsx 拆分独立文件（解决 react-refresh ESLint 警告）
- uploadValidation 内联到 ImageInput（controls/ 不再混工具函数）
- 删除空占位 Test3.tsx

### 支付系统 & 订单明细

- **RechargePage antd 6.x 适配**：`InputNumber.addonAfter` → `Space.Compact`、`Space direction` → `orientation`，消除弃用警告
- **OrdersPage 订单明细页面**（`/orders`，方案 B — 独立订单管理页）：
  - 状态筛选 Segmented（全部/待支付/已支付/已过期/支付失败）+ 分页 Table
  - "继续支付"操作：打开支付 URL + `startPolling` 单订单轮询
  - `pollingRef: Map<orderId, timer>` 管理多订单并发轮询，幂等启动（重复点击防重）
  - 局部 state 更新 + 终态全量刷新（`fetchOrders`）
  - `AbortController` 防竞态：切换筛选/分页时取消旧请求
  - `columns` 使用 `useMemo` 稳定引用
  - 错误态 Result + 重试按钮
- **PageDispatcher**：注册 `/orders` 路由（width: 820, height: 640），新增 `CLOSE_PAGE` / `PAGE_LOCK` 事件监听
- **payments.ts**：支付 API 模块类型体系（`CreateOrderResponseBody` → `OrderListResponseBody` / `OrderInfoResponseBody` 名义类型），`PaymentAPI.getOrdersListInfo` 支持 `AbortSignal`

---

## 0.0.20（2026-06-12）

**任务状态轮询 + Token 刷新容错增强 + 提交防抖 + 文件上传 Hook**

### 任务状态轮询

- 新增 `useTaskPolling` hook：批量轮询非终态任务状态，递归 `setTimeout` + `next_poll_ms` 自适应间隔
- `TaskHistory` 集成批量轮询，`OutputPreview` 改为监听终态转换（Context 桥接）触发 `refetch()`，消除重复请求
- `POLLING_STATUSES` 统一管理非终态状态，所有轮询逻辑引用此常量
- `batchTaskStatus` 使用 GET + 逗号拼接 `task_ids=a,b,c`，修复 axios 默认 bracket 序列化

### Token 刷新容错增强

- **主动刷新**：JWT `exp` 解码驱动定时器，在 75% 过期点通过 `setTimeout` 提前续期
- **失败分级**：`refreshHandler` 永久失败（refresh_token 过期）→ **throw** → 清 token 弹登录；临时失败（网络超时）→ **return null** → 仅拒绝当前请求不登出
- 新增 `RefreshTokenExpiredError` 类区分失败类型
- `AppProvider` 登录/自动登录/退出 启停主动刷新定时器

### 提交按钮防抖

- 两级防护：2s 节流防抖（"你点击的太快了"）+ 二次确认弹窗（"您已提交，确认要再次提交吗？"）
- `doSubmit` 抽取为 `useCallback`，`handleSubmit` 负责门控
- 修复 `useAsyncMutation.execute` 返回值判空（原 `try/catch` 为死代码）

### 文件上传 Hook

- 新增 `useFileUpload` hook：封装 `request.upload()` 为 antd Upload 兼容 `customRequest`，复用全局拦截器
- `ImageInput` / `ImageListInput` / `AudioListInput` 集成 `customRequest`
- `uploadValidation.beforeUpload` 返回值修正：`false` → `true`（校验通过后放行至 `customRequest`）

### 其他

- `AnnouncementDrawer` 接入公告 API + `EnumResolver`
- billing / announcement / banner 服务模块完善
- 文档：ARCHITECTURE.md 新增轮询/Token刷新/上传/防抖章节

---

## 0.0.19（2026-06-11）

**数据获取架构重构 + Mac 指纹采集 + Token 刷新容错 + 账单页面**

### 数据获取架构重构

- `useAsyncData` 集成 AbortController：cleanup 时真正中断 HTTP 请求，不再仅丢弃响应（解决 StrictMode 双重请求）
- fetcher 签名变更：`() => Promise<T>` → `(signal: AbortSignal) => Promise<T>`
- API 模块统一 `signal?: AbortSignal` 可选参数，透传 axios config（banner/auth/models/task/vip）
- `use-api.ts` 成为数据 Hook 集中管理中心：
  - 新增 `useAccountInfo` — `Promise.all` 并行获取用户信息 + VIP 等级
  - 新增 `useBillingBalance` — 账户余额
  - 新增 `useBillingLedger` — 账单明细（支持分页参数）
- `AccountInfo.tsx` 重构：~40 行手写状态管理（`useRef`+`useEffect`+`cancelled`+`retryTick`）→ 1 行 `useAccountInfo()`
- 共享工具 `src/utils/display.ts` — `centToYuan` / `formatDate`，消除 AccountInfo/BillingInfo 重复定义
- 移除 `modelFirstFetchDone` 模块级变量（StrictMode 不安全）

### Mac 硬件指纹采集

- `electron/preload/device.ts` Mac 完整实现：
  - UUID：`ioreg -d2 -c IOPlatformExpertDevice` → `IOPlatformUUID`
  - CPU：`sysctl -n hw.model` → 机型标识
  - HDD：三级回退 `system_profiler SPNVMeDataType` → `SPSerialATADataType` → `SPHardwareDataType`
- `isMacOS()` / `runMacCommand()` / `getMacHddValue()` 辅助函数
- `getComponentId()` / `fingerprintSha256()` Mac 早退分支，与 Windows 共享 SHA256 管线

### 账单页面

- `BillingInfo.tsx` — 余额卡片（BalanceCard）+ 账单表格（LedgerTable）+ 分页
- `BillingAPI` — `getBalance` / `getLedger`，`signal` 参数透传
- `PageDispatcher` 注册 `/billing` 页面（FloatingPanel 960×680）
- 修复 `billing.ts` signal 参数位置 bug：`get(url, {signal})` → `get(url, undefined, {signal})`
- BillingInfo 标题精简：移除冗余页面 Title 和 Card title，仅保留 FloatingPanel 标题栏

### Bug 修复

- **Token 刷新容错**（`auth-token.ts`）：网络错误/超时时保留 refresh_token，仅 RefreshError（token 过期）时清除。
  解决网络短暂中断后被迫手动重新登录的问题
- **AppProvider 自动登录**：`email`/`admin_permissions` 等 nullable 字段默认值修复（`?? ''` / `?? []`）
- **antd Table align**：`align: 'left'` → `align: 'left' as const`，修复 TS2322 类型错误
- **分页器位置**：显式添加 `position: ['bottomRight']`

### 文档

- CLAUDE.md 精简为 AI 行为规则，项目技术内容移入 ARCHITECTURE.md
- ARCHITECTURE.md 新增：数据获取架构、页面调度详情、Token 刷新错误分类、设备指纹

---

## 0.0.18（2026-06-10）

**前后端联调 — 任务创建 + 账户信息 + 预估花费**

### 任务创建联调

- `CreatTaskRequestBody.device_id` 改为后端必填参数，API 层 `Omit` 封装，自动注入 `getDeviceId()`（UUID v4 持久化，与登录/注册统一）
- `useSubmitTask` 泛型同步改为 `Omit<CreatTaskRequestBody, 'device_id'>`，调用方无感
- `submitTask` 移除 `body.device_id || getDeviceId()` 兜底逻辑，始终以本地生成的设备 ID 为准

### 预估花费计算（与 QT/Python 后端对齐）

- `src/utils/pricing.ts` — 从 Python 后端 `calculate_cost` 完整移植六种定价模式：
  - 服务端：`SIMPLE` · `MULTI_DIMENSION` · `BILLING_ADAPTER`（per_k_chars / rate + 条件附加费）
  - 客户端：`fixed` · `per_k_chars` · `rate_matrix` · `matrix`
- `ModelInputForm.tsx` — 三层兜底预估消费展示：完整动态计价 → 配置文件兜底提取 → 模式标签
- **修复 6 个定价 Bug**：
  - SIMPLE 浮点冗余 `(x/100)*100` 在 IEEE 754 下不恒等 → `Math.round(分子)/100`
  - `rate_matrix` / `matrix` 内联维度匹配缺少 `.trim().toLowerCase()` + null 跳过 → 统一 `matchDimensions()`
  - `lookupMappingValue` / `matchDimensions` 缺 null 守卫 → `Cannot use 'in' operator` 崩溃
  - `rate_matrix` 错误应用 `unit_scale`（Python spec 无此行为）→ 移除乘法
  - `matrix` 模式 `dimensions` 空值提前返 null（与 `MULTI_DIMENSION` 不一致）→ 对齐处理
  - 矩阵维度提取 `row.raw` — API 实际在行顶层存储维度（如 `resolution`），`raw` 子对象不存在 → `matrixRowData()` 兼容两种格式
- `pricing_config` 类型修正：`Record<string, unknown>` → `Record<string, unknown> | null`（对齐 OpenAPI `anyOf`）
- 修复 React Hooks 顺序违例 — `estimatedCostDisplay` useMemo 移至提前返回之前

### 账户信息联调

- `AccountInfo.tsx` "当前套餐"从 VIP 等级列表匹配详细数据：
  - `vip_level_id` → `VipLevelsItem.id` 映射查找
  - 新增套餐说明、套餐周期字段，席位上限优先取 VIP 等级值
  - 到期时间提取 `isExpired` 变量复用
- `VipAPI.getVipLevels()` 与 `AuthAPI.getUserInfo()` 并行加载

### 模型列表缓存

- 加密持久化缓存（safe-storage）：启动时 `Promise.all` 初始化，缓存优先渲染消除 loading 闪烁
- `useModelList` Stale-while-revalidate：即时展示缓存 → 后台拉新 → 覆盖缓存

### 其他

- VIP API 模块（`src/services/modules/vip-api.ts`）— 激活码/等级列表/订单/模拟支付
- ESLint/TS 类型修复（未使用符号清理、分号补充）
- CLAUDE.md 更新系统兼容性说明

---

## 0.0.17（2026-06-09）

**修复接口重复调用 — 请求量减半**

- AppProvider 自动登录 useEffect 增加 aborted 清理标志，修复 StrictMode 双重挂载导致 refreshToken/getUserInfo 各调两次
- useModelList 提升到 LeftPanel 单例调用，修复 ModelSelector 和 TaskHistory 各自独立请求全量模型列表
- 开发模式 DevTools 中"已停止"的请求即为 StrictMode 第一轮挂载被丢弃的请求
- 模型输入栏三层架构：useUI 组件体系（10 种 widget → antd 映射）+ useModelUI Hook（param_schema → UIFieldConfig[]）
- constraints_config.requires 动态联动：enable_switch 开关控制依赖字段启用/禁用
- 修复模型默认值不加载（antd 外部 form 实例忽略 initialValues）+ DependentFormItem prop 透传断裂
- PageDispatcher 统一页面调度：Modal/Drawer/FloatingPanel 三容器，全局互斥，动态视口尺寸
- 账户信息页：AuthAPI.getUserInfo() 驱动，积分/套餐/统计三卡片布局
- 代码去重：runFieldChecks 校验运行器 + createImageBeforeUpload 上传校验工厂
- 主题切换性能优化 — View Transitions API + 0.15s 统一过渡 + 设置页增强（0.0.15 延续）
- 目录调整：wechat-work/ → headers/

---

## 0.0.16（2026-06-09）

**模型输入栏重构 + 统一页面调度 + 依赖联动**

- 模型输入栏三层架构：useUI 组件体系（10 种 widget → antd 映射）+ useModelUI Hook（param_schema → UIFieldConfig[]）
- constraints_config.requires 动态联动：enable_switch 开关控制依赖字段启用/禁用
- 修复模型默认值不加载（antd 外部 form 实例忽略 initialValues）+ DependentFormItem prop 透传断裂
- PageDispatcher 统一页面调度：Modal/Drawer/FloatingPanel 三容器，全局互斥，动态视口尺寸
- 账户信息页：AuthAPI.getUserInfo() 驱动，积分/套餐/统计三卡片布局
- 代码去重：runFieldChecks 校验运行器 + createImageBeforeUpload 上传校验工厂
- 主题切换性能优化 — View Transitions API + 0.15s 统一过渡 + 设置页增强（0.0.15 延续）
- 目录调整：wechat-work/ → headers/

---

## 0.0.15（2026-06-09）

**主题切换性能优化 — 桌面端流畅度提升**

- View Transitions API 驱动主题切换：GPU 合成器单次 cross-fade 替代 80+ 个独立 CSS 过渡，消除 Electron 卡顿
- 主题更新时序统一：`applyHtmlTheme` 从 updater → `useLayoutEffect`，CSS 变量与 React 提交同帧
- 过渡参数对齐：全部 `0.2s ease` → `0.15s linear`，桌面应用更利落
- CSS 过渡精准覆盖：antd 容器组件（Layout/Card/Modal/Table/Input/Menu 等 ~80 个类）替代 `html *` 全局选择器
- 设置页 Esc 键关闭 + macOS 关闭按钮适配 + 关闭后焦点防跳转

---

## 0.0.14 -- 🚀更新公告

**模型选择器焕新**

- 模型列表改为标签页分组展示，新增「全部模型」Tab
- 列表项新增悬停高亮效果，维护中模型自动置灰并提示
- 修复选择模型后参数表单重复 key 报错
- 类型体系重构，支持后端分类 slug 自动映射

---

## 0.0.13（2026-06-07）

- 修复主题切换后首页状态重置问题：设置页去路由化，改为事件总线驱动的 Modal 叠加
- 首页三栏分隔条视觉对齐：移除右侧多余 margin，左右完全对称
- 轮播图新增关闭按钮：session 级别隐藏，每次启动重新展示
- 确立 QT 多窗口模型 → Web 架构映射原则：叠加层走 Modal/Drawer + 事件总线，不走路由
- 修复首页三栏布局溢出：拖拽分隔条增加最大宽度约束 + 视口缩小时自动收窄面板，防止右侧面板被挤出视口

---

## 0.0.12（2026-06-04）

- 重构更新检查流程：无更新不再抛异常，PreCheck → 直接 IPC 通知
- 新增用户决定下载流程：检查到新版本后展示更新内容，用户确认后再下载
- 设置页新增"查看详情"弹窗，Markdown 格式化展示更新日志
- 新增"下载更新"按钮，与"安装更新"分离为两个独立操作
- 修复测试服务器版本排序（字符串序 → 语义版本序，0.0.10 正确排在 0.0.9 之后）
- electron-updater Provider 增加 TTL 缓存，避免重复 API 请求
- 修复 Windows cmd `set` 命令空格导致的 Invalid URL 问题
- 修复 electron-updater 'error' 事件拦截，无更新不再爆红

---

## 格式说明

每个版本以 `## x.y.z（日期）` 开头，内容为无序列表。打包脚本会提取最新版本的日志填入 update-info.json。
