From 47968565a5da4d6a916965398c861e5440cb7d09 Mon Sep 17 00:00:00 2001
From: comlibmb <1844410276@qq.com>
Date: Tue, 10 Feb 2026 20:34:45 +0800
Subject: [PATCH] feat(admin): implement user level, group and label modules
with database, rpc and ui
---
...2026-02-10__admin__user-group-db-and-ui.md | 31 ++
...2026-02-10__admin__user-label-db-and-ui.md | 31 ++
...2026-02-10__admin__user-level-db-design.md | 46 +++
docs/sql/10_schema/user/ak_user_groups_v1.sql | 30 ++
docs/sql/10_schema/user/ak_user_labels_v1.sql | 33 ++
docs/sql/10_schema/user/ak_user_levels_v1.sql | 55 +++
.../sql/20_rls/user/ak_user_groups_rls_v1.sql | 12 +
.../sql/20_rls/user/ak_user_labels_rls_v1.sql | 12 +
.../sql/20_rls/user/ak_user_levels_rls_v1.sql | 23 ++
.../user/rpc_admin_user_group_delete_v1.sql | 36 ++
.../user/rpc_admin_user_group_list_v1.sql | 60 +++
.../user/rpc_admin_user_group_save_v1.sql | 66 ++++
.../rpc_admin_user_group_set_status_v1.sql | 37 ++
.../user/rpc_admin_user_label_delete_v1.sql | 36 ++
.../user/rpc_admin_user_label_list_v1.sql | 60 +++
.../user/rpc_admin_user_label_save_v1.sql | 68 ++++
.../rpc_admin_user_label_set_status_v1.sql | 37 ++
.../user/rpc_admin_user_level_delete_v1.sql | 36 ++
.../user/rpc_admin_user_level_list_v1.sql | 64 ++++
.../user/rpc_admin_user_level_save_v1.sql | 94 +++++
.../rpc_admin_user_level_set_status_v1.sql | 37 ++
.../rpc_admin_user_level_set_visible_v1.sql | 37 ++
pages/mall/admin/user/group.uvue | 304 ++++++++++++---
pages/mall/admin/user/label.uvue | 348 ++++++++++++++----
pages/mall/admin/user/level.uvue | 160 ++++++--
services/admin/userGroupService.uts | 91 +++++
services/admin/userLabelService.uts | 82 +++++
services/admin/userLevelService.uts | 110 ++++++
28 files changed, 1896 insertions(+), 140 deletions(-)
create mode 100644 docs/ops/2026-02-10__admin__user-group-db-and-ui.md
create mode 100644 docs/ops/2026-02-10__admin__user-label-db-and-ui.md
create mode 100644 docs/ops/2026-02-10__admin__user-level-db-design.md
create mode 100644 docs/sql/10_schema/user/ak_user_groups_v1.sql
create mode 100644 docs/sql/10_schema/user/ak_user_labels_v1.sql
create mode 100644 docs/sql/10_schema/user/ak_user_levels_v1.sql
create mode 100644 docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
create mode 100644 docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
create mode 100644 docs/sql/20_rls/user/ak_user_levels_rls_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql
create mode 100644 docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql
create mode 100644 services/admin/userGroupService.uts
create mode 100644 services/admin/userLabelService.uts
create mode 100644 services/admin/userLevelService.uts
diff --git a/docs/ops/2026-02-10__admin__user-group-db-and-ui.md b/docs/ops/2026-02-10__admin__user-group-db-and-ui.md
new file mode 100644
index 00000000..76a6a54c
--- /dev/null
+++ b/docs/ops/2026-02-10__admin__user-group-db-and-ui.md
@@ -0,0 +1,31 @@
+# 用户分组数据库设计与 RPC (v1)
+
+## 摘要
+为“用户分组”功能新增数据库表 `public.ak_user_groups`(支持逻辑删除),并提供管理端 RPC(分页列表/保存/删除/状态切换)。同时启用 RLS,默认仅允许管理端通过 RPC 访问。
+
+## 动机
+- 完善用户精细化运营体系,支持对用户进行分组分类。
+- 替换前端 `pages/mall/admin/user/group.uvue` 中的硬编码 Mock 数据,实现真实数据持久化与完整交互。
+
+## 影响范围
+- 数据库:新增 `ak_user_groups` 表及相关索引、RLS 策略、4 个管理端 RPC。
+- 前端:新增 `userGroupService.uts`,重构 `group.uvue` 页面。
+
+## 变更清单
+- 数据库 SQL:
+ - `docs/sql/10_schema/user/ak_user_groups_v1.sql`
+ - `docs/sql/20_rls/user/ak_user_groups_rls_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql`
+- 前端代码:
+ - `services/admin/userGroupService.uts`
+ - `pages/mall/admin/user/group.uvue`
+
+## 兼容性与风险
+- 逻辑删除:采用 `deleted_at` 字段,确保历史关联数据不被物理破坏。
+- 安全性:所有管理操作均通过 `SECURITY DEFINER` RPC 并校验 `admin/analytics` 角色。
+
+## 验证方式
+- 执行 SQL 后,通过 Admin 端的“用户分组”菜单进行增删改查操作,观察数据库及界面响应。
diff --git a/docs/ops/2026-02-10__admin__user-label-db-and-ui.md b/docs/ops/2026-02-10__admin__user-label-db-and-ui.md
new file mode 100644
index 00000000..d6b7042c
--- /dev/null
+++ b/docs/ops/2026-02-10__admin__user-label-db-and-ui.md
@@ -0,0 +1,31 @@
+# 用户标签数据库设计与 RPC (v1)
+
+## 摘要
+为“用户标签”功能新增数据库表 `public.ak_user_labels`(支持逻辑删除),并提供管理端 RPC(分页列表/保存/删除/状态切换)。同时启用 RLS,默认仅允许管理端通过 RPC 访问。
+
+## 动机
+- 完善用户画像体系,支持对用户进行行为特征标记。
+- 替换前端 `pages/mall/admin/user/label.uvue` 中的硬编码 Mock 数据,实现真实数据持久化。
+
+## 影响范围
+- 数据库:新增 `ak_user_labels` 表及相关索引、RLS 策略、4 个管理端 RPC。
+- 前端:新增 `userLabelService.uts`,重构 `label.uvue` 页面。
+
+## 变更清单
+- 数据库 SQL:
+ - `docs/sql/10_schema/user/ak_user_labels_v1.sql`
+ - `docs/sql/20_rls/user/ak_user_labels_rls_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql`
+- 前端代码:
+ - `services/admin/userLabelService.uts`
+ - `pages/mall/admin/user/label.uvue`
+
+## 兼容性与风险
+- 逻辑删除:采用 `deleted_at` 字段,确保历史关联数据不被物理破坏。
+- 安全性:所有管理操作均通过 `SECURITY DEFINER` RPC 并校验 `admin/analytics` 角色。
+
+## 验证方式
+- 执行 SQL 后,通过 Admin 端的“用户标签”菜单进行增删改查操作,观察数据库及界面响应。
diff --git a/docs/ops/2026-02-10__admin__user-level-db-design.md b/docs/ops/2026-02-10__admin__user-level-db-design.md
new file mode 100644
index 00000000..8fd328a1
--- /dev/null
+++ b/docs/ops/2026-02-10__admin__user-level-db-design.md
@@ -0,0 +1,46 @@
+# 用户等级数据库设计与 RPC(v1)
+
+## 摘要
+为“用户等级”功能新增数据库表 `public.ak_user_levels`(支持逻辑删除),并提供 admin 侧管理 RPC(分页列表/保存/删除/状态切换/展示切换)。同时启用 RLS:消费者端仅可读取“启用且展示且未删除”的等级。
+
+## 动机
+- 当前 admin 用户等级页面存在硬编码 mock 数据,需要接入数据库。
+- 统一等级数据口径,为消费者端展示等级提供可靠数据源。
+
+## 影响范围
+- 数据库:新增表、索引;启用 RLS 并新增 select policy;新增 5 个 admin RPC。
+- 前端:后续可通过 `services/` 接入新 RPC,移除 `pages/mall/admin/user/level.uvue` 中 mock。
+
+## 变更清单
+- 新增文件:
+ - `docs/sql/10_schema/user/ak_user_levels_v1.sql`
+ - `docs/sql/20_rls/user/ak_user_levels_rls_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql`
+ - `docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql`
+
+## 兼容性与风险
+- consumer 端读取:RLS 仅开放 `anon/authenticated` 对可见/启用/未删除等级的 SELECT;不会暴露删除或禁用的数据。
+- admin 端管理:通过 `SECURITY DEFINER` RPC 并进行角色鉴权,避免直通表的全局权限。
+- 逻辑删除:通过 `deleted_at` 字段实现,避免历史引用破坏。
+
+## 回滚方案
+- 回滚 schema:删除表 `ak_user_levels`(需人工确认,不在本次脚本中提供)。
+- 回滚 rpc:删除对应函数(需人工确认,不在本次脚本中提供)。
+- 回滚 rls:移除 policy 并禁用 RLS(需人工确认)。
+
+## 验证方式
+- 在 SQL 控制台依次执行:schema -> rls -> rpc。
+- 使用 admin 账号调用:
+ - `rpc_admin_user_level_save` 创建数据
+ - `rpc_admin_user_level_list` 验证分页返回
+ - `rpc_admin_user_level_set_visible/status` 验证更新
+ - `rpc_admin_user_level_delete` 验证逻辑删除
+- 使用普通账号/匿名访问验证仅能看到启用且展示的数据。
+
+## 关联文档
+- `docs/project_spec/AGENT_PROJECT_SPEC.md`
+- `docs/sql/30_rpc/auth/get_current_user_role_v1.sql`
+- `docs/sql/11_roles_and_permissions_strategy.md`
diff --git a/docs/sql/10_schema/user/ak_user_groups_v1.sql b/docs/sql/10_schema/user/ak_user_groups_v1.sql
new file mode 100644
index 00000000..a4bc33f1
--- /dev/null
+++ b/docs/sql/10_schema/user/ak_user_groups_v1.sql
@@ -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);
diff --git a/docs/sql/10_schema/user/ak_user_labels_v1.sql b/docs/sql/10_schema/user/ak_user_labels_v1.sql
new file mode 100644
index 00000000..18513a91
--- /dev/null
+++ b/docs/sql/10_schema/user/ak_user_labels_v1.sql
@@ -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);
diff --git a/docs/sql/10_schema/user/ak_user_levels_v1.sql b/docs/sql/10_schema/user/ak_user_levels_v1.sql
new file mode 100644
index 00000000..4c0a1109
--- /dev/null
+++ b/docs/sql/10_schema/user/ak_user_levels_v1.sql
@@ -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;
diff --git a/docs/sql/20_rls/user/ak_user_groups_rls_v1.sql b/docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
new file mode 100644
index 00000000..8698205d
--- /dev/null
+++ b/docs/sql/20_rls/user/ak_user_groups_rls_v1.sql
@@ -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 读写权限
diff --git a/docs/sql/20_rls/user/ak_user_labels_rls_v1.sql b/docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
new file mode 100644
index 00000000..5df42930
--- /dev/null
+++ b/docs/sql/20_rls/user/ak_user_labels_rls_v1.sql
@@ -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 读写权限
diff --git a/docs/sql/20_rls/user/ak_user_levels_rls_v1.sql b/docs/sql/20_rls/user/ak_user_levels_rls_v1.sql
new file mode 100644
index 00000000..9171be0c
--- /dev/null
+++ b/docs/sql/20_rls/user/ak_user_levels_rls_v1.sql
@@ -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
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql
new file mode 100644
index 00000000..5fd60697
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql
new file mode 100644
index 00000000..686502c6
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_group_list_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql
new file mode 100644
index 00000000..8cae1bde
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_group_save_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql
new file mode 100644
index 00000000..c3ae3897
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_group_set_status_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql
new file mode 100644
index 00000000..04b397cf
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql
new file mode 100644
index 00000000..2a555b36
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_label_list_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql
new file mode 100644
index 00000000..47d12ed4
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_label_save_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql
new file mode 100644
index 00000000..ffd0f4dd
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_label_set_status_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql
new file mode 100644
index 00000000..aed3d544
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql
new file mode 100644
index 00000000..d83b6fed
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_level_list_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql
new file mode 100644
index 00000000..bf92d230
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_level_save_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql
new file mode 100644
index 00000000..70604a68
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_level_set_status_v1.sql
@@ -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;
+$$;
diff --git a/docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql b/docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql
new file mode 100644
index 00000000..f111341f
--- /dev/null
+++ b/docs/sql/30_rpc/user/rpc_admin_user_level_set_visible_v1.sql
@@ -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;
+$$;
diff --git a/pages/mall/admin/user/group.uvue b/pages/mall/admin/user/group.uvue
index 3ac2abab..7cce44ac 100644
--- a/pages/mall/admin/user/group.uvue
+++ b/pages/mall/admin/user/group.uvue
@@ -3,7 +3,12 @@
+
+
+
+
+
@@ -11,19 +16,29 @@
-
+ 加载中...
+ 暂无数据
+
{{ group.id }}
{{ group.name }}
+
+
+
+
+
+
修改
|
- 删除
+ 删除
@@ -31,19 +46,15 @@
@@ -66,9 +77,26 @@
class="form-input"
v-model="formData.name"
placeholder="请输入分组名称"
- autofocus
/>
+
+
+ 备注说明:
+
+
+
+
+
+ 状态:
+
+
+
+
+