289 lines
10 KiB
SQL
289 lines
10 KiB
SQL
-- =====================================================
|
||
-- 推销模式功能 - 数据库脚本(第一阶段)
|
||
-- 包含:用户余额系统、分享免单系统、会员等级系统
|
||
-- 创建日期: 2026-03-06
|
||
-- 注意:请在Supabase SQL编辑器中分段执行
|
||
-- =====================================================
|
||
|
||
-- =====================================================
|
||
-- 0. 启用必要扩展
|
||
-- =====================================================
|
||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||
|
||
-- =====================================================
|
||
-- 一、用户余额系统
|
||
-- =====================================================
|
||
|
||
-- 1. 用户余额表
|
||
DROP TABLE IF EXISTS ml_user_balance CASCADE;
|
||
CREATE TABLE ml_user_balance (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
user_id UUID NOT NULL,
|
||
balance DECIMAL(10,2) DEFAULT 0,
|
||
frozen_balance DECIMAL(10,2) DEFAULT 0,
|
||
total_earned DECIMAL(10,2) DEFAULT 0,
|
||
total_withdrawn DECIMAL(10,2) DEFAULT 0,
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
UNIQUE(user_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_user_balance_user_id ON ml_user_balance(user_id);
|
||
|
||
COMMENT ON TABLE ml_user_balance IS '用户余额表';
|
||
COMMENT ON COLUMN ml_user_balance.balance IS '可用余额';
|
||
COMMENT ON COLUMN ml_user_balance.frozen_balance IS '冻结余额';
|
||
COMMENT ON COLUMN ml_user_balance.total_earned IS '累计获得';
|
||
COMMENT ON COLUMN ml_user_balance.total_withdrawn IS '累计提现';
|
||
|
||
-- 2. 余额变动记录表
|
||
DROP TABLE IF EXISTS ml_balance_records CASCADE;
|
||
CREATE TABLE ml_balance_records (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
user_id UUID NOT NULL,
|
||
type VARCHAR(50) NOT NULL,
|
||
amount DECIMAL(10,2) NOT NULL,
|
||
balance_before DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||
balance_after DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||
related_id UUID,
|
||
description VARCHAR(200),
|
||
operator_id UUID,
|
||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_balance_records_user_id ON ml_balance_records(user_id);
|
||
CREATE INDEX IF NOT EXISTS idx_balance_records_type ON ml_balance_records(type);
|
||
CREATE INDEX IF NOT EXISTS idx_balance_records_created_at ON ml_balance_records(created_at);
|
||
|
||
COMMENT ON TABLE ml_balance_records IS '余额变动记录表';
|
||
COMMENT ON COLUMN ml_balance_records.type IS '类型:free_order-免单奖励,rebate-返利,withdraw-提现,clear-清零,manual-手动调整';
|
||
|
||
-- =====================================================
|
||
-- 二、分享免单系统
|
||
-- =====================================================
|
||
|
||
-- 1. 分享记录表
|
||
DROP TABLE IF EXISTS ml_share_records CASCADE;
|
||
CREATE TABLE ml_share_records (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
user_id UUID NOT NULL,
|
||
product_id UUID NOT NULL,
|
||
order_id UUID NOT NULL,
|
||
order_item_id UUID,
|
||
share_code VARCHAR(20) NOT NULL UNIQUE,
|
||
product_name VARCHAR(200),
|
||
product_image VARCHAR(500),
|
||
product_price DECIMAL(10,2),
|
||
required_count INT DEFAULT 4,
|
||
current_count INT DEFAULT 0,
|
||
status INT DEFAULT 0,
|
||
reward_amount DECIMAL(10,2),
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
completed_at TIMESTAMPTZ,
|
||
expired_at TIMESTAMPTZ
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_share_records_user_id ON ml_share_records(user_id);
|
||
CREATE INDEX IF NOT EXISTS idx_share_records_share_code ON ml_share_records(share_code);
|
||
CREATE INDEX IF NOT EXISTS idx_share_records_status ON ml_share_records(status);
|
||
|
||
COMMENT ON TABLE ml_share_records IS '分享免单记录表';
|
||
COMMENT ON COLUMN ml_share_records.status IS '状态:0-进行中,1-已完成,2-已失效,3-已过期';
|
||
|
||
-- 2. 二级购买记录表
|
||
DROP TABLE IF EXISTS ml_secondary_purchases CASCADE;
|
||
CREATE TABLE ml_secondary_purchases (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
share_record_id UUID NOT NULL,
|
||
buyer_id UUID NOT NULL,
|
||
order_id UUID NOT NULL,
|
||
quantity INT DEFAULT 1,
|
||
unit_price DECIMAL(10,2),
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
UNIQUE(order_id, share_record_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_secondary_purchases_share_record_id ON ml_secondary_purchases(share_record_id);
|
||
CREATE INDEX IF NOT EXISTS idx_secondary_purchases_buyer_id ON ml_secondary_purchases(buyer_id);
|
||
|
||
COMMENT ON TABLE ml_secondary_purchases IS '二级用户购买记录表';
|
||
|
||
-- 3. 免单奖励记录表
|
||
DROP TABLE IF EXISTS ml_free_order_rewards CASCADE;
|
||
CREATE TABLE ml_free_order_rewards (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
user_id UUID NOT NULL,
|
||
share_record_id UUID NOT NULL,
|
||
amount DECIMAL(10,2) NOT NULL,
|
||
status INT DEFAULT 0,
|
||
balance_record_id UUID,
|
||
cleared_at TIMESTAMPTZ,
|
||
cleared_by UUID,
|
||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_free_order_rewards_user_id ON ml_free_order_rewards(user_id);
|
||
CREATE INDEX IF NOT EXISTS idx_free_order_rewards_status ON ml_free_order_rewards(status);
|
||
|
||
COMMENT ON TABLE ml_free_order_rewards IS '免单奖励记录表';
|
||
COMMENT ON COLUMN ml_free_order_rewards.status IS '状态:0-待发放,1-已发放,2-已清零';
|
||
|
||
-- =====================================================
|
||
-- 三、会员等级系统
|
||
-- =====================================================
|
||
|
||
-- 1. 会员等级配置表
|
||
DROP TABLE IF EXISTS ml_member_levels CASCADE;
|
||
CREATE TABLE ml_member_levels (
|
||
id INT PRIMARY KEY,
|
||
name VARCHAR(50) NOT NULL,
|
||
min_amount DECIMAL(10,2) DEFAULT 0,
|
||
discount DECIMAL(5,4) DEFAULT 1.0000,
|
||
icon VARCHAR(200),
|
||
description TEXT,
|
||
sort_order INT DEFAULT 0,
|
||
status INT DEFAULT 1,
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||
);
|
||
|
||
COMMENT ON TABLE ml_member_levels IS '会员等级配置表';
|
||
COMMENT ON COLUMN ml_member_levels.discount IS '折扣率,0.85表示85折';
|
||
|
||
-- 初始化会员等级数据
|
||
INSERT INTO ml_member_levels (id, name, min_amount, discount, description, sort_order) VALUES
|
||
(0, '普通会员', 0, 1.0000, '注册即可成为普通会员', 0),
|
||
(1, '铜牌会员', 500, 0.9800, '累计消费500元升级', 1),
|
||
(2, '银牌会员', 2000, 0.9500, '累计消费2000元升级', 2),
|
||
(3, '金牌会员', 5000, 0.9200, '累计消费5000元升级', 3),
|
||
(4, '钻石会员', 10000, 0.8800, '累计消费10000元升级', 4),
|
||
(5, 'VIP会员', 0, 0.8500, '商家特邀会员', 5);
|
||
|
||
-- 2. 会员等级变更记录表
|
||
DROP TABLE IF EXISTS ml_member_level_logs CASCADE;
|
||
CREATE TABLE ml_member_level_logs (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
user_id UUID NOT NULL,
|
||
old_level INT DEFAULT 0,
|
||
new_level INT NOT NULL,
|
||
reason VARCHAR(200),
|
||
operator_id UUID,
|
||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_member_level_logs_user_id ON ml_member_level_logs(user_id);
|
||
|
||
COMMENT ON TABLE ml_member_level_logs IS '会员等级变更记录表';
|
||
|
||
-- =====================================================
|
||
-- 四、RLS 策略
|
||
-- =====================================================
|
||
|
||
-- 用户余额表 RLS
|
||
ALTER TABLE ml_user_balance ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own balance" ON ml_user_balance;
|
||
CREATE POLICY "Users can view own balance"
|
||
ON ml_user_balance FOR SELECT
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
DROP POLICY IF EXISTS "Users can insert own balance" ON ml_user_balance;
|
||
CREATE POLICY "Users can insert own balance"
|
||
ON ml_user_balance FOR INSERT
|
||
TO authenticated
|
||
WITH CHECK (auth.uid() = user_id);
|
||
|
||
DROP POLICY IF EXISTS "Users can update own balance" ON ml_user_balance;
|
||
CREATE POLICY "Users can update own balance"
|
||
ON ml_user_balance FOR UPDATE
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
-- 余额记录表 RLS
|
||
ALTER TABLE ml_balance_records ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own balance records" ON ml_balance_records;
|
||
CREATE POLICY "Users can view own balance records"
|
||
ON ml_balance_records FOR SELECT
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
DROP POLICY IF EXISTS "Users can insert own balance records" ON ml_balance_records;
|
||
CREATE POLICY "Users can insert own balance records"
|
||
ON ml_balance_records FOR INSERT
|
||
TO authenticated
|
||
WITH CHECK (auth.uid() = user_id);
|
||
|
||
-- 分享记录表 RLS
|
||
ALTER TABLE ml_share_records ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own share records" ON ml_share_records;
|
||
CREATE POLICY "Users can view own share records"
|
||
ON ml_share_records FOR SELECT
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
DROP POLICY IF EXISTS "Users can insert own share records" ON ml_share_records;
|
||
CREATE POLICY "Users can insert own share records"
|
||
ON ml_share_records FOR INSERT
|
||
TO authenticated
|
||
WITH CHECK (auth.uid() = user_id);
|
||
|
||
DROP POLICY IF EXISTS "Users can update own share records" ON ml_share_records;
|
||
CREATE POLICY "Users can update own share records"
|
||
ON ml_share_records FOR UPDATE
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
-- 允许通过分享码查询
|
||
DROP POLICY IF EXISTS "Anyone can view by share code" ON ml_share_records;
|
||
CREATE POLICY "Anyone can view by share code"
|
||
ON ml_share_records FOR SELECT
|
||
TO authenticated, anon
|
||
USING (share_code IS NOT NULL);
|
||
|
||
-- 二级购买记录表 RLS
|
||
ALTER TABLE ml_secondary_purchases ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own secondary purchases" ON ml_secondary_purchases;
|
||
CREATE POLICY "Users can view own secondary purchases"
|
||
ON ml_secondary_purchases FOR SELECT
|
||
TO authenticated
|
||
USING (buyer_id = auth.uid() OR EXISTS (
|
||
SELECT 1 FROM ml_share_records WHERE id = share_record_id AND user_id = auth.uid()
|
||
));
|
||
|
||
DROP POLICY IF EXISTS "Users can insert secondary purchases" ON ml_secondary_purchases;
|
||
CREATE POLICY "Users can insert secondary purchases"
|
||
ON ml_secondary_purchases FOR INSERT
|
||
TO authenticated
|
||
WITH CHECK (true);
|
||
|
||
-- 免单奖励记录表 RLS
|
||
ALTER TABLE ml_free_order_rewards ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own rewards" ON ml_free_order_rewards;
|
||
CREATE POLICY "Users can view own rewards"
|
||
ON ml_free_order_rewards FOR SELECT
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|
||
|
||
-- 会员等级配置表 RLS
|
||
ALTER TABLE ml_member_levels ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Anyone can view member levels" ON ml_member_levels;
|
||
CREATE POLICY "Anyone can view member levels"
|
||
ON ml_member_levels FOR SELECT
|
||
TO authenticated, anon
|
||
USING (status = 1);
|
||
|
||
-- 会员等级变更记录表 RLS
|
||
ALTER TABLE ml_member_level_logs ENABLE ROW LEVEL SECURITY;
|
||
|
||
DROP POLICY IF EXISTS "Users can view own level logs" ON ml_member_level_logs;
|
||
CREATE POLICY "Users can view own level logs"
|
||
ON ml_member_level_logs FOR SELECT
|
||
TO authenticated
|
||
USING (auth.uid() = user_id);
|