feat(admin): implement user level, group and label modules with database, rpc and ui
This commit is contained in:
30
docs/sql/10_schema/user/ak_user_groups_v1.sql
Normal file
30
docs/sql/10_schema/user/ak_user_groups_v1.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
-- =====================================================================================
|
||||
-- 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);
|
||||
33
docs/sql/10_schema/user/ak_user_labels_v1.sql
Normal file
33
docs/sql/10_schema/user/ak_user_labels_v1.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- =====================================================================================
|
||||
-- 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);
|
||||
55
docs/sql/10_schema/user/ak_user_levels_v1.sql
Normal file
55
docs/sql/10_schema/user/ak_user_levels_v1.sql
Normal file
@@ -0,0 +1,55 @@
|
||||
-- =====================================================================================
|
||||
-- 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;
|
||||
12
docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
Normal file
12
docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- =====================================================================================
|
||||
-- RLS: 用户分组表
|
||||
-- 位置:docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
|
||||
-- 对象类型:RLS 策略
|
||||
-- 版本:v1
|
||||
-- 说明:管理端全量访问通过 RPC 完成;消费者端默认不开放直接访问
|
||||
-- =====================================================================================
|
||||
|
||||
ALTER TABLE public.ak_user_groups ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 如果未来消费者端需要展示所在分组,可以在此添加对应的 SELECT 策略
|
||||
-- 目前默认不向普通用户开放任何直接 SQL 读写权限
|
||||
12
docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
Normal file
12
docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- =====================================================================================
|
||||
-- RLS: 用户标签表
|
||||
-- 位置:docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
|
||||
-- 对象类型:RLS 策略
|
||||
-- 版本:v1
|
||||
-- 说明:管理端全量访问通过 RPC 完成;消费者端默认不开放直接访问
|
||||
-- =====================================================================================
|
||||
|
||||
ALTER TABLE public.ak_user_labels ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 若后续消费者端需要展示标签,可在此添加 SELECT 策略
|
||||
-- 当前默认不向普通用户开放任何直接 SQL 读写权限
|
||||
23
docs/sql/20_rls/user/ak_user_levels_rls_v1.sql
Normal file
23
docs/sql/20_rls/user/ak_user_levels_rls_v1.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- =====================================================================================
|
||||
-- RLS: 用户等级表
|
||||
-- 位置:docs/sql/20_rls/user/
|
||||
-- 对象类型:RLS 策略
|
||||
-- 版本:v1
|
||||
-- 说明:消费者端可读(仅可见/启用/未删除);管理端全量访问通过 RPC 完成
|
||||
-- =====================================================================================
|
||||
|
||||
ALTER TABLE public.ak_user_levels ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 消费者端:允许读取可见且启用的等级(未删除)
|
||||
DROP POLICY IF EXISTS ak_user_levels_public_select_visible_active ON public.ak_user_levels;
|
||||
CREATE POLICY ak_user_levels_public_select_visible_active
|
||||
ON public.ak_user_levels
|
||||
FOR SELECT
|
||||
TO anon, authenticated
|
||||
USING (
|
||||
deleted_at IS NULL
|
||||
AND status = 1
|
||||
AND is_visible = TRUE
|
||||
);
|
||||
|
||||
-- 默认不开放写权限(INSERT/UPDATE/DELETE)给 anon/authenticated
|
||||
36
docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql
Normal file
36
docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_group_delete
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:逻辑删除用户分组(设置 deleted_at)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_group_delete(
|
||||
p_id UUID
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 逻辑删除
|
||||
UPDATE public.ak_user_groups
|
||||
SET deleted_at = now(), updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
60
docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql
Normal file
60
docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql
Normal file
@@ -0,0 +1,60 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_group_list
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:管理端分页获取用户分组列表,支持搜索、状态筛选及逻辑删除过滤
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_group_list(
|
||||
p_page INT,
|
||||
p_page_size INT,
|
||||
p_search TEXT DEFAULT NULL,
|
||||
p_status INT DEFAULT NULL,
|
||||
p_include_deleted BOOLEAN DEFAULT FALSE
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_total INT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ak_user_groups
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%' OR remark ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status);
|
||||
|
||||
-- 3. 分页获取数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
id, name, remark, status,
|
||||
created_at, updated_at, deleted_at
|
||||
FROM public.ak_user_groups
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%' OR remark ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status)
|
||||
ORDER BY created_at DESC
|
||||
LIMIT p_page_size
|
||||
OFFSET (p_page - 1) * p_page_size
|
||||
) t;
|
||||
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
66
docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql
Normal file
66
docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql
Normal file
@@ -0,0 +1,66 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_group_save
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:新增/更新用户分组(逻辑删除记录默认不允许更新)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_group_save(
|
||||
p_id UUID DEFAULT NULL,
|
||||
p_name TEXT,
|
||||
p_remark TEXT DEFAULT NULL,
|
||||
p_status INT DEFAULT 1
|
||||
)
|
||||
RETURNS UUID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id UUID;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 参数校验
|
||||
IF p_name IS NULL OR length(trim(p_name)) = 0 THEN
|
||||
RAISE EXCEPTION 'Invalid name';
|
||||
END IF;
|
||||
|
||||
-- 3. 新增
|
||||
IF p_id IS NULL THEN
|
||||
INSERT INTO public.ak_user_groups(
|
||||
name, remark, status,
|
||||
created_at, updated_at, deleted_at
|
||||
) VALUES (
|
||||
p_name, p_remark, COALESCE(p_status, 1),
|
||||
now(), now(), NULL
|
||||
)
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
RETURN v_id;
|
||||
END IF;
|
||||
|
||||
-- 4. 更新(不允许更新已删除记录)
|
||||
UPDATE public.ak_user_groups
|
||||
SET
|
||||
name = p_name,
|
||||
remark = p_remark,
|
||||
status = COALESCE(p_status, status),
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
IF v_id IS NULL THEN
|
||||
RAISE EXCEPTION 'Not found or deleted';
|
||||
END IF;
|
||||
|
||||
RETURN v_id;
|
||||
END;
|
||||
$$;
|
||||
37
docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql
Normal file
37
docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_group_set_status
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:设置用户分组状态(启用/禁用)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_group_set_status(
|
||||
p_id UUID,
|
||||
p_status INT
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
UPDATE public.ak_user_groups
|
||||
SET status = p_status,
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
36
docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql
Normal file
36
docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_label_delete
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:逻辑删除用户标签(设置 deleted_at)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_label_delete(
|
||||
p_id UUID
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 逻辑删除
|
||||
UPDATE public.ak_user_labels
|
||||
SET deleted_at = now(), updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
60
docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql
Normal file
60
docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql
Normal file
@@ -0,0 +1,60 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_label_list
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:管理端分页获取用户标签列表,支持搜索、状态筛选及逻辑删除过滤
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_label_list(
|
||||
p_page INT,
|
||||
p_page_size INT,
|
||||
p_search TEXT DEFAULT NULL,
|
||||
p_status INT DEFAULT NULL,
|
||||
p_include_deleted BOOLEAN DEFAULT FALSE
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_total INT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ak_user_labels
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%' OR remark ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status);
|
||||
|
||||
-- 3. 分页获取数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
id, name, color, remark, status,
|
||||
created_at, updated_at, deleted_at
|
||||
FROM public.ak_user_labels
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%' OR remark ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status)
|
||||
ORDER BY created_at DESC
|
||||
LIMIT p_page_size
|
||||
OFFSET (p_page - 1) * p_page_size
|
||||
) t;
|
||||
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
68
docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql
Normal file
68
docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql
Normal file
@@ -0,0 +1,68 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_label_save
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:新增/更新用户标签(逻辑删除记录默认不允许更新)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_label_save(
|
||||
p_id UUID DEFAULT NULL,
|
||||
p_name TEXT,
|
||||
p_color TEXT DEFAULT NULL,
|
||||
p_remark TEXT DEFAULT NULL,
|
||||
p_status INT DEFAULT 1
|
||||
)
|
||||
RETURNS UUID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id UUID;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 参数校验
|
||||
IF p_name IS NULL OR length(trim(p_name)) = 0 THEN
|
||||
RAISE EXCEPTION 'Invalid name';
|
||||
END IF;
|
||||
|
||||
-- 3. 新增
|
||||
IF p_id IS NULL THEN
|
||||
INSERT INTO public.ak_user_labels(
|
||||
name, color, remark, status,
|
||||
created_at, updated_at, deleted_at
|
||||
) VALUES (
|
||||
p_name, p_color, p_remark, COALESCE(p_status, 1),
|
||||
now(), now(), NULL
|
||||
)
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
RETURN v_id;
|
||||
END IF;
|
||||
|
||||
-- 4. 更新(不允许更新已删除记录)
|
||||
UPDATE public.ak_user_labels
|
||||
SET
|
||||
name = p_name,
|
||||
color = p_color,
|
||||
remark = p_remark,
|
||||
status = COALESCE(p_status, status),
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
IF v_id IS NULL THEN
|
||||
RAISE EXCEPTION 'Not found or deleted';
|
||||
END IF;
|
||||
|
||||
RETURN v_id;
|
||||
END;
|
||||
$$;
|
||||
37
docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql
Normal file
37
docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_label_set_status
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:设置用户标签状态(启用/禁用)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_label_set_status(
|
||||
p_id UUID,
|
||||
p_status INT
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
UPDATE public.ak_user_labels
|
||||
SET status = p_status,
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
36
docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql
Normal file
36
docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_level_delete
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:逻辑删除用户等级(设置 deleted_at)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_level_delete(
|
||||
p_id UUID
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 逻辑删除
|
||||
UPDATE public.ak_user_levels
|
||||
SET deleted_at = now(), updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
64
docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql
Normal file
64
docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_level_list
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:管理端分页获取用户等级列表,支持搜索、状态筛选及逻辑删除过滤
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_level_list(
|
||||
p_page INT,
|
||||
p_page_size INT,
|
||||
p_search TEXT DEFAULT NULL,
|
||||
p_status INT DEFAULT NULL,
|
||||
p_is_visible BOOLEAN DEFAULT NULL,
|
||||
p_include_deleted BOOLEAN DEFAULT FALSE
|
||||
)
|
||||
RETURNS JSONB
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_total INT;
|
||||
v_items JSONB;
|
||||
BEGIN
|
||||
-- 1. 权限检查 (依赖 public.get_current_user_role())
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 获取总数
|
||||
SELECT COUNT(*) INTO v_total
|
||||
FROM public.ak_user_levels
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status)
|
||||
AND (p_is_visible IS NULL OR is_visible = p_is_visible);
|
||||
|
||||
-- 3. 分页获取数据
|
||||
SELECT jsonb_agg(t) INTO v_items
|
||||
FROM (
|
||||
SELECT
|
||||
id, name, level_weight, min_experience, discount_percent,
|
||||
is_visible, status, icon_url, bg_image_url, bg_style_json,
|
||||
remark, created_at, updated_at, deleted_at
|
||||
FROM public.ak_user_levels
|
||||
WHERE (p_include_deleted OR deleted_at IS NULL)
|
||||
AND (p_search IS NULL OR name ILIKE '%' || p_search || '%')
|
||||
AND (p_status IS NULL OR status = p_status)
|
||||
AND (p_is_visible IS NULL OR is_visible = p_is_visible)
|
||||
ORDER BY level_weight ASC
|
||||
LIMIT p_page_size
|
||||
OFFSET (p_page - 1) * p_page_size
|
||||
) t;
|
||||
|
||||
RETURN jsonb_build_object(
|
||||
'total', v_total,
|
||||
'items', COALESCE(v_items, '[]'::jsonb)
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
94
docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql
Normal file
94
docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql
Normal file
@@ -0,0 +1,94 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_level_save
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:新增/更新用户等级(逻辑删除记录默认不允许更新)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_level_save(
|
||||
p_id UUID DEFAULT NULL,
|
||||
p_name TEXT,
|
||||
p_level_weight INT,
|
||||
p_min_experience INT,
|
||||
p_discount_percent INT,
|
||||
p_is_visible BOOLEAN,
|
||||
p_status INT,
|
||||
p_icon_url TEXT DEFAULT NULL,
|
||||
p_bg_image_url TEXT DEFAULT NULL,
|
||||
p_bg_style_json JSONB DEFAULT NULL,
|
||||
p_remark TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS UUID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id UUID;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
-- 2. 参数校验(最小化)
|
||||
IF p_name IS NULL OR length(trim(p_name)) = 0 THEN
|
||||
RAISE EXCEPTION 'Invalid name';
|
||||
END IF;
|
||||
|
||||
IF p_level_weight < 0 OR p_min_experience < 0 THEN
|
||||
RAISE EXCEPTION 'Invalid level_weight or min_experience';
|
||||
END IF;
|
||||
|
||||
IF p_discount_percent < 1 OR p_discount_percent > 100 THEN
|
||||
RAISE EXCEPTION 'Invalid discount_percent';
|
||||
END IF;
|
||||
|
||||
-- 3. 新增
|
||||
IF p_id IS NULL THEN
|
||||
INSERT INTO public.ak_user_levels(
|
||||
name, level_weight, min_experience, discount_percent,
|
||||
is_visible, status,
|
||||
icon_url, bg_image_url, bg_style_json,
|
||||
remark,
|
||||
created_at, updated_at, deleted_at
|
||||
) VALUES (
|
||||
p_name, p_level_weight, p_min_experience, p_discount_percent,
|
||||
p_is_visible, p_status,
|
||||
p_icon_url, p_bg_image_url, p_bg_style_json,
|
||||
p_remark,
|
||||
now(), now(), NULL
|
||||
)
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
RETURN v_id;
|
||||
END IF;
|
||||
|
||||
-- 4. 更新(不允许更新已删除记录)
|
||||
UPDATE public.ak_user_levels
|
||||
SET
|
||||
name = p_name,
|
||||
level_weight = p_level_weight,
|
||||
min_experience = p_min_experience,
|
||||
discount_percent = p_discount_percent,
|
||||
is_visible = p_is_visible,
|
||||
status = p_status,
|
||||
icon_url = p_icon_url,
|
||||
bg_image_url = p_bg_image_url,
|
||||
bg_style_json = p_bg_style_json,
|
||||
remark = p_remark,
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL
|
||||
RETURNING id INTO v_id;
|
||||
|
||||
IF v_id IS NULL THEN
|
||||
RAISE EXCEPTION 'Not found or deleted';
|
||||
END IF;
|
||||
|
||||
RETURN v_id;
|
||||
END;
|
||||
$$;
|
||||
37
docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql
Normal file
37
docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_level_set_status
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:设置用户等级状态(启用/禁用)
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_level_set_status(
|
||||
p_id UUID,
|
||||
p_status INT
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
UPDATE public.ak_user_levels
|
||||
SET status = p_status,
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
37
docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql
Normal file
37
docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- =====================================================================================
|
||||
-- RPC: rpc_admin_user_level_set_visible
|
||||
-- 位置:docs/sql/30_rpc/user/
|
||||
-- 对象类型:RPC 函数 (SECURITY DEFINER)
|
||||
-- 版本:v1
|
||||
-- 说明:设置用户等级是否展示
|
||||
-- =====================================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_admin_user_level_set_visible(
|
||||
p_id UUID,
|
||||
p_is_visible BOOLEAN
|
||||
)
|
||||
RETURNS BOOLEAN
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_ok BOOLEAN;
|
||||
BEGIN
|
||||
-- 1. 权限检查
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM public.ak_users
|
||||
WHERE auth_id = auth.uid() AND role IN ('admin', 'analytics')
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
UPDATE public.ak_user_levels
|
||||
SET is_visible = p_is_visible,
|
||||
updated_at = now()
|
||||
WHERE id = p_id AND deleted_at IS NULL;
|
||||
|
||||
GET DIAGNOSTICS v_ok = ROW_COUNT;
|
||||
RETURN v_ok;
|
||||
END;
|
||||
$$;
|
||||
Reference in New Issue
Block a user