aslan-server/rc-service/rc-service-other/docs/Aslan游戏王活动接口.md

14 KiB
Raw Blame History

Aslan 游戏王活动接口

本文对应 H5 activity/game-king/aslan.html 与 webconsole 游戏王配置页。接口契约以当前仓库的 AslanGameKingRestControllerAslanGameKingBackRestControllerAslanGameKingModelsAslanGameKingWalletListener 为准。

通用约定

  • 下列地址均为网关或 webconsole 域名后的相对路径H5 通过现有 common_aslan 请求层调用。
  • Controller 返回值会由框架包装为 ResultResponse:成功时核心结构为 {"status":true,"errorCode":0,"time":<毫秒时间戳>,"body":...};业务数据均在 body
  • DTO 中的 Long ID 在响应 JSON 中按字符串输出H5 应保留字符串,不要转成 JavaScript Number。
  • 时间字段 startTimeendTimesettlementTimeserverTimedrawTimedeliverTime 均为 Unix 毫秒时间戳。

H5 鉴权头

H5 五个接口都使用网关鉴权,不接受客户端提交 userIdsysOrigin 业务字段。

Header 必填 精确格式/说明
Authorization Bearer <app access token>;网关从已校验 token 取得用户 ID再通过内部头注入 AppExtCommand.reqUserId
Req-Sys-Origin origin=<活动所属系统>;originChild=<子系统>;origin 必须与后台活动的 sysOrigin 完全相同;未传 originChild 时框架回落为 origin
Req-Client H5 固定传 H5
Req-App-Intel 分号分隔,例如 version=<版本>;build=<正整数>;channel=<渠道>;version、正数 buildchannel 都由网关校验。

Req-Inner-Internal 是网关生成的内部头H5 不应自行构造。抽奖 JSON 即使额外带入 reqUserIdreqSysOriginController 也不会使用这些字段。

Webconsole 鉴权

webconsole 接口使用 Authorization: Bearer <console JWT>。迁移 SQL 同时登记了 activity:game-king:* 资源与 ActivityGameKing 菜单;账号需拥有相应后台菜单/资源权限。

H5 接口

基础路径:/activity/game/king/aslan

1. 活动详情

GET /activity/game/king/aslan/detail

Query

参数 必填 说明
activityId 活动 ID。省略时按当前 Req-Sys-Origin 依次选择进行中、最近将开始、最近结束的已启用活动。

bodyDetail

  • activity:活动配置,主要字段为 idactivityCodeactivityNameactivityDescsysOrigintimeZonestartTimeendTimesettlementDelayMinutessettlementTimecoinPerDrawrankingTyperankingPeriodenabledsettlementStatus。兼容字段 eventTypes 恒为 ["GAME_EXPENDITURE"],不代表可配置白名单。
  • prizes7 个奖项;主要字段为 idprizeNameprizeImageweightstockresourceGroupIdsortOrderrewardItems
  • rankRewards:固定档位 1234-78-1011-30 及其 resourceGroupIdrewardNamerewardItems
  • supportedRankingTypes:固定为 TYCOONVICTORIOUS
  • supportedRankingPeriods:固定为 DAILYOVERALL
  • activityStatusUPCOMINGACTIVEENDEDDISABLED
  • serverTime:服务端当前毫秒时间戳。

2. 我的活动状态

GET /activity/game/king/aslan/me

Query可选 activityId,选择规则同详情接口。

bodyUserStateactivityIdtotalConsumedearnedChancesusedChancesavailableChancesnextChanceRemainingrank。其中抽奖机会只由支出流水累计,earnedChances = floor(totalConsumed / coinPerDraw)

3. 抽奖

POST /activity/game/king/aslan/draw

Body

{
  "activityId": "可选活动ID",
  "requestId": "本次点击生成且重试时保持不变的唯一值"
}
  • requestId 必填、去除首尾空格后非空、最长 64 字符。
  • 幂等范围为“活动 + 当前用户 + requestId”。网络重试必须复用原值;新的一次抽奖必须生成新值。
  • ACTIVE 活动且 availableChances > 0 时可抽。

bodyDrawResult

  • recordidactivityIduserIdrequestIdprizeIdprizeNameprizeImageresourceGroupIddeliveryStatusfailureReasondrawTimedeliverTime
  • prize:命中奖项及展示用 rewardItems
  • remainingChances:本次扣减后的剩余机会。
  • idempotentReplay:是否返回同一 requestId 的已有结果。

4. 排行榜

GET /activity/game/king/aslan/ranking

