MatchMaster/assets/coin_madness/README.md

299 lines
16 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.

# CoinMadness(黄金矿工)活动前端说明
更新日期:2026-09-23。本文描述当前客户端实际实现;后续修改接口或流程时,请同步更新本文。请求示例省略真实账号和 token。
## 1. 代码分工
| 文件 | 职责 |
| --- | --- |
| [script/CoinMadnessPanel.ts](script/CoinMadnessPanel.ts) | 活动主面板、购买和领取按钮、倒计时、金币动画 |
| [script/CoinMadnessSettlement.ts](script/CoinMadnessSettlement.ts) | 补发到账通知窗口 |
| [script/CoinMadnessDigits.ts](script/CoinMadnessDigits.ts) | 图片数字显示 |
| [../Script/coin_madness/CoinMadnessHost.ts](../Script/coin_madness/CoinMadnessHost.ts) | 首页入口、同步时机、分包加载释放、主面板/说明/结算窗口切换 |
| [../Script/coin_madness/GoldMinerService.ts](../Script/coin_madness/GoldMinerService.ts) | 活动接口、支付订单、领奖与补发、交付记录和恢复流程 |
| [../Script/module/Pay/Utils.ts](../Script/module/Pay/Utils.ts) | POSTJSON、服务器选择、金币保存队列、通关保存请求 |
| [../Script/module/Tool/GameTool.ts](../Script/module/Tool/GameTool.ts) | addLevel 中接入真实通关事件 |
| [../Script/GameManager.ts](../Script/GameManager.ts) | startGame 中提前获取首页活动状态 |
| [../Script/JiaZai.ts](../Script/JiaZai.ts) | 挂载 Host、首页左侧活动补位、金币数字刷新 |
通常调用关系:
```text
CoinMadnessPanel(用户操作)
→ CoinMadnessHost.requestActivity
→ GoldMinerService(组织业务)
→ Utils.POSTJSON(发送 HTTP)
→ 后端
```
真实通关另走 GameTool.addLevel → Utils.setUserLevel;活动胜利事件附在原有关卡保存请求里。
## 2. 环境与接口清单
活动请求使用 POST JSON。Utils.serverUrl 根据微信版本选择服务器:开发版/体验版使用 testHttpip,其余使用 httpip。具体地址以 Utils.ts 为准,不在本文重复硬编码。
GoldMinerService.post 为认证请求补充 uid;Utils.POSTJSON 补充 token。activityConfig/list 使用非认证请求。
共涉及 8 个主要后端地址。goldMiner/index 是同一个地址,通过 action 区分业务。
| 地址 | action | 用途 | 直接调用位置 |
| --- | --- | --- | --- |
| activityConfig/list | 无 | 活动日程、服务器时间,辅助判断通关所属期次 | GoldMinerService.readSchedule |
| goldMiner/index | info | 玩家活动状态、价格、进度、任务和领取状态 | GoldMinerService.readInfo |
| goldMiner/index | claim | 检查资格,返回本档奖励授权与金额 | GoldMinerService.deliver |
| goldMiner/index | confirm_delivery | 确认普通奖励已保存到账 | GoldMinerService.deliver |
| goldMiner/index | settlements | 查询往期补发清单 | GoldMinerService.settle |
| goldMiner/index | confirm_settlement_delivery | 确认补发奖励已保存到账 | GoldMinerService.deliver |
| goldMiner/index | create_order | 旧版 iOS 客服支付下单 | GoldMinerService.purchase |
| userLevel | save | 保存关卡,并携带 goldMiner 胜利事件 | Utils.setUserLevel |
| userCoin | save | 保存领取/补发后的金币总余额 | GoldMinerService.deliver |
| wx/orderPaySig | 无 | Android 原生支付下单,返回支付参数 | GoldMinerService.purchase |
| wx/iosorderPaySig | 无 | iOS 原生支付下单,返回支付参数 | GoldMinerService.purchase |
| wx/getPayInfo | 无 | 查询 Android 订单支付和权益结果 | GoldMinerService.queryOrder |
| wx/iosgetPayInfo | 无 | 查询 iOS 订单支付和权益结果 | GoldMinerService.queryOrder |
Network 中多个 index 请求不一定重复:必须查看 Payload.action。HTTP 200 只代表获得 HTTP 响应,业务成功仍要检查响应 code 和内部业务结果。
## 3. 首页、入口和完整刷新
### 触发时机
- 首次登录:GameManager.startGame 在加载画面期间调用 readForDisplay,和商店分包加载并行;拿到首份活动状态或请求失败后继续进入首页。
- 首页 Host 启动、游戏返回前台:调用 sync。
- 打开活动面板:先显示 service.view 的已有数据,再请求首份最新信息。
- 本地检测到活动时间阶段变化:触发同步,包括到期。
readForDisplay 会启动/复用 refresh,但只等待第一次 info。后续恢复仍继续执行,并不是只请求 info。
### refresh 的真实执行顺序
```text
info ← 首份数据返回后即可显示入口/主面板
→ activityConfig/list
→ 遍历未完成订单,逐笔 queryOrder
→ 恢复未完成的普通领奖和 issuing 奖励
→ settlements,处理补发
→ info ← 获取最终任务状态
```
没有待恢复订单、没有奖励、没有分页时,通常仍有 4 次请求:info → list → settlements → info。
同一客户端的在途 refresh 会复用 Promise;前一轮完成后再次触发会新开一轮。恢复与购买、领奖使用同一串行队列,避免并发交付,但后面的操作可能等待前面的恢复任务。
### 入口显示与布局
- 有补发到账通知或可领取/发放中的奖励时,入口可显示红点。
- 普通展示还要求 canIos 开关允许,且 info.status 为 purchasable、purchase_disabled 或 unlocked。
- locked、unavailable 默认不显示入口,奖励通知是例外。
- 使用 HomeScene 的 Load/Top/CoinMadnessEntry;找不到时才创建。
- JiaZai.refreshHomeActivityEntryLayout 统一排列左侧入口,参与首页渐隐控制;不固定悬浮在另一套坐标上。
## 4. 倒计时、到期与重试
前端用服务器时间与本地时间差校准:
```text
offset = serverTime - Date.now()
剩余时间 = endsAt - (Date.now() + offset)
```
面板每秒重新计算显示,Host 每 0.5 秒检查本地时间阶段/红点。这些本地检查本身不发请求。当前没有固定每 30 秒的全量轮询。
到期时活动面板退出:已有到账通知则切换结算窗口;否则关闭并触发同步,补发处理成功后再展示通知。
settlements 返回 settling 或补发请求失败会设置重试标记。Host 使用 5、15、30 秒的间隔,最多追加 3 次重试。未完成订单查单失败也可能让完整刷新进入重试。
因此单次触发正常查询一次、需重试时通常最多四轮;这不是整个会话总上限:重新进入首页、回前台、测试操作、其他到期触发都可能增加请求。分页时每页各请求一次。
已知边界:
- 后端临时开启一个前端未知的活动,玩家一直停在首页时,当前实现没有固定轮询自动发现,要等下次同步。
- settlements 返回空列表且未标记 settling 时,前端按本次无记录处理,不会仅因空列表重试。
- 后端持续 settling 超过有限重试次数,需要后续同步或检查服务端结算任务。
## 5. 真实通关流程
```text
GameTool.addLevel
→ 本地关卡推进
→ GoldMinerService.victory 生成活动事件
→ Utils.setUserLevel
→ userLevel / save(附带 goldMiner)
→ GoldMinerService.victoryResult 处理活动结果
```
主线上报示例(省略认证字段):
```json
{
"action": "save",
"levelAmount": 91,
"goldMiner": {
"periodId": "实际活动期ID",
"eventId": "本次胜利唯一ID",
"outcome": "win",
"mode": "main",
"clearedMainLevel": 91
}
}
```
- 主线省略 isWuXian;无尽使用字符串 "true",goldMiner.mode 为 endless 并携带 endlessSequence。
- 前端需识别有效活动期和符合条件的真实胜利,才附带 goldMiner;配置补关等不作为真实胜利计数。
- 不是再单独请求 index 给活动加进度。
- 检查 data.goldMiner.code、activityCounted、duplicate、progressWins。外层 code=1 不等于活动计数一定成功。
- victoryResult 更新本地活动累计次数;完整任务领取状态由后续 info 获取。
- 本地关卡已前进不代表服务器保存成功。userLevel 整体不是纯活动幂等接口,不应自动无限重放失败请求。
## 6. 购买解锁流程
```text
Panel.run('purchase')
→ Host.requestActivity
→ Service.request → purchase
→ info:校验活动期、购买状态与价格
→ 下单:返回 outTradeNo、支付参数
→ 微信客户端拉起支付
→ queryOrder:查询后端订单权益
→ info:刷新解锁状态
→ 面板更新,成功解锁后自动打开一次“?”说明
```
| 渠道 | 下单地址 | 微信客户端 API | 查单地址 |
| --- | --- | --- | --- |
| Android 原生 | wx/orderPaySig | wx.requestMidasPaymentGameItem | wx/getPayInfo |
| iOS 原生 | wx/iosorderPaySig | wx.requestMidasPaymentGameItem | wx/iosgetPayInfo |
| 旧版 iOS 客服 | goldMiner/index,create_order | wx.openCustomerServiceConversation | wx/iosgetPayInfo |
微信支付 API 与 wx.showToast 是客户端 API,不是本项目后端地址。支付窗口关闭不等于后端确认成功。
queryOrder 验证 pay_state=2、rewardDelivery='goldMiner.claim' 和 goldMiner 权益数据。购买后最多连续尝试查询四次;pending 之外的异常会提前退出。仍未确认时提示“支付结果确认中”。
提示使用 wx.showToast:购买成功、已取消支付、购买失败或支付结果确认中。购买只解锁权益,不自动发放全部任务金币。跨期承接权益可能分配给下一期,不等于当前期立即解锁。
## 7. 点击领取一档任务奖励
```text
Panel.run('claim')
→ Host.requestActivity
→ Service.request → deliver
→ claim:取得奖励授权
→ userCoin/save:保存增加后的总余额
→ confirm_delivery:确认该档到账
→ info:读取最新任务状态
→ 播放金币动画
→ 飞到顶部后更新金币数字
```
以余额 1000、奖励 300 为例,userCoin/save 上传 coinAmount=1300,不能上传 300。
正常首次领取通常四次请求。当前仍等待最后一次 info 返回才播放动画;没有固定的领取前等待秒数,但网络、串行排队会造成等待。
金币余额实际保存早于动画,只有数字显示被延迟。金币飞行约 1.51 秒到达目标后释放显示等待;关闭面板也会恢复余额显示。飞行金币已放大两倍。
已保存但未确认的奖励恢复时只重试确认;已确认奖励不重复加金币。具体取决于本地交付记录和后端响应。
## 8. 活动结束后的补发
```text
Service.refresh → settle
→ settlements:获得补发清单
→ 对每档 reward 调用 deliver(直接使用清单中的授权)
→ userCoin/save
→ confirm_settlement_delivery
→ refresh 末尾 info
→ Host.showSettlementNotice
→ 显示补发到账窗口
```
补发清单包含奖励授权,不再对过期任务调用 claim。
一档 1000 金币待补发的结构示例:
```json
{
"code": 1,
"data": {
"items": [{
"settlementId": "实际结算ID",
"periodId": "实际活动期ID",
"rewards": [{
"taskId": "实际任务ID",
"grantId": "实际奖励凭证ID",
"items": [{ "type": "coin", "count": 1000 }]
}]
}],
"nextCursor": null
},
"msg": "成功"
}
```
同一奖励的 ID 应稳定,多个任务分别列出各自的 reward。不要仅返回总金额,也不要在可处理清单上继续标记 settling。
confirm_settlement_delivery 请求携带 settlementId、grantIds;当前逐档调用,grantIds 每次包含一档的 grantId。客户端验证响应中的 settlementId 和 confirmedGrantIds。
如果一页有三档待补发奖励,核心流程通常是:查询一次 + 保存三次 + 确认三次,完整 refresh 还包含其他查询。
limit=100 是一页最多查询的记录数,不是金币数量。nextCursor 非空时用 afterId 翻页;即使当前页 items 为空也继续翻页。
返回 settling 时表示尚未生成可处理清单,不表示没有奖励,也不表示到账。
离线结束的活动在下次进入首页时同样查询,不依赖打开活动面板。仅有符合补发条件、实际处理成功的金额才形成到账通知,不是所有玩家到期都弹结算。
关闭结算窗口只调用 dismissNotice 清除本地通知,不再发币、不再调用确认接口。若到账后未关闭窗口就退出,下次可能再次显示通知,但不应再次发币。
补发通知直接加载 CoinMadnessSettlement,不先实例化活动主面板。关闭通知后立即更新入口及左侧补位;过期任务的残留红点不保留入口。如果已有新一期可参与活动,则保留新一期入口。
## 9. 标识关联与本地记录
| 字段 | 含义及用途 |
| --- | --- |
| periodId | 关联某一期活动的通关、权益、任务和补发 |
| eventId | 一次胜利的唯一事件标识,用于活动事件去重 |
| outTradeNo | 下单返回的订单号,查单使用 |
| taskId | 一档活动任务 |
| grantId | 具体奖励授权,确认与交付恢复使用 |
| settlementId | 一笔补发结算,补发确认使用 |
本地账本按服务器和账号隔离,包含 orders、grants、events、notices 等数据。
确认接口存在的原因:查询到授权不等于金币已保存。保存金币成功后,确认接口才告诉活动后端“这档已完成”。
但当前 userCoin/save 是总余额覆盖,与确认接口不是同一个事务;仅靠 grantId 不能保证重装、多设备等情况下严格只发一次。余额保存结果不明时,代码会阻止直接重复加币,需要核对,不能只因仍是 issuing 就再加一次。
## 10. 为什么 getPayInfo 经常出现
每次完整 refresh 都遍历本地订单:有订单号、未标记 done、且不是 cancelled 的订单都会查。因此历史未付款或失败订单可能反复出现。
查单失败也会设置 refreshNeedsRetry,下一轮完整刷新会再查这些订单。多个订单意味着一轮多个 getPayInfo。这是查单,不是重复下单或扣款。
当前读取界面、订单恢复、领奖恢复和补发仍在同一个 refresh 中。首屏优化只是提前展示第一次 info,不代表这些后台请求已经拆开。后续若优化请求数量,应明确拆分触发职责,不直接删除交付确认。
## 11. 排查与验证
2026-09-30 清理:已删除游戏测试分包、活动测试面板、首页测试入口及两个演示场景。保留活动正式流程、支付诊断日志和离线回归检查。
- 进度不涨:查看真实通关那条 userLevel 的请求 goldMiner 与响应 data.goldMiner,再对比 info 的 periodId/progressWins/tasks。
- 未弹补发:查看 settlements 是否 settling、有无 items、后续 userCoin/save 和 confirm_settlement_delivery 是否成功。
- 领取慢:检查串行队列中的前序恢复,以及 claim → 保存 → 确认 → info 各次耗时。
- “网络结果未知”:检查 transportReason、HTTP 状态。空响应、非 JSON、超时、连接失败需分别定位。
- 在浏览器地址栏打开接口是 GET,不等于游戏实际 POST;应查看 Network 中同一条请求的 Response。
仓库根目录可运行以下离线检查(不操作真实支付和余额):
```text
node tools/coin-madness/check-api.cjs
node tools/coin-madness/check-first-display.cjs
node tools/coin-madness/check-expiry-sync.cjs
node tools/coin-madness/check-expired-panel.cjs
node tools/coin-madness/check-release-ui.cjs
node tools/coin-madness/check-home-entry-ready.cjs
node tools/coin-madness/check-settlement-entry.cjs
node tools/coin-madness/check-types.cjs
```
类型检查比较现有基线;“无新增错误”不代表整个项目零错误。界面实际布局、微信支付及真机网络仍需开发版/体验版验证。
补充协议资料:[v1.5 变更](../../docs/GoldMiner-API-v1.5-changes.md)、[接入说明](../../docs/GoldMiner接入说明.md)。旧 v1.3 文档中的补发 _id/taskIds、ack_settlement 不再是当前客户端补发流程,应以 v1.5 与现行代码为准。