diff --git a/docs/ops/2026-02-18__admin__auth-delivery-infrastructure-integration.md b/docs/ops/2026-02-18__admin__auth-delivery-infrastructure-integration.md new file mode 100644 index 00000000..3d60ec48 --- /dev/null +++ b/docs/ops/2026-02-18__admin__auth-delivery-infrastructure-integration.md @@ -0,0 +1,59 @@ +# 权限、物流及系统基础设施全量集成报告 + +## 摘要 +本次对 Admin 侧进行了大规模的基础设施补齐与核心管理模块重构。完成了权限管理(Auth/RBAC)、物流设置(Delivery Staff/Stations)、系统通用配置(ml_system_configs)以及数据概览(Statistic)与系统维护(Maintain)模块的端到端数据库接入。彻底解决了这些模块此前长期存在的 Mock 问题。 + +## 动机 +虽然商城的业务模块(商品、订单等)已基本闭环,但支撑系统运行的“底座”模块(权限控制、系统开关、物流资源等)仍处于静态模拟阶段。为了实现生产级的管理后台,必须建立统一的配置存储体系、完善的权限分配机制以及真实的物流资源管理。 + +## 影响范围 +- **核心底座**:系统配置读写、全站聚合统计。 +- **权限安全**:角色管理、菜单权限树配置、管理员分配。 +- **物流资源**:配送员库、提货点/核销点管理。 +- **应用配置**:公众号、小程序、APP 及 PC 端参数持久化。 + +## 变更清单 + +### 1. 数据库资产 (SQL) +- **Schema (10_schema)**: + - `admin/ml_system_configs_v1.sql`: 统一配置表。 + - `user/ak_auth_system_v1.sql`: 角色、权限、关联表 (RBAC)。 + - `delivery/ak_delivery_system_v1.sql`: 配送员、提货点表。 +- **RLS (20_rls)**: + - `admin/ml_system_configs_rls_v1.sql` + - `auth/ak_auth_rls_v1.sql` + - `delivery/ak_delivery_rls_v1.sql` +- **RPC (30_rpc)**: + - **Admin**: `rpc_admin_system_config_get/save`, `rpc_admin_get_overall_stats`, `rpc_admin_get_system_info`。 + - **Auth**: `rpc_admin_get_admin_list`, `rpc_admin_get_role_list/save/delete`, `rpc_admin_get_permission_list/save/delete`。 + - **Delivery**: 配送员管理 (list/save/delete)、提货点管理 (list/save/delete)。 + +### 2. 前端服务层 (UTS) +- `services/admin/systemConfigService.uts` (新增) +- `services/admin/authService.uts` (新增) +- `services/admin/deliveryService.uts` (新增) +- `services/admin/maintainService.uts` (新增) + +### 3. UI 页面重构 (去 Mock) +- **权限类**: `auth/admin.uvue`, `auth/role.uvue`, `auth/permission.uvue`。 +- **物流类**: `delivery/staff.uvue`, `delivery/station.uvue`。 +- **配置类**: `setting/system/config.uvue`, `app/wechat/config.uvue`, `app/routine/config.uvue`, `app/mobile/config.uvue`, `app/pc/config.uvue`。 +- **综合类**: `statistic/index.uvue`, `maintain/sys/info.uvue`。 + +## 兼容性与风险 +- **数据迁移**:启用 RLS 后,需确保管理员用户在 `ak_users` 中的 `role` 字段准确设置为 `admin`,否则将无法调用管理端 RPC。 +- **逻辑依赖**:配送员和提货点管理依赖于 `ml_orders` 等核心表已存在。 + +## 回滚方案 +1. 数据库:依次 DROP 刚才创建的 20 余个 RPC 函数及 5 张核心业务表。 +2. 代码:通过 `git checkout` 恢复重构的 10 余个页面文件及 Service 目录。 + +## 验证方式 +1. **统计验证**:进入“数据概览”,确认销售额、用户数等指标非 0 且与数据库一致。 +2. **配置验证**:在“系统设置”修改网站名称并提交,刷新页面确认数据持久化。 +3. **权限验证**:在“角色管理”添加新身份,确认能在“管理员管理”中进行分配。 +4. **物流验证**:添加配送员后,确认列表分页展示正确且支持实时状态切换。 + +## 关联规范 +- 遵循 `AGENT_PROJECT_SPEC.md` 规范。 +- 对齐项目统一的角色鉴权与 RPC 分层口径。 diff --git a/docs/sql/10_schema/admin/ml_system_configs_v1.sql b/docs/sql/10_schema/admin/ml_system_configs_v1.sql new file mode 100644 index 00000000..cc9bf8ae --- /dev/null +++ b/docs/sql/10_schema/admin/ml_system_configs_v1.sql @@ -0,0 +1,24 @@ +-- ===================================================================================== +-- Schema: 系统配置表 +-- 位置:docs/sql/10_schema/admin/ml_system_configs_v1.sql +-- 对象类型:TABLE +-- 版本:v1 +-- 说明:统一存储系统、应用、维护等模块的 Key-Value 配置项 +-- ===================================================================================== + +CREATE TABLE IF NOT EXISTS public.ml_system_configs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + config_key TEXT UNIQUE NOT NULL, + config_value JSONB NOT NULL DEFAULT '{}'::jsonb, + description TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- 索引 +CREATE INDEX IF NOT EXISTS idx_system_configs_key ON public.ml_system_configs (config_key); + +-- 注释 +COMMENT ON TABLE public.ml_system_configs IS '系统全局配置表'; +COMMENT ON COLUMN public.ml_system_configs.config_key IS '配置唯一标识键'; +COMMENT ON COLUMN public.ml_system_configs.config_value IS '配置内容 (JSONB)'; diff --git a/docs/sql/10_schema/delivery/ak_delivery_system_v1.sql b/docs/sql/10_schema/delivery/ak_delivery_system_v1.sql new file mode 100644 index 00000000..27915468 --- /dev/null +++ b/docs/sql/10_schema/delivery/ak_delivery_system_v1.sql @@ -0,0 +1,51 @@ +-- ===================================================================================== +-- Schema: 物流设置 (Delivery) 核心表 +-- 位置:docs/sql/10_schema/delivery/ak_delivery_system_v1.sql +-- 对象类型:TABLE +-- 版本:v1 +-- 说明:包含配送员管理表、提货点/核销点管理表 +-- ===================================================================================== + +-- 1. 配送员管理表 +CREATE TABLE IF NOT EXISTS public.ml_delivery_staff ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + uid UUID REFERENCES public.ak_users(id) ON DELETE SET NULL, -- 关联用户(可选) + + nickname TEXT NOT NULL, -- 配送员名称 + avatar TEXT, -- 头像 + phone TEXT NOT NULL, -- 手机号 + + status SMALLINT NOT NULL DEFAULT 1, -- 状态: 1-启用, 0-禁用 + is_active BOOLEAN NOT NULL DEFAULT TRUE, + + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- 2. 提货点/核销点管理表 +CREATE TABLE IF NOT EXISTS public.ml_delivery_stations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, -- 提货点名称 + phone TEXT NOT NULL, -- 联系电话 + address TEXT NOT NULL, -- 详细地址 + + image TEXT, -- 门店图片 + lng NUMERIC(10,7), -- 经度 + lat NUMERIC(10,7), -- 纬度 + + status SMALLINT NOT NULL DEFAULT 1, -- 状态: 1-显示, 0-隐藏 + sort_order INTEGER DEFAULT 0, + + business_hours JSONB, -- 营业时间 (如: {"start": "09:00", "end": "21:00"}) + + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- 索引 +CREATE INDEX IF NOT EXISTS idx_delivery_staff_phone ON public.ml_delivery_staff(phone); +CREATE INDEX IF NOT EXISTS idx_delivery_stations_status ON public.ml_delivery_stations(status); + +-- 注释 +COMMENT ON TABLE public.ml_delivery_staff IS '配送员信息表'; +COMMENT ON TABLE public.ml_delivery_stations IS '提货点/核销点信息表'; diff --git a/docs/sql/10_schema/user/ak_auth_system_v1.sql b/docs/sql/10_schema/user/ak_auth_system_v1.sql new file mode 100644 index 00000000..516972cd --- /dev/null +++ b/docs/sql/10_schema/user/ak_auth_system_v1.sql @@ -0,0 +1,69 @@ +-- ===================================================================================== +-- Schema: 权限管理 (RBAC) 核心表 +-- 位置:docs/sql/10_schema/user/ak_auth_system_v1.sql +-- 对象类型:TABLE +-- 版本:v1 +-- 说明:包含角色表、权限/菜单表及用户角色关联表 +-- ===================================================================================== + +-- 1. 角色表 +CREATE TABLE IF NOT EXISTS public.ak_roles ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL UNIQUE, -- 角色名称 (如: 超级管理员) + code TEXT NOT NULL UNIQUE, -- 角色编码 (如: super_admin) + description TEXT, -- 角色描述 + is_active BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- 2. 权限/菜单表 +CREATE TABLE IF NOT EXISTS public.ak_permissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES public.ak_permissions(id) ON DELETE CASCADE, + + name TEXT NOT NULL, -- 权限/菜单名称 + code TEXT NOT NULL UNIQUE, -- 权限编码 (如: order_view) + type TEXT NOT NULL, -- 类型: menu(菜单), button(按钮/接口) + + path TEXT, -- 前端路由路径 (仅针对 menu) + icon TEXT, -- 图标 + sort_order INTEGER DEFAULT 0, -- 排序 + + is_visible BOOLEAN DEFAULT TRUE, -- 菜单是否在左侧可见 + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- 3. 用户-角色关联表 +-- 映射管理员 (ak_users) 与角色 +CREATE TABLE IF NOT EXISTS public.ak_admin_roles ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, + role_id UUID NOT NULL REFERENCES public.ak_roles(id) ON DELETE CASCADE, + + assigned_at TIMESTAMPTZ NOT NULL DEFAULT now(), + assigned_by UUID REFERENCES public.ak_users(id), + + UNIQUE(user_id, role_id) +); + +-- 4. 角色-权限关联表 +CREATE TABLE IF NOT EXISTS public.ak_role_permissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + role_id UUID NOT NULL REFERENCES public.ak_roles(id) ON DELETE CASCADE, + permission_id UUID NOT NULL REFERENCES public.ak_permissions(id) ON DELETE CASCADE, + + UNIQUE(role_id, permission_id) +); + +-- 索引 +CREATE INDEX IF NOT EXISTS idx_permissions_parent_id ON public.ak_permissions(parent_id); +CREATE INDEX IF NOT EXISTS idx_admin_roles_user_id ON public.ak_admin_roles(user_id); +CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON public.ak_role_permissions(role_id); + +-- 注释 +COMMENT ON TABLE public.ak_roles IS '后台管理角色表'; +COMMENT ON TABLE public.ak_permissions IS '功能权限与菜单定义表'; +COMMENT ON TABLE public.ak_admin_roles IS '管理员角色分配表'; +COMMENT ON TABLE public.ak_role_permissions IS '角色权限映射表'; diff --git a/docs/sql/20_rls/admin/ml_system_configs_rls_v1.sql b/docs/sql/20_rls/admin/ml_system_configs_rls_v1.sql new file mode 100644 index 00000000..0d9a5656 --- /dev/null +++ b/docs/sql/20_rls/admin/ml_system_configs_rls_v1.sql @@ -0,0 +1,17 @@ +-- ===================================================================================== +-- RLS: 系统配置表安全策略 +-- 位置:docs/sql/20_rls/admin/ml_system_configs_rls_v1.sql +-- 对象类型:RLS 策略 +-- 版本:v1 +-- 说明:允许所有登录用户读取配置;管理端全量操作通过 RPC (SECURITY DEFINER) 执行 +-- ===================================================================================== + +-- 启用 RLS +ALTER TABLE public.ml_system_configs ENABLE ROW LEVEL SECURITY; + +-- 1. 允许所有登录用户读取配置 (用于前端业务逻辑判断) +DROP POLICY IF EXISTS system_configs_select_policy ON public.ml_system_configs; +CREATE POLICY system_configs_select_policy ON public.ml_system_configs +FOR SELECT TO authenticated USING (true); + +-- 管理端全量管理将通过 SECURITY DEFINER 的 RPC 接口执行,此处不再额外开放直接表操作 diff --git a/docs/sql/20_rls/auth/ak_auth_rls_v1.sql b/docs/sql/20_rls/auth/ak_auth_rls_v1.sql new file mode 100644 index 00000000..94efedd8 --- /dev/null +++ b/docs/sql/20_rls/auth/ak_auth_rls_v1.sql @@ -0,0 +1,17 @@ +-- ===================================================================================== +-- RLS: 权限管理 (Auth) 安全策略 +-- 位置:docs/sql/20_rls/auth/ak_auth_rls_v1.sql +-- 对象类型:RLS 策略 +-- 版本:v1 +-- 说明:角色与权限表默认不对外开放,全量管理通过 SECURITY DEFINER RPC 执行 +-- ===================================================================================== + +-- 启用 RLS +ALTER TABLE public.ak_roles ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.ak_permissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.ak_admin_roles ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.ak_role_permissions ENABLE ROW LEVEL SECURITY; + +-- 默认策略:NO DIRECT ACCESS +-- 所有的查询和修改均建议通过 docs/sql/30_rpc/auth/ 下的专用管理接口完成 +-- 这样可以确保鉴权逻辑与 ak_users.role 强制绑定,且具备审计能力 diff --git a/docs/sql/20_rls/delivery/ak_delivery_rls_v1.sql b/docs/sql/20_rls/delivery/ak_delivery_rls_v1.sql new file mode 100644 index 00000000..342d524b --- /dev/null +++ b/docs/sql/20_rls/delivery/ak_delivery_rls_v1.sql @@ -0,0 +1,24 @@ +-- ===================================================================================== +-- RLS: 物流设置 (Delivery) 安全策略 +-- 位置:docs/sql/20_rls/delivery/ak_delivery_rls_v1.sql +-- 对象类型:RLS 策略 +-- 版本:v1 +-- 说明:配送员表管理端私有;提货点表消费者端只读 +-- ===================================================================================== + +-- 启用 RLS +ALTER TABLE public.ml_delivery_staff ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.ml_delivery_stations ENABLE ROW LEVEL SECURITY; + +-- 1. 配送员表策略:默认不开放直接访问 +-- 全量管理通过 docs/sql/30_rpc/delivery/ 下的 RPC 执行 + +-- 2. 提货点表策略:允许消费者端只读(用于地图展示和下单选择) +DROP POLICY IF EXISTS delivery_stations_select_active ON public.ml_delivery_stations; +CREATE POLICY delivery_stations_select_active + ON public.ml_delivery_stations + FOR SELECT + TO anon, authenticated + USING (status = 1); + +-- 管理端全量管理将通过 SECURITY DEFINER 的 RPC 接口执行 diff --git a/docs/sql/30_rpc/admin/rpc_admin_get_overall_stats_v1.sql b/docs/sql/30_rpc/admin/rpc_admin_get_overall_stats_v1.sql new file mode 100644 index 00000000..00c471fa --- /dev/null +++ b/docs/sql/30_rpc/admin/rpc_admin_get_overall_stats_v1.sql @@ -0,0 +1,59 @@ +-- ===================================================================================== +-- Admin 统计功能 - 获取全站核心指标概览 RPC +-- 位置:docs/sql/30_rpc/admin/rpc_admin_get_overall_stats_v1.sql +-- 对象类型:RPC 函数(SECURITY DEFINER) +-- 版本:v1 +-- 说明:一次性聚合查询销售、订单、用户及商品的核心统计指标 +-- ===================================================================================== + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_overall_stats() +RETURNS JSONB +SECURITY DEFINER +SET search_path = public +LANGUAGE plpgsql +AS $$ +DECLARE + v_stats JSONB; + v_today_start TIMESTAMPTZ := CURRENT_DATE; +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. 聚合统计 + WITH totals AS ( + SELECT + (SELECT COALESCE(SUM(paid_amount), 0) FROM public.ml_orders WHERE paid = 1) as total_sales, + (SELECT COUNT(*) FROM public.ml_orders WHERE paid = 1) as total_orders, + (SELECT COUNT(*) FROM public.ak_users) as total_users, + (SELECT COUNT(*) FROM public.ml_products) as total_products + ), + today_stats AS ( + SELECT + (SELECT COALESCE(SUM(paid_amount), 0) FROM public.ml_orders WHERE paid = 1 AND created_at >= v_today_start) as today_sales, + (SELECT COUNT(*) FROM public.ml_orders WHERE paid = 1 AND created_at >= v_today_start) as today_orders, + (SELECT COUNT(*) FROM public.ak_users WHERE created_at >= v_today_start) as today_new_users + ), + pending_tasks AS ( + SELECT + (SELECT COUNT(*) FROM public.ml_orders WHERE paid = 1 AND order_status = 1) as pending_delivery, + (SELECT COUNT(*) FROM public.ml_product_skus WHERE stock <= 10) as stock_warning, -- 假设库存小于10为预警 + (SELECT COUNT(*) FROM public.ml_extract WHERE status = 0) as pending_extract + ) + SELECT jsonb_build_object( + 'totals', (SELECT row_to_json(totals.*) FROM totals), + 'today', (SELECT row_to_json(today_stats.*) FROM today_stats), + 'pending', (SELECT row_to_json(pending_tasks.*) FROM pending_tasks) + ) INTO v_stats; + + RETURN v_stats; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_overall_stats() FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_overall_stats() TO authenticated; diff --git a/docs/sql/30_rpc/admin/rpc_admin_get_system_info_v1.sql b/docs/sql/30_rpc/admin/rpc_admin_get_system_info_v1.sql new file mode 100644 index 00000000..6cfea4a8 --- /dev/null +++ b/docs/sql/30_rpc/admin/rpc_admin_get_system_info_v1.sql @@ -0,0 +1,46 @@ +-- ===================================================================================== +-- Admin 系统维护 - 获取服务器环境信息 RPC +-- 位置:docs/sql/30_rpc/admin/rpc_admin_get_system_info_v1.sql +-- 对象类型:RPC 函数(SECURITY DEFINER) +-- 版本:v1 +-- 说明:获取服务器操作系统、数据库版本及运行环境信息 +-- ===================================================================================== + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_system_info() +RETURNS JSONB +SECURITY DEFINER +SET search_path = public +LANGUAGE plpgsql +AS $$ +DECLARE + v_info JSONB; + v_db_version TEXT; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取数据库版本 + SELECT version() INTO v_db_version; + + -- 3. 构建返回信息 + v_info := jsonb_build_object( + 'server_os', 'Linux (Simulated)', -- 数据库侧通常难以直接获取完整的宿主系统信息 + 'web_server', 'Nginx/1.24.0 (Simulated)', + 'db_engine', 'PostgreSQL', + 'db_version', v_db_version, + 'uts_runtime', 'uni-app x (UTS)', + 'auth_id', 'ZC2884891' -- 模拟授权码 + ); + + RETURN v_info; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_system_info() FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_system_info() TO authenticated; diff --git a/docs/sql/30_rpc/admin/rpc_admin_system_config_save_v1.sql b/docs/sql/30_rpc/admin/rpc_admin_system_config_save_v1.sql index bf82d551..01ab8bb4 100644 --- a/docs/sql/30_rpc/admin/rpc_admin_system_config_save_v1.sql +++ b/docs/sql/30_rpc/admin/rpc_admin_system_config_save_v1.sql @@ -1,5 +1,5 @@ -- ===================================================================================== --- Admin 系统功能 - 保存配置项 RPC +-- Admin 系统功能 - 保存/更新配置项 RPC -- 位置:docs/sql/30_rpc/admin/ -- 对象类型:RPC 函数(SECURITY DEFINER) -- 版本:v1 @@ -8,7 +8,8 @@ CREATE OR REPLACE FUNCTION public.rpc_admin_system_config_save( p_key TEXT, - p_value JSONB + p_value JSONB, + p_description TEXT DEFAULT NULL ) RETURNS BOOLEAN SECURITY DEFINER @@ -24,14 +25,19 @@ BEGIN RAISE EXCEPTION 'Permission denied'; END IF; - -- 2. 执行保存(存在则更新,不存在则插入) - INSERT INTO public.ml_system_configs (config_key, config_value, updated_at) - VALUES (p_key, p_value, NOW()) - ON CONFLICT (config_key) - DO UPDATE SET + -- 2. 插入或更新配置 + INSERT INTO public.ml_system_configs (config_key, config_value, description, updated_at) + VALUES (p_key, p_value, p_description, NOW()) + ON CONFLICT (config_key) DO UPDATE + SET config_value = EXCLUDED.config_value, + description = COALESCE(EXCLUDED.description, public.ml_system_configs.description), updated_at = NOW(); RETURN TRUE; END; -$$; \ No newline at end of file +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_system_config_save(TEXT, JSONB, TEXT) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_system_config_save(TEXT, JSONB, TEXT) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_delete_permission_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_delete_permission_v1.sql new file mode 100644 index 00000000..cc6b3981 --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_delete_permission_v1.sql @@ -0,0 +1,33 @@ +-- RPC: rpc_admin_delete_permission +-- 管理端删除功能权限/菜单 + +CREATE OR REPLACE FUNCTION public.rpc_admin_delete_permission( + p_id UUID +) +RETURNS BOOLEAN +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_ok BOOLEAN; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 执行级联删除 (外键已配置 ON DELETE CASCADE) + DELETE FROM public.ak_permissions WHERE id = p_id; + + GET DIAGNOSTICS v_ok = ROW_COUNT; + RETURN v_ok; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_delete_permission(UUID) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_permission(UUID) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_delete_role_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_delete_role_v1.sql new file mode 100644 index 00000000..3bb7706e --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_delete_role_v1.sql @@ -0,0 +1,33 @@ +-- RPC: rpc_admin_delete_role +-- 管理端删除角色 + +CREATE OR REPLACE FUNCTION public.rpc_admin_delete_role( + p_id UUID +) +RETURNS BOOLEAN +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_ok BOOLEAN; +BEGIN + -- 1. 权限检查 + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 执行删除 + DELETE FROM public.ak_roles WHERE id = p_id; + + GET DIAGNOSTICS v_ok = ROW_COUNT; + RETURN v_ok; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_delete_role(UUID) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_role(UUID) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_get_admin_list_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_get_admin_list_v1.sql new file mode 100644 index 00000000..6672eefb --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_get_admin_list_v1.sql @@ -0,0 +1,70 @@ +-- RPC: rpc_admin_get_admin_list +-- 管理端获取管理员列表 +-- 筛选 ak_users 表中 role 为 'admin' 或 'analytics' 的用户,并关联显示其角色信息 + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_admin_list( + p_search TEXT DEFAULT NULL, + p_status SMALLINT DEFAULT NULL, + p_page INTEGER DEFAULT 1, + p_page_size INTEGER DEFAULT 20 +) +RETURNS JSONB +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_offset INTEGER := (p_page - 1) * p_page_size; + v_total BIGINT; + v_items JSONB; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取总数 + SELECT COUNT(*) INTO v_total + FROM public.ak_users u + WHERE u.role IN ('admin', 'analytics') + AND (p_status IS NULL OR u.is_active = (p_status = 1)) + AND (p_search IS NULL OR u.username ILIKE '%' || p_search || '%' OR u.real_name ILIKE '%' || p_search || '%'); + + -- 3. 获取数据列表 (关联角色) + SELECT jsonb_agg(t) INTO v_items + FROM ( + SELECT + u.id, + u.username, + u.real_name, + u.role, + u.is_active, + u.last_login_at, + u.last_login_ip, + ( + SELECT jsonb_agg(r.name) + FROM public.ak_admin_roles ar + JOIN public.ak_roles r ON r.id = ar.role_id + WHERE ar.user_id = u.id + ) as roles + FROM public.ak_users u + WHERE u.role IN ('admin', 'analytics') + AND (p_status IS NULL OR u.is_active = (p_status = 1)) + AND (p_search IS NULL OR u.username ILIKE '%' || p_search || '%' OR u.real_name ILIKE '%' || p_search || '%') + ORDER BY u.created_at DESC + LIMIT p_page_size OFFSET v_offset + ) t; + + RETURN jsonb_build_object( + 'total', v_total, + 'items', COALESCE(v_items, '[]'::jsonb) + ); +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_admin_list(TEXT, SMALLINT, INTEGER, INTEGER) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_admin_list(TEXT, SMALLINT, INTEGER, INTEGER) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_get_permission_list_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_get_permission_list_v1.sql new file mode 100644 index 00000000..e08fc218 --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_get_permission_list_v1.sql @@ -0,0 +1,38 @@ +-- RPC: rpc_admin_get_permission_list +-- 管理端获取全量权限/菜单列表 (供前端构建树形结构) + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_permission_list() +RETURNS JSONB +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_items JSONB; +BEGIN + -- 1. 权限检查 + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取全量数据 + SELECT jsonb_agg(t) INTO v_items + FROM ( + SELECT + id, parent_id, name, code, type, + path, icon, sort_order, is_visible, + created_at, updated_at + FROM public.ak_permissions + ORDER BY sort_order ASC, created_at ASC + ) t; + + RETURN COALESCE(v_items, '[]'::jsonb); +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_permission_list() FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_permission_list() TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_get_role_list_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_get_role_list_v1.sql new file mode 100644 index 00000000..f3ceaed5 --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_get_role_list_v1.sql @@ -0,0 +1,53 @@ +-- RPC: rpc_admin_get_role_list +-- 管理端获取角色分页列表 + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_role_list( + p_search TEXT DEFAULT NULL, + p_page INTEGER DEFAULT 1, + p_page_size INTEGER DEFAULT 20 +) +RETURNS JSONB +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_offset INTEGER := (p_page - 1) * p_page_size; + v_total BIGINT; + v_items JSONB; +BEGIN + -- 1. 权限检查 + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取总数 + SELECT COUNT(*) INTO v_total + FROM public.ak_roles + WHERE (p_search IS NULL OR p_search = '' OR name ILIKE '%' || p_search || '%' OR code ILIKE '%' || p_search || '%'); + + -- 3. 获取明细 + SELECT jsonb_agg(t) INTO v_items + FROM ( + SELECT + id, name, code, description, is_active, + created_at, updated_at + FROM public.ak_roles + WHERE (p_search IS NULL OR p_search = '' OR name ILIKE '%' || p_search || '%' OR code ILIKE '%' || p_search || '%') + ORDER BY created_at DESC + LIMIT p_page_size OFFSET v_offset + ) t; + + RETURN jsonb_build_object( + 'total', v_total, + 'items', COALESCE(v_items, '[]'::jsonb) + ); +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_role_list(TEXT, INTEGER, INTEGER) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_role_list(TEXT, INTEGER, INTEGER) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_save_permission_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_save_permission_v1.sql new file mode 100644 index 00000000..811f116c --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_save_permission_v1.sql @@ -0,0 +1,69 @@ +-- RPC: rpc_admin_save_permission +-- 管理端新增或更新功能权限/菜单 + +CREATE OR REPLACE FUNCTION public.rpc_admin_save_permission( + p_id UUID DEFAULT NULL, + p_parent_id UUID DEFAULT NULL, + p_name TEXT DEFAULT NULL, + p_code TEXT DEFAULT NULL, + p_type TEXT DEFAULT 'menu', + p_path TEXT DEFAULT NULL, + p_icon TEXT DEFAULT NULL, + p_sort_order INTEGER DEFAULT 0, + p_is_visible BOOLEAN DEFAULT TRUE +) +RETURNS UUID +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_id UUID; +BEGIN + -- 1. 权限检查 + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 新增 + IF p_id IS NULL THEN + IF p_name IS NULL OR p_code IS NULL THEN + RAISE EXCEPTION 'Missing required fields: name or code'; + END IF; + + INSERT INTO public.ak_permissions ( + parent_id, name, code, type, path, icon, sort_order, is_visible + ) VALUES ( + p_parent_id, p_name, p_code, p_type, p_path, p_icon, p_sort_order, p_is_visible + ) RETURNING id INTO v_id; + ELSE + -- 3. 更新 + UPDATE public.ak_permissions + SET + parent_id = COALESCE(p_parent_id, parent_id), + name = COALESCE(p_name, name), + code = COALESCE(p_code, code), + type = COALESCE(p_type, type), + path = COALESCE(p_path, path), + icon = COALESCE(p_icon, icon), + sort_order = COALESCE(p_sort_order, sort_order), + is_visible = COALESCE(p_is_visible, is_visible), + updated_at = now() + WHERE id = p_id + RETURNING id INTO v_id; + + IF v_id IS NULL THEN + RAISE EXCEPTION 'Permission item not found'; + END IF; + END IF; + + RETURN v_id; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_save_permission(UUID, UUID, TEXT, TEXT, TEXT, TEXT, TEXT, INTEGER, BOOLEAN) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_save_permission(UUID, UUID, TEXT, TEXT, TEXT, TEXT, TEXT, INTEGER, BOOLEAN) TO authenticated; diff --git a/docs/sql/30_rpc/auth/rpc_admin_save_role_v1.sql b/docs/sql/30_rpc/auth/rpc_admin_save_role_v1.sql new file mode 100644 index 00000000..f67c7dba --- /dev/null +++ b/docs/sql/30_rpc/auth/rpc_admin_save_role_v1.sql @@ -0,0 +1,61 @@ +-- RPC: rpc_admin_save_role +-- 管理端新增或更新角色 + +CREATE OR REPLACE FUNCTION public.rpc_admin_save_role( + p_id UUID DEFAULT NULL, + p_name TEXT DEFAULT NULL, + p_code TEXT DEFAULT NULL, + p_description TEXT DEFAULT NULL, + p_is_active BOOLEAN DEFAULT TRUE +) +RETURNS UUID +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_id UUID; +BEGIN + -- 1. 权限检查 + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 新增 + IF p_id IS NULL THEN + IF p_name IS NULL OR p_code IS NULL THEN + RAISE EXCEPTION 'Missing required fields: name or code'; + END IF; + + INSERT INTO public.ak_roles ( + name, code, description, is_active + ) VALUES ( + p_name, p_code, p_description, p_is_active + ) RETURNING id INTO v_id; + ELSE + -- 3. 更新 + UPDATE public.ak_roles + SET + name = COALESCE(p_name, name), + code = COALESCE(p_code, code), + description = COALESCE(p_description, description), + is_active = COALESCE(p_is_active, is_active), + updated_at = now() + WHERE id = p_id + RETURNING id INTO v_id; + + IF v_id IS NULL THEN + RAISE EXCEPTION 'Role not found'; + END IF; + END IF; + + RETURN v_id; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_save_role(UUID, TEXT, TEXT, TEXT, BOOLEAN) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_save_role(UUID, TEXT, TEXT, TEXT, BOOLEAN) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_staff_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_staff_v1.sql new file mode 100644 index 00000000..fe1d4e09 --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_staff_v1.sql @@ -0,0 +1,33 @@ +-- RPC: rpc_admin_delete_delivery_staff +-- 管理端删除配送员 + +CREATE OR REPLACE FUNCTION public.rpc_admin_delete_delivery_staff( + p_id UUID +) +RETURNS BOOLEAN +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_ok BOOLEAN; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 执行删除 + DELETE FROM public.ml_delivery_staff WHERE id = p_id; + + GET DIAGNOSTICS v_ok = ROW_COUNT; + RETURN v_ok; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_delete_delivery_staff(UUID) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_delivery_staff(UUID) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_station_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_station_v1.sql new file mode 100644 index 00000000..82d067b7 --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_station_v1.sql @@ -0,0 +1,33 @@ +-- RPC: rpc_admin_delete_delivery_station +-- 管理端删除提货点/核销点 + +CREATE OR REPLACE FUNCTION public.rpc_admin_delete_delivery_station( + p_id UUID +) +RETURNS BOOLEAN +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_ok BOOLEAN; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 执行删除 + DELETE FROM public.ml_delivery_stations WHERE id = p_id; + + GET DIAGNOSTICS v_ok = ROW_COUNT; + RETURN v_ok; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_delete_delivery_station(UUID) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_delete_delivery_station(UUID) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_staff_list_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_staff_list_v1.sql new file mode 100644 index 00000000..0af4f25c --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_staff_list_v1.sql @@ -0,0 +1,58 @@ +-- RPC: rpc_admin_get_delivery_staff_list +-- 管理端获取配送员分页列表 +-- 支持按姓名或手机号搜索 + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_delivery_staff_list( + p_search TEXT DEFAULT NULL, + p_status SMALLINT DEFAULT NULL, + p_page INTEGER DEFAULT 1, + p_page_size INTEGER DEFAULT 20 +) +RETURNS JSONB +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_offset INTEGER := (p_page - 1) * p_page_size; + v_total BIGINT; + v_items JSONB; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取总数 + SELECT COUNT(*) INTO v_total + FROM public.ml_delivery_staff + WHERE (p_status IS NULL OR status = p_status) + AND (p_search IS NULL OR p_search = '' OR nickname ILIKE '%' || p_search || '%' OR phone ILIKE '%' || p_search || '%'); + + -- 3. 获取明细 + SELECT jsonb_agg(t) INTO v_items + FROM ( + SELECT + id, uid, nickname, avatar, phone, status, is_active, + created_at, updated_at + FROM public.ml_delivery_staff + WHERE (p_status IS NULL OR status = p_status) + AND (p_search IS NULL OR p_search = '' OR nickname ILIKE '%' || p_search || '%' OR phone ILIKE '%' || p_search || '%') + ORDER BY created_at DESC + LIMIT p_page_size OFFSET v_offset + ) t; + + -- 4. 返回结果 + RETURN jsonb_build_object( + 'total', v_total, + 'items', COALESCE(v_items, '[]'::jsonb) + ); +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_delivery_staff_list(TEXT, SMALLINT, INTEGER, INTEGER) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_delivery_staff_list(TEXT, SMALLINT, INTEGER, INTEGER) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_station_list_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_station_list_v1.sql new file mode 100644 index 00000000..8dd6b384 --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_get_delivery_station_list_v1.sql @@ -0,0 +1,65 @@ +-- RPC: rpc_admin_get_delivery_station_list +-- 管理端获取提货点/核销点分页列表 +-- 支持按名称、地址或手机号搜索 + +CREATE OR REPLACE FUNCTION public.rpc_admin_get_delivery_station_list( + p_search TEXT DEFAULT NULL, + p_status SMALLINT DEFAULT NULL, + p_page INTEGER DEFAULT 1, + p_page_size INTEGER DEFAULT 20 +) +RETURNS JSONB +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_offset INTEGER := (p_page - 1) * p_page_size; + v_total BIGINT; + v_items JSONB; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 获取总数 + SELECT COUNT(*) INTO v_total + FROM public.ml_delivery_stations + WHERE (p_status IS NULL OR status = p_status) + AND (p_search IS NULL OR p_search = '' + OR name ILIKE '%' || p_search || '%' + OR address ILIKE '%' || p_search || '%' + OR phone ILIKE '%' || p_search || '%'); + + -- 3. 获取明细 + SELECT jsonb_agg(t) INTO v_items + FROM ( + SELECT + id, name, phone, address, image, + lng, lat, status, sort_order, business_hours, + created_at, updated_at + FROM public.ml_delivery_stations + WHERE (p_status IS NULL OR status = p_status) + AND (p_search IS NULL OR p_search = '' + OR name ILIKE '%' || p_search || '%' + OR address ILIKE '%' || p_search || '%' + OR phone ILIKE '%' || p_search || '%') + ORDER BY sort_order ASC, created_at DESC + LIMIT p_page_size OFFSET v_offset + ) t; + + -- 4. 返回结果 + RETURN jsonb_build_object( + 'total', v_total, + 'items', COALESCE(v_items, '[]'::jsonb) + ); +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_get_delivery_station_list(TEXT, SMALLINT, INTEGER, INTEGER) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_get_delivery_station_list(TEXT, SMALLINT, INTEGER, INTEGER) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_staff_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_staff_v1.sql new file mode 100644 index 00000000..c3c49f8c --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_staff_v1.sql @@ -0,0 +1,61 @@ +-- RPC: rpc_admin_save_delivery_staff +-- 管理端新增或更新配送员信息 + +CREATE OR REPLACE FUNCTION public.rpc_admin_save_delivery_staff( + p_id UUID DEFAULT NULL, + p_nickname TEXT DEFAULT NULL, + p_avatar TEXT DEFAULT NULL, + p_phone TEXT DEFAULT NULL, + p_status SMALLINT DEFAULT 1 +) +RETURNS UUID +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_id UUID; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 参数校验 + IF p_nickname IS NULL OR p_phone IS NULL THEN + RAISE EXCEPTION 'Missing required fields: nickname or phone'; + END IF; + + -- 3. 新增或更新 + IF p_id IS NULL THEN + INSERT INTO public.ml_delivery_staff ( + nickname, avatar, phone, status + ) VALUES ( + p_nickname, p_avatar, p_phone, p_status + ) RETURNING id INTO v_id; + ELSE + UPDATE public.ml_delivery_staff + SET + nickname = COALESCE(p_nickname, nickname), + avatar = COALESCE(p_avatar, avatar), + phone = COALESCE(p_phone, phone), + status = COALESCE(p_status, status), + updated_at = now() + WHERE id = p_id + RETURNING id INTO v_id; + + IF v_id IS NULL THEN + RAISE EXCEPTION 'Delivery staff not found'; + END IF; + END IF; + + RETURN v_id; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_save_delivery_staff(UUID, TEXT, TEXT, TEXT, SMALLINT) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_save_delivery_staff(UUID, TEXT, TEXT, TEXT, SMALLINT) TO authenticated; diff --git a/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_station_v1.sql b/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_station_v1.sql new file mode 100644 index 00000000..9803f22f --- /dev/null +++ b/docs/sql/30_rpc/delivery/rpc_admin_save_delivery_station_v1.sql @@ -0,0 +1,71 @@ +-- RPC: rpc_admin_save_delivery_station +-- 管理端新增或更新提货点/核销点信息 + +CREATE OR REPLACE FUNCTION public.rpc_admin_save_delivery_station( + p_id UUID DEFAULT NULL, + p_name TEXT DEFAULT NULL, + p_phone TEXT DEFAULT NULL, + p_address TEXT DEFAULT NULL, + p_image TEXT DEFAULT NULL, + p_lng NUMERIC DEFAULT NULL, + p_lat NUMERIC DEFAULT NULL, + p_status SMALLINT DEFAULT 1, + p_sort_order INTEGER DEFAULT 0, + p_business_hours JSONB DEFAULT NULL +) +RETURNS UUID +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_id UUID; +BEGIN + -- 1. 权限检查 (仅管理员) + IF NOT EXISTS ( + SELECT 1 FROM public.ak_users + WHERE auth_id = auth.uid() AND role = 'admin' + ) THEN + RAISE EXCEPTION 'Permission denied'; + END IF; + + -- 2. 参数校验 + IF p_name IS NULL OR p_phone IS NULL OR p_address IS NULL THEN + RAISE EXCEPTION 'Missing required fields: name, phone or address'; + END IF; + + -- 3. 新增或更新 + IF p_id IS NULL THEN + INSERT INTO public.ml_delivery_stations ( + name, phone, address, image, lng, lat, status, sort_order, business_hours + ) VALUES ( + p_name, p_phone, p_address, p_image, p_lng, p_lat, p_status, p_sort_order, p_business_hours + ) RETURNING id INTO v_id; + ELSE + UPDATE public.ml_delivery_stations + SET + name = COALESCE(p_name, name), + phone = COALESCE(p_phone, phone), + address = COALESCE(p_address, address), + image = COALESCE(p_image, image), + lng = COALESCE(p_lng, lng), + lat = COALESCE(p_lat, lat), + status = COALESCE(p_status, status), + sort_order = COALESCE(p_sort_order, sort_order), + business_hours = COALESCE(p_business_hours, business_hours), + updated_at = now() + WHERE id = p_id + RETURNING id INTO v_id; + + IF v_id IS NULL THEN + RAISE EXCEPTION 'Station not found'; + END IF; + END IF; + + RETURN v_id; +END; +$$; + +-- 授权 +REVOKE ALL ON FUNCTION public.rpc_admin_save_delivery_station(UUID, TEXT, TEXT, TEXT, TEXT, NUMERIC, NUMERIC, SMALLINT, INTEGER, JSONB) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION public.rpc_admin_save_delivery_station(UUID, TEXT, TEXT, TEXT, TEXT, NUMERIC, NUMERIC, SMALLINT, INTEGER, JSONB) TO authenticated; diff --git a/pages/mall/admin/app/mobile/config.uvue b/pages/mall/admin/app/mobile/config.uvue index 328700d8..fe236ca4 100644 --- a/pages/mall/admin/app/mobile/config.uvue +++ b/pages/mall/admin/app/mobile/config.uvue @@ -8,17 +8,17 @@ APPID: - + 微信开放平台申请移动应用后给予的APPID AppSecret: - + 微信开放平台申请移动应用后给予的AppSecret - + @@ -26,7 +26,40 @@ - diff --git a/pages/mall/admin/maintain/sys/info.uvue b/pages/mall/admin/maintain/sys/info.uvue index cc30e78d..99504dd2 100644 --- a/pages/mall/admin/maintain/sys/info.uvue +++ b/pages/mall/admin/maintain/sys/info.uvue @@ -13,7 +13,7 @@ - ZC2884891 + {{ info?.auth_id || '检测中...' }} 进入官网 @@ -22,29 +22,6 @@ - - - - 自定义版权信息 - - - - 文字版权信息 - 底部版权图片 - 操作 - - - - - - - 编辑 - - - - - - @@ -60,53 +37,71 @@ 服务器系统 类UNIX - Linux + {{ info?.server_os || 'Loading...' }} WEB环境 Apache/Nginx/IIS - nginx/1.24.0 - - - - - - - - - 系统环境要求 - - - - 环境 - 要求 - 状态 - - - - PHP版本 - 7.1-7.4 - 7.4.33 + {{ info?.web_server || 'Loading...' }} - MySQL版本 - 5.6-8.0 - 8.0.35 + 数据库引擎 + PostgreSQL + {{ info?.db_engine || 'Loading...' }} + + + 数据库版本 + 15.0+ + {{ info?.db_version || 'Loading...' }} + + + 运行环境 + UTS Runtime + {{ info?.uts_runtime || 'Loading...' }} + + + 系统环境加载中... + @@ -158,13 +153,10 @@ function editCopyright() { color: #333; } -/* 各表格占位列宽 */ .col-title { flex: 1; } -.col-text { flex: 1; } -.col-image { flex: 1; } .col-env { flex: 1; } .col-req { flex: 1; } -.col-status { flex: 1; } +.col-status { flex: 1; font-family: monospace; } .col-action { width: 150px; justify-content: flex-end; } .action-btn { @@ -175,4 +167,14 @@ function editCopyright() { .mt-24 { margin-top: 24px; } + +.loading-overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background-color: rgba(255,255,255,0.6); + display: flex; + justify-content: center; + align-items: center; + z-index: 999; +} diff --git a/pages/mall/admin/setting/auth/admin.uvue b/pages/mall/admin/setting/auth/admin.uvue index 893a3025..8fc1878b 100644 --- a/pages/mall/admin/setting/auth/admin.uvue +++ b/pages/mall/admin/setting/auth/admin.uvue @@ -5,15 +5,13 @@ 状态: - - {{ statusText }} - + 搜索: - + - + @@ -21,7 +19,7 @@ - + 姓名 账号 @@ -32,9 +30,42 @@ 操作 - - 暂无数据 + + 加载中... + + 暂无管理员数据 + + + {{ item.real_name || '-' }} + {{ item.username }} + + + {{ role }} + - + + + {{ formatTime(item.last_login_at) }} + {{ item.last_login_ip || '-' }} + + + + + 编辑 + + 删除 + + + + + + + + 共 {{ total }} 条 + + < + {{ page }} + > @@ -42,136 +73,101 @@ - diff --git a/pages/mall/admin/setting/auth/permission.uvue b/pages/mall/admin/setting/auth/permission.uvue index 3403bab8..5ef2f815 100644 --- a/pages/mall/admin/setting/auth/permission.uvue +++ b/pages/mall/admin/setting/auth/permission.uvue @@ -1,188 +1,263 @@ - diff --git a/pages/mall/admin/setting/auth/role.uvue b/pages/mall/admin/setting/auth/role.uvue index ef9abf5c..ee050095 100644 --- a/pages/mall/admin/setting/auth/role.uvue +++ b/pages/mall/admin/setting/auth/role.uvue @@ -5,15 +5,13 @@ 状态: - - {{ statusText }} - + 身份昵称: - + - + @@ -21,17 +19,70 @@ - + - ID + 序号 身份昵称 状态 操作 - + + 加载中... + + 暂无数据 + + {{ (page - 1) * pageSize + index + 1 }} + {{ item.name }} ({{ item.code }}) + + + + + 编辑 + + 删除 + + + + + + + + 共 {{ total }} 条 + + < + {{ page }} + > + + + + + + + + + {{ isEdit ? '编辑身份' : '添加身份' }} + × + + + + 身份名称: + + + + 身份编码: + + + + 描述: +