# RBAC 路由权限 API 响应示例 v3.2 ## 📋 文档说明 本文档展示 v3.2 版本 RBAC 路由权限接口的完整响应格式。 **v3.2 核心变更**: - ✅ 使用 `status` 字段管理路由启用/禁用状态 - ✅ 取消勾选后路由不删除,只是设置为 status=0 - ✅ 接口返回 `enabled` 字段标识路由是否启用 - ✅ 仅省级管理员可修改路由权限 --- ## 1️⃣ GET /rbac/roles/{role_id}/routes ### 功能说明 获取角色关联的所有路由(包括禁用的),每个路由带 `enabled` 字段 ### 请求示例 ```bash GET /rbac/roles/1/routes Authorization: Bearer ``` ### 响应示例 ```json { "code": 200, "msg": "success", "data": { "role_id": 1, "routes": [ { "id": 31, "route_path": "/home", "route_name": "Home", "route_title": "系统概览", "parent_id": null, "icon": "ri-dashboard-line", "sort_order": 1, "is_hidden": false, "component": "views/Home.vue", "enabled": true, "permissions": [ { "id": 10, "permission_key": "dashboard:stats:view", "display_name": "查看统计数据", "api_method": "GET", "api_path": "/api/v3/dashboard/stats" } ] }, { "id": 2, "route_path": "/documents", "route_name": "Documents", "route_title": "文件管理", "parent_id": null, "icon": "ri-folder-3-line", "sort_order": 2, "is_hidden": false, "component": "views/documents/Index.vue", "enabled": false, "permissions": [ { "id": 20, "permission_key": "document:list:read", "display_name": "查看文档列表", "api_method": "GET", "api_path": "/api/v2/documents" } ], "children": [ { "id": 59, "route_path": "/files/upload", "route_name": "FilesUpload", "route_title": "文件上传", "parent_id": 2, "enabled": false, "permissions": [] } ] }, { "id": 41, "route_path": "/rules", "route_name": "Rules", "route_title": "评查规则库", "parent_id": null, "icon": "ri-book-3-line", "sort_order": 3, "is_hidden": false, "component": "views/rules/Index.vue", "enabled": true, "permissions": [ { "id": 28, "permission_key": "evaluation_group:list:read", "display_name": "查看评查点分组列表", "api_method": "GET", "api_path": "/api/v3/evaluation-point-groups" } ] } ] } } ``` ### 字段说明 | 字段 | 类型 | 说明 | |------|------|------| | `enabled` | boolean | **true=启用(前端显示为勾选)**, **false=禁用(前端显示为未勾选)** | | `permissions` | array | 路由关联的API权限列表 | ### 前端使用示例 ```javascript // 获取角色路由 const response = await fetch('/rbac/roles/1/routes') const { routes } = response.data // 提取启用的路由ID(用于Tree组件初始勾选) const checkedKeys = [] const extractEnabled = (routeList) => { routeList.forEach(route => { if (route.enabled) { checkedKeys.push(route.id) } if (route.children) { extractEnabled(route.children) } }) } extractEnabled(routes) // 设置Tree组件默认勾选 treeRef.value.setCheckedKeys(checkedKeys) ``` --- ## 2️⃣ PUT /rbac/roles/{role_id}/routes ### 功能说明 批量更新角色路由权限(状态管理模式) - route_ids 中的路由设置为启用(status=1) - 不在 route_ids 中的路由设置为禁用(status=0) - **仅省级管理员可调用** ### 请求示例 ```bash PUT /rbac/roles/1/routes Authorization: Bearer Content-Type: application/json { "route_ids": [31, 41], "permission": "RW" } ``` ### 响应示例(成功) ```json { "code": 200, "msg": "success", "data": { "role_id": 1, "enabled_count": 2, "disabled_count": 1, "inserted_count": 0, "route_ids": [31, 41] } } ``` ### 响应字段说明 | 字段 | 类型 | 说明 | |------|------|------| | `enabled_count` | int | 本次启用的路由数量 | | `disabled_count` | int | 本次禁用的路由数量 | | `inserted_count` | int | 本次新插入的路由数量 | | `route_ids` | array | 启用的路由ID列表 | ### 响应示例(权限不足) ```json { "code": 4003, "msg": "权限不足:仅省级管理员可以修改角色路由权限", "data": null } ``` ### 前端使用示例 ```javascript // 保存路由权限 const saveRoutePermissions = async (roleId) => { const checkedKeys = treeRef.value.getCheckedKeys() try { const response = await fetch(`/rbac/roles/${roleId}/routes`, { method: 'PUT', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ route_ids: checkedKeys, permission: 'RW' }) }) const result = await response.json() if (result.code === 200) { ElMessage.success( `成功启用 ${result.data.enabled_count} 个路由,` + `禁用 ${result.data.disabled_count} 个路由` ) // 刷新路由列表以更新enabled状态 await loadRoutes() } else if (result.code === 4003) { ElMessage.error('权限不足:仅省级管理员可以修改路由权限') } } catch (error) { ElMessage.error('保存失败:' + error.message) } } ``` --- ## 3️⃣ 完整工作流程示例 ### Vue 3 + Element Plus 完整组件 ```vue ``` --- ## 4️⃣ 数据库表结构 ### role_route 表(v3.2更新) ```sql CREATE TABLE role_route ( id SERIAL PRIMARY KEY, role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE, route_id INTEGER NOT NULL REFERENCES sys_routes(id) ON DELETE CASCADE, permission VARCHAR(10) DEFAULT 'RW', status SMALLINT DEFAULT 1 NOT NULL, -- ⭐新增:0=禁用,1=启用 created_at TIMESTAMP(6) WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP(6) WITH TIME ZONE DEFAULT NOW(), CONSTRAINT role_route_role_id_route_id_key UNIQUE (role_id, route_id), CONSTRAINT chk_role_route_status CHECK (status IN (0, 1)) ); -- 索引 CREATE INDEX idx_role_route_status ON role_route(status); CREATE INDEX idx_role_route_role_status ON role_route(role_id, status); -- 注释 COMMENT ON COLUMN role_route.status IS '状态:0=禁用,1=启用'; ``` --- ## 5️⃣ 核心逻辑说明 ### 状态管理逻辑 ```python # 批量更新时的逻辑: # 1. 先将所有路由设置为禁用(status=0) UPDATE role_route SET status = 0 WHERE role_id = ? # 2. 将勾选的路由设置为启用(status=1) UPDATE role_route SET status = 1 WHERE role_id = ? AND route_id IN (?) # 3. 如果记录不存在,插入新记录(status默认为1) INSERT INTO role_route (role_id, route_id, permission, status) VALUES (?, ?, 'RW', 1) ``` ### 查询逻辑 ```python # 查询时返回所有路由(包括禁用的) SELECT sr.*, rr.status as route_status FROM role_route rr JOIN sys_routes sr ON rr.route_id = sr.id WHERE rr.role_id = ? -- 不限制status,返回所有记录 # 将 status 字段映射为 enabled route['enabled'] = route['route_status'] == 1 ``` --- ## 📝 版本对比 | 特性 | v3.1 | v3.2 | |------|------|------| | 取消勾选行为 | 删除记录 | 设置 status=0 | | 路由显示 | 取消勾选后消失 | 取消勾选后仍显示 | | 数据库操作 | DELETE | UPDATE status | | 权限检查 | 无 | 仅省级管理员 | | 返回字段 | assigned_count, removed_count | enabled_count, disabled_count, inserted_count | --- ## 💡 常见问题 ### Q1: 为什么取消勾选后路由还显示? **A**: v3.2 采用状态管理模式,取消勾选只是将 status 设置为 0(禁用),不会删除记录。这样可以保留历史配置,方便恢复。 ### Q2: 非省级管理员调用修改接口会怎样? **A**: 返回 403 错误,提示"权限不足:仅省级管理员可以修改角色路由权限" ### Q3: enabled 和 assigned 有什么区别? **A**: - `enabled` (v3.2): 基于 role_route.status 字段,表示路由是否启用 - `assigned` (v3.2旧版): 基于记录是否存在,已废弃 ### Q4: 如何查看只启用的路由? **A**: 调用接口时传参 `include_disabled=false`(默认为 true,返回所有) --- **文档版本**: v3.2 **最后更新**: 2025-11-28 **维护者**: Backend Team