幸运升级接口文档(Cocos 客户端对接)
适用版本:当前 master。所有接口路径前缀 /api/luckyUpgrade(另有 1 个关联接口在 /api/userPackSack)。
代码位置:skins-service/service-playingmethod/.../ApiLuckyUpgradeController.java、ApiLuckyUpgradeServiceImpl.java、ApiUpgradeRecordServiceImpl.java。
一、玩法机制(实现口径)
1.1 一局流程
1.2 消耗与判定公式
| 项 |
公式 / 取值 |
| 单次消耗 |
price = 饰品实时价(tt_ornament.use_price) × probability / 100,保留 2 位小数(前端不传价格,由后端算,防 0 元 100% 中奖) |
| 判定概率 |
eff = min(probability, 75)(封顶 75:选 90% 也只按 75% 判定,但钱按 90% 收) |
| 本轮空间 |
fullV:从该饰品位对应奖池的幸运区间 [min, max) 里随机取 nextInt(max-min) + min |
| 判定 |
每拉一次 进度 += eff;进度 + eff >= fullV 即中奖,中奖后 fullV 重新随机、进度清 0;否则失败继续累加 |
| 推论 |
玩家为一件饰品付出的总成本 ≈ 饰品价 × fullV / 100。所以幸运区间 = 该池的"售价百分比区间":[50,250] 表示平均要付 50%~250% 原价才出;压到个位数(如 [9,10])等于必中、平台必亏 |
1.3 幸运值与幸运区间:三套独立奖池
幸运值 = 该池"累计原始概率",失败累加 probability(原始值,不是封顶后的 75)、中奖清 0;界面与记录里展示的就是它。
| 奖池 |
判定/显示用 userType |
幸运区间字段 |
幸运值字段 |
本轮已投金额字段 |
| 普通用户 |
02 |
tt_upgrade_ornaments.luck_section |
probability_invested |
amount_invested / effective_amount_invested |
| 主播 |
01 |
anchor_luck_section |
anchor_probability_invested |
anchor_amount_invested / anchor_effective_amount_invested |
| 白号 |
06(is_blank_account=1 优先判定) |
blank_luck_section(未配置回退 luck_section) |
blank_probability_invested |
blank_amount_invested / blank_effective_amount_invested |
- 三池完全隔离:进度缓存在 Redis
upgrade_range_fixed:{饰品位}:{池类型} / upgrade_range:{饰品位}:{池类型},互不影响、互不阻塞(锁也是按「饰品位 + 池类型」)。
- 同一池内是共享进度:同一个池子的玩家一起把进度推到
fullV,谁那一拉跨过阈值谁中奖(和普通/主播现有行为一致,白号同理,白号之间共享 06 池)。
- 白号记录里的幸运值/已投金额读的都是白号自己的池,不再是真实玩家池的读数。
1.4 获得与失败奖励
- 成功:获得
tt_upgrade_ornaments.ornaments_id 对应的整件饰品,gain_ornaments_price = 该饰品实时价。
- 失败:获得后台「幸运升级 → 失败奖励」为该饰品位配置的饰品(
tt_upgrade_fail_ornaments,可多件,按 ornament_number 计数),gain_ornaments_price = 安慰奖总价值;该饰品位没配失败奖励时啥都不给(gainOrnamentList 为 []、金额 0)。
- 所有获得物都写入背包
tt_box_records(source = 4 幸运升级、状态 = 在背包)。
1.5 流水与返佣口径
| 场景 |
流水 source |
| 升级消费 |
40(GOLD_DEVICE,「幸运升级消费」,输出) |
| 游戏内分解(结果页立即分解) |
41(GOLD_DEVICE_REWARD,「幸运升级奖励」,输入) |
| 背包里分解(事后在背包页分解) |
10(DECOMPOSE_ORNAMENT,输入) |
- 消费 source 40 计入:今日/历史投注流水、综合消费排行榜、流水抽奖资格、上级返佣(按
classicGameCommissionRate 口径)、VIP 流水返利。
- 白号例外:白号消费不触发上级返佣、不触发 VIP 流水返利;后台充值/流水/记录类页面普遍按
is_blank_account=1 排除白号。
二、通用约定
- 域名:
{host}(例:http://103.108.67.60:28081)。
- Content-Type:
application/json;鉴权:除 getOrnamentsList 外都需要请求头带 token,401 时按项目统一逻辑弹登录。
- 统一响应:
| code |
含义 |
| 200 |
成功(客户端以 code === 200 判定) |
| 401 |
未登录 / 登录过期,msg「登录过期,请重新登录。」 |
| 702 |
账户余额不足 |
| 703 |
玩家未充值不能游玩任何游戏 |
| 500 |
业务失败,msg 直接给玩家看 |
- 维护开关(
sys_config,后台「网站设置」):websiteMaintenance=1 → 「网站维护中......」;luckyUpgradeMaintenance=1 → 「幸运升级维护中......」。两个开关都先于登录校验返回。
- 通用拦截(
upgrade 接口):非 主播(01)/普通(02)/白号 → 「非法的用户类型」;status=1 → 「账号已被封禁,无法参与游戏」;del_flag != 0 → 「账号状态异常,无法参与游戏」。
- 幸运升级相关也有
/api/luckyUpgrade/** 其他接口,本文件只覆盖下表这些。
三、接口清单
| 接口 |
说明 |
鉴权 |
分页 |
POST /api/luckyUpgrade/getOrnamentsList |
可升级饰品列表(含当前幸运值) |
否(未登录按普通用户口径) |
无 |
POST /api/luckyUpgrade/upgrade |
拉取一次(扣款 + 判定 + 发奖) |
是 |
- |
POST /api/luckyUpgrade/recordPage |
记录页:全服/我的 × 当前饰品/全部饰品 |
是 |
真分页 |
POST /api/luckyUpgrade/recentPulls |
某饰品位最近 50 次拉取流水 |
是 |
无(固定 50) |
POST /api/luckyUpgrade/myHistoryRecord |
我的记录(全部饰品,成败都返回) |
是 |
真分页 |
POST /api/luckyUpgrade/getUpgradeRecord |
通用条件查询(内部/后台复用) |
是 |
真分页 |
POST /api/luckyUpgrade/tenTopUpgradeRecord |
十佳掉落榜(按实际获得价值 Top10) |
是 |
无(固定 10) |
POST /api/userPackSack/decompose |
分解获得的饰品(结果页或背包) |
是 |
- |
四、接口详情
4.1 POST /api/luckyUpgrade/getOrnamentsList — 可升级饰品列表
请求(全部可选,无分页、无排序参数,返回按 use_price 升序)
| 字段 |
类型 |
说明 |
| id |
Integer |
可直接取某一个饰品位(tt_upgrade_ornaments.id) |
| type |
String |
饰品类型数字字典码(1匕首 2手枪 3步枪 4微型冲锋枪 5重型武器 6手套 7印花 8其它);空串按不传处理 |
| itemName |
String |
饰品名称模糊匹配 |
| priceMin / priceMax |
BigDecimal |
按价格区间过滤(只在传了 priceMax 时生效;不传 priceMin 默认 0) |
| userType |
String |
后端注入,客户端不要传(用登录用户身份决定返回哪个池的幸运值) |
响应:data 为数组,仅返回 status='0'(启用)的饰品位:
| 字段 |
类型 |
说明 |
| id |
Integer |
可升级饰品ID(后续 upgrade.upgradeId、recordPage.upgradeId、recentPulls.upgradeRecordId 都传它) |
| ornamentId |
Long |
饰品ID(tt_ornament.id) |
| name |
String |
饰品全名(优先展示) |
| itemName |
String |
名称(与 name 同源字段) |
| usePrice |
BigDecimal |
实时价格(= 计算消耗、展示目标金额的基准) |
| imageUrl |
String |
饰品图片 |
| shortName / typeName / rarityName / exteriorName / levelImg |
String |
简称 / 类型 / 稀有度 / 磨损度 / 品质图 |
| luckyValue |
Integer |
当前幸运值(按登录身份取对应池:普通/主播/白号) |
4.2 POST /api/luckyUpgrade/upgrade — 拉取一次
请求
| 字段 |
类型 |
必填 |
说明 |
| upgradeId |
Integer |
是 |
可升级饰品ID(getOrnamentsList 的 id) |
| probability |
Integer |
是 |
本次选择的成功率,1~100;判定按 min(概率,75),扣款按传入值 |
响应:data = 本条升级记录(tt_upgrade_record),字段如下:
| 字段 |
类型 |
说明 |
| id |
Long |
升级记录ID |
| userId / nickName / userType / userAvatar |
- |
玩家信息(昵称是升级时快照) |
| probability |
Integer |
本次选择的成功率(原始概率快照) |
| luckyValue |
Integer |
本次升级时的幸运值快照(中奖为 0) |
| amountConsumed |
BigDecimal |
本次实际消耗 |
| amountRequired |
BigDecimal |
本轮目标金额快照 = 饰品价 × fullV% |
| amountInvested / effectiveAmountInvested |
BigDecimal |
本轮已投金额(实际扣款口径 / 真实计算口径)快照 |
| effectiveAmount |
BigDecimal |
真实计算金额 = 饰品价 × min(概率,75)% |
| targetUpgradeId |
Integer |
可升级饰品ID |
| targetOrnamentId |
Long |
目标饰品ID |
| targetOrnamentPrice |
BigDecimal |
目标饰品价格 |
| isVictory |
Boolean |
成败:true=升级成功 |
| gainOrnamentsPrice |
BigDecimal |
本次获得饰品总价值(成功=目标饰品价,失败=安慰奖总价,可能为 0) |
| gainOrnamentList |
Array |
本次实际获得物(JSON 数组,不是字符串),每项:id=背包记录ID(tt_box_records.id)、ornamentId、ornamentName、ornamentHashName、ornamentPrice、ornamentImgUrl、ornamentLevelId、ornamentLevelImg、ornamentNumber;无获得时为 [] |
| openTime |
String |
升级时间 yyyy-MM-dd HH:mm:ss |
失败返回示例:{"code":500,"msg":"系统繁忙,请稍后重试。"}(同池并发抢锁失败,客户端可直接重试);{"code":703,"msg":"玩家未充值不能游玩任何游戏"};{"code":702,"msg":"账户余额不足"};{"code":500,"msg":"该饰品未在幸运升级开放。"}。
结果页立即分解:取 gainOrnamentList[i].id 作为 packSackIds,调 4.8 接口(decomposeType="game")。不分解就等于饰品留在背包里。
4.3 POST /api/luckyUpgrade/recordPage — 记录页(主力接口)
请求(二维组合,共 4 种场景,均需登录)
| 字段 |
类型 |
必填 |
默认 |
说明 |
| scope |
Integer |
否 |
0 |
0=全服(不过滤用户) 1=我的 |
| itemScope |
Integer |
否 |
0 |
0=全部饰品 1=当前饰品 |
| upgradeId |
Long |
条件必填 |
- |
可升级饰品ID;itemScope=1 时必填,为空返回 500;itemScope=0 时传了也忽略 |
| page |
Integer |
否 |
1 |
页码(≥1) |
| size |
Integer |
否 |
10 |
每页条数(1~20,超限参数错误) |
响应:data 为分页对象 { records, total, current, size, pages },records 按 openTime 倒序:
| 字段 |
类型 |
说明 |
| userId / avatar / nickName / vipLevel |
- |
玩家信息(昵称是升级时快照) |
| probability |
Integer |
成功率(原始概率,如 89 表示 89%) |
| luckyValue |
Integer |
幸运值快照(按该玩家所属池;白号是白号池的值) |
| amountConsumed |
BigDecimal |
消耗 |
| gainOrnamentsPrice |
BigDecimal |
获得饰品总价值 |
| isVictory |
Boolean |
成败:true=升级成功(前端胜负样式用) |
| openTime |
String |
升级时间 |
| targetOrnamentId |
Long |
目标饰品ID |
| name / imageUrl / usePrice / exteriorName / levelImg |
- |
本次实际获得的饰品:成功=目标饰品,失败=安慰奖饰品(gainOrnamentList 首件);未配安慰奖的失败记录会回退成目标饰品且金额为 0,胜负请用 isVictory 判断,不要看图片 |
- 全服(scope=0)不过滤白号、机器人、封禁用户,白号可正常上榜。
- 旧的
recentPulls / myHistoryRecord 场景都被本接口覆盖,可继续用但建议逐步切到本接口。
4.4 POST /api/luckyUpgrade/recentPulls — 某饰品位最近 50 次拉取流水
请求:{ "upgradeRecordId": 25 }
| 字段 |
类型 |
必填 |
说明 |
| upgradeRecordId |
Long |
是 |
⚠️ 字段名有历史误导性:实际语义是「可升级饰品ID」tt_upgrade_ornaments.id(getOrnamentsList 的 id)。为空返回 500「upgradeRecordId(升级饰品ID)不能为空」 |
| 其他字段 |
- |
否 |
ornamentId/userType/userId/page/size/limit 全部忽略 |
- 无分页:固定最近 50 条(SQL
LIMIT 50),没有 page/total。
- 不过滤:全服所有人(含白号、机器人、封禁/删除用户),成功与失败都返回。
nickName/avatar/vipLevel 可能为 null(该记录的用户已不在 tt_user),客户端要能容错。
响应:data 直接是数组(不是分页对象):
| 字段 |
类型 |
说明 |
| avatar / nickName / vipLevel |
- |
拉取人信息 |
| probability |
Integer |
本次拉取选择的成功率(不是中奖率) |
| luckyValue |
Integer |
本次拉取时的幸运值快照(累计原始概率;成功为 0),与 recordPage 同口径 |
| isVictory |
Boolean |
成败:true=升级成功 |
| name / imageUrl / usePrice / exteriorName / levelImg |
- |
目标饰品("谁在拉这个饰品",不是获得物) |
| openTime |
String |
拉取时间 |
4.5 POST /api/luckyUpgrade/myHistoryRecord — 我的记录(全部饰品)
| 字段 |
类型 |
必填 |
默认 |
说明 |
| page |
Integer |
否 |
1 |
页码 |
| size |
Integer |
否 |
10 |
1~20 |
响应:data 为分页对象,records 是 tt_upgrade_record(字段同 4.2 的响应,含 gainOrnamentList),仅当前登录用户、不含他人记录、成败都返回、按时间倒序;昵称/头像会补齐。
4.6 POST /api/luckyUpgrade/getUpgradeRecord — 通用条件查询
| 字段 |
类型 |
必填 |
说明 |
| page / size |
Integer |
必传 |
不传会 500(内部直接用于构造分页对象) |
| upgradeRecordId |
Long |
否 |
按记录ID精确查 |
| ornamentId |
Long |
否 |
按目标饰品ID过滤 |
| userType |
String |
否 |
按用户类型过滤(01/02/06…) |
| userId |
Integer |
否 |
按用户过滤 |
响应:data 为分页对象(records 为 tt_upgrade_record,userAvatar 已补齐,gainOrnamentList 空值兜底为 [])。主要用于内部/后台复用,客户端记录页请用 recordPage。
4.7 POST /api/luckyUpgrade/tenTopUpgradeRecord — 十佳掉落榜
| 字段 |
类型 |
必填 |
说明 |
| isVictory |
Boolean |
否 |
true 只看成功、false 只看失败;不传则全部记录一起排 |
响应:data 为分页对象(固定第 1 页、10 条),按 gainOrnamentsPrice(实际获得价值)倒序取 Top10 —— 即"实际掉落榜",不是目标饰品价值榜。
4.8 POST /api/userPackSack/decompose — 分解饰品(结果页/背包)
| 字段 |
类型 |
必填 |
说明 |
| packSackIds |
Long[] |
条件必填 |
背包记录ID(tt_box_records.id,即 gainOrnamentList[i].id);isAll=true 时可不传 |
| isAll |
Boolean |
是 |
是否全选 |
| decomposeType |
String |
否 |
game=游戏结果页立即分解(按饰品来源记 GOLD_DEVICE_REWARD(41));backpack=背包分解(记 DECOMPOSE_ORNAMENT(10)) |
返回 {"code":200,"msg":"成功分解N件饰品"}。受 websiteMaintenance 开关拦截。
五、前端对接要点
- upgradeId 语义:所有接口里的
upgradeId / recentPulls.upgradeRecordId 都是可升级饰品ID(tt_upgrade_ornaments.id),来自 getOrnamentsList 的 id,不是 tt_ornament.id,也不是升级记录ID。
- 扣款以服务端为准:不要传价格;展示价格用
usePrice × probability / 100(与后端同公式,后端保留 2 位小数)。
- 概率封顶 75:UI 上若提供 >75% 的档位,要提示"更高概率只加钱、不提升判定"。
- 幸运值怎么用:主界面实时幸运值取
getOrnamentsList.luckyValue;拉取成功后用 upgrade 响应里的 luckyValue 立即覆盖,不必等列表刷新。记录里的幸运值是历史快照。
- 分池:幸运值/幸运区间按 普通(02) / 主播(01) / 白号(06) 三套独立,白号看到的是白号池的值;同一池内进度是共享的,别人垫的进度也算在你头上。
- 分页:
recordPage/myHistoryRecord 的 size 上限 20;切换 tab(我的/全服、当前饰品/全部饰品)时 page 重置为 1。
- 失败记录展示:以
isVictory 判断胜负,name/imageUrl/... 是"实际获得物"(失败=安慰奖);无安慰奖时金额为 0。
- 结果页分解:
gainOrnamentList 里的 id 就是分解入参;不调用 = 饰品留在背包。
- 并发:同一饰品位 + 同一奖池同时拉取会串行,抢不到锁返回 500「系统繁忙,请稍后重试。」,可直接提示重试。
六、后台配置与调参
6.1 「幸运升级 → 饰品列表」(tt_upgrade_ornaments)
| 后台列 |
字段 |
说明 |
| 普通用户 / 幸运区间 |
luck_section |
普通用户池的 [min, max),即"售价百分比区间" |
| 普通用户 / 本轮已投金额 |
amount_invested |
普通池当前累计投入(运行时值,后台不可编辑回写) |
| 主播用户 / 幸运区间 |
anchor_luck_section |
主播池区间 |
| 白号用户 / 幸运区间 |
blank_luck_section |
白号池区间;为空则回退 luck_section |
| 白号用户 / 本轮已投金额 |
blank_amount_invested |
白号池当前累计投入 |
| 状态 |
status |
0=启用(=可升级、会出现在客户端列表) 1=禁用 |
- 调难度就调"幸运区间":区间 = 玩家为该饰品付出的价格百分比。想更容易出就整体下调(如
[80,280]→[60,200]);不要压到个位数(如 [9,10] 等于必中,等于按 9% 价格卖货),也不要配成 min == max(会被后端防护强制改成 [0,160])。
- 改完区间要清缓存才立即生效:
DEL upgrade_range:{饰品位}:{池} + DEL upgrade_range_fixed:{饰品位}:{池}(池=01/02/06)。不清的话当前这一轮仍按旧空间跑,等本轮中奖后自动按新配置重建。Redis 实测在 db0,密码见 application-*.yml。
- 白号是独立奖池,可与普通/主播配不同的区间;「批量填货」新增饰品位时白号区间默认取普通用户的默认值。
6.2 「幸运升级 → 失败奖励」(tt_upgrade_fail_ornaments)
每个饰品位可配多件失败奖励(ornament_name / ornament_price / ornament_number / ornament_level_id),玩家升级失败即发放这些饰品;没配就不发(记录里 gainOrnamentList=[]、gainOrnamentsPrice=0)。
6.3 维护开关(后台「网站设置」,sys_config)
| key |
值 |
效果 |
websiteMaintenance |
1 |
全站维护:upgrade 与分解接口都拦截 |
luckyUpgradeMaintenance |
1 |
只拦幸运升级:upgrade 返回「幸运升级维护中......」 |
6.4 数据落库
| 表 |
说明 |
tt_upgrade_record |
每条拉取记录(成败、消耗、获得总额、各项快照、gain_ornament_list JSON、lucky_value) |
tt_box_records |
获得物入背包(source=4 幸运升级),id 即结果页分解入参 |
tt_user_blend_ercash |
余额流水:消费 40、游戏内分解 41、背包分解 10 |
tt_upgrade_ornaments |
饰品位配置 + 三个池的运行进度(各池幸运值/已投金额) |
字段变更历史见 docs/updata_sql.md(含白号三列的 ALTER)。