MatchMaster/assets/coin_madness
2026-09-30 20:05:20 +08:00
..
prefab feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
script feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
texture feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
prefab.meta feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
README.md docs: align Gold Miner documentation with current client and V1.7 gaps 2026-09-30 20:05:20 +08:00
README.md.meta feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
script.meta feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00
texture.meta feat: integrate Gold Miner activity and remove development test panels 2026-09-30 19:43:47 +08:00

CoinMadness(黄金矿工)活动前端说明

核对日期:2026-09-30,客户端基准 7e14f661。本文描述实际实现,不代表完整兼容仓库后端 V1.7 或已完成线上验收。文档入口 · 接入差异与验证状态。请求示例省略真实账号和 token。

活动预制体、图片和面板脚本在 coin_madness 分包;Host、GoldMinerService、BrownLoadingSpinner 在主包侧,入口图在 resources。游戏测试包、活动测试面板及演示场景已移除。普通 Creator 预览不启动真实活动;独立预览夹具仍在 tools/coin-madness。

1. 代码分工

文件 职责
script/CoinMadnessPanel.ts 活动主面板、购买和领取按钮、倒计时、金币动画
script/CoinMadnessSettlement.ts 补发到账通知窗口
script/CoinMadnessDigits.ts 图片数字显示
../Script/coin_madness/CoinMadnessHost.ts 首页入口、同步时机、分包加载释放、主面板/说明/结算窗口切换
../Script/coin_madness/GoldMinerService.ts 活动接口、支付订单、领奖与补发、交付记录和恢复流程
../Script/module/Pay/Utils.ts POSTJSON、服务器选择、金币保存队列、通关保存请求
../Script/module/Tool/GameTool.ts addLevel 中接入真实通关事件
../Script/GameManager.ts startGame 中提前获取首页活动状态
../Script/JiaZai.ts 挂载 Host、首页左侧活动补位、金币数字刷新

通常调用关系:

CoinMadnessPanel(用户操作)
  → CoinMadnessHost.requestActivity
  → GoldMinerService(组织业务)
  → Utils.POSTJSON(发送 HTTP)
  → 后端

真实通关另走 GameTool.addLevel → Utils.setUserLevel;活动胜利事件附在原有关卡保存请求里。

2. 环境与接口清单

活动请求使用 POST JSON。Utils.serverUrl 根据微信版本选择服务器:开发版/体验版使用 testHttpip,其余使用 httpip。具体地址以 Utils.ts 为准,不在本文重复硬编码。

当前两个地址相同:合入 main 后,开发版/体验版也会请求同一正式服。账本隔离依据实际 URL 和 uid,不依据版本名称。

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
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 的真实执行顺序

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. 倒计时、到期与重试

前端用服务器时间与本地时间差校准:

offset = serverTime - Date.now()
剩余时间 = endsAt - (Date.now() + offset)

面板每秒重新计算显示,Host 每 0.5 秒检查本地时间阶段/红点。这些本地检查本身不发请求。当前没有固定每 30 秒的全量轮询。

到期时活动面板退出:已有到账通知则切换结算窗口;否则关闭并触发同步,补发处理成功后再展示通知。

settlements 返回 settling、补发失败或查单失败会设置重试标记。Host 的重试间隔依次为 2、3、5、7、10、15、25、30、50 秒,当前计数未重置时最多追加 9 次。回前台等 resumeSync 会重置计数。

恢复标记触发 retryRecovery,只查未完成订单与补发;订单有变化或通知金额改变时才读取 info,不重读日程或重放普通领奖。完整同步抛错则重试完整 refresh。重新进入首页、回前台或期次边界可触发新一轮;重试次数不是整个会话的总请求上限。

已知边界:

  • 后端临时开启一个前端未知的活动,玩家一直停在首页时,当前实现没有固定轮询自动发现,要等下次同步。
  • settlements 返回空列表且未标记 settling 时,前端按本次无记录处理,不会仅因空列表重试。
  • 后端持续 settling 超过有限重试次数,需要后续同步或检查服务端结算任务。

