-- ============================================================ -- 美家卡智影 - 后台运维 SQL 脚本 -- 适用场景:暂无管理后台,直接操作数据库 -- 注意:所有操作应在事务中执行,操作前请备份数据 -- ============================================================ -- ----------------------------------------------------------- -- 一、新增用户(支持同时赠送初始积分) -- ----------------------------------------------------------- -- 用法:修改下方变量后执行 DO $$ DECLARE v_mobile TEXT := '13800138000'; -- ← 修改:手机号 v_nickname TEXT := '新用户昵称'; -- ← 修改:昵称(可为空) v_source TEXT := 'manual'; -- ← 修改:注册来源:manual / invite / promotion v_invited_by UUID := NULL; -- ← 修改:邀请人 user_id(没有则留 NULL) v_gift_points INT := 2000; -- ← 修改:赠送初始积分(0 表示不赠送) v_gift_days INT := 365; -- ← 修改:赠送积分有效期(天) v_user_id UUID; v_batch_id BIGINT; v_now TIMESTAMPTZ := NOW(); BEGIN -- 1. 插入用户 INSERT INTO mjk_users ( id, mobile, password_hash, status, nickname, avatar_url, source, invited_by, last_login_at, last_login_ip, deleted_at, extra, created_at, updated_at ) VALUES ( gen_random_uuid(), v_mobile, NULL, -- 密码哈希(未设置密码) 'active', v_nickname, NULL, v_source, v_invited_by, NULL, NULL, NULL, '{}'::JSONB, v_now, v_now ) RETURNING id INTO v_user_id; -- 2. 初始化积分汇总(余额为 0) INSERT INTO mjk_user_points ( user_id, balance, total_recharged, total_consumed, total_expired, created_at, updated_at ) VALUES ( v_user_id, 0, 0, 0, 0, v_now, v_now ); -- 3. 如有赠送积分,创建批次 + 流水 + 更新余额 IF v_gift_points > 0 THEN -- 3.1 插入积分批次 INSERT INTO mjk_point_batches ( user_id, amount, remaining, expired_at, source, created_at, updated_at ) VALUES ( v_user_id, v_gift_points, v_gift_points, v_now + (v_gift_days || ' days')::INTERVAL, 'gift', v_now, v_now ) RETURNING id INTO v_batch_id; -- 3.2 插入积分流水 INSERT INTO mjk_point_transactions ( user_id, type, amount, balance_before, balance_after, source_type, source_id, batch_id, duration, category, description, created_at, updated_at ) VALUES ( v_user_id, 'recharge', v_gift_points, 0, -- 变动前余额 v_gift_points, -- 变动后余额 'manual_gift', v_batch_id::TEXT, v_batch_id, NULL, '充值', '新用户注册赠送积分', v_now, v_now ); -- 3.3 更新用户积分汇总 UPDATE mjk_user_points SET balance = v_gift_points, total_recharged = v_gift_points, updated_at = v_now WHERE user_id = v_user_id; END IF; RAISE NOTICE '用户创建成功,user_id = %', v_user_id; END $$; -- ----------------------------------------------------------- -- 二、积分赠送(给已有用户赠送积分) -- ----------------------------------------------------------- -- 用法:修改下方变量后执行 DO $$ DECLARE v_mobile TEXT := '13860199646'; -- ← 修改:目标用户手机号 v_gift_points INT := 5000; -- ← 修改:赠送积分数量 v_gift_days INT := 180; -- ← 修改:有效期(天) v_reason TEXT := '运营活动赠送'; -- ← 修改:赠送原因(写入流水描述) v_user_id UUID; v_batch_id BIGINT; v_balance_before INT; v_now TIMESTAMPTZ := NOW(); BEGIN -- 1. 查找用户 SELECT id INTO v_user_id FROM mjk_users WHERE mobile = v_mobile AND status = 'active' AND deleted_at IS NULL; IF v_user_id IS NULL THEN RAISE EXCEPTION '用户不存在或已注销:mobile = %', v_mobile; END IF; -- 2. 获取当前余额 SELECT balance INTO v_balance_before FROM mjk_user_points WHERE user_id = v_user_id; IF v_balance_before IS NULL THEN -- 如果没有积分记录,先初始化 INSERT INTO mjk_user_points ( user_id, balance, total_recharged, total_consumed, total_expired, created_at, updated_at ) VALUES ( v_user_id, 0, 0, 0, 0, v_now, v_now ); v_balance_before := 0; END IF; -- 3. 插入积分批次 INSERT INTO mjk_point_batches ( user_id, amount, remaining, expired_at, source, created_at, updated_at ) VALUES ( v_user_id, v_gift_points, v_gift_points, v_now + (v_gift_days || ' days')::INTERVAL, 'gift', v_now, v_now ) RETURNING id INTO v_batch_id; -- 4. 插入积分流水 INSERT INTO mjk_point_transactions ( user_id, type, amount, balance_before, balance_after, source_type, source_id, batch_id, duration, category, description, created_at, updated_at ) VALUES ( v_user_id, 'recharge', v_gift_points, v_balance_before, v_balance_before + v_gift_points, 'manual_gift', v_batch_id::TEXT, v_batch_id, NULL, '充值', v_reason, v_now, v_now ); -- 5. 更新用户积分汇总 UPDATE mjk_user_points SET balance = balance + v_gift_points, total_recharged = total_recharged + v_gift_points, updated_at = v_now WHERE user_id = v_user_id; RAISE NOTICE '已向用户 % 赠送 % 积分,当前余额 = %', v_mobile, v_gift_points, v_balance_before + v_gift_points; END $$; -- ----------------------------------------------------------- -- 三、积分补偿(给用户补偿积分,source = compensation) -- ----------------------------------------------------------- -- 用法:修改下方变量后执行 DO $$ DECLARE v_mobile TEXT := '13800138000'; -- ← 修改:目标用户手机号 v_comp_points INT := 200; -- ← 修改:补偿积分数量 v_comp_days INT := 365; -- ← 修改:有效期(天,建议给长一点) v_reason TEXT := '系统故障补偿'; -- ← 修改:补偿原因 v_user_id UUID; v_batch_id BIGINT; v_balance_before INT; v_now TIMESTAMPTZ := NOW(); BEGIN -- 1. 查找用户 SELECT id INTO v_user_id FROM mjk_users WHERE mobile = v_mobile AND status = 'active' AND deleted_at IS NULL; IF v_user_id IS NULL THEN RAISE EXCEPTION '用户不存在或已注销:mobile = %', v_mobile; END IF; -- 2. 获取当前余额 SELECT balance INTO v_balance_before FROM mjk_user_points WHERE user_id = v_user_id; IF v_balance_before IS NULL THEN INSERT INTO mjk_user_points ( user_id, balance, total_recharged, total_consumed, total_expired, created_at, updated_at ) VALUES ( v_user_id, 0, 0, 0, 0, v_now, v_now ); v_balance_before := 0; END IF; -- 3. 插入积分批次(source = compensation) INSERT INTO mjk_point_batches ( user_id, amount, remaining, expired_at, source, created_at, updated_at ) VALUES ( v_user_id, v_comp_points, v_comp_points, v_now + (v_comp_days || ' days')::INTERVAL, 'compensation', v_now, v_now ) RETURNING id INTO v_batch_id; -- 4. 插入积分流水 INSERT INTO mjk_point_transactions ( user_id, type, amount, balance_before, balance_after, source_type, source_id, batch_id, duration, category, description, created_at, updated_at ) VALUES ( v_user_id, 'recharge', v_comp_points, v_balance_before, v_balance_before + v_comp_points, 'manual_compensation', v_batch_id::TEXT, v_batch_id, NULL, '补偿', v_reason, v_now, v_now ); -- 5. 更新用户积分汇总 UPDATE mjk_user_points SET balance = balance + v_comp_points, total_recharged = total_recharged + v_comp_points, updated_at = v_now WHERE user_id = v_user_id; RAISE NOTICE '已向用户 % 补偿 % 积分,当前余额 = %', v_mobile, v_comp_points, v_balance_before + v_comp_points; END $$; -- ----------------------------------------------------------- -- 四、批量积分补偿(给多个用户同时补偿) -- ----------------------------------------------------------- -- 用法:将要补偿的手机号填入临时表,然后执行 -- 步骤 1:创建临时补偿名单(手机号 + 补偿数量 + 原因) -- DROP TABLE IF EXISTS _temp_compensation_list; CREATE TEMP TABLE IF NOT EXISTS _temp_compensation_list ( mobile TEXT PRIMARY KEY, comp_points INT NOT NULL, reason TEXT NOT NULL DEFAULT '批量补偿' ); -- 步骤 2:插入要补偿的用户(每次执行前清空并重新插入) TRUNCATE _temp_compensation_list; INSERT INTO _temp_compensation_list (mobile, comp_points, reason) VALUES ('13800138000', 100, '活动补偿'), ('13800138001', 200, '活动补偿'), ('13800138002', 100, '活动补偿'); -- 步骤 3:执行批量补偿 DO $$ DECLARE v_rec RECORD; v_user_id UUID; v_batch_id BIGINT; v_balance_before INT; v_now TIMESTAMPTZ := NOW(); v_comp_days INT := 365; v_success_cnt INT := 0; v_fail_cnt INT := 0; BEGIN FOR v_rec IN SELECT * FROM _temp_compensation_list LOOP BEGIN -- 查找用户 SELECT id INTO v_user_id FROM mjk_users WHERE mobile = v_rec.mobile AND status = 'active' AND deleted_at IS NULL; IF v_user_id IS NULL THEN RAISE WARNING '用户不存在:%', v_rec.mobile; v_fail_cnt := v_fail_cnt + 1; CONTINUE; END IF; -- 获取当前余额 SELECT balance INTO v_balance_before FROM mjk_user_points WHERE user_id = v_user_id; IF v_balance_before IS NULL THEN INSERT INTO mjk_user_points ( user_id, balance, total_recharged, total_consumed, total_expired, created_at, updated_at ) VALUES ( v_user_id, 0, 0, 0, 0, v_now, v_now ); v_balance_before := 0; END IF; -- 插入批次 INSERT INTO mjk_point_batches ( user_id, amount, remaining, expired_at, source, created_at, updated_at ) VALUES ( v_user_id, v_rec.comp_points, v_rec.comp_points, v_now + (v_comp_days || ' days')::INTERVAL, 'compensation', v_now, v_now ) RETURNING id INTO v_batch_id; -- 插入流水 INSERT INTO mjk_point_transactions ( user_id, type, amount, balance_before, balance_after, source_type, source_id, batch_id, duration, category, description, created_at, updated_at ) VALUES ( v_user_id, 'recharge', v_rec.comp_points, v_balance_before, v_balance_before + v_rec.comp_points, 'batch_compensation', v_batch_id::TEXT, v_batch_id, NULL, '补偿', v_rec.reason, v_now, v_now ); -- 更新汇总 UPDATE mjk_user_points SET balance = balance + v_rec.comp_points, total_recharged = total_recharged + v_rec.comp_points, updated_at = v_now WHERE user_id = v_user_id; v_success_cnt := v_success_cnt + 1; EXCEPTION WHEN OTHERS THEN RAISE WARNING '补偿失败 %: %', v_rec.mobile, SQLERRM; v_fail_cnt := v_fail_cnt + 1; END; END LOOP; RAISE NOTICE '批量补偿完成:成功 % 人,失败 % 人', v_success_cnt, v_fail_cnt; END $$; -- 清理临时表 -- DROP TABLE IF EXISTS _temp_compensation_list;