topfans/backend/scripts/20260513_economic_system.sql
2026-05-14 15:59:07 +08:00

279 lines
12 KiB
SQL
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.

-- ============================================================
-- 经济系统建表脚本
-- 执行方式: psql -h <host> -U <user> -d <db> -f backend/scripts/20260513_economic_system.sql
-- 创建日期: 2026-05-13
-- 说明: 本脚本用于初始化经济系统相关的表和配置
-- - fan_profiles 表新增字段: revenue_boost_bps, like_bet_count
-- - 铸造消耗配置、用户铸爱累计
-- - 等级阈值、升级奖励配置
-- - 水晶/游戏币流水表
-- ============================================================
-- 1. Add revenue_boost_bps column to fan_profiles (if not exists)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'fan_profiles' AND column_name = 'revenue_boost_bps') THEN
ALTER TABLE fan_profiles ADD COLUMN revenue_boost_bps INT NOT NULL DEFAULT 0;
END IF;
END $$;
-- 1.2 Add like_bet_count column to fan_profiles (if not exists)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'fan_profiles' AND column_name = 'like_bet_count') THEN
ALTER TABLE fan_profiles ADD COLUMN like_bet_count INT NOT NULL DEFAULT 0;
END IF;
END $$;
-- 2. 铸造消耗配置表
CREATE TABLE IF NOT EXISTS mint_cost_config (
id BIGSERIAL PRIMARY KEY,
mint_count INT NOT NULL UNIQUE,
cost_crystal BIGINT NOT NULL,
probability BIGINT DEFAULT 0,
reward_type VARCHAR(50) DEFAULT NULL,
reward_value BIGINT DEFAULT 0,
description VARCHAR(255),
updated_at BIGINT NOT NULL
);
COMMENT ON TABLE mint_cost_config IS '铸造消耗配置表,记录每次铸造的水晶消耗和保底概率';
-- 初始数据
INSERT INTO mint_cost_config (mint_count, cost_crystal, probability, reward_type, reward_value, description, updated_at) VALUES
(1, 2, 0, NULL, 0, '第1次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(2, 4, 0, NULL, 0, '第2次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(3, 8, 0, NULL, 0, '第3次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(4, 16, 0, NULL, 0, '第4次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(5, 32, 0, NULL, 0, '第5次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(6, 64, 0, NULL, 0, '第6次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(7, 128, 0, NULL, 0, '第7次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(8, 256, 0, NULL, 0, '第8次铸造', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(9, 512, 20, '收益提升', 500, '20%概率获得500 bps+5%)永久收益提升(小保底)', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(10, 1024, 100, '收益提升', 500, '100%概率获得500 bps+5%)永久收益提升(大保底)', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT (mint_count) DO NOTHING;
-- 3. 用户铸爱累计表
CREATE TABLE IF NOT EXISTS user_mint_count (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
mint_count INT NOT NULL DEFAULT 0,
revenue_boost_bps INT NOT NULL DEFAULT 0,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_user_mint_star UNIQUE (user_id, star_id)
);
COMMENT ON TABLE user_mint_count IS '用户铸爱累计表,记录用户累计铸造次数和永久收益提升基点';
-- 4. 等级阈值配置表
CREATE TABLE IF NOT EXISTS level_thresholds (
level INT PRIMARY KEY,
max_exhibition_hours BIGINT NOT NULL,
like_bet_count INT NOT NULL,
description VARCHAR(100)
);
COMMENT ON TABLE level_thresholds IS '等级阈值配置表,记录升级到每个等级需要的累计上架时长和点赞押注次数';
-- 初始数据20级满级
INSERT INTO level_thresholds (level, max_exhibition_hours, like_bet_count, description) VALUES
(1, 0, 0, '1级新手'),
(2, 6, 6, '2级粉丝'),
(3, 12, 7, '3级真爱'),
(4, 18, 8, '4级铁粉'),
(5, 24, 9, '5级钻石粉'),
(6, 30, 9, '6级钻石粉'),
(7, 36, 10, '7级钻石粉'),
(8, 42, 11, '8级钻石粉'),
(9, 48, 12, '9级钻石粉'),
(10, 54, 13, '10级钻石粉'),
(11, 60, 13, '11级钻石粉'),
(12, 66, 13, '12级钻石粉'),
(13, 72, 14, '13级钻石粉'),
(14, 78, 15, '14级钻石粉'),
(15, 84, 16, '15级钻石粉'),
(16, 90, 16, '16级钻石粉'),
(17, 96, 17, '17级钻石粉'),
(18, 102, 18, '18级钻石粉'),
(19, 108, 19, '19级钻石粉'),
(20, 114, 20, '20级终极粉')
ON CONFLICT (level) DO NOTHING;
-- 5. 用户累计上架时长表
CREATE TABLE IF NOT EXISTS user_exhibition_hours (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
total_exhibition_hours BIGINT NOT NULL DEFAULT 0,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_exhibition_user_star UNIQUE (user_id, star_id)
);
COMMENT ON TABLE user_exhibition_hours IS '用户累计上架时长表,记录用户累计上架时长';
-- 6. 等级上限配置表
CREATE TABLE IF NOT EXISTS level_cap_config (
id BIGSERIAL PRIMARY KEY,
max_level INT NOT NULL DEFAULT 20,
updated_at BIGINT NOT NULL
);
COMMENT ON TABLE level_cap_config IS '等级上限配置表,记录最高等级';
INSERT INTO level_cap_config (max_level, updated_at) VALUES (20, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT DO NOTHING;
-- 7. 等级升级条件配置表21级+
CREATE TABLE IF NOT EXISTS level_upgrade_conditions (
level INT PRIMARY KEY,
require_total_hours BIGINT NOT NULL,
require_dazi_level INT DEFAULT 0,
description VARCHAR(100),
updated_at BIGINT NOT NULL
);
COMMENT ON TABLE level_upgrade_conditions IS '等级升级条件配置表记录21级及以上的升级条件';
-- 8. 升级奖励配置表
CREATE TABLE IF NOT EXISTS level_up_reward_config (
id BIGSERIAL PRIMARY KEY,
level INT NOT NULL,
reward_type VARCHAR(50) NOT NULL,
reward_value BIGINT NOT NULL DEFAULT 0,
is_enabled BOOLEAN DEFAULT true,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_level_reward_type UNIQUE (level, reward_type)
);
COMMENT ON TABLE level_up_reward_config IS '升级奖励配置表,记录升级时发放的奖励类型和数值';
-- 初始数据21级示例后续可扩展更多等级
INSERT INTO level_upgrade_conditions (level, require_total_hours, require_dazi_level, description, updated_at) VALUES
(21, 120, 21, '21级总时长120h + 搭子21级', ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT (level) DO NOTHING;
-- 8. 升级奖励配置表
CREATE TABLE IF NOT EXISTS level_up_reward_config (
id BIGSERIAL PRIMARY KEY,
level INT NOT NULL,
reward_type VARCHAR(50) NOT NULL,
reward_value BIGINT NOT NULL DEFAULT 0,
is_enabled BOOLEAN DEFAULT true,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_level_reward_type UNIQUE (level, reward_type)
);
-- 初始数据示例
INSERT INTO level_up_reward_config (level, reward_type, reward_value, is_enabled, updated_at) VALUES
(2, 'crystal', 10, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(2, 'like_bet_count', 1, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(3, 'crystal', 20, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(3, 'like_bet_count', 1, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(4, 'crystal', 30, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(4, 'like_bet_count', 1, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(5, 'crystal', 50, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(5, 'like_bet_count', 1, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(6, 'crystal', 80, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(7, 'crystal', 120, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(8, 'crystal', 180, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(9, 'crystal', 280, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(10, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(11, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(12, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(13, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(14, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(15, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(16, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(17, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(18, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(19, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(20, 'crystal', 500, true, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT (level, reward_type) DO NOTHING;
-- 9. 搭子等级阈值配置表(预留)
CREATE TABLE IF NOT EXISTS dazi_level_thresholds (
level INT PRIMARY KEY,
upgrade_condition VARCHAR(100),
condition_param INT DEFAULT 0,
description VARCHAR(100)
);
COMMENT ON TABLE dazi_level_thresholds IS '搭子等级阈值配置表(预留)';
-- 10. 用户搭子等级表(预留)
CREATE TABLE IF NOT EXISTS user_dazi_level (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
dazi_level INT NOT NULL DEFAULT 1,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_dazi_user_star UNIQUE (user_id, star_id)
);
COMMENT ON TABLE user_dazi_level IS '用户搭子等级表(预留)';
-- 11. 水晶交易流水表(预留)
CREATE TABLE IF NOT EXISTS crystal_transaction_records (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
change_type VARCHAR(30) NOT NULL,
delta BIGINT NOT NULL,
balance_before BIGINT NOT NULL,
balance_after BIGINT NOT NULL,
source_id VARCHAR(100),
description VARCHAR(255),
created_at BIGINT NOT NULL
);
COMMENT ON TABLE crystal_transaction_records IS '水晶交易流水表,记录水晶的收支明细(复式记账)';
CREATE INDEX IF NOT EXISTS ix_crystal_tx_user_star ON crystal_transaction_records(user_id, star_id);
CREATE INDEX IF NOT EXISTS ix_crystal_tx_created ON crystal_transaction_records(created_at DESC);
CREATE INDEX IF NOT EXISTS ix_crystal_tx_change_type ON crystal_transaction_records(change_type);
-- 12. 游戏币交易流水表(预留)
CREATE TABLE IF NOT EXISTS coin_transaction_records (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
change_type VARCHAR(30) NOT NULL,
delta BIGINT NOT NULL,
balance_before BIGINT NOT NULL,
balance_after BIGINT NOT NULL,
source_id VARCHAR(100),
description VARCHAR(255),
created_at BIGINT NOT NULL
);
COMMENT ON TABLE coin_transaction_records IS '游戏币交易流水表(预留)';
CREATE INDEX IF NOT EXISTS ix_coin_tx_user_star ON coin_transaction_records(user_id, star_id);
CREATE INDEX IF NOT EXISTS ix_coin_tx_created ON coin_transaction_records(created_at DESC);
-- 13. 铸造奖励配置表(预留)
CREATE TABLE IF NOT EXISTS mint_reward_config (
id BIGSERIAL PRIMARY KEY,
star_id BIGINT NOT NULL UNIQUE,
base_reward BIGINT NOT NULL DEFAULT 0,
is_enabled BOOLEAN DEFAULT true,
updated_at BIGINT NOT NULL
);
COMMENT ON TABLE mint_reward_config IS '铸造奖励配置表(预留),记录每个明星的铸造基础奖励';
-- 初始数据0=全服默认)
INSERT INTO mint_reward_config (star_id, base_reward, is_enabled, updated_at) VALUES (0, 0, false, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT (star_id) DO NOTHING;
-- 14. 铸造阶梯奖励配置表(预留)
CREATE TABLE IF NOT EXISTS mint_milestone_config (
id BIGSERIAL PRIMARY KEY,
star_id BIGINT NOT NULL,
milestone_count INT NOT NULL,
bonus_reward BIGINT NOT NULL,
created_at BIGINT NOT NULL,
CONSTRAINT uk_milestone_star_count UNIQUE (star_id, milestone_count)
);
COMMENT ON TABLE mint_milestone_config IS '铸造阶梯奖励配置表(预留),记录铸造里程碑奖励';
-- 初始数据示例
INSERT INTO mint_milestone_config (star_id, milestone_count, bonus_reward, created_at) VALUES
(0, 10, 5, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(0, 30, 15, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000)),
(0, 100, 50, ROUND(EXTRACT(EPOCH FROM NOW()) * 1000))
ON CONFLICT (star_id, milestone_count) DO NOTHING;
-- ============================================================
-- 完成
-- ============================================================