-- ==================================================================== -- 角色字段统一升级脚本 - Role Field Unification Upgrade -- ==================================================================== -- 目的:将所有表的 user_type (INTEGER) 字段统一为 role (TEXT) 字段 -- 兼容性:Supabase + PostgreSQL 14+ -- 执行顺序:在现有数据库基础上执行 -- ==================================================================== BEGIN; -- ==================================================================== -- 1. 统一 ml_user_profiles 表的角色字段 -- ==================================================================== -- 1.1 添加新的 role 字段 ALTER TABLE public.ml_user_profiles ADD COLUMN IF NOT EXISTS role TEXT DEFAULT 'customer'; -- 1.2 将现有 user_type 数据迁移到 role 字段 UPDATE public.ml_user_profiles SET role = CASE WHEN user_type = 1 THEN 'customer' -- 消费者 WHEN user_type = 2 THEN 'merchant' -- 商家 WHEN user_type = 3 THEN 'delivery' -- 配送员 WHEN user_type = 4 THEN 'service' -- 客服 WHEN user_type = 5 THEN 'admin' -- 管理员 ELSE 'customer' END WHERE role IS NULL OR role = 'customer'; -- 1.3 设置 role 字段约束 ALTER TABLE public.ml_user_profiles ALTER COLUMN role SET NOT NULL; ALTER TABLE public.ml_user_profiles ADD CONSTRAINT IF NOT EXISTS chk_ml_user_role CHECK (role IN ('customer', 'merchant', 'delivery', 'service', 'admin')); -- 1.4 更新索引 DROP INDEX IF EXISTS idx_ml_user_profiles_type; CREATE INDEX IF NOT EXISTS idx_ml_user_profiles_role ON public.ml_user_profiles(role); -- 1.5 删除旧的 user_type 字段和约束(可选,建议在测试确认后执行) -- ALTER TABLE public.ml_user_profiles DROP CONSTRAINT IF EXISTS chk_ml_user_type; -- ALTER TABLE public.ml_user_profiles DROP COLUMN IF EXISTS user_type; -- ==================================================================== -- 2. 更新相关函数中的字段引用 -- ==================================================================== -- 2.1 更新商家验证函数 CREATE OR REPLACE FUNCTION public.is_verified_merchant(user_uuid UUID) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE result BOOLEAN := FALSE; BEGIN SELECT (role = 'merchant' AND verification_status = 1) INTO result FROM public.ml_user_profiles WHERE user_id = user_uuid; RETURN COALESCE(result, FALSE); END; $$; -- 2.2 更新用户信息视图 CREATE OR REPLACE VIEW public.vw_user_info AS SELECT u.id as user_id, u.email, u.username, u.role as user_role, u.status as user_status, u.created_at as user_created_at, p.cid as profile_cid, p.role as profile_role, p.status as profile_status, p.real_name, p.avatar_url, p.phone, p.credit_score, p.verification_status, p.created_at as profile_created_at, CASE WHEN p.role = 'customer' THEN '消费者' WHEN p.role = 'merchant' THEN '商家' WHEN p.role = 'delivery' THEN '配送员' WHEN p.role = 'service' THEN '客服' WHEN p.role = 'admin' THEN '管理员' ELSE '未知' END as role_name FROM public.ak_users u LEFT JOIN public.ml_user_profiles p ON u.id = p.user_id; -- ==================================================================== -- 3. 更新 RLS 策略中的角色检查 -- ==================================================================== -- 3.1 更新商品相关策略 DROP POLICY IF EXISTS "商家管理自己的商品" ON public.ml_products; CREATE POLICY "商家管理自己的商品" ON public.ml_products FOR ALL TO authenticated USING ( merchant_id = auth.uid() OR EXISTS ( SELECT 1 FROM public.ml_user_profiles p WHERE p.user_id = auth.uid() AND p.role IN ('admin', 'service') ) ); -- 3.2 更新订单相关策略 DROP POLICY IF EXISTS "配送员查看分配的订单" ON public.ml_orders; CREATE POLICY "配送员查看分配的订单" ON public.ml_orders FOR SELECT TO authenticated USING ( delivery_id = auth.uid() OR EXISTS ( SELECT 1 FROM public.ml_user_profiles p WHERE p.user_id = auth.uid() AND p.role IN ('admin', 'service') ) ); -- 3.3 更新用户资料策略 DROP POLICY IF EXISTS "用户管理自己的资料" ON public.ml_user_profiles; CREATE POLICY "用户管理自己的资料" ON public.ml_user_profiles FOR ALL TO authenticated USING ( user_id = auth.uid() OR EXISTS ( SELECT 1 FROM public.ml_user_profiles p WHERE p.user_id = auth.uid() AND p.role IN ('admin', 'service') ) ); -- ==================================================================== -- 4. 更新字段注释 -- ==================================================================== COMMENT ON COLUMN public.ml_user_profiles.role IS '用户角色:customer消费者, merchant商家, delivery配送员, service客服, admin管理员'; -- ==================================================================== -- 5. 创建角色辅助函数 -- ==================================================================== -- 5.1 获取用户角色函数 CREATE OR REPLACE FUNCTION public.get_user_role(user_uuid UUID) RETURNS TEXT LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE user_role TEXT; BEGIN SELECT role INTO user_role FROM public.ml_user_profiles WHERE user_id = user_uuid; RETURN COALESCE(user_role, 'customer'); END; $$; -- 5.2 检查用户权限函数 CREATE OR REPLACE FUNCTION public.check_user_permission(user_uuid UUID, required_roles TEXT[]) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE user_role TEXT; BEGIN SELECT role INTO user_role FROM public.ml_user_profiles WHERE user_id = user_uuid; RETURN user_role = ANY(required_roles); END; $$; -- 5.3 角色升级函数(将用户提升为商家等) CREATE OR REPLACE FUNCTION public.upgrade_user_role(user_uuid UUID, new_role TEXT) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN -- 检查新角色是否有效 IF new_role NOT IN ('customer', 'merchant', 'delivery', 'service', 'admin') THEN RAISE EXCEPTION '无效的角色类型: %', new_role; END IF; -- 更新用户角色 UPDATE public.ml_user_profiles SET role = new_role, updated_at = CURRENT_TIMESTAMP WHERE user_id = user_uuid; -- 同步更新 ak_users 表的 role 字段 UPDATE public.ak_users SET role = new_role, updated_at = CURRENT_TIMESTAMP WHERE id = user_uuid; RETURN FOUND; END; $$; -- ==================================================================== -- 6. 数据一致性检查 -- ==================================================================== -- 6.1 检查角色字段一致性 DO $$ DECLARE inconsistent_count INTEGER; BEGIN SELECT COUNT(*) INTO inconsistent_count FROM public.ak_users u JOIN public.ml_user_profiles p ON u.id = p.user_id WHERE u.role != p.role; IF inconsistent_count > 0 THEN RAISE NOTICE '发现 % 条记录的角色字段不一致,正在同步...', inconsistent_count; -- 以 ml_user_profiles.role 为准同步到 ak_users.role UPDATE public.ak_users SET role = p.role, updated_at = CURRENT_TIMESTAMP FROM public.ml_user_profiles p WHERE ak_users.id = p.user_id AND ak_users.role != p.role; RAISE NOTICE '角色字段同步完成'; ELSE RAISE NOTICE '角色字段一致性检查通过'; END IF; END; $$; -- ==================================================================== -- 7. 创建角色统计视图 -- ==================================================================== CREATE OR REPLACE VIEW public.vw_role_statistics AS SELECT role, COUNT(*) as user_count, COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() as percentage FROM public.ml_user_profiles GROUP BY role ORDER BY user_count DESC; COMMIT; -- ==================================================================== -- 执行验证 -- ==================================================================== -- 检查角色分布 SELECT '角色分布统计:' as info; SELECT * FROM public.vw_role_statistics; -- 检查索引 SELECT '索引检查:' as info; SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'ml_user_profiles' AND indexname LIKE '%role%'; -- 检查约束 SELECT '约束检查:' as info; SELECT conname, pg_get_constraintdef(oid) as definition FROM pg_constraint WHERE conrelid = 'public.ml_user_profiles'::regclass AND conname LIKE '%role%'; SELECT '角色字段统一升级完成!' as result;