268 lines
8.9 KiB
Markdown
268 lines
8.9 KiB
Markdown
# 七日签到后端接口文档
|
||
|
||
## 1. 基本约定
|
||
|
||
- 基础地址:`https://<APPID>.laf.run`
|
||
- 数据格式:`application/json`
|
||
- 时区:UTC+8
|
||
- 活动周期:触发当天为第 1 个自然日,第 15 天 00:00 结束
|
||
- 签到规则:14 个自然日内累计领取 7 次,允许断签,每个自然日最多领取一次
|
||
- 适用用户库:仅主游戏 `users`;`gameName: "iaa"` 不支持签到活动
|
||
- 身份校验:请求携带登录接口返回的 `uid` 和 `token`
|
||
- 通用成功码:`code: 1`
|
||
- 通用失败码:`code: 0`
|
||
|
||
签到奖励由后端校验并记录,实际金币、道具、无限体力和猫皮肤仍由前端根据领取接口返回的 `rewards` 发放。前端必须使用 `claimId` 做发奖幂等。
|
||
|
||
## 2. 推荐调用流程
|
||
|
||
1. 玩家进入主界面后调用 `signInActivityInfo`。
|
||
2. 如果返回 `data: false`,表示玩家尚未达到目标关卡,不展示活动。
|
||
3. 如果返回活动对象,按照 `status`、`canClaim`、`todayClaimed` 和 `rewards` 渲染活动。
|
||
4. 玩家点击领取时调用 `signInClaim`。
|
||
5. 领取成功后,前端先检查本地是否处理过 `claimId`,未处理过才发放 `rewards`。
|
||
6. 发奖完成后保存 `claimId`,并重新请求 `signInActivityInfo` 刷新页面状态。
|
||
|
||
活动只在 `users.levelAmount` 达到目标关卡且没有活动状态的用户首次调用 `signInActivityInfo` 时创建。`login` 和 `setUserLevel` 均不读取签到配置、不判断签到资格,也不创建签到活动。
|
||
|
||
## 3. 查询签到活动信息
|
||
|
||
### `POST /signInActivityInfo`
|
||
|
||
云函数同时配置了 GET 和 POST;客户端统一使用 POST。
|
||
|
||
### 请求参数
|
||
|
||
```ts
|
||
interface SignInActivityInfoRequest {
|
||
uid: string;
|
||
token: string;
|
||
gameName?: string;
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `uid` | string | 是 | 用户 `_id` |
|
||
| `token` | string | 是 | 登录令牌 |
|
||
| `gameName` | string | 否 | 不传表示主游戏;传 `iaa` 会被拒绝 |
|
||
|
||
### 未达到目标关卡
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"data": false,
|
||
"msg": "未达到签到活动开启关卡"
|
||
}
|
||
```
|
||
|
||
### 达到目标关卡
|
||
|
||
用户没有活动状态时,本次请求会创建活动;已有活动状态时不会重置开始和结束时间。
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"data": {
|
||
"serverNow": 1788310800000,
|
||
"activityId": "seven_day_sign_in_v1",
|
||
"status": "active",
|
||
"triggerLevel": 23,
|
||
"triggerReached": true,
|
||
"startAt": 1788278400000,
|
||
"endAt": 1789488000000,
|
||
"claimedCount": 0,
|
||
"todayClaimed": false,
|
||
"canClaim": true,
|
||
"nextRewardDay": 1,
|
||
"rewards": [
|
||
{
|
||
"day": 1,
|
||
"items": [
|
||
{ "type": "infinite_health", "count": 900 }
|
||
],
|
||
"claimed": false
|
||
}
|
||
]
|
||
},
|
||
"msg": "成功"
|
||
}
|
||
```
|
||
|
||
### 返回字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| `serverNow` | number | 服务器当前毫秒时间戳 |
|
||
| `activityId` | string | 用户参与的活动配置 ID |
|
||
| `status` | string | `active`、`completed` 或 `expired` |
|
||
| `triggerLevel` | number | 活动开启目标关卡,当前配置为 23 |
|
||
| `triggerReached` | boolean | 服务端根据 `users.levelAmount` 确认的关卡是否达标 |
|
||
| `startAt` | number | 活动第 1 天 UTC+8 零点时间戳 |
|
||
| `endAt` | number | 活动结束时间戳,不包含该时刻 |
|
||
| `claimedCount` | number | 已领取奖励天数,范围 0~7 |
|
||
| `todayClaimed` | boolean | 当前 UTC+8 自然日是否已经领取 |
|
||
| `canClaim` | boolean | 当前是否可以领取下一档奖励 |
|
||
| `nextRewardDay` | number \| null | 下一档奖励序号;当前不可领取时为 `null` |
|
||
| `rewards` | RewardDay[] | 完整七天奖励及每档领取状态 |
|
||
|
||
状态说明:
|
||
|
||
| 状态 | 说明 |
|
||
| --- | --- |
|
||
| `active` | 活动期内且尚未领取满 7 天 |
|
||
| `completed` | 已领取全部 7 天奖励 |
|
||
| `expired` | 已到第 15 天 00:00 且未领取满 7 天 |
|
||
|
||
## 4. 领取签到奖励
|
||
|
||
### `POST /signInClaim`
|
||
|
||
客户端不能指定领取第几天。后端按照当前累计领取次数自动发放下一档配置,并使用用户、活动和自然日生成唯一 `claimId`。
|
||
|
||
### 请求参数
|
||
|
||
```ts
|
||
interface SignInClaimRequest {
|
||
uid: string;
|
||
token: string;
|
||
gameName?: string;
|
||
}
|
||
```
|
||
|
||
### 成功响应
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"data": {
|
||
"claimId": "71b4...9a2f",
|
||
"rewardDay": 1,
|
||
"rewards": [
|
||
{ "type": "infinite_health", "count": 900 }
|
||
],
|
||
"claimedCount": 1,
|
||
"todayClaimed": true,
|
||
"completed": false
|
||
},
|
||
"msg": "领取成功"
|
||
}
|
||
```
|
||
|
||
### 返回字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| `claimId` | string | 本次领取唯一标识,前端发奖幂等键 |
|
||
| `rewardDay` | number | 本次领取的奖励序号,范围 1~7 |
|
||
| `rewards` | RewardItem[] | 本次需要由前端发放的奖励 |
|
||
| `claimedCount` | number | 领取成功后的累计领取天数 |
|
||
| `todayClaimed` | boolean | 成功时固定为 `true` |
|
||
| `completed` | boolean | 本次领取后是否已经领满 7 天 |
|
||
|
||
## 5. 奖励数据结构
|
||
|
||
```ts
|
||
interface RewardDay {
|
||
day: number;
|
||
items: RewardItem[];
|
||
claimed: boolean;
|
||
}
|
||
|
||
interface RewardItem {
|
||
type: "coin" | "freeze" | "hammer" | "magic_wand" | "infinite_health" | "cat_skin";
|
||
count: number;
|
||
itemId?: number;
|
||
}
|
||
```
|
||
|
||
| `type` | 含义 | `count` 单位 | 额外字段 |
|
||
| --- | --- | --- | --- |
|
||
| `coin` | 金币 | 个 | 无 |
|
||
| `hammer` | 锤子 | 个 | 无 |
|
||
| `freeze` | 冻结道具 | 个 | 无 |
|
||
| `magic_wand` | 魔法棒 | 个 | 无 |
|
||
| `infinite_health` | 无限体力 | 秒 | 无 |
|
||
| `cat_skin` | 猫皮肤 | 个 | 必须提供正整数 `itemId` |
|
||
|
||
当前七天配置:
|
||
|
||
| Day | 奖励数据 | 展示含义 |
|
||
| --- | --- | --- |
|
||
| 1 | `infinite_health: 900` | 无限体力 15 分钟 |
|
||
| 2 | `hammer: 1` | 锤子 ×1 |
|
||
| 3 | `infinite_health: 1800` | 无限体力 30 分钟 |
|
||
| 4 | `freeze: 1`、`magic_wand: 1` | 冻结 ×1、魔法棒 ×1 |
|
||
| 5 | `coin: 600` | 金币 ×600 |
|
||
| 6 | `hammer: 1`、`freeze: 1`、`magic_wand: 1` | 三种道具各 ×1 |
|
||
| 7 | `infinite_health: 3600`、`cat_skin: 1, itemId: 12` | 无限体力 1 小时、专属猫 12 |
|
||
|
||
## 6. 错误响应
|
||
|
||
两个签到接口共用的错误:
|
||
|
||
| `code` | `data` | `msg` | 触发条件 |
|
||
| --- | --- | --- | --- |
|
||
| 0 | null | `未获取到uid` | 未传 `uid` |
|
||
| 0 | null | `七日签到仅支持主游戏` | `gameName` 为 `iaa` |
|
||
| 0 | null | `未获取到用户信息` | 用户不存在 |
|
||
| 0 | null | `token校验失败` | token 不匹配 |
|
||
| 0 | null | `签到活动配置不存在或配置无效` | 找不到配置、配置非法或同时启用多条配置 |
|
||
|
||
`signInActivityInfo` 特有错误:
|
||
|
||
| `code` | `data` | `msg` |
|
||
| --- | --- | --- |
|
||
| 0 | null | `签到活动开启失败` |
|
||
|
||
`signInClaim` 特有错误:
|
||
|
||
| `code` | `data` | `msg` |
|
||
| --- | --- | --- |
|
||
| 0 | null | `签到活动尚未开启` |
|
||
| 0 | null | `七日签到奖励已全部领取` |
|
||
| 0 | null | `七日签到活动已结束` |
|
||
| 0 | null | `今天已经领取` |
|
||
| 0 | null | `签到奖励配置异常` |
|
||
|
||
## 7. 数据库配置
|
||
|
||
配置集合:`sign_in_activity_config`
|
||
|
||
- 必须且只能存在一条 `enabled: true` 的有效配置。
|
||
- 当前可导入配置文件:`laf-cloud/sign-in-activity-config.json`。
|
||
- 用户开始活动后通过 `activityId` 继续读取配置,因此旧配置可以禁用,但在参与用户全部结束前不能删除。
|
||
|
||
用户活动状态写入 `users.signInActivity`。数据库中使用 JSON 字符串保存,读取时由服务端解析为下述结构;这样可以兼容字段原值为 `null` 的用户,并避免 Laf 将对象更新展开成点路径后触发 MongoDB 错误:
|
||
|
||
```ts
|
||
interface SignInActivityState {
|
||
activityId: string;
|
||
startAt: number;
|
||
endAt: number;
|
||
activatedAt: number;
|
||
completedAt: number | null;
|
||
}
|
||
```
|
||
|
||
领取记录集合:`sign_in_activity_claims`
|
||
|
||
- 每次领取保存奖励序号、奖励快照和领取时间。
|
||
- 记录 `_id` 与 `claimId` 相同,由 `uid + activityId + UTC+8自然日` 计算 SHA-256。
|
||
- 同一用户、同一活动、同一自然日的并发请求只能成功写入一条记录。
|
||
|
||
## 8. 前端接入注意事项
|
||
|
||
- 不要根据客户端本地关卡自行判定资格;服务端使用 `users.levelAmount` 判断,以 `signInActivityInfo` 返回值为准。
|
||
- `data: false` 是正常成功响应,不应作为网络或服务器错误处理。
|
||
- 领取成功不代表后端已经增加资产;前端负责发奖。
|
||
- 前端必须保存已处理的 `claimId`,避免重复回调造成重复发奖。
|
||
- `infinite_health.count` 单位是秒。
|
||
- Day 7 的 `cat_skin.itemId` 当前为 12,客户端必须先支持猫 12 的资源、展示和幂等写入 `catArr`。
|
||
- 倒计时使用 `serverNow` 和 `endAt`,不要完全依赖客户端本地时间。
|
||
|
||
## 9. 单账号测试接口
|
||
|
||
测试环境可发布 `POST /signInTestAdmin`,用一个账号快速准备未达标、待领取 Day 1~7、当天已领、过期和完成状态。该接口的密钥配置、参数和测试顺序见 `laf-cloud/signInActivity.TESTING.md`;禁止在正式环境发布。
|