# 干杯日记 - 酒友圈模块接口文档 > 版本: v1.0 > 日期: 2026-07-20 > 模块: 酒友圈(社交模块) > 小程序: 干杯日记(uni-app 微信小程序) > 基础URL: `https://your-domain.com/api/v1` --- ## 1. 模块概述 酒友圈是干杯日记的核心社交模块,包含三大子功能: | 子功能 | 说明 | |--------|------| | 动态信息流 | 酒友发布饮酒动态,支持点赞、评论 | | 酒友管理 | 好友请求、酒友列表、搜索、删除 | | 约酒活动 | 发起酒局、报名、取消、签到 | **前端当前状态:** 所有接口已在前端 `common/api.js` 中预留调用方法,暂用 Mock 数据。后端实现后前端仅需切换调用方式,无需改动页面逻辑。**请严格按照本文档的字段名和数据结构实现**,确保前端零改动对接。 --- ## 2. 通用约定 ### 2.1 鉴权 - 请求头:`Authorization: Bearer {token}` - 所有接口均需登录态 ### 2.2 统一响应格式 ```json { "code": 0, "message": "success", "data": {} } ``` ### 2.3 错误码 | code | 含义 | |------|------| | 0 | 成功 | | 400 | 参数错误 | | 401 | 未登录/token过期 | | 403 | 无权限(如:非酒友关系、非发起人) | | 404 | 资源不存在 | | 409 | 冲突(如:重复报名、已是酒友) | | 500 | 服务器错误 | ### 2.4 时间格式 - 所有时间字段使用 ISO 8601:`2026-07-20T22:30:00.000Z` - 前端会自行转换为相对时间("2小时前"等) --- ## 3. 动态信息流 ### 3.1 获取动态列表 ``` GET /circle/feeds ``` **查询参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | page | int | 否 | 页码,默认1 | | pageSize | int | 否 | 每页数量,默认10 | **响应 data:** ```json { "list": [ { "id": "feed001", "userId": "user_002", "nickname": "老张", "avatar": "https://xxx/avatar.jpg", "time": "2026-07-20T20:30:00.000Z", "text": "今晚和几个老兄弟整了瓶飞天,配重庆火锅,巴适得很!", "drinks": [ { "category": "baijiu", "name": "飞天茅台53度", "amount": "100ml" } ], "feeling": "tipsy", "images": ["https://xxx/img1.jpg"], "likes": 12, "liked": false, "comments": 3 } ], "total": 50, "hasMore": true } ``` **Feed 字段说明:** | 字段 | 类型 | 说明 | |------|------|------| | id | string | 动态ID | | userId | string | 发布者用户ID | | nickname | string | 发布者昵称 | | avatar | string | 发布者头像URL(可为空字符串) | | time | string | 发布时间 ISO 8601 | | text | string | 动态文字内容 | | drinks | DrinkTag[] | 关联酒水标签(见下方结构) | | feeling | string/null | 感受ID:sober/buzzed/tipsy/drunk | | images | string[] | 配图URL数组(最多9张) | | likes | int | 点赞数 | | liked | boolean | 当前用户是否已点赞 | | comments | int | 评论数 | **DrinkTag 结构:** | 字段 | 类型 | 说明 | |------|------|------| | category | string | 酒类ID(baijiu/beer/wine/whisky/huangjiu/sake/fruit/cocktail) | | name | string | 酒名(如"飞天茅台53度") | | amount | string | 用量展示文本(如"100ml"、"3瓶") | **业务规则:** - 仅返回当前用户**酒友**发布的动态(visibility=friends)+ 公开动态(visibility=public) - 按发布时间倒序 - 自己的动态也包含在内 --- ### 3.2 发布动态 ``` POST /circle/feeds ``` **请求参数:** ```json { "text": "今晚小酌一杯", "images": ["https://xxx/img1.jpg"], "recordId": "record_1689234567890", "visibility": "friends" } ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | text | string | 否 | 文字内容(最长500字),text和images至少一项非空 | | images | string[] | 否 | 图片URL数组(最多9张,先调上传接口获取URL) | | recordId | string/null | 否 | 关联的饮酒记录ID,传入时自动提取酒水信息生成drinks标签 | | visibility | string | 否 | 可见范围:friends(默认)/private | **响应 data:** ```json { "success": true, "feedId": "feed_1689234567890" } ``` **业务规则:** - 传入 recordId 时,后端从记录中提取 drinks 信息填充到动态的 drinks 字段 - UGC 内容(text)需接入微信内容安全审核(msgSecCheck) --- ### 3.3 点赞动态 ``` POST /circle/feeds/:id/like ``` **响应 data:** ```json { "success": true } ``` ### 3.4 取消点赞 ``` POST /circle/feeds/:id/unlike ``` **响应 data:** ```json { "success": true } ``` > 重复点赞/取消应幂等处理,不报错。 --- ### 3.5 获取动态评论 ``` GET /circle/feeds/:id/comments ``` **响应 data:** ```json { "list": [ { "id": "c001", "userId": "user_003", "nickname": "酒仙李白", "avatar": "https://xxx/avatar3.jpg", "content": "茅台配火锅,土豪啊老张!", "time": "2026-07-20T21:00:00.000Z" } ] } ``` **Comment 字段说明:** | 字段 | 类型 | 说明 | |------|------|------| | id | string | 评论ID | | userId | string | 评论者ID | | nickname | string | 评论者昵称 | | avatar | string | 评论者头像 | | content | string | 评论内容 | | time | string | 评论时间 ISO 8601 | > 按时间正序返回(最早在前)。 --- ### 3.6 发表评论 ``` POST /circle/feeds/:id/comments ``` **请求参数:** ```json { "content": "看着就馋了,下次带上我" } ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | content | string | 是 | 评论内容(最长200字) | **响应 data:** ```json { "success": true, "comment": { "id": "c_1689234567890", "content": "看着就馋了,下次带上我", "time": "2026-07-20T22:00:00.000Z" } } ``` **业务规则:** - 评论需接入内容安全审核 - 评论成功后,动态的 comments 计数 +1 --- ## 4. 酒友管理 ### 4.1 获取酒友列表 ``` GET /circle/friends ``` **查询参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | keyword | string | 否 | 按昵称模糊搜索 | **响应 data:** ```json { "list": [ { "id": "user_002", "nickname": "老张", "avatar": "https://xxx/avatar.jpg", "lastDrink": "昨晚喝了飞天茅台", "lastDrinkTime": "2026-07-20T20:30:00.000Z", "online": true } ] } ``` **Friend 字段说明:** | 字段 | 类型 | 说明 | |------|------|------| | id | string | 酒友用户ID | | nickname | string | 昵称 | | avatar | string | 头像URL | | lastDrink | string | 最近一次饮酒摘要文本(如"昨晚喝了飞天茅台"),无记录则为空 | | lastDrinkTime | string | 最近饮酒时间 ISO 8601 | | online | boolean | 是否在线(24小时内活跃视为在线) | --- ### 4.2 获取好友请求列表 ``` GET /circle/friend-requests ``` **响应 data:** ```json { "list": [ { "id": "req001", "userId": "user_101", "nickname": "夜猫子", "avatar": "https://xxx/avatar101.jpg", "message": "一起喝过酒,加个好友", "time": "2026-07-20T21:00:00.000Z" } ] } ``` > 仅返回**待处理**的请求(status=pending),按时间倒序。 --- ### 4.3 发送好友请求 ``` POST /circle/friend-requests ``` **请求参数:** ```json { "userId": "user_101", "message": "一起喝过酒,加个好友" } ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | userId | string | 是 | 目标用户ID | | message | string | 否 | 验证消息(最长50字) | **响应 data:** ```json { "success": true } ``` **业务规则:** - 已是酒友返回 409 - 已有待处理请求则幂等返回成功 --- ### 4.4 接受好友请求 ``` POST /circle/friend-requests/:id/accept ``` **响应 data:** ```json { "success": true } ``` **业务规则:** - 接受后双方建立酒友关系 - 请求状态更新为 accepted --- ### 4.5 删除酒友 ``` DELETE /circle/friends/:userId ``` **响应 data:** ```json { "success": true } ``` **业务规则:** - 双向解除酒友关系 - 删除后对方动态不再出现在自己的信息流中 --- ## 5. 约酒活动(酒局) ### 5.1 获取酒局列表 ``` GET /circle/events ``` **查询参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | status | string | 否 | 状态筛选:open/ongoing/ended,不传返回全部 | **响应 data:** ```json { "list": [ { "id": "evt001", "title": "周五夜·老地方火锅局", "organizer": { "id": "user_002", "nickname": "老张", "avatar": "https://xxx/avatar.jpg" }, "time": "2026-07-25T19:00:00.000Z", "location": "渝味晓宇火锅(解放碑店)", "maxPeople": 8, "joined": 5, "participants": [ { "id": "user_002", "nickname": "老张", "avatar": "https://xxx/avatar.jpg" } ], "status": "open", "note": "自带酒水,AA制餐费", "isJoined": false, "isOrganizer": false } ] } ``` **Event 字段说明:** | 字段 | 类型 | 说明 | |------|------|------| | id | string | 酒局ID | | title | string | 酒局名称(最长30字) | | organizer | UserInfo | 发起人信息 | | time | string | 开始时间 ISO 8601 | | location | string | 地点文本 | | maxPeople | int | 人数上限(2-50) | | joined | int | 已报名人数(含发起人) | | participants | UserInfo[] | 参与者列表 | | status | string | 状态:open(报名中)/ongoing(进行中)/ended(已结束) | | note | string | 备注 | | isJoined | boolean | 当前用户是否已报名 | | isOrganizer | boolean | 当前用户是否为发起人 | **状态流转规则(后端自动维护):** - `open`:当前时间 < 开始时间 - `ongoing`:开始时间 <= 当前时间 < 开始时间+6小时 - `ended`:当前时间 >= 开始时间+6小时 **可见范围:** 仅酒友可见(同动态信息流规则) --- ### 5.2 获取酒局详情 ``` GET /circle/events/:id ``` **响应 data:** 同 5.1 中单个 Event 结构 --- ### 5.3 发起酒局 ``` POST /circle/events ``` **请求参数:** ```json { "title": "周五夜·老地方火锅局", "time": "2026-07-25T19:00:00.000Z", "location": "渝味晓宇火锅(解放碑店)", "maxPeople": 8, "note": "自带酒水,AA制餐费" } ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | title | string | 是 | 酒局名称(最长30字) | | time | string | 是 | 开始时间(必须为未来时间) | | location | string | 是 | 地点(最长50字) | | maxPeople | int | 是 | 人数上限(2-50) | | note | string | 否 | 备注(最长200字) | **响应 data:** ```json { "success": true, "eventId": "evt_1689234567890" } ``` **业务规则:** - 发起人自动算作已报名(joined 初始为1) - 发起人 isOrganizer = true --- ### 5.4 报名酒局 ``` POST /circle/events/:id/join ``` **响应 data:** ```json { "success": true } ``` **业务规则:** - 人数已满返回 409 - 酒局非 open 状态返回 403 - 重复报名幂等处理 --- ### 5.5 取消报名 ``` POST /circle/events/:id/quit ``` **响应 data:** ```json { "success": true } ``` **业务规则:** - 发起人不可取消报名(返回 403) - 未报名状态幂等处理 --- ### 5.6 酒局签到 ``` POST /circle/events/:id/checkin ``` **响应 data:** ```json { "success": true } ``` **业务规则:** - 仅 ongoing 状态可签到(返回 403) - 仅已报名用户可签到 - 签到后可在参与者信息中标记 checkedIn(可选扩展) --- ## 6. 数据库表设计参考 ### 6.1 酒友关系表 (friendships) ```sql CREATE TABLE friendships ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(32) NOT NULL, friend_id VARCHAR(32) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE INDEX idx_user_friend (user_id, friend_id), INDEX idx_friend (friend_id) ); ``` > 双向关系存两条记录(A->B 和 B->A),便于查询。 ### 6.2 好友请求表 (friend_requests) ```sql CREATE TABLE friend_requests ( id VARCHAR(32) PRIMARY KEY, from_user_id VARCHAR(32) NOT NULL, to_user_id VARCHAR(32) NOT NULL, message VARCHAR(64), status ENUM('pending', 'accepted', 'rejected') DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_to_status (to_user_id, status), INDEX idx_from_to (from_user_id, to_user_id) ); ``` ### 6.3 动态表 (feeds) ```sql CREATE TABLE feeds ( id VARCHAR(32) PRIMARY KEY, user_id VARCHAR(32) NOT NULL, text VARCHAR(512), drinks JSON, feeling VARCHAR(16), images JSON, record_id VARCHAR(32), visibility ENUM('friends', 'private') DEFAULT 'friends', like_count INT DEFAULT 0, comment_count INT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_time (user_id, created_at), INDEX idx_created (created_at) ); ``` ### 6.4 评论表 (comments) ```sql CREATE TABLE comments ( id VARCHAR(32) PRIMARY KEY, feed_id VARCHAR(32) NOT NULL, user_id VARCHAR(32) NOT NULL, content VARCHAR(256) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_feed (feed_id, created_at) ); ``` ### 6.5 酒局表 (events) ```sql CREATE TABLE events ( id VARCHAR(32) PRIMARY KEY, organizer_id VARCHAR(32) NOT NULL, title VARCHAR(64) NOT NULL, start_time DATETIME NOT NULL, location VARCHAR(128) NOT NULL, max_people INT NOT NULL DEFAULT 6, joined_count INT NOT NULL DEFAULT 1, note VARCHAR(256), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_organizer (organizer_id), INDEX idx_start_time (start_time) ); ``` ### 6.6 酒局报名表 (event_participants) ```sql CREATE TABLE event_participants ( id BIGINT AUTO_INCREMENT PRIMARY KEY, event_id VARCHAR(32) NOT NULL, user_id VARCHAR(32) NOT NULL, checked_in TINYINT(1) DEFAULT 0, joined_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE INDEX idx_event_user (event_id, user_id), INDEX idx_user (user_id) ); ``` --- ## 7. 前端对接说明 ### 7.1 前端调用位置 所有接口调用集中在 `common/api.js`,当前为 Mock 实现,方法签名如下: ```js // 动态 GetCircleFeeds({ page, pageSize }) // GET /circle/feeds PublishFeed({ text, images, recordId, visibility }) // POST /circle/feeds LikeFeed({ feedId }) // POST /circle/feeds/:id/like UnlikeFeed({ feedId }) // POST /circle/feeds/:id/unlike GetFeedComments({ feedId }) // GET /circle/feeds/:id/comments AddComment({ feedId, content }) // POST /circle/feeds/:id/comments // 酒友 GetFriends({ keyword }) // GET /circle/friends GetFriendRequests() // GET /circle/friend-requests SendFriendRequest({ userId }) // POST /circle/friend-requests AcceptFriendRequest({ requestId }) // POST /circle/friend-requests/:id/accept RemoveFriend({ userId }) // DELETE /circle/friends/:userId // 酒局 GetEvents({ status }) // GET /circle/events GetEventDetail({ eventId }) // GET /circle/events/:id CreateEvent({ title, time, location, maxPeople, note }) // POST /circle/events JoinEvent({ eventId }) // POST /circle/events/:id/join QuitEvent({ eventId }) // POST /circle/events/:id/quit CheckInEvent({ eventId }) // POST /circle/events/:id/checkin ``` ### 7.2 响应解包约定 前端 SDK 会自动解包 `data.data`,因此接口实际返回给前端的结构为: ```json { "code": 0, "data": { ... } } ``` 前端拿到的就是 `data` 内的对象。 ### 7.3 注意事项 1. **字段名严格一致**:前端已按本文档字段名渲染,请勿更改命名(如 `likes` 不能改为 `likeCount`) 2. **头像可为空**:avatar 字段允许空字符串,前端有默认占位头像 3. **时间格式**:统一 ISO 8601,前端自行格式化 4. **内容安全**:text、content、title、note 等 UGC 字段需接入微信 msgSecCheck 审核 5. **幂等性**:点赞/取消、报名/取消等操作需幂等,避免前端重试导致计数错误