Files
accounting/项目计划书.md
2026-03-26 01:23:19 +08:00

40 KiB
Executable File
Raw Blame History

记账助手 - 项目计划书

个人记账 Web 应用,用于日常收支记录、分类管理、统计分析和余额追踪。


一、项目概述

1.1 项目信息

项 目 说 明
项目名称 记账助手
项目类型 个人记账 Web 应用
架构模式 前后端分离SPA + REST API
部署方式 生产环境后端 serve 前端静态文件,单端口部署

1.2 技术栈

技术 版本
前端框架 Vue 3 (Composition API + <script setup>) 3.5.12
构建工具 Vite 5.4.11
UI 组件库 Element Plus (中文 locale) 2.8.8
状态管理 Pinia 2.2.6
路由 Vue Router 4 (History 模式) 4.4.5
HTTP 客户端 Axios 1.7.7
图表库 ECharts 5.5.1
后端框架 Express 4.21.0
数据库 sql.js内存 SQLite文件持久化 1.11.0

1.3 项目目录结构

记账/
├── package.json              # 根 monorepo 脚本 (concurrently 并行启动前后端)
├── client/                   # 前端工程
│   ├── index.html            # SPA 入口 (lang="zh-CN")
│   ├── vite.config.js        # 开发代理 + 手动 chunk 分包
│   ├── package.json
│   └── src/
│       ├── main.js           # 应用初始化 (Vue + Router + Pinia + ElementPlus)
│       ├── App.vue           # 根组件 (Navbar + <router-view>)
│       ├── api/index.js      # Axios 封装 + 全部 API 定义
│       ├── router/index.js   # 路由配置 (3 个页面)
│       ├── stores/           # Pinia 状态管理
│       │   ├── records.js    # 记录 CRUD + 分类列表
│       │   └── statistics.js # 统计数据 + 余额
│       ├── views/            # 页面组件
│       │   ├── Dashboard.vue # 总览页
│       │   ├── DailyInput.vue# 记账页
│       │   └── Statistics.vue# 统计页
│       ├── components/       # 可复用组件
│       │   ├── Navbar.vue
│       │   ├── BalanceCard.vue
│       │   ├── SummaryCards.vue
│       │   ├── RecordForm.vue
│       │   ├── RecordTable.vue
│       │   ├── TrendChart.vue
│       │   └── CategoryPieChart.vue
│       └── styles/
│           └── global.css    # 全局样式 + 颜色变量
└── server/                   # 后端工程
    ├── index.js              # Express 入口 + 中间件 + 静态文件
    ├── db.js                 # sql.js 初始化 + 建表 + DbWrapper
    ├── package.json
    ├── routes/
    │   ├── records.js        # CRUD /api/records
    │   ├── categories.js     # CRUD /api/categories
    │   ├── statistics.js     # 多维度统计 /api/statistics/*
    │   └── balance.js        # 余额管理 /api/balance
    └── data/
        └── accounting.db     # SQLite 数据库文件 (运行时生成)

二、数据库设计

2.1 ER 关系图

┌─────────────────────┐       ┌─────────────────────────────┐
│   balance_settings  │       │         categories          │
├─────────────────────┤       ├─────────────────────────────┤
│ id          INTEGER │       │ id          INTEGER  PK AI  │
│   (固定=1, 单行表)  │       │ name        TEXT  NOT NULL   │
│ initial_balance REAL│       │             UNIQUE           │
│ updated_at DATETIME │       │ type        TEXT  NOT NULL   │
└─────────────────────┘       │             DEFAULT 'expense'│
                              │ icon        TEXT             │
                              │ sort_order  INTEGER  DEF 0  │
                              │ created_at  DATETIME        │
                              └──────────┬──────────────────┘
                                         │
                                         │ 1:N (category_id FK)
                                         │
                              ┌──────────┴──────────────────┐
                              │          records            │
                              ├─────────────────────────────┤
                              │ id          INTEGER  PK AI  │
                              │ date        TEXT  NOT NULL   │
                              │ type        TEXT  NOT NULL   │
                              │ category_id INTEGER  FK     │
                              │ amount      REAL  NOT NULL   │
                              │             DEFAULT 0       │
                              │ note        TEXT             │
                              │ created_at  DATETIME        │
                              │ updated_at  DATETIME        │
                              └─────────────────────────────┘

