diff --git a/.opencode/skills/pancli-design/SKILL.md b/.opencode/skills/pancli-design/SKILL.md
new file mode 100644
index 0000000..c76ed4f
--- /dev/null
+++ b/.opencode/skills/pancli-design/SKILL.md
@@ -0,0 +1,856 @@
+---
+name: pancli-design
+description: 专业的设计技能,用于使用 pancli (pencil tools) 创建现代化、一致的 EmailBill 移动端 UI 设计
+license: MIT
+compatibility: Requires pencil_* tools (batch_design, batch_get, etc.)
+metadata:
+ author: EmailBill Design Team
+ version: "2.0.0"
+ generatedBy: opencode
+ lastUpdated: "2026-02-03"
+ source: ".pans/v2.pen 日历设计 (亮色/暗色)"
+---
+
+# pancli-design - EmailBill UI 设计系统
+
+> 专业的设计技能,用于使用 pancli (pencil tools) 创建现代化、一致的移动端 UI 设计。
+
+## 何时使用此技能
+
+**总是使用此技能当:**
+- 使用 pancli 创建新的 UI 界面或组件
+- 修改现有的 .pen 设计文件
+- 处理亮色/暗色主题设计
+- 为 EmailBill 项目设计移动端优先的界面
+
+**触发条件:**
+- 用户提到 "画设计图"、"设计"、"UI"、"界面"、"pancli"、".pen"
+- 任务涉及 `pencil_*` 工具
+- 创建视觉原型或模型
+
+## 核心设计原则
+
+### 1. 现代移动端优先设计
+
+**布局标准:**
+- 移动视口: 375px 宽度 (iPhone SE 基准)
+- 安全区域: 尊重 iOS/Android 安全区域边距
+- 触摸目标: 交互元素最小 44x44px
+- 间距比例: 4px, 8px, 12px, 16px, 24px, 32px (8px 基础网格)
+- 圆角半径: 12px (卡片), 16px (对话框), 24px (药丸/标签), 8px (按钮)
+- 卡片阴影: `0 2px 12px rgba(0,0,0,0.08)` 用于突出表面
+
+**避免 AI 设计痕迹:**
+- 不要使用通用的 "Dashboard" 占位符文本
+- 不要使用图库照片或 Lorem Ipsum
+- 不要使用过饱和的主色 (#007AFF, 不是 #0088FF)
+- 不要使用生硬的阴影或渐变
+- 不要使用 Comic Sans, Papyrus 或装饰性字体
+- 使用代码库中的真实中文业务术语
+
+### 2. 统一色彩系统 (基于实际 v2.pen 日历设计)
+
+**亮色主题:**
+```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`
+- **主文本**: 亮色 `#1A1A1A`, 暗色 `#F4F4F5`
+- **次要文本**: 亮色 `#6B7280`, 暗色 `#A1A1AA`
+- **支出/负数**: `#FF6B6B` (两种模式一致)
+- **主操作按钮**: `#3B82F6` (两种模式一致)
+- **圆角**: 12px (小按钮), 16px (卡片), 20px (统计卡片), 22px (图标按钮)
+- **阴影**: 亮色使用柔和阴影, 暗色使用更深的阴影或无阴影
+- **避免**: 纯黑 (#000000) 或纯白 (#FFFFFF) 文本
+
+### 3. 排版系统 (基于实际 v2.pen 设计)
+
+**字体栈:**
+```css
+/* 标题与大标题 - 基于 v2.pen */
+font-family: 'Bricolage Grotesque', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
+
+/* 正文与界面 - 基于 v2.pen */
+font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
+
+/* 备选: 系统默认 */
+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 保证可读性
+- 使用真实业务术语,避免 Lorem Ipsum
+
+### 4. 组件库 (基于实际 v2.pen 设计)
+
+**卡片 (基于 statsCard, tCard):**
+```
+统计卡片 (大卡片):
+ - 背景: #F6F7F8 (亮色), #18181B (暗色)
+ - 内边距: 20px
+ - 圆角: 20px
+ - 间距: 12px (元素之间)
+ - 布局: 垂直
+
+交易卡片 (列表卡片):
+ - 背景: #F6F7F8 (亮色), #18181B (暗色)
+ - 内边距: 16px
+ - 圆角: 16px
+ - 间距: 14px (水平元素)
+ - 高度: 自适应内容
+```
+
+**按钮 (基于实际设计):**
+```
+图标按钮 (通知按钮):
+ - 尺寸: 44x44px
+ - 圆角: 22px (完全圆形)
+ - 背景: #F5F5F5 (亮色), #27272A (暗色)
+ - 图标大小: 20px
+
+标签按钮:
+ - 内边距: 6px 10px / 6px 12px
+ - 圆角: 12px
+ - 字体: DM Sans 13px/500
+ - 颜色:
+ - 温暖色: #FFFBEB (亮色), #451A03 (暗色)
+ - 绿色: #F0FDF4 (亮色), #064E3B (暗色)
+ - 蓝色: #E0E7FF (亮色), #312E81 (暗色)
+
+悬浮按钮 (FAB):
+ - 尺寸: 56x56px
+ - 圆角: 28px
+ - 背景: #3B82F6
+ - 描边: 4px 白色边框
+ - 阴影: 提升效果
+```
+
+**图标与文字:**
+```
+图标容器:
+ - 尺寸: 44x44px
+ - 圆角: 22px
+ - 背景: #FFFFFF (亮色), #27272A (暗色)
+ - 图标: 20px (lucide 字体)
+ - 颜色: #FF6B6B (星标), #FCD34D (咖啡)
+
+章节标题:
+ - 字体: Bricolage Grotesque 18px/700
+ - 颜色: #1A1A1A (亮色), #F4F4F5 (暗色)
+
+大数值:
+ - 字体: Bricolage Grotesque 32px/800
+ - 颜色: #1A1A1A (亮色), #F4F4F5 (暗色)
+```
+
+**布局模式 (基于 Calendar 结构):**
+```
+页面容器:
+ - 宽度: 402px (设计视口)
+ - 布局: 垂直
+ - 内边距: 24px (容器边距)
+ - 间距: 16px (章节之间)
+
+头部区域:
+ - 内边距: 8px 24px
+ - 布局: 水平, 两端对齐
+ - 对齐项: 居中
+
+内容区域:
+ - 内边距: 24px
+ - 间距: 12-16px
+ - 布局: 垂直
+```
+
+### 5. 布局模式
+
+**页面结构 (Flex 容器):**
+```
+.page-container-flex:
+ - display: flex
+ - flex-direction: column
+ - height: 100%
+ - overflow: hidden
+
+ 结构:
+ 1. van-nav-bar (固定高度)
+ 2. van-tabs 或 sticky-header
+ 3. scroll-content (flex: 1, overflow-y: auto)
+ 4. bottom-button 或 van-tabbar (固定)
+```
+
+**导航栏背景透明化 (一致性模式):**
+```css
+/* 设置页面容器背景色 */
+:deep(.van-nav-bar) {
+ background: transparent !important;
+}
+```
+**重要:** 项目中所有视图都采用此模式,使导航栏背景透明,与页面背景融合。实现此效果时,请确保:
+- 页面容器有明确的背景色 (亮色: #FFFFFF, 暗色: #09090B)
+- 导航栏始终使用 `:deep(.van-nav-bar)` 选择器
+- 必须添加 `!important` 覆盖 Vant 默认样式
+- 在 `
+```
+
+```vue
+
+
+
+
+
+
+```
+
+**模块化的好处:**
+- ✅ **关注点分离**:Index 只管布局和编排,模块专注业务逻辑
+- ✅ **独立维护**:修改某个模块不影响其他模块
+- ✅ **可复用性**:模块可以在其他页面复用
+- ✅ **可测试性**:每个模块可以独立测试
+- ✅ **代码清晰**:职责明确,代码结构清晰
+
+**反模式(不要这样做):**
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**什么时候需要模块化?**
+- 页面有 3 个以上独立功能区域
+- 每个区域有自己的数据查询需求
+- 页面代码超过 300 行
+- 功能区域可能被其他页面复用
+
+**什么时候不需要模块化?**
+- 简单页面(如登录页、详情页)
+- 只有一个主要功能
+- 代码少于 200 行
+- 无明显的功能分区
+
+### 1. **数据优先,提前确认**
+
+在开始编码前,**必须先确认数据表结构**:
+
+**检查清单:**
+- [ ] 读取 .pen 设计文件,理解所有数据需求
+- [ ] 检查现有 Entity 层,确认是否支持设计需求
+- [ ] 如果需要新增字段/表/枚举值,**先询问用户确认**
+- [ ] 列出所有数据变更,等待用户批准后再继续
+
+**示例确认流程:**
+```markdown
+## 数据表结构确认
+
+根据设计图分析,需要以下数据支持:
+
+### 现有实体:
+✅ TransactionRecord - 支持交易记录
+✅ BudgetRecord - 支持预算管理
+✅ TransactionCategory - 支持分类
+
+### 需要变更:
+1. **TransactionCategory 表新增字段**
+ - 字段名: IconName (string)
+ - 用途: 存储 lucide 图标名称(如 "utensils"、"shopping-cart")
+ - 原因: 设计图使用图标名称渲染,现有 Icon 字段存储 SVG 不适合
+
+2. **BudgetRecord 新增计算字段**
+ - 字段名: ProgressPercentage (decimal, 计算属性)
+ - 用途: 当前支出占预算的百分比
+ - 原因: 设计图显示进度条需要
+
+### 是否批准以上变更?如不批准,请提供替代方案。
+```
+
+**不得做:**
+- ❌ 未经确认直接修改 Entity 层
+- ❌ 假设字段存在而不检查
+- ❌ 跳过数据表确认直接实施前端
+
+### 2. **交互细节,逐一确认**
+
+设计图无法表达所有交互逻辑,**必须向用户确认**:
+
+**需要确认的交互:**
+1. **按钮点击行为**
+ - 跳转到哪个页面?
+ - 弹出什么对话框?
+ - 触发什么 API?
+
+2. **周期切换逻辑**(如周/月/年)
+ - 周:本周一到周日?还是最近7天?
+ - 月:自然月?还是最近30天?
+ - 年:当年1-12月?还是最近12个月?
+
+3. **数据计算逻辑**
+ - 环比百分比如何计算?
+ - 趋势图数据范围?
+ - 空状态显示什么?
+
+4. **跳转目标**
+ - "查看全部"跳转到哪里?
+ - "管理预算"跳转到哪个页面?
+ - 通知按钮打开什么?
+
+**示例确认:**
+```markdown
+## 交互行为确认
+
+### 1. 顶部通知按钮
+设计图:bell 图标按钮
+**问题:** 点击后跳转到哪里?
+- A. 消息中心(MessageView.vue)
+- B. 通知列表(新页面)
+- C. 弹出通知面板
+
+### 2. 周期切换(周/月/年)
+设计图:三个 segment 切换按钮
+**问题:** 周期定义?
+- 周:本周一到周日 or 最近7天
+- 月:当前自然月 or 最近30天
+- 年:当年1-12月 or 最近12个月
+
+### 3. 核心指标徽章(如 "-15%")
+设计图:显示百分比变化
+**问题:** 对比哪个周期?
+- A. 与上一周期对比(上周/上月/去年)
+- B. 与同期对比(去年同周/去年同月)
+- C. 与预算目标对比
+
+请明确以上交互逻辑。
+```
+
+### 3. **高度还原设计稿**
+
+**视觉还原标准:**
+- 严格按照设计图的间距、字号、颜色、圆角
+- 使用设计图中的实际字体(如 DM Sans, Bricolage Grotesque, JetBrains Mono)
+- 匹配卡片阴影、边框样式
+- 复现设计图的布局层级
+
+**对照检查:**
+```typescript
+// 设计图:
+// - padding: 24px
+// - gap: 16px
+// - cornerRadius: 12px
+// - fontSize: 14px
+// - fontWeight: 600
+
+// 实现:
+
+
+
+```
+
+**字体映射:**
+| 设计图字体 | CSS 实现 |
+|-----------|---------|
+| Bricolage Grotesque | `font-family: 'Bricolage Grotesque', system-ui, sans-serif` |
+| DM Sans | `font-family: 'DM Sans', -apple-system, sans-serif` |
+| JetBrains Mono | `font-family: 'JetBrains Mono', 'SF Mono', monospace` |
+| Newsreader | `font-family: 'Newsreader', Georgia, serif` |
+
+### 4. **前后端同步开发**
+
+**开发顺序:**
+```
+1. 确认数据表 → 2. 开发后端 API → 3. 实施前端组件 → 4. 集成测试 → 5. 视觉验证
+```
+
+**后端开发标准:**
+- 在 `Entity/` 中新增/修改实体
+- 在 `Repository/` 中添加数据访问方法
+- 在 `Service/` 中实现业务逻辑
+- 在 `WebApi/Controllers/` 中创建 API 端点
+- 编写 xUnit 测试验证逻辑
+
+**前端开发标准:**
+- 在 `Web/src/views/` 中创建/修改页面组件
+- 在 `Web/src/components/` 中提取可复用组件
+- 在 `Web/src/api/` 中定义 API 客户端
+- 使用 Vue 3 Composition API + `
+
+
+```
+
+**B. 业务模块 (Business Module)**
+`src/views/Statistics/modules/MetricsCard.vue`
+- **职责**:独立负责特定功能区域的 UI 和数据获取。
+- **原则**:自包含 (Self-contained) - 自己 import api,自己 fetch data。
+
+```vue
+
+
+
+
+
+
+
+
总支出
+
¥{{ formatMoney(stats.totalExpense) }}
+
+
+
+
+
+
+
+
+
+```
+
+### 阶段 5: 集成测试与验证
+
+**5.1 运行测试**
+```bash
+# 后端测试
+dotnet test WebApi.Test/WebApi.Test.csproj
+
+# 前端构建
+cd Web
+pnpm lint
+pnpm build
+```
+
+**5.2 视觉验证**
+```typescript
+// 使用 pencil 截图对比
+pencil_get_screenshot(nodeId: "jF3SD") // 设计图截图
+
+// 在浏览器中截图实际效果
+// 对比以下方面:
+// - 间距是否一致(padding, gap)
+// - 字号是否匹配(fontSize)
+// - 颜色是否准确(fill, textColor)
+// - 圆角是否正确(cornerRadius)
+// - 布局是否对齐(layout, justifyContent, alignItems)
+```
+
+**5.3 交互验证**
+- [ ] 周期切换按钮工作正常
+- [ ] 核心指标数据正确显示
+- [ ] 徽章百分比计算准确
+- [ ] 点击卡片跳转正确
+- [ ] 空状态显示合理
+- [ ] 加载状态流畅
+- [ ] 错误处理友好
+
+## 避免的反模式
+
+### ❌ 不要这样做:
+
+**1. 未经确认修改数据表**
+```csharp
+// ❌ 直接新增字段
+public class TransactionCategory : BaseEntity
+{
+ public string IconName { get; set; } // ❌ 未经用户确认
+}
+```
+
+**2. 猜测交互逻辑**
+```vue
+// ❌ 假设跳转目标
+
+
+```
+
+**3. 不按设计图样式**
+```scss
+// 设计图: padding: 24px
+.card {
+ padding: 20px; // ❌ 不匹配设计
+}
+```
+
+**4. 跳过测试**
+```bash
+# ❌ 不运行测试直接提交
+git add .
+git commit -m "完成实施"
+```
+
+**5. 忽略暗色模式**
+```scss
+.card {
+ background: #FFFFFF; // ❌ 只实现亮色模式
+}
+```
+
+### ✅ 应该这样做:
+
+**1. 数据变更先确认**
+```markdown
+## 数据表变更请求
+
+需要在 TransactionCategory 新增以下字段:
+- IconName (string): 存储图标名称
+- 用途: 前端渲染 lucide 图标
+
+是否批准?
+```
+
+**2. 交互逻辑先确认**
+```markdown
+## 交互确认
+
+通知按钮点击后:
+- A. 跳转到 MessageView
+- B. 弹出通知列表
+- C. 其他
+
+请明确选择。
+```
+
+**3. 严格按照设计图**
+```scss
+// 设计图: padding: 24px, gap: 16px, borderRadius: 12px
+.card {
+ padding: 24px; // ✅ 匹配设计
+ gap: 16px; // ✅ 匹配设计
+ border-radius: 12px; // ✅ 匹配设计
+}
+```
+
+**4. 完整测试**
+```bash
+# ✅ 运行所有测试
+dotnet test
+cd Web && pnpm lint && pnpm build
+```
+
+**5. 支持暗色模式**
+```scss
+.card {
+ background: #FFFFFF;
+
+ @media (prefers-color-scheme: dark) {
+ background: #18181B; // ✅ 暗色适配
+ }
+}
+```
+
+## 委派与任务管理
+
+**使用此技能时:**
+
+```typescript
+delegate_task(
+ category: "visual-engineering",
+ load_skills: ["pancli-implement", "frontend-ui-ux"],
+ description: "根据 v2.pen 设计图实施统计概览页面",
+ prompt: `
+ ## 任务
+ 根据 .pans/v2.pen 中的统计概览设计图(节点 ID: jF3SD)实施完整的前后端功能
+
+ ## 预期结果
+ - [ ] Entity 层变更(如需要,经用户确认)
+ - [ ] 后端 API 开发并通过测试
+ - [ ] 前端页面高度还原设计图
+ - [ ] 交互逻辑符合用户确认
+ - [ ] 亮色/暗色主题都正常
+ - [ ] 所有测试通过(dotnet test, pnpm build)
+
+ ## 必需工具
+ - pencil_batch_get: 读取设计文件
+ - pencil_get_screenshot: 设计图截图
+ - read: 读取现有代码
+ - glob: 查找文件
+ - edit/write: 修改/新增代码
+ - bash: 运行测试
+
+ ## 必须做
+ 1. **数据确认阶段**
+ - 读取设计文件分析数据需求
+ - 检查现有 Entity 是否支持
+ - 如需变更,生成确认清单并等待用户批准
+
+ 2. **交互确认阶段**
+ - 列出所有不确定的交互逻辑
+ - 生成确认清单并等待用户明确
+
+ 3. **后端开发**
+ - 按用户批准修改 Entity
+ - 实现 Repository 数据访问
+ - 创建 Controller API
+ - 编写 xUnit 测试并通过
+
+ 4. **前端开发**
+ - **复杂页面强制模块化**: 采用 Index.vue + modules/ 结构
+ - Index.vue 仅编排,modules 负责数据获取
+ - 定义 API 客户端(src/api/)
+ - 严格按照设计图样式(间距、字号、颜色、圆角)
+ - 使用设计图中的实际字体
+ - 支持亮色/暗色主题
+
+ 5. **验证阶段**
+ - 运行后端测试:dotnet test
+ - 运行前端构建:pnpm lint && pnpm build
+ - 视觉对比设计图截图
+ - 验证交互逻辑
+
+ ## 不得做
+ - ❌ 未经确认直接修改 Entity
+ - ❌ 猜测交互逻辑而不询问
+ - ❌ 禁止复杂页面写成单文件组件 (Monolithic)
+ - ❌ 不按设计图样式随意实现
+ - ❌ 跳过测试
+ - ❌ 忽略暗色模式
+ - ❌ 使用占位数据而不调用真实 API
+
+ ## 上下文
+ - 设计文件: .pans/v2.pen
+ - 设计节点 ID: jF3SD (Statistics - Overview - Light)
+ - 现有页面: Web/src/views/StatisticsView.vue
+ - 现有 API: Web/src/api/statistics.js
+ - Entity 层: Entity/*.cs
+ - Controller 层: WebApi/Controllers/*.cs
+
+ ## 实施流程
+ 1. 数据确认 → 等待批准
+ 2. 交互确认 → 等待明确
+ 3. 后端开发 → 测试通过
+ 4. 前端开发 → 视觉验证
+ 5. 集成测试 → 全部通过
+ `,
+ run_in_background: false
+)
+```
+
+## 快速参考
+
+### 数据表确认模板
+
+```markdown
+## 数据表结构确认
+
+### 现有实体分析
+✅ [实体名] - 支持 [功能]
+❌ [实体名] - 缺少 [字段]
+
+### 需要变更
+1. **[表名] 新增字段**
+ - 字段名: [字段名] ([类型])
+ - 用途: [用途说明]
+ - 原因: [为什么需要]
+
+2. **[表名] 修改字段**
+ - 字段名: [字段名]
+ - 变更: [原类型] → [新类型]
+ - 原因: [为什么修改]
+
+### 是否批准?
+```
+
+### 交互确认模板
+
+```markdown
+## 交互逻辑确认
+
+### 1. [交互元素名称]
+**设计位置:** [描述]
+**问题:** [需要确认的问题]
+**选项:**
+- A. [选项1]
+- B. [选项2]
+- C. 其他:[请说明]
+
+### 2. [数据计算逻辑]
+**设计显示:** [设计图显示的内容]
+**问题:** [计算逻辑或数据来源]
+**选项:**
+- A. [选项1]
+- B. [选项2]
+
+请逐一明确。
+```
+
+### 样式映射表
+
+| 设计图属性 | CSS 属性 | 示例 |
+|-----------|---------|------|
+| padding | padding | `padding: 24px` |
+| gap | gap | `gap: 16px` |
+| cornerRadius | border-radius | `border-radius: 12px` |
+| fill | background | `background: #FFFFFF` |
+| textColor | color | `color: #1A1A1A` |
+| fontSize | font-size | `font-size: 14px` |
+| fontWeight | font-weight | `font-weight: 600` |
+| fontFamily | font-family | `font-family: 'DM Sans', sans-serif` |
+| width: "fill_container" | width: 100% | `width: 100%` |
+| height: "hug_contents" | height: auto | `height: auto` |
+| layout: "vertical" | flex-direction: column | `flex-direction: column` |
+| layout: "horizontal" | flex-direction: row | `flex-direction: row` |
+| justifyContent: "space_between" | justify-content: space-between | `justify-content: space-between` |
+| alignItems: "center" | align-items: center | `align-items: center` |
+
+---
+
+**版本:** 1.0.0
+**最后更新:** 2026-02-03
+**维护者:** EmailBill 开发团队
diff --git a/.pans/v2.pen b/.pans/v2.pen
index c660472..84026cd 100644
--- a/.pans/v2.pen
+++ b/.pans/v2.pen
@@ -6,12 +6,71 @@
"id": "jF3SD",
"x": -983,
"y": 369,
- "name": "Statistics",
+ "name": "Statistics - Overview - Light",
"clip": true,
- "width": 402,
+ "width": 375,
"fill": "#FFFFFF",
"layout": "vertical",
"children": [
+ {
+ "type": "frame",
+ "id": "HdrL1",
+ "name": "header",
+ "width": "fill_container",
+ "gap": 4,
+ "padding": [
+ 8,
+ 24
+ ],
+ "justifyContent": "space_between",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "frame",
+ "id": "HdrC1",
+ "name": "headerContent",
+ "width": 142,
+ "height": 39,
+ "layout": "vertical",
+ "gap": 4,
+ "children": [
+ {
+ "type": "text",
+ "id": "TxtL1",
+ "name": "subtitle",
+ "fill": "#1a1a1a",
+ "content": "2026年",
+ "fontFamily": "DM Sans",
+ "fontSize": 24,
+ "fontWeight": "500"
+ }
+ ]
+ },
+ {
+ "type": "frame",
+ "id": "BtnL1",
+ "name": "notifBtn",
+ "width": 44,
+ "height": 44,
+ "fill": "#F5F5F5",
+ "cornerRadius": 22,
+ "justifyContent": "center",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "icon_font",
+ "id": "IcnL1",
+ "name": "icon",
+ "width": 20,
+ "height": 20,
+ "iconFontName": "bell",
+ "iconFontFamily": "lucide",
+ "fill": "#1A1A1A"
+ }
+ ]
+ }
+ ]
+ },
{
"type": "frame",
"id": "AMTax",
@@ -56,8 +115,8 @@
"id": "H0yK4",
"name": "dayLabel",
"fill": "#1A1A1A",
- "content": "日",
- "fontFamily": "Inter",
+ "content": "周",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "600"
}
@@ -77,8 +136,8 @@
"id": "qMr9M",
"name": "weekLabel",
"fill": "#888888",
- "content": "周",
- "fontFamily": "Inter",
+ "content": "月",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -98,8 +157,8 @@
"id": "NJAly",
"name": "monthLabel",
"fill": "#888888",
- "content": "月",
- "fontFamily": "Inter",
+ "content": "年",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -149,7 +208,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -174,7 +233,7 @@
"name": "card1Label",
"fill": "#888888",
"content": "总支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -230,7 +289,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -255,7 +314,7 @@
"name": "card2Label",
"fill": "#888888",
"content": "交易笔数",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -290,7 +349,7 @@
"name": "card2Bottom",
"width": "fill_container",
"height": 24,
- "gap": 3,
+ "gap": 4,
"alignItems": "end",
"children": [
{
@@ -383,7 +442,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -408,7 +467,7 @@
"name": "incomeLabel",
"fill": "#888888",
"content": "总收入",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -464,7 +523,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -489,7 +548,7 @@
"name": "balanceLabel",
"fill": "#888888",
"content": "净收支",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -593,7 +652,7 @@
"name": "linkText",
"fill": "#0D6E6E",
"content": "查看全部",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
},
@@ -624,7 +683,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -968,7 +1027,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -1319,7 +1378,7 @@
"name": "budgetLinkText",
"fill": "#0D6E6E",
"content": "管理预算",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
},
@@ -1350,7 +1409,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -1745,8 +1804,8 @@
"id": "PlVHb",
"x": -1413,
"y": 369,
- "name": "Calendar (Dark)",
- "width": 402,
+ "name": "Calendar - Main View - Dark",
+ "width": 375,
"fill": "#09090B",
"layout": "vertical",
"children": [
@@ -3229,7 +3288,7 @@
"cornerRadius": 20,
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -3256,7 +3315,7 @@
"fill": "#451a03",
"cornerRadius": 12,
"padding": [
- 6,
+ 8,
10
],
"children": [
@@ -3329,7 +3388,7 @@
"fill": "#064e3b",
"cornerRadius": 12,
"padding": [
- 6,
+ 8,
12
],
"children": [
@@ -3351,9 +3410,9 @@
"name": "smartBtn",
"fill": "#312e81",
"cornerRadius": 12,
- "gap": 6,
+ "gap": 8,
"padding": [
- 6,
+ 8,
12
],
"alignItems": "center",
@@ -3391,7 +3450,7 @@
"width": "fill_container",
"fill": "#18181b",
"cornerRadius": 16,
- "gap": 14,
+ "gap": 16,
"padding": 16,
"alignItems": "center",
"children": [
@@ -3467,7 +3526,7 @@
"width": "fill_container",
"fill": "#18181b",
"cornerRadius": 16,
- "gap": 14,
+ "gap": 16,
"padding": 16,
"alignItems": "center",
"children": [
@@ -3545,8 +3604,8 @@
"id": "uxvyO",
"x": -1841,
"y": 369,
- "name": "Calendar",
- "width": 402,
+ "name": "Calendar - Main View - Light",
+ "width": 375,
"fill": "#FFFFFF",
"layout": "vertical",
"children": [
@@ -5004,20 +5063,10 @@
"id": "LMdOg",
"name": "statsTitle",
"fill": "#1A1A1A",
- "content": "每日统计",
+ "content": "2026年1月12日",
"fontFamily": "Bricolage Grotesque",
"fontSize": 18,
"fontWeight": "700"
- },
- {
- "type": "text",
- "id": "1TSK3",
- "name": "statsDate",
- "fill": "#6B7280",
- "content": "2026年1月12日",
- "fontFamily": "DM Sans",
- "fontSize": 13,
- "fontWeight": "500"
}
]
},
@@ -5030,13 +5079,14 @@
"cornerRadius": 20,
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
"id": "UiJYD",
"name": "statsRow",
- "width": "fill_container",
+ "width": 91,
+ "height": 17,
"justifyContent": "space_between",
"alignItems": "center",
"children": [
@@ -5045,33 +5095,10 @@
"id": "QBHWG",
"name": "statsLabel",
"fill": "#6B7280",
- "content": "Total Spent",
+ "content": "支出",
"fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
- },
- {
- "type": "frame",
- "id": "6TcZ1",
- "name": "b1",
- "fill": "#FFFBEB",
- "cornerRadius": 12,
- "padding": [
- 6,
- 10
- ],
- "children": [
- {
- "type": "text",
- "id": "znYtx",
- "name": "t29",
- "fill": "#D97706",
- "content": "Daily Limit: 2500",
- "fontFamily": "DM Sans",
- "fontSize": 11,
- "fontWeight": "600"
- }
- ]
}
]
},
@@ -5130,7 +5157,7 @@
"fill": "#F0FDF4",
"cornerRadius": 12,
"padding": [
- 6,
+ 8,
12
],
"children": [
@@ -5152,9 +5179,9 @@
"name": "smartBtn",
"fill": "#E0E7FF",
"cornerRadius": 12,
- "gap": 6,
+ "gap": 8,
"padding": [
- 6,
+ 8,
12
],
"alignItems": "center",
@@ -5192,7 +5219,7 @@
"width": "fill_container",
"fill": "#F6F7F8",
"cornerRadius": 16,
- "gap": 14,
+ "gap": 16,
"padding": 16,
"alignItems": "center",
"children": [
@@ -5268,7 +5295,7 @@
"width": "fill_container",
"fill": "#F6F7F8",
"cornerRadius": 16,
- "gap": 14,
+ "gap": 16,
"padding": 16,
"alignItems": "center",
"children": [
@@ -5346,12 +5373,71 @@
"id": "SNGbj",
"x": -538,
"y": 369,
- "name": "Statistics Dark",
+ "name": "Statistics - Overview - Dark",
"clip": true,
- "width": 402,
- "fill": "#0F0F0F",
+ "width": 375,
+ "fill": "#09090B",
"layout": "vertical",
"children": [
+ {
+ "type": "frame",
+ "id": "HdrD1",
+ "name": "header",
+ "width": "fill_container",
+ "gap": 4,
+ "padding": [
+ 8,
+ 24
+ ],
+ "justifyContent": "space_between",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "frame",
+ "id": "HdrCD1",
+ "name": "headerContent",
+ "width": 142,
+ "height": 39,
+ "layout": "vertical",
+ "gap": 4,
+ "children": [
+ {
+ "type": "text",
+ "id": "TxtD1",
+ "name": "subtitle",
+ "fill": "#a1a1aa",
+ "content": "2026年",
+ "fontFamily": "DM Sans",
+ "fontSize": 24,
+ "fontWeight": "500"
+ }
+ ]
+ },
+ {
+ "type": "frame",
+ "id": "BtnD1",
+ "name": "notifBtn",
+ "width": 44,
+ "height": 44,
+ "fill": "#27272a",
+ "cornerRadius": 22,
+ "justifyContent": "center",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "icon_font",
+ "id": "IcnD1",
+ "name": "icon",
+ "width": 20,
+ "height": 20,
+ "iconFontName": "bell",
+ "iconFontFamily": "lucide",
+ "fill": "#f4f4f5"
+ }
+ ]
+ }
+ ]
+ },
{
"type": "frame",
"id": "Ne4V3",
@@ -5397,7 +5483,7 @@
"name": "dayLabel",
"fill": "#1A1A1A",
"content": "日",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "600"
}
@@ -5419,7 +5505,7 @@
"name": "weekLabel",
"fill": "#888888",
"content": "周",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -5441,7 +5527,7 @@
"name": "monthLabel",
"fill": "#888888",
"content": "月",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -5491,7 +5577,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -5516,7 +5602,7 @@
"name": "card1Label",
"fill": "#888888",
"content": "总支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -5572,7 +5658,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -5597,7 +5683,7 @@
"name": "card2Label",
"fill": "#888888",
"content": "交易笔数",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -5632,7 +5718,7 @@
"name": "card2Bottom",
"width": "fill_container",
"height": 24,
- "gap": 3,
+ "gap": 4,
"alignItems": "end",
"children": [
{
@@ -5725,7 +5811,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -5750,7 +5836,7 @@
"name": "incomeLabel",
"fill": "#888888",
"content": "总收入",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -5806,7 +5892,7 @@
},
"layout": "vertical",
"gap": 12,
- "padding": 20,
+ "padding": 24,
"justifyContent": "space_between",
"children": [
{
@@ -5831,7 +5917,7 @@
"name": "balanceLabel",
"fill": "#888888",
"content": "净收支",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "500"
},
@@ -5935,7 +6021,7 @@
"name": "linkText",
"fill": "#0D6E6E",
"content": "查看全部",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
},
@@ -5966,7 +6052,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -6310,7 +6396,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -6661,7 +6747,7 @@
"name": "budgetLinkText",
"fill": "#0D6E6E",
"content": "管理预算",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
},
@@ -6692,7 +6778,7 @@
},
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "frame",
@@ -7085,13 +7171,72 @@
{
"type": "frame",
"id": "BCxxA",
- "x": -36,
+ "x": -100,
"y": 369,
- "name": "Budget Stats (Light)",
- "width": 402,
+ "name": "Budget - Statistics - Light",
+ "width": 375,
"fill": "#FFFFFF",
"layout": "vertical",
"children": [
+ {
+ "type": "frame",
+ "id": "HdrL2",
+ "name": "header",
+ "width": "fill_container",
+ "gap": 4,
+ "padding": [
+ 8,
+ 24
+ ],
+ "justifyContent": "space_between",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "frame",
+ "id": "HdrCL2",
+ "name": "headerContent",
+ "width": 142,
+ "height": 39,
+ "layout": "vertical",
+ "gap": 4,
+ "children": [
+ {
+ "type": "text",
+ "id": "TxtL2",
+ "name": "subtitle",
+ "fill": "#1a1a1a",
+ "content": "2026年1月",
+ "fontFamily": "DM Sans",
+ "fontSize": 24,
+ "fontWeight": "500"
+ }
+ ]
+ },
+ {
+ "type": "frame",
+ "id": "BtnL2",
+ "name": "notifBtn",
+ "width": 44,
+ "height": 44,
+ "fill": "#F5F5F5",
+ "cornerRadius": 22,
+ "justifyContent": "center",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "icon_font",
+ "id": "IcnL2",
+ "name": "icon",
+ "width": 20,
+ "height": 20,
+ "iconFontName": "bell",
+ "iconFontFamily": "lucide",
+ "fill": "#1A1A1A"
+ }
+ ]
+ }
+ ]
+ },
{
"type": "frame",
"id": "LXM6A",
@@ -7099,55 +7244,6 @@
"width": "fill_container",
"layout": "vertical",
"children": [
- {
- "type": "frame",
- "id": "4R8MH",
- "name": "navTop",
- "width": "fill_container",
- "padding": [
- 12,
- 16
- ],
- "justifyContent": "space_between",
- "alignItems": "center",
- "children": [
- {
- "type": "frame",
- "id": "5kBJY",
- "name": "dateBtn",
- "fill": "#F5F5F5",
- "cornerRadius": 8,
- "gap": 4,
- "padding": [
- 6,
- 12
- ],
- "alignItems": "center",
- "children": [
- {
- "type": "text",
- "id": "N6BSi",
- "name": "dateText",
- "fill": "#18181B",
- "content": "2026年1月",
- "fontFamily": "Inter",
- "fontSize": 16,
- "fontWeight": "500"
- },
- {
- "type": "icon_font",
- "id": "wSRWZ",
- "name": "dateIcon",
- "width": 16,
- "height": 16,
- "iconFontName": "chevron-down",
- "iconFontFamily": "lucide",
- "fill": "#71717A"
- }
- ]
- }
- ]
- },
{
"type": "frame",
"id": "SRWHt",
@@ -7178,7 +7274,7 @@
"name": "tab1Text",
"fill": "#1A1A1A",
"content": "支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "600"
}
@@ -7203,7 +7299,7 @@
"name": "tab2Text",
"fill": "#888888",
"content": "收入",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -7228,7 +7324,7 @@
"name": "tab3Text",
"fill": "#888888",
"content": "计划",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -7256,7 +7352,7 @@
"cornerRadius": 16,
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "text",
@@ -7264,7 +7360,7 @@
"name": "overallTitle",
"fill": "#71717A",
"content": "本月预算",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 14,
"fontWeight": "normal"
},
@@ -7289,7 +7385,7 @@
"name": "overallCurrent",
"fill": "#18181B",
"content": "¥8,523",
- "fontFamily": "Inter",
+ "fontFamily": "Bricolage Grotesque",
"fontSize": 28,
"fontWeight": "700"
},
@@ -7299,7 +7395,7 @@
"name": "overallLimit",
"fill": "#71717A",
"content": "/ ¥15,000",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "normal"
}
@@ -7311,7 +7407,7 @@
"name": "overallPercent",
"fill": "#18181B",
"content": "56.8%",
- "fontFamily": "Inter",
+ "fontFamily": "Bricolage Grotesque",
"fontSize": 24,
"fontWeight": "600"
}
@@ -7372,7 +7468,7 @@
"name": "cardTitle1",
"fill": "#18181B",
"content": "餐饮美食",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -7393,7 +7489,7 @@
"name": "cardBadgeText1",
"fill": "#3B82F6",
"content": "月度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -7441,7 +7537,7 @@
"name": "cardLabel1",
"fill": "#71717A",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7451,7 +7547,7 @@
"name": "cardAmount1",
"fill": "#EF4444",
"content": "¥2,456",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7471,7 +7567,7 @@
"name": "cardLabel2",
"fill": "#71717A",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7481,7 +7577,7 @@
"name": "cardAmount2",
"fill": "#10B981",
"content": "¥544",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7516,7 +7612,7 @@
"name": "cardTitle2",
"fill": "#18181B",
"content": "交通出行",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -7537,7 +7633,7 @@
"name": "cardBadgeText2",
"fill": "#F59E0B",
"content": "年度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -7585,7 +7681,7 @@
"name": "cardLabel3",
"fill": "#71717A",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7595,7 +7691,7 @@
"name": "cardAmount3",
"fill": "#EF4444",
"content": "¥1,280",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7615,7 +7711,7 @@
"name": "cardLabel4",
"fill": "#71717A",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7625,7 +7721,7 @@
"name": "cardAmount4",
"fill": "#10B981",
"content": "¥3,720",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7660,7 +7756,7 @@
"name": "cardTitle3",
"fill": "#18181B",
"content": "购物消费",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -7681,7 +7777,7 @@
"name": "cardBadgeText3",
"fill": "#3B82F6",
"content": "月度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -7729,7 +7825,7 @@
"name": "cardLabel5",
"fill": "#71717A",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7739,7 +7835,7 @@
"name": "cardAmount5",
"fill": "#EF4444",
"content": "¥1,850",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7759,7 +7855,7 @@
"name": "cardLabel6",
"fill": "#71717A",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -7769,7 +7865,7 @@
"name": "cardAmount6",
"fill": "#10B981",
"content": "¥650",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -7782,47 +7878,78 @@
]
}
]
- },
- {
- "type": "frame",
- "id": "hzxw1",
- "name": "fab",
- "width": 56,
- "height": 56,
- "fill": "#3B82F6",
- "cornerRadius": 28,
- "stroke": {
- "align": "outside",
- "thickness": 4,
- "fill": "#FFFFFF"
- },
- "justifyContent": "center",
- "alignItems": "center",
- "children": [
- {
- "type": "icon_font",
- "id": "VDoNM",
- "name": "fabIcon",
- "width": 24,
- "height": 24,
- "iconFontName": "pencil",
- "iconFontFamily": "lucide",
- "fill": "#FFFFFF"
- }
- ]
}
]
},
{
"type": "frame",
"id": "zYTEk",
- "x": 466,
+ "x": 402,
"y": 369,
- "name": "Budget Stats (Dark)",
- "width": 402,
- "fill": "#0F0F0F",
+ "name": "Budget - Statistics - Dark",
+ "width": 375,
+ "fill": "#09090B",
"layout": "vertical",
"children": [
+ {
+ "type": "frame",
+ "id": "HdrD2",
+ "name": "header",
+ "width": "fill_container",
+ "gap": 4,
+ "padding": [
+ 8,
+ 24
+ ],
+ "justifyContent": "space_between",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "frame",
+ "id": "HdrCD2",
+ "name": "headerContent",
+ "width": 142,
+ "height": 39,
+ "layout": "vertical",
+ "gap": 4,
+ "children": [
+ {
+ "type": "text",
+ "id": "TxtD2",
+ "name": "subtitle",
+ "fill": "#a1a1aa",
+ "content": "2026年1月",
+ "fontFamily": "DM Sans",
+ "fontSize": 24,
+ "fontWeight": "500"
+ }
+ ]
+ },
+ {
+ "type": "frame",
+ "id": "BtnD2",
+ "name": "notifBtn",
+ "width": 44,
+ "height": 44,
+ "fill": "#27272a",
+ "cornerRadius": 22,
+ "justifyContent": "center",
+ "alignItems": "center",
+ "children": [
+ {
+ "type": "icon_font",
+ "id": "IcnD2",
+ "name": "icon",
+ "width": 20,
+ "height": 20,
+ "iconFontName": "bell",
+ "iconFontFamily": "lucide",
+ "fill": "#f4f4f5"
+ }
+ ]
+ }
+ ]
+ },
{
"type": "frame",
"id": "UcVry",
@@ -7830,55 +7957,6 @@
"width": "fill_container",
"layout": "vertical",
"children": [
- {
- "type": "frame",
- "id": "yKDZC",
- "name": "navTop",
- "width": "fill_container",
- "padding": [
- 12,
- 16
- ],
- "justifyContent": "space_between",
- "alignItems": "center",
- "children": [
- {
- "type": "frame",
- "id": "QTSlc",
- "name": "dateBtn",
- "fill": "#27272A",
- "cornerRadius": 8,
- "gap": 4,
- "padding": [
- 6,
- 12
- ],
- "alignItems": "center",
- "children": [
- {
- "type": "text",
- "id": "hEsJE",
- "name": "dateText",
- "fill": "#FAFAFA",
- "content": "2026年1月",
- "fontFamily": "Inter",
- "fontSize": 16,
- "fontWeight": "500"
- },
- {
- "type": "icon_font",
- "id": "SrQTT",
- "name": "dateIcon",
- "width": 16,
- "height": 16,
- "iconFontName": "chevron-down",
- "iconFontFamily": "lucide",
- "fill": "#A1A1AA"
- }
- ]
- }
- ]
- },
{
"type": "frame",
"id": "TmjqN",
@@ -7909,7 +7987,7 @@
"name": "tab1Text",
"fill": "#FFFFFF",
"content": "支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "600"
}
@@ -7934,7 +8012,7 @@
"name": "tab2Text",
"fill": "#888888",
"content": "收入",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -7959,7 +8037,7 @@
"name": "tab3Text",
"fill": "#888888",
"content": "计划",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 13,
"fontWeight": "500"
}
@@ -7987,7 +8065,7 @@
"cornerRadius": 16,
"layout": "vertical",
"gap": 16,
- "padding": 20,
+ "padding": 24,
"children": [
{
"type": "text",
@@ -7995,7 +8073,7 @@
"name": "overallTitle",
"fill": "#A1A1AA",
"content": "本月预算",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 14,
"fontWeight": "normal"
},
@@ -8020,7 +8098,7 @@
"name": "overallCurrent",
"fill": "#FAFAFA",
"content": "¥8,523",
- "fontFamily": "Inter",
+ "fontFamily": "Bricolage Grotesque",
"fontSize": 28,
"fontWeight": "700"
},
@@ -8030,7 +8108,7 @@
"name": "overallLimit",
"fill": "#A1A1AA",
"content": "/ ¥15,000",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "normal"
}
@@ -8042,7 +8120,7 @@
"name": "overallPercent",
"fill": "#FAFAFA",
"content": "56.8%",
- "fontFamily": "Inter",
+ "fontFamily": "Bricolage Grotesque",
"fontSize": 24,
"fontWeight": "600"
}
@@ -8103,7 +8181,7 @@
"name": "cardTitle1",
"fill": "#FAFAFA",
"content": "餐饮美食",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -8124,7 +8202,7 @@
"name": "cardBadgeText1",
"fill": "#60A5FA",
"content": "月度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -8172,7 +8250,7 @@
"name": "cardLabel1",
"fill": "#A1A1AA",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8182,7 +8260,7 @@
"name": "cardAmount1",
"fill": "#EF4444",
"content": "¥2,456",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8202,7 +8280,7 @@
"name": "cardLabel2",
"fill": "#A1A1AA",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8212,7 +8290,7 @@
"name": "cardAmount2",
"fill": "#10B981",
"content": "¥544",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8247,7 +8325,7 @@
"name": "cardTitle2",
"fill": "#FAFAFA",
"content": "交通出行",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -8268,7 +8346,7 @@
"name": "cardBadgeText2",
"fill": "#FCD34D",
"content": "年度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -8316,7 +8394,7 @@
"name": "cardLabel3",
"fill": "#A1A1AA",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8326,7 +8404,7 @@
"name": "cardAmount3",
"fill": "#EF4444",
"content": "¥1,280",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8346,7 +8424,7 @@
"name": "cardLabel4",
"fill": "#A1A1AA",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8356,7 +8434,7 @@
"name": "cardAmount4",
"fill": "#10B981",
"content": "¥3,720",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8391,7 +8469,7 @@
"name": "cardTitle3",
"fill": "#FAFAFA",
"content": "购物消费",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 16,
"fontWeight": "600"
},
@@ -8412,7 +8490,7 @@
"name": "cardBadgeText3",
"fill": "#60A5FA",
"content": "月度",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
}
@@ -8460,7 +8538,7 @@
"name": "cardLabel5",
"fill": "#A1A1AA",
"content": "已支出",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8470,7 +8548,7 @@
"name": "cardAmount5",
"fill": "#EF4444",
"content": "¥1,850",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8490,7 +8568,7 @@
"name": "cardLabel6",
"fill": "#A1A1AA",
"content": "余额",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 12,
"fontWeight": "normal"
},
@@ -8500,7 +8578,7 @@
"name": "cardAmount6",
"fill": "#10B981",
"content": "¥650",
- "fontFamily": "Inter",
+ "fontFamily": "DM Sans",
"fontSize": 18,
"fontWeight": "600"
}
@@ -8513,566 +8591,6 @@
]
}
]
- },
- {
- "type": "frame",
- "id": "Euc04",
- "name": "fab",
- "width": 56,
- "height": 56,
- "fill": "#3B82F6",
- "cornerRadius": 28,
- "stroke": {
- "align": "outside",
- "thickness": 4,
- "fill": "#FFFFFF"
- },
- "justifyContent": "center",
- "alignItems": "center",
- "children": [
- {
- "type": "icon_font",
- "id": "zKjKJ",
- "name": "fabIcon",
- "width": 24,
- "height": 24,
- "iconFontName": "pencil",
- "iconFontFamily": "lucide",
- "fill": "#FFFFFF"
- }
- ]
- }
- ]
- },
- {
- "type": "frame",
- "id": "Rg59j",
- "x": 900,
- "y": 369,
- "name": "Budget Analytics",
- "width": 402,
- "fill": "#F5F7FA",
- "layout": "vertical",
- "gap": 16,
- "padding": 20,
- "children": [
- {
- "type": "frame",
- "id": "Nq8k9",
- "name": "header",
- "width": "fill_container",
- "layout": "vertical",
- "gap": 8,
- "children": [
- {
- "type": "text",
- "id": "j7M8v",
- "name": "titleText",
- "fill": "#1A1A1A",
- "content": "预算分析",
- "fontFamily": "Inter",
- "fontSize": 24,
- "fontWeight": "700"
- },
- {
- "type": "text",
- "id": "Dj7FE",
- "name": "dateText",
- "fill": "#6B7280",
- "content": "2026年1月",
- "fontFamily": "Inter",
- "fontSize": 14,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "rUUNa",
- "name": "remainCard",
- "width": "fill_container",
- "fill": "#FFFFFF",
- "cornerRadius": 12,
- "layout": "vertical",
- "gap": 12,
- "padding": 16,
- "children": [
- {
- "type": "text",
- "id": "Lsb2n",
- "name": "remainTitle",
- "fill": "#6B7280",
- "content": "预算剩余",
- "fontFamily": "Inter",
- "fontSize": 14,
- "fontWeight": "500"
- },
- {
- "type": "text",
- "id": "FPMMo",
- "name": "remainAmount",
- "fill": "#10B981",
- "content": "¥3,250",
- "fontFamily": "Inter",
- "fontSize": 32,
- "fontWeight": "700"
- },
- {
- "type": "text",
- "id": "lMDn7",
- "name": "remainDesc",
- "fill": "#9CA3AF",
- "content": "总预算 ¥10,000 | 已使用 68%",
- "fontFamily": "Inter",
- "fontSize": 12,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "12oX3",
- "name": "burndownCard",
- "width": "fill_container",
- "fill": "#FFFFFF",
- "cornerRadius": 12,
- "layout": "vertical",
- "gap": 12,
- "padding": 16,
- "children": [
- {
- "type": "text",
- "id": "XIsI0",
- "name": "burnTitle",
- "fill": "#1A1A1A",
- "content": "预算燃尽图",
- "fontFamily": "Inter",
- "fontSize": 16,
- "fontWeight": "600"
- },
- {
- "type": "frame",
- "id": "ryx65",
- "name": "chartArea1",
- "width": "fill_container",
- "height": 200,
- "fill": "#F9FAFB",
- "cornerRadius": 8,
- "layout": "none",
- "children": [
- {
- "type": "line",
- "id": "h85XX",
- "x": 20,
- "y": 20,
- "name": "idealLine",
- "width": 310,
- "height": 160,
- "stroke": {
- "thickness": 2,
- "fill": "#D1D5DB"
- }
- },
- {
- "type": "path",
- "id": "c6Bys",
- "x": 20,
- "y": 20,
- "name": "actualLine",
- "geometry": "M0 0l100 40 100 60 110 40",
- "width": 310,
- "height": 160,
- "stroke": {
- "thickness": 3,
- "fill": "#3B82F6"
- }
- },
- {
- "type": "ellipse",
- "id": "RQY2V",
- "x": 15,
- "y": 15,
- "name": "point1",
- "fill": "#3B82F6",
- "width": 10,
- "height": 10
- },
- {
- "type": "ellipse",
- "id": "SE4dr",
- "x": 115,
- "y": 55,
- "name": "point2",
- "fill": "#3B82F6",
- "width": 10,
- "height": 10
- },
- {
- "type": "ellipse",
- "id": "9fGPC",
- "x": 215,
- "y": 115,
- "name": "point3",
- "fill": "#3B82F6",
- "width": 10,
- "height": 10
- },
- {
- "type": "ellipse",
- "id": "7HZDX",
- "x": 315,
- "y": 155,
- "name": "point4",
- "fill": "#3B82F6",
- "width": 10,
- "height": 10
- }
- ]
- },
- {
- "type": "frame",
- "id": "maILp",
- "name": "legend1",
- "width": "fill_container",
- "gap": 16,
- "justifyContent": "center",
- "children": [
- {
- "type": "frame",
- "id": "VyDB0",
- "name": "ideal",
- "gap": 6,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "id": "RkZ6D",
- "name": "idealDot",
- "fill": "#D1D5DB",
- "width": 12,
- "height": 2
- },
- {
- "type": "text",
- "id": "tpHGY",
- "name": "idealLabel",
- "fill": "#6B7280",
- "content": "理想消耗",
- "fontFamily": "Inter",
- "fontSize": 12,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "7yVCB",
- "name": "actual",
- "gap": 6,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "id": "sBgPG",
- "name": "actualDot",
- "fill": "#3B82F6",
- "width": 12,
- "height": 2
- },
- {
- "type": "text",
- "id": "XkLVA",
- "name": "actualLabel",
- "fill": "#6B7280",
- "content": "实际消耗",
- "fontFamily": "Inter",
- "fontSize": 12,
- "fontWeight": "normal"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "type": "frame",
- "id": "GiIWx",
- "name": "varianceCard",
- "width": "fill_container",
- "fill": "#FFFFFF",
- "cornerRadius": 12,
- "layout": "vertical",
- "gap": 12,
- "padding": 16,
- "children": [
- {
- "type": "text",
- "id": "6Kket",
- "name": "varTitle",
- "fill": "#1A1A1A",
- "content": "预算偏差分析",
- "fontFamily": "Inter",
- "fontSize": 16,
- "fontWeight": "600"
- },
- {
- "type": "frame",
- "id": "i5z6p",
- "name": "chartArea2",
- "width": "fill_container",
- "height": 240,
- "fill": "#F9FAFB",
- "cornerRadius": 8,
- "layout": "none",
- "children": [
- {
- "type": "frame",
- "id": "TFE88",
- "x": 30,
- "y": 180,
- "name": "bar1Frame",
- "width": 50,
- "height": 80,
- "layout": "vertical",
- "gap": 4,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 4,
- "id": "uWXEp",
- "name": "bar1",
- "fill": "#EF4444",
- "width": 40,
- "height": 60
- },
- {
- "type": "text",
- "id": "b1CKO",
- "name": "label1",
- "fill": "#6B7280",
- "content": "餐饮",
- "fontFamily": "Inter",
- "fontSize": 11,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "lHkYX",
- "x": 100,
- "y": 140,
- "name": "bar2Frame",
- "width": 50,
- "height": 120,
- "layout": "vertical",
- "gap": 4,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 4,
- "id": "UCaPk",
- "name": "bar2",
- "fill": "#F59E0B",
- "width": 40,
- "height": 100
- },
- {
- "type": "text",
- "id": "qpX6L",
- "name": "label2",
- "fill": "#6B7280",
- "content": "交通",
- "fontFamily": "Inter",
- "fontSize": 11,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "XzvK2",
- "x": 170,
- "y": 160,
- "name": "bar3Frame",
- "width": 50,
- "height": 100,
- "layout": "vertical",
- "gap": 4,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 4,
- "id": "IJypN",
- "name": "bar3",
- "fill": "#10B981",
- "width": 40,
- "height": 80
- },
- {
- "type": "text",
- "id": "inAFN",
- "name": "label3",
- "fill": "#6B7280",
- "content": "购物",
- "fontFamily": "Inter",
- "fontSize": 11,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "mwQeE",
- "x": 240,
- "y": 150,
- "name": "bar4Frame",
- "width": 50,
- "height": 110,
- "layout": "vertical",
- "gap": 4,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 4,
- "id": "jgJBQ",
- "name": "bar4",
- "fill": "#3B82F6",
- "width": 40,
- "height": 90
- },
- {
- "type": "text",
- "id": "hweUc",
- "name": "label4",
- "fill": "#6B7280",
- "content": "娱乐",
- "fontFamily": "Inter",
- "fontSize": 11,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "o1uNO",
- "x": 310,
- "y": 190,
- "name": "bar5Frame",
- "width": 50,
- "height": 70,
- "layout": "vertical",
- "gap": 4,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 4,
- "id": "0MwYg",
- "name": "bar5",
- "fill": "#8B5CF6",
- "width": 40,
- "height": 50
- },
- {
- "type": "text",
- "id": "9iXy6",
- "name": "label5",
- "fill": "#6B7280",
- "content": "其他",
- "fontFamily": "Inter",
- "fontSize": 11,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "line",
- "id": "98osi",
- "x": 20,
- "y": 200,
- "name": "axisLine",
- "width": 350,
- "height": 0,
- "stroke": {
- "thickness": 1,
- "fill": "#E5E7EB"
- }
- }
- ]
- },
- {
- "type": "frame",
- "id": "aOAnk",
- "name": "legend2",
- "width": "fill_container",
- "gap": 12,
- "justifyContent": "center",
- "children": [
- {
- "type": "frame",
- "id": "yKfLI",
- "name": "over",
- "gap": 6,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 2,
- "id": "tsGkr",
- "name": "overDot",
- "fill": "#EF4444",
- "width": 8,
- "height": 8
- },
- {
- "type": "text",
- "id": "cMKm7",
- "name": "overLabel",
- "fill": "#6B7280",
- "content": "超支",
- "fontFamily": "Inter",
- "fontSize": 12,
- "fontWeight": "normal"
- }
- ]
- },
- {
- "type": "frame",
- "id": "BL57C",
- "name": "normal",
- "gap": 6,
- "alignItems": "center",
- "children": [
- {
- "type": "rectangle",
- "cornerRadius": 2,
- "id": "1Vkqa",
- "name": "normalDot",
- "fill": "#10B981",
- "width": 8,
- "height": 8
- },
- {
- "type": "text",
- "id": "MSLKe",
- "name": "normalLabel",
- "fill": "#6B7280",
- "content": "正常",
- "fontFamily": "Inter",
- "fontSize": 12,
- "fontWeight": "normal"
- }
- ]
- }
- ]
- }
- ]
}
]
}
diff --git a/.sisyphus/notepads/calendar-refactor/learnings.md b/.sisyphus/notepads/calendar-refactor/learnings.md
new file mode 100644
index 0000000..6718db9
--- /dev/null
+++ b/.sisyphus/notepads/calendar-refactor/learnings.md
@@ -0,0 +1,325 @@
+
+## Vue 3 Composition API Research - Modular Architecture Best Practices
+
+### 研究日期: 2026-02-03
+
+---
+
+## 1. 官方 Vue 3 组件组织原则
+
+### 1.1 Composables 用于代码组织
+来源: Vue 官方文档 - https://vuejs.org/guide/reusability/composables
+
+**核心原则:**
+- Composables 不仅用于复用,也用于**代码组织**
+- 当组件变得过于复杂时,应该将逻辑按**关注点分离**提取到更小的函数中
+- 可以将提取的 composables 视为**组件级别的服务**,它们可以相互通信
+
+**官方示例模式:**
+```vue
+
+```
+
+**关键洞察:**
+- Composables 应返回**普通对象**包含多个 refs,保持响应式
+- 避免返回 reactive 对象,因为解构会失去响应性
+- Composables 可以接收其他 composables 的返回值作为参数
+
+---
+
+## 2. 代码分割与懒加载
+
+### 2.1 defineAsyncComponent 用于模块懒加载
+来源: Vue 官方文档 - https://github.com/vuejs/docs/blob/main/src/guide/best-practices/performance.md
+
+**适用场景:**
+- 将大型组件树分割成独立的 chunks
+- 仅在组件渲染时才加载,改善初始加载时间
+
+```js
+import { defineAsyncComponent } from 'vue'
+
+// Foo.vue 及其依赖被单独打包成一个 chunk
+// 只有在组件被渲染时才会按需获取
+const Foo = defineAsyncComponent(() => import('./Foo.vue'))
+```
+
+### 2.2 动态导入用于 JS 代码分割
+```js
+// lazy.js 及其依赖会被分割成单独的 chunk
+// 只在 loadLazy() 被调用时才加载
+function loadLazy() {
+ return import('./lazy.js')
+}
+```
+
+---
+
+## 3. 真实世界的模块化架构模式
+
+### 3.1 Dashboard 模块化架构 - 成功案例
+
+**案例 1: Soybean Admin (MIT License)**
+来源: https://github.com/soybeanjs/soybean-admin/blob/main/src/views/home/index.vue
+
+```vue
+
+```
+
+**架构特点:**
+- Index.vue 作为**容器组件**,只负责布局和响应式计算
+- 每个 modules/*.vue 是**独立的功能模块**
+- 模块命名清晰: header-banner, card-data, line-chart 等
+- 使用 Pinia store 进行状态共享
+
+**案例 2: Art Design Pro (MIT License)**
+来源: https://github.com/Daymychen/art-design-pro/blob/main/src/views/dashboard/ecommerce/index.vue
+
+```vue
+
+```
+
+**架构特点:**
+- 电商 dashboard 包含 13 个独立模块
+- 每个模块代表一个业务功能卡片
+- Index.vue **不传递数据**,模块自治
+
+---
+
+## 4. 模块间通信模式
+
+### 4.1 defineEmits 用于子到父通信
+来源: Vue 核心仓库 - https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiSetupHelpers.ts
+
+**TypeScript 类型声明模式:**
+```ts
+const emit = defineEmits<{
+ 'update:modelValue': [value: string];
+ 'change': [event: Event];
+ 'custom-event': [payload: CustomPayload];
+}>();
+```
+
+**Runtime 声明模式:**
+```js
+const emit = defineEmits(['change', 'update'])
+```
+
+### 4.2 Props 模式 - 数据传递 vs 自取数据
+
+**案例研究: Halo CMS (GPL-3.0)**
+来源: https://github.com/halo-dev/halo/blob/main/ui/console-src/modules/system/users/components/GrantPermissionModal.vue
+
+```vue
+
+```
+
+**模式总结:**
+- **Props 传递身份标识** (如 user ID),而非完整数据
+- **模块自己获取详细数据** (通过 composables)
+- 这样保持模块的**高内聚低耦合**
+
+---
+
+## 5. 何时模块应该自取数据 vs 接收 Props
+
+### 5.1 自取数据的场景
+- 模块是**独立的业务单元**(如日历、统计卡片)
+- 数据获取逻辑属于模块内部关注点
+- 模块需要**定期刷新**或**重新加载**数据
+- 多个平行模块各自管理自己的状态
+
+**示例:**
+```vue
+
+
+```
+
+### 5.2 接收 Props 的场景
+- 模块是**展示组件**(Presentational Component)
+- 父组件需要**协调多个子组件**的数据
+- 数据来源于**全局状态管理**(如 Pinia store)
+- 需要在父组件层面做**数据聚合或转换**
+
+**示例:**
+```vue
+
+
+```
+
+---
+
+## 6. TypeScript vs JavaScript 在 Vue 3 项目中
+
+### 6.1 EmailBill 项目的选择
+**当前状况:**
+- ESLint 配置中禁用了 TypeScript 规则
+- 使用 `
-
-
diff --git a/Web/src/views/calendarV2/Index.vue b/Web/src/views/calendarV2/Index.vue
new file mode 100644
index 0000000..6c36351
--- /dev/null
+++ b/Web/src/views/calendarV2/Index.vue
@@ -0,0 +1,380 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Web/src/views/calendarV2/modules/Calendar.vue b/Web/src/views/calendarV2/modules/Calendar.vue
new file mode 100644
index 0000000..c69fafc
--- /dev/null
+++ b/Web/src/views/calendarV2/modules/Calendar.vue
@@ -0,0 +1,453 @@
+
+
+
+
+
+ {{ day }}
+
+
+
+
+
+
+
+
+
+ {{ day.dayNumber }}
+
+
+ {{ day.amount }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Web/src/views/calendarV2/modules/Stats.vue b/Web/src/views/calendarV2/modules/Stats.vue
new file mode 100644
index 0000000..81a2953
--- /dev/null
+++ b/Web/src/views/calendarV2/modules/Stats.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+ {{ isToday ? '今日支出' : '当日支出' }}
+
+
+ ¥{{ selectedDayExpense.toFixed(2) }}
+
+
+
+
+
+
+
+ {{ isToday ? '今日收入' : '当日收入' }}
+
+
+ ¥{{ selectedDayIncome.toFixed(2) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/Web/src/views/calendarV2/modules/TransactionList.vue b/Web/src/views/calendarV2/modules/TransactionList.vue
new file mode 100644
index 0000000..860573d
--- /dev/null
+++ b/Web/src/views/calendarV2/modules/TransactionList.vue
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+ 当天暂无交易记录
+
+
+ 轻松享受无消费的一天 ✨
+
+
+
+
+
+
+
+
+
+ {{ txn.amount }}
+
+
+
+
+
+
+
+
+