-- ===================================================================================== -- Migration: 全量软删除 (Soft Delete) 基础设施补齐 -- 位置:docs/sql/10_schema/99_soft_delete_migration_v1.sql -- 对象类型:ALTER TABLE -- 说明:为所有核心业务表补齐 deleted_at, deleted_by, restored_at, restored_by 字段 -- 涵盖:权限、配置、内容、装修、物流、分销、财务、客服、营销、商品、用户、订单 -- ===================================================================================== DO $$ DECLARE -- 需补齐软删除字段的业务表全量清单 t_names TEXT[] := ARRAY[ -- 1. 系统与权限 (Auth/System) 'ak_roles', 'ak_permissions', 'ak_admin_roles', 'ak_role_permissions', 'ml_system_configs', -- 2. 内容与装修 (CMS/Decoration) 'ml_articles', 'ml_article_categories', 'ak_diy_pages', -- 3. 物流资源 (Delivery) 'ml_delivery_staff', 'ml_delivery_stations', 'ak_shipping_templates', -- 4. 分销体系 (Distribution) 'ak_distribution_agents', 'ak_distribution_divisions', 'ak_distribution_agent_applications', 'ak_distribution_division_applications', 'ak_promoter_relations', 'ak_commission_logs', 'ak_distribution_level', 'ak_distribution_config', -- 5. 财务管理 (Finance) 'ml_extract', 'ml_invoices', 'ml_user_bill', 'ml_user_recharge', -- 6. 客服系统 (Kefu) 'ml_kefu_accounts', 'ml_kefu_words', 'ml_kefu_word_categories', 'ml_kefu_auto_replies', 'ml_kefu_feedbacks', -- 7. 营销活动 (Marketing) 'ak_advanced_marketing', 'ak_bargain_groupbuy', 'ak_live_products', 'ak_lottery_live', 'ak_marketing_checkin_configs', 'ak_marketing_newcomer_config', 'ak_marketing_signin_logs', 'ak_member_management', 'ak_recharge_management', 'ak_signin_configs', -- 8. 商品中心 (Product) 'ml_products', 'ml_product_skus', 'ml_categories', 'ak_product_labels', 'ak_product_member_prices', 'ak_product_protections', 'ak_product_templates', -- 9. 用户管理 (User) 'ak_user_labels', 'ak_user_groups', 'ak_user_levels', 'ak_users', -- 10. 订单中心 (Order) 'ml_orders' ]; t_name TEXT; BEGIN FOREACH t_name IN ARRAY t_names LOOP -- 检查表是否存在 IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = t_name) THEN -- 1. 增加 deleted_at 字段 IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = t_name AND column_name = 'deleted_at') THEN EXECUTE format('ALTER TABLE public.%I ADD COLUMN deleted_at TIMESTAMPTZ DEFAULT NULL', t_name); END IF; -- 2. 增加 deleted_by 字段 IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = t_name AND column_name = 'deleted_by') THEN EXECUTE format('ALTER TABLE public.%I ADD COLUMN deleted_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL', t_name); END IF; -- 3. 增加 restored_at 字段 IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = t_name AND column_name = 'restored_at') THEN EXECUTE format('ALTER TABLE public.%I ADD COLUMN restored_at TIMESTAMPTZ DEFAULT NULL', t_name); END IF; -- 4. 增加 restored_by 字段 IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = t_name AND column_name = 'restored_by') THEN EXECUTE format('ALTER TABLE public.%I ADD COLUMN restored_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL', t_name); END IF; -- 5. 建立软删除索引 EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON public.%I (deleted_at) WHERE deleted_at IS NULL', 'idx_' || t_name || '_soft_delete', t_name); END IF; END LOOP; END $$; -- ===================================================================================== -- Schema: 系统配置表 -- 位置:docs/sql/10_schema/admin/ml_system_configs_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 说明:统一存储系统、应用、维护等模块的 Key-Value 配置项 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ml_system_configs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), config_key TEXT UNIQUE NOT NULL, config_value JSONB NOT NULL DEFAULT '{}'::jsonb, description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS idx_system_configs_key ON public.ml_system_configs (config_key); -- 注释 COMMENT ON TABLE public.ml_system_configs IS '系统全局配置表'; COMMENT ON COLUMN public.ml_system_configs.config_key IS '配置唯一标识键'; COMMENT ON COLUMN public.ml_system_configs.config_value IS '配置内容 (JSONB)'; -- ===================================================================================== -- Migration: Auth 安全约束增强 -- 位置:docs/sql/10_schema/auth/ak_auth_security_constraints_v1.sql -- 对象类型:ALTER TABLE / CONSTRAINT -- 说明:增强 ak_users 与 auth.users 的关联安全性,防止孤儿数据 -- ===================================================================================== -- 1. 确保 ak_users.auth_id 存在外键约束指向 auth.users -- 注意:Supabase 的 auth.users 表在 auth schema 下,需要确保权限正确 DO $$ BEGIN -- 检查是否已存在外键约束 IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'fk_ak_users_auth_id' AND table_name = 'ak_users' ) THEN -- 添加外键约束,当 auth.users 被删除时自动删除对应的 profile ALTER TABLE public.ak_users ADD CONSTRAINT fk_ak_users_auth_id FOREIGN KEY (auth_id) REFERENCES auth.users(id) ON DELETE CASCADE; END IF; END $$; -- 2. 为 auth_id 建立唯一索引,确保一个 auth 用户只有一个 profile CREATE UNIQUE INDEX IF NOT EXISTS idx_ak_users_auth_id_unique ON public.ak_users(auth_id); -- 3. 为 role 字段建立索引,加速权限查询 CREATE INDEX IF NOT EXISTS idx_ak_users_role ON public.ak_users(role); -- 4. 添加检查约束,确保 role 字段只能是有效值 ALTER TABLE public.ak_users DROP CONSTRAINT IF EXISTS chk_ak_users_role_valid; ALTER TABLE public.ak_users ADD CONSTRAINT chk_ak_users_role_valid CHECK (role IN ('user', 'admin', 'staff', 'agent', 'kefu') OR role IS NULL); -- 5. 为 ak_admin_roles 添加约束确保关联有效性 DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'fk_ak_admin_roles_admin_id' AND table_name = 'ak_admin_roles' ) THEN ALTER TABLE public.ak_admin_roles ADD CONSTRAINT fk_ak_admin_roles_admin_id FOREIGN KEY (admin_id) REFERENCES public.ak_users(id) ON DELETE CASCADE; END IF; END $$; -- 6. 为 ak_role_permissions 添加约束确保关联有效性 DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'fk_ak_role_permissions_role_id' AND table_name = 'ak_role_permissions' ) THEN ALTER TABLE public.ak_role_permissions ADD CONSTRAINT fk_ak_role_permissions_role_id FOREIGN KEY (role_id) REFERENCES public.ak_roles(id) ON DELETE CASCADE; END IF; END $$; DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'fk_ak_role_permissions_permission_id' AND table_name = 'ak_role_permissions' ) THEN ALTER TABLE public.ak_role_permissions ADD CONSTRAINT fk_ak_role_permissions_permission_id FOREIGN KEY (permission_id) REFERENCES public.ak_permissions(id) ON DELETE CASCADE; END IF; END $$;-- ===================================================================================== -- Schema: 内容管理模块核心表 -- 位置:docs/sql/10_schema/cms/ml_cms_tables_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:包含文章分类及文章主表定义 -- ===================================================================================== -- 1. 文章分类表 CREATE TABLE IF NOT EXISTS public.ml_article_categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, icon TEXT NULL, sort INTEGER NOT NULL DEFAULT 0, status SMALLINT NOT NULL DEFAULT 1, -- 1: 启用, 0: 禁用 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 唯一性约束 CREATE UNIQUE INDEX IF NOT EXISTS ml_article_categories_name_uniq ON public.ml_article_categories (name); -- 2. 文章主表 CREATE TABLE IF NOT EXISTS public.ml_articles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), category_id UUID NOT NULL REFERENCES public.ml_article_categories(id), title TEXT NOT NULL, author TEXT NULL, image TEXT NULL, -- 文章封面图 description TEXT NULL, -- 文章简介 content TEXT NOT NULL, -- 文章内容 (富文本) status SMALLINT NOT NULL DEFAULT 0, -- 0: 未发布, 1: 已发布 views INTEGER NOT NULL DEFAULT 0, -- 浏览量 is_banner BOOLEAN NOT NULL DEFAULT FALSE, -- 是否展示在 banner is_hot BOOLEAN NOT NULL DEFAULT FALSE, -- 是否热门 linked_product_id UUID NULL, -- 关联商品ID (可选) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 常用查询索引 CREATE INDEX IF NOT EXISTS ml_articles_category_id_idx ON public.ml_articles (category_id); CREATE INDEX IF NOT EXISTS ml_articles_status_idx ON public.ml_articles (status); CREATE INDEX IF NOT EXISTS ml_articles_created_at_idx ON public.ml_articles (created_at DESC); -- ===================================================================================== -- Schema: 装修模块 - DIY 页面配置表 -- 位置:docs/sql/10_schema/decoration/ak_diy_pages_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 说明:存储首页、专题页及个人中心的 DIY 布局 JSON 配置 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_diy_pages ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, type TEXT NOT NULL, -- home: 首页, topic: 专题页, user: 个人中心 config JSONB NOT NULL DEFAULT '{}'::jsonb, -- 核心布局配置 (组件列表及参数) is_home BOOLEAN NOT NULL DEFAULT FALSE, -- 是否为生效首页 is_active BOOLEAN NOT NULL DEFAULT TRUE, -- 是否启用 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_by UUID REFERENCES public.ak_users(id), updated_by UUID REFERENCES public.ak_users(id) ); -- 索引 CREATE INDEX IF NOT EXISTS idx_diy_pages_type ON public.ak_diy_pages (type); CREATE INDEX IF NOT EXISTS idx_diy_pages_is_home ON public.ak_diy_pages (is_home) WHERE is_home = TRUE; -- 注释 COMMENT ON TABLE public.ak_diy_pages IS 'DIY 页面装修配置表'; COMMENT ON COLUMN public.ak_diy_pages.type IS '页面类型: home(首页), topic(专题), user(个人中心)'; COMMENT ON COLUMN public.ak_diy_pages.config IS 'DIY 布局配置 JSON'; -- ===================================================================================== -- Schema: 物流设置 (Delivery) 核心表 -- 位置:docs/sql/10_schema/delivery/ak_delivery_system_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 说明:包含配送员管理表、提货点/核销点管理表 -- ===================================================================================== -- 1. 配送员管理表 CREATE TABLE IF NOT EXISTS public.ml_delivery_staff ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID REFERENCES public.ak_users(id) ON DELETE SET NULL, -- 关联用户(可选) nickname TEXT NOT NULL, -- 配送员名称 avatar TEXT, -- 头像 phone TEXT NOT NULL, -- 手机号 status SMALLINT NOT NULL DEFAULT 1, -- 状态: 1-启用, 0-禁用 is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 2. 提货点/核销点管理表 CREATE TABLE IF NOT EXISTS public.ml_delivery_stations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, -- 提货点名称 phone TEXT NOT NULL, -- 联系电话 address TEXT NOT NULL, -- 详细地址 image TEXT, -- 门店图片 lng NUMERIC(10,7), -- 经度 lat NUMERIC(10,7), -- 纬度 status SMALLINT NOT NULL DEFAULT 1, -- 状态: 1-显示, 0-隐藏 sort_order INTEGER DEFAULT 0, business_hours JSONB, -- 营业时间 (如: {"start": "09:00", "end": "21:00"}) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS idx_delivery_staff_phone ON public.ml_delivery_staff(phone); CREATE INDEX IF NOT EXISTS idx_delivery_stations_status ON public.ml_delivery_stations(status); -- 注释 COMMENT ON TABLE public.ml_delivery_staff IS '配送员信息表'; COMMENT ON TABLE public.ml_delivery_stations IS '提货点/核销点信息表'; -- ===================================================================================== -- Schema: 医养执行端 Delivery 基础表升级 -- 位置:docs/sql/10_schema/delivery/ak_delivery_system_v2.sql -- 对象类型:ALTER TABLE / INDEX / TRIGGER -- 版本:v2 -- 说明:在 v1 基础上最小升级为“医养上门服务执行端”可用模型。 -- 补齐 uid 唯一索引、软删除、机构关联、staff_no、在线状态、资质状态。 -- ===================================================================================== -- 0. 通用 updated_at 触发器 CREATE OR REPLACE FUNCTION public.tg_set_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- 1. 配送/执行人员表升级 ALTER TABLE public.ml_delivery_staff ADD COLUMN IF NOT EXISTS station_id UUID REFERENCES public.ml_delivery_stations(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS staff_no TEXT, ADD COLUMN IF NOT EXISTS online_status TEXT NOT NULL DEFAULT 'resting', ADD COLUMN IF NOT EXISTS certificate_status TEXT NOT NULL DEFAULT 'pending', ADD COLUMN IF NOT EXISTS certificate_expire_at DATE, ADD COLUMN IF NOT EXISTS service_area TEXT NOT NULL DEFAULT '', ADD COLUMN IF NOT EXISTS skills JSONB NOT NULL DEFAULT '[]'::jsonb, ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ, ADD COLUMN IF NOT EXISTS deleted_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL; ALTER TABLE public.ml_delivery_staff DROP CONSTRAINT IF EXISTS chk_ml_delivery_staff_online_status; ALTER TABLE public.ml_delivery_staff ADD CONSTRAINT chk_ml_delivery_staff_online_status CHECK (online_status IN ('online', 'resting', 'busy')); ALTER TABLE public.ml_delivery_staff DROP CONSTRAINT IF EXISTS chk_ml_delivery_staff_certificate_status; ALTER TABLE public.ml_delivery_staff ADD CONSTRAINT chk_ml_delivery_staff_certificate_status CHECK (certificate_status IN ('valid', 'expired', 'pending')); -- 2. 站点/机构表升级 ALTER TABLE public.ml_delivery_stations ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ, ADD COLUMN IF NOT EXISTS deleted_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL; -- 3. 索引 CREATE UNIQUE INDEX IF NOT EXISTS uq_ml_delivery_staff_uid_active ON public.ml_delivery_staff(uid) WHERE uid IS NOT NULL AND deleted_at IS NULL; CREATE UNIQUE INDEX IF NOT EXISTS uq_ml_delivery_staff_staff_no_active ON public.ml_delivery_staff(staff_no) WHERE staff_no IS NOT NULL AND deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_station_id ON public.ml_delivery_staff(station_id) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_deleted_at ON public.ml_delivery_staff(deleted_at); CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_status_active ON public.ml_delivery_staff(status, is_active) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_stations_deleted_at ON public.ml_delivery_stations(deleted_at); CREATE INDEX IF NOT EXISTS idx_ml_delivery_stations_status_active ON public.ml_delivery_stations(status) WHERE deleted_at IS NULL; -- 4. 自动维护 updated_at DROP TRIGGER IF EXISTS trg_ml_delivery_staff_set_updated_at ON public.ml_delivery_staff; CREATE TRIGGER trg_ml_delivery_staff_set_updated_at BEFORE UPDATE ON public.ml_delivery_staff FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); DROP TRIGGER IF EXISTS trg_ml_delivery_stations_set_updated_at ON public.ml_delivery_stations; CREATE TRIGGER trg_ml_delivery_stations_set_updated_at BEFORE UPDATE ON public.ml_delivery_stations FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); -- 5. 注释 COMMENT ON COLUMN public.ml_delivery_staff.station_id IS '所属机构/服务站点 ID'; COMMENT ON COLUMN public.ml_delivery_staff.staff_no IS '服务人员编号'; COMMENT ON COLUMN public.ml_delivery_staff.online_status IS '在线状态:online/resting/busy'; COMMENT ON COLUMN public.ml_delivery_staff.certificate_status IS '资质状态:valid/expired/pending'; COMMENT ON COLUMN public.ml_delivery_staff.certificate_expire_at IS '主要资质到期日期'; COMMENT ON COLUMN public.ml_delivery_staff.service_area IS '服务区域描述'; COMMENT ON COLUMN public.ml_delivery_staff.skills IS '技能标签 JSON 数组'; COMMENT ON COLUMN public.ml_delivery_staff.deleted_at IS '软删除时间'; COMMENT ON COLUMN public.ml_delivery_staff.deleted_by IS '软删除操作人'; COMMENT ON COLUMN public.ml_delivery_stations.deleted_at IS '软删除时间'; COMMENT ON COLUMN public.ml_delivery_stations.deleted_by IS '软删除操作人'; -- 佣金流水表:记录每一笔佣金变动(冻结/可用/已提现/取消) CREATE TABLE IF NOT EXISTS public.ak_commission_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- 佣金获得者 uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, -- 佣金来源用户(下单用户/被推广用户,可为空) source_uid UUID REFERENCES public.ak_users(id) ON DELETE SET NULL, -- 关联订单 order_id UUID REFERENCES public.ml_orders(id) ON DELETE SET NULL, order_no VARCHAR(50), -- 金额与状态 amount DECIMAL(12,2) NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'frozen', -- frozen/available/withdrawn/canceled -- 冻结到期时间(用于解冻逻辑) frozen_until TIMESTAMPTZ, remark TEXT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), CONSTRAINT chk_ak_commission_amount_nonneg CHECK (amount >= 0), CONSTRAINT chk_ak_commission_status CHECK (status IN ('frozen','available','withdrawn','canceled')) ); CREATE INDEX IF NOT EXISTS idx_ak_commission_logs_uid ON public.ak_commission_logs(uid); CREATE INDEX IF NOT EXISTS idx_ak_commission_logs_order_id ON public.ak_commission_logs(order_id); CREATE INDEX IF NOT EXISTS idx_ak_commission_logs_status ON public.ak_commission_logs(status); CREATE INDEX IF NOT EXISTS idx_ak_commission_logs_created_at ON public.ak_commission_logs(created_at); -- 启用 RLS ALTER TABLE public.ak_commission_logs ENABLE ROW LEVEL SECURITY; -- Admin 可读写 CREATE POLICY "Admins can manage commission logs" ON public.ak_commission_logs FOR ALL TO authenticated USING ( EXISTS ( SELECT 1 FROM public.ak_users WHERE id = auth.uid() AND role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users WHERE id = auth.uid() AND role = 'admin' ) ); -- 用户仅可查看自己的佣金流水 CREATE POLICY "Users can view own commission logs" ON public.ak_commission_logs FOR SELECT TO authenticated USING (uid = auth.uid()); -- ===================================================================================== -- Schema: 分销代理商申请表 -- 位置:docs/sql/10_schema/distribution/ak_distribution_agent_applications_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 依赖:ak_users, ak_distribution_divisions -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_distribution_agent_applications ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, division_uid UUID NOT NULL REFERENCES public.ak_distribution_divisions(uid), agent_name TEXT NOT NULL, agent_phone TEXT NULL, proof_images JSONB NULL, -- 申请凭证图片列表 status TEXT NOT NULL DEFAULT 'pending', -- pending/approved/rejected refusal_reason TEXT NULL, approved_at TIMESTAMPTZ NULL, approved_by UUID NULL REFERENCES public.ak_users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_dist_agent_applications_uid ON public.ak_distribution_agent_applications(uid); CREATE INDEX IF NOT EXISTS idx_dist_agent_applications_division_uid ON public.ak_distribution_agent_applications(division_uid); CREATE INDEX IF NOT EXISTS idx_dist_agent_applications_status ON public.ak_distribution_agent_applications(status); COMMENT ON TABLE public.ak_distribution_agent_applications IS '分销代理商申请记录表'; COMMENT ON COLUMN public.ak_distribution_agent_applications.proof_images IS '申请图片列表(JSON)'; -- ===================================================================================== -- Schema: 分销代理商管理表 -- 位置:docs/sql/10_schema/distribution/ak_distribution_agents_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 依赖:ak_users, ak_distribution_divisions -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_distribution_agents ( uid UUID PRIMARY KEY REFERENCES public.ak_users(id) ON DELETE CASCADE, division_uid UUID NOT NULL REFERENCES public.ak_distribution_divisions(uid), -- 所属事业部 name TEXT NOT NULL, commission_ratio NUMERIC(5,2) DEFAULT 0 CHECK (commission_ratio >= 0 AND commission_ratio <= 100), is_enabled BOOLEAN DEFAULT TRUE, end_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), created_by UUID REFERENCES public.ak_users(id), updated_by UUID REFERENCES public.ak_users(id) ); -- 索引 CREATE INDEX IF NOT EXISTS idx_distribution_agents_division_uid ON public.ak_distribution_agents(division_uid); -- 注释 COMMENT ON TABLE public.ak_distribution_agents IS '分销代理商信息表'; COMMENT ON COLUMN public.ak_distribution_agents.uid IS '用户ID(关联代理商本人)'; COMMENT ON COLUMN public.ak_distribution_agents.division_uid IS '所属事业部UID'; COMMENT ON COLUMN public.ak_distribution_agents.commission_ratio IS '代理商固定分佣比例(%)'; -- 1. 创建分销配置表 CREATE TABLE IF NOT EXISTS public.ak_distribution_config ( id TEXT PRIMARY KEY DEFAULT 'global_config', is_enabled BOOLEAN DEFAULT true, -- 分销启用 extract_type TEXT DEFAULT '2', -- 分销模式: 1指定, 2人人, 3满额 bind_type TEXT DEFAULT '2', -- 绑定关系: 1所有用户, 2新用户 store_brokerage_binding_status TEXT DEFAULT '1', -- 绑定模式: 1永久, 2有效期, 3临时 brokerage_poster_status TEXT, -- 分销海报图路径/URL brokerage_level INTEGER DEFAULT 2, -- 分销层级: 1, 2 is_area_manager BOOLEAN DEFAULT true, -- 事业部开关 is_agent_apply BOOLEAN DEFAULT true, -- 代理商申请开关 is_commission_window BOOLEAN DEFAULT true, -- 佣金悬浮窗开关 -- 返佣设置 is_self_brokerage BOOLEAN DEFAULT true, -- 自购返佣 is_member_brokerage BOOLEAN DEFAULT false, -- 购买会员返佣 brokerage_type TEXT DEFAULT '1', -- 返佣类型: 1价格, 2实付 is_promoter_brokerage BOOLEAN DEFAULT true, -- 推广用户返佣 promoter_brokerage_price DECIMAL(10,2) DEFAULT 2.00, promoter_brokerage_day_max DECIMAL(10,2) DEFAULT -1.00, store_brokerage_ratio DECIMAL(10,2) DEFAULT 20.00, store_brokerage_two_ratio DECIMAL(10,2) DEFAULT 2.00, extract_frozen_time INTEGER DEFAULT 1, -- 提现设置 user_extract_min_price DECIMAL(10,2) DEFAULT 1.00, extract_bank_list TEXT DEFAULT '中国银行', extract_type_list TEXT[] DEFAULT ARRAY['bank', 'wechat', 'alipay'], wechat_extract_type TEXT DEFAULT '1', alipay_extract_type TEXT DEFAULT '1', user_extract_fee DECIMAL(10,2) DEFAULT 0.00, updated_at TIMESTAMPTZ DEFAULT now(), updated_by UUID REFERENCES auth.users(id) ); -- 2. 启用 RLS ALTER TABLE public.ak_distribution_config ENABLE ROW LEVEL SECURITY; -- 3. 创建权限策略 (基于公共角色函数或直接查询 ak_users) -- 允许 Admin 查看配置 CREATE POLICY "Admins can view distribution config" ON public.ak_distribution_config FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM public.ak_users WHERE auth_id = auth.uid() AND role = 'admin' ) ); -- 允许 Admin 修改配置 CREATE POLICY "Admins can update distribution config" ON public.ak_distribution_config FOR ALL TO authenticated USING ( EXISTS ( SELECT 1 FROM public.ak_users WHERE auth_id = auth.uid() AND role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users WHERE auth_id = auth.uid() AND role = 'admin' ) ); -- 4. 插入初始化数据 INSERT INTO public.ak_distribution_config (id) VALUES ('global_config') ON CONFLICT (id) DO NOTHING; -- ===================================================================================== -- Schema: 分销事业部申请表 -- 位置:docs/sql/10_schema/distribution/ak_distribution_division_applications_v1.sql -- 说明:记录用户申请加入事业部成为代理商的流水,支持审核流转,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_distribution_division_applications ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, division_id UUID NOT NULL REFERENCES public.ak_distribution_divisions(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 申请人填写的代理商名称 phone TEXT NOT NULL, -- 申请人联系电话 images JSONB DEFAULT '[]'::jsonb, -- 申请附件图片 (数组) status INTEGER DEFAULT 1, -- 状态: 1待审核, 2已同意, 3已拒绝 admin_remark TEXT, -- 审核备注 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 启用 RLS ALTER TABLE public.ak_distribution_division_applications ENABLE ROW LEVEL SECURITY; -- 权限策略 CREATE POLICY "Merchants manage their own applications" ON public.ak_distribution_division_applications FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许用户提交和查看自己的申请 CREATE POLICY "Users handle own applications" ON public.ak_distribution_division_applications FOR ALL TO authenticated USING (uid = auth.uid()) WITH CHECK (uid = auth.uid()); -- 索引 CREATE INDEX IF NOT EXISTS idx_div_app_merchant ON public.ak_distribution_division_applications(merchant_id); CREATE INDEX IF NOT EXISTS idx_div_app_uid ON public.ak_distribution_division_applications(uid); CREATE INDEX IF NOT EXISTS idx_div_app_status ON public.ak_distribution_division_applications(status); -- ===================================================================================== -- Schema: 分销事业部管理表 -- 位置:docs/sql/10_schema/distribution/ak_distribution_divisions_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 依赖:ak_users -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_distribution_divisions ( uid UUID PRIMARY KEY REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, invite_code TEXT UNIQUE NOT NULL, commission_ratio NUMERIC(5,2) DEFAULT 0 CHECK (commission_ratio >= 0 AND commission_ratio <= 100), is_enabled BOOLEAN DEFAULT TRUE, end_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), created_by UUID REFERENCES public.ak_users(id), updated_by UUID REFERENCES public.ak_users(id) ); -- 索引 CREATE INDEX IF NOT EXISTS idx_distribution_divisions_invite_code ON public.ak_distribution_divisions(invite_code); -- 注释 COMMENT ON TABLE public.ak_distribution_divisions IS '分销事业部信息表'; COMMENT ON COLUMN public.ak_distribution_divisions.uid IS '用户ID(关联事业部负责人)'; COMMENT ON COLUMN public.ak_distribution_divisions.invite_code IS '事业部专属邀请码'; COMMENT ON COLUMN public.ak_distribution_divisions.commission_ratio IS '事业部固定分佣比例(%)'; COMMENT ON COLUMN public.ak_distribution_divisions.end_time IS '事业部有效截止时间'; -- 1. 创建分销等级表 CREATE TABLE IF NOT EXISTS public.ak_distribution_level ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, -- 等级名称 level INTEGER NOT NULL UNIQUE, -- 等级权重/数字(如1, 2, 3) percent1 DECIMAL(10,2) DEFAULT 0, -- 一级分佣比例 (%) percent2 DECIMAL(10,2) DEFAULT 0, -- 二级分佣比例 (%) task_total INTEGER DEFAULT 0, -- 任务总数 task_finish INTEGER DEFAULT 0, -- 需完成数量(升级门槛) is_visible BOOLEAN DEFAULT true, -- 是否显示 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 启用 RLS ALTER TABLE public.ak_distribution_level ENABLE ROW LEVEL SECURITY; -- 3. 创建权限策略 -- 允许所有认证用户查看等级(用于前端展示) CREATE POLICY "Anyone can view levels" ON public.ak_distribution_level FOR SELECT TO authenticated USING (true); -- 仅允许 Admin 进行管理 (INSERT/UPDATE/DELETE) CREATE POLICY "Admins can manage levels" ON public.ak_distribution_level FOR ALL TO authenticated USING ( EXISTS ( SELECT 1 FROM public.ak_users WHERE auth_id = auth.uid() AND role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users WHERE auth_id = auth.uid() AND role = 'admin' ) ); -- 4. 插入初始化示例数据 INSERT INTO public.ak_distribution_level (name, level, percent1, percent2, is_visible) VALUES ('普通分销员', 1, 10.00, 5.00, true) ON CONFLICT (level) DO NOTHING; -- 推广员关系表:记录下级与上级(邀请人)的绑定关系 CREATE TABLE IF NOT EXISTS public.ak_promoter_relations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, inviter_uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, bind_time TIMESTAMPTZ DEFAULT now(), created_at TIMESTAMPTZ DEFAULT now(), CONSTRAINT chk_ak_promoter_relations_no_self CHECK (uid <> inviter_uid), CONSTRAINT uq_ak_promoter_relations_uid UNIQUE (uid) ); CREATE INDEX IF NOT EXISTS idx_ak_promoter_relations_inviter_uid ON public.ak_promoter_relations(inviter_uid); -- 启用 RLS ALTER TABLE public.ak_promoter_relations ENABLE ROW LEVEL SECURITY; -- Admin 可读写 CREATE POLICY "Admins can manage promoter relations" ON public.ak_promoter_relations FOR ALL TO authenticated USING ( EXISTS ( SELECT 1 FROM public.ak_users WHERE id = auth.uid() AND role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users WHERE id = auth.uid() AND role = 'admin' ) ); -- 普通用户可查看与自己相关的关系(可选,便于移动端展示上级/下级) CREATE POLICY "Users can view their promoter relation" ON public.ak_promoter_relations FOR SELECT TO authenticated USING (uid = auth.uid() OR inviter_uid = auth.uid()); -- ===================================================================================== -- Schema: 用户提现申请表 -- 位置:docs/sql/10_schema/finance/ -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:管理用户发起的提现申请(佣金/余额),支持多种提现方式及快照信息 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ml_extract ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id), real_name TEXT NULL, -- 提现人姓名快照 extract_type TEXT NOT NULL, -- 提现方式: alipay, wechat, bank -- 账号快照信息 alipay_code TEXT NULL, -- 支付宝账号 wechat_code TEXT NULL, -- 微信账号 bank_code TEXT NULL, -- 银行卡号 bank_address TEXT NULL, -- 开户行地址 extract_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 申请提现金额 service_fee DECIMAL(12,2) NOT NULL DEFAULT 0, -- 提现手续费 balance DECIMAL(12,2) NOT NULL DEFAULT 0, -- 提现时的余额快照 status SMALLINT NOT NULL DEFAULT 0, -- 状态: 0:待审核, 1:已通过, -1:已驳回 refusal_reason TEXT NULL, -- 驳回原因 admin_id UUID NULL REFERENCES public.ak_users(id), -- 审核人ID payment_time TIMESTAMPTZ NULL, -- 打款/到账时间 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS ml_extract_uid_idx ON public.ml_extract (uid); CREATE INDEX IF NOT EXISTS ml_extract_status_idx ON public.ml_extract (status); CREATE INDEX IF NOT EXISTS ml_extract_created_at_idx ON public.ml_extract (created_at DESC); -- ===================================================================================== -- Schema: 发票管理表 -- 位置:docs/sql/10_schema/finance/ml_invoices_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:记录用户提交的开票申请及其处理状态 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ml_invoices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id), order_no TEXT NOT NULL, -- 关联订单号 order_amount DECIMAL(12,2) NOT NULL, -- 订单金额 invoice_type SMALLINT NOT NULL DEFAULT 1, -- 1: 电子普通发票, 2: 增值税专用发票 header_type SMALLINT NOT NULL DEFAULT 1, -- 1: 个人, 2: 企业 header_name TEXT NOT NULL, -- 发票抬头 tax_id TEXT NULL, -- 企业税号 email TEXT NULL, -- 接收邮箱 remark TEXT NULL, -- 备注 status SMALLINT NOT NULL DEFAULT 0, -- 0: 待开票, 1: 已开票, -1: 已拒绝 refusal_reason TEXT NULL, -- 驳回原因 invoice_url TEXT NULL, -- 电子发票文件路径/URL created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS ml_invoices_uid_idx ON public.ml_invoices (uid); CREATE INDEX IF NOT EXISTS ml_invoices_order_no_idx ON public.ml_invoices (order_no); CREATE INDEX IF NOT EXISTS ml_invoices_status_idx ON public.ml_invoices (status); -- ===================================================================================== -- Schema: 用户资金流水表 -- 位置:docs/sql/10_schema/finance/ -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:记录用户余额、积分、佣金的所有增减流水(原子日志) -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ml_user_bill ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id), link_id TEXT NULL, -- 关联业务ID(订单号、提现ID、充值ID等) pm SMALLINT NOT NULL DEFAULT 1, -- 0:支出, 1:收入 title TEXT NOT NULL, -- 流水标题(如:商品购买、充值、提现) category TEXT NOT NULL, -- 业务大类(如:balance-余额, integral-积分, brokerage-佣金) type TEXT NOT NULL, -- 业务子类型(如:recharge, extract, pay, refund, system_add, system_sub) number DECIMAL(12,2) NOT NULL DEFAULT 0, -- 变动金额 balance DECIMAL(12,2) NOT NULL DEFAULT 0, -- 变动后的余额快照 mark TEXT NULL, -- 备注 status SMALLINT NOT NULL DEFAULT 1, -- 状态(1:有效, 0:无效/冲正) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 常用查询索引 CREATE INDEX IF NOT EXISTS ml_user_bill_uid_idx ON public.ml_user_bill (uid); CREATE INDEX IF NOT EXISTS ml_user_bill_category_type_idx ON public.ml_user_bill (category, type); CREATE INDEX IF NOT EXISTS ml_user_bill_created_at_idx ON public.ml_user_bill (created_at DESC); -- ===================================================================================== -- Schema: 用户充值记录表 -- 位置:docs/sql/10_schema/finance/ -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:记录用户主动发起的充值申请及支付状态 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ml_user_recharge ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), uid UUID NOT NULL REFERENCES public.ak_users(id), order_no TEXT UNIQUE NOT NULL, -- 充值订单号(cz开头) recharge_type TEXT NOT NULL, -- 充值渠道: wechat, alipay, system (后台补单) price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 实际充值金额 give_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 赠送金额 paid SMALLINT NOT NULL DEFAULT 0, -- 支付状态: 0:未支付, 1:已支付 pay_time TIMESTAMPTZ NULL, -- 支付时间 channel_trade_no TEXT NULL, -- 外部渠道流水号 status SMALLINT NOT NULL DEFAULT 1, -- 记录状态: 1:正常, 0:逻辑删除 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS ml_user_recharge_uid_idx ON public.ml_user_recharge (uid); CREATE INDEX IF NOT EXISTS ml_user_recharge_order_no_idx ON public.ml_user_recharge (order_no); CREATE INDEX IF NOT EXISTS ml_user_recharge_created_at_idx ON public.ml_user_recharge (created_at DESC); -- ===================================================================================== -- Schema: homecare foundation -- Version: v1 -- Purpose: 为 ec_service_requests / ec_care_tasks / ec_care_records / hc_* 新链补齐最小结构、索引与基础 RLS。 -- Coverage: -- 1. consumer 下单与自动派单字段 -- 2. consumer 验收 / 退回整改 / 评价字段 -- 3. delivery 执行记录、异常、证据、事件字段 -- ===================================================================================== -- 执行稿见:mall_sql/migrations/20260526_homecare_foundation_v1.sql-- ===================================================================================== -- Schema: 客服模块核心表 -- 位置:docs/sql/10_schema/kefu/ml_kefu_tables_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:包含客服账号、话术、留言及自动回复逻辑 -- ===================================================================================== -- 1. 客服人员表 CREATE TABLE IF NOT EXISTS public.ml_kefu_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES public.ak_users(id), -- 关联主用户表 nickname TEXT NOT NULL, -- 客服昵称 avatar TEXT NULL, -- 客服头像 status SMALLINT NOT NULL DEFAULT 1, -- 1:启用, 0:禁用 is_online BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 2. 话术分类表 CREATE TABLE IF NOT EXISTS public.ml_kefu_word_categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, sort INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 3. 客服快捷话术表 CREATE TABLE IF NOT EXISTS public.ml_kefu_words ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), category_id UUID NOT NULL REFERENCES public.ml_kefu_word_categories(id) ON DELETE CASCADE, title TEXT NOT NULL, content TEXT NOT NULL, sort INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 4. 用户留言反馈表 CREATE TABLE IF NOT EXISTS public.ml_kefu_feedbacks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NULL REFERENCES public.ak_users(id), -- 允许匿名留言 nickname TEXT NULL, phone TEXT NULL, content TEXT NOT NULL, status SMALLINT NOT NULL DEFAULT 0, -- 0:未处理, 1:已处理 reply_content TEXT NULL, -- 管理员回复内容 processed_at TIMESTAMPTZ NULL, -- 处理时间 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 5. 关键词自动回复表 CREATE TABLE IF NOT EXISTS public.ml_kefu_auto_replies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), keyword TEXT NOT NULL, content TEXT NOT NULL, reply_type TEXT NOT NULL DEFAULT 'text', -- text, image status SMALLINT NOT NULL DEFAULT 1, -- 1:开启, 0:关闭 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 索引 CREATE INDEX IF NOT EXISTS ml_kefu_accounts_user_id_idx ON public.ml_kefu_accounts (user_id); CREATE INDEX IF NOT EXISTS ml_kefu_words_category_id_idx ON public.ml_kefu_words (category_id); CREATE INDEX IF NOT EXISTS ml_kefu_feedbacks_status_idx ON public.ml_kefu_feedbacks (status); CREATE INDEX IF NOT EXISTS ml_kefu_auto_replies_keyword_idx ON public.ml_kefu_auto_replies (keyword); -- ===================================================================================== -- Schema: 秒杀与拼团活动表 -- 位置:docs/sql/10_schema/marketing/ak_advanced_marketing_v1.sql -- 说明:管理秒杀活动与拼团活动,按商家隔离。 -- ===================================================================================== -- 1. 秒杀活动表 CREATE TABLE IF NOT EXISTS public.ak_seckill_activities ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, title TEXT NOT NULL, -- 活动标题 single_limit INTEGER DEFAULT 1, -- 单次限购 total_limit INTEGER DEFAULT 10, -- 总购买数量限制 product_count INTEGER DEFAULT 0, -- 包含商品数量 time_range TEXT NOT NULL, -- 活动时段 (如 "06:00-24:00") start_date TIMESTAMPTZ NOT NULL, -- 开始日期 end_date TIMESTAMPTZ NOT NULL, -- 结束日期 status BOOLEAN DEFAULT true, -- 状态: true开启, false关闭 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 拼团活动表 (开团记录) CREATE TABLE IF NOT EXISTS public.ak_combination_activities ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, uid UUID NOT NULL REFERENCES public.ak_users(id), -- 开团团长 product_id UUID NOT NULL REFERENCES public.ml_products(id), -- 拼团商品 people INTEGER DEFAULT 2, -- 几人团 count_people INTEGER DEFAULT 1, -- 当前几人参加 start_time TIMESTAMPTZ DEFAULT now(), -- 开团时间 stop_time TIMESTAMPTZ NOT NULL, -- 结束时间 status TEXT NOT NULL DEFAULT 'ongoing', -- ongoing进行中, pending未完成, ended已成功 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), CONSTRAINT chk_comb_status CHECK (status IN ('ongoing', 'pending', 'ended')) ); -- 3. 启用 RLS ALTER TABLE public.ak_seckill_activities ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_combination_activities ENABLE ROW LEVEL SECURITY; -- 4. 创建权限策略 (按 merchant_id 隔离) -- 秒杀策略 CREATE POLICY "Merchants can manage their own seckill activities" ON public.ak_seckill_activities FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 拼团策略 CREATE POLICY "Merchants can manage their own combination activities" ON public.ak_combination_activities FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看(用于移动端展示) CREATE POLICY "Anyone can view active marketing activities" ON public.ak_seckill_activities FOR SELECT TO authenticated USING (status = true); CREATE POLICY "Anyone can view ongoing combinations" ON public.ak_combination_activities FOR SELECT TO authenticated USING (true); -- ===================================================================================== -- Schema: 砍价与团购活动表 -- 位置:docs/sql/10_schema/marketing/ak_bargain_groupbuy_v1.sql -- 说明:管理砍价与团购活动,按商家隔离。 -- ===================================================================================== -- 1. 砍价活动表 CREATE TABLE IF NOT EXISTS public.ak_marketing_bargains ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES public.ml_products(id) ON DELETE CASCADE, title TEXT NOT NULL, -- 活动标题 min_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 砍价最低价 stock INTEGER DEFAULT 0, -- 活动库存 start_time TIMESTAMPTZ NOT NULL, -- 开始时间 stop_time TIMESTAMPTZ NOT NULL, -- 结束时间 status BOOLEAN DEFAULT true, -- 状态: true开启, false关闭 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 团购活动表 CREATE TABLE IF NOT EXISTS public.ak_marketing_groupbuys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES public.ml_products(id) ON DELETE CASCADE, title TEXT NOT NULL, -- 活动标题 price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 团购价格 people INTEGER DEFAULT 2, -- 成团人数要求 stock INTEGER DEFAULT 0, -- 活动库存 start_time TIMESTAMPTZ NOT NULL, -- 开始时间 stop_time TIMESTAMPTZ NOT NULL, -- 结束时间 status BOOLEAN DEFAULT true, -- 状态: true开启, false关闭 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 3. 启用 RLS ALTER TABLE public.ak_marketing_bargains ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_groupbuys ENABLE ROW LEVEL SECURITY; -- 4. 创建权限策略 (按 merchant_id 隔离) -- 砍价策略 CREATE POLICY "Merchants can manage their own bargains" ON public.ak_marketing_bargains FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 团购策略 CREATE POLICY "Merchants can manage their own groupbuys" ON public.ak_marketing_groupbuys FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看(用于移动端展示) CREATE POLICY "Anyone can view active marketing activities" ON public.ak_marketing_bargains FOR SELECT TO authenticated USING (status = true); CREATE POLICY "Anyone can view active groupbuys" ON public.ak_marketing_groupbuys FOR SELECT TO authenticated USING (status = true); -- 5. 索引 CREATE INDEX IF NOT EXISTS idx_bargains_merchant ON public.ak_marketing_bargains(merchant_id); CREATE INDEX IF NOT EXISTS idx_groupbuys_merchant ON public.ak_marketing_groupbuys(merchant_id); -- ===================================================================================== -- Schema: 直播商品管理表 -- 位置:docs/sql/10_schema/marketing/ak_live_products_v1.sql -- 说明:管理直播活动关联的商品,支持直播价设置与审核状态,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_marketing_live_products ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES public.ml_products(id) ON DELETE CASCADE, live_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 直播专属价 stock INTEGER DEFAULT 0, -- 直播可用库存 audit_status INTEGER DEFAULT 1, -- 审核状态: 1待审核, 2审核通过, 3审核驳回 is_show BOOLEAN DEFAULT true, -- 是否在直播间显示 sort_order INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 启用 RLS ALTER TABLE public.ak_marketing_live_products ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理自己的直播商品 CREATE POLICY "Merchants can manage their own live products" ON public.ak_marketing_live_products FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许查看审核通过的商品 CREATE POLICY "Anyone can view approved live products" ON public.ak_marketing_live_products FOR SELECT TO authenticated USING (audit_status = 2 AND is_show = true); -- 索引 CREATE INDEX IF NOT EXISTS idx_live_products_merchant ON public.ak_marketing_live_products(merchant_id); CREATE INDEX IF NOT EXISTS idx_live_products_product ON public.ak_marketing_live_products(product_id); -- ===================================================================================== -- Schema: 抽奖与直播管理表 -- 位置:docs/sql/10_schema/marketing/ak_lottery_live_v1.sql -- 说明:管理抽奖活动、奖品、主播及直播间,按商家隔离。 -- ===================================================================================== -- 1. 抽奖活动表 CREATE TABLE IF NOT EXISTS public.ak_marketing_lotteries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 活动名称 type INTEGER DEFAULT 1, -- 活动类型: 1积分抽奖, 2订单评价, 3订单支付 start_time TIMESTAMPTZ NOT NULL, -- 开始时间 end_time TIMESTAMPTZ NOT NULL, -- 结束时间 is_open BOOLEAN DEFAULT true, -- 是否开启 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 抽奖奖品表 CREATE TABLE IF NOT EXISTS public.ak_marketing_lottery_prizes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), lottery_id UUID NOT NULL REFERENCES public.ak_marketing_lotteries(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 奖品名称 prize_type TEXT NOT NULL, -- 奖品类型: points, balance, coupon, physical amount DECIMAL(12,2) DEFAULT 0, -- 奖励面值/数量 stock INTEGER DEFAULT 0, -- 奖品库存 probability DECIMAL(5,2) DEFAULT 0, -- 中奖概率 (0-100) sort_order INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT now() ); -- 3. 直播主播表 CREATE TABLE IF NOT EXISTS public.ak_marketing_live_anchors ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, nickname TEXT NOT NULL, -- 主播昵称 wechat TEXT, -- 微信号 phone TEXT, -- 联系电话 avatar_url TEXT, -- 头像 status BOOLEAN DEFAULT true, -- 状态 created_at TIMESTAMPTZ DEFAULT now() ); -- 4. 直播间管理表 CREATE TABLE IF NOT EXISTS public.ak_marketing_live_rooms ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, anchor_id UUID REFERENCES public.ak_marketing_live_anchors(id) ON DELETE SET NULL, name TEXT NOT NULL, -- 直播间名称 background_url TEXT, -- 背景图 share_img_url TEXT, -- 分享图 start_time TIMESTAMPTZ NOT NULL, -- 开始时间 end_time TIMESTAMPTZ NOT NULL, -- 计划结束时间 sort INTEGER DEFAULT 0, -- 排序 type TEXT DEFAULT 'phone', -- 类型: phone手机直播等 like_enabled BOOLEAN DEFAULT true, -- 开启点赞 sale_enabled BOOLEAN DEFAULT true, -- 开启卖货 comment_enabled BOOLEAN DEFAULT true, -- 开启评论 is_show BOOLEAN DEFAULT true, -- 是否显示 live_status INTEGER DEFAULT 1, -- 1未开始, 2直播中, 3暂停, 4已结束 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 5. 启用 RLS ALTER TABLE public.ak_marketing_lotteries ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_lottery_prizes ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_live_anchors ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_live_rooms ENABLE ROW LEVEL SECURITY; -- 6. 创建权限策略 (按 merchant_id 隔离) CREATE POLICY "Merchants manage their own lotteries" ON public.ak_marketing_lotteries FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); CREATE POLICY "Merchants manage their own anchors" ON public.ak_marketing_live_anchors FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); CREATE POLICY "Merchants manage their own rooms" ON public.ak_marketing_live_rooms FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许查看 CREATE POLICY "Users can view lotteries" ON public.ak_marketing_lotteries FOR SELECT TO authenticated USING (is_open = true); CREATE POLICY "Users can view active rooms" ON public.ak_marketing_live_rooms FOR SELECT TO authenticated USING (is_show = true); -- ===================================================================================== -- Schema: 打卡/签到增强配置表 -- 位置:docs/sql/10_schema/marketing/ak_marketing_checkin_configs_v1.sql -- 说明:管理打卡开关、模式、提醒及基础奖励(积分/经验),按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_marketing_checkin_configs ( id TEXT PRIMARY KEY DEFAULT 'checkin_config', merchant_id UUID NOT NULL UNIQUE REFERENCES public.ak_users(id) ON DELETE CASCADE, is_open BOOLEAN DEFAULT true, -- 签到开关 mode TEXT DEFAULT 'none', -- 签到模式: none(无限制), week(周循环), month(月循环) notice_enabled BOOLEAN DEFAULT false, -- 签到提醒开关 integral_reward INTEGER DEFAULT 10, -- 每日签到赠送积分 exp_reward INTEGER DEFAULT 1, -- 每日签到赠送经验 updated_at TIMESTAMPTZ DEFAULT now(), updated_by UUID REFERENCES auth.users(id) ); -- 启用 RLS ALTER TABLE public.ak_marketing_checkin_configs ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理自己的打卡配置 CREATE POLICY "Merchants manage their own checkin configs" ON public.ak_marketing_checkin_configs FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看(用于前台展示) CREATE POLICY "Anyone can view checkin config" ON public.ak_marketing_checkin_configs FOR SELECT TO authenticated USING (true); -- 插入初始化数据(为每个管理员/商家初始化一条) -- 实际应在商家创建时触发,此处先预留 -- ===================================================================================== -- Schema: 新人礼配置表 -- 位置:docs/sql/10_schema/marketing/ak_marketing_newcomer_config_v1.sql -- 说明:管理新用户注册后的奖励(余额、积分、优惠券),按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_marketing_newcomer_config ( id TEXT PRIMARY KEY DEFAULT 'newcomer_config', merchant_id UUID NOT NULL UNIQUE REFERENCES public.ak_users(id) ON DELETE CASCADE, balance_reward DECIMAL(12,2) DEFAULT 0.00, -- 赠送余额 integral_reward INTEGER DEFAULT 0, -- 赠送积分 -- 赠送优惠券 (JSONB 格式): [{ "id": "coupon_uuid", "name": "显示名称", "desc": "发放描述" }] coupons_json JSONB DEFAULT '[]'::jsonb, updated_at TIMESTAMPTZ DEFAULT now(), updated_by UUID REFERENCES auth.users(id) ); -- 启用 RLS ALTER TABLE public.ak_marketing_newcomer_config ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理自己的新人礼配置 CREATE POLICY "Merchants manage their own newcomer configs" ON public.ak_marketing_newcomer_config FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许查看配置(用于移动端展示) CREATE POLICY "Anyone can view newcomer config" ON public.ak_marketing_newcomer_config FOR SELECT TO authenticated USING (true); -- ===================================================================================== -- Schema: 签到记录表 -- 位置:docs/sql/10_schema/marketing/ak_marketing_signin_logs_v1.sql -- 说明:记录用户每日签到的详细流水,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_marketing_signin_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, points INTEGER NOT NULL DEFAULT 0, -- 本次签到获得的积分 is_continuous_reward BOOLEAN DEFAULT false, -- 是否包含连续签到额外奖励 created_at TIMESTAMPTZ DEFAULT now() ); -- 启用 RLS ALTER TABLE public.ak_marketing_signin_logs ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理/查看自己的签到记录 CREATE POLICY "Merchants manage their own signin logs" ON public.ak_marketing_signin_logs FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许用户查看自己的签到记录 CREATE POLICY "Users view own signin logs" ON public.ak_marketing_signin_logs FOR SELECT TO authenticated USING (uid = auth.uid()); -- 索引 CREATE INDEX IF NOT EXISTS idx_signin_logs_merchant ON public.ak_marketing_signin_logs(merchant_id); CREATE INDEX IF NOT EXISTS idx_signin_logs_uid ON public.ak_marketing_signin_logs(uid, created_at DESC); -- ===================================================================================== -- Schema: 付费会员管理相关表 -- 位置:docs/sql/10_schema/marketing/ak_member_management_v1.sql -- 说明:管理会员卡类型、权益内容及基础配置,按商家隔离。 -- ===================================================================================== -- 1. 会员卡类型表 CREATE TABLE IF NOT EXISTS public.ak_marketing_member_types ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 会员名 (如: 月卡, 年卡) duration_days INTEGER DEFAULT 30, -- 有效期(天),0表示永久 price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 原价 discount_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 优惠价/实际支付价 is_open BOOLEAN DEFAULT true, -- 是否开启 sort_order INTEGER DEFAULT 0, -- 排序 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 会员权益表 CREATE TABLE IF NOT EXISTS public.ak_marketing_member_rights ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 权益名称 description TEXT, -- 权益简介 icon_url TEXT, -- 权益图标 is_show BOOLEAN DEFAULT true, -- 是否展示 sort_order INTEGER DEFAULT 0, -- 排序 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 3. 会员基础配置表 (每个商家一条记录) CREATE TABLE IF NOT EXISTS public.ak_marketing_member_config ( id TEXT PRIMARY KEY DEFAULT 'member_config', merchant_id UUID NOT NULL UNIQUE REFERENCES public.ak_users(id) ON DELETE CASCADE, is_enabled BOOLEAN DEFAULT true, -- 是否开启付费会员功能 bg_img_url TEXT, -- 会员期内背景图 expire_bg_img_url TEXT, -- 会员到期背景图 rules_description TEXT, -- 会员规则说明文本 updated_at TIMESTAMPTZ DEFAULT now() ); -- 4. 启用 RLS ALTER TABLE public.ak_marketing_member_types ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_member_rights ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_marketing_member_config ENABLE ROW LEVEL SECURITY; -- 5. 创建权限策略 (按 merchant_id 隔离) -- 商家管理自己的数据 CREATE POLICY "Merchants manage their own member types" ON public.ak_marketing_member_types FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); CREATE POLICY "Merchants manage their own member rights" ON public.ak_marketing_member_rights FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); CREATE POLICY "Merchants manage their own member config" ON public.ak_marketing_member_config FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看 (移动端展示) CREATE POLICY "Users can view active member types" ON public.ak_marketing_member_types FOR SELECT TO authenticated USING (is_open = true); CREATE POLICY "Users can view active member rights" ON public.ak_marketing_member_rights FOR SELECT TO authenticated USING (is_show = true); CREATE POLICY "Users can view member config" ON public.ak_marketing_member_config FOR SELECT TO authenticated USING (true); -- 6. 索引 CREATE INDEX IF NOT EXISTS idx_member_types_merchant ON public.ak_marketing_member_types(merchant_id); CREATE INDEX IF NOT EXISTS idx_member_rights_merchant ON public.ak_marketing_member_rights(merchant_id); -- ===================================================================================== -- Schema: 充值配置与额度模板表 -- 位置:docs/sql/10_schema/marketing/ak_recharge_management_v1.sql -- 说明:管理用户充值开关、最低金额及预设额度,按商家隔离。 -- ===================================================================================== -- 1. 充值基础配置表 (每个商家一条记录) CREATE TABLE IF NOT EXISTS public.ak_recharge_configs ( id TEXT PRIMARY KEY DEFAULT 'recharge_config', merchant_id UUID NOT NULL UNIQUE REFERENCES public.ak_users(id) ON DELETE CASCADE, balance_enabled BOOLEAN DEFAULT true, -- 余额功能是否启用 recharge_notice TEXT, -- 充值注意事项说明 mp_recharge_enabled BOOLEAN DEFAULT false, -- 小程序充值开关 min_recharge_amount DECIMAL(12,2) DEFAULT 0.01, -- 最低充值金额 updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 充值额度模板表 CREATE TABLE IF NOT EXISTS public.ak_recharge_quotas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 售价(实际充值金额) bonus_price DECIMAL(12,2) NOT NULL DEFAULT 0, -- 赠送金额 is_open BOOLEAN DEFAULT true, -- 是否可用 sort_order INTEGER DEFAULT 0, -- 排序 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 3. 启用 RLS ALTER TABLE public.ak_recharge_configs ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_recharge_quotas ENABLE ROW LEVEL SECURITY; -- 4. 创建权限策略 (按 merchant_id 隔离) CREATE POLICY "Merchants manage their own recharge configs" ON public.ak_recharge_configs FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); CREATE POLICY "Merchants manage their own recharge quotas" ON public.ak_recharge_quotas FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看 CREATE POLICY "Users can view recharge configs" ON public.ak_recharge_configs FOR SELECT TO authenticated USING (true); CREATE POLICY "Users can view active recharge quotas" ON public.ak_recharge_quotas FOR SELECT TO authenticated USING (is_open = true); -- 5. 索引 CREATE INDEX IF NOT EXISTS idx_recharge_quotas_merchant ON public.ak_recharge_quotas(merchant_id); -- ===================================================================================== -- Schema: 签到规则配置表 -- 位置:docs/sql/10_schema/marketing/ak_signin_configs_v1.sql -- 说明:记录每日签到积分、连续签到奖励及规则说明,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_signin_configs ( id TEXT PRIMARY KEY DEFAULT 'signin_config', -- 每个商家一个配置记录 merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, is_enabled BOOLEAN DEFAULT true, -- 签到功能是否启用 daily_points INTEGER DEFAULT 10, -- 每日签到固定奖励积分 -- 连续签到奖励 (JSONB 格式): [{ "day": 3, "points": 20 }, { "day": 7, "points": 50 }] continuous_rewards JSONB DEFAULT '[]'::jsonb, rules_description TEXT DEFAULT '1.每日签到可获得积分奖励;\n2.连续签到满足天数可获得额外阶梯奖励;\n3.签到中断将重新从第一天开始计算。', updated_at TIMESTAMPTZ DEFAULT now(), updated_by UUID REFERENCES auth.users(id), -- 约束:同一个商家只有一个签到配置记录 UNIQUE(merchant_id) ); -- 启用 RLS ALTER TABLE public.ak_signin_configs ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理自己的签到配置 CREATE POLICY "Merchants can manage their own signin configs" ON public.ak_signin_configs FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看配置(用于移动端签到展示) CREATE POLICY "Authenticated users can view signin configs" ON public.ak_signin_configs FOR SELECT TO authenticated USING (true); -- ===================================================================================== -- Schema Update: ml_orders 字段补齐 -- 位置:docs/sql/10_schema/order/ -- 对象类型:Schema (ALTER TABLE) -- 版本:v1 -- 说明:为订单主表补齐核销记录 RPC 所依赖的业务字段(order_type, verified_at, verifier_id) -- ===================================================================================== DO $$ BEGIN -- 1. 补齐 order_type (1:普通, 2:收银, 3:核销) IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_orders' AND column_name = 'order_type') THEN ALTER TABLE public.ml_orders ADD COLUMN order_type INTEGER DEFAULT 1; COMMENT ON COLUMN public.ml_orders.order_type IS '订单类型: 1:普通, 2:收银, 3:核销'; END IF; -- 2. 补齐 verified_at (核销时间) IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_orders' AND column_name = 'verified_at') THEN ALTER TABLE public.ml_orders ADD COLUMN verified_at TIMESTAMP WITH TIME ZONE; COMMENT ON COLUMN public.ml_orders.verified_at IS '核销时间'; END IF; -- 3. 补齐 verifier_id (核销员ID) IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_orders' AND column_name = 'verifier_id') THEN ALTER TABLE public.ml_orders ADD COLUMN verifier_id UUID REFERENCES public.ak_users(id); COMMENT ON COLUMN public.ml_orders.verifier_id IS '核销员ID'; END IF; -- 4. 补齐 pay_type (支付方式: 1:余额, 2:微信, 3:支付宝, 4:线下支付) IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_orders' AND column_name = 'pay_type') THEN ALTER TABLE public.ml_orders ADD COLUMN pay_type INTEGER DEFAULT 1; COMMENT ON COLUMN public.ml_orders.pay_type IS '支付方式: 1:余额, 2:微信, 3:支付宝, 4:线下支付'; END IF; -- 5. 补齐 channel_type (订单渠道: 1:公众号, 2:小程序, 3:H5, 4:PC, 5:APP) IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_orders' AND column_name = 'channel_type') THEN ALTER TABLE public.ml_orders ADD COLUMN channel_type INTEGER DEFAULT 1; COMMENT ON COLUMN public.ml_orders.channel_type IS '订单渠道: 1:公众号, 2:小程序, 3:H5, 4:PC, 5:APP'; END IF; END $$; -- 1. 商品标签分组表 CREATE TABLE IF NOT EXISTS public.ak_product_label_groups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, sort_order INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 2. 商品标签表 CREATE TABLE IF NOT EXISTS public.ak_product_labels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), group_id UUID REFERENCES public.ak_product_label_groups(id) ON DELETE SET NULL, merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, is_active BOOLEAN DEFAULT true, show_in_mobile BOOLEAN DEFAULT true, sort_order INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 3. 启用 RLS ALTER TABLE public.ak_product_label_groups ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_product_labels ENABLE ROW LEVEL SECURITY; -- 4. 创建权限策略 (按 merchant_id 隔离) -- 分组策略 CREATE POLICY "Users can manage their own label groups" ON public.ak_product_label_groups FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 标签策略 CREATE POLICY "Users can manage their own labels" ON public.ak_product_labels FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 5. 索引 CREATE INDEX IF NOT EXISTS idx_label_groups_merchant ON public.ak_product_label_groups(merchant_id); CREATE INDEX IF NOT EXISTS idx_labels_group ON public.ak_product_labels(group_id); CREATE INDEX IF NOT EXISTS idx_labels_merchant ON public.ak_product_labels(merchant_id); -- ===================================================================================== -- Schema: 商品会员价表 (按 SKU + 等级 维度) -- 位置:docs/sql/10_schema/product/ak_product_member_prices_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:记录特定商品 SKU 在不同会员等级下的专享价格,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_product_member_prices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES public.ml_products(id) ON DELETE CASCADE, sku_id UUID NOT NULL REFERENCES public.ml_product_skus(id) ON DELETE CASCADE, level_id UUID NOT NULL REFERENCES public.ak_user_levels(id) ON DELETE CASCADE, member_price DECIMAL(12,2) NOT NULL CHECK (member_price >= 0), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), -- 约束:同一个商家的同一个 SKU 在同一个等级下只能有一个会员价 UNIQUE(merchant_id, sku_id, level_id) ); -- 索引 CREATE INDEX IF NOT EXISTS idx_prod_member_prices_product ON public.ak_product_member_prices(product_id); CREATE INDEX IF NOT EXISTS idx_prod_member_prices_sku ON public.ak_product_member_prices(sku_id); CREATE INDEX IF NOT EXISTS idx_prod_member_prices_level ON public.ak_product_member_prices(level_id); CREATE INDEX IF NOT EXISTS idx_prod_member_prices_merchant ON public.ak_product_member_prices(merchant_id); -- 启用 RLS ALTER TABLE public.ak_product_member_prices ENABLE ROW LEVEL SECURITY; -- 权限策略:商家仅能管理自己的商品会员价 CREATE POLICY "Merchants can manage their own product member prices" ON public.ak_product_member_prices FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许所有认证用户查看会员价(前台下单需计算) CREATE POLICY "Authenticated users can view product member prices" ON public.ak_product_member_prices FOR SELECT TO authenticated USING (true); -- 商品保障/服务条款(按 merchant_id 隔离) CREATE TABLE IF NOT EXISTS public.ak_product_protections ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', icon_url TEXT, sort_order INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_ak_product_protections_merchant ON public.ak_product_protections(merchant_id); CREATE INDEX IF NOT EXISTS idx_ak_product_protections_active ON public.ak_product_protections(is_active); ALTER TABLE public.ak_product_protections ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can manage their own product protections" ON public.ak_product_protections FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 商品规格模板表 + 商品参数模板表(按 merchant_id 隔离) -- 1) 商品规格模板表 CREATE TABLE IF NOT EXISTS public.ak_product_spec_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, specs TEXT NOT NULL DEFAULT '', attrs TEXT NOT NULL DEFAULT '', sort_order INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_spec_templates_merchant ON public.ak_product_spec_templates(merchant_id); ALTER TABLE public.ak_product_spec_templates ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can manage their own spec templates" ON public.ak_product_spec_templates FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 2) 商品参数模板表 CREATE TABLE IF NOT EXISTS public.ak_product_param_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, sort_order INTEGER DEFAULT 0, params JSONB NOT NULL DEFAULT '[]'::jsonb, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_param_templates_merchant ON public.ak_product_param_templates(merchant_id); ALTER TABLE public.ak_product_param_templates ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can manage their own param templates" ON public.ak_product_param_templates FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- ===================================================================================== -- Schema: 运费模板表 -- 位置:docs/sql/10_schema/product/ak_shipping_templates_v1.sql -- 说明:管理商家的运费计算规则,按商家隔离。 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_shipping_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), merchant_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 模板名称 calc_method TEXT DEFAULT 'piece', -- 计费方式: piece(件数), weight(重量), volume(体积) is_free_shipping BOOLEAN DEFAULT false, -- 是否包邮 sort_order INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- 启用 RLS ALTER TABLE public.ak_shipping_templates ENABLE ROW LEVEL SECURITY; -- 权限策略:商家管理自己的模板 CREATE POLICY "Merchants manage own shipping templates" ON public.ak_shipping_templates FOR ALL TO authenticated USING (merchant_id = auth.uid()) WITH CHECK (merchant_id = auth.uid()); -- 允许查看 CREATE POLICY "Authenticated users view shipping templates" ON public.ak_shipping_templates FOR SELECT TO authenticated USING (true); -- 索引 CREATE INDEX IF NOT EXISTS idx_shipping_templates_merchant ON public.ak_shipping_templates(merchant_id); -- Schema: 医疗商城独立分类与商品分类关联 -- 执行阶段: 10_schema CREATE TABLE IF NOT EXISTS public.medical_mall_categories ( id TEXT PRIMARY KEY, name TEXT NOT NULL, parent_id TEXT NULL REFERENCES public.medical_mall_categories(id), level INTEGER NOT NULL CHECK (level IN (1, 2)), sort_order INTEGER NOT NULL DEFAULT 0, icon TEXT, image_url TEXT, description TEXT, scene TEXT NOT NULL DEFAULT 'medical_mall', category_type TEXT NOT NULL DEFAULT 'normal', compliance_type TEXT NOT NULL DEFAULT 'normal', is_active BOOLEAN NOT NULL DEFAULT TRUE, deleted_at TIMESTAMPTZ NULL, deleted_by UUID NULL REFERENCES public.ak_users(id), restored_at TIMESTAMPTZ NULL, restored_by UUID NULL REFERENCES public.ak_users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); COMMENT ON TABLE public.medical_mall_categories IS '医疗商城独立分类表'; COMMENT ON COLUMN public.medical_mall_categories.scene IS '分类场景,如 medical_mall / home_mall'; COMMENT ON COLUMN public.medical_mall_categories.category_type IS '分类类型:device / otc / care / rehab / elderly / nutrition / protection / tcm / all'; COMMENT ON COLUMN public.medical_mall_categories.compliance_type IS '合规类型:normal / otc / device_class_i / device_class_ii / device_class_iii / rx_hidden'; CREATE INDEX IF NOT EXISTS idx_medical_mall_categories_parent ON public.medical_mall_categories(parent_id) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_medical_mall_categories_level_sort ON public.medical_mall_categories(level, sort_order) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_medical_mall_categories_scene_active ON public.medical_mall_categories(scene, is_active) WHERE deleted_at IS NULL; CREATE TABLE IF NOT EXISTS public.medical_mall_product_categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), product_id UUID NOT NULL REFERENCES public.ml_products(id) ON DELETE CASCADE, category_id TEXT NOT NULL REFERENCES public.medical_mall_categories(id), is_primary BOOLEAN NOT NULL DEFAULT FALSE, sort_order INTEGER NOT NULL DEFAULT 0, deleted_at TIMESTAMPTZ NULL, deleted_by UUID NULL REFERENCES public.ak_users(id), restored_at TIMESTAMPTZ NULL, restored_by UUID NULL REFERENCES public.ak_users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (product_id, category_id) ); COMMENT ON TABLE public.medical_mall_product_categories IS '医疗商城商品与分类关联表'; CREATE INDEX IF NOT EXISTS idx_medical_mall_product_categories_category ON public.medical_mall_product_categories(category_id, sort_order) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_medical_mall_product_categories_product ON public.medical_mall_product_categories(product_id) WHERE deleted_at IS NULL;-- ===================================================================================== -- Schema Update: ml_products 扩展字段 (物流、营销、高级设置) -- 位置:docs/sql/10_schema/product/ml_products_ext_v1.sql -- 说明:补齐商品编辑页 Step 3-6 所需的持久化字段。 -- ===================================================================================== DO $$ BEGIN -- 1. 物流设置:关联运费模板 IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_products' AND column_name = 'shipping_template_id') THEN ALTER TABLE public.ml_products ADD COLUMN shipping_template_id UUID REFERENCES public.ak_shipping_templates(id) ON DELETE SET NULL; COMMENT ON COLUMN public.ml_products.shipping_template_id IS '关联运费模板ID'; END IF; -- 2. 营销设置:赠送积分 IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_products' AND column_name = 'give_integral') THEN ALTER TABLE public.ml_products ADD COLUMN give_integral INTEGER DEFAULT 0; COMMENT ON COLUMN public.ml_products.give_integral IS '购买赠送积分'; END IF; -- 3. 高级设置:警戒库存 IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_products' AND column_name = 'stock_warning') THEN ALTER TABLE public.ml_products ADD COLUMN stock_warning INTEGER DEFAULT 10; COMMENT ON COLUMN public.ml_products.stock_warning IS '库存报警数值'; END IF; -- 4. 高级设置:虚拟销量 IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_products' AND column_name = 'virtual_sales') THEN ALTER TABLE public.ml_products ADD COLUMN virtual_sales INTEGER DEFAULT 0; COMMENT ON COLUMN public.ml_products.virtual_sales IS '虚拟销量(展示用)'; END IF; -- 5. 高级设置:排序 IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'ml_products' AND column_name = 'sort_order') THEN ALTER TABLE public.ml_products ADD COLUMN sort_order INTEGER DEFAULT 0; COMMENT ON COLUMN public.ml_products.sort_order IS '商品排序权重'; END IF; END $$; -- ===================================================================================== -- Schema: 权限管理 (RBAC) 核心表 -- 位置:docs/sql/10_schema/user/ak_auth_system_v1.sql -- 对象类型:TABLE -- 版本:v1 -- 说明:包含角色表、权限/菜单表及用户角色关联表 -- ===================================================================================== -- 1. 角色表 CREATE TABLE IF NOT EXISTS public.ak_roles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL UNIQUE, -- 角色名称 (如: 超级管理员) code TEXT NOT NULL UNIQUE, -- 角色编码 (如: super_admin) description TEXT, -- 角色描述 is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 2. 权限/菜单表 CREATE TABLE IF NOT EXISTS public.ak_permissions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), parent_id UUID REFERENCES public.ak_permissions(id) ON DELETE CASCADE, name TEXT NOT NULL, -- 权限/菜单名称 code TEXT NOT NULL UNIQUE, -- 权限编码 (如: order_view) type TEXT NOT NULL, -- 类型: menu(菜单), button(按钮/接口) path TEXT, -- 前端路由路径 (仅针对 menu) icon TEXT, -- 图标 sort_order INTEGER DEFAULT 0, -- 排序 is_visible BOOLEAN DEFAULT TRUE, -- 菜单是否在左侧可见 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- 3. 用户-角色关联表 -- 映射管理员 (ak_users) 与角色 CREATE TABLE IF NOT EXISTS public.ak_admin_roles ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, role_id UUID NOT NULL REFERENCES public.ak_roles(id) ON DELETE CASCADE, assigned_at TIMESTAMPTZ NOT NULL DEFAULT now(), assigned_by UUID REFERENCES public.ak_users(id), UNIQUE(user_id, role_id) ); -- 4. 角色-权限关联表 CREATE TABLE IF NOT EXISTS public.ak_role_permissions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), role_id UUID NOT NULL REFERENCES public.ak_roles(id) ON DELETE CASCADE, permission_id UUID NOT NULL REFERENCES public.ak_permissions(id) ON DELETE CASCADE, UNIQUE(role_id, permission_id) ); -- 索引 CREATE INDEX IF NOT EXISTS idx_permissions_parent_id ON public.ak_permissions(parent_id); CREATE INDEX IF NOT EXISTS idx_admin_roles_user_id ON public.ak_admin_roles(user_id); CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON public.ak_role_permissions(role_id); -- 注释 COMMENT ON TABLE public.ak_roles IS '后台管理角色表'; COMMENT ON TABLE public.ak_permissions IS '功能权限与菜单定义表'; COMMENT ON TABLE public.ak_admin_roles IS '管理员角色分配表'; COMMENT ON TABLE public.ak_role_permissions IS '角色权限映射表'; -- ===================================================================================== -- Schema: 用户分组表 -- 位置:docs/sql/10_schema/user/ak_user_groups_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:用户分组定义,支持逻辑删除和状态管理 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_user_groups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, remark TEXT NULL, status INT NOT NULL DEFAULT 1, -- 1:启用, 0:禁用 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ NULL, CONSTRAINT ak_user_groups_name_length CHECK (char_length(name) >= 1) ); -- 唯一性约束(仅对未删除记录生效) CREATE UNIQUE INDEX IF NOT EXISTS ak_user_groups_name_uniq_active ON public.ak_user_groups (name) WHERE deleted_at IS NULL; -- 常用查询索引 CREATE INDEX IF NOT EXISTS ak_user_groups_status_idx ON public.ak_user_groups (status) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS ak_user_groups_created_at_idx ON public.ak_user_groups (created_at DESC); -- ===================================================================================== -- Schema: 用户标签表 -- 位置:docs/sql/10_schema/user/ak_user_labels_v1.sql -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:用户标签定义,支持逻辑删除与状态管理 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_user_labels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, color TEXT NULL, remark TEXT NULL, status INT NOT NULL DEFAULT 1, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ NULL, CONSTRAINT ak_user_labels_name_length CHECK (char_length(name) >= 1) ); CREATE UNIQUE INDEX IF NOT EXISTS ak_user_labels_name_uniq_active ON public.ak_user_labels (name) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS ak_user_labels_status_idx ON public.ak_user_labels (status) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS ak_user_labels_created_at_idx ON public.ak_user_labels (created_at DESC); -- ===================================================================================== -- Schema: 用户等级表 -- 位置:docs/sql/10_schema/user/ -- 对象类型:Schema (DDL) -- 版本:v1 -- 说明:用户等级(经验值/折扣/展示/状态),支持逻辑删除 -- ===================================================================================== CREATE TABLE IF NOT EXISTS public.ak_user_levels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, level_weight INT NOT NULL, min_experience INT NOT NULL DEFAULT 0, discount_percent INT NOT NULL DEFAULT 100, is_visible BOOLEAN NOT NULL DEFAULT TRUE, status INT NOT NULL DEFAULT 1, icon_url TEXT NULL, bg_image_url TEXT NULL, bg_style_json JSONB NULL, remark TEXT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ NULL, CONSTRAINT ak_user_levels_level_weight_nonnegative CHECK (level_weight >= 0), CONSTRAINT ak_user_levels_min_experience_nonnegative CHECK (min_experience >= 0), CONSTRAINT ak_user_levels_discount_percent_range CHECK (discount_percent BETWEEN 1 AND 100) ); -- 唯一性(仅对未删除记录生效) CREATE UNIQUE INDEX IF NOT EXISTS ak_user_levels_name_uniq_active ON public.ak_user_levels (name) WHERE deleted_at IS NULL; CREATE UNIQUE INDEX IF NOT EXISTS ak_user_levels_level_weight_uniq_active ON public.ak_user_levels (level_weight) WHERE deleted_at IS NULL; -- 常用查询索引 CREATE INDEX IF NOT EXISTS ak_user_levels_active_filter_idx ON public.ak_user_levels (status, is_visible) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS ak_user_levels_min_experience_idx ON public.ak_user_levels (min_experience) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS ak_user_levels_level_weight_desc_idx ON public.ak_user_levels (level_weight DESC) WHERE deleted_at IS NULL; -- Schema Update: public.ak_users 增加真实姓名与手机号字段(用于分销/推广员等管理端展示) DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'ak_users' AND column_name = 'real_name' ) THEN ALTER TABLE public.ak_users ADD COLUMN real_name text; COMMENT ON COLUMN public.ak_users.real_name IS '真实姓名(可选)'; END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'ak_users' AND column_name = 'phone' ) THEN ALTER TABLE public.ak_users ADD COLUMN phone text; COMMENT ON COLUMN public.ak_users.phone IS '手机号(可选)'; END IF; END $$; -- ===================================================================================== -- Schema: public.ak_users -- Version: v1 -- Purpose: 修复 auth.users -> ak_users 自动同步的写入协调问题 -- Change: 放宽 username 和 email 的 NOT NULL 约束,以允许数据库触发器成功插入新用户记录。 -- 同时,将 role 的默认值更新为 'customer' 以符合业务逻辑。 -- ===================================================================================== BEGIN; -- 步骤 1 & 2: 允许 username/email 为空,并更新 role 默认值 -- 这样数据库的自动用户同步触发器就不会因为缺少 NOT NULL 的值而失败。 -- 前端代码 (ensureUserProfile) 会在用户首次登录时尝试填充这些值。 ALTER TABLE public.ak_users ALTER COLUMN username DROP NOT NULL, ALTER COLUMN email DROP NOT NULL, ALTER COLUMN role SET DEFAULT 'customer'; COMMIT; -- ===================================================================================== -- User 模块扩展 - 财务字段补全 -- 位置:docs/sql/10_schema/user/ -- 版本:v1 -- 描述:为 ak_users 增加余额与佣金字段,支持财务业务。 -- ===================================================================================== ALTER TABLE public.ak_users ADD COLUMN IF NOT EXISTS now_money DECIMAL(12,2) DEFAULT 0, ADD COLUMN IF NOT EXISTS brokerage_price DECIMAL(12,2) DEFAULT 0; COMMENT ON COLUMN public.ak_users.now_money IS '用户当前余额'; COMMENT ON COLUMN public.ak_users.brokerage_price IS '用户当前佣金';