# 喝了么 - 后端接口文档 > 版本: 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 | 是 | 微信登录code(wx.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 调用即可