Query 参数 必填 说明
activityId 活动 ID。
rankingType TYCOON(游戏支出)或兼容维度 VICTORIOUS;省略时使用活动配置。本活动事件采集只接收支出,因此运营配置固定使用 TYCOON
period DAILYOVERALL;省略时使用活动配置。
limit 默认 30服务端限制到 1100。

bodyRankingrankingTypeperiodstatDateentriesmyDAILYstatDate 是活动 timeZone 下当天的 yyyy-MM-ddOVERALL 时为空。每个 RankEntry 包含 rankuserIdaccountnicknameavatarscoretotalConsumedtotalWonme

同分排序固定为:分值降序、首次到达该分值时间升序、userId 升序。

5. 我的抽奖记录

GET /activity/game/king/aslan/draw-records

Query 参数 必填 说明
activityId 活动 ID。
limit 默认 20服务端限制到 1100。

bodyDrawRecord[],字段同抽奖结果中的 record。逐项发奖明细 deliveryItems 只在管理端填充。

Webconsole 管理接口

基础路径:/activity/game-king

方法与路径 关键入参 body/作用
GET /list Activity[]
GET /detail/{id} 活动 ID Detail
POST /save SaveCommand JSON 新增或修改活动,返回 Activity
PUT /enable/{id} Query enabled=true/false 启停活动。活动开始后不能再改变启用状态。
GET /prizes/{id} 活动 ID Prize[]
PUT /prizes/{id} {"activityId":"同路径ID","prizes":[...]} 覆盖保存 7 个奖项;活动开始后禁止修改。
GET /rank-rewards/{id} 活动 ID RankReward[]
PUT /rank-rewards/{id} {"activityId":"同路径ID","rankRewards":[...]} 覆盖保存 6 个固定排名奖励档;活动开始后禁止修改。
GET /draw-records/{id} 可选 deliveryStatuslimit 抽奖记录及 deliveryItems;状态可为 PENDING/PROCESSING/SUCCESS/FAILED/UNKNOWNlimit 默认/最大均为 100。
POST /draw/retry/{recordId} 抽奖记录 ID 仅重试已核实可重试的 FAILED 记录,不处理 UNKNOWN
GET /settlement-records/{id} 活动 ID Top 30 冻结结算记录及逐项 deliveryItems
POST /settlement/{id} 活动 ID 到达 settlementTime 后冻结 TYCOON/OVERALL Top 30 并发奖。
POST /settlement/retry/{recordId} 结算记录 ID 仅重试已核实可重试的 FAILED 记录,不处理 UNKNOWN
POST /delivery-item/resolve/{itemId} Query delivered=true/false 只处理 UNKNOWN 单项;语义见下文。
POST /backfill/{id} lastIdlimit 可选 服务端按固定第三方游戏支出口径分页补算钱包流水,返回 BackfillResult

SaveCommand 关键字段与约束

字段 约束
id 修改时传;新增不传。
activityCode 必填,最长 64活动间唯一。
activityName 必填,最长 128。
activityDesc 可选,最长 1000。
sysOrigin 必填,必须是服务端支持的 SysOriginPlatformEnum 值,并与 H5 Req-Sys-Origin.origin、钱包事件 sysOrigin 一致。
timeZone 必填;默认 Asia/Riyadh,必须是合法 IANA 时区。
startTimeendTime 必填毫秒时间戳,且 startTime < endTime
settlementDelayMinutes 01440默认 30settlementTime = endTime + settlementDelayMinutes
coinPerDraw 必填,正整数金币数。
eventTypes 已废弃且可不传;旧客户端传值也会被忽略,服务端统一保存 GAME_EXPENDITURE 兼容哨兵。
rankingType TYCOONVICTORIOUS,默认 TYCOON
rankingPeriod DAILYOVERALL,默认 OVERALL
enabled 默认 false。首次以 true 保存时,startTime 必须晚于当前时间。
prizesrankRewards 可随活动一起保存,也可通过独立接口保存。启用前两者都必须完整。

同一 sysOrigin 的已启用活动时间窗不得重叠。活动开始后,统计时间、系统、时区、结算延时、coinPerDraw 和启用状态等统计口径会锁定。事件资格由服务端固定分类器决定,不允许 webconsole 手工配置。

奖项必须恰好 7 个且全部 enabled=truesortOrder 为不重复的 17prizeName/prizeImage 非空,weight > 0stock >= -1,并配置 resourceGroupIdstock=-1 表示无限库存0 表示耗尽。

排名奖励必须恰好为 1-12-23-34-78-1011-30 六档。奖项和排名奖励引用的资源组必须已上架、sysOrigin 与活动一致且至少包含一个奖励配置。

补数返回

