Files

22 KiB
Raw Permalink Blame History

数据库变更台账

数据库改动只写这里:中文标题 + 完整可执行 SQL。不再单独建 docs/*.sql(全量基线除外)。 只记变更 SQL;不写回滚 SQL —— 已执行的条目即为既成事实,要撤销请从本文件的 git 历史取旧版本。 若某条变更依赖尚未执行的前置对象(建表、种子数据等),必须在条目标注清楚,别让后来者踩空。


头像库「是否默认」唯一化:tt_user_avatar 存量数据清洗

背景:tt_user_avatar.is_default 的语义是「新用户 / 白号注册时分配的初始头像」, 全表必须最多只有一条 is_default='1'。但后台「设置 → 头像管理」的开关写成默认时, 后端只做了 updateById,没有把其他记录的默认标记清掉 ⇒ 库中一度累积出 7 条默认(id 63~69), id=62 反而是「否」。后果:后台看到一排「是」容易误解(用户 2026-09-24 反馈), 且 C 端注册处(ApiRegisterServiceImpl / PromoLoginServiceImpl)用的是 list(is_default='1') + RandomUtil.choice(...) 随机挑一条,导致默认头像实际不唯一、每次注册拿到的都不同。

代码侧修复(非 SQL,见 docs/修改记录.md 同日条目):TtUserAvatarServiceImpl 在 updateUserAvatarById / saveAvatar 中增加互斥逻辑 —— 任何把某条置为 is_default='1' 的写入, 都先把其余记录清成 '0',两步同一事务。

本次数据库变更 1 处(2026-09-24 已在库 henan 执行):把多余的默认标记收敛为只保留 id 最小的一条(id=63)。

变更 SQL:

UPDATE `tt_user_avatar`
   SET `is_default` = '0'
 WHERE `is_default` = '1'
   AND `id` <> (SELECT `min_id` FROM (
         SELECT MIN(`id`) AS `min_id` FROM `tt_user_avatar` WHERE `is_default` = '1'
       ) AS `t`);

⚠️ MySQL 不允许在 UPDATE 的子查询里直接查同一张表,故此处包了一层派生表 t 绕过; 该写法的坑已记在 .workbuddy/memory/ 当日日志里,后续同类 SQL 照此办理。

验证口径:执行后 SELECT is_default, COUNT(*) FROM tt_user_avatar GROUP BY is_default; 应当只有两行 —— 0 → N(N = 总数-1)、1 → 1。


幸运升级·水位策略简化为「单一目标水位」:sys_config 配置结构变更

背景:上一版把水位策略做成了 4 档波段表(每档 = 水位下界/上界 + 随机数下界/上界), 后台要维护 16 个数、还要保证档间单调且留有重叠,运营难维护也容易配错。本次简化为只填一个「目标水位(%)」: 随机数的中心由目标水位自动反推,取值范围仍由每个饰品自己的「随机数区间」限定 (水位高于目标 → 落点靠近区间下限)。口径推导、换算表、仿真数据与算例见 docs/修改记录.md 的 2026-09-24 条。

本次数据库变更 1 处(2026-09-24 已在库 henan 执行):sys_config.config_key = 'luckyUpgradeWatermark' 的 config_value 由「波段表」改为「目标水位 + 灵敏度」,bands 字段废弃(后端已不再读取,留着不报错)。

⚠️ 前置依赖:本条的 UPDATE 依赖下一节「幸运升级·水位驱动改造」插入的那行 sys_config —— 全新库必须先执行那一条,再执行本条。

⚠️ 同时恢复(代码侧,非 SQL):饰品列表页的「随机数区间」编辑入口重新启用, tt_upgrade_ornaments.luck_section / anchor_luck_section / blank_luck_section 现在必须配置, 且要包含按目标水位推算出的中心值,否则中心被夹在边界上、水位停不到目标值。 ⇒ 下一节里「上线前清空三个区间列」的说法已作废,不要再执行那两条清空 SQL。

变更 SQL:

UPDATE `sys_config`
   SET `config_value` = '{"enabled":true,"targetWatermark":30,"gain":2,"luckyValueMode":"raw"}',
       `remark` = '幸运升级水位策略:目标水位%(平台希望长期维持的净收益比例)、灵敏度 gain、幸运值展示口径 raw/eff。随机数中心 = 100/((1-目标水位/100)*实测标定系数),再由每个饰品的随机数区间限定取值范围;中奖判定恒用 min(概率,75)。enabled=false 逐字节回退固定区间',
       `update_time` = NOW()
 WHERE `config_key` = 'luckyUpgradeWatermark';

字段口径:

字段 含义
enabled true = 按水位动态出随机数;false = 逐字节回退「每个饰品位固定 luck_section」
targetWatermark 目标水位(%):平台希望长期维持的净收益比例。30 ⇒ 长期平均 RTP ≈ 70%
gain 响应灵敏度:水位每偏离目标 1 个点,随机数中心反向调整 gain%。默认 2,后台不展示(调参用)
luckyValueMode 幸运值展示口径:raw(默认,累加前端原始概率)/ eff(累加 min(概率,75));不影响判定

幸运升级·水位驱动改造:水位日志表、拉取记录快照列、水位策略配置与「奖池水位」菜单

背景:幸运升级原来每个饰品位配一套固定幸运区间,随机数永远落在区间内(如 [100,160)), 玩家能看出「每次都要投到 1 倍原价以上才出」。本次改为按全局水位动态决定本轮的随机数区间: 水位 = (Σ下注 − Σ返奖 + 人工调整) / Σ下注(排除白号),水位越高 → 可出的随机数越低。 同时新增后台人工注水/抽水。方案、换算表、口径推导与算例全部汇总在 docs/修改记录.md 的 2026-09-23 条(不另建单独文档)。

本次数据库变更 4 处(2026-09-23 已在库 henan 执行):

对象 变更 说明
tt_upgrade_reward_log 新建表 注水/抽水审计日志,delta 为带符号影响,水位调整额 = SUM(delta)(DB 为真相,Redis 只是短缓存)
tt_upgrade_record 新增 2 列 watermark(本次拉取时的水位%)、round_target(本轮抽到的随机数快照)
sys_config 新增 1 行 config_id=155、config_key='luckyUpgradeWatermark',水位波段表 + 幸运值展示口径;enabled=false 可逐字节回退旧行为
sys_menu / sys_role_menu 各新增 1 / 2 行 menu_id=3208「幸运升级 → 奖池水位」,授权给 role_id 101(三恒)、103(Fdily)

为什么 menu_id 用 3208:3200~3207 是麻将胡了的号段,按顺序往后取,不复用已下架玩法的旧号段。

变更 SQL:

CREATE TABLE IF NOT EXISTS `tt_upgrade_reward_log` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'PK',
  `type` tinyint NOT NULL COMMENT '1注水 2抽水 3重置',
  `amount` decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '调整金额(绝对值,展示用)',
  `delta` decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '对水位的带符号影响(注水正/抽水负/重置为抵消值)',
  `watermark_before` decimal(8,2) DEFAULT NULL COMMENT '调整前水位%',
  `watermark_after` decimal(8,2) DEFAULT NULL COMMENT '调整后水位%',
  `operator` varchar(64) DEFAULT NULL COMMENT '操作人',
  `remark` varchar(200) DEFAULT NULL COMMENT '调整原因(必填,前端保证)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_create` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='幸运升级奖池水位调整日志';

ALTER TABLE `tt_upgrade_record`
  ADD COLUMN `watermark` decimal(8,2) NULL COMMENT '本次拉取时的水位%(1-RTP,排除白号,含人工调整)',
  ADD COLUMN `round_target` int NULL COMMENT '本轮抽到的随机数 fullV 快照';

INSERT INTO `sys_config`
  (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
VALUES
  (155, '幸运升级水位策略', 'luckyUpgradeWatermark',
   '{"enabled":true,"luckyValueMode":"raw","bands":[{"from":-999,"to":10,"vMin":95,"vMax":130},{"from":10,"to":26,"vMin":115,"vMax":150},{"from":26,"to":36,"vMin":75,"vMax":175},{"from":36,"to":999,"vMin":85,"vMax":128}]}',
   'Y', 'admin', NOW(), '', NULL, '幸运升级水位策略:波段表(水位%→随机数区间) + 幸运值展示口径 raw(原始概率)/eff(与判定同口径);中奖判定恒用 min(概率,75)。enabled=false 逐字节回退固定区间');

INSERT INTO `sys_menu`
  (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
VALUES
  (3208, '奖池水位', 2075, 3, 'rewardPool', 'skins/luckyUpgrade/rewardPool/index', NULL, 1, 0, 'C', '0', '0', 'skins:upgrade:pool', 'money', 'admin', NOW(), '', NULL, '幸运升级·奖池水位(全局水位/人工注水抽水/调整历史)');

INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES (101, 3208), (103, 3208);

验证(2026-09-23 实测结果):

SELECT COUNT(*) FROM information_schema.tables
 WHERE table_schema='henan' AND table_name='tt_upgrade_reward_log';                          -- 期望 1,实测 1
SELECT COUNT(*) FROM information_schema.columns
 WHERE table_schema='henan' AND table_name='tt_upgrade_record'
   AND column_name IN ('watermark','round_target');                                          -- 期望 2,实测 2
SELECT COUNT(*) FROM sys_config    WHERE config_key='luckyUpgradeWatermark';                 -- 期望 1,实测 1
SELECT COUNT(*) FROM sys_menu      WHERE menu_id=3208;                                       -- 期望 1,实测 1
SELECT COUNT(*) FROM sys_role_menu WHERE menu_id=3208;                                       -- 期望 2,实测 2

后台左侧「幸运升级」目录下出现「奖池水位」页(/luckyUpgrade/rewardPool)。

注意:水位策略上线后的运营动作

⚠️ 本节第 1 条已被本文件顶部「水位策略简化为单一目标水位」那条取代: luck_section / anchor_luck_section / blank_luck_section 重新成为必填项 (语义 = 随机数的允许取值范围),不要清空;而且要配成**包含「按目标水位推算出的中心值」**的区间。 清空后后端会用兜底区间 [80,160],能用但不受控。

  1. 两个已存在的饰品位(tt_upgrade_ornaments.id 18 / 25)的 luck_section 要清空,才能完全跟随全局波段 —— 已作废,见上方提示。
  2. 水位从 0 起步。enabled=true 时前几件货会落在收紧档(水位低 → 随机数高),属预期行为; 需要立刻放水用后台「奖池水位 → 注水」。

管理后台按钮级权限补全:sys_menu 补 24 行 F(按钮)记录

背景:后台按钮的显隐走前端 v-hasPermi(ruoyi-ui/src/directive/permission/hasPermi.js), 接口放行走后端 @PreAuthorize("@ss.hasPermi('...')"),两边比对的是同一个 sys_menu.perms (超管 user_id=1 拿 *:*:*,其他人拿「已授权菜单行的 perms 去重集合」,见 ruoyi-framework/.../SysPermissionService.java:55)。

历史遗留:从 menu_id 31xx 段开始,新增页面只建了 C 行、没建 F 行 (F 行分布:1000 段 61 行、2000 段 18 行、3100 段仅 9 行、3200+ 段 0 行)。 后果是这些页面的按钮在角色授权树里根本勾不到 ⇒ 除超管外谁都看不见; 更严重的是部分 列表/查询接口也会 403,页面进去是空的。

盘点结果:代码在用、但 sys_menu 未登记的权限串共 43 个。其中 23 个属于 4 个无菜单入口的孤儿页面 (ttOrnaments/boxOpenChance、ttBonus/firstRecharge、ttWelfare/monthlyRecharges、ttReplacementRecord/index —— 已核实无菜单、无组件引用、无路由、无接口复用方,不可达,本期不动); 其余 20 个 + 复用组补 4 行 = 24 行,本次补齐。

为什么 menu_id 用 3209~3232:MAX(menu_id)=3208(麻将胡了 3200~3207、幸运升级 3208),按顺序往后取。

本次数据库变更 3 处(2026-09-27 已在库 henan 执行):

对象 变更 说明
sys_menu 新增 24 行 menu_id=3209~3232,menu_type='F',挂到 6 个 C 行下(2035/2038/2086/2092/2123/3118)
sys_menu 修正 3 行 menu_id=3160~3162 的 parent_id:3156(目录 M「流水抽奖」)→ 3157(页面 C「抽奖活动」)。同属 F 行挂载错误,不改的话勾「抽奖活动」联动带不到这 3 个按钮
sys_role_menu 新增 24 行 把上述 F 行补授权给「已授权其父 C 行」的角色(动态 SQL,执行时按实际授权现状生成)。执行时这些父 C 行**仅 role_id=104(测试人员)**已授权 ⇒ 24 行全落给 104(sys_role_menu 总行数 222 → 246)

关于 3160~3162:这三个串(system:turnoverLottery:add/edit/remove)当前代码里无人使用 (turnoverLottery/list.vue 的新增/修改/删除按钮没写 v-hasPermi,后端也没有对应 @PreAuthorize), 所以本次修正只是把菜单树层级摆正、消除「F 行挂在目录下」的隐患,不影响线上行为。 若将来给该页面补按钮权限,直接复用这三个串即可。

变更 SQL:

/* ---- 1. 24 行按钮权限(F)---- */
INSERT INTO `sys_menu`
  (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
   `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
VALUES
  /* 奖池详情(ttRoll/prizedetail)—— 该页「删除」按钮历史上绑的就是 admin:prize:edit */
  (3209, '修改奖池',           2038, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:prize:edit',                          '#', 'admin', NOW(), '', NULL, '奖池详情·修改'),
  /* CDK管理(ttRedPack/index)—— 整套新增,此前 0 行 F */
  (3210, '新增红包',           2086, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:add',                   '#', 'admin', NOW(), '', NULL, 'CDK管理·新增'),
  (3211, '删除红包',           2086, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:remove',                '#', 'admin', NOW(), '', NULL, 'CDK管理·删除'),
  (3212, '修改红包',           2086, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:edit',                  '#', 'admin', NOW(), '', NULL, 'CDK管理·修改'),
  (3213, '导出红包',           2086, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:export',                '#', 'admin', NOW(), '', NULL, 'CDK管理·导出'),
  (3214, '红包查询',           2086, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:query',                 '#', 'admin', NOW(), '', NULL, 'CDK管理·详情'),
  (3215, '红包列表',           2086, 6, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:list',                  '#', 'admin', NOW(), '', NULL, 'CDK管理·列表接口'),
  (3216, '红包全部列表',        2086, 7, '', NULL, NULL, 1, 0, 'F', '0', '0', 'skinsback:ttRedPack:listAll',               '#', 'admin', NOW(), '', NULL, 'CDK管理·不分页列表接口'),
  /* 对战排行榜奖励(ttFight/fightRankingReward)—— 此前 0 行 F */
  (3217, '新增奖励',           2092, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:reward:add',                          '#', 'admin', NOW(), '', NULL, '对战排行榜奖励·生成'),
  (3218, '删除奖励',           2092, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:reward:remove',                       '#', 'admin', NOW(), '', NULL, '对战排行榜奖励·清空'),
  (3219, '修改奖励',           2092, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:reward:edit',                         '#', 'admin', NOW(), '', NULL, '对战排行榜奖励·修改'),
  (3220, '奖励查询',           2092, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:reward:query',                        '#', 'admin', NOW(), '', NULL, '对战排行榜奖励·详情'),
  (3221, '奖励列表',           2092, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:reward:list',                         '#', 'admin', NOW(), '', NULL, '对战排行榜奖励·列表接口'),
  /* 机器人对战配置(ttFight/robotFightConfig)—— 该 C 行下原有 4 行(3119~3122),价格配置这套是漏的,故 order 从 5 起 */
  (3222, '新增价格配置',        3118, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:robotFightPriceConfig:add',           '#', 'admin', NOW(), '', NULL, '机器人对战配置·价格配置新增'),
  (3223, '删除价格配置',        3118, 6, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:robotFightPriceConfig:remove',        '#', 'admin', NOW(), '', NULL, '机器人对战配置·价格配置删除'),
  (3224, '修改价格配置',        3118, 7, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:robotFightPriceConfig:edit',          '#', 'admin', NOW(), '', NULL, '机器人对战配置·价格配置修改'),
  (3225, '价格配置查询',        3118, 8, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:robotFightPriceConfig:query',         '#', 'admin', NOW(), '', NULL, '机器人对战配置·价格配置详情'),
  (3226, '价格配置列表',        3118, 9, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:robotFightPriceConfig:list',          '#', 'admin', NOW(), '', NULL, '机器人对战配置·价格配置列表接口'),
  /* 货币列表(ttRechargeList/index)—— 该页只有详情接口校验;列表接口本身无 @PreAuthorize */
  (3227, '货币查询',           2035, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:rechargeList:query',                  '#', 'admin', NOW(), '', NULL, '货币列表·详情'),
  /* 机器人对战分组宝箱(ttFight/robotFightGroupBox)
     ⚠️ 复用组:该页前端按钮用 admin:box:{add,edit,remove}、后端接口用 admin:box:{list,query},
        而这 4 个串原先只挂在 2019「宝箱列表」下 —— 父子联动带不过来,
        所以必须在 2123 下再挂一遍,才能做到「勾这一个页面 = 该页完整可用」。*/
  (3228, '新增分组宝箱',        2123, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:box:add',                             '#', 'admin', NOW(), '', NULL, '机器人对战分组宝箱·新增(与 2020 同 perms,刻意重复)'),
  (3229, '删除分组宝箱',        2123, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:box:remove',                          '#', 'admin', NOW(), '', NULL, '机器人对战分组宝箱·删除(与 2021 同 perms,刻意重复)'),
  (3230, '修改分组宝箱',        2123, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:box:edit',                            '#', 'admin', NOW(), '', NULL, '机器人对战分组宝箱·修改(与 2022 同 perms,刻意重复)'),
  (3231, '分组宝箱查询',        2123, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:box:query',                           '#', 'admin', NOW(), '', NULL, '机器人对战分组宝箱·详情接口'),
  (3232, '分组宝箱列表',        2123, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'admin:box:list',                            '#', 'admin', NOW(), '', NULL, '机器人对战分组宝箱·列表接口(与 2019/3139 同 perms,刻意重复)');

/* ---- 2. 授权补齐:把新 F 行补给「已授权其父 C 行」的角色 ----
   动态写法的好处:不依赖执行时刻的角色授权现状,也不用在角色界面逐个重存。
   注意:只补 F 行;C 行(页面本身)是否可见仍由业务在「角色管理」里决定。*/
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
SELECT DISTINCT `rm`.`role_id`, `f`.`menu_id`
  FROM `sys_menu` `f`
  JOIN `sys_role_menu` `rm` ON `rm`.`menu_id` = `f`.`parent_id`
 WHERE `f`.`menu_id` BETWEEN 3209 AND 3232
   AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` `x`
                    WHERE `x`.`role_id` = `rm`.`role_id` AND `x`.`menu_id` = `f`.`menu_id`);