2.2 表结构详细说明

表 1categories分类表

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
name TEXT NOT NULL, UNIQUE 分类名称,全局唯一
type TEXT NOT NULL, DEFAULT 'expense' 类型:income(收入)/ expense(支出)
icon TEXT 可空 Element Plus 图标名称
sort_order INTEGER DEFAULT 0 排序权重(升序排列)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间

表 2records记录表

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
date TEXT NOT NULL 记录日期,格式 YYYY-MM-DD
type TEXT NOT NULL 类型:income / expense
category_id INTEGER NOT NULL, FOREIGN KEY → categories.id 关联分类
amount REAL NOT NULL, DEFAULT 0 金额(非负数)
note TEXT 可空 备注
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP 更新时间

索引:

  • idx_records_daterecords(date) — 按日期查询加速
  • idx_records_typerecords(type) — 按类型过滤加速

表 3balance_settings余额设置表

字段 类型 约束 说明
id INTEGER PRIMARY KEY, 固定值 1 单行表,只有一条记录
initial_balance REAL NOT NULL, DEFAULT 0 用户设置的初始余额
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP 更新时间

余额计算公式:

当前余额 = initial_balance + SUM(所有收入) - SUM(所有支出)

2.3 预置种子数据15 个默认分类)

sort_order name type icon
1 工资 income Money
2 利息 income Coin
3 其他收入 income Plus
10 餐饮 expense Bowl
11 交通 expense Van
12 购物 expense ShoppingCart
13 话费 expense Phone
14 水电费 expense Lightning
15 物业费 expense House
16 云服务 expense Monitor
17 火车票 expense Ticket
18 机票 expense Position
19 公益 expense Star
20 还款 expense CreditCard
99 其他 expense More

三、API 接口设计

3.1 接口总览

模块 方法 路径 功能
记录 GET /api/records 查询记录(支持按日期/月份/分页)
POST /api/records 创建记录
PUT /api/records/:id 更新记录(部分更新)
DELETE /api/records/:id 删除记录
分类 GET /api/categories 查询分类(可按类型过滤)
POST /api/categories 创建分类
PUT /api/categories/:id 更新分类
DELETE /api/categories/:id 删除分类(有关联记录时禁止)
统计 GET /api/statistics/daily 日统计
GET /api/statistics/weekly 周统计(周一至周日)
GET /api/statistics/monthly 月统计
GET /api/statistics/yearly 年统计
GET /api/statistics/balance 余额查询
GET /api/statistics/trend 趋势数据(日期范围)
余额 GET /api/balance 获取余额信息
PUT /api/balance 设置初始余额

3.2 记录接口详细设计

GET /api/records — 查询记录

Query Parameters:
  date   (可选) YYYY-MM-DD — 精确日期查询
  month  (可选) YYYY-MM   — 按月份查询
  page   (可选) Integer   — 分页页码
  limit  (可选) Integer   — 每页条数,默认 50

Response 200:
[
  {
    "id": 1,
    "date": "2026-03-08",
    "type": "expense",
    "category_id": 4,
    "amount": 35.50,
    "note": "午餐",
    "created_at": "2026-03-08T12:00:00",
    "updated_at": "2026-03-08T12:00:00",
    "category_name": "餐饮",
    "category_type": "expense",
    "category_icon": "Bowl"
  }
]

排序: date DESC, created_at DESC

POST /api/records — 创建记录

Request Body (必填):
{
  "date": "2026-03-08",          // YYYY-MM-DD
  "type": "expense",             // income | expense
  "category_id": 4,              // 必须存在于 categories 表
  "amount": 35.50,               // 非负数
  "note": "午餐"                 // 可选
}

Response 201: 完整记录对象(含关联分类信息)

验证规则:
  - date, type, category_id, amount 为必填
  - amount 不能为负数

PUT /api/records/:id — 更新记录