5. 真实通关流程

GameTool.addLevel
  → 本地关卡推进
  → GoldMinerService.victory 生成活动事件
  → Utils.setUserLevel
  → userLevel / save(附带 goldMiner)
  → GoldMinerService.victoryResult 处理活动结果

主线上报示例(省略认证字段):

{
  "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. 购买解锁流程

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 客服 Utils.GoKEFu 本地生成订单及会话参数 wx.openCustomerServiceConversation wx/iosgetPayInfo

微信支付 API 与 wx.showToast 是客户端 API,不是本项目后端地址。支付窗口关闭不等于后端确认成功。

queryOrder 验证 pay_state=2、rewardDelivery='goldMiner.claim' 和 goldMiner 权益数据。支付客户端调用成功后最多尝试查单四次,间隔 1.5、3、4.5 秒;PAYMENT_PENDING 和 NETWORK_UNKNOWN 可快速重试,其他异常提前退出。仍未确认时提示“支付结果确认中”。每次有效购买生成新 createRequestId;iOS 原生明确返回错误码 16 且非取消时回退 GoKEFu。当前客服链路不同于后端 V1.7 的 create_order 签名票据,见接入差异。

提示使用 wx.showToast:购买成功、已取消支付、购买失败或支付结果确认中。购买只解锁权益,不自动发放全部任务金币。跨期承接权益可能分配给下一期,不等于当前期立即解锁。

7. 点击领取一档任务奖励

Panel.run('claim')
  → Host.requestActivity
  → Service.request → deliver
  → claim:取得奖励授权
  → userCoin/save:保存增加后的总余额
  → onSaved:立即启动金币动画,飞到顶部后释放数字显示等待
  → confirm_delivery:确认该档到账(不等待动画)
  → info:读取最新任务状态

以余额 1000、奖励 300 为例,userCoin/save 上传 coinAmount=1300,不能上传 300。

正常首次领取通常四次请求。金币保存确认成功后就播放动画,无须等待 confirm_delivery 或最后一次 info;服务端确认失败时仍保留恢复凭证。网络和串行队列可能造成保存前等待。

金币余额实际保存早于动画,只有数字显示被延迟。当前每档动画产生 16 枚金币,约 0.935 秒后释放显示等待,再过 0.24 秒清理动画层;并发动画全部到达后刷新顶部数字。关闭面板也会恢复显示。

已保存但未确认的奖励恢复时只重试确认;已确认奖励不重复加金币。具体取决于本地交付记录和后端响应。

8. 活动结束后的补发

Service.refresh → settle
  → settlements:获得补发清单
  → 对每档 reward 调用 deliver(直接使用清单中的授权)
      → userCoin/save
      → confirm_settlement_delivery
  → refresh 末尾 info
  → Host.showSettlementNotice
  → 显示补发到账窗口

补发清单包含奖励授权,不再对过期任务调用 claim。

一档 1000 金币待补发的结构示例:

{
  "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,但 V1.7 已改为服务器控制页大小,不能依赖这个参数决定返回数量。非 settling 响应中,nextCursor 非空时用 afterId 翻页,即使 items 为空也继续。当前遇 settling 会立即退出,即使有 nextCursor;这与 V1.7 要求继续扫描其他期的规则不同,尚待对齐。no_pending_rewards 的空列表、空游标可自然结束本轮。

返回 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 包括首屏、订单、领奖恢复和补发;retryRecovery 已单独用于恢复重试。首屏提前返回第一次 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。

仓库根目录可运行以下离线检查(不操作真实支付和余额):

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

上面列出的是可运行的现有脚本,不代表全部已通过。上次 check-types 报 Utils.ts 的 wx 声明问题,check-release-ui 的夹具及断言待维护;通过记录和真机待验项见接入说明。类型检查以 HEAD 为基线,提交后基线随之改变,“无新增”不等于零错误。

最新仓库协议:后端 V1.7;当前兼容边界:接入说明。V1.3/V1.5 只作历史参考,不能据此认定客户端已完成 V1.7 接入。