admin接入数据库
This commit is contained in:
@@ -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)';
|
||||
@@ -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 '代理商固定分佣比例(%)';
|
||||
|
||||
@@ -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 '事业部有效截止时间';
|
||||
|
||||
52
docs/sql/20_rls/distribution/ml_distribution_rls_v1.sql
Normal file
52
docs/sql/20_rls/distribution/ml_distribution_rls_v1.sql
Normal 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 接口执行,此处不再额外开放直接表操作
|
||||
31
docs/sql/30_rpc/distribution/rpc_admin_delete_agent_v1.sql
Normal file
31
docs/sql/30_rpc/distribution/rpc_admin_delete_agent_v1.sql
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
62
docs/sql/30_rpc/distribution/rpc_admin_get_agent_list_v1.sql
Normal file
62
docs/sql/30_rpc/distribution/rpc_admin_get_agent_list_v1.sql
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
54
docs/sql/30_rpc/distribution/rpc_admin_save_agent_v1.sql
Normal file
54
docs/sql/30_rpc/distribution/rpc_admin_save_agent_v1.sql
Normal 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;
|
||||
47
docs/sql/30_rpc/distribution/rpc_admin_save_division_v1.sql
Normal file
47
docs/sql/30_rpc/distribution/rpc_admin_save_division_v1.sql
Normal 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;
|
||||
Reference in New Issue
Block a user