# 使用说明
* 喝酒了么 - 后端接口 API
* 小程序:喝酒了么(uni-app 微信小程序)
* 基础URL: /api/v1
*
* 主要功能模块:
* 1. 用户模块 - 微信登录、用户信息管理
* 2. 打卡记录模块 - 饮酒记录创建、查询、日历数据
* 3. 照片上传模块 - 单张/批量照片上传
* 4. 统计模块 - 用户统计、月度统计、酒类分布
* 5. 成就模块 - 成就列表和进度
* 6. 社交模块 - 朋友圈动态、点赞
**版本:** v1.0.8
## 安装
```
npm install --registry="https://npm.wash-painting.cn" HaveADrink
```
## 用法
用户需实现普通 http 请求函数和文件上传函数,返回值均为 json 对象
**示例**
```javascript
// reslove 和 reject 必须返回 json 对象
const http_request_function = (url, method, headers, body) => {
return new Promise((reslove, reject)=>{});
}
const upload_function = (url, method, headers, data) => {
return new Promise((reslove, reject)=>{});
}
const client = new HaveADrink(host, http_request_function, upload_function);
```
## 接口文档
### 微信登录, 获取openid、unionid、token
POST `/api/have_a_drink/v1/auth/wechat/login`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|code|`string`|required| 登录时获取的 code, 可通过 wx.login 获取|
|nickName|`string`|| 用户昵称|
|avatarUrl|`string`|| 头像URL|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|token|`string`| JWT Token
|
|user|`User`| 用户信息
|
|isNew|`boolean`| 是否新用户
|
|session_key|`string`| 会话密钥
|
|open_id|`string`| 用户唯一标识
|
|union_id|`string`| 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台账号下会返回,详见 UnionID 机制说明。
|
|errcode|`number`| 错误码
|
|errmsg|`string`| 错误信息
|
|refresh_token|`string`| 刷新token
|
**User**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 用户ID|
|nickname|`string`| 用户昵称|
|avatar|`string`| 头像URL|
|joinedAt|`string`| 加入时间|
|preferences|`UserPreferences`| 用户偏好|
**UserPreferences**
|名称|类型|说明|
|:-|:-|:-|
|favoriteCategories|`Array`| 偏好酒类ID列表|
|frequency|`Frequency`| 饮酒频率|
```javascript
const req = new WechatLoginReq()
client.WechatLogin(req).then(...).catch(...)
```
### 获取微信手机号
POST `/api/have_a_drink/v1/auth/wechat/get_phone_number`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|code|`string`|required| 手机号获取凭证|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|errcode|`number`| 错误码
|
|errmsg|`string`| 错误信息
|
|token|`string`| token:api使用
|
|expires_in|`number`| token 超时时间,单位(秒)
|
|refresh_token|`string`| refresh_token:刷新token
|
```javascript
const req = new WechatGetPhoneNumberReq()
client.WechatGetPhoneNumber(req).then(...).catch(...)
```
### 刷新 token 接口
POST `/api/have_a_drink/v1/auth/refresh_token`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|refresh_token|`string`|required| 签发 token 时生成的 refresh_token|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|token|`string`| 生成的新token
|
|expire_in|`number`| token 超时时间,单位(秒)
|
|refresh_token|`string`| refresh_token:刷新token
|
```javascript
const req = new RefreshTokenReq()
client.RefreshToken(req).then(...).catch(...)
```
### 获取成就列表
GET `/api/have_a_drink/v1/achievements/list`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`AchievementsData`| 成就列表数据
|
**AchievementsData**
|名称|类型|说明|
|:-|:-|:-|
|achievements|`Array`| 成就列表|
**Achievement**
|名称|类型|说明|
|:-|:-|:-|
|id|`string`| 成就ID|
|name|`string`| 成就名称|
|desc|`string`| 成就描述|
|icon|`string`| 成就图标|
|unlocked|`boolean`| 是否已解锁|
|unlockedAt|`string`| 解锁时间|
|condition|`AchievementCondition`| 成就条件|
|progress|`number`| 进度(0-1)|
**AchievementCondition**
|名称|类型|说明|
|:-|:-|:-|
|type|`AchievementConditionType`| 条件类型|
|value|`number`| 目标值|
**AchievementConditionType**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|TotalRecords|"total_records"|`AchievementConditionType`|总记录数|
|TotalStandardCups|"total_standard_cups"|`AchievementConditionType`|累计标准杯|
|StreakDays|"streak_days"|`AchievementConditionType`|连续打卡天数|
|CategoryRecords|"category_records"|`AchievementConditionType`|某酒类打卡次数|
|CategoryVariety|"category_variety"|`AchievementConditionType`|尝试酒类品种数|
```javascript
const req = new GetAchievementsReq()
client.GetAchievements(req).then(...).catch(...)
```
### 获取朋友圈动态
GET `/api/have_a_drink/v1/communication/feed`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|lastId|`string\|number`|| 游标分页,上一页最后一条ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`FeedPageData`| 朋友圈动态分页数据
|
**FeedPageData**
|名称|类型|说明|
|:-|:-|:-|
|list|`Array`| 动态列表|
**FeedItem**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 记录ID|
|user|`FeedUser`| 用户信息|
|date|`string`| 日期|
|mode|`Mode`| 打卡模式|
|drinks|`Array`| 酒水列表|
|food|`FoodInfo`| 配餐信息|
|feeling|`Feeling`| 感受|
|photos|`Array`| 照片URL数组|
|standardCupsTotal|`number`| 标准杯总数|
|quote|`string`| 酒言酒语|
|likeCount|`number`| 点赞数|
|commentCount|`number`| 评论数|
|liked|`boolean`| 当前用户是否已点赞|
|createdAt|`string`| 创建时间|
**FeedUser**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 用户ID|
|nickname|`string`| 用户昵称|
|avatar|`string`| 头像URL|
**DrinkItem**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类ID|
|brand|`string`| 品牌名称|
|product|`string`| 产品名|
|amount|`number`| 饮用量数值|
|unit|`Unit`| 单位|
|degree|`number`| 酒精度数(%)|
|standardCups|`number`| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`| 自定义饮酒数量|
|customUnit|`Unit`| 自定义饮酒单位|
**Category**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Baijiu|"baijiu"|`Category`|白酒|
|Beer|"beer"|`Category`|啤酒|
|Wine|"wine"|`Category`|红酒|
|Whisky|"whisky"|`Category`|洋酒|
|Huangjiu|"huangjiu"|`Category`|黄酒|
|Sake|"sake"|`Category`|清酒|
|Fruit|"fruit"|`Category`|果酒|
|Cocktail|"cocktail"|`Category`|调酒|
|Other|"other"|`Category`|其他|
**Unit**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Ml|"ml"|`Unit`|毫升|
|Liang|"liang"|`Unit`|两|
|Bottle|"bottle"|`Unit`|瓶|
|Cup|"cup"|`Unit`|杯|
|Can|"can"|`Unit`|听|
|Shot|"shot"|`Unit`|shot|
**Unit**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Ml|"ml"|`Unit`|毫升|
|Liang|"liang"|`Unit`|两|
|Bottle|"bottle"|`Unit`|瓶|
|Cup|"cup"|`Unit`|杯|
|Can|"can"|`Unit`|听|
|Shot|"shot"|`Unit`|shot|
**FoodInfo**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类ID|
|name|`string`| 具体菜名|
**FoodCategory**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Hotpot|"hotpot"|`FoodCategory`|火锅|
|Bbq|"bbq"|`FoodCategory`|烧烤|
|Stirfry|"stirfry"|`FoodCategory`|炒菜|
|Seafood|"seafood"|`FoodCategory`|海鲜|
|Japanese|"japanese"|`FoodCategory`|日料|
|Western|"western"|`FoodCategory`|西餐|
|Snack|"snack"|`FoodCategory`|小吃卤味|
|Junk|"junk"|`FoodCategory`|零食|
|None|"none"|`FoodCategory`|无配餐|
```javascript
const req = new GetFeedReq()
client.GetFeed(req).then(...).catch(...)
```
### 上传照片
POST `/api/have_a_drink/v1/photo/upload/photo`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|url|`string`|required| 图片Url|
|recordId|`string\|number`|required| 关联记录ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new UploadPhotoReq()
client.UploadPhoto(req).then(...).catch(...)
```
### 批量上传照片
POST `/api/have_a_drink/v1/photo/upload/photos`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|urls|`Array`|required,max=9| 图片URL数组(最多9张)|
|recordId|`string\|number`|required| 关联记录ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new UploadPhotosReq()
client.UploadPhotos(req).then(...).catch(...)
```
### 创建打卡记录
POST `/api/have_a_drink/v1/record/records`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|date|`string`|required| 日期 YYYY-MM-DD|
|mode|`Mode`|今日喝了: Mode.Drank = "drank"
今日未喝: Mode.Abstain = "abstain"| 打卡模式|
|drinks|`Array`|| 酒水列表(mode=abstain时为空数组)|
|food|`FoodInfo`|| 配餐信息|
|feeling|`Feeling`|微醺: Feeling.Tipsy = "tipsy"
到位: Feeling.Buzzed = "buzzed"
醉了: Feeling.Drunk = "drunk"
断片: Feeling.Blackout = "blackout"| 感受ID|
|photos|`Array`|max=9| 照片URL数组(最多9张)|
|visibility|`Visibility`|公开: Visibility.Public = "public"
仅好友: Visibility.Friends = "friends"
仅自己: Visibility.Private = "private"| 可见范围|
|quote|`string`|| 酒言酒语|
**DrinkItem**
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|category|`Category`|| 酒类分类ID|
|brand|`string`|required| 品牌名称|
|product|`string`|| 产品名|
|amount|`number`|required,gt=0| 饮用量数值|
|unit|`Unit`|required| 单位|
|degree|`number`|required,gte=0,lte=100| 酒精度数(%)|
|standardCups|`number`|| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`|| 自定义饮酒数量|
|customUnit|`Unit`|| 自定义饮酒单位|
**Category**
|名称|值|类型|说明|
|:-|:-|:-|:-|
|Baijiu|"baijiu"|`Category`|白酒|
|Beer|"beer"|`Category`|啤酒|
|Wine|"wine"|`Category`|红酒|
|Whisky|"whisky"|`Category`|洋酒|
|Huangjiu|"huangjiu"|`Category`|黄酒|
|Sake|"sake"|`Category`|清酒|
|Fruit|"fruit"|`Category`|果酒|
|Cocktail|"cocktail"|`Category`|调酒|
|Other|"other"|`Category`|其他|
**Unit**
|名称|值|类型|说明|
|:-|:-|:-|:-|
|Ml|"ml"|`Unit`|毫升|
|Liang|"liang"|`Unit`|两|
|Bottle|"bottle"|`Unit`|瓶|
|Cup|"cup"|`Unit`|杯|
|Can|"can"|`Unit`|听|
|Shot|"shot"|`Unit`|shot|
**Unit**
|名称|值|类型|说明|
|:-|:-|:-|:-|
|Ml|"ml"|`Unit`|毫升|
|Liang|"liang"|`Unit`|两|
|Bottle|"bottle"|`Unit`|瓶|
|Cup|"cup"|`Unit`|杯|
|Can|"can"|`Unit`|听|
|Shot|"shot"|`Unit`|shot|
**FoodInfo**
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|category|`FoodCategory`|| 配餐分类ID|
|name|`string`|| 具体菜名|
**FoodCategory**
|名称|值|类型|说明|
|:-|:-|:-|:-|
|Hotpot|"hotpot"|`FoodCategory`|火锅|
|Bbq|"bbq"|`FoodCategory`|烧烤|
|Stirfry|"stirfry"|`FoodCategory`|炒菜|
|Seafood|"seafood"|`FoodCategory`|海鲜|
|Japanese|"japanese"|`FoodCategory`|日料|
|Western|"western"|`FoodCategory`|西餐|
|Snack|"snack"|`FoodCategory`|小吃卤味|
|Junk|"junk"|`FoodCategory`|零食|
|None|"none"|`FoodCategory`|无配餐|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`Record`| 创建的记录详情
|
**Record**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 记录ID|
|date|`string`| 日期|
|mode|`Mode`| 打卡模式|
|drinks|`Array`| 酒水列表|
|food|`FoodInfo`| 配餐信息|
|feeling|`Feeling`| 感受|
|photos|`Array`| 照片URL数组|
|visibility|`Visibility`| 可见范围|
|quote|`string`| 酒言酒语|
|standardCupsTotal|`number`| 标准杯总数|
|createdAt|`string`| 创建时间|
**Mode**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Drank|"drank"|`Mode`|今日喝了|
|Abstain|"abstain"|`Mode`|今日未喝|
**DrinkItem**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类ID|
|brand|`string`| 品牌名称|
|product|`string`| 产品名|
|amount|`number`| 饮用量数值|
|unit|`Unit`| 单位|
|degree|`number`| 酒精度数(%)|
|standardCups|`number`| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`| 自定义饮酒数量|
|customUnit|`Unit`| 自定义饮酒单位|
**FoodInfo**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类ID|
|name|`string`| 具体菜名|
**Feeling**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Tipsy|"tipsy"|`Feeling`|微醺|
|Buzzed|"buzzed"|`Feeling`|到位|
|Drunk|"drunk"|`Feeling`|醉了|
|Blackout|"blackout"|`Feeling`|断片|
**Visibility**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Public|"public"|`Visibility`|公开|
|Friends|"friends"|`Visibility`|仅好友|
|Private|"private"|`Visibility`|仅自己|
```javascript
const req = new CreateRecordReq()
client.CreateRecord(req).then(...).catch(...)
```
### 获取记录列表
GET `/api/have_a_drink/v1/record/records`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|page|`number`|required,min=1| 页码|
|pageSize|`number`|required,min=1,max=100| 每页数量,默认1-100|
|month|`string`|| 月份筛选 YYYY-MM|
|mode|`Mode`|今日喝了: Mode.Drank = "drank"
今日未喝: Mode.Abstain = "abstain"| 打卡模式筛选|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 分页数据
|
**Record**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 记录ID|
|date|`string`| 日期|
|mode|`Mode`| 打卡模式|
|drinks|`Array`| 酒水列表|
|food|`FoodInfo`| 配餐信息|
|feeling|`Feeling`| 感受|
|photos|`Array`| 照片URL数组|
|visibility|`Visibility`| 可见范围|
|quote|`string`| 酒言酒语|
|standardCupsTotal|`number`| 标准杯总数|
|createdAt|`string`| 创建时间|
**Mode**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Drank|"drank"|`Mode`|今日喝了|
|Abstain|"abstain"|`Mode`|今日未喝|
**DrinkItem**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类ID|
|brand|`string`| 品牌名称|
|product|`string`| 产品名|
|amount|`number`| 饮用量数值|
|unit|`Unit`| 单位|
|degree|`number`| 酒精度数(%)|
|standardCups|`number`| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`| 自定义饮酒数量|
|customUnit|`Unit`| 自定义饮酒单位|
**FoodInfo**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类ID|
|name|`string`| 具体菜名|
**Feeling**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Tipsy|"tipsy"|`Feeling`|微醺|
|Buzzed|"buzzed"|`Feeling`|到位|
|Drunk|"drunk"|`Feeling`|醉了|
|Blackout|"blackout"|`Feeling`|断片|
**Visibility**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Public|"public"|`Visibility`|公开|
|Friends|"friends"|`Visibility`|仅好友|
|Private|"private"|`Visibility`|仅自己|
```javascript
const req = new GetRecordsReq()
client.GetRecords(req).then(...).catch(...)
```
### 获取单条记录详情
GET `/api/have_a_drink/v1/record/records/detail`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|required| 记录ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`Record`| 记录详情
|
**Record**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 记录ID|
|date|`string`| 日期|
|mode|`Mode`| 打卡模式|
|drinks|`Array`| 酒水列表|
|food|`FoodInfo`| 配餐信息|
|feeling|`Feeling`| 感受|
|photos|`Array`| 照片URL数组|
|visibility|`Visibility`| 可见范围|
|quote|`string`| 酒言酒语|
|standardCupsTotal|`number`| 标准杯总数|
|createdAt|`string`| 创建时间|
**Mode**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Drank|"drank"|`Mode`|今日喝了|
|Abstain|"abstain"|`Mode`|今日未喝|
**DrinkItem**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类ID|
|brand|`string`| 品牌名称|
|product|`string`| 产品名|
|amount|`number`| 饮用量数值|
|unit|`Unit`| 单位|
|degree|`number`| 酒精度数(%)|
|standardCups|`number`| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`| 自定义饮酒数量|
|customUnit|`Unit`| 自定义饮酒单位|
**FoodInfo**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类ID|
|name|`string`| 具体菜名|
**Feeling**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Tipsy|"tipsy"|`Feeling`|微醺|
|Buzzed|"buzzed"|`Feeling`|到位|
|Drunk|"drunk"|`Feeling`|醉了|
|Blackout|"blackout"|`Feeling`|断片|
**Visibility**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Public|"public"|`Visibility`|公开|
|Friends|"friends"|`Visibility`|仅好友|
|Private|"private"|`Visibility`|仅自己|
```javascript
const req = new GetRecordDetailReq()
client.GetRecordDetail(req).then(...).catch(...)
```
### 删除记录
DELETE `/api/have_a_drink/v1/record/records`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|required| 记录ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new DeleteRecordReq()
client.DeleteRecord(req).then(...).catch(...)
```
### 获取日历打卡数据
GET `/api/have_a_drink/v1/record/records/calendar`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|year|`number`|required| 年份|
|month|`number`|required,gte=1,lte=12| 月份(1-12)|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|year|`number`| 年份
|
|month|`number`| 月份
|
|days|`Array`| 每天的打卡数据,null表示当天无记录
|
**CalendarDayData**
|名称|类型|说明|
|:-|:-|:-|
|date|`string`| 日期YYYY-MM-DD|
|hasRecord|`boolean`| 是否有记录|
|mode|`Mode`| 打卡模式|
|standardCupsTotal|`number`| 标准杯总数|
|id|`string\|number`| 记录ID|
|drinks|`Array`| 酒水列表|
|food|`FoodInfo`| 配餐信息|
|feeling|`Feeling`| 感受|
|photos|`Array`| 照片URL数组|
|visibility|`Visibility`| 可见范围|
|quote|`string`| 酒言酒语|
|createdAt|`string`| 创建时间|
**Mode**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Drank|"drank"|`Mode`|今日喝了|
|Abstain|"abstain"|`Mode`|今日未喝|
**DrinkItem**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类ID|
|brand|`string`| 品牌名称|
|product|`string`| 产品名|
|amount|`number`| 饮用量数值|
|unit|`Unit`| 单位|
|degree|`number`| 酒精度数(%)|
|standardCups|`number`| 标准杯数(前端计算,后端应校验)|
|customAmount|`number`| 自定义饮酒数量|
|customUnit|`Unit`| 自定义饮酒单位|
**FoodInfo**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类ID|
|name|`string`| 具体菜名|
**Feeling**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Tipsy|"tipsy"|`Feeling`|微醺|
|Buzzed|"buzzed"|`Feeling`|到位|
|Drunk|"drunk"|`Feeling`|醉了|
|Blackout|"blackout"|`Feeling`|断片|
**Visibility**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Public|"public"|`Visibility`|公开|
|Friends|"friends"|`Visibility`|仅好友|
|Private|"private"|`Visibility`|仅自己|
```javascript
const req = new GetCalendarReq()
client.GetCalendar(req).then(...).catch(...)
```
### 获取用户统计概览
GET `/api/have_a_drink/v1/statistics/overview`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`StatsOverview`| 统计概览数据
|
**StatsOverview**
|名称|类型|说明|
|:-|:-|:-|
|weekDrinkCount|`number`| 本周饮酒天数|
|weekCups|`number`| 本周标准杯总数|
|monthDrinkCount|`number`| 本月饮酒天数|
|monthCups|`number`| 本月标准杯总数|
|streak|`number`| 当前连续打卡天数|
|streakType|`Mode`| 连续类型|
|totalDays|`number`| 总饮酒天数(去重)|
|totalRecords|`number`| 总记录数|
|totalCups|`number`| 历史累计标准杯|
|favCategory|`Category`| 最爱酒类ID|
|categoryVariety|`number`| 尝试过的酒类品种数|
**Mode**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Drank|"drank"|`Mode`|今日喝了|
|Abstain|"abstain"|`Mode`|今日未喝|
**Category**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Baijiu|"baijiu"|`Category`|白酒|
|Beer|"beer"|`Category`|啤酒|
|Wine|"wine"|`Category`|红酒|
|Whisky|"whisky"|`Category`|洋酒|
|Huangjiu|"huangjiu"|`Category`|黄酒|
|Sake|"sake"|`Category`|清酒|
|Fruit|"fruit"|`Category`|果酒|
|Cocktail|"cocktail"|`Category`|调酒|
|Other|"other"|`Category`|其他|
```javascript
const req = new GetStatsOverviewReq()
client.GetStatsOverview(req).then(...).catch(...)
```
### 获取月度统计
GET `/api/have_a_drink/v1/statistics/monthly`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|year|`number`|| 年份,默认当前年|
|month|`number`|| 月份,默认当前月|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`MonthlyStats`| 月度统计数据
|
**MonthlyStats**
|名称|类型|说明|
|:-|:-|:-|
|year|`number`| 年份|
|month|`number`| 月份|
|drinkDays|`number`| 饮酒天数|
|abstainDays|`number`| 戒酒天数|
|totalCups|`number`| 总标准杯数|
|avgCupsPerDay|`number`| 日均标准杯数|
|categoryBreakdown|`Array`| 酒类分布|
|feelingBreakdown|`Array`| 感受分布|
|foodBreakdown|`Array`| 配餐分布|
**CategoryBreakdown**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类|
|count|`number`| 次数|
|cups|`number`| 标准杯数|
**FeelingBreakdown**
|名称|类型|说明|
|:-|:-|:-|
|feeling|`Feeling`| 感受类型|
|count|`number`| 次数|
**FoodBreakdown**
|名称|类型|说明|
|:-|:-|:-|
|category|`FoodCategory`| 配餐分类|
|count|`number`| 次数|
```javascript
const req = new GetMonthlyStatsReq()
client.GetMonthlyStats(req).then(...).catch(...)
```
### 获取酒类分布统计
GET `/api/have_a_drink/v1/statistics/categories`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|data|`CategoryStatsData`| 酒类分布统计数据
|
**CategoryStatsData**
|名称|类型|说明|
|:-|:-|:-|
|categories|`Array`| 酒类分布列表|
**CategoryStats**
|名称|类型|说明|
|:-|:-|:-|
|id|`Category`| 酒类分类ID|
|name|`string`| 酒类名称|
|recordCount|`number`| 记录次数|
|totalCups|`number`| 总标准杯数|
|percentage|`number`| 占比(百分比)|
```javascript
const req = new GetCategoryStatsReq()
client.GetCategoryStats(req).then(...).catch(...)
```
### 获取用户信息
GET `/api/have_a_drink/v1/user/user/profile`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|id|`string\|number`| 用户ID
|
|nickname|`string`| 用户昵称
|
|avatar|`string`| 头像URL
|
|joinedAt|`string`| 加入时间
|
|preferences|`UserPreferences`| 用户偏好
|
**UserPreferences**
|名称|类型|说明|
|:-|:-|:-|
|favoriteCategories|`Array`| 偏好酒类ID列表|
|frequency|`Frequency`| 饮酒频率|
**Frequency**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Rarely|"rarely"|`Frequency`|很少|
|Sometimes|"sometimes"|`Frequency`|有时|
|Often|"often"|`Frequency`|经常|
```javascript
const req = new GetUserProfileReq()
client.GetUserProfile(req).then(...).catch(...)
```
### 更新用户偏好
PUT `/api/have_a_drink/v1/user/user/preferences`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|favoriteCategories|`Array`|| 偏好酒类ID列表|
|frequency|`Frequency`|很少: Frequency.Rarely = "rarely"
有时: Frequency.Sometimes = "sometimes"
经常: Frequency.Often = "often"| 饮酒频率|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|favoriteCategories|`Array`| 偏好酒类ID列表
|
|frequency|`Frequency`| 饮酒频率
很少: Frequency.Rarely = "rarely"
有时: Frequency.Sometimes = "sometimes"
经常: Frequency.Often = "often"|
```javascript
const req = new UpdatePreferencesReq()
client.UpdatePreferences(req).then(...).catch(...)
```
### 上传文件
POST `/api/have_a_drink/v1/upload/image`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|image|`any`|required| 图片|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|id|`string\|number`| 图片 id
|
|url|`string`| 图片 url
|
```javascript
const req = new UploadImageReq()
client.UploadImage(req).then(...).catch(...)
```
### 动态信息流
GET `/api/have_a_drink/v1/moments/feeds`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|lastId|`string\|number`|| 最后一条动态ID,用于分页|
|pageSize|`number`|| 每页数量|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 动态列表
|
|hasMore|`boolean`| 是否还有更多动态
|
**Feed**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 动态ID|
|userId|`string\|number`| 用户ID|
|nickname|`string`| 昵称|
|avatar|`string`| 头像|
|time|`string`| 发布时间|
|text|`string`| 动态文本|
|drinks|`Array`| 酒水标签|
|feeling|`Feeling`| 自我感觉|
|images|`Array`| 图片列表|
|likes|`number`| 点赞数|
|liked|`boolean`| 是否点赞|
|comments|`number`| 评论数|
**DrinkTag**
|名称|类型|说明|
|:-|:-|:-|
|category|`Category`| 酒类分类|
|name|`string`| 酒类名称|
|amount|`number`| 酒类数量|
**Feeling**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Tipsy|"tipsy"|`Feeling`|微醺|
|Buzzed|"buzzed"|`Feeling`|到位|
|Drunk|"drunk"|`Feeling`|醉了|
|Blackout|"blackout"|`Feeling`|断片|
```javascript
const req = new GetFeedsReq()
client.GetFeeds(req).then(...).catch(...)
```
### 发布动态
POST `/api/have_a_drink/v1/moments/feeds`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|text|`string`|| 动态文本|
|images|`Array`|| 图片列表|
|recordId|`string\|number`|| 关联的记录ID|
|visibility|`Visibility`|公开: Visibility.Public = "public"
仅好友: Visibility.Friends = "friends"
仅自己: Visibility.Private = "private"| 可见性|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|success|`boolean`| 是否成功
|
|feedId|`string\|number`| 动态ID
|
```javascript
const req = new PublishFeedReq()
client.PublishFeed(req).then(...).catch(...)
```
### 点赞
POST `/api/have_a_drink/v1/moments/feeds/like`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 动态ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|ok|`boolean`| 是否成功
|
```javascript
const req = new LikeFeedReq()
client.LikeFeed(req).then(...).catch(...)
```
### 取消点赞
POST `/api/have_a_drink/v1/moments/feeds/unlike`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 动态ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|ok|`boolean`| 是否成功
|
```javascript
const req = new UnlikeFeedReq()
client.UnlikeFeed(req).then(...).catch(...)
```
### 获取评论
GET `/api/have_a_drink/v1/moments/feeds/comments`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 动态ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 评论列表
|
**Comment**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 评论ID|
|userId|`string\|number`| 用户ID|
|nickname|`string`| 昵称|
|avatar|`string`| 头像|
|content|`string`| 评论内容|
|time|`string`| 评论时间|
```javascript
const req = new GetFeedCommentsReq()
client.GetFeedComments(req).then(...).catch(...)
```
### 发表评论
POST `/api/have_a_drink/v1/moments/feeds/comments`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 动态ID|
|content|`string`|| 评论内容|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|id|`string\|number`| 评论ID
|
|userId|`string\|number`| 用户ID
|
|nickname|`string`| 昵称
|
|avatar|`string`| 头像
|
|content|`string`| 评论内容
|
|time|`string`| 评论时间
|
```javascript
const req = new AddCommentFullReq()
client.AddComment(req).then(...).catch(...)
```
### 酒友管理
GET `/api/have_a_drink/v1/friends/friends`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|keyword|`string`|| 搜索关键词|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 分页数据
|
**Friend**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 酒友ID|
|nickname|`string`| 昵称|
|avatar|`string`| 头像|
|lastDrink|`string\|number`| 最近一次喝的酒|
|lastDrinkTime|`string`| 最近一次喝的酒时间|
|online|`boolean`| 是否在线|
```javascript
const req = new GetFriendsReq()
client.GetFriends(req).then(...).catch(...)
```
### 好友请求管理
GET `/api/have_a_drink/v1/friends/friend-requests`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 分页数据
|
**FriendRequest**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 好友请求ID|
|userId|`string\|number`| 酒友ID|
|nickname|`string`| 昵称|
|avatar|`string`| 头像|
|message|`string`| 消息|
|time|`string`| 创建时间|
```javascript
const req = new GetFriendRequestsReq()
client.GetFriendRequests(req).then(...).catch(...)
```
### 发送好友请求
POST `/api/have_a_drink/v1/friends/friend-requests`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|userId|`string\|number`|| 酒友ID|
|message|`string`|| 消息|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new SendFriendRequestReq()
client.SendFriendRequest(req).then(...).catch(...)
```
### 接受好友请求
POST `/api/have_a_drink/v1/friends/friend-requests/accept`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 好友请求ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new AcceptFriendRequestReq()
client.AcceptFriendRequest(req).then(...).catch(...)
```
### 删除酒友
DELETE `/api/have_a_drink/v1/friends/friends`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|userId|`string\|number`|| 酒友ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
```javascript
const req = new RemoveFriendReq()
client.RemoveFriend(req).then(...).catch(...)
```
### 约酒活动
GET `/api/have_a_drink/v1/events/events`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|status|`EventStatus`|开放报名: EventStatus.Open = 1
待开始: EventStatus.Upcoming = 2
进行中: EventStatus.Ongoing = 3
已结束: EventStatus.Ended = 4| 状态筛选|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 分页数据
|
**Event**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 酒局ID|
|title|`string`| 酒局标题|
|organizer|`User`| 酒局组织者|
|time|`string`| 酒局时间|
|location|`string`| 酒局地点|
|maxPeople|`number`| 最大人数|
|joined|`number`| 已报名人数|
|participants|`Array`| 已报名用户|
|status|`EventStatus`| 酒局状态|
|note|`string`| 酒局备注|
|isJoined|`boolean`| 是否已报名|
|isOrganizer|`boolean`| 是否为组织者|
**User**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 用户ID|
|nickname|`string`| 用户昵称|
|avatar|`string`| 头像URL|
|joinedAt|`string`| 加入时间|
|preferences|`UserPreferences`| 用户偏好|
**UserPreferences**
|名称|类型|说明|
|:-|:-|:-|
|favoriteCategories|`Array`| 偏好酒类ID列表|
|frequency|`Frequency`| 饮酒频率|
**Frequency**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Rarely|"rarely"|`Frequency`|很少|
|Sometimes|"sometimes"|`Frequency`|有时|
|Often|"often"|`Frequency`|经常|
**EventStatus**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Open|1|`EventStatus`|开放报名|
|Upcoming|2|`EventStatus`|待开始|
|Ongoing|3|`EventStatus`|进行中|
|Ended|4|`EventStatus`|已结束|
```javascript
const req = new GetEventsReq()
client.GetEvents(req).then(...).catch(...)
```
### 获取酒局详情
GET `/api/have_a_drink/v1/events/events/detail`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 酒局ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|id|`string\|number`| 酒局ID
|
|title|`string`| 酒局标题
|
|organizer|`User`| 酒局组织者
|
|time|`string`| 酒局时间
|
|location|`string`| 酒局地点
|
|maxPeople|`number`| 最大人数
|
|joined|`number`| 已报名人数
|
|participants|`Array`| 已报名用户
|
|status|`EventStatus`| 酒局状态
开放报名: EventStatus.Open = 1
待开始: EventStatus.Upcoming = 2
进行中: EventStatus.Ongoing = 3
已结束: EventStatus.Ended = 4|
|note|`string`| 酒局备注
|
|isJoined|`boolean`| 是否已报名
|
|isOrganizer|`boolean`| 是否为组织者
|
**User**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 用户ID|
|nickname|`string`| 用户昵称|
|avatar|`string`| 头像URL|
|joinedAt|`string`| 加入时间|
|preferences|`UserPreferences`| 用户偏好|
**UserPreferences**
|名称|类型|说明|
|:-|:-|:-|
|favoriteCategories|`Array`| 偏好酒类ID列表|
|frequency|`Frequency`| 饮酒频率|
```javascript
const req = new GetEventDetailReq()
client.GetEventDetail(req).then(...).catch(...)
```
### 发起酒局
POST `/api/have_a_drink/v1/events/events`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|title|`string`|| 酒局标题|
|time|`string`|| 酒局时间|
|location|`string`|| 酒局地点|
|maxPeople|`number`|| 最大人数|
|geo|`GeoPoint`|| 坐标信息|
|note|`string`|| 酒局备注|
**GeoPoint**
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|latitude|`number`|| 纬度|
|longitude|`number`|| 经度|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|eventId|`string\|number`| 酒局ID
|
```javascript
const req = new CreateEventReq()
client.CreateEvent(req).then(...).catch(...)
```
### 报名酒局
POST `/api/have_a_drink/v1/events/events/join`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 酒局ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|ok|`boolean`| 是否成功
|
```javascript
const req = new JoinEventReq()
client.JoinEvent(req).then(...).catch(...)
```
### 取消报名酒局
POST `/api/have_a_drink/v1/events/events/quit`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 酒局ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|ok|`boolean`| 是否成功
|
```javascript
const req = new QuitEventReq()
client.QuitEvent(req).then(...).catch(...)
```
### 签到酒局
POST `/api/have_a_drink/v1/events/events/checkin`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string\|number`|| 酒局ID|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|ok|`boolean`| 是否成功
|
```javascript
const req = new CheckInEventReq()
client.CheckInEvent(req).then(...).catch(...)
```
### 获取会话列表
GET `/api/have_a_drink/v1/chat/conversations`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 会话列表
|
**Conversation**
|名称|类型|说明|
|:-|:-|:-|
|id|`string`| 会话ID|
|friendId|`string\|number`| 对方用户ID|
|nickname|`string`| 对方昵称|
|avatar|`string`| 对方头像URL(可为空)|
|lastMessage|`string`| 最后一条消息摘要|
|lastTime|`string`| 最后消息时间(ISO 8601)|
|unread|`number`| 未读消息数|
|online|`boolean`| 对方是否在线|
```javascript
const req = new GetConversationsReq()
client.GetConversations(req).then(...).catch(...)
```
### 获取历史消息
GET `/api/have_a_drink/v1/chat/messages`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|conversationId|`string`|required| 会话ID|
|lastID|`string\|number`|| 游标分页|
|pageSize|`number`|gt=0,lte=100| 每页数量,默认20|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|list|`Array`| 消息列表
|
|hasMore|`boolean`| 是否还有更多消息
|
**Message**
|名称|类型|说明|
|:-|:-|:-|
|id|`string\|number`| 消息ID|
|conversationId|`string`| 会话ID|
|senderId|`string\|number`| 发送者ID|
|receiverId|`string\|number`| 接收者ID|
|type|`MessageType`| 消息类型|
|content|`string`| 消息内容|
|timestamp|`number`| 发送时间(毫秒时间戳)|
|status|`MessageStatus`| 消息状态|
**MessageType**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Text|"text"|`MessageType`|文本消息|
|Image|"image"|`MessageType`|图片消息|
**MessageStatus**
|名称|值|类型|说明|
|:-|:-:|:-|:-|
|Sending|"sending"|`MessageStatus`|发送中|
|Sent|"sent"|`MessageStatus`|已发送|
|Delivered|"delivered"|`MessageStatus`|已送达|
|Read|"read"|`MessageStatus`|已读|
```javascript
const req = new GetMessagesReq()
client.GetMessages(req).then(...).catch(...)
```
### 标记会话已读
POST `/api/have_a_drink/v1/chat/conversations/read`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|id|`string`|required| 会话ID(路径参数)|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|success|`boolean`| 是否成功
|
```javascript
const req = new MarkReadReq()
client.MarkRead(req).then(...).catch(...)
```
### 获取未读消息总数
GET `/api/have_a_drink/v1/chat/unread-count`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|total|`number`| 未读总数
|
```javascript
const req = new GetUnreadCountReq()
client.GetUnreadCount(req).then(...).catch(...)
```
### 注意:连接建立后,服务端会先验证 token,然后推送 connected 事件
WS `/api/have_a_drink/v1/chat/chat`
#### 请求参数
|名称|类型|校验规则|说明|
|:-|:-|:-|:-|
|mesgType|`ClientMesgType`|发送消息: ClientMesgType.Chat = "chat"
输入状态: ClientMesgType.Typing = "typing"
已读回执: ClientMesgType.Read = "read"
心跳: ClientMesgType.Ping = "ping"| 消息类型|
|data|`ClientMessage`|| 消息数据|
#### 返回值
|名称|类型|说明|
|:-|:-:|:-|
|mesgType|`ServerMesgType`| 消息类型
推送新消息: ServerMesgType.Chat = "chat"
对方输入状态: ServerMesgType.Typing = "typing"
对方已读回执: ServerMesgType.Read = "read"
消息送达确认: ServerMesgType.Ack = "ack"
心跳响应: ServerMesgType.Pong = "pong"
连接成功: ServerMesgType.Connected = "connected"
被踢下线: ServerMesgType.Kicked = "kicked"|
|data|`ServerMessage`| 消息数据
|
```javascript
const req = new ChatWebSocket()
client.ChatWebSocket(req).then(...).catch(...)
```