admin接入数据库

This commit is contained in:
comlibmb
2026-02-16 15:19:17 +08:00
parent e648ff0c22
commit 5acda05134
18 changed files with 1736 additions and 470 deletions

View File

@@ -0,0 +1,34 @@
-- =====================================================================================
-- 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)';

View File

@@ -1,41 +1,29 @@
-- =====================================================================================
-- 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 (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
merchant_id 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,
uid UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE,
name TEXT NOT NULL, -- 代理商名称(或备注名)
status BOOLEAN DEFAULT true, -- 状态: true开启, false关闭
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(),
-- 约束:一个用户在一个商家下只能成为一个代理商
UNIQUE(merchant_id, uid)
created_by UUID REFERENCES public.ak_users(id),
updated_by UUID REFERENCES public.ak_users(id)
);
-- 启用 RLS
ALTER TABLE public.ak_distribution_agents ENABLE ROW LEVEL SECURITY;
-- 权限策略:商家仅能管理自己的代理商
CREATE POLICY "Merchants manage their own agents"
ON public.ak_distribution_agents FOR ALL
TO authenticated
USING (merchant_id = auth.uid())
WITH CHECK (merchant_id = auth.uid());
-- 允许查看
CREATE POLICY "Authenticated users view active agents"
ON public.ak_distribution_agents FOR SELECT
TO authenticated
USING (status = true);
-- 索引
CREATE INDEX IF NOT EXISTS idx_agents_merchant ON public.ak_distribution_agents(merchant_id);
CREATE INDEX IF NOT EXISTS idx_agents_division ON public.ak_distribution_agents(division_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 '代理商固定分佣比例(%)';

View File

@@ -1,46 +1,30 @@
-- =====================================================================================
-- Schema: 分销事业部管理表
-- 位置docs/sql/10_schema/distribution/ak_distribution_divisions_v1.sql
-- 说明:管理分销体系中的事业部,支持独立分销比例、邀请码及有效期,按商家隔离。
-- 对象类型TABLE
-- 版本v1
-- 依赖ak_users
-- =====================================================================================
CREATE TABLE IF NOT EXISTS public.ak_distribution_divisions (
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), -- 事业部负责人UID
name TEXT NOT NULL, -- 事业部名称
invite_code TEXT UNIQUE NOT NULL, -- 事业部专属邀请码
ratio DECIMAL(5,2) DEFAULT 0, -- 事业部额外分销比例 (%)
agent_count INTEGER DEFAULT 0, -- 下属代理商数量 (由程序或触发器维护)
end_time TIMESTAMPTZ, -- 协议截止时间
status BOOLEAN DEFAULT true, -- 状态: true开启, false关闭
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(),
-- 约束:一个用户在一个商家下只能负责一个事业部
UNIQUE(merchant_id, uid)
created_by UUID REFERENCES public.ak_users(id),
updated_by UUID REFERENCES public.ak_users(id)
);
-- 启用 RLS
ALTER TABLE public.ak_distribution_divisions ENABLE ROW LEVEL SECURITY;
-- 权限策略
CREATE POLICY "Merchants manage their own divisions"
ON public.ak_distribution_divisions FOR ALL
TO authenticated
USING (merchant_id = auth.uid())
WITH CHECK (merchant_id = auth.uid());
-- 允许查看
CREATE POLICY "Authenticated users view active divisions"
ON public.ak_distribution_divisions FOR SELECT
TO authenticated
USING (status = true);
-- 索引
CREATE INDEX IF NOT EXISTS idx_divisions_merchant ON public.ak_distribution_divisions(merchant_id);
CREATE INDEX IF NOT EXISTS idx_divisions_uid ON public.ak_distribution_divisions(uid);
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 '事业部有效截止时间';

View File