Path: :id — 记录 ID
Request Body (部分更新): { date?, type?, category_id?, amount?, note? }
Response 200: 更新后的完整记录对象
Response 404: { "error": "记录不存在" }
自动更新 updated_at

DELETE /api/records/:id — 删除记录

Path: :id — 记录 ID
Response 200: { "message": "删除成功" }
Response 404: { "error": "记录不存在" }

3.3 分类接口详细设计

GET /api/categories

Query: type (可选) — income | expense
Response 200: 分类数组,按 sort_order 升序

POST /api/categories

Request Body:
{
  "name": "娱乐",               // 必填,唯一
  "type": "expense",            // 默认 expense
  "icon": "Headset",            // 可选
  "sort_order": 21              // 可选,默认 0
}
Response 201: 新分类对象
Response 400: { "error": "分类名称不能为空" }
Response 400: { "error": "分类名称已存在" }

PUT /api/categories/:id

Request Body (部分更新): { name?, type?, icon?, sort_order? }
Response 200: 更新后的分类对象
Response 404: { "error": "分类不存在" }

DELETE /api/categories/:id

Response 200: { "message": "删除成功" }
Response 400: { "error": "该分类下存在记录,无法删除" }
Response 404: { "error": "分类不存在" }
业务规则: 有关联记录的分类不可删除

3.4 统计接口详细设计

GET /api/statistics/daily

Query (必填): date=YYYY-MM-DD

Response 200:
{
  "date": "2026-03-08",
  "income": 0,
  "expense": 85.50,
  "balance": -85.50,
  "categories": [
    { "name": "餐饮", "icon": "Bowl", "total": 55.00 },
    { "name": "交通", "icon": "Van", "total": 30.50 }
  ]   // 支出分类排行,按金额降序
}

GET /api/statistics/weekly

Query (必填): date=YYYY-MM-DD (该日所在周)

Response 200:
{
  "startDate": "2026-03-02",     // 周一
  "endDate": "2026-03-08",       // 周日
  "income": 5000,
  "expense": 1200,
  "balance": 3800,
  "dailyData": [
    { "date": "2026-03-02", "type": "expense", "total": 150 },
    { "date": "2026-03-02", "type": "income", "total": 5000 }
  ],   // 每日收支明细,按日期升序
  "categories": [...]            // 周支出分类排行
}

GET /api/statistics/monthly

Query (必填): month=YYYY-MM

Response 200:
{
  "month": "2026-03",
  "income": 8000,
  "expense": 3500,
  "balance": 4500,
  "dailyData": [...],            // 每日收支明细
  "categories": [...]            // 月支出分类排行
}

GET /api/statistics/yearly

Query (必填): year=YYYY

Response 200:
{
  "year": "2026",
  "income": 96000,
  "expense": 45000,
  "balance": 51000,
  "monthlyData": [
    { "month": "2026-01", "type": "expense", "total": 3800 },
    { "month": "2026-01", "type": "income", "total": 8000 }
  ],   // 每月收支明细,按月份升序
  "categories": [...]            // 年支出分类排行
}

GET /api/statistics/balance

Response 200:
{
  "initial_balance": 10000,
  "total_income": 96000,
  "total_expense": 45000,
  "current_balance": 61000       // = 10000 + 96000 - 45000
}

GET /api/statistics/trend

Query (必填): start=YYYY-MM-DD & end=YYYY-MM-DD

Response 200:
[
  { "date": "2026-03-01", "type": "expense", "total": 200 },
  { "date": "2026-03-01", "type": "income", "total": 8000 }
]   // 按日期升序

3.5 余额接口详细设计

GET /api/balance

Response 200:
{
  "initial_balance": 10000,
  "total_income": 96000,
  "total_expense": 45000,
  "current_balance": 61000
}

PUT /api/balance

Request Body (必填):
{ "initial_balance": 15000 }

Response 200: 更新后的完整余额信息
Response 400: { "error": "请提供初始余额" }

四、页面设计

4.1 全局布局

