Files
henan-backend/docs/updata_sql.md
T

217 lines
15 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.
# 数据库变更台账
> **数据库改动只写这里**:中文标题 + 完整可执行 SQL。不再单独建 `docs/*.sql`(全量基线除外)。
> 只记**变更 SQL**;**不写回滚 SQL** —— 已执行的条目即为既成事实,要撤销请从本文件的 git 历史取旧版本。
> 若某条变更依赖**尚未执行**的前置对象(建表、种子数据等),必须在条目标注清楚,别让后来者踩空。
---
## 幸运升级·水位策略简化为「单一目标水位」:`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**:
```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**:
```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 实测结果):
```sql
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` 时前几件货会落在收紧档(水位低 → 随机数高),属预期行为;
需要立刻放水用后台「奖池水位 → 注水」。
---
## 新增「麻将胡了」(mahjong 玩法)的后台菜单、角色授权与维护开关
**背景**:麻将胡了以「**新游戏**」类型接入,复用原玫瑰女郎(olympus 玩法)的整套统计口径
—— 消费流水 `source=68`、奖励流水 `source=69`、开箱产出 `source=15`、新游戏返佣费率字段
`tt_user.newGameCommissionRate`。代码层改动(后端统计链路 + 两个前端)见 `docs/修改记录.md`;
本条目**只记数据库变更**。
**本次数据库变更 3 张表、共 17 行**(2026-09-22 已在库 `henan` 执行):
| 表 | 变更 | 说明 |
|---|---|---|
| `sys_config` | 新增 **1 行** | `config_id=154`、`config_key='mahjongMaintenance'`,即「麻将胡了维护」开关 |
| `sys_menu` | 新增 **8 行** | 顶级目录 `mahjong`(`menu_id=3200`)+ 7 个子页面(`3201`~`3207`) |
| `sys_role_menu` | 新增 **8 行** | 全部授权给 `role_id=103` |
> **为什么 `menu_id` 用 `3200~3207`**:`3130~3137` 是已下架的奥林匹斯旧号段,不复用,
> 免得数据里「哪段 ID 属于哪个玩法」的对应关系失真。
**变更 SQL**:
```sql
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
(3200, '麻将胡了', 0, 6, 'mahjong', '', NULL, 1, 0, 'M', '0', '0', '', 'star', 'admin', NOW(), '', NULL, '麻将胡了游戏后台管理目录'),
(3201, '箱子配置', 3200, 1, 'box', 'game/mahjong/box/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:box', 'shopping', 'admin', NOW(), '', NULL, '麻将胡了·箱子配置(11 档投注,price ≡ bet)'),
(3202, '饰品列表', 3200, 2, 'bucket', 'game/mahjong/bucket/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:bucket', 'star', 'admin', NOW(), '', NULL, '麻将胡了·16 档饰品桶定义(0x~500x,只读)'),
(3203, '回合管理', 3200, 3, 'round', 'game/mahjong/round/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:round', 'documentation', 'admin', NOW(), '', NULL, '麻将胡了·预生成回合池(只读)'),
(3204, '奖池水位', 3200, 4, 'rewardPool', 'game/mahjong/rewardPool/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:pool', 'money', 'admin', NOW(), '', NULL, '麻将胡了·奖池水位(3 身份:普通/主播/白号)'),
(3205, '玩家记录', 3200, 5, 'record', 'game/mahjong/record/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:record', 'list', 'admin', NOW(), '', NULL, '麻将胡了·玩家游玩记录'),
(3206, '每日统计', 3200, 6, 'dailywin', 'game/mahjong/dailywin/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:win', 'chart', 'admin', NOW(), '', NULL, '麻将胡了·每日投注/赢奖/RTP 统计'),
(3207, '奖品管理', 3200, 7, 'prize', 'game/mahjong/prize/index', NULL, 1, 0, 'C', '0', '0', 'game:mahjong:prize', 'guide', 'admin', NOW(), '', NULL, '麻将胡了·返奖饰品与返奖区间');
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
(103, 3200), (103, 3201), (103, 3202), (103, 3203),
(103, 3204), (103, 3205), (103, 3206), (103, 3207);
INSERT INTO `sys_config`
(`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
VALUES
(154, '麻将胡了维护', 'mahjongMaintenance', '0', 'Y', 'admin', NOW(), '', NULL, '麻将胡了维护开关 0正常 1维护');
```
**验证**(2026-09-22 实测结果):
```sql
SELECT COUNT(*) FROM sys_menu WHERE menu_id BETWEEN 3200 AND 3207; -- 期望 8,实测 8
SELECT COUNT(*) FROM sys_role_menu WHERE menu_id BETWEEN 3200 AND 3207; -- 期望 8,实测 8
SELECT COUNT(*) FROM sys_config WHERE config_key = 'mahjongMaintenance'; -- 期望 1,实测 1
```
后台左侧出现「麻将胡了」目录(`order_num=6`),下辖 7 个子页面;
「网站设置」页出现「麻将胡了维护」下拉框(0 正常 / 1 维护)。
**前置依赖:麻将胡了的 11 张游戏表**(`game_mahjong_box` / `_bucket` / `_box_bucket` /
`_round` / `_step` / `_record` / `_user` / `_box_template` / `_reward_log` / `_prize_ornament` / `_prize_range`)。
**DDL 与种子数据的权威出处是 `mahjong-py/schema.sql`,不抄进本台账**(已拍板:建表只以该文件为权威、直接对库执行)。
该文件**可重复执行**(`CREATE TABLE IF NOT EXISTS` + `ON DUPLICATE KEY UPDATE`),无任何 `DROP` / `DELETE`。
执行方式(**2026-09-22 已执行**):
```bash
docker exec -i henan_mysql_db mysql -uroot -p123456 --default-character-set=utf8mb4 -D henan < mahjong-py/schema.sql
```
落库结果(实测):
| 表 | 行数 | 说明 |
|---|---|---|
| `game_mahjong_box` | 11 | 11 档投注,`price ≡ bet` |
| `game_mahjong_bucket` | 16 | 0x ~ 500x |
| `game_mahjong_prize_ornament` | 12 | 返奖饰品(沿用玫瑰女郎 id 以维持区间映射) |
| `game_mahjong_prize_range` | 12 | 连续覆盖 0.01 ~ 99,999,999 |
| `_box_bucket` / `_round` / `_step` / `_record` / `_user` / `_box_template` / `_reward_log` | 0 | 空表,等运行期数据 |
```sql
SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = 'henan' AND table_name LIKE 'game\_mahjong\_%'; -- 期望 11,实测 11
```
**仍需后台操作生成的运行期数据**(不是建表,别当成漏建):
1. `game_mahjong_box_bucket` 的 **528 行配比**(16 桶 × 11 箱 × 3 身份)—— 后台
「麻将胡了 → 箱子配置 → 一键重算」(`POST /admin/mahjong/box/recalc_all`)。**空表时挑不到回合。**
2. **每箱×身份的初始奖池水位** —— 后台「奖池水位 → 注水」(`¥300` / `¥500` 两档需单独注)。