/* ---- 3. 修正 3 行挂错父节点的 F(3160~3162:目录 3156 → 页面 3157)---- */
UPDATE `sys_menu`
   SET `parent_id` = 3157
 WHERE `menu_id` BETWEEN 3160 AND 3162
   AND `menu_type` = 'F'
   AND `parent_id` = 3156;

验证:

-- ① 24 行 F 都进去了、且 perms 无重复录入
SELECT COUNT(*) FROM sys_menu WHERE menu_id BETWEEN 3209 AND 3232 AND menu_type='F';   -- 期望 24
SELECT perms, COUNT(*) FROM sys_menu WHERE menu_id BETWEEN 3209 AND 3232
 GROUP BY perms HAVING COUNT(*) > 1;                                                    -- 期望 0 行(2123 组与 2019 组不同 id,不算重复)

-- ② 全库 F 行的 parent 必须是指向 C 行的 menu_id(防挂错;本次修掉了 3160~3162 这组)
SELECT f.menu_id, f.menu_name, f.perms, f.parent_id, p.menu_type
  FROM sys_menu f LEFT JOIN sys_menu p ON p.menu_id = f.parent_id
 WHERE f.menu_type = 'F' AND (p.menu_id IS NULL OR p.menu_type <> 'C');                -- 期望 0 行