@@ -0,0 +1,52 @@
-- =====================================================================================
-- RLS: 分销模块安全策略
-- 位置docs/sql/20_rls/distribution/ml_distribution_rls_v1.sql
-- 对象类型RLS 策略
-- 版本v1
-- 说明:管理端全量权限通过 SECURITY DEFINER RPC 执行;用户仅能访问个人关联数据
-- =====================================================================================
-- 启用 RLS
ALTER TABLE public.ak_distribution_config ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_distribution_level ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_promoter_relations ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_commission_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_distribution_divisions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_distribution_agents ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ak_distribution_agent_applications ENABLE ROW LEVEL SECURITY;
-- 1. 分销配置:允许所有登录用户读取(消费者端展示逻辑需要)
DROP POLICY IF EXISTS dist_config_select_policy ON public.ak_distribution_config;
CREATE POLICY dist_config_select_policy ON public.ak_distribution_config
FOR SELECT TO authenticated USING (true);
-- 2. 分销等级:允许所有登录用户读取可见等级
DROP POLICY IF EXISTS dist_level_select_policy ON public.ak_distribution_level;
CREATE POLICY dist_level_select_policy ON public.ak_distribution_level
FOR SELECT TO authenticated USING (is_visible = true);
-- 3. 推广员关系:用户仅能查看与自己相关的记录
DROP POLICY IF EXISTS promoter_relations_select_policy ON public.ak_promoter_relations;
CREATE POLICY promoter_relations_select_policy ON public.ak_promoter_relations
FOR SELECT TO authenticated USING (uid = auth.uid() OR inviter_uid = auth.uid());
-- 4. 佣金日志:用户仅能查看自己的佣金记录
DROP POLICY IF EXISTS commission_logs_select_policy ON public.ak_commission_logs;
CREATE POLICY commission_logs_select_policy ON public.ak_commission_logs
FOR SELECT TO authenticated USING (uid = auth.uid());
-- 5. 事业部与代理商:允许登录用户查看启用的记录
DROP POLICY IF EXISTS dist_divisions_select_policy ON public.ak_distribution_divisions;
CREATE POLICY dist_divisions_select_policy ON public.ak_distribution_divisions
FOR SELECT TO authenticated USING (is_enabled = true);
DROP POLICY IF EXISTS dist_agents_select_policy ON public.ak_distribution_agents;
CREATE POLICY dist_agents_select_policy ON public.ak_distribution_agents
FOR SELECT TO authenticated USING (is_enabled = true);
-- 6. 代理商申请:用户仅能管理自己的申请记录
DROP POLICY IF EXISTS dist_apply_user_policy ON public.ak_distribution_agent_applications;
CREATE POLICY dist_apply_user_policy ON public.ak_distribution_agent_applications
FOR ALL TO authenticated USING (uid = auth.uid()) WITH CHECK (uid = auth.uid());
-- 管理端全量管理将通过 SECURITY DEFINER 的 RPC 接口执行,此处不再额外开放直接表操作

View File

