fix
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 20s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 20s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
This commit is contained in:
@@ -32,120 +32,60 @@ metadata:
|
|||||||
|
|
||||||
### 1. 现代移动端优先设计
|
### 1. 现代移动端优先设计
|
||||||
|
|
||||||
**布局标准:**
|
**核心规范:**
|
||||||
- 移动视口: 375px 宽度 (iPhone SE 基准)
|
- 移动视口: 375px 宽度 (iPhone SE 基准)
|
||||||
- 安全区域: 尊重 iOS/Android 安全区域边距
|
- 安全区域: 尊重 iOS/Android 安全区域边距
|
||||||
- 触摸目标: 交互元素最小 44x44px
|
- 交互元素最小触摸目标: 44x44px
|
||||||
- 间距比例: 4px, 8px, 12px, 16px, 24px, 32px (8px 基础网格)
|
- 间距基于 8px 网格: 4px, 8px, 12px, 16px, 24px, 32px
|
||||||
- 圆角半径: 12px (卡片), 16px (对话框), 24px (药丸/标签), 8px (按钮)
|
- 卡片阴影: `0 2px 12px rgba(0,0,0,0.08)` (亮色模式)
|
||||||
- 卡片阴影: `0 2px 12px rgba(0,0,0,0.08)` 用于突出表面
|
|
||||||
|
|
||||||
**避免 AI 设计痕迹:**
|
**反 AI 设计痕迹检查清单:**
|
||||||
- 不要使用通用的 "Dashboard" 占位符文本
|
- ❌ 使用 "Dashboard", "Lorem Ipsum" 等通用占位符
|
||||||
- 不要使用图库照片或 Lorem Ipsum
|
- ❌ 使用过饱和的颜色或生硬的渐变
|
||||||
- 不要使用过饱和的主色 (#007AFF, 不是 #0088FF)
|
- ❌ 使用装饰性字体 (Comic Sans, Papyrus)
|
||||||
- 不要使用生硬的阴影或渐变
|
- ✅ 使用代码库中的真实中文业务术语
|
||||||
- 不要使用 Comic Sans, Papyrus 或装饰性字体
|
- ✅ 使用克制的配色和柔和的阴影
|
||||||
- 使用代码库中的真实中文业务术语
|
- ✅ 使用专业的系统字体
|
||||||
|
|
||||||
### 2. 统一色彩系统 (基于实际 v2.pen 日历设计)
|
### 2. 统一色彩系统
|
||||||
|
|
||||||
**亮色主题:**
|
**色彩分层:**
|
||||||
```css
|
- **背景层**: 页面背景 → 卡片背景 → 强调背景 (三层递进)
|
||||||
/* 背景色 - 基于实际设计 */
|
- **文本层**: 主文本 → 次要文本 → 三级文本 (三级层次)
|
||||||
--background-page: #FFFFFF /* 页面背景 (Calendar frame fill) */
|
- **语义色**: 红色(支出/危险) → 黄色(警告) → 绿色(收入/成功) → 蓝色(主操作/信息)
|
||||||
--background-card: #F6F7F8 /* 卡片背景 (statsCard, tCard fills) */
|
|
||||||
--background-accent: #F5F5F5 /* 强调背景 (notif button) */
|
|
||||||
|
|
||||||
/* 文本色 - 基于实际设计 */
|
|
||||||
--text-primary: #1A1A1A /* 主文本 (titles, labels) */
|
|
||||||
--text-secondary: #6B7280 /* 次要文本 (dates, subtitles) */
|
|
||||||
--text-tertiary: #9CA3AF /* 三级文本 (weekday labels) */
|
|
||||||
|
|
||||||
/* 语义色 - 基于实际设计 */
|
|
||||||
--accent-red: #FF6B6B /* 支出/负数 (expense icon) */
|
|
||||||
--accent-yellow: #FCD34D /* 警告/中性 (coffee icon) */
|
|
||||||
--accent-green: #F0FDF4 /* 收入/正数 (badge background) */
|
|
||||||
--accent-blue: #E0E7FF /* 智能标签 (smart button) */
|
|
||||||
--accent-warm: #FFFBEB /* 温暖色调 (badge background) */
|
|
||||||
|
|
||||||
/* 主操作色 */
|
|
||||||
--primary: #3B82F6 /* 主色调 (FAB button from Budget Stats) */
|
|
||||||
|
|
||||||
/* 边框与分割线 */
|
|
||||||
--border: #E5E7EB /* 边框颜色 (从设计推断) */
|
|
||||||
```
|
|
||||||
|
|
||||||
**暗色主题:**
|
|
||||||
```css
|
|
||||||
/* 背景色 - 基于实际暗色设计 */
|
|
||||||
--background-page: #09090B /* 页面背景 (Calendar Dark frame) */
|
|
||||||
--background-card: #18181B /* 卡片背景 (dark statsCard, tCard) */
|
|
||||||
--background-accent: #27272A /* 强调背景 (dark notif, tCat) */
|
|
||||||
|
|
||||||
/* 文本色 - 基于实际暗色设计 */
|
|
||||||
--text-primary: #F4F4F5 /* 主文本 (dark titles) */
|
|
||||||
--text-secondary: #A1A1AA /* 次要文本 (dark dates, subtitles) */
|
|
||||||
--text-tertiary: #71717A /* 三级文本 (dark weekday labels) */
|
|
||||||
|
|
||||||
/* 语义色 - 暗色模式适配 */
|
|
||||||
--accent-red: #FF6B6B /* 保持一致 */
|
|
||||||
--accent-yellow: #FCD34D /* 保持一致 */
|
|
||||||
--accent-green: #064E3B /* 深绿 (dark badge) */
|
|
||||||
--accent-blue: #312E81 /* 深蓝 (dark smart button) */
|
|
||||||
--accent-warm: #451A03 /* 深暖色 (dark badge) */
|
|
||||||
|
|
||||||
/* 主操作色 */
|
|
||||||
--primary: #3B82F6 /* 保持一致 */
|
|
||||||
|
|
||||||
/* 边框与分割线 */
|
|
||||||
--border: #3F3F46 /* 深色边框 */
|
|
||||||
```
|
|
||||||
|
|
||||||
**颜色使用规则:**
|
**颜色使用规则:**
|
||||||
- **页面背景**: 亮色 `#FFFFFF`, 暗色 `#09090B`
|
- 始终使用语义颜色变量,避免硬编码十六进制值
|
||||||
- **卡片背景**: 亮色 `#F6F7F8`, 暗色 `#18181B`
|
- 支出/负数统一使用红色 `#FF6B6B`,收入/正数使用绿色系
|
||||||
- **主文本**: 亮色 `#1A1A1A`, 暗色 `#F4F4F5`
|
- 主操作按钮统一使用蓝色 `#3B82F6`
|
||||||
- **次要文本**: 亮色 `#6B7280`, 暗色 `#A1A1AA`
|
- 避免纯黑 (#000000) 或纯白 (#FFFFFF) 文本,使用柔和的色调
|
||||||
- **支出/负数**: `#FF6B6B` (两种模式一致)
|
- 暗色模式下减少阴影强度或完全移除
|
||||||
- **主操作按钮**: `#3B82F6` (两种模式一致)
|
- 详细色值参见文末"快速参考"表格
|
||||||
- **圆角**: 12px (小按钮), 16px (卡片), 20px (统计卡片), 22px (图标按钮)
|
|
||||||
- **阴影**: 亮色使用柔和阴影, 暗色使用更深的阴影或无阴影
|
|
||||||
- **避免**: 纯黑 (#000000) 或纯白 (#FFFFFF) 文本
|
|
||||||
|
|
||||||
### 3. 排版系统 (基于实际 v2.pen 设计)
|
### 3. 排版系统
|
||||||
|
|
||||||
**字体栈:**
|
**字体栈:**
|
||||||
```css
|
- **标题**: `'Bricolage Grotesque'` - 用于大数值、章节标题
|
||||||
/* 标题与大标题 - 基于 v2.pen */
|
- **正文**: `'DM Sans'` - 用于界面文本、说明
|
||||||
font-family: 'Bricolage Grotesque', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
- **数字**: `'DIN Alternate'` - 用于金额、数据显示
|
||||||
|
- **备选**: `-apple-system, 'PingFang SC'` - 系统默认字体
|
||||||
|
|
||||||
/* 正文与界面 - 基于 v2.pen */
|
**排版原则:**
|
||||||
font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
|
- 使用真实中文业务术语,避免 Lorem Ipsum
|
||||||
|
|
||||||
/* 备选: 系统默认 */
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', sans-serif;
|
|
||||||
```
|
|
||||||
|
|
||||||
**字号比例 (从实际设计提取):**
|
|
||||||
| 用途 | 字体 | 大小 | 粗细 | 示例 |
|
|
||||||
|------|------|------|------|------|
|
|
||||||
| 大标题数值 | Bricolage Grotesque | 32px | 800 | ¥ 1,248.50 (statsVal) |
|
|
||||||
| 页面标题 | DM Sans | 24px | 500 | 2026年1月 (subtitle) |
|
|
||||||
| 章节标题 | Bricolage Grotesque | 18px | 700 | 每日统计, 交易记录 (titles) |
|
|
||||||
| 正文文本 | DM Sans | 15px | 600 | Lunch, Coffee (交易名称) |
|
|
||||||
| 说明文字 | DM Sans | 13px | 500 | 12:30 PM, Total Spent (标签) |
|
|
||||||
| 微型文字 | DM Sans | 12px | 600 | 一二三四五六日 (星期) |
|
|
||||||
|
|
||||||
**中文文本规则:**
|
|
||||||
- 使用简体中文
|
|
||||||
- 真实业务术语: "每日统计" (daily stats), "交易记录" (transactions)
|
|
||||||
- 行高: 1.4-1.6 保证可读性
|
- 行高: 1.4-1.6 保证可读性
|
||||||
- 使用真实业务术语,避免 Lorem Ipsum
|
- 数字数据使用等宽字体 (tabular-nums)
|
||||||
|
- 字号遵循比例系统,避免任意数值
|
||||||
|
- 详细字号比例参见文末"快速参考"表格
|
||||||
|
|
||||||
### 4. 组件库 (基于实际 v2.pen 设计)
|
### 4. 组件库
|
||||||
|
|
||||||
**卡片 (基于 statsCard, tCard):**
|
**设计原则:**
|
||||||
|
- 所有尺寸和间距基于 8px 网格系统
|
||||||
|
- 圆角: 12px (小按钮), 16px/20px (卡片), 22px/28px (圆形按钮)
|
||||||
|
- 交互元素最小触摸目标: 44x44px
|
||||||
|
- 详细组件规格参见文末"快速参考"表格
|
||||||
|
|
||||||
|
**卡片设计 (基于 statsCard, tCard):**
|
||||||
```
|
```
|
||||||
统计卡片 (大卡片):
|
统计卡片 (大卡片):
|
||||||
- 背景: #F6F7F8 (亮色), #18181B (暗色)
|
- 背景: #F6F7F8 (亮色), #18181B (暗色)
|
||||||
@@ -207,23 +147,16 @@ font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB
|
|||||||
|
|
||||||
**布局模式 (基于 Calendar 结构):**
|
**布局模式 (基于 Calendar 结构):**
|
||||||
```
|
```
|
||||||
页面容器:
|
页面容器: 402px (设计视口), 垂直布局, 24px 内边距
|
||||||
- 宽度: 402px (设计视口)
|
头部区域: 水平布局, 两端对齐, 8px 24px 内边距
|
||||||
- 布局: 垂直
|
内容区域: 垂直布局, 24px 内边距, 12-16px 间距
|
||||||
- 内边距: 24px (容器边距)
|
|
||||||
- 间距: 16px (章节之间)
|
|
||||||
|
|
||||||
头部区域:
|
|
||||||
- 内边距: 8px 24px
|
|
||||||
- 布局: 水平, 两端对齐
|
|
||||||
- 对齐项: 居中
|
|
||||||
|
|
||||||
内容区域:
|
|
||||||
- 内边距: 24px
|
|
||||||
- 间距: 12-16px
|
|
||||||
- 布局: 垂直
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**关键布局原则:**
|
||||||
|
- 遵循 Flex 容器模式 (见下方"5. 布局模式")
|
||||||
|
- 导航栏背景必须透明 (`:deep(.van-nav-bar) { background: transparent !important; }`)
|
||||||
|
- 尊重安全区域 (`env(safe-area-inset-bottom)`)
|
||||||
|
|
||||||
### 5. 布局模式
|
### 5. 布局模式
|
||||||
|
|
||||||
**页面结构 (Flex 容器):**
|
**页面结构 (Flex 容器):**
|
||||||
@@ -241,17 +174,17 @@ font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB
|
|||||||
4. bottom-button 或 van-tabbar (固定)
|
4. bottom-button 或 van-tabbar (固定)
|
||||||
```
|
```
|
||||||
|
|
||||||
**导航栏背景透明化 (一致性模式):**
|
**导航栏背景透明化 (项目标准模式):**
|
||||||
```css
|
```css
|
||||||
/* 设置页面容器背景色 */
|
/* 所有页面统一设置 */
|
||||||
:deep(.van-nav-bar) {
|
:deep(.van-nav-bar) {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
**重要:** 项目中所有视图都采用此模式,使导航栏背景透明,与页面背景融合。实现此效果时,请确保:
|
**关键要求:**
|
||||||
- 页面容器有明确的背景色 (亮色: #FFFFFF, 暗色: #09090B)
|
- 页面容器必须有明确的背景色
|
||||||
- 导航栏始终使用 `:deep(.van-nav-bar)` 选择器
|
- 必须使用 `:deep()` 选择器覆盖 Vant 样式
|
||||||
- 必须添加 `!important` 覆盖 Vant 默认样式
|
- 必须添加 `!important` 标记
|
||||||
- 在 `<style scoped>` 块中添加此规则
|
- 在 `<style scoped>` 块中添加此规则
|
||||||
|
|
||||||
**安全区域处理:**
|
**安全区域处理:**
|
||||||
@@ -407,42 +340,23 @@ document.documentElement.setAttribute('data-theme', theme.value)
|
|||||||
- 示例: "Budget/ListView", "Budget/EditForm"
|
- 示例: "Budget/ListView", "Budget/EditForm"
|
||||||
```
|
```
|
||||||
|
|
||||||
**图层命名:**
|
|
||||||
```
|
|
||||||
内部元素可用中文:
|
|
||||||
✅ 预算卡片背景
|
|
||||||
✅ 金额文本
|
|
||||||
✅ 操作按钮组
|
|
||||||
|
|
||||||
组件用英文:
|
|
||||||
✅ CardBackground
|
|
||||||
✅ AmountLabel
|
|
||||||
✅ ActionButtons
|
|
||||||
```
|
|
||||||
|
|
||||||
### 10. 质量检查清单
|
### 10. 质量检查清单
|
||||||
|
|
||||||
**完成设计前:**
|
**设计完成前必检项:**
|
||||||
- [ ] 同时创建了亮色和暗色主题
|
- [ ] 同时创建亮色和暗色主题
|
||||||
- [ ] 所有文本使用真实中文业务术语 (无 Lorem Ipsum)
|
- [ ] 使用真实中文业务术语 (无占位文本)
|
||||||
- [ ] 交互元素 ≥ 44x44px
|
- [ ] 交互元素 ≥ 44x44px
|
||||||
- [ ] 间距遵循 8px 网格
|
- [ ] 间距遵循 8px 网格
|
||||||
- [ ] 颜色使用语义变量 (非硬编码十六进制)
|
- [ ] 使用语义颜色变量 (非硬编码)
|
||||||
- [ ] 圆角: 12px/16px/24px 保持一致
|
- [ ] 导航栏背景透明 (`:deep(.van-nav-bar)`)
|
||||||
- [ ] 尊重安全区域边距 (底部: 50px + 安全区域)
|
- [ ] 帧命名: 模块-屏幕-变体 格式
|
||||||
- [ ] 帧正确命名 模块/屏幕/变体
|
- [ ] 可复用组件标记 `reusable: true`
|
||||||
- [ ] 可复用组件标记为 `reusable: true`
|
- [ ] 两种主题截图验证
|
||||||
- [ ] 字号匹配字号比例 (12/14/16/18/24)
|
|
||||||
- [ ] 数字数据使用 DIN Alternate
|
|
||||||
- [ ] 无 AI 生成的占位内容
|
|
||||||
- [ ] 已截图并视觉验证
|
|
||||||
- [ ] 导航栏背景设置为透明 (`:deep(.van-nav-bar) { background: transparent !important; }`)
|
|
||||||
|
|
||||||
**无障碍:**
|
**无障碍标准:**
|
||||||
- [ ] 正文对比度 ≥ 4.5:1
|
- [ ] 正文对比度 ≥ 4.5:1
|
||||||
- [ ] 大文本对比度 ≥ 3:1 (18px+)
|
- [ ] 大文本对比度 ≥ 3:1 (18px+)
|
||||||
- [ ] 触摸目标清晰分离 (最小 8px 间距)
|
- [ ] 触摸目标间距 ≥ 8px
|
||||||
- [ ] 颜色不是信息的唯一指示器
|
|
||||||
|
|
||||||
## PANCLI 工作流程
|
## PANCLI 工作流程
|
||||||
|
|
||||||
@@ -804,9 +718,10 @@ delegate_task(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 快速参考 (基于实际 v2.pen 设计)
|
## 快速参考
|
||||||
|
|
||||||
|
**颜色面板 (基于实际 v2.pen 设计):**
|
||||||
|
|
||||||
**颜色面板:**
|
|
||||||
| 名称 | 亮色 | 暗色 | 用途 |
|
| 名称 | 亮色 | 暗色 | 用途 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| 页面背景 | #FFFFFF | #09090B | 页面背景 |
|
| 页面背景 | #FFFFFF | #09090B | 页面背景 |
|
||||||
@@ -821,7 +736,8 @@ delegate_task(
|
|||||||
| 绿色 | #F0FDF4 | #064E3B | 收入标签 |
|
| 绿色 | #F0FDF4 | #064E3B | 收入标签 |
|
||||||
| 蓝色 | #E0E7FF | #312E81 | 信息标签 |
|
| 蓝色 | #E0E7FF | #312E81 | 信息标签 |
|
||||||
|
|
||||||
**排版 (实际字体):**
|
**排版比例:**
|
||||||
|
|
||||||
| 用途 | 字体 | 大小 | 粗细 |
|
| 用途 | 字体 | 大小 | 粗细 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| 大数值 | Bricolage Grotesque | 32px | 800 |
|
| 大数值 | Bricolage Grotesque | 32px | 800 |
|
||||||
@@ -831,26 +747,19 @@ delegate_task(
|
|||||||
| 说明 | DM Sans | 13px | 500 |
|
| 说明 | DM Sans | 13px | 500 |
|
||||||
| 微型标签 | DM Sans | 12px | 600 |
|
| 微型标签 | DM Sans | 12px | 600 |
|
||||||
|
|
||||||
**间距与布局 (实际数值):**
|
**组件规格:**
|
||||||
- 容器内边距: 24px (主区域), 20px (卡片), 16px (小卡片)
|
|
||||||
- 间距比例: 2px, 4px, 8px, 12px, 14px, 16px
|
|
||||||
- 图标大小: 20px
|
|
||||||
- 图标按钮: 44x44px
|
|
||||||
- FAB 按钮: 56x56px
|
|
||||||
|
|
||||||
**圆角 (实际数值):**
|
- **容器内边距**: 24px (主区域), 20px (卡片), 16px (小卡片)
|
||||||
- 小按钮/标签: 12px
|
- **间距比例**: 2px, 4px, 8px, 12px, 14px, 16px
|
||||||
- 卡片: 16px, 20px
|
- **圆角**: 12px (标签), 16px/20px (卡片), 22px/28px (圆形按钮)
|
||||||
- 图标按钮: 22px (圆形)
|
- **图标**: 20px
|
||||||
- FAB: 28px (圆形)
|
- **图标按钮**: 44x44px
|
||||||
|
- **FAB 按钮**: 56x56px
|
||||||
**触摸目标:** 最小 44x44px
|
- **触摸目标**: 最小 44x44px
|
||||||
|
- **设计视口**: 402px 宽度
|
||||||
**视口:** 402px (设计宽度), 移动端优先
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**版本:** 2.0.0 (使用 v2.pen 实际设计值更新)
|
**版本:** 2.0.0
|
||||||
**最后更新:** 2026-02-03
|
**最后更新:** 2026-02-04
|
||||||
**来源:** .pans/v2.pen 日历 (亮色/暗色)
|
|
||||||
**维护者:** EmailBill 设计团队
|
**维护者:** EmailBill 设计团队
|
||||||
|
|||||||
44
.sisyphus/notepads/calendar-v2-data-loading-fix/decisions.md
Normal file
44
.sisyphus/notepads/calendar-v2-data-loading-fix/decisions.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Calendar V2 数据加载修复 - 决策记录
|
||||||
|
|
||||||
|
## 2026-02-04 修复决策
|
||||||
|
|
||||||
|
### 问题确认
|
||||||
|
用户报告:"日历v2中当前月份的日历矩阵中并没有加载当前月份的消费数据"
|
||||||
|
|
||||||
|
### 根因分析
|
||||||
|
1. `Web/src/views/calendarV2/modules/Calendar.vue` 的 `fetchAllRelevantMonthsData` 函数
|
||||||
|
2. 第 144 行在调用 API 时传递的 `month` 参数格式错误
|
||||||
|
3. JavaScript Date 的 month 是 0-11,但后端 API 期望 1-12
|
||||||
|
4. 上月和下月数据正常,因为代码中已有 `+1` 转换
|
||||||
|
|
||||||
|
### 修复方案
|
||||||
|
**选择:** 在第 144 行添加 `+1` 转换,与上月/下月处理保持一致
|
||||||
|
|
||||||
|
**理由:**
|
||||||
|
- 最小化修改范围(仅1行代码 + 1行注释)
|
||||||
|
- 保持代码一致性(三个月份处理逻辑统一)
|
||||||
|
- 不影响其他功能模块
|
||||||
|
- 符合现有的API约定
|
||||||
|
|
||||||
|
**拒绝的方案:**
|
||||||
|
- ❌ 修改后端 API 接受 0-11 格式 - 会破坏现有其他调用方
|
||||||
|
- ❌ 修改 `fetchDailyStats` 函数内部转换 - 会影响所有调用处
|
||||||
|
- ❌ 使用 watch 监听并重新加载 - 增加不必要的复杂度
|
||||||
|
|
||||||
|
### 代码变更
|
||||||
|
```diff
|
||||||
|
- const promises = [fetchDailyStats(year, month)]
|
||||||
|
+ // JavaScript Date.month 是 0-11,但后端 API 期望 1-12
|
||||||
|
+ const promises = [fetchDailyStats(year, month + 1)]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 验证结果
|
||||||
|
✅ 代码审查通过
|
||||||
|
✅ ESLint 检查通过(0 errors)
|
||||||
|
✅ 逻辑一致性确认(当前月、上月、下月都使用 +1)
|
||||||
|
|
||||||
|
### 影响范围
|
||||||
|
- **修改文件:** 仅 `Web/src/views/calendarV2/modules/Calendar.vue`
|
||||||
|
- **影响功能:** 日历v2 当前月份数据加载
|
||||||
|
- **用户可见变化:** 当前月份的日期单元格将正确显示消费金额
|
||||||
|
- **副作用:** 无
|
||||||
165
.sisyphus/notepads/calendar-v2-data-loading-fix/learnings.md
Normal file
165
.sisyphus/notepads/calendar-v2-data-loading-fix/learnings.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# Calendar V2 数据加载修复 - 学习笔记
|
||||||
|
|
||||||
|
## 2026-02-04 初始分析
|
||||||
|
|
||||||
|
### 问题根因
|
||||||
|
- `Web/src/views/calendarV2/modules/Calendar.vue` 第 144 行
|
||||||
|
- `fetchAllRelevantMonthsData` 函数在加载当前月数据时,传递的 `month` 参数是 JavaScript Date 的月份(0-11)
|
||||||
|
- 但后端 API `GetDailyStatistics` 期望的是 1-12 格式
|
||||||
|
- 上月和下月数据加载正确,因为代码中有 `prevMonth + 1` 和 `nextMonth + 1`
|
||||||
|
- **当前月数据加载失败,导致日历矩阵中没有当前月的消费数据**
|
||||||
|
|
||||||
|
### API 约定
|
||||||
|
- 后端 API: `WebApi/Controllers/TransactionRecordController.cs` 的 `GetDailyStatisticsAsync`
|
||||||
|
- 参数格式: `year` (完整年份), `month` (1-12)
|
||||||
|
- 前端 API: `Web/src/api/statistics.js` 的 `getDailyStatistics`
|
||||||
|
|
||||||
|
### 相关代码位置
|
||||||
|
- 问题文件: `Web/src/views/calendarV2/modules/Calendar.vue`
|
||||||
|
- 问题函数: `fetchAllRelevantMonthsData` (第 120-164 行)
|
||||||
|
- 问题行: 第 144 行 `const promises = [fetchDailyStats(year, month)]`
|
||||||
|
- 正确格式应该是: `const promises = [fetchDailyStats(year, month + 1)]`
|
||||||
|
|
||||||
|
|
||||||
|
## 2026-02-04 修复完成
|
||||||
|
|
||||||
|
### 修改内容
|
||||||
|
- 文件: `Web/src/views/calendarV2/modules/Calendar.vue`
|
||||||
|
- 行号: 第 144 行
|
||||||
|
- 修改前: `const promises = [fetchDailyStats(year, month)]`
|
||||||
|
- 修改后: `const promises = [fetchDailyStats(year, month + 1)]`
|
||||||
|
- 新增注释: "// JavaScript Date.month 是 0-11,但后端 API 期望 1-12"
|
||||||
|
|
||||||
|
### 验证结果
|
||||||
|
- ✅ 代码风格检查通过 (`pnpm lint`)
|
||||||
|
- ✅ 仅有项目已存在的 40 个警告,无新增错误
|
||||||
|
- ✅ 上月和下月加载逻辑保持不变(第 149 和 155 行已正确)
|
||||||
|
- ✅ 与上月、下月的处理方式保持一致
|
||||||
|
|
||||||
|
### 修复逻辑验证
|
||||||
|
- 当前月: `month + 1` (例如: JavaScript 1 月 → API 2 月)
|
||||||
|
- 上个月: `prevMonth + 1` (已有逻辑,正确)
|
||||||
|
- 下个月: `nextMonth + 1` (已有逻辑,正确)
|
||||||
|
- 三者逻辑统一,符合后端 API 约定
|
||||||
|
|
||||||
|
### 后续建议
|
||||||
|
- 前端测试: 切换到不同月份,确认日历矩阵中的消费数据正确显示
|
||||||
|
- 边界测试: 特别测试 1 月(跨年上月)和 12 月(跨年下月)的数据加载
|
||||||
|
|
||||||
|
|
||||||
|
## 2026-02-04 浏览器验证测试
|
||||||
|
|
||||||
|
### 测试环境
|
||||||
|
- Vue Dev Server: http://localhost:5175 (运行中)
|
||||||
|
- 测试工具: 由于 Playwright chrome 安装超时,采用手动浏览器测试
|
||||||
|
|
||||||
|
### 手动测试步骤
|
||||||
|
1. 打开浏览器访问 http://localhost:5175
|
||||||
|
2. 导航到日历 v2 页面(路径: /calendar 或 /calendarV2)
|
||||||
|
3. 检查当前月份(2026年2月)的日期单元格
|
||||||
|
4. 验证有消费记录的日期是否显示金额
|
||||||
|
5. 切换到其他月份,验证数据加载是否正常
|
||||||
|
|
||||||
|
### 预期结果
|
||||||
|
- **修复前**: 当前月份(2月)的日历单元格不显示消费金额,因为传递了错误的月份参数(2 而非 3)
|
||||||
|
- **修复后**: 当前月份的日历单元格应正确显示消费金额,因为现在传递正确的参数(month + 1)
|
||||||
|
|
||||||
|
### 技术备注
|
||||||
|
- Playwright MCP 在 Windows 环境下 chrome 安装需要较长时间
|
||||||
|
- 建议使用已安装的浏览器进行手动验证
|
||||||
|
- 修复的核心逻辑已通过代码审查和 lint 检查确认正确
|
||||||
|
|
||||||
|
### 验证要点
|
||||||
|
✅ 第 144 行已修改为 `month + 1`
|
||||||
|
✅ 与第 149、155 行的 prevMonth+1 和 nextMonth+1 逻辑一致
|
||||||
|
✅ 符合后端 API 的 1-12 月份格式要求
|
||||||
|
✅ 代码注释已添加,说明转换原因
|
||||||
|
|
||||||
|
|
||||||
|
### 手动验证清单
|
||||||
|
|
||||||
|
请在浏览器中完成以下验证:
|
||||||
|
|
||||||
|
- [ ] 访问 http://localhost:5175 确认应用正常启动
|
||||||
|
- [ ] 定位日历 v2 页面入口(可能在导航栏或底部 Tab)
|
||||||
|
- [ ] 进入日历页面后,观察当前月份(2026年2月)的日期单元格
|
||||||
|
- [ ] 确认有消费记录的日期在单元格底部显示金额(非零、非空)
|
||||||
|
- [ ] 切换到上一个月(1月),验证数据显示正常
|
||||||
|
- [ ] 切换到下一个月(3月),验证数据显示正常
|
||||||
|
- [ ] 检查控制台是否有 API 错误(按 F12 查看 Console 和 Network 标签)
|
||||||
|
- [ ] 确认 API 请求的 month 参数为 1-12 格式(Network 标签中查看 `GetDailyStatistics` 请求)
|
||||||
|
|
||||||
|
### 成功标准
|
||||||
|
1. 当前月份日历单元格显示消费金额
|
||||||
|
2. 无 API 请求失败或参数错误
|
||||||
|
3. 上月/下月数据加载正常
|
||||||
|
4. month 参数在 Network 请求中为正确的 1-12 格式
|
||||||
|
|
||||||
|
|
||||||
|
## 验证状态总结
|
||||||
|
|
||||||
|
### 自动化测试状态
|
||||||
|
❌ Playwright 浏览器自动化测试失败
|
||||||
|
- 原因: Chrome 安装失败(可能是网络或权限问题)
|
||||||
|
- 错误信息: "Failed to install chrome"
|
||||||
|
|
||||||
|
### 代码验证状态
|
||||||
|
✅ 代码修复已完成并验证
|
||||||
|
- 修改位置: `Web/src/views/calendarV2/modules/Calendar.vue` 第 145 行
|
||||||
|
- 修改内容: `month` → `month + 1`
|
||||||
|
- Lint 检查: 通过(无新增错误)
|
||||||
|
- 逻辑审查: 与上月/下月处理一致
|
||||||
|
|
||||||
|
### 下一步操作
|
||||||
|
由于自动化测试环境问题,建议进行以下操作之一:
|
||||||
|
1. **手动浏览器测试**: 按照上述清单在实际浏览器中验证
|
||||||
|
2. **开发环境测试**: 在开发机器上运行 dev server 并手动测试
|
||||||
|
3. **使用已安装的浏览器**: 如果系统有 Chrome/Edge/Firefox,直接访问 http://localhost:5175
|
||||||
|
|
||||||
|
### 修复信心评估
|
||||||
|
✅ 高信心 - 基于以下原因:
|
||||||
|
1. 问题根因明确:月份参数格式不匹配
|
||||||
|
2. 修复逻辑简单:添加 +1 转换
|
||||||
|
3. 与现有代码一致:上月和下月已使用相同模式
|
||||||
|
4. 代码审查通过:符合项目规范
|
||||||
|
5. API 约定清晰:后端期望 1-12 格式
|
||||||
|
|
||||||
|
|
||||||
|
## 代码修复最终确认
|
||||||
|
|
||||||
|
### 修改已应用
|
||||||
|
文件: `Web/src/views/calendarV2/modules/Calendar.vue`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 第 144-145 行(已修复)
|
||||||
|
// JavaScript Date.month 是 0-11,但后端 API 期望 1-12
|
||||||
|
const promises = [fetchDailyStats(year, month + 1)]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 逻辑一致性验证
|
||||||
|
三个月份加载逻辑统一:
|
||||||
|
- 当前月: `month + 1` ✅ (第 145 行)
|
||||||
|
- 上个月: `prevMonth + 1` ✅ (第 150 行)
|
||||||
|
- 下个月: `nextMonth + 1` ✅ (第 156 行)
|
||||||
|
|
||||||
|
### 修复影响范围
|
||||||
|
- 仅影响当前月份的数据加载
|
||||||
|
- 不影响上月和下月数据(已正确)
|
||||||
|
- 不影响其他视图或组件
|
||||||
|
|
||||||
|
### 浏览器验证限制
|
||||||
|
由于 Playwright Chrome 安装失败,无法完成自动化截图验证。
|
||||||
|
但代码逻辑已通过以下方式确认:
|
||||||
|
1. ✅ 代码审查:修改符合预期
|
||||||
|
2. ✅ Lint 检查:无新增错误
|
||||||
|
3. ✅ 逻辑分析:与已有正确代码保持一致
|
||||||
|
4. ✅ API 约定:符合后端期望格式
|
||||||
|
|
||||||
|
### 建议的验证方式
|
||||||
|
在有浏览器环境的开发机器上:
|
||||||
|
1. 启动 dev server: `cd Web && pnpm dev`
|
||||||
|
2. 打开浏览器访问应用
|
||||||
|
3. 进入日历 v2 页面
|
||||||
|
4. 检查当前月份(2026年2月)的日期单元格是否显示消费金额
|
||||||
|
5. 打开开发者工具检查 Network 请求,确认 month 参数为 2(而非 1)
|
||||||
|
|
||||||
@@ -33,7 +33,10 @@
|
|||||||
¥ {{ formatAmount(parseFloat(editForm.amount) || 0) }}
|
¥ {{ formatAmount(parseFloat(editForm.amount) || 0) }}
|
||||||
</div>
|
</div>
|
||||||
<!-- 编辑模式 -->
|
<!-- 编辑模式 -->
|
||||||
<div v-else class="amount-input-wrapper">
|
<div
|
||||||
|
v-else
|
||||||
|
class="amount-input-wrapper"
|
||||||
|
>
|
||||||
<span class="currency-symbol">¥</span>
|
<span class="currency-symbol">¥</span>
|
||||||
<input
|
<input
|
||||||
ref="amountInputRef"
|
ref="amountInputRef"
|
||||||
|
|||||||
@@ -301,7 +301,6 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
/* ========== 页面容器 ========== */
|
/* ========== 页面容器 ========== */
|
||||||
.calendar-v2-wrapper {
|
.calendar-v2-wrapper {
|
||||||
background-color: var(--bg-primary);
|
|
||||||
font-family: var(--font-primary);
|
font-family: var(--font-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,8 @@ const fetchAllRelevantMonthsData = async (year, month) => {
|
|||||||
const needNextMonth = totalCells > (startDayOfWeek + lastDay.getDate())
|
const needNextMonth = totalCells > (startDayOfWeek + lastDay.getDate())
|
||||||
|
|
||||||
// 并行加载所有需要的月份数据
|
// 并行加载所有需要的月份数据
|
||||||
const promises = [fetchDailyStats(year, month)]
|
// JavaScript Date.month 是 0-11,但后端 API 期望 1-12
|
||||||
|
const promises = [fetchDailyStats(year, month + 1)]
|
||||||
|
|
||||||
if (needPrevMonth) {
|
if (needPrevMonth) {
|
||||||
const prevMonth = month === 0 ? 11 : month - 1
|
const prevMonth = month === 0 ? 11 : month - 1
|
||||||
|
|||||||
Reference in New Issue
Block a user