-- ③ 授权补齐后:每个新 F 行,其父 C 行的每个授权角色都应能查到
SELECT f.menu_id, f.perms, rm.role_id
  FROM sys_menu f
  JOIN sys_role_menu rm ON rm.menu_id = f.parent_id
 WHERE f.menu_id BETWEEN 3209 AND 3232
   AND NOT EXISTS (SELECT 1 FROM sys_role_menu x
                    WHERE x.role_id = rm.role_id AND x.menu_id = f.menu_id);            -- 期望 0 行

-- ④ 端到端:模拟某角色的 perms 集合,确认缺串已消失
SELECT DISTINCT m.perms FROM sys_menu m
  JOIN sys_role_menu rm ON m.menu_id = rm.menu_id
 WHERE rm.role_id = <角色ID> AND m.perms IS NOT NULL AND m.perms <> '';

代码侧配套(非 SQL):新增 .workbuddy/verify-perms.cjs,做「代码在用的权限串 ↔ sys_menu.perms」双向差集, 防止后续新增页面再次只建 C 行、漏建 F 行。跑法见脚本头部注释。

注意:权限生效需要用户重新登录(permissions 是登录时从 /getInfo 拉取的,存在前端 store 里,不会热更新)。


-----------------------对战接口优化--------------------------

SHOW INDEX FROM tt_fight;

ALTER TABLE tt_fight ADD INDEX idx_ttf_status_create (status, create_time);

ALTER TABLE tt_fight ADD COLUMN total_ornaments_price DECIMAL(18,2) NULL COMMENT '本场开箱饰品总价值(百佳榜排序用)', ADD INDEX idx_ttf_status_total (status, total_ornaments_price);

ALTER TABLE tt_fight_user ADD INDEX idx_tfu_fight_user (fight_id, user_id);

ALTER TABLE tt_fight ADD INDEX idx_ttf_create_time (create_time);