@@ -0,0 +1,31 @@
-- RPC: rpc_admin_delete_agent
-- 管理端删除代理商
CREATE OR REPLACE FUNCTION public.rpc_admin_delete_agent(
p_uid uuid
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_ok boolean;
BEGIN
-- 仅管理员可操作
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role = 'admin'
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
DELETE FROM public.ak_distribution_agents WHERE uid = p_uid;
GET DIAGNOSTICS v_ok = ROW_COUNT;
RETURN v_ok;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_delete_agent(uuid) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_agent(uuid) TO authenticated;

View File

@@ -0,0 +1,38 @@
-- RPC: rpc_admin_delete_division
-- 管理端删除事业部
CREATE OR REPLACE FUNCTION public.rpc_admin_delete_division(
p_uid uuid
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_ok boolean;
BEGIN
-- 仅管理员可操作
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role = 'admin'
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
-- 检查是否有关联代理商
IF EXISTS (
SELECT 1 FROM public.ak_distribution_agents WHERE division_uid = p_uid
) THEN
RAISE EXCEPTION 'cannot delete division with associated agents';
END IF;
DELETE FROM public.ak_distribution_divisions WHERE uid = p_uid;
GET DIAGNOSTICS v_ok = ROW_COUNT;
RETURN v_ok;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_delete_division(uuid) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_division(uuid) TO authenticated;

View File

@@ -0,0 +1,68 @@
-- RPC: rpc_admin_get_agent_apply_list
-- 管理端获取代理商申请列表
-- 支持按状态过滤all, pending, approved, rejected
CREATE OR REPLACE FUNCTION public.rpc_admin_get_agent_apply_list(
p_status text DEFAULT 'all',
p_search text DEFAULT NULL,
p_page integer DEFAULT 1,
p_page_size integer DEFAULT 20
)
RETURNS TABLE (
id uuid,
uid uuid,
name text,
phone text,
dept_uid uuid,
dept_name text,
proof_images jsonb,
status text,
refusal_reason text,
time timestamptz,
invite_code text
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_page integer := GREATEST(1, COALESCE(p_page, 1));
v_page_size integer := LEAST(200, GREATEST(1, COALESCE(p_page_size, 20)));
v_offset integer := (v_page - 1) * v_page_size;
BEGIN
-- 权限检查
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role IN ('admin', 'analytics')
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
RETURN QUERY
SELECT
a.id,
a.uid,
a.agent_name AS name,
a.agent_phone AS phone,
a.division_uid AS dept_uid,
d.name AS dept_name,
a.proof_images,
a.status,
a.refusal_reason,
a.created_at AS time,
d.invite_code
FROM public.ak_distribution_agent_applications a
JOIN public.ak_distribution_divisions d ON d.uid = a.division_uid
WHERE (p_status = 'all' OR a.status = p_status)
AND (
p_search IS NULL OR p_search = ''
OR a.agent_name ILIKE ('%' || p_search || '%')
OR a.uid::text ILIKE ('%' || p_search || '%')
)
ORDER BY a.created_at DESC
LIMIT v_page_size OFFSET v_offset;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_get_agent_apply_list(text, text, integer, integer) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_get_agent_apply_list(text, text, integer, integer) TO authenticated;

View File

@@ -0,0 +1,62 @@
-- RPC: rpc_admin_get_agent_list
-- 管理端获取代理商列表
-- 支持搜索代理商名称或负责人UID并关联显示所属事业部信息
CREATE OR REPLACE FUNCTION public.rpc_admin_get_agent_list(
p_search text DEFAULT NULL,
p_page integer DEFAULT 1,
p_page_size integer DEFAULT 20
)
RETURNS TABLE (
uid uuid,
name text,
division_uid uuid,
division_name text,
commission_ratio numeric,
is_enabled boolean,
end_time timestamptz,
created_at timestamptz,
"staffCount" bigint
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_page integer := GREATEST(1, COALESCE(p_page, 1));
v_page_size integer := LEAST(200, GREATEST(1, COALESCE(p_page_size, 20)));
v_offset integer := (v_page - 1) * v_page_size;
BEGIN
-- 权限检查
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role IN ('admin', 'analytics')
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
RETURN QUERY
SELECT
a.uid,
a.name,
a.division_uid,
d.name AS division_name,
a.commission_ratio,
a.is_enabled,
a.end_time,
a.created_at,
(SELECT COUNT(*) FROM public.ak_promoter_relations r WHERE r.inviter_uid = a.uid)::bigint AS "staffCount"
FROM public.ak_distribution_agents a
JOIN public.ak_distribution_divisions d ON d.uid = a.division_uid
WHERE (
p_search IS NULL OR p_search = ''
OR a.name ILIKE ('%' || p_search || '%')
OR a.uid::text ILIKE ('%' || p_search || '%')
)
ORDER BY a.created_at DESC
LIMIT v_page_size OFFSET v_offset;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_get_agent_list(text, integer, integer) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_get_agent_list(text, integer, integer) TO authenticated;

View File

@@ -0,0 +1,59 @@
-- RPC: rpc_admin_get_division_list
-- 管理端获取事业部列表
-- 支持搜索事业部名称或负责人UID
CREATE OR REPLACE FUNCTION public.rpc_admin_get_division_list(
p_search text DEFAULT NULL,
p_page integer DEFAULT 1,
p_page_size integer DEFAULT 20
)
RETURNS TABLE (
uid uuid,
name text,
invite_code text,
commission_ratio numeric,
is_enabled boolean,
end_time timestamptz,
created_at timestamptz,
"agentCount" bigint
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_page integer := GREATEST(1, COALESCE(p_page, 1));
v_page_size integer := LEAST(200, GREATEST(1, COALESCE(p_page_size, 20)));
v_offset integer := (v_page - 1) * v_page_size;
BEGIN
-- 仅管理员或分析员可调用
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role IN ('admin', 'analytics')
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
RETURN QUERY
SELECT
d.uid,
d.name,
d.invite_code,
d.commission_ratio,
d.is_enabled,
d.end_time,
d.created_at,
(SELECT COUNT(*) FROM public.ak_distribution_agents a WHERE a.division_uid = d.uid)::bigint AS "agentCount"
FROM public.ak_distribution_divisions d
WHERE (
p_search IS NULL OR p_search = ''
OR d.name ILIKE ('%' || p_search || '%')
OR d.uid::text ILIKE ('%' || p_search || '%')
)
ORDER BY d.created_at DESC
LIMIT v_page_size OFFSET v_offset;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_get_division_list(text, integer, integer) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_get_division_list(text, integer, integer) TO authenticated;

View File

@@ -0,0 +1,69 @@
-- RPC: rpc_admin_process_agent_apply
-- 管理端审核代理商申请
-- 若通过(approved),则同步在 ak_distribution_agents 中创建或更新记录
CREATE OR REPLACE FUNCTION public.rpc_admin_process_agent_apply(
p_id uuid,
p_status text, -- approved / rejected
p_refusal_reason text DEFAULT NULL
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_uid uuid;
v_division_uid uuid;
v_agent_name text;
BEGIN
-- 仅管理员可审核
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role = 'admin'
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
-- 1. 获取并锁定申请记录
SELECT uid, division_uid, agent_name
INTO v_uid, v_division_uid, v_agent_name
FROM public.ak_distribution_agent_applications
WHERE id = p_id;
IF v_uid IS NULL THEN
RAISE EXCEPTION 'application record not found';
END IF;
-- 2. 更新申请状态
UPDATE public.ak_distribution_agent_applications
SET
status = p_status,
refusal_reason = CASE WHEN p_status = 'rejected' THEN p_refusal_reason ELSE NULL END,
approved_at = now(),
approved_by = auth.uid(),
updated_at = now()
WHERE id = p_id;
-- 3. 如果通过,则同步到代理商正式表
IF p_status = 'approved' THEN
INSERT INTO public.ak_distribution_agents (
uid, division_uid, name, commission_ratio, is_enabled, updated_at, updated_by
)
VALUES (
v_uid, v_division_uid, v_agent_name, 0, true, now(), auth.uid()
)
ON CONFLICT (uid) DO UPDATE
SET
division_uid = EXCLUDED.division_uid,
name = EXCLUDED.name,
updated_at = now(),
updated_by = auth.uid();
END IF;
RETURN true;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_process_agent_apply(uuid, text, text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_process_agent_apply(uuid, text, text) TO authenticated;

View File

@@ -0,0 +1,54 @@
-- RPC: rpc_admin_save_agent
-- 管理端新增或更新代理商
CREATE OR REPLACE FUNCTION public.rpc_admin_save_agent(
p_uid uuid,
p_division_uid uuid,
p_name text,
p_commission_ratio numeric,
p_is_enabled boolean DEFAULT true,
p_end_time timestamptz DEFAULT NULL
)
RETURNS uuid
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
-- 仅管理员可操作
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role = 'admin'
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
-- 确保事业部存在
IF NOT EXISTS (
SELECT 1 FROM public.ak_distribution_divisions WHERE uid = p_division_uid
) THEN
RAISE EXCEPTION 'parent division not found';
END IF;
INSERT INTO public.ak_distribution_agents (
uid, division_uid, name, commission_ratio, is_enabled, end_time, updated_at, updated_by
)
VALUES (
p_uid, p_division_uid, p_name, p_commission_ratio, p_is_enabled, p_end_time, now(), auth.uid()
)
ON CONFLICT (uid) DO UPDATE
SET
division_uid = EXCLUDED.division_uid,
name = EXCLUDED.name,
commission_ratio = EXCLUDED.commission_ratio,
is_enabled = EXCLUDED.is_enabled,
end_time = EXCLUDED.end_time,
updated_at = now(),
updated_by = auth.uid();
RETURN p_uid;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_save_agent(uuid, uuid, text, numeric, boolean, timestamptz) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_save_agent(uuid, uuid, text, numeric, boolean, timestamptz) TO authenticated;

View File

@@ -0,0 +1,47 @@
-- RPC: rpc_admin_save_division
-- 管理端新增或更新事业部
CREATE OR REPLACE FUNCTION public.rpc_admin_save_division(
p_uid uuid,
p_name text,
p_invite_code text,
p_commission_ratio numeric,
p_is_enabled boolean DEFAULT true,
p_end_time timestamptz DEFAULT NULL
)
RETURNS uuid
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
-- 仅管理员可操作
IF NOT EXISTS (
SELECT 1 FROM public.ak_users u
WHERE u.id = auth.uid() AND u.role = 'admin'
) THEN
RAISE EXCEPTION 'permission denied';
END IF;
INSERT INTO public.ak_distribution_divisions (
uid, name, invite_code, commission_ratio, is_enabled, end_time, updated_at, updated_by
)
VALUES (
p_uid, p_name, p_invite_code, p_commission_ratio, p_is_enabled, p_end_time, now(), auth.uid()
)
ON CONFLICT (uid) DO UPDATE
SET
name = EXCLUDED.name,
invite_code = EXCLUDED.invite_code,
commission_ratio = EXCLUDED.commission_ratio,
is_enabled = EXCLUDED.is_enabled,
end_time = EXCLUDED.end_time,
updated_at = now(),
updated_by = auth.uid();
RETURN p_uid;
END;
$$;
REVOKE ALL ON FUNCTION public.rpc_admin_save_division(uuid, text, text, numeric, boolean, timestamptz) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.rpc_admin_save_division(uuid, text, text, numeric, boolean, timestamptz) TO authenticated;