POST /backfill/{id} 不接收 eventTypereceiptTypelimit 默认 200、最大 500调用方只需把本次 nextLastId 作为下次 lastId 继续请求,直到返回 finished=true。钱包侧会强制 EXPENDITURE,并以四个转义后的左锚定游戏前缀查询,避免扫描活动时间窗内的全部非游戏支出。

BackfillResult 字段:eventType(恒为 GAME_EXPENDITURE)、receiptType(恒为 1/EXPENDITURE)、scannedacceptednextLastIdfinished。补数查询边界同实时统计,为 [startTime,endTime);调用钱包历史接口时实现为 endTime - 1ms

钱包事件统计契约

  • RocketMQ topic逻辑 topic RC_DEFAULT_APP_ORDINARY,运行时由 ${rocketmq.topics.RC_DEFAULT_APP_ORDINARY} 解析。
  • tagwallet_sync_gold_v2
  • 独立 consumer groupASLAN_GAME_KING_WALLET_SYNC_V1。不得和钱包落库消费者共用 group否则会竞争消费。
  • 事件模型:WalletReceiptSyncEvent。使用字段 assetRecordIduserIdsysOrigineventTypeeventIdreceiptTypebizTypeamountcreateTime
  • 唯一有效分类条件为:bizType=WalletBizType.GOLD.getType()receiptType=EXPENDITURE(1),并且 eventTypeHOT_GAME_HKYS_GAME_BAISHUN_GAME_YOMI_GAME_ 之一开头;此外金额必须非 0、sysOrigin 必须与活动相同、createTime 必须位于 [startTime,endTime)
  • 分类器使用严格 startsWith,且前缀后必须有具体游戏 ID/标识;裸 HOT_GAME_ 等前缀不会计入。禁止仅判断“支出”、contains("GAME")GoldOriginMapping,这些宽泛条件会误收礼物/奖励等流水或遗漏 YOMI。
  • 有效流水只累计 TYCOON 与抽奖机会;INCOME 不进入该活动统计。
  • 实时 MQ、MQ 重投和后台补数共用唯一幂等键 (activity_id, asset_record_id)
  • DAILY 按活动 timeZone 落日表OVERALL 使用全活动累计。活动结算奖励固定按 TYCOON/OVERALL而不是当前 H5 正在查看的榜单维度。

结算截点与发奖核账

  • 默认在 endTime + 30 分钟 到达结算截点;后台可通过 settlementDelayMinutes 配置 01440 分钟。定时任务每 5 分钟扫描一次到期活动。
  • 统计有效时间仍只到 endTime不含30 分钟只是给异步消息到达留出的缓冲,不代表 RocketMQ 已提供“无更早消息”的 watermark。要求严格完整时应在截点前按 nextLastId 连续调用固定口径补数直至 finished=true,再执行结算。
  • 首次结算会在活动行排他锁内冻结 TYCOON/OVERALL Top 30已进入统计事务会先完成冻结后到达的 MQ 或补数会被拒绝,排名快照不会再漂移。
  • 每个奖励组拆成 deliveryItems 逐项发放。普通失败可标为 FAILED 并在运营核实后走 retry外部适配器抛错PROCESSING 超过 10 分钟租期时,结果不能判定是否已到账,因此标为 UNKNOWN
  • UNKNOWN 永远不会被定时任务或普通 retry 盲目补发。运营核对下游账目后调用 /delivery-item/resolve/{itemId}delivered=true 表示确认已到账,仅把该项记为成功且不再次发送;delivered=false 表示确认未到账,原子解锁父记录与该项后再补发。
  • 结算中存在 FAILEDUNKNOWN 时活动聚合状态为 PARTIAL_FAILED;全部成功后为 COMPLETED

数据库迁移

  • 测试环境:.deploy/test-deploy/sql/20260717_aslan_game_king.sql
  • 生产环境:.deploy/prod-deploy/sql/20260717_aslan_game_king.sql
  • 两份 SQL 内容应保持字节一致。迁移创建 9 张独立活动表,并登记 webconsole 菜单/资源。活动表 event_types 只为兼容旧服务保留,默认且只写 GAME_EXPENDITURE,真实流水的 ledger.event_type 仍保留用于审计。
  • SQL 文件开头已记录性能评估:实时写路径使用唯一键/主键聚合,榜单直接读取维度索引,恢复与到期扫描均有状态时间索引;补数绑定 sys_origin + EXPENDITURE 并使用四个转义后的左锚定前缀,利用钱包 (sys_origin,event_type,create_time) 索引。迁移不回填钱包流水,也不扫描更新既有业务大表。
  • 当前交付只新增了迁移文件,尚未在测试或生产数据库执行。执行前仍需按环境发布流程复核目标库、变更窗口和执行计划。