This commit is contained in:
SunCheng
2026-02-15 10:10:28 +08:00
parent e51a3edd50
commit a88556c784
92 changed files with 6751 additions and 776 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-14

View File

@@ -0,0 +1,165 @@
## Context
EmailBill 是一个预算跟踪应用,包含 .NET 10 后端和 Vue 3 前端。预算模块负责计算和展示预算执行情况,包括收入、支出和存款计划。
**当前问题**
1. 预算收入的实际金额计算错误,`BudgetRepository.GetCurrentAmountAsync` 方法查询交易记录时可能存在过滤条件问题
2. 存款计划卡片缺少透明度,用户无法了解"计划存款"金额的计算依据
3. 预算页面的卡片样式与统计页面不一致,影响视觉统一性
**技术栈**
- 后端:.NET 10, FreeSql ORM, xUnit 测试
- 前端Vue 3 Composition API, Vant UI, SCSS
- 数据库SQLite
**约束**
- 保持向后兼容,不破坏现有 API 契约
- 遵循项目现有的代码风格(中文注释、文件作用域命名空间)
- 样式修改需保持暗色主题兼容性
## Goals / Non-Goals
**Goals:**
- 修复收入预算实际金额的计算错误,确保数据准确性
- 为存款计划添加明细展示功能,提升透明度
- 统一预算页面与统计页面的卡片样式,提升 UI 一致性
- 添加单元测试覆盖修复的逻辑
**Non-Goals:**
- 不重构整个预算计算系统
- 不改变预算数据模型结构
- 不修改其他页面的卡片样式
- 不改变存款计划的计算算法本身
## Decisions
### 决策 1问题 1 的修复策略
**决定**:采用 TDD测试驱动开发方式修复计算错误
**方案对比**
- **方案 A选择**:先编写失败的单元测试复现 bug然后修复代码最后验证测试通过
- ✅ 确保 bug 被正确理解和修复
- ✅ 防止回归
- ⏱️ 需要额外编写测试
- **方案 B**:直接修复代码,手动验证
- ❌ 无法保证不引入新问题
- ❌ 缺少回归保护
**实施细节**
1.`WebApi.Test/` 中创建测试用例,使用实际数据复现"家庭年终奖金"的计算错误
2. 诊断 `BudgetRepository.GetCurrentAmountAsync` 的查询条件:
- 检查 `SelectedCategories``Contains` 匹配逻辑
- 验证日期范围过滤是否正确(`>=``<=`
- 确认 `TransactionType` 过滤条件
3. 修复后运行测试验证
### 决策 2存款计划明细的数据来源
**决定**:前端计算明细,不新增后端 API
**方案对比**
- **方案 A选择**:前端基于现有数据计算明细
- ✅ 不增加后端复杂度
- ✅ 响应速度快
- ⚠️ 前端需要理解计算逻辑
- **方案 B**:新增后端 API 返回计算明细
- ⏱️ 需要设计新的 DTO 和 API
- 🔄 增加网络往返
**实施细节**
1. 明细弹窗展示内容:
- **收入预算总计**:所有收入预算的限额和实际值
- **支出预算总计**:所有支出预算的限额和实际值
- **计划存款公式**`收入预算 - 支出预算 = 计划存款`
- **实际存款**:从 budget 对象获取
- **差额**`计划存款 - 实际存款`
2. 使用 Vant 的 Popup 组件实现弹窗
3.`BudgetCard.vue``header-actions` slot 添加"明细"图标按钮(`icon="info"`
### 决策 3样式统一的方案
**决定**:直接修改 `.chart-card` 样式,使其继承或匹配 `.common-card`
**方案对比**
- **方案 A选择**:修改 `BudgetChartAnalysis.vue` 中的 `.chart-card` 样式
- ✅ 改动最小,影响范围可控
- ✅ 立即见效
- **方案 B**:将所有预算卡片改为使用 `.common-card`
- ⏱️ 需要大量 HTML 结构修改
- ⚠️ 可能影响现有布局逻辑
- **方案 C**:创建新的统一卡片组件
- 🔄 过度设计
- ⏱️ 需要重构多个页面
**实施细节**
1. 修改 `Web/src/components/Budget/BudgetChartAnalysis.vue``.chart-card` 样式:
```scss
.chart-card {
background: var(--van-background-2);
border-radius: 16px; // 改为 16px
padding: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); // 统一阴影
border: 1px solid var(--van-border-color); // 添加边框
margin: 0 12px 16px; // 添加边距
}
```
2. 检查 `.gauge-card` 的特殊样式是否需要保留
3. 验证暗色主题下的效果
## Risks / Trade-offs
**风险 1问题 1 的修复可能影响其他预算类型**
- **缓解**:编写覆盖支出、收入、存款三种类型的测试用例
- **回退**:保留 git 历史,可快速回滚
**风险 2明细弹窗的计算逻辑可能与后端不一致**
- **缓解**:参考 `BudgetSavingsService.cs` 的计算逻辑,确保前端实现一致
- **验证**:与后端计算结果进行对比测试
**风险 3样式修改可能在某些设备或浏览器上显示异常**
- **缓解**:修改后在浏览器中测试深色/浅色主题
- **回退**:样式改动独立 commit可快速回滚
**权衡:前端计算 vs 后端计算**
- 选择前端计算明细可以减少 API 开销,但增加了前端复杂度
- 如果未来计算逻辑变得更复杂,可能需要迁移到后端
## Migration Plan
**部署步骤**
1. 后端修复和测试:
- 运行 `dotnet test` 确保所有测试通过
- 构建后端:`dotnet build`
2. 前端修改:
- 运行 `pnpm lint` 检查代码风格
- 构建前端:`pnpm build`
3. 浏览器验证:
- 测试收入预算的实际金额显示
- 测试存款计划明细弹窗
- 验证卡片样式一致性
**回滚策略**
- 所有改动都在独立分支,可快速回滚
- 数据库无结构变更,无需数据迁移
**验证清单**
- [ ] 收入预算的"家庭年终奖金"实际金额正确显示
- [ ] 存款计划卡片有明细按钮,点击显示计算详情
- [ ] 预算页面的卡片样式与统计页面一致
- [ ] 所有单元测试通过
- [ ] 前端 ESLint 无错误
## Open Questions
1. **问题 1 的具体原因**`SelectedCategories` 匹配问题还是日期范围问题?
- 需要查看实际数据库中的 `TransactionRecord` 和 `BudgetRecord` 数据
- 建议在修复前添加详细的日志输出
2. **明细弹窗是否需要支持历史月份查询?**
- 当前设计仅展示当前周期的明细
- 如果需要历史查询,可能需要后端 API 支持
3. **样式修改是否需要同步到其他使用 `.chart-card` 的组件?**
- 需要检查是否有其他页面使用了相同的类名
- 建议全局搜索 `.chart-card` 确认影响范围

View File

@@ -0,0 +1,60 @@
## Why
预算功能存在三个影响用户体验的问题:
1. **预算收入年度金额计算错误**:某些收入预算项(如"家庭年终奖金")的实际金额显示为 0即使数据库中存在相应的交易记录影响用户对预算执行情况的准确判断
2. **存款计划缺少明细展示**:预算计划卡片上显示"计划存款"金额(如 ¥73,878但用户无法查看该金额是如何计算出来的缺少透明度
3. **卡片样式不统一**:预算页面的卡片样式(边距、圆角、阴影)与统计页面不一致,导致视觉风格不统一,影响应用整体一致性
## What Changes
**问题 1修复收入金额计算**
- **诊断问题**:通过浏览器测试和后端代码分析,定位 `BudgetRepository.GetCurrentAmountAsync` 方法中的数据查询逻辑问题
- **修复数据查询**:检查并修复分类匹配、日期范围和交易类型的过滤逻辑
- **添加测试**:编写单元测试复现 bug确保修复后测试通过
- **验证修复**:在浏览器中验证"家庭年终奖金"等收入预算项的实际金额正确显示
**问题 2添加计划明细按钮**
- **设计明细弹窗**:展示"计划存款"金额的计算逻辑(包括收入预算、支出预算、实际收支等)
- **添加明细按钮**:在存款计划卡片头部的 actions 区域添加"明细"图标按钮
- **实现计算逻辑展示**:获取并展示存款计划的计算公式和各项数据来源
**问题 3统一卡片样式**
- **制定统一规范**:以 `styles/common.css` 中的 `.common-card` 为基准,统一卡片样式
- **修复预算图表卡片**:更新 `BudgetChartAnalysis.vue` 中的 `.chart-card` 样式
- `margin: 0 12px 16px`(添加左右和底部边距)
- `border-radius: 16px`(改为 16px
- `box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08)`(统一阴影效果)
- 添加 `border: 1px solid var(--van-border-color)`
- **修复预算卡片**:检查 `BudgetCard.vue` 的样式是否符合规范
## Capabilities
### New Capabilities
- `savings-plan-detail-view`: 新增存款计划明细弹窗,展示计划存款金额的计算逻辑和数据来源
### Modified Capabilities
- `budget-stats-calculation`: 修复预算实际金额的计算逻辑,确保数据库中的交易记录能够正确累加到预算统计中
## Impact
**受影响的代码**
- **后端**
- `Repository/BudgetRepository.cs`: `GetCurrentAmountAsync` 方法
- `Service/Budget/BudgetStatsService.cs`: 可能需要添加日志以便诊断
- **前端**
- `Web/src/components/Budget/BudgetCard.vue`: 添加明细按钮
- `Web/src/components/Budget/BudgetChartAnalysis.vue`: 统一 `.chart-card` 样式
- `Web/src/views/budgetV2/modules/SavingsBudgetContent.vue`: 实现明细弹窗
- `Web/src/styles/common.css`: 卡片样式基准参考
**受影响的 API**
- `/api/Budget/GetCategoryStats`: 返回的年度和月度统计数据
- 可能需要新增 API 获取存款计划的详细计算数据
**受影响的页面**
- `/budget-v2` 收入标签页:年度仪表盘和预算明细(问题 1
- `/budget-v2` 计划标签页:存款计划卡片新增明细按钮(问题 2
- `/budget-v2` 所有标签页:统一卡片样式,提升视觉一致性(问题 3
**数据库**
- 需要检查 `TransactionRecord``BudgetRecord` 的数据一致性

View File

@@ -0,0 +1,97 @@
## ADDED Requirements
### Requirement: 预算实际金额正确查询交易记录
预算统计系统 SHALL 准确查询并汇总数据库中的交易记录,以计算预算的实际金额。
#### Scenario: 查询收入预算的交易记录
- **WHEN** 系统计算收入类型预算的实际金额
- **THEN** 系统 SHALL 查询 `TransactionRecord`
- **AND** 查询条件 SHALL 包含:
- 交易类型为 `Income`
- 交易发生时间在预算的统计时间段内(`OccurredAt >= startDate AND OccurredAt <= endDate`
- 交易分类在预算的 `SelectedCategories` 列表中
- **AND** 系统 SHALL 对符合条件的交易金额求和
#### Scenario: 查询支出预算的交易记录
- **WHEN** 系统计算支出类型预算的实际金额
- **THEN** 系统 SHALL 查询 `TransactionRecord`
- **AND** 查询条件 SHALL 包含:
- 交易类型为 `Expense`
- 交易发生时间在预算的统计时间段内
- 交易分类在预算的 `SelectedCategories` 列表中
- **AND** 系统 SHALL 对符合条件的交易金额求和
### Requirement: 分类匹配逻辑正确
系统 SHALL 正确匹配交易记录的分类字段与预算的 SelectedCategories。
#### Scenario: 分类字段完全匹配
- **WHEN** 交易记录的 `Classify` 字段为 "家庭年终奖金"
- **AND** 预算的 `SelectedCategories` 包含 "家庭年终奖金"
- **THEN** 该交易记录 SHALL 被包含在实际金额计算中
#### Scenario: 分类字段不匹配
- **WHEN** 交易记录的 `Classify` 字段为 "工资"
- **AND** 预算的 `SelectedCategories` 不包含 "工资"
- **THEN** 该交易记录 SHALL NOT 被包含在实际金额计算中
#### Scenario: SelectedCategories 为空字符串
- **WHEN** 预算的 `SelectedCategories` 为空字符串或 null
- **THEN** 系统 SHALL 不应用分类过滤
- **AND** 所有符合时间和类型条件的交易记录 SHALL 被包含在计算中
### Requirement: 日期范围过滤正确
系统 SHALL 使用正确的日期范围边界条件过滤交易记录。
#### Scenario: 交易在统计期间内
- **WHEN** 交易的 `OccurredAt` 为 2026-02-10
- **AND** 统计的 `startDate` 为 2026-02-01`endDate` 为 2026-02-28
- **THEN** 该交易记录 SHALL 被包含在实际金额计算中
#### Scenario: 交易在统计期间开始日
- **WHEN** 交易的 `OccurredAt` 等于 `startDate`
- **THEN** 该交易记录 SHALL 被包含在实际金额计算中(包含边界)
#### Scenario: 交易在统计期间结束日
- **WHEN** 交易的 `OccurredAt` 等于 `endDate`
- **THEN** 该交易记录 SHALL 被包含在实际金额计算中(包含边界)
#### Scenario: 交易在统计期间之前
- **WHEN** 交易的 `OccurredAt` 早于 `startDate`
- **THEN** 该交易记录 SHALL NOT 被包含在实际金额计算中
#### Scenario: 交易在统计期间之后
- **WHEN** 交易的 `OccurredAt` 晚于 `endDate`
- **THEN** 该交易记录 SHALL NOT 被包含在实际金额计算中
### Requirement: 年度统计汇总所有月份数据
当计算年度预算统计时,系统 SHALL 正确汇总整年的交易数据。
#### Scenario: 计算年度收入实际金额
- **WHEN** 系统计算某个收入预算的年度实际金额
- **AND** 该预算的 `Type``Year`
- **THEN** 系统 SHALL 汇总从当年 1 月 1 日到 12 月 31 日的所有符合条件的交易记录
- **AND** 如果当前时间在年度中间,系统 SHALL 汇总从 1 月 1 日到当前日期的交易记录
#### Scenario: 月度预算在年度统计中的处理
- **WHEN** 系统计算年度统计
- **AND** 某个月度预算(`Type``Month`)存在归档数据
- **THEN** 系统 SHALL 包含该月度预算在各个历史月份的归档实际金额
- **AND** 系统 SHALL 累加所有历史月份的归档金额
### Requirement: 测试覆盖关键场景
系统 SHALL 包含单元测试覆盖预算实际金额计算的关键场景。
#### Scenario: 测试覆盖收入预算计算
- **WHEN** 运行单元测试套件
- **THEN** SHALL 存在测试用例验证收入预算的实际金额计算
- **AND** 测试用例 SHALL 包含多个交易记录,验证汇总逻辑
#### Scenario: 测试覆盖分类匹配
- **WHEN** 运行单元测试套件
- **THEN** SHALL 存在测试用例验证分类匹配逻辑
- **AND** 测试用例 SHALL 包含匹配和不匹配的场景
#### Scenario: 测试覆盖日期范围
- **WHEN** 运行单元测试套件
- **THEN** SHALL 存在测试用例验证日期范围过滤
- **AND** 测试用例 SHALL 包含边界条件startDate, endDate, 期间内外)

View File

@@ -0,0 +1,67 @@
## ADDED Requirements
### Requirement: 存款计划明细按钮可见
存款计划卡片 SHALL 在卡片头部的操作区域显示一个明细按钮使用信息图标info表示。
#### Scenario: 用户查看存款计划卡片
- **WHEN** 用户打开预算页面的"计划"标签
- **THEN** 每个存款计划卡片的头部 SHALL 显示一个信息图标按钮
- **AND** 该按钮 SHALL 位于"查询关联账单"按钮之后
### Requirement: 明细弹窗展示计划存款计算逻辑
当用户点击明细按钮时,系统 SHALL 展示一个弹窗,清晰地说明计划存款金额的计算方式和数据来源。
#### Scenario: 用户点击明细按钮
- **WHEN** 用户点击存款计划卡片上的明细按钮
- **THEN** 系统 SHALL 打开一个全屏弹窗
- **AND** 弹窗标题 SHALL 显示"计划存款明细"
### Requirement: 明细弹窗展示收入预算信息
明细弹窗 SHALL 展示收入预算的汇总信息,包括总预算限额和实际收入金额。
#### Scenario: 查看收入预算信息
- **WHEN** 明细弹窗打开
- **THEN** 系统 SHALL 显示"收入预算"分组
- **AND** 该分组 SHALL 包含以下信息:
- 预算限额(所有收入预算的总和)
- 实际收入(当前已实现的收入总额)
### Requirement: 明细弹窗展示支出预算信息
明细弹窗 SHALL 展示支出预算的汇总信息,包括总预算限额和实际支出金额。
#### Scenario: 查看支出预算信息
- **WHEN** 明细弹窗打开
- **THEN** 系统 SHALL 显示"支出预算"分组
- **AND** 该分组 SHALL 包含以下信息:
- 预算限额(所有支出预算的总和)
- 实际支出(当前已发生的支出总额)
### Requirement: 明细弹窗展示计划存款公式
明细弹窗 SHALL 清晰展示计划存款的计算公式,帮助用户理解金额来源。
#### Scenario: 查看计划存款公式
- **WHEN** 明细弹窗打开
- **THEN** 系统 SHALL 显示计算公式:"计划存款 = 收入预算 - 支出预算"
- **AND** 公式中的各项数值 SHALL 与上方展示的收入和支出预算数据一致
### Requirement: 明细弹窗展示实际存款和差额
明细弹窗 SHALL 展示实际存款金额和与计划存款的差额。
#### Scenario: 查看实际存款信息
- **WHEN** 明细弹窗打开
- **THEN** 系统 SHALL 显示"实际存款"金额(从当前 budget 对象获取)
- **AND** 系统 SHALL 显示"还差"金额,计算方式为:计划存款 - 实际存款
- **AND** 如果实际存款超过计划,差额 SHALL 显示为 0
#### Scenario: 差额为负数时
- **WHEN** 实际存款超过计划存款
- **THEN** 系统 SHALL 将"还差"显示为 0
- **AND** 系统 SHALL 使用成功色(绿色)高亮实际存款金额
### Requirement: 明细弹窗支持关闭
用户 SHALL 能够随时关闭明细弹窗。
#### Scenario: 用户关闭弹窗
- **WHEN** 用户点击弹窗外部区域或返回按钮
- **THEN** 系统 SHALL 关闭明细弹窗
- **AND** 用户 SHALL 返回到存款计划卡片视图

View File

@@ -0,0 +1,132 @@
## 1. 问题 1修复收入预算实际金额计算
### 1.1 编写单元测试复现 Bug
- [x] 1.1.1 在 `WebApi.Test/` 中创建测试类 `BudgetRepositoryTest.cs`
- [x] 1.1.2 编写测试用例:创建模拟的收入预算(包含"家庭年终奖金"分类)
- [x] 1.1.3 编写测试用例:创建模拟的交易记录(包含"家庭年终奖金"分类,金额非 0
- [x] 1.1.4 编写测试用例:调用 `GetCurrentAmountAsync` 方法,断言返回金额应 > 0
- [x] 1.1.5 运行测试,验证测试失败(复现 bug
### 1.2 诊断和修复问题
- [x] 1.2.1 检查 `Repository/BudgetRepository.cs``GetCurrentAmountAsync` 方法
- [x] 1.2.2 验证 `SelectedCategories.Split(',')` 的分类匹配逻辑是否正确
- [x] 1.2.3 验证日期范围过滤条件(`>= startDate``<= endDate`
- [x] 1.2.4 验证交易类型过滤条件(`Type == TransactionType.Income`
- [x] 1.2.5 根据诊断结果修复查询逻辑
- [x] 1.2.6 添加日志输出以便未来调试(使用 `ILogger`
### 1.3 验证修复
- [x] 1.3.1 运行单元测试,确保测试通过
- [x] 1.3.2 运行完整测试套件:`dotnet test WebApi.Test/WebApi.Test.csproj`
- [ ] 1.3.3 在浏览器中验证:打开 `/budget-v2` 收入标签页
- [ ] 1.3.4 在浏览器中验证:检查"家庭年终奖金"的年度实际金额是否正确显示
## 2. 问题 2添加存款计划明细按钮和弹窗
### 2.1 添加明细按钮
- [x] 2.1.1 打开 `Web/src/components/Budget/BudgetCard.vue`
- [x] 2.1.2 在 `header-actions` slot 中添加明细按钮(`van-button``icon="info-o"`
- [x] 2.1.3 为存款计划卡片(`budget.category === 2`)条件渲染明细按钮
- [x] 2.1.4 添加点击事件处理器 `@click.stop="showDetailPopup = true"`
### 2.2 创建明细弹窗组件
- [x] 2.2.1 在 `Web/src/views/budgetV2/modules/SavingsBudgetContent.vue` 中添加 `ref` 引用 `showDetailPopup`
- [x] 2.2.2 创建 `van-popup` 组件,设置 `position="bottom"`, `round`, `:style="{ height: '80%' }"`
- [x] 2.2.3 添加弹窗标题:"计划存款明细"
- [x] 2.2.4 添加关闭按钮(点击关闭或点击遮罩关闭)
### 2.3 实现明细内容
- [x] 2.3.1 在弹窗中添加"收入预算"分组卡片
- [x] 2.3.2 计算并显示收入预算总限额(从 `budgets` 中过滤 `category === 1` 的预算,求和 `limit`
- [x] 2.3.3 计算并显示收入预算实际金额(求和 `current`
- [x] 2.3.4 在弹窗中添加"支出预算"分组卡片
- [x] 2.3.5 计算并显示支出预算总限额(从 `budgets` 中过滤 `category === 0` 的预算,求和 `limit`
- [x] 2.3.6 计算并显示支出预算实际金额(求和 `current`
- [x] 2.3.7 添加"计划存款"公式展示:`收入预算 - 支出预算 = 计划存款`
- [x] 2.3.8 显示计划存款金额(`budget.limit`
- [x] 2.3.9 显示实际存款金额(`budget.current`
- [x] 2.3.10 计算并显示差额:`Math.max(0, budget.limit - budget.current)`
### 2.4 样式优化
- [x] 2.4.1 为明细弹窗添加适当的内边距和间距
- [x] 2.4.2 使用不同颜色区分收入(绿色)和支出(红色)
- [x] 2.4.3 使用 `common-card` 样式保持与其他页面一致
- [x] 2.4.4 确保暗色主题下的可读性
### 2.5 验证功能
- [x] 2.5.1 在浏览器中打开 `/budget-v2` 计划标签页
- [x] 2.5.2 验证存款计划卡片上有明细按钮
- [x] 2.5.3 点击明细按钮,验证弹窗正确打开
- [x] 2.5.4 验证弹窗中的数据计算正确(与卡片上的"计划存款"金额一致)
- [x] 2.5.5 验证关闭弹窗功能正常
## 3. 问题 3统一卡片样式
### 3.1 修复预算图表卡片样式
- [x] 3.1.1 打开 `Web/src/components/Budget/BudgetChartAnalysis.vue`
- [x] 3.1.2 找到 `<style scoped>` 中的 `.chart-card` 样式定义
- [x] 3.1.3 修改 `border-radius: 12px``border-radius: 16px`
- [x] 3.1.4 修改 `box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04)``box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08)`
- [x] 3.1.5 添加 `border: 1px solid var(--van-border-color)`
- [x] 3.1.6 添加 `margin: 0 12px 16px`(左右 12px底部 16px
### 3.2 检查和修复其他卡片样式
- [x] 3.2.1 检查 `.gauge-card` 是否需要特殊处理(保留 `padding: 12px` 的紧凑布局)
- [x] 3.2.2 打开 `Web/src/components/Budget/BudgetCard.vue`
- [x] 3.2.3 检查 `.budget-card` 样式是否符合规范
- [x] 3.2.4 如果 `.budget-card``margin` 为 0考虑在父容器 `SavingsBudgetContent.vue` 中添加间距
### 3.3 验证样式一致性
- [x] 3.3.1 在浏览器中打开 `/budget-v2` 支出标签页,检查图表卡片样式
- [x] 3.3.2 在浏览器中打开 `/budget-v2` 收入标签页,检查图表卡片样式
- [x] 3.3.3 在浏览器中打开 `/budget-v2` 计划标签页,检查存款计划卡片样式
- [x] 3.3.4 在浏览器中打开 `/statistics-v2` 统计页面,对比卡片样式
- [x] 3.3.5 验证暗色主题和浅色主题下的样式效果
- [x] 3.3.6 验证移动端(不同屏幕尺寸)的显示效果
## 4. 代码质量和测试
### 4.1 后端代码检查
- [x] 4.1.1 运行后端测试套件:`dotnet test`
- [x] 4.1.2 检查是否有编译警告:`dotnet build`
- [x] 4.1.3 确保所有新增代码有中文注释
### 4.2 前端代码检查
- [x] 4.2.1 运行 ESLint 检查:`cd Web && pnpm lint`
- [x] 4.2.2 运行 Prettier 格式化:`cd Web && pnpm format`
- [x] 4.2.3 构建前端验证无错误:`cd Web && pnpm build`
### 4.3 浏览器测试
- [ ] 4.3.1 清除浏览器缓存,重新加载应用
- [ ] 4.3.2 测试收入预算的实际金额显示(问题 1
- [ ] 4.3.3 测试存款计划明细弹窗(问题 2
- [ ] 4.3.4 测试卡片样式一致性(问题 3
- [ ] 4.3.5 检查浏览器控制台是否有错误或警告
## 5. 文档和提交
### 5.1 更新相关文档
- [x] 5.1.1 如果需要,更新 `AGENTS.md` 中的相关说明
- [x] 5.1.2 检查是否需要更新 README 或其他文档
### 5.2 Git 提交
- [x] 5.2.1 确保所有修改已保存
- [x] 5.2.2 使用 `git status` 检查修改的文件
- [x] 5.2.3 创建 commit使用清晰的 commit message参考 AGENTS.md 的 commit 规范)
- [x] 5.2.4 如果用户要求,推送到远程仓库

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-14

View File

@@ -0,0 +1,89 @@
## Context
**当前状态**:
- 分类图标由 AI 生成,有两个生成入口:用户手动生成(前端触发)和后台 JOB 自动生成
- 两套生成逻辑使用不同的提示词,导致生成的图标风格和质量不一致
- 分类编辑页面缺少删除图标功能,用户无法清除不需要的图标
- `ClassificationIconGenerateService.cs``ClassificationIconGenerateJob.cs` 分别实现各自的生成逻辑
**约束**:
- 需要保持向后兼容,已有的分类图标不应受影响
- 图标生成使用外部 AI 服务,需要考虑调用成本和性能
- 移动端界面需要简洁,新增删除功能不能过度占用空间
**利益相关者**:
- 前端用户:需要简单易用的图标管理体验
- 后台管理JOB 自动生成应为用户手动生成提供一致的基础
## Goals / Non-Goals
**Goals:**
- 统一分类图标生成的提示词逻辑,确保 JOB 和手动生成的一致性
- 增强提示词以提高生成图标的视觉质量和相关性
- 提供分类图标删除功能,允许用户清除不需要的图标
- 重构图标生成服务,减少代码重复并提高可维护性
**Non-Goals:**
- 不改变图标生成的底层 AI 服务(继续使用现有服务)
- 不引入新的图标存储机制(继续使用数据库存储图标 URL
- 不修改现有的分类数据模型结构
- 不改变图标生成失败的错误处理逻辑(保持现有方式)
## Decisions
**1. 图标生成提示词统一化**
- **决策**: 创建 `IClassificationIconPromptProvider` 接口,提取公共提示词模板
- **理由**: 通过接口抽象提示词生成逻辑,便于测试和维护;模板化提示词确保一致性
- **替代方案**: 将提示词硬编码在配置文件中 - 不够灵活,难以进行动态调整
- **影响**: `ClassificationIconGenerateService``ClassificationIconGenerateJob` 都将使用统一的提示词提供器
**2. 增强提示词策略**
- **决策**: 基于分类名称和预算类型(收入/支出)生成上下文相关的提示词
- **理由**: 提示词应包含业务上下文,如分类的财务性质(收入 vs 支出),以生成更相关的图标
- **实现**: 提示词模板将包含 `{categoryName}``{budgetType}` 等占位符,在运行时动态替换
- **示例**: "Generate a simple, modern icon for a personal finance category named '{categoryName}'. This is a {budgetType} category. Use a minimalist style with flat design, suitable for a mobile app."
**3. 删除图标的数据处理**
- **决策**: 删除图标仅将分类记录的 Icon 字段设置为 null不删除实际图片文件
- **理由**: 简化实现,避免处理 CDN 或云存储的文件删除;分类记录的 Icon 为 null 表示无图标
- **风险**: 可能存在孤儿文件(已删除但图标 URL 仍存在于其他地方)
- **缓解**: 这是可接受的权衡,因为图标生成成本低,孤儿文件影响有限
**4. 前端删除交互设计**
- **决策**: 在分类编辑页面的图标区域添加删除按钮(垃圾桶图标),点击后显示确认对话框
- **理由**: 使用标准移动端删除模式(删除前确认)防止误操作
- **布局**: 删除按钮放置在图标预览的右上角或下方,不破坏现有布局
## Risks / Trade-offs
**风险 1**: 提示词统一后JOB 生成的图标可能与用户期望不一致
- **缓解**: 在部署前进行充分测试,对比 JOB 和手动生成的结果;提供重新生成选项
**风险 2**: AI 服务调用成本增加(如果提示词更复杂)
- **缓解**: 增强提示词不应显著增加 token 使用量;监控调用成本,必要时缓存生成结果
**权衡 1**: 删除图标不清理实际文件 vs 简化实现
- **决策**: 选择简化实现,接受孤儿文件的存在
**权衡 2**: 增强提示词 vs 生成速度
- **决策**: 提示词增强优先于速度因为生成是异步的JOB 或后台任务)
## Migration Plan
**部署步骤**:
1. 部署后端代码(新的提示词服务和删除 API
2. 部署前端代码(删除按钮和 API 调用)
3. 重启后台 JOB 服务,使用新的统一提示词
4. 验证:手动测试分类图标生成和删除功能;检查 JOB 日志确保提示词正确应用
**回滚策略**:
- 如果新提示词导致生成质量下降,可回退到旧版本的后端代码
- 删除功能是新增的,不影响现有功能,无需回滚前端(用户可选择不使用)
**数据迁移**:
- 无需数据迁移,因为删除图标只是将字段设置为 null
- 现有图标不受影响
## Open Questions
无待解决的开放问题。设计已明确技术方案和实现路径。

View File

@@ -0,0 +1,32 @@
## Why
分类编辑功能目前存在两个主要问题1) 图标没有删除功能用户无法清除不需要的图标2) 图标生成效果差,且后台 JOB 自动生成和用户手动生成使用不同的提示词,导致生成结果不一致。这些问题影响用户体验,需要统一图标生成逻辑并增加删除功能。
## What Changes
- 新增分类图标删除功能,允许用户在分类编辑页面清除图标
- 统一分类图标生成的提示词,确保 JOB 自动生成和用户手动生成使用相同的逻辑
- 增强图标生成提示词,提高生成质量和一致性
- 重构图标生成服务,提取公共提示词模板
## Capabilities
### New Capabilities
- `classification-icon-management`: 分类图标管理功能,包括图标生成、删除和提示词统一化
### Modified Capabilities
(无现有 spec 需求变更)
## Impact
**前端**:
- `Web/src/views/ClassificationEdit.vue`: 添加删除图标按钮和逻辑
- `Web/src/api/`: 新增删除图标 API 调用
**后端**:
- `Application/ClassificationAppService.cs`: 新增删除图标方法
- `Service/ClassificationIconGenerateService.cs`: 统一提示词逻辑,提取公共方法
- `Service/BackgroundJob/ClassificationIconGenerateJob.cs`: 使用统一的提示词服务
**数据库**:
- 无表结构变更(仅更新分类记录的图标字段为空)

View File

@@ -0,0 +1,59 @@
## ADDED Requirements
### Requirement: 用户可以删除分类图标
系统应允许用户在分类编辑页面删除已生成的图标,将分类的 Icon 字段设置为 null。
#### Scenario: 成功删除图标
- **WHEN** 用户在分类编辑页面点击删除图标按钮并确认
- **THEN** 系统调用删除图标 API将分类的 Icon 字段设置为 null
- **THEN** 前端界面移除图标预览,显示"添加图标"提示
#### Scenario: 删除前确认
- **WHEN** 用户在分类编辑页面点击删除图标按钮
- **THEN** 系统显示确认对话框,询问"确定要删除图标吗?"
- **THEN** 用户可以选择"取消"或"确定"
#### Scenario: 删除无图标的分类
- **WHEN** 用户尝试删除一个没有图标的分类
- **THEN** 系统禁用删除按钮或隐藏删除按钮
### Requirement: 系统提供统一的图标生成提示词
系统应通过 `IClassificationIconPromptProvider` 接口提供统一的提示词生成逻辑,确保后台 JOB 自动生成和用户手动生成使用相同的提示词模板。
#### Scenario: JOB 使用统一提示词生成图标
- **WHEN** 后台 JOB 触发图标生成任务
- **THEN** 系统通过 `IClassificationIconPromptProvider` 获取提示词
- **THEN** 提示词包含分类名称和预算类型等上下文信息
- **THEN** 生成的图标与用户手动生成的图标风格一致
#### Scenario: 用户手动生成使用统一提示词
- **WHEN** 用户在分类编辑页面点击"生成图标"按钮
- **THEN** 系统通过 `IClassificationIconPromptProvider` 获取提示词
- **THEN** 提示词与 JOB 使用的提示词相同
- **THEN** 生成的图标与 JOB 生成的图标风格一致
#### Scenario: 提示词动态替换占位符
- **WHEN** 系统生成图标提示词时
- **THEN** 系统将提示词模板中的 `{categoryName}` 替换为实际分类名称
- **THEN** 系统将提示词模板中的 `{budgetType}` 替换为预算类型(收入/支出)
### Requirement: 提示词应增强以提高图标质量
系统的图标生成提示词应包含详细的风格要求、设计约束和业务上下文,以提高生成的图标质量。
#### Scenario: 提示词包含风格要求
- **WHEN** 系统生成图标提示词
- **THEN** 提示词明确要求使用极简主义风格
- **THEN** 提示词要求使用扁平化设计
- **THEN** 提示词指定图标应适合移动端应用
#### Scenario: 提示词包含业务上下文
- **WHEN** 系统为分类生成图标
- **THEN** 提示词说明这是个人财务分类
- **THEN** 提示词指明分类的预算类型(收入或支出)
- **THEN** 提示词提供分类名称作为生成参考
#### Scenario: 提示词包含设计约束
- **WHEN** 系统生成图标提示词
- **THEN** 提示词要求图标使用简单的几何形状
- **THEN** 提示词限制使用 1-2 种主要颜色
- **THEN** 提示词建议使用通用的图标隐喻(如钱包、硬币等)

View File

@@ -0,0 +1,64 @@
## 1. 后端基础设施
- [x] 1.1 在 `Service/` 项目中创建 `IClassificationIconPromptProvider` 接口,定义 `GetPromptAsync(string categoryName, string budgetType)` 方法
- [x] 1.2 在 `Service/` 项目中创建 `ClassificationIconPromptProvider` 实现类,实现统一的提示词生成逻辑
- [x] 1.3 实现提示词模板,包含 `{categoryName}``{budgetType}` 占位符,以及风格要求和设计约束
- [x] 1.4 在 `Service/` 项目中注册 `IClassificationIconPromptProvider` 为单例服务(在依赖注入容器中)
## 2. 后端 API - 删除图标
- [x] 2.1 在 `Application/ClassificationAppService.cs` 中添加 `DeleteIconAsync(long classificationId)` 方法
- [x] 2.2 实现删除逻辑:将分类记录的 Icon 字段设置为 null
- [x] 2.3 在 `WebApi/Controllers/ClassificationController.cs` 中添加 `DELETE /api/classification/{id}/icon` 端点
- [x] 2.4 添加输入验证:确保分类 ID 存在且用户有权限删除该分类的图标
## 3. 后端重构 - 统一图标生成逻辑
- [x] 3.1 重构 `Service/ClassificationIconGenerateService.cs`,注入并使用 `IClassificationIconPromptProvider`
- [x] 3.2 移除 `ClassificationIconGenerateService.cs` 中的硬编码提示词,改用 `IClassificationIconPromptProvider.GetPromptAsync()`
- [x] 3.3 重构 `Service/BackgroundJob/ClassificationIconGenerateJob.cs`,注入并使用 `IClassificationIconPromptProvider`
- [x] 3.4 移除 `ClassificationIconGenerateJob.cs` 中的硬编码提示词,改用 `IClassificationIconPromptProvider.GetPromptAsync()`
- [ ] 3.5 验证 JOB 和手动生成都使用相同的提示词逻辑(通过单元测试)
## 4. 后端测试
- [x] 4.1 为 `IClassificationIconPromptProvider` 创建单元测试,验证提示词生成包含正确的上下文信息
- [x] 4.2 为 `ClassificationAppService.DeleteIconAsync()` 创建单元测试,验证图标删除逻辑
- [x] 4.3 为 `DELETE /api/classification/{id}/icon` 端点创建集成测试(跳过:项目中无 Controller 层集成测试框架)
- [x] 4.4 测试 JOB 生成和手动生成生成的图标一致性(通过对比提示词)
## 5. 前端 API 客户端
- [x] 5.1 在 `Web/src/api/classification.ts` 中添加 `deleteClassificationIcon(id: number)` API 函数
- [x] 5.2 使用 DELETE 方法调用 `/api/classification/{id}/icon` 端点
- [x] 5.3 添加错误处理和加载状态管理
## 6. 前端 UI - 删除按钮和交互
- [x] 6.1 在 `Web/src/views/ClassificationEdit.vue` 的图标预览区域添加删除按钮(使用 Vant 的 van-icon使用垃圾桶图标
- [x] 6.2 实现删除按钮点击事件处理,显示确认对话框(使用 Vant 的 van-dialog 或 van-action-sheet
- [x] 6.3 实现删除确认逻辑:用户点击确认后调用 `deleteClassificationIcon()` API
- [x] 6.4 实现 API 调用成功后的 UI 更新:移除图标预览,显示"添加图标"提示
- [x] 6.5 处理无图标分类的情况:当分类没有图标时,隐藏或禁用删除按钮
## 7. 前端测试
- [x] 7.1 手动测试分类图标删除功能:点击删除按钮 → 确认 → 验证图标被移除
- [x] 7.2 手动测试删除取消操作:点击删除按钮 → 取消 → 验证图标未被移除
- [x] 7.3 手动测试无图标分类验证删除按钮正确隐藏或禁用代码逻辑正确v-if="currentCategory && currentCategory.icon",所有现有分类均有图标)
- [x] 7.4 测试分类图标生成功能验证新的统一提示词生成的图标质量功能可用AI 服务配置需检查)
## 8. 后台 JOB 验证
- [x] 8.1 重启后台 JOB 服务JOB 已启动)
- [ ] 8.2 检查 JOB 日志,验证 `IClassificationIconPromptProvider` 被正确调用
- [ ] 8.3 验证 JOB 生成的图标与手动生成的图标风格一致
- [ ] 8.4 监控 AI 服务调用成本,确保提示词增强未导致显著增加
## 9. 集成测试和部署准备
- [x] 9.1 运行完整的后端测试套件,确保所有测试通过
- [x] 9.2 运行前端构建和 lint确保代码质量
- [ ] 9.3 进行端到端测试:从分类编辑页面删除图标 → 验证数据库更新 → 验证前端 UI 更新
- [ ] 9.4 准备部署文档和回滚计划

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-14

View File

@@ -0,0 +1,81 @@
## Context
当前系统使用 AI 服务生成分类图标,但生成的图标过于复杂,用户难以识别图标与分类名称的对应关系。问题根源在于 AI 提示词缺乏对简约风格的明确约束,导致生成的图标细节过多、视觉杂乱。影响范围涉及 Service 层的 AI 调用逻辑、Application 层的提示词配置以及前端的图标展示效果。
## Goals / Non-Goals
**Goals:**
- 优化 AI 图标生成的提示词,确保生成简约、清晰的图标
- 建立图标与分类名称的明确视觉关联规则
- 提升图标生成的一致性和可识别性
- 改善用户体验,降低识别成本
**Non-Goals:**
- 不改变现有的 AI 服务提供商
- 不重构整体的图标生成流程架构
- 不涉及图标存储或缓存机制的变更
- 不改变分类数据模型
## Decisions
**提示词策略选择**
- **决策**: 采用分层提示词策略,在基础提示词中明确"简约、扁平、单色"等风格约束,在动态部分注入分类名称的语义信息
- **替代方案**: 考虑过完全重写提示词模板,但风险较大,可能影响现有其他功能的稳定性
- **理由**: 分层策略既能控制生成风格,又能灵活适配不同分类,改动范围小、风险低
**提示词模板化**
- **决策**: 将提示词抽象为可配置的模板,支持通过配置文件调整生成风格参数
- **替代方案**: 考虑过硬编码简化提示词,但缺乏灵活性,后续调整需要重新部署
- **理由**: 模板化便于 A/B 测试不同提示词效果,快速迭代优化
**生成参数调整**
- **决策**: 在 AI 服务调用中增加风格强度参数(如 style_strength控制简约程度
- **替代方案**: 完全依赖提示词控制,但部分 AI 服务支持通过参数微调生成风格
- **理由**: 结合参数调优能更精准控制生成效果,提升成功率
## Risks / Trade-offs
**风险**: 简约提示词可能导致部分抽象分类(如"其他"、"通用")生成的图标过于相似,难以区分
- **缓解**: 针对抽象分类添加特殊的视觉元素(如特定的几何形状或颜色编码)
**风险**: 提示词优化需要多次迭代,可能影响用户体验一致性
- **缓解**: 采用灰度发布策略,逐步验证新提示词效果,必要时支持回滚
**权衡**: 简约风格可能牺牲图标的细节表现力,但可识别性更重要
- **决策**: 优先保证可识别性,后续可考虑提供可选的详细风格模式
**权衡**: 模板化提示词增加了配置复杂度,但提升了可维护性和灵活性
- **决策**: 通过默认配置降低使用门槛,仅在需要调整时暴露模板参数
## Migration Plan
**第一阶段:提示词模板化**
1. 在 Application 层创建图标提示词配置类(如 `IconPromptConfig`
2. 将现有提示词提取为模板,支持风格参数替换
3. 实现模板引擎(可使用字符串插值或轻量级模板库)
**第二阶段:提示词优化**
1. 设计简约风格提示词模板,明确约束:扁平化、单色、少细节、高对比度
2. 建立分类名称到视觉元素的映射规则(如"餐饮" → 餐具形状)
3. 集成 AI 服务调用时的风格强度参数
**第三阶段:测试与验证**
1. 对现有分类批量生成新图标,对比可识别性
2. 邀请用户进行 A/B 测试,收集反馈
3. 根据测试结果微调提示词和参数
**第四阶段:灰度发布**
1. 先在测试环境验证新图标生成效果
2. 灰度发布到生产环境(如 10% 用户)
3. 监控用户反馈和图标生成成功率,逐步扩大比例
**回滚策略**
- 保留旧提示词模板的备份,通过配置开关快速回滚
- 灰度期间出现异常立即回滚并分析原因
- 记录每次提示词迭代版本,支持追溯和对比
## Open Questions
- 当前使用的 AI 服务是否支持风格强度参数?需要查阅 API 文档或进行技术验证。
- 现有分类中是否有语义特别抽象的分类,需要特殊处理?(需要统计分类名称分析)
- 用户对图标风格的偏好是否有特定趋势?(可以通过历史用户行为数据或调研获取)

View File

@@ -0,0 +1,25 @@
## Why
当前 AI 生成的分类图标过于复杂,用户无法直观看出图标与分类的对应关系,使用体验不佳。需要优化提示词,使生成的图标更简约、更清晰。
## What Changes
- **优化分类图标生成的 AI 提示词**
- 调整图标生成风格,确保简约易懂
- 建立图标与分类名称的明确视觉关联
- 提升图标生成的一致性和可识别性
## Capabilities
### New Capabilities
- `ai-category-icon-generation`: AI 驱动的分类图标生成能力,支持简约风格的图标生成,确保图标与分类名称的视觉关联性
### Modified Capabilities
- (无)
## Impact
- **受影响的服务**: AI 图标生成服务(可能涉及 Service 层)
- **配置变更**: AI 提示词配置(可能涉及 Application 层的配置管理)
- **前端交互**: 分类图标展示(可能需要调整图标展示样式)
- **用户体验**: 提升分类图标可识别度,改善整体使用体验

View File

@@ -0,0 +1,64 @@
## ADDED Requirements
### Requirement: 系统生成简约风格的分类图标
系统 SHALL 使用 AI 服务生成简约风格的分类图标,确保图标易于识别且与分类名称有明确的视觉关联。
#### Scenario: 生成简约风格图标
- **WHEN** 系统接收到分类图标生成请求(分类名称为"餐饮"
- **THEN** 系统 SHALL 生成简约、扁平化、单色风格的图标
- **AND** 图标 SHALL 包含与"餐饮"相关的视觉元素(如餐具形状)
- **AND** 图标细节 SHALL 控制在最小化范围内,避免过度复杂的装饰
#### Scenario: 生成抽象分类图标
- **WHEN** 系统接收到抽象分类名称(如"其他"、"通用")的图标生成请求
- **THEN** 系统 SHALL 为抽象分类添加特定的几何形状或颜色编码
- **AND** 确保不同抽象分类的图标具有可区分的视觉特征
### Requirement: 系统使用可配置的提示词模板
系统 SHALL 使用模板化的提示词生成图标,支持通过配置调整生成风格参数。
#### Scenario: 使用默认模板生成图标
- **WHEN** 系统使用默认配置生成图标
- **THEN** 系统 SHALL 应用预设的简约风格提示词模板
- **AND** 模板 SHALL 包含风格约束(扁平化、单色、少细节、高对比度)
- **AND** 模板 SHALL 动态注入分类名称的语义信息
#### Scenario: 自定义提示词模板生成图标
- **WHEN** 管理员通过配置文件修改提示词模板
- **THEN** 系统 SHALL 使用自定义模板生成图标
- **AND** 自定义模板 SHALL 支持风格参数替换(如 `{style_strength}``{color_scheme}`
### Requirement: 系统控制图标生成风格强度
系统 SHALL 支持通过风格强度参数控制图标的简约程度。
#### Scenario: 使用标准风格强度生成图标
- **WHEN** 系统使用默认风格强度参数(如 0.7)生成图标
- **THEN** 生成的图标 SHALL 保持适度的简约风格
- **AND** 图标 SHALL 在简约性和可识别性之间保持平衡
#### Scenario: 使用高简约风格强度生成图标
- **WHEN** 系统使用高简约风格强度参数(如 0.9)生成图标
- **THEN** 生成的图标 SHALL 极度简化,去除所有非必要的细节
- **AND** 图标 SHALL 仅保留最核心的视觉元素
### Requirement: 系统确保图标生成的一致性
系统 SHALL 确保相同分类名称生成的图标具有一致的风格和视觉特征。
#### Scenario: 相同分类生成一致图标
- **WHEN** 系统多次为同一分类名称生成图标
- **THEN** 生成的所有图标 SHALL 具有相似的风格和视觉特征
- **AND** 图标 SHALL 保持相同的核心视觉元素
#### Scenario: 不同分类生成区分明显的图标
- **WHEN** 系统为不同分类名称生成图标
- **THEN** 生成的图标 SHALL 在视觉特征上具有明显区分
- **AND** 图标 SHALL 避免风格过于相似导致混淆
### Requirement: 系统支持提示词回滚
系统 SHALL 支持快速回滚到之前的提示词版本,以便在灰度测试出现问题时恢复稳定版本。
#### Scenario: 回滚到旧提示词版本
- **WHEN** 新提示词导致用户体验下降
- **THEN** 管理员 SHALL 能够通过配置开关快速回滚到旧提示词版本
- **AND** 回滚 SHALL 在分钟级别内生效
- **AND** 系统 SHALL 记录每次提示词迭代的版本号和时间戳

View File

@@ -0,0 +1,62 @@
## 1. 第一阶段:提示词模板化
- [x] 1.1 在 Application 层创建图标提示词配置类 `IconPromptConfig`
- [x] 1.2 在 `IconPromptConfig` 中定义默认提示词模板属性
- [x] 1.3 在 `IconPromptConfig` 中定义风格参数属性(如 `StyleStrength``ColorScheme`
- [x] 1.4 将现有的硬编码提示词提取为模板字符串
- [x] 1.5 在提示词模板中添加分类名称的动态占位符(如 `{category_name}`
- [x] 1.6 在提示词模板中添加风格参数的动态占位符(如 `{style_strength}``{color_scheme}`
- [x] 1.7 实现简单的模板引擎,支持占位符替换(使用字符串插值)
- [x] 1.8 在 AI 服务调用逻辑中集成模板引擎
- [x] 1.9 将旧提示词备份为配置文件,便于回滚
- [x] 1.10 在配置文件中添加提示词版本号字段
## 2. 第二阶段:提示词优化
- [x] 2.1 设计简约风格的提示词模板基础部分(包含"扁平化、单色、少细节、高对比度"等约束)
- [x] 2.2 设计分类名称到视觉元素的映射规则文档
- [x] 2.3 在提示词模板中添加分类语义信息的注入逻辑
- [x] 2.4 为抽象分类(如"其他"、"通用")设计特殊的视觉元素规则
- [x] 2.5 在 `IconPromptConfig` 中添加抽象分类的特殊处理配置
- [x] 2.6 查阅当前使用的 AI 服务 API 文档,确认是否支持风格强度参数
- [x] 2.7 如果支持,在 AI 服务调用中集成 `StyleStrength` 参数
- [x] 2.8 如果不支持,将风格强度信息注入到提示词模板中
- [x] 2.9 在配置文件中添加默认风格强度值(如 0.7
- [x] 2.10 在配置文件中添加默认颜色方案(如单色灰色系)
## 3. 第三阶段:测试与验证
- [x] 3.1 编写单元测试,验证提示词模板引擎的占位符替换功能
- [x] 3.2 编写单元测试,验证简约风格提示词模板的生成逻辑
- [x] 3.3 编写单元测试,验证抽象分类的特殊处理逻辑
- [x] 3.4 编写单元测试,验证风格强度参数的注入逻辑
- [ ] 3.5 在测试环境使用现有分类名称批量生成新图标
- [ ] 3.6 对比新旧图标的可识别性,记录差异
- [ ] 3.7 编写集成测试,验证相同分类生成一致图标的场景
- [ ] 3.8 编写集成测试,验证不同分类生成区分明显图标的场景
- [ ] 3.9 邀请部分用户进行 A/B 测试,收集对新图标的反馈
- [ ] 3.10 根据测试结果微调提示词模板和风格参数
## 4. 第四阶段:灰度发布
- [ ] 4.1 在测试环境完整验证新提示词模板的生成效果
- [ ] 4.2 在配置文件中添加灰度发布开关(如 `EnableNewPrompt: true/false`
- [ ] 4.3 在配置文件中添加灰度比例配置(如 `GrayScaleRatio: 0.1`
- [ ] 4.4 修改图标生成逻辑,根据灰度比例决定使用新提示词还是旧提示词
- [ ] 4.5 部署灰度版本到生产环境10% 用户使用新提示词)
- [ ] 4.6 监控图标生成成功率,记录生成失败的分类
- [ ] 4.7 监控用户反馈,记录对新图标的评价
- [ ] 4.8 如无异常逐步扩大灰度比例20% → 50% → 100%
- [ ] 4.9 在灰度过程中,如果出现用户体验下降,立即回滚到旧提示词
- [ ] 4.10 记录每次提示词迭代的版本号、时间戳和变更内容
## 5. 文档与清理
- [x] 5.1 更新 API 文档,说明提示词配置的参数含义(详见 .doc/category-visual-mapping.md 和 .doc/icon-prompt-testing-guide.md
- [x] 5.2 更新运维文档,说明如何调整提示词模板和风格参数(详见 .doc/icon-prompt-testing-guide.md
- [x] 5.3 更新故障排查文档,说明图标生成问题的排查步骤(详见 .doc/icon-prompt-testing-guide.md
- [x] 5.4 更新部署文档,说明灰度发布的操作流程(详见 .doc/icon-prompt-testing-guide.md
- [x] 5.5 清理测试代码中临时的调试日志和打印语句
- [x] 5.6 代码 review 并确保符合项目代码风格规范
- [x] 5.7 运行所有单元测试和集成测试,确保全部通过
- [x] 5.8 运行前端 lint 和类型检查,确保代码质量