┌──────────────────────────────────────────────────────────┐
│  [钱包图标] 记账助手          │  总览  │  记账  │  统计  │  ← 顶部导航栏 (sticky, 56px)
├──────────────────────────────────────────────────────────┤
│                                                          │
│                    <router-view />                        │  ← 主内容区
│                    max-width: 1200px                      │     居中布局
│                    padding: 20px                          │
│                                                          │
└──────────────────────────────────────────────────────────┘
背景色: #f5f7fa

导航栏 Navbar

  • 固定在页面顶部 (position: sticky)
  • 左侧:钱包图标 + "记账助手" 品牌文字(蓝色 #409eff
  • 右侧:三个导航链接,当前页面高亮(浅蓝背景 #ecf5ff + 加粗)
  • 阴影效果:0 2px 8px rgba(0,0,0,0.08)

颜色体系:

语义 颜色 CSS 类 用途
收入 #67c23a (绿) .text-income 收入金额、收入标签
支出 #f56c6c (红) .text-expense 支出金额、支出标签
结余 #409eff (蓝) .text-balance 余额、品牌色

响应式断点:

  • ≥ 768px:图表区域双列布局
  • < 768px:单列堆叠
  • ≥ 640px:汇总卡片三列
  • < 640px:汇总卡片单列

4.2 页面一:总览页 Dashboard路由 /

页面标题: "总览 - 记账助手"

布局结构:

┌──────────────────────────────────────────────────────────┐
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │        ✨ 余额卡片 (BalanceCard)  ✨                │  │
│  │   渐变背景 #667eea → #764ba2                       │  │
│  │                                                    │  │
│  │              "当前余额"                             │  │
│  │           ¥ 61,000.00                              │  │
│  │         (32px 加粗白色字)                           │  │
│  │          "点击设置初始余额"                          │  │
│  │                                                    │  │
│  │   呼吸动画 (3秒循环缩放 1→1.02)                    │  │
│  │   悬停: scale(1.01) + 阴影增强                     │  │
│  │   点击: 弹出修改初始余额对话框                      │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐     │
│  │  本月收入     │ │  本月支出     │ │  本月结余     │     │
│  │  ¥8,000.00   │ │  ¥3,500.00   │ │  ¥4,500.00   │     │
│  │  (绿色)      │ │  (红色)      │ │  (蓝色)      │     │
│  └──────────────┘ └──────────────┘ └──────────────┘     │
│         ↑ SummaryCards 组件 — 三列网格                    │
│                                                          │
│  ┌─────────────────────┐ ┌─────────────────────┐        │
│  │  本月支出趋势        │ │  支出分类            │        │
│  │  (TrendChart)       │ │  (CategoryPieChart) │        │
│  │                     │ │                     │        │
│  │  折线图 + 面积       │ │  环形饼图            │        │
│  │  红色渐变填充        │ │  内半径40% 外70%    │        │
│  │  X: 日期 (MM-DD)    │ │  右侧图例           │        │
│  │  Y: 金额 ¥          │ │  Tooltip: 名称+%   │        │
│  │  smooth 平滑曲线     │ │                     │        │
│  │  高度: 320px        │ │  高度: 320px        │        │
│  └─────────────────────┘ └─────────────────────┘        │
│         ↑ 双列布局 (768px 以下单列)                       │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  最近记录 (el-table)                                │  │
│  │  ┌────────┬──────────┬──────────┬─────────┐        │  │
│  │  │  日期   │  分类     │  金额    │  备注   │        │  │
│  │  ├────────┼──────────┼──────────┼─────────┤        │  │
│  │  │03-08   │ 🏷餐饮   │ -¥55.00  │ 午餐    │        │  │
│  │  │        │ (红tag)  │ (红字)   │         │        │  │
│  │  │03-08   │ 🏷工资   │ +¥8000   │ 3月薪资 │        │  │
│  │  │        │ (绿tag)  │ (绿字)   │         │        │  │
│  │  └────────┴──────────┴──────────┴─────────┘        │  │
│  │  显示最近 20 条记录                                  │  │
│  │  分类列: Tag 组件 (income→success绿, expense→danger红)│  │
│  │  金额列: 收入 +¥ 绿色 / 支出 -¥ 红色                │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
└──────────────────────────────────────────────────────────┘

初始余额修改对话框:

┌─── 设置初始余额 ──────────────┐
│                               │
│  初始余额:  [ 10000.00  ▲▼ ] │  ← el-input-number
│             precision: 2      │     step: 100
│                               │
│          [取消]  [确认]        │
└───────────────────────────────┘

数据加载时机: 页面挂载时并行加载余额、当月统计、当月记录


4.3 页面二:记账页 DailyInput路由 /input

页面标题: "记账 - 记账助手"

布局结构:

┌──────────────────────────────────────────────────────────┐
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │   [◀]    📅 2026-03-08 (日期选择器)    [▶]  [今天] │  │
│  │                                                    │  │
│  │   ◀ 前一天 / ▶ 后一天 / 今天按钮快速跳转            │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  记录表单 (RecordForm)                              │  │
│  │                                                    │  │
│  │  类型:  ○ 支出(默认)  ○ 收入                       │  │
│  │                                                    │  │
│  │  分类:  [  下拉选择  ▼ ]                            │  │
│  │         (根据类型自动过滤可选分类)                    │  │
│  │         (切换类型时清空已选分类)                      │  │
│  │                                                    │  │
│  │  金额:  [ 0.00      ▲▼ ]                           │  │
│  │         step: 10, precision: 2                     │  │
│  │                                                    │  │
│  │  备注:  [ 输入备注(可选)    ]                      │  │
│  │         (支持回车直接提交)                           │  │
│  │                                                    │  │
│  │  [          添加记录          ]                     │  │
│  │                                                    │  │
│  │  验证: 分类必选 + 金额 > 0                          │  │
│  │  提交后: 重置金额和备注,保留类型和分类               │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  当日记录列表 (RecordTable)                         │  │
│  │  ┌──────────┬──────────┬────────┬──────────────┐   │  │
│  │  │  分类     │  金额    │  备注   │  操作        │   │  │
│  │  ├──────────┼──────────┼────────┼──────────────┤   │  │
│  │  │ 🏷餐饮   │ -¥55.00  │ 午餐   │ [编辑][删除] │   │  │
│  │  │ 🏷交通   │ -¥30.50  │ 地铁   │ [编辑][删除] │   │  │
│  │  ├──────────┼──────────┼────────┼──────────────┤   │  │
│  │  │ 支出合计: ¥85.50 (红)  收入合计: ¥0.00 (绿) │   │  │
│  │  └──────────┴──────────┴────────┴──────────────┘   │  │
│  │                                                    │  │
│  │  空状态: "暂无记录"                                 │  │
│  │  条纹样式表格 + 加载遮罩                            │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
└──────────────────────────────────────────────────────────┘

编辑记录对话框:

┌─── 编辑记录 (宽 400px) ─────────┐
│                                  │
│  分类:  [  下拉选择  ▼ ]         │  ← 根据记录类型过滤
│                                  │
│  金额:  [ 55.00      ▲▼ ]       │
│                                  │
│  备注:  [ 午餐           ]       │
│                                  │
│          [取消]  [确认]           │
└──────────────────────────────────┘

交互流程:

  1. 页面加载 → 获取分类列表 + 当日记录
  2. 切换日期 → 自动拉取对应日期的记录
  3. 填写表单 → 提交 → 新记录插入到列表最前面 → 提示"添加成功"
  4. 点击编辑 → 弹出对话框 → 修改 → 提示"修改成功"
  5. 点击删除 → 确认后删除 → 提示"删除成功"

4.4 页面三:统计页 Statistics路由 /statistics

页面标题: "统计 - 记账助手"

布局结构:

┌──────────────────────────────────────────────────────────┐
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  维度切换: [日] [周] [月(默认)] [年]               │  │
│  │            ↑ el-radio-group 按钮组                  │  │
│  │                                                    │  │
│  │  日期选择: 📅 [  2026-03  ▼  ]                     │  │
│  │            ↑ 根据维度显示不同类型:                    │  │
│  │              日/周 → type="date"                    │  │
│  │              月   → type="month"                   │  │
│  │              年   → type="year"                    │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐     │
│  │  收入         │ │  支出         │ │  结余         │     │
│  │  ¥8,000.00   │ │  ¥3,500.00   │ │  ¥4,500.00   │     │
│  │  (绿色)      │ │  (红色)      │ │  (蓝色)      │     │
│  └──────────────┘ └──────────────┘ └──────────────┘     │
│         ↑ SummaryCards                                    │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  收支趋势对比 (ECharts 柱状图)                      │  │
│  │                                                    │  │
│  │  ██                                                │  │
│  │  ██ ██      ██                                     │  │
│  │  ██ ██  ██  ██ ██                                  │  │
│  │  ──────────────────                                │  │
│  │  3月  4月  5月  6月                                 │  │
│  │                                                    │  │
│  │  ■ 收入(绿色柱)  ■ 支出(红色柱)                    │  │
│  │  年维度: 按月展示 / 其他维度: 按日展示               │  │
│  │  高度: 320px                                       │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
│  ┌─────────────────────┐ ┌─────────────────────┐        │
│  │  分类排行            │ │  支出分类            │        │
│  │  (横向柱状图)        │ │  (CategoryPieChart) │        │
│  │                     │ │                     │        │
│  │  餐饮    ████████   │ │    环形饼图          │        │
│  │  交通    ██████     │ │                     │        │
│  │  购物    ████       │ │                     │        │
│  │                     │ │                     │        │
│  │  渐变色: 蓝→紫      │ │                     │        │
│  │  从低到高排序        │ │                     │        │
│  └─────────────────────┘ └─────────────────────┘        │
│         ↑ 双列布局                                       │
│                                                          │
│  ┌────────────────────────────────────────────────────┐  │
│  │  明细数据 (el-table)                                │  │
│  │  ┌────────┬──────────┬──────────┬─────────┐        │  │
│  │  │  日期 ↕ │  分类     │  金额 ↕  │  备注   │        │  │
│  │  ├────────┼──────────┼──────────┼─────────┤        │  │
│  │  │03-08   │ 🏷餐饮   │ -¥55.00  │ 午餐    │        │  │
│  │  └────────┴──────────┴──────────┴─────────┘        │  │
│  │  支持日期和金额列排序                                │  │
│  │  默认按日期倒序                                     │  │
│  └────────────────────────────────────────────────────┘  │
│                                                          │
└──────────────────────────────────────────────────────────┘

交互流程:

  1. 默认加载当月统计
  2. 切换维度 → 自动拉取对应维度的统计数据
  3. 更改日期 → 刷新所有图表和表格
  4. 图表自适应窗口大小 (resize 监听)

五、组件设计

5.1 组件层级关系

App.vue
├── Navbar.vue                        // 全局导航栏
└── <router-view>
    ├── Dashboard.vue                 // 总览页
    │   ├── BalanceCard.vue           //   余额卡片 + 修改对话框
    │   ├── SummaryCards.vue          //   收支汇总三卡片
    │   ├── TrendChart.vue            //   支出趋势折线图
    │   ├── CategoryPieChart.vue      //   分类饼图
    │   └── el-table (内联)            //   最近记录表格
    │
    ├── DailyInput.vue                // 记账页
    │   ├── RecordForm.vue            //   记录输入表单
    │   └── RecordTable.vue           //   当日记录列表 + 编辑对话框
    │
    └── Statistics.vue                // 统计页
        ├── SummaryCards.vue          //   收支汇总三卡片 (复用)
        ├── CategoryPieChart.vue      //   分类饼图 (复用)
        ├── ECharts (内联初始化)       //   趋势柱状图 + 排行图
        └── el-table (内联)            //   明细数据表格

5.2 组件 Props 接口

组件 Props 类型 默认值 说明
BalanceCard balance Number 0 当前余额
SummaryCards income Number 0 收入总额
expense Number 0 支出总额
TrendChart data Array [] 记录数据数组
title String '支出趋势' 图表标题
CategoryPieChart data Array [] [{name, total}]
title String '支出分类' 图表标题
RecordForm categories Array [] 可选分类列表
date String (必填) 当前日期
RecordTable records Array [] 记录列表
categories Array [] 分类列表
loading Boolean false 加载状态

5.3 组件 Events

组件 事件 载荷 说明
RecordForm submit {date, type, category_id, amount, note} 提交新记录
RecordTable edit {id, type, category_id, amount, note} 编辑记录
delete id 删除记录

六、状态管理设计

6.1 Records Store

┌─ records store ──────────────────────────┐
│                                          │
│  State:                                  │
│    records: []          // 当前记录列表    │
│    categories: []       // 全部分类列表    │
│    loading: false       // 加载状态        │
│                                          │
│  Actions:                                │
│    fetchCategories()    → GET /categories │
│    fetchByDate(date)    → GET /records    │
│    fetchByMonth(month)  → GET /records    │
│    addRecord(data)      → POST /records   │
│    updateRecord(id,data)→ PUT /records/:id│
│    deleteRecord(id)     → DELETE /records │
│                                          │
│  数据更新策略:                             │
│    add    → unshift 到数组前端             │
│    update → 原地替换                      │
│    delete → filter 过滤                   │
│                                          │
└──────────────────────────────────────────┘

6.2 Statistics Store

┌─ statistics store ───────────────────────┐
│                                          │
│  State:                                  │
│    balanceInfo: {                         │
│      initial_balance: 0                  │
│      total_income: 0                     │
│      total_expense: 0                    │
│      current_balance: 0                  │
│    }                                     │
│    monthlyStats: null                    │
│    loading: false                        │
│                                          │
│  Actions:                                │
│    fetchBalance()              → 持久state│
│    updateInitialBalance(amt)   → 持久state│
│    fetchMonthlyStats(month)    → 持久state│
│    fetchDailyStats(date)       → 直接返回  │
│    fetchWeeklyStats(date)      → 直接返回  │
│    fetchYearlyStats(year)      → 直接返回  │
│    fetchTrend(start, end)      → 直接返回  │
│                                          │
└──────────────────────────────────────────┘

七、关键设计决策

7.1 数据库选型 — sql.js

  • 采用 sql.js 在内存中运行 SQLite无需安装原生数据库
  • 每次写操作后自动调用 saveDb() 将内存数据导出到 data/accounting.db 文件
  • DbWrapper 封装了 all() / get() / run() 三个方法,屏蔽了 sql.js 底层 prepare/step/getAsObject 的复杂性
  • 适合个人使用场景,不适合高并发

7.2 开发与生产环境

环境 前端 后端 API 通信
开发 Vite dev server :5173 Express :3000 Vite proxy /api → :3000
生产 构建为 client/dist 静态文件 Express :3000 serve 静态文件 同源直接请求

7.3 前端构建优化 — 手动 chunk 分包

manualChunks: {
  'element-plus': ['element-plus'],    // UI 组件库独立包
  'echarts': ['echarts'],              // 图表库独立包
  'vue': ['vue', 'vue-router', 'pinia'] // Vue 核心独立包
}

7.4 SPA 路由支持

生产环境下,后端对所有非 /api 开头的请求返回 index.html确保前端路由History 模式)正常工作。

7.5 API 响应拦截

Axios response interceptor 自动提取 response.dataStore 层无需手动解包。


八、样式规范

8.1 全局样式 Token

Token 用途
字体 PingFang SC, Microsoft YaHei, sans-serif 中文优先字体栈
等宽数字字体 Menlo, Monaco, Consolas, monospace 金额展示
页面背景 #f5f7fa 全局浅灰背景
文字颜色 #303133 主要文字
次要文字 #909399 标签、说明
卡片圆角 12px 统一圆角
卡片阴影 0 4px 12px rgba(0,0,0,0.08) 统一浮起效果
余额卡片渐变 #667eea → #764ba2 (135deg) 主视觉焦点

8.2 动画

动画 属性 说明
呼吸动画 scale(1) → scale(1.02)3s 循环 余额卡片
悬停缩放 scale(1.01)0.3s ease 余额卡片 hover
过渡 transition: all 0.3s ease 通用过渡