Files
hejiu/docs/API接口文档.md
T
cg b95243c8f8 docs(api): 更新API接口文档并调整应用配置
- 添加完整的后端接口文档,包含用户、打卡记录、统计等模块
- 修复应用名称从"喝酒了么"统一更正为"喝了么"
- 重构App.vue中的启动逻辑,增加数据迁移和路由守卫功能
- 调整DrinkCalendar组件的UI间距和尺寸参数
- 优化DrinkCard组件的品牌展示文案
- 修改manifest.json中的应用描述和微信小程序配置
- 调整pages.json中的页面路径顺序和tabBar配置
- 更新全局样式文件中的应用名称标识
- 修改mock数据中的用户头像默认值
- 优化卡片导出功能的绘制逻辑和视觉效果
2026-07-14 23:27:23 +08:00

701 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 喝了么 - 后端接口文档
> 版本: v1.0
> 日期: 2026-07-13
> 小程序: 喝了么(uni-app 微信小程序)
> 基础URL: `https://your-domain.com/api/v1`
---
## 1. 通用说明
### 1.1 请求格式
- Content-Type: `application/json`
- 鉴权方式: 请求头 `Authorization: Bearer {token}`(微信登录获取)
- 所有时间字段使用 ISO 8601 格式
### 1.2 统一响应格式
```json
{
"code": 0,
"message": "success",
"data": {}
}
```
| code | 含义 |
|------|------|
| 0 | 成功 |
| 400 | 参数错误 |
| 401 | 未登录/token过期 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 500 | 服务器错误 |
### 1.3 分页参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | int | 否 | 页码,默认1 |
| pageSize | int | 否 | 每页数量,默认20 |
### 1.4 分页响应
```json
{
"code": 0,
"data": {
"list": [],
"total": 100,
"page": 1,
"pageSize": 20
}
}
```
---
## 2. 用户模块
### 2.1 微信登录
```
POST /auth/wechat-login
```
**请求参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | 是 | 微信登录codewx.login获取) |
| nickName | string | 否 | 用户昵称 |
| avatarUrl | string | 否 | 头像URL |
**响应 data**
```json
{
"token": "jwt_token_xxx",
"user": {
"id": "user_001",
"nickname": "酒友小王",
"avatar": "https://xxx/avatar.jpg",
"joinedAt": "2026-01-15T00:00:00.000Z",
"preferences": {
"favoriteCategories": ["baijiu", "beer"],
"frequency": "often"
}
},
"isNew": false
}
```
### 2.2 获取用户信息
```
GET /user/profile
```
**响应 data**
```json
{
"id": "user_001",
"nickname": "酒友小王",
"avatar": "https://xxx/avatar.jpg",
"joinedAt": "2026-01-15T00:00:00.000Z",
"preferences": {
"favoriteCategories": ["baijiu", "beer"],
"frequency": "often"
}
}
```
### 2.3 更新用户偏好
```
PUT /user/preferences
```
**请求参数:**
```json
{
"favoriteCategories": ["baijiu", "beer"],
"frequency": "often"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| favoriteCategories | string[] | 偏好酒类ID列表 |
| frequency | string | 饮酒频率:rarely / sometimes / often |
---
## 3. 打卡记录模块(核心)
### 3.1 创建打卡记录
```
POST /records
```
**请求参数:**
```json
{
"date": "2026-07-13",
"mode": "drank",
"drinks": [
{
"category": "baijiu",
"brand": "茅台",
"product": "飞天茅台53度",
"amount": 100,
"unit": "ml",
"degree": 53,
"standardCups": 2.12
}
],
"food": {
"category": "hotpot",
"name": "重庆老火锅"
},
"feeling": "tipsy",
"photos": [],
"visibility": "friends",
"quote": "人生得意须尽欢,莫使金樽空对月"
}
```
**字段说明:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| date | string | 是 | 日期 YYYY-MM-DD |
| mode | string | 是 | 打卡模式:`drank`(喝了) / `abstain`(未喝) |
| drinks | DrinkItem[] | 否 | 酒水列表(mode=abstain时为空数组) |
| food | FoodInfo / null | 否 | 配餐信息 |
| feeling | string / null | 否 | 感受ID |
| photos | string[] | 否 | 照片URL数组(最多9张) |
| visibility | string | 否 | 可见范围:`public` / `friends` / `private`,默认 `friends` |
| quote | string | 否 | 酒言酒语(用户选择或自定义) |
**DrinkItem 结构:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| category | string | 是 | 酒类分类ID |
| brand | string | 是 | 品牌名称 |
| product | string | 否 | 产品名 |
| amount | number | 是 | 饮用量数值 |
| unit | string | 是 | 单位:ml / liang(两) / bottle(瓶) / cup(杯) / can(听) / shot |
| degree | number | 是 | 酒精度数(%) |
| standardCups | number | 否 | 标准杯数(前端计算,后端应校验) |
**FoodInfo 结构:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| category | string | 是 | 配餐分类ID |
| name | string | 否 | 具体菜名 |
**响应 data**
```json
{
"id": "record_1689234567890",
"date": "2026-07-13",
"mode": "drank",
"drinks": [...],
"food": {...},
"feeling": "tipsy",
"photos": [],
"visibility": "friends",
"quote": "...",
"standardCupsTotal": 2.12,
"createdAt": "2026-07-13T22:30:00.000Z"
}
```
> **标准杯计算公式:**
> `标准杯 = (饮用量ml × 酒精度数% × 0.8) / 10`
> 1标准杯 = 10g纯酒精
> **单位换算为ml**
> | 单位 | 换算 |
> |------|------|
> | ml | ×1 |
> | liang(两) | ×50 |
> | bottle(瓶) | ×500 |
> | cup(杯) | ×150 |
> | can(听) | ×330 |
> | shot | ×30 |
### 3.2 获取记录列表
```
GET /records
```
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | int | 否 | 页码 |
| pageSize | int | 否 | 每页数量 |
| month | string | 否 | 月份筛选 YYYY-MM |
| mode | string | 否 | 打卡模式筛选 drank/abstain |
**响应 data**
```json
{
"list": [
{
"id": "record_xxx",
"date": "2026-07-13",
"mode": "drank",
"drinks": [...],
"food": {...},
"feeling": "tipsy",
"photos": [],
"visibility": "friends",
"standardCupsTotal": 2.12,
"createdAt": "2026-07-13T22:30:00.000Z"
}
],
"total": 30,
"page": 1,
"pageSize": 20
}
```
### 3.3 获取单条记录详情
```
GET /records/:id
```
**响应 data** 同 3.1 创建记录的返回结构
### 3.4 删除记录
```
DELETE /records/:id
```
### 3.5 获取日历打卡数据
```
GET /records/calendar
```
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| year | int | 是 | 年份 |
| month | int | 是 | 月份(1-12) |
**响应 data**
```json
{
"year": 2026,
"month": 7,
"days": {
"2026-07-01": { "mode": "drank", "standardCupsTotal": 2.5 },
"2026-07-02": { "mode": "abstain", "standardCupsTotal": 0 },
"2026-07-03": null
}
}
```
> 前端根据此数据渲染日历打卡状态。null表示当天无记录。
---
## 4. 照片上传
### 4.1 上传照片
```
POST /upload/photo
Content-Type: multipart/form-data
```
**请求参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file | File | 是 | 图片文件(jpg/png,最大10MB |
| recordId | string | 否 | 关联记录ID(可选,用于后续关联) |
**响应 data**
```json
{
"url": "https://cdn.xxx.com/photos/2026/07/abc123.jpg",
"width": 1080,
"height": 1920,
"size": 256000
}
```
### 4.2 批量上传
```
POST /upload/photos
Content-Type: multipart/form-data
```
**请求参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| files | File[] | 是 | 图片文件数组(最多9张) |
**响应 data**
```json
{
"photos": [
{ "url": "https://...", "width": 1080, "height": 1920, "size": 256000 },
...
]
}
```
---
## 5. 统计模块
### 5.1 获取用户统计概览
```
GET /stats/overview
```
**响应 data**
```json
{
"weekDrinkCount": 3,
"weekCups": 6.5,
"monthDrinkCount": 12,
"monthCups": 28.3,
"streak": 5,
"streakType": "drank",
"totalDays": 45,
"totalRecords": 48,
"totalCups": 134.4,
"favCategory": "baijiu",
"categoryVariety": 5
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| weekDrinkCount | int | 本周饮酒天数 |
| weekCups | float | 本周标准杯总数 |
| monthDrinkCount | int | 本月饮酒天数 |
| monthCups | float | 本月标准杯总数 |
| streak | int | 当前连续打卡天数 |
| streakType | string | 连续类型:drank/abstain |
| totalDays | int | 总饮酒天数(去重) |
| totalRecords | int | 总记录数 |
| totalCups | float | 历史累计标准杯 |
| favCategory | string/null | 最爱酒类ID |
| categoryVariety | int | 尝试过的酒类品种数 |
### 5.2 获取月度统计
```
GET /stats/monthly
```
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| year | int | 否 | 年份,默认当前年 |
| month | int | 否 | 月份,默认当前月 |
**响应 data**
```json
{
"year": 2026,
"month": 7,
"drinkDays": 18,
"abstainDays": 12,
"totalCups": 45.6,
"avgCupsPerDay": 2.53,
"categoryBreakdown": [
{ "category": "baijiu", "count": 8, "cups": 22.4 },
{ "category": "beer", "count": 6, "cups": 15.2 },
{ "category": "wine", "count": 4, "cups": 8.0 }
],
"feelingBreakdown": [
{ "feeling": "tipsy", "count": 10 },
{ "feeling": "buzzed", "count": 5 },
{ "feeling": "drunk", "count": 2 },
{ "feeling": "blackout", "count": 1 }
],
"foodBreakdown": [
{ "category": "hotpot", "count": 5 },
{ "category": "bbq", "count": 4 }
]
}
```
### 5.3 获取酒类分布统计
```
GET /stats/categories
```
**响应 data**
```json
{
"categories": [
{
"id": "baijiu",
"name": "白酒",
"recordCount": 20,
"totalCups": 56.8,
"percentage": 42.3
},
{
"id": "beer",
"name": "啤酒",
"recordCount": 15,
"totalCups": 38.2,
"percentage": 28.5
}
]
}
```
---
## 6. 成就模块
### 6.1 获取成就列表
```
GET /achievements
```
**响应 data**
```json
{
"achievements": [
{
"id": "first_checkin",
"name": "初来乍到",
"desc": "完成第一次打卡,开启你的饮酒记录之旅",
"icon": "🏅",
"unlocked": true,
"unlockedAt": "2026-01-15T20:00:00.000Z",
"condition": {
"type": "total_records",
"value": 1
},
"progress": 1.0
},
{
"id": "hundred_cups",
"name": "百杯不醉",
"desc": "累计饮用100标准杯",
"icon": "🏆",
"unlocked": false,
"unlockedAt": null,
"condition": {
"type": "total_standard_cups",
"value": 100
},
"progress": 0.75
}
]
}
```
**成就条件类型:**
| type | 说明 | value含义 |
|------|------|-----------|
| total_records | 总记录数 | 次数 |
| total_standard_cups | 累计标准杯 | 杯数 |
| streak_days | 连续打卡天数 | 天数 |
| category_records | 某酒类打卡次数 | 次数(需配合category字段) |
| category_variety | 尝试酒类品种数 | 品种数 |
---
## 7. 社交模块(朋友圈/卡片分享)
### 7.1 获取朋友圈动态
```
GET /feed
```
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | int | 否 | 页码 |
| pageSize | int | 否 | 每页数量 |
| lastId | string | 否 | 游标分页,上一页最后一条ID |
**响应 data**
```json
{
"list": [
{
"id": "record_xxx",
"user": {
"id": "user_002",
"nickname": "酒友小李",
"avatar": "https://xxx/avatar2.jpg"
},
"date": "2026-07-13",
"mode": "drank",
"drinks": [...],
"food": {...},
"feeling": "tipsy",
"photos": ["https://..."],
"standardCupsTotal": 3.5,
"quote": "酒逢知己千杯少",
"likeCount": 5,
"commentCount": 2,
"liked": false,
"createdAt": "2026-07-13T22:30:00.000Z"
}
],
"total": 100,
"page": 1,
"pageSize": 20
}
```
### 7.2 点赞/取消点赞
```
POST /records/:id/like
POST /records/:id/unlike
```
---
## 8. 数据字典
### 8.1 酒类分类 (category)
| ID | 名称 | 默认度数 |
|----|------|----------|
| baijiu | 白酒 | 52 |
| beer | 啤酒 | 5 |
| wine | 红酒 | 13 |
| whisky | 洋酒 | 40 |
| huangjiu | 黄酒 | 15 |
| sake | 清酒 | 15 |
| fruit | 果酒 | 8 |
| cocktail | 调酒 | 15 |
| other | 其他 | 10 |
### 8.2 饮用量单位 (unit)
| ID | 名称 | 换算(ml) |
|----|------|----------|
| ml | ml | 1 |
| liang | 两 | 50 |
| bottle | 瓶 | 500 |
| cup | 杯 | 150 |
| can | 听 | 330 |
| shot | shot | 30 |
### 8.3 配餐分类 (food category)
| ID | 名称 |
|----|------|
| hotpot | 火锅 |
| bbq | 烧烤 |
| stirfry | 炒菜 |
| seafood | 海鲜 |
| japanese | 日料 |
| western | 西餐 |
| snack | 小吃卤味 |
| junk | 零食 |
| none | 无配餐 |
### 8.4 饮用感受 (feeling)
| ID | 名称 | 描述 |
|----|------|------|
| tipsy | 微醺 | 刚刚好的快乐 |
| buzzed | 到位 | 今夜刚刚好 |
| drunk | 醉了 | 有点上头了 |
| blackout | 断片 | 什么都不记得了 |
### 8.5 可见范围 (visibility)
| ID | 名称 | 说明 |
|----|------|------|
| public | 公开 | 所有人可见 |
| friends | 仅好友 | 好友可见 |
| private | 仅自己 | 仅自己可见 |
### 8.6 打卡模式 (mode)
| ID | 名称 | 说明 |
|----|------|------|
| drank | 今日喝了 | 有饮酒记录 |
| abstain | 今日未喝 | 戒酒打卡 |
---
## 9. 数据库表设计参考
### 9.1 用户表 (users)
```sql
CREATE TABLE users (
id VARCHAR(32) PRIMARY KEY,
openid VARCHAR(64) UNIQUE NOT NULL,
union_id VARCHAR(64),
nickname VARCHAR(64),
avatar VARCHAR(512),
preferences JSON,
joined_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
```
### 9.2 打卡记录表 (records)
```sql
CREATE TABLE records (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
date DATE NOT NULL,
mode ENUM('drank', 'abstain') NOT NULL,
drinks JSON,
food JSON,
feeling VARCHAR(16),
photos JSON,
visibility ENUM('public', 'friends', 'private') DEFAULT 'friends',
quote VARCHAR(256),
standard_cups_total DECIMAL(8,2) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_date (user_id, date),
INDEX idx_user_mode (user_id, mode, date)
);
```
### 9.3 照片表 (photos)
```sql
CREATE TABLE photos (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
record_id VARCHAR(32),
url VARCHAR(512) NOT NULL,
width INT,
height INT,
size INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_record (record_id),
INDEX idx_user (user_id)
);
```
### 9.4 点赞表 (likes)
```sql
CREATE TABLE likes (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
record_id VARCHAR(32) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_user_record (user_id, record_id)
);
```
### 9.5 成就记录表 (user_achievements)
```sql
CREATE TABLE user_achievements (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
achievement_id VARCHAR(32) NOT NULL,
unlocked_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_user_achievement (user_id, achievement_id)
);
```
---
## 10. 备注
1. **标准杯计算建议由后端完成**,前端传入的 `standardCups` 仅作参考,后端应以 `amount``unit``degree` 为准重新计算
2. **照片上传**建议走对象存储(OSS/COS),返回CDN链接
3. **日历接口**建议缓存,避免每次查全月记录
4. **成就检测**可在创建记录后异步触发,避免影响主流程
5. **可见范围**控制需在 feed 接口和记录详情接口中做权限过滤
6. 前端目前使用 Mock 数据(`mock-data.js`),切换到真实接口时只需替换 `common/mock-data.js` 中的方法为 HTTP 调用即可