- users 表添加 nickname、avatar_url 字段 - 用户信息 API(GET/PUT /me)+ 头像上传(multer) - 头像通过 API 路由获取(公开,不经过 auth) - 登录接口返回用户昵称和头像 - 用户信息 Store + 个人资料编辑页面 - 我的页面和首页显示真实用户信息 - 群组表(groups、group_members)+ transactions 添加 group_id - 群组 API(创建/加入/退出/解散) - 交易和统计 API 支持 group_id 视图切换 - 群组客户端 Store + 身份切换 - 群组管理页面 - App 初始化群组 Store - UPLOAD_DIR 配置化 - Node.js 备份替代 mysqldump - 统一前端 BASE_URL(config.ts) - uploads 加入 .gitignore - 修复 trust proxy 警告
223 lines
8.0 KiB
Markdown
223 lines
8.0 KiB
Markdown
# 小菜记账 (Xiaocai Accounting)
|
||
|
||
可爱 × 高级的个人记账小程序。让记账从负担变成享受。
|
||
|
||
## Tech Stack
|
||
|
||
### 前端 (client/)
|
||
- **框架**: Uni-app (Vue 3 + Composition API)
|
||
- **状态管理**: Pinia
|
||
- **样式**: SCSS (Claymorphism 风格)
|
||
- **图标**: Lucide Icons (SVG 组件,禁止 emoji)
|
||
- **图表**: uCharts (小程序端)
|
||
- **目标平台**: 微信小程序 / H5
|
||
|
||
### 后端 (server/)
|
||
- **运行时**: Node.js + Express
|
||
- **数据库**: MySQL 8.0 (mysql2 连接池)
|
||
- **认证**: HMAC-SHA256 签名 token,30 天过期
|
||
- **文件上传**: multer (头像,最大 2MB)
|
||
- **备份**: Node.js mysql2 导出 (不依赖 mysqldump)
|
||
- **CORS**: 已配置,支持 credentials
|
||
|
||
## Design System
|
||
|
||
完整设计规格: `docs/superpowers/specs/2026-05-27-xiaocai-design.md`
|
||
|
||
### 核心设计语言: Claymorphism (软3D粘土风格)
|
||
|
||
- **主色调**: 珊瑚橙 `#FF8C69` — 温暖、活泼、有亲和力
|
||
- **背景色**: 暖奶油 `#FFF8F0` — 比纯白更柔和
|
||
- **文字色**: 暖深棕 `#2D1B1B` — 不用纯黑
|
||
- **圆角**: 卡片 20px, 按钮 14-16px
|
||
- **阴影**: 双层 (外阴影 + 内阴影,模拟粘土质感)
|
||
|
||
### 字体
|
||
- 英文: Fredoka (标题) + Nunito (正文)
|
||
- 中文: PingFang SC / 系统默认
|
||
- 数字和金额使用 Fredoka,等宽数字
|
||
|
||
### 关键原则
|
||
- 最小触摸目标 44×44px
|
||
- 禁止使用 emoji 作为图标,统一使用 Icon 组件
|
||
- 尊重 prefers-reduced-motion
|
||
- 文字对比度 ≥ 4.5:1 (WCAG AA)
|
||
|
||
### 小程序胶囊适配
|
||
- 微信小程序右上角有胶囊按钮,页面顶部右侧元素(图标、按钮)需避开
|
||
- 使用 `system.ts` 导出的 `capsuleRight` 计算安全距离
|
||
- 导航栏添加动态 padding: `:style="{ paddingRight: capsuleRight + 'px' }"`
|
||
- 居中标题页面(统计、账单、我的)不需要处理
|
||
- 有右侧元素的页面(首页 bell、编辑页保存按钮)必须处理
|
||
|
||
## Project Conventions
|
||
|
||
### 命名
|
||
- 目录: kebab-case (`category-manage/`, `transaction-item/`)
|
||
- 组件: PascalCase (`AmountCard.vue`, `TransactionItem.vue`)
|
||
- 变量/函数: camelCase (`totalExpense`, `formatAmount()`)
|
||
- 常量: UPPER_SNAKE_CASE (`MAX_BUDGET`, `STORAGE_KEY`)
|
||
- CSS 类: BEM 或 Tailwind 风格
|
||
|
||
### 文件组织
|
||
```
|
||
client/src/
|
||
├── pages/ # 页面 (uni-app 规范)
|
||
│ ├── index/ # 首页仪表盘
|
||
│ ├── add/ # 添加/编辑记录
|
||
│ ├── stats/ # 统计分析
|
||
│ ├── bills/ # 全部账单 (下拉刷新/上拉加载)
|
||
│ ├── profile/ # 我的(身份切换入口)
|
||
│ ├── profile-edit/ # 编辑资料(昵称+头像)
|
||
│ ├── group-manage/ # 群组管理(创建/加入/退出/解散)
|
||
│ ├── category-manage/ # 分类管理
|
||
│ └── budget/ # 预算设置
|
||
├── components/ # 公共组件
|
||
│ ├── BudgetBar/ # 预算进度条
|
||
│ ├── CategoryIcon/ # 分类图标 (首字+颜色)
|
||
│ ├── Icon/ # 图标组件 (PNG 映射)
|
||
│ ├── Numpad/ # 数字键盘
|
||
│ ├── Skeleton/ # 骨架屏
|
||
│ └── TransactionItem/ # 交易列表项
|
||
├── stores/ # Pinia stores
|
||
│ ├── transaction.ts # 交易 CRUD (自动传递 group_id)
|
||
│ ├── category.ts # 分类 CRUD
|
||
│ ├── budget.ts # 预算管理
|
||
│ ├── stats.ts # 统计概览 (自动传递 group_id)
|
||
│ ├── user.ts # 用户信息 (昵称/头像)
|
||
│ └── group.ts # 群组管理 (身份切换)
|
||
├── api/ # API 封装
|
||
│ ├── auth.ts # 登录接口
|
||
│ ├── transaction.ts # 交易接口
|
||
│ ├── stats.ts # 统计接口
|
||
│ ├── user.ts # 用户信息接口 (含头像上传)
|
||
│ └── group.ts # 群组接口
|
||
├── utils/
|
||
│ ├── format.ts # 金额/日期格式化
|
||
│ ├── request.ts # HTTP 请求封装 (401 自动重登录+队列重试)
|
||
│ ├── system.ts # 系统信息 (statusBarHeight, capsuleRight)
|
||
│ └── app-ready.ts # App 启动就绪机制 (waitForReady)
|
||
├── config.ts # 全局配置 (API_BASE)
|
||
└── static/icons/ # tabBar 图标 (PNG)
|
||
|
||
server/src/
|
||
├── index.ts # Express 入口 (CORS, JSON, 静态文件, 路由注册)
|
||
├── middleware/auth.ts # HMAC token 验证 (timingSafeEqual)
|
||
├── routes/
|
||
│ ├── auth.ts # 登录 / token 签发 (返回用户信息)
|
||
│ ├── transaction.ts # 交易 CRUD (支持 group_id 视图切换)
|
||
│ ├── category.ts # 分类 CRUD (默认+自定义)
|
||
│ ├── budget.ts # 预算 CRUD (按月)
|
||
│ ├── stats.ts # 统计查询 (支持 group_id)
|
||
│ ├── user.ts # 用户信息 + 头像上传
|
||
│ ├── group.ts # 群组 CRUD (创建/加入/退出/解散)
|
||
│ └── backup.ts # 备份 API
|
||
├── utils/
|
||
│ ├── backup.ts # Node.js 数据库备份 (gzip)
|
||
│ └── date.ts # 日期工具
|
||
└── db/
|
||
├── connection.ts # MySQL 连接池
|
||
├── init.ts # 建表 + seed + 迁移 (幂等)
|
||
├── schema.sql # 表结构
|
||
└── seed.sql # 默认分类数据
|
||
```
|
||
|
||
### 数据库表
|
||
- `users` — 用户 (openid, nickname, avatar_url)
|
||
- `categories` — 分类 (user_id=0 默认, 其他=自定义)
|
||
- `transactions` — 交易记录 (user_id, group_id, amount 分)
|
||
- `budgets` — 预算 (user_id, month, amount)
|
||
- `groups` — 群组 (name, invite_code, created_by)
|
||
- `group_members` — 群组成员 (group_id, user_id, role)
|
||
|
||
### 金额处理
|
||
- 存储单位: 分 (整数,避免浮点精度问题)
|
||
- 显示单位: 元 (保留两位小数)
|
||
- 格式化: `¥ 1,234.56` (¥ 后空格,千分位分隔)
|
||
- 收入前缀 `+`,支出前缀 `-`
|
||
- 使用 `formatAmount()` 带 ¥ 前缀,`formatAmountRaw()` 纯数字
|
||
|
||
### 数据持久化
|
||
- 前端本地存储 Key:
|
||
- `xc:token` — 认证 token
|
||
- `xc:userId` — 用户 ID
|
||
- `xc:nickname` — 用户昵称
|
||
- `xc:avatar_url` — 头像文件名
|
||
- `xc:currentGroupId` — 当前选中群组 ID (null=个人模式)
|
||
- 后端 MySQL 数据库
|
||
- API 基础地址: `config.ts` 中的 `API_BASE`
|
||
|
||
### 认证流程
|
||
- H5: 页面加载时自动 demo-login 获取 token
|
||
- 微信小程序: `App.vue` onLaunch 调用 `wx.login` 获取 code,换 token
|
||
- Token: HMAC-SHA256 签名,30 天过期
|
||
- 401 处理: 请求入队 → 自动重登录 → 队列中所有请求重试
|
||
- 启动就绪: `app-ready.ts` 的 `waitForReady()` 确保页面在登录完成后才加载数据
|
||
|
||
### 一起记 (群组)
|
||
- 群组仅做数据聚合,记录始终属于记录者 (user_id)
|
||
- 个人视图: `WHERE user_id = 我` (所有记录)
|
||
- 群组视图: `WHERE group_id = X AND user_id IN (当前成员)`
|
||
- 退出群组: 该用户的 group_id 设为 NULL,记录回到个人视图
|
||
- 身份切换: 「我的」页底部弹窗选择,全局生效
|
||
|
||
### Git
|
||
- 分支: `master` → `main` (注意远程)
|
||
- Commit 风格: 中文描述,简洁明了
|
||
- `feat: 添加记账页面`
|
||
- `fix: 修复金额计算精度问题`
|
||
|
||
## Commands
|
||
|
||
```bash
|
||
# 前端开发 (H5)
|
||
cd client && npm run dev:h5
|
||
|
||
# 前端开发 (微信小程序)
|
||
cd client && npm run dev:mp-weixin
|
||
|
||
# 前端构建
|
||
cd client && npm run build:mp-weixin
|
||
|
||
# 后端开发
|
||
cd server && npm run dev
|
||
|
||
# 后端构建
|
||
cd server && npm run build
|
||
|
||
# 数据库初始化
|
||
cd server && npm run db:init
|
||
```
|
||
|
||
## 部署
|
||
|
||
- 开发服务: `dev.xiaocai.j35.site:3000`
|
||
- 正式服务: `xiaocai.j35.site`
|
||
- MySQL: 本地 3306 端口
|
||
- 小程序开发版自动连接 dev 服务,正式版/H5 连接线上 (config.ts)
|
||
|
||
### 手动部署步骤
|
||
|
||
```bash
|
||
# 1. 本地构建后端
|
||
cd server && npm run build
|
||
|
||
# 2. 复制 dist 目录到服务器
|
||
scp -r server/dist/* root@106.14.208.43:/var/www/xiaocai/
|
||
|
||
# 3. SSH 到服务器
|
||
ssh root@106.14.208.43
|
||
|
||
# 4. 安装依赖(如 node_modules 已存在可跳过)
|
||
cd /var/www/xiaocai && npm install --production
|
||
|
||
# 5. 重启服务
|
||
pm2 restart xiaocai-server
|
||
# 或直接运行
|
||
NODE_ENV=production node dist/index.js
|
||
```
|
||
|
||
## 开发
|
||
|
||
@DEV.md
|