MatchMaster/docs/GoldMiner-FRONTEND-API-v1.3.md

622 lines
36 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.3
> 历史协议副本(2026-09-30 标注):仓库最新协议为 [V1.7](../server/laf-cloud/functions/goldMiner/FRONTEND-API.md)。正文保留历史内容,附属链接已修复并指向仓库当前资料;顺序领奖、旧补发等条款不能覆盖当前协议。客户端差异见 [接入说明](GoldMiner接入说明.md)。
更新时间:2026-09-18。依据当前 `local` 分支实现编写,包含精简后的 `info` 协议。示例价格、目标和金币仅用于联调,页面必须使用接口返回值。部署环境需具有相同版本的后端代码。
## 1. 接入约定与接口总览
所有下列请求均使用 **POST + JSON Body**,请求头为 `Content-Type: application/json`。地址前缀 `{{baseUrl}}` 替换为后端提供的测试服或正式服域名;不要将两个环境的账号、订单和 token 混用。部分通用函数配置也允许 GET,但实现读取 `ctx.body`,前端统一使用 POST。
| 用途 | 地址 | action |
| --- | --- | --- |
| 活动信息、任务状态 | `/goldMiner/index` | `info` |
| 客服渠道创建活动订单 | `/goldMiner/index` | `create_order` |
| 申请领取单档奖励 | `/goldMiner/index` | `claim` |
| 确认客户端已保存奖励 | `/goldMiner/index` | `confirm_delivery` |
| 查询往期补发列表 | `/goldMiner/index` | `settlements` |
| 确认补发记录已处理 | `/goldMiner/index` | `ack_settlement` |
| 通关上报、读取主线进度 | `/userLevel` | `save` / `read` |
| 保存、读取金币余额 | `/userCoin` | `save` / `read` |
| 原生支付下单 | `/wx/orderPaySig`;iOS 入口 `/wx/iosorderPaySig` | 不传 |
| 查询支付及活动权益 | `/wx/getPayInfo`、`/wx/iosgetPayInfo` | 不传 |
| 兼容旧订单领取入口 | `/wx/getOrderReward` | 不传 |
| 外部支付页转单 | `/wx/checkIos` | 不传 |
`iosorderPaySig.ts` 在仓库中没有配套 YAML,使用该入口前需后端确认测试服已发布同名 POST 云函数;不能仅凭源码存在判断线上可调用。
### 公共参数与类型
除支付页票据鉴权方式外,游戏端请求均在 Body 中携带以下字段:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| uid | string | 是 | 当前登录玩家 ID,使用 `users` 账号 |
| token | string | 是 | 当前登录 token;过期后按游戏登录流程刷新 |
| action | string | 按接口 | `/goldMiner/index`、`userLevel`、`userCoin` 必填 |
黄金矿工不支持 `gameName: "iaa"`,游戏端不传此值。无需在 Authorization Header 中重复传 token。
时间戳均为 Unix **毫秒**;日期安排按北京时间 `Asia/Shanghai`。活动周四 00:00 开始,下周一 00:00 结束,结束时间为不包含的边界。金额 `priceFen` 单位为分,显示元时除以 100。数量及进度使用整数,布尔值使用 JSON boolean。
`periodId` 格式为 `goldMiner:YYYY-MM-DD`,日期必须是该期周四,例如 `goldMiner:2026-09-17`。游戏优先使用服务端返回的期 ID。`eventId`、`requestId`、`createRequestId` 等标识支持 1~100 位英文字母、数字、下划线、冒号及连字符;可使用 UUID。生成后必须随原操作保存,重试时复用。
### 返回包装
活动接口及黄金矿工支付分支成功结构:
```json
{"code":1,"data":{},"msg":"成功"}
```
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| code | number | `1` 为业务成功,`0` 为业务失败;不能仅依靠 HTTP 状态判断 |
| data | object / null | 各接口业务数据;活动标准失败时为 null |
| msg | string | 提示信息,不作为程序状态判断依据 |
| errorCode | string | 活动标准失败时返回,用于程序分支 |
```json
{"code":0,"data":null,"errorCode":"NOT_PAID","msg":"NOT_PAID"}
```
例外:`wx/checkIos` 直接返回 `true` / `false`;通用接口的前置校验可能只有 `code/data/msg`、没有 `errorCode`。`userLevel` 和 `userCoin` 的无效 action 返回 `{ "code":400, "message":"无效的操作类型,请使用 save 或 read" }`。网络错误、空响应也需单独处理。
## 2. 获取活动信息:info
**POST `{{baseUrl}}/goldMiner/index`**
请求只有公共参数,`action` 固定为 `info`,不传 periodId。
```json
{"action":"info","uid":"USER_ID","token":"LOGIN_TOKEN"}
```
### data 字段
| 字段 | 类型 | 返回条件 | 含义 |
| --- | --- | --- | --- |
| serverTime | number | 总是 | 服务器时间,辅助校正倒计时 |
| status | string | 总是 | 下表中的活动状态 |
| periodId | string | 总是 | 当前日历对应的活动期 ID |
| startsAt | number | 除 locked 外 | 该期开始时间 |
| endsAt | number | 除 locked 外 | 该期结束边界,倒计时到此结束 |
| configVersion | string | 可展示活动时 | 本期冻结的配置版本,可用于日志排查 |
| priceFen | number | 可展示活动时 | 本期单次解锁价格,单位分 |
| productId | string | 可展示活动时 | 下单使用的商品 ID,不要写死 |
| progressWins | number | 可展示活动时 | 本期累计有效胜利数,上限为 maxTarget |
| maxTarget | number | 可展示活动时 | 最后一档累计目标 |
| tasks | array | 总是 | 按领取顺序排好的任务;locked/unavailable 时为空 |
“可展示活动时”指 `purchasable`、`purchase_disabled`、`unlocked`。缺省字段不是 0 或 false,不能用上一期缓存填充。
| status | 含义 | 前端处理 |
| --- | --- | --- |
| unavailable | 非开放时段、无有效配置,或请求期间活动已结束 | 关闭当期购买和领取;往期补发仍可单独查询 |
| locked | 活动开放,但未满足主线资格门槛 | 不展示可购买任务页;按产品要求展示入口门槛提示 |
| purchasable | 已获资格,未付费,允许购买 | 展示价格和购买按钮;未付费也累计进度 |
| purchase_disabled | 已获资格,未付费,本期暂停购买 | 隐藏/禁用购买按钮;仍展示和累计进度 |
| unlocked | 本期资格已解锁 | 隐藏购买按钮,按任务状态展示领取操作 |
默认通过主线第 41 关后获得资格;门槛可由后端配置。info 不返回具体门槛数值,如需显示门槛文案应与活动配置保持一致。`unlocked` 包含正常购买及延期支付顺延生效;前端不需区分来源。
### tasks[] 字段
| 字段 | 类型 | 含义 |
| --- | --- | --- |
| taskId | string | 档位 ID,领取时原样传回;不能拿数组下标替代 |
| targetWins | number | 本期累计通关目标,例如 3、5、7、9、10 |
| itemsSnapshot | array | 本档奖励快照,元素字段见下表 |
| claimStatus | string | locked / claimable / issuing / claimed |
| completed | boolean | 累计胜利是否达到该档目标,与是否付费、是否可领取无关 |
| progress | number | `min(progressWins, targetWins)`,是通关数,不是百分比 |
| itemsSnapshot[] 字段 | 类型 | 含义 |
| --- | --- | --- |
| type | string | 道具类型,当前配置仅支持 `coin`(金币) |
| count | number | 道具数量,正整数 |
保留数组结构以便以后扩展道具。出现客户端暂不支持的道具类型时,不应静默跳过并确认已到账。
| claimStatus | 含义 | 操作 |
| --- | --- | --- |
| locked | 未付费、目标未达成,或前一档尚未完成到账确认 | 不能领取;即便 completed=true 也可能处于此状态 |
| claimable | 已付费、已达标且前序档位已确认 | 调用 claim |
| issuing | 已取得奖励授权,但尚未确认客户端保存成功 | 对同一 periodId/taskId 再调用 claim,恢复原 grantId 的流程 |
| claimed | 本档客户端到账已经确认 | 展示已领取,不再增加金币 |
任务顺序由后端保证,无需 sequence。第一档未领取不阻止后续档累积进度,但第一档完成 `confirm_delivery` 前不能领取第二档。
完整示例:本期尚未购买,但已通关 3 次。
```json
{
"code": 1,
"data": {
"serverTime": 1789723456450,
"status": "purchasable",
"periodId": "goldMiner:2026-09-17",
"startsAt": 1789574400000,
"endsAt": 1789920000000,
"configVersion": "gold_miner_test_20260917_v1",
"priceFen": 100,
"productId": "gold_miner",
"progressWins": 3,
"maxTarget": 10,
"tasks": [
{"taskId":"task_1","targetWins":3,"itemsSnapshot":[{"type":"coin","count":100}],"claimStatus":"locked","completed":true,"progress":3},
{"taskId":"task_2","targetWins":5,"itemsSnapshot":[{"type":"coin","count":200}],"claimStatus":"locked","completed":false,"progress":3},
{"taskId":"task_3","targetWins":7,"itemsSnapshot":[{"type":"coin","count":300}],"claimStatus":"locked","completed":false,"progress":3},
{"taskId":"task_4","targetWins":9,"itemsSnapshot":[{"type":"coin","count":400}],"claimStatus":"locked","completed":false,"progress":3},
{"taskId":"task_5","targetWins":10,"itemsSnapshot":[{"type":"coin","count":500}],"claimStatus":"locked","completed":false,"progress":3}
]
},
"msg": "成功"
}
```
未达门槛时的完整 data:
```json
{"serverTime":1789723456450,"status":"locked","periodId":"goldMiner:2026-09-17","tasks":[]}
```
不可用时的完整 data(示例为周一休息期):
```json
{"serverTime":1789920000000,"status":"unavailable","periodId":"goldMiner:2026-09-17","startsAt":1789574400000,"endsAt":1789920000000,"tasks":[]}
```
不可用状态下的日期来自活动日历,不能据此认定活动已启用或计算下一期购买资格。
## 3. 通关上报:userLevel/save
**POST `{{baseUrl}}/userLevel`**。在现有关卡保存请求中附带 `goldMiner`,不要依赖玩家是否打开活动页面或是否付费。每次有效胜利上报一个事件,黄金矿工每个事件加 1,不按 levelAmount 的差值一次增加多关。
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| action | string | 是 | `save` |
| uid / token | string | 是 | 公共鉴权参数 |
| levelAmount | number | 是 | 本次保存后的主线通关整值;无尽模式保持现有主线值 |
| isWuXian | string | 无尽必填 | 无尽传字符串 `"true"`;主线省略。沿用旧协议字符串形式 |
| goldMiner | object | 活动统计必填 | 不携带则只保存普通关卡,不增加活动进度 |
| goldMiner.periodId | string | 是 | 本次胜利首次上报对应的活动期;重试不更换 |
| goldMiner.eventId | string | 是 | 本次胜利的唯一事件 ID;重试保持不变 |
| goldMiner.outcome | string | 是 | 固定 `win`,失败、放弃不报活动胜利 |
| goldMiner.mode | string | 是 | `main` 或 `endless`,必须与 isWuXian 对应 |
| goldMiner.clearedMainLevel | number | 主线必填 | 本次通过的主线关号,正整数且须等于 levelAmount |
| goldMiner.endlessSequence | number | 无尽必填 | 无尽成功结算序号,正整数;同一胜利重试相同,新胜利使用新序号 |
主线示例:
```json
{"action":"save","uid":"USER_ID","token":"LOGIN_TOKEN","levelAmount":42,"goldMiner":{"periodId":"goldMiner:2026-09-17","eventId":"win-main-42","outcome":"win","mode":"main","clearedMainLevel":42}}
```
无尽示例(1000 仅是假设的当前主线通关值):
```json
{"action":"save","uid":"USER_ID","token":"LOGIN_TOKEN","levelAmount":1000,"isWuXian":"true","goldMiner":{"periodId":"goldMiner:2026-09-17","eventId":"win-endless-123","outcome":"win","mode":"endless","endlessSequence":123}}
```
无尽序号需持久化,并避免同一账号多设备生成冲突序号;不能使用循环复用的关卡模板号。同一期按 eventId 和“模式 + 关号/序号”两层去重:换 eventId 重报同一关也不会再加活动进度。
### 返回字段
```json
{"code":1,"data":{"goldMiner":{"code":1,"activityCounted":true,"duplicate":false,"progressWins":1},"IP":"127.0.0.1","address":"其他","rank":-1,"levelAmount":42,"film":42,"timestamp":1789723456450},"msg":"用户数据更新成功"}
```
| data 字段 | 类型 | 含义 |
| --- | --- | --- |
| goldMiner | object,可缺省 | 活动处理结果;仅请求携带活动事件时返回 |
| IP / address | string | 原关卡接口的请求 IP / 地址信息 |
| rank | number | 原排行处理结果,默认 -1;活动 UI 不依赖 |
| levelAmount | number | 已保存的主线通关值 |
| film | number | 原关卡进度相关字段,不是活动进度 |
| timestamp | number | 本次响应时间 |
| data.goldMiner 字段 | 类型 | 含义 |
| --- | --- | --- |
| code | number | 活动处理独立结果:1 成功、0 失败 |
| activityCounted | boolean | 成功时是否新增了 1 次活动胜利 |
| duplicate | boolean,可缺省 | 成功时是否命中历史事件;资格关分支没有此字段 |
| progressWins | number | 活动处理成功后的累计胜利数 |
| reason | string,可缺省 | `qualification_level` 表示本次关号不高于资格门槛,不计入活动 |
| data / errorCode / msg | null / string / string | 活动失败时使用标准失败包装字段 |
活动失败仍可能出现外层 code=1,表示主线保存成功。例如 `data.goldMiner={"code":0,"data":null,"errorCode":"PERIOD_ENDED","msg":"PERIOD_ENDED"}`,不能因此重复推进普通关卡。
- 通过第 41 关获得资格,但该次胜利不计;从后续胜利开始计数。开放前的胜利不追溯。
- 开放前开局、开放期间胜利并成功上报可计;结束后才到达服务端的新事件不补记。已记录事件结束后重试可返回 duplicate=true,但不会新增进度。
- 达到 maxTarget 后 activityCounted=false;它不一定意味着 duplicate=true。
- 旧 userLevel 会在与已存主线值相差超过 10 时提前结束,可能没有正常 JSON 返回;应按既有关卡保存约束调用。
- 活动事件去重不等于整个 userLevel 幂等:重试无尽 save 仍可能影响旧的生涯统计。按现有通关队列管理重试,不能把该接口当作纯活动重试入口无限重放。
读取普通主线进度可传 `{"action":"read","uid":"USER_ID","token":"LOGIN_TOKEN"}`;成功 data 为 `levelAmount:number, film:number, timestamp:number`,不返回黄金矿工状态。刷新活动使用 info。
## 4. 支付下单与查询
### 4.1 原生支付下单
**POST `/wx/orderPaySig`** 或 **POST `/wx/iosorderPaySig`**,按项目支付入口选择。
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| uid / token | string | 是 | 公共鉴权参数 |
| itemid | string | 是 | info.productId,注意参数名为小写 itemid |
| createRequestId | string | 是 | 本次创建订单请求标识,重试复用 |
```json
{"uid":"USER_ID","token":"LOGIN_TOKEN","itemid":"gold_miner","createRequestId":"buy-20260917-001"}
```
不需传 periodId、价格或数量,后端绑定当前开放期、冻结价格和数量 1。即使传入 itemPrice/itemCount,也不能修改活动价格或数量。
| 成功 data 字段 | 类型 | 含义 |
| --- | --- | --- |
| outTradeNo | string | 后端订单号,持久化用于查询和恢复 |
| signData | string | 原生支付签名原文,是 JSON 字符串;完整保留,不修改或解析后重新序列化 |
| signature | string | 玩家会话签名,交给现有原生支付流程 |
| paySig | string | 支付签名,交给现有原生支付流程 |
返回结构示例(签名内容仅为占位,不能用于实际支付):
```json
{"code":1,"data":{"outTradeNo":"ORDER_NO_FROM_CREATE","signData":"SIGNED_JSON_STRING_FROM_SERVER","signature":"SESSION_SIGNATURE_FROM_SERVER","paySig":"PAY_SIGNATURE_FROM_SERVER"},"msg":"成功"}
```
测试服与正式服隔离不等于免费支付沙箱;当前原生签名使用支付环境 env=0,联调支付应使用后端确认的测试商品和金额。
同环境、账号、期次只创建一个稳定订单;重试或更换 createRequestId 不会创建第二笔活动订单。不要在重试时切换原生/客服渠道,已有另一渠道订单会报 PAYMENT_CHANNEL_CONFLICT。
### 4.2 客服渠道下单
**POST `/goldMiner/index`**。
```json
{"action":"create_order","channel":"legacy_ios","uid":"USER_ID","token":"LOGIN_TOKEN","itemid":"gold_miner","createRequestId":"buy-20260917-001"}
```
参数与原生下单相同,另外必填 `action:"create_order"` 和 `channel:"legacy_ios"`。成功 data:
| 字段 | 类型 | 含义 |
| --- | --- | --- |
| outTradeNo | string | 本期稳定订单号 |
| periodId | string | 订单所属期 |
| priceFen | number | 订单价格,分 |
| productId | string | 商品 ID |
| quantity | number | 固定 1 |
| channel | string | 固定 legacy_ios |
| expiresAt | number | 本次客服票据到期时间,最长 15 分钟且不超过活动结束 |
| sessionFrom | string | 已签名的客服入口参数字符串,原样传入现有 `wx.openCustomerServiceConversation` 的 sessionFrom |
返回结构示例(sessionFrom 为不可手工生成的占位字符串):
```json
{"code":1,"data":{"outTradeNo":"ORDER_NO_FROM_CREATE","periodId":"goldMiner:2026-09-17","priceFen":100,"productId":"gold_miner","quantity":1,"channel":"legacy_ios","expiresAt":1789724356450,"sessionFrom":"SIGNED_SESSION_FROM_SERVER"},"msg":"成功"}
```
不要自己拼接 sessionFrom、修改内部字段或把登录 token 放进支付页 URL。票据到期且活动仍开放时,可重新调用 create_order 获取新票据,订单号保持稳定。客服网关处理后给玩家发送支付页链接;游戏端不直接调用 `wx/KeFu` 模拟客服事件。
### 4.3 查询支付结果和权益
**POST `/wx/getPayInfo`** 或 **POST `/wx/iosgetPayInfo`**。兼容入口 **POST `/wx/getOrderReward`** 对黄金矿工也返回同一协议,不直接发金币。
```json
{"uid":"USER_ID","token":"LOGIN_TOKEN","outTradeNo":"ORDER_NO_FROM_CREATE"}
```
三个参数均为必填 string,不需 action。原生支付以已验证的服务端通知为依据;客服渠道还会按后端节流策略主动查单。客户端支付成功回调只用于触发查询,不能代替服务端确认。
| 成功 data 字段 | 类型 | 含义 |
| --- | --- | --- |
| pay_state | number | 黄金矿工成功固定为 2,表示支付及权益已确认,不表示所有任务已领奖 |
| rewardDelivery | string | 固定 `goldMiner.claim`,后续逐档领取 |
| goldMiner | object | 当前订单的活动元数据,完整字段见下面两表 |
`goldMiner` 目前为订单快照直出,比 info 字段多。前端主要使用 `fulfillmentRoute` 和 `targetPeriodId`,其余字段供核对日志,不用于自行计算领取资格。
| goldMiner 字段 | 类型 | 含义 |
| --- | --- | --- |
| schemaVersion | number | 当前 1 |
| uid / accountScope | string | 所属玩家 / 固定 users |
| paymentChannel | string | native 或 legacy_ios |
| periodId | string | 原购买期 |
| startsAt / endsAt | number | 原购买期时间边界 |
| configVersion / configHash | string | 订单绑定配置版本 / 哈希 |
| productSnapshot | object | `productId:string`、`priceFen:number`,订单冻结商品信息 |
| createRequestId | string | 首次建单请求标识 |
| confirmedAt | number | 服务端确认支付的毫秒时间 |
| fulfillmentStatus | string | 成功响应中为 fulfilled;处理中/失败通过错误响应表示 |
| fulfillmentRoute | string | current_period / settle_original / carry_next,见下表 |
| targetPeriodId | string | 实际分配权益的目标期 |
| revision | number | 内部版本字段,前端无需参与维护 |
| entitlementId | string | 已分配权益记录 ID |
| fulfilledAt | number | 权益处理完成时间 |
| lastErrorCode | string,可缺省 | 曾经处理失败的原因,成功后可能仍保留,不能覆盖当前成功结论 |
| nextRetryAt | number,可缺省 | 曾设置的后端重试时间,同样可能是历史值 |
客服订单还可能携带以下字段;按实际存在读取,前端不需回传:
| goldMiner 字段 | 类型 | 含义 |
| --- | --- | --- |
| merchantSnapshot | object | `mchid/appid/notifyUrl/pageUrl/checkUrl` 均为 string:商户及接入地址快照 |
| prepayState | string | created / creating / ready / paid / closed;成功支付后为 paid |
| prepayId / prepayExpiresAt | string / number | 预支付 ID / 到期时间,可缺省 |
| ioLeaseUntil / ioLeaseToken | number / string | 后端并发处理锁信息,token 可缺省,不是玩家鉴权 token |
| nextQueryAt / queryAttempts | number | 后端下次查单时间 / 查单次数 |
| lastQueryError | string / null | 最近查单错误,可缺省 |
| transactionId | string | 微信交易号 |
| paidAt | number | 支付平台记录的支付成功时间 |
| confirmationSource | string | merchant_notify 或 merchant_query,支付确认来源 |
| fulfillmentRoute | 含义 | 前端下一步 |
| --- | --- | --- |
| current_period | 权益分配到原购买期 | 重新 info;若此时已结束则查询 settlements |
| settle_original | 延迟支付确认时原期已结束,存在达标奖励 | 查询 settlements,按原期逐档补发 |
| carry_next | 延迟支付确认时原期无可结算奖励,资格顺延下一期 | 提示目标期生效;目标期开放后 info 返回 unlocked,无需再买 |
原生订单正常解锁的完整响应示例(标识和哈希为占位):
```json
{
"code": 1,
"data": {
"pay_state": 2,
"rewardDelivery": "goldMiner.claim",
"goldMiner": {
"schemaVersion": 1,
"uid": "USER_ID",
"accountScope": "users",
"paymentChannel": "native",
"periodId": "goldMiner:2026-09-17",
"startsAt": 1789574400000,
"endsAt": 1789920000000,
"configVersion": "gold_miner_test_20260917_v1",
"configHash": "CONFIG_HASH_FROM_SERVER",
"productSnapshot": {"productId":"gold_miner","priceFen":100},
"createRequestId": "buy-20260917-001",
"confirmedAt": 1789723456450,
"fulfillmentStatus": "fulfilled",
"fulfillmentRoute": "current_period",
"targetPeriodId": "goldMiner:2026-09-17",
"revision": 0,
"entitlementId": "ENTITLEMENT_ID_FROM_SERVER",
"fulfilledAt": 1789723456500
}
},
"msg": "活动权益已确认"
}
```
权益只顺延到紧邻的下一期,不无限滚动。查询成功不代表应一次发放全部任务金币。遇到 PAYMENT_PENDING 可间隔重试原订单查询;网络失败也保存订单号,登录恢复后继续查询,不能直接重新付款。建议有限次数退避轮询,离开支付流程后停止高频请求。
### 4.4 外部支付页转单:checkIos
**POST `/wx/checkIos`**。由现有 order3.html 处理,普通活动页面通常无需主动调用。
支付页票据方式:
```json
{"openid":"ORDER_OWNER_OPENID","time":"HANDOFF_TICKET_FROM_PAYMENT_LINK","outTradeNo":"ORDER_NO_FROM_CREATE"}
```
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| openid | string | 票据方式必填 | 支付页链接携带的订单所属 openid |
| time | string | 票据方式必填 | 链接携带的 handoff 签名票据,不是时间戳,不是 sessionFrom 中的客服票据 |
| outTradeNo | string | 是 | 原订单号 |
| uid / token | string | 游戏鉴权方式必填 | 游戏端也可只用 uid、token、outTradeNo 调用,替代 openid/time |
返回 JSON boolean:`true` 表示订单关联/兼容转单成功,`false` 表示校验或处理失败;不返回 code。**true 不表示已支付,更不表示已发奖**。之后仍由游戏端调用支付查询接口。支付通知接口 `goldMiner/merchantNotify`、原生支付回调和管理接口不属于前端调用范围。
## 5. 奖励申请、金币保存与确认
### 5.1 申请奖励:claim
**POST `/goldMiner/index`**。
```json
{"action":"claim","uid":"USER_ID","token":"LOGIN_TOKEN","periodId":"goldMiner:2026-09-17","taskId":"task_1","requestId":"claim-20260917-task1"}
```
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| action | string | 是 | claim |
| uid / token | string | 是 | 公共鉴权参数 |
| periodId | string | 是 | 奖励所属期,补发必须使用旧期 ID |
| taskId | string | 是 | info 或补发记录提供的档位 ID |
| requestId | string | 是 | 本次领取请求标识,重试复用 |
```json
{"code":1,"data":{"grantId":"GRANT_ID_FROM_SERVER","taskId":"task_1","items":[{"type":"coin","count":100}],"claimStatus":"issuing","claimedThrough":0,"requiresClientDelivery":true},"msg":"成功"}
```
| data 字段 | 类型 | 含义 |
| --- | --- | --- |
| grantId | string | 服务端稳定的本档发奖标识,用它对客户端到账去重 |
| taskId | string | 本次档位 |
| items | array | 本次授权道具,元素为 type:string、count:number;金币数量以此为准 |
| claimStatus | string | issuing 或 claimed,与 info 的四态枚举范围不同 |
| claimedThrough | number | 已按顺序完成到账确认的档位数;此接口仍保留 |
| requiresClientDelivery | boolean | true 表示服务端尚未确认到账;false 表示已确认,不再加金币 |
同账号、期次和档位重复 claim 返回同一 grantId,更换 requestId 也不会产生第二份授权。`requiresClientDelivery=true` 不代表客户端肯定还未加金币,也可能是金币已保存但确认请求失败,必须结合本地交付记录恢复。
### 5.2 金币保存:userCoin
**POST `/userCoin`**。继续沿用游戏现有金币流程,后端不直接加金币。
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| action | string | 是 | read 或 save |
| uid / token | string | 是 | 公共鉴权参数 |
| coinAmount | number | save 必填 | 保存后的金币总余额,非奖励增量;传 100 表示余额变为 100 |
```json
{"action":"read","uid":"USER_ID","token":"LOGIN_TOKEN"}
```
```json
{"action":"save","uid":"USER_ID","token":"LOGIN_TOKEN","coinAmount":1600}
```
read/save 成功均返回 `data.coinAmount:number`(当前/已保存余额)和 `data.timestamp:number`(用户记录/保存响应时间)。save 示例:
```json
{"code":1,"data":{"coinAmount":1600,"timestamp":1789723456450},"msg":"用户数据更新成功"}
```
协议是整值覆盖,不支持 grantId 或原子增量;负值会被旧接口归零。不得把奖励数量直接当总余额上传,也不能让多条金币写入并发覆盖。按现有金币管理队列串行保存,成功后再确认本档到账。
### 5.3 确认到账:confirm_delivery
**POST `/goldMiner/index`**。
```json
{"action":"confirm_delivery","uid":"USER_ID","token":"LOGIN_TOKEN","periodId":"goldMiner:2026-09-17","taskId":"task_1","grantId":"GRANT_ID_FROM_SERVER"}
```
所有字段必填,均为 string;action 固定 confirm_delivery,periodId/taskId 与 claim 一致,grantId 必须为 claim 返回值。无需 requestId,也不传金币数量。
```json
{"code":1,"data":{"grantId":"GRANT_ID_FROM_SERVER","claimStatus":"claimed","claimedThrough":1},"msg":"成功"}
```
| data 字段 | 类型 | 含义 |
| --- | --- | --- |
| grantId | string | 已确认的授权 ID |
| claimStatus | string | 固定 claimed |
| claimedThrough | number | 当前已确认的连续档位数 |
同一授权重复确认成功且不重复推进顺序。只有本接口成功后,下一档才可能变为 claimable。确认接口不会再修改金币余额。
### 5.4 客户端恢复顺序
1. 调用 claim,持久化 uid、periodId、taskId、grantId、items 和交付阶段。
2. 若服务端已 claimed / requiresClientDelivery=false,不再加金币;若本地记录该 grantId 已保存金币,也跳过加币。
3. 尚未保存时,交由游戏金币模块执行一次到账并保存总余额,记录该 grantId 的保存结果。不要每次重试都重新做“当前余额 + 奖励”。
4. 保存确定成功后调用 confirm_delivery;确认失败只重试确认。成功后刷新 info 或继续补发下一档。
当前 userCoin/save 与 confirm_delivery **不是同一个事务**,服务端也不验证金币保存凭证。断线、重装或多设备并发时,仅靠 grantId 不能保证金币端严格只到账一次;余额保存结果不明时,需要沿用游戏已有恢复机制核对,不能仅根据 issuing 自动再次加币,也不能未发奖就提前确认。这是现有金币协议的限制,本次文档不改变该协议。
## 6. 往期补发
活动结束后,已付费且达标的未领取档位进入补发流程;未达标奖励失效。未付费不能在结束后补买,已有订单的延迟确认按支付路由处理。补发不依赖当前 info 是否可用。
### 6.1 查询列表:settlements
**POST `/goldMiner/index`**。
```json
{"action":"settlements","uid":"USER_ID","token":"LOGIN_TOKEN","limit":20}
```
| 参数 | 类型 | 必填 | 含义 |
| --- | --- | --- | --- |
| action | string | 是 | settlements |
| uid / token | string | 是 | 公共鉴权参数 |
| limit | number | 否 | 默认 20,范围 1~100;限制每次扫描的历史玩家期记录数 |
| afterId | string | 否 | 上一页返回的 nextCursor;首次省略,不能使用 settlementId 替代 |
```json
{"code":1,"data":{"items":[{"_id":"SETTLEMENT_ID_FROM_SERVER","uid":"USER_ID","periodId":"goldMiner:2026-09-17","taskIds":["task_1","task_2"],"itemsSummary":[{"type":"coin","count":300}],"deliveryStatus":"pending","clientSavedAt":null,"revision":5,"createdAt":1789920000000,"acknowledgedAt":null}],"nextCursor":null},"msg":"成功"}
```
| data 字段 | 类型 | 含义 |
| --- | --- | --- |
| items | array | 本页扫描得到的结算记录,可能为空 |
| nextCursor | string / null | 下一页游标;非 null 时继续请求,直到 null |
| items[] 字段 | 类型 | 含义 |
| --- | --- | --- |
| _id | string | 结算记录 ID,ack_settlement 时映射为 settlementId |
| uid | string | 所属玩家 |
| periodId | string | 奖励所属的旧活动期 |
| taskIds | string[] | 本结算覆盖档位,已按领取顺序排列 |
| itemsSummary | array | 本结算覆盖奖励的合计,元素 type/count;不是“剩余待发数量” |
| deliveryStatus | string | pending:均未确认;partial:部分确认;client_saved:全部确认 |
| clientSavedAt | number / null | 全部确认后的最后确认时间,未全部完成为 null |
| revision | number | 内部投影版本,前端无需修改 |
| createdAt | number | 该期进度被关闭、生成结算的时间,可能晚于实际结束时刻 |
| acknowledgedAt | number / null | 客户端确认结算记录已处理的时间,尚未确认时为 null |
分页扫描历史玩家期记录,并非仅扫描待发记录,所以 `items=[]` 但 `nextCursor!=null` 时仍需翻页。已完成、已确认记录也可能返回,前端按 deliveryStatus/acknowledgedAt 过滤待处理展示。
对 pending/partial 记录,按 taskIds 顺序逐一执行 **claim → 保存金币 → confirm_delivery**;使用记录中的 periodId。重试已发档位时 claim 会返回 claimed,不再加币。itemsSummary 仅供展示,不要汇总加币后又逐档加币。
### 6.2 确认结算已处理:ack_settlement
**POST `/goldMiner/index`**。
```json
{"action":"ack_settlement","uid":"USER_ID","token":"LOGIN_TOKEN","settlementId":"SETTLEMENT_ID_FROM_SERVER"}
```
所有参数必填且为 string。settlementId 来自记录的 `_id`;全部档位确认到账后调用。
```json
{"code":1,"data":{"settlementId":"SETTLEMENT_ID_FROM_SERVER","acknowledged":true},"msg":"成功"}
```
data.settlementId 为 string,data.acknowledged 为 boolean,成功固定 true。重复调用安全;deliveryStatus 尚不是 client_saved 时返回 DELIVERY_PENDING。此操作只确认处理完成,不发金币,也不删除结算记录。
## 7. 错误码与处理
以下错误码可能来自活动或黄金矿工支付分支;通用接口前置错误及 checkIos 的返回例外见第 1 节。
| errorCode | 含义与前端处理 |
| --- | --- |
| UNAUTHORIZED | 登录或订单归属校验失败;刷新登录并核对账号,不跨账号重试订单 |
| INVALID_ACTION / INVALID_INPUT / INVALID_PERIOD | action、参数或期 ID 不合法;修正请求 |
| INVALID_TASK / INVALID_GRANT | 档位或授权不匹配;重新读取任务/原领取结果,不伪造 ID |
| NOT_FOUND | 活动记录、订单快照或结算不存在;核对账号、期和 ID |
| NOT_QUALIFIED | 未满足活动门槛;刷新 info |
| PERIOD_ENDED | 活动不在可操作时间或事件属于旧期;停止新购买/进度补记,刷新 info;补发走 settlements |
| PURCHASE_DISABLED | 本期暂停新购买;刷新 info |
| ALREADY_UNLOCKED | 已有权益或订单已确认;继续原订单查询并刷新 info,不再次付款 |
| NOT_PAID | 本期未解锁;恢复支付查询或展示购买 |
| TARGET_NOT_REACHED | 任务目标未达成;刷新进度 |
| PREVIOUS_NOT_CLAIMED | 前序档位未确认到账;先恢复并确认前序档位 |
| DELIVERY_PENDING | 补发尚未全部确认;继续逐档处理 |
| EVENT_PAYLOAD_CONFLICT | 同一个事件 ID 对应不同胜利内容;检查持久化队列,不能改 ID 来绕过校验 |
| INVALID_PRODUCT | 商品与本期配置不符;使用最新 info.productId |
| PAYMENT_PENDING | 尚无可信支付确认;保留原订单并退避查询,不等同确定支付失败 |
| PAYMENT_CHANNEL_DISABLED | 客服支付渠道未启用;提示暂不可用,交后端确认渠道配置 |
| PAYMENT_CHANNEL_CONFLICT | 本期已有其他渠道订单;继续原渠道 |
| ORDER_CLOSED | 订单已关闭或无法继续支付;停止拉起该支付页并刷新状态 |
| ORDER_ENVIRONMENT_MISMATCH | 订单/商户环境不一致;停止重试并核对部署环境 |
| ORDER_SNAPSHOT_CONFLICT / PAYMENT_CONFLICT | 订单快照或交易号冲突;保留订单号交后端排查 |
| ENTITLEMENT_CONFLICT / MANUAL_REVIEW | 资格分配冲突或进入人工核对;不要重付,交后端核对 |
| CONFIG_UNAVAILABLE / PAYMENT_CONFIG_UNAVAILABLE | 活动或支付配置缺失/异常;提示暂不可用,交后端处理 |
| CUSTOMER_SERVICE_UNAVAILABLE | 客服消息发送失败;保留订单,由原流程恢复 |
| INVALID_PAYMENT / INVALID_PAYMENT_SIGNATURE | 支付响应或签名校验失败;不能按成功处理,交后端排查 |
| MERCHANT_* | 商户请求相关错误,后缀来自商户响应;保留原订单,查询类暂时故障退避恢复 |
| RETRYABLE | 暂时失败或并发冲突;复用原请求标识退避重试,并遵守金币/关卡恢复约束 |
服务端订单元数据内的 lastErrorCode/lastQueryError 可能保留历史错误,不等同本次接口 errorCode。未知错误码按失败处理并保留日志,不能默认支付或领奖成功。
## 8. 前端接入顺序与版本迁移
1. 登录/回到游戏后恢复未完成订单查询及奖励交付记录,拉取 info 和 settlements。
2. 游戏胜利保存关卡时附带活动事件;未打开活动页、未付费仍正常上报。结束后停止新事件补记。
3. 页面直接按 tasks 返回顺序展示,以 status 控制购买,以 claimStatus 控制档位领取;不根据 completed 单独开放按钮。
4. 购买后查询到权益确认,重新读取 info;按 fulfillmentRoute 处理往期结算或下期资格。
5. 每档金币保存并 confirm_delivery 成功后再处理下一档;断线恢复原 grantId,补发同样逐档执行。
本版精简仅作用于 **info 的展示响应**:
| 旧字段 | 当前用法 |
| --- | --- |
| availability / qualified / purchasable / entitlement.status | 使用 status 五态 |
| entitlement.source | 删除,前端只判断本期是否 unlocked |
| nextStartsAt / nextPeriodId / currency | info 不返回;金额单位在协议中约定 |
| tasks[].sequence | 删除,使用数组顺序 |
| tasks[].claimed / issuing / claimable / blockReason | 删除,使用 claimStatus 四态 |
| info.claimedThrough | 删除,按任务 claimStatus 展示;claim 和 confirm_delivery 仍返回 claimedThrough |
不要将 info 的 claimable 状态当作后端永久承诺;点击后的 claim 才是实际领取判定。页面倒计时归零、切回前台、支付完成及奖励确认后均应刷新状态。
联调文件:[Postman 使用说明](../server/laf-cloud/functions/goldMiner/postman/gold-miner.README.md)、[Collection](../server/laf-cloud/functions/goldMiner/postman/gold-miner.postman_collection.json)、[环境模板](../server/laf-cloud/functions/goldMiner/postman/gold-miner.postman_environment.json)。内部维护与部署细节见 [后端说明](../server/laf-cloud/functions/goldMiner/README.md) 和 [客服支付接入说明](../server/laf-cloud/functions/goldMiner/LEGACY-PAYMENT.md)。