feat(rbac-web): 前端页面级权限与「权限与角色」管理页

- 新增 rbac 的 api/types/mock,对接后端 catalog/roles/users;mock 模式与后端 PageCatalog 完全对齐
- EffectivePermissions 增加 allowedPages,auth store 新增 hasPage 判定
- 路由守卫按 route.name = 页面 Key 做页面级放行,无权时跳转到 scope 内首个可访问页面;AppShell 菜单按 hasPage 过滤
- 路由守卫 switchScope 失败自动重试一次;新增懒加载 chunk 失败整页自愈 onError,修复切页白屏
- PermissionGuard hidden 态改为友好空态提示;AuthRoleView 重写为完整的用户/角色/权限编辑界面
This commit is contained in:
zhaowei.huang
2026-05-29 23:51:57 +08:00
parent 37680a0ae7
commit 00cfcf2897
11 changed files with 976 additions and 106 deletions
@@ -0,0 +1,65 @@
import http from './http'
import type {
RbacRole, RbacUserView, RbacCatalog, SaveRolePayload, CreateUserPayload, UpdateUserPayload
} from '@/types/rbac'
import {
mockRbacCatalog, mockRbacRoles, mockRbacSaveRole, mockRbacDeleteRole,
mockRbacUsers, mockRbacCreateUser, mockRbacUpdateUser, mockRbacSetPassword, mockRbacDeleteUser
} from '@/mock/rbac'
const MOCK = import.meta.env.VITE_USE_MOCK === 'true'
export async function fetchCatalog(): Promise<RbacCatalog> {
if (MOCK) return mockRbacCatalog()
const { data } = await http.get<RbacCatalog>('/rbac/catalog')
return data
}
export async function fetchRoles(): Promise<RbacRole[]> {
if (MOCK) return mockRbacRoles()
const { data } = await http.get<RbacRole[]>('/rbac/roles')
return data
}
export async function saveRole(payload: SaveRolePayload): Promise<RbacRole> {
if (MOCK) return mockRbacSaveRole(payload)
if (payload.id) {
const { data } = await http.put<RbacRole>(`/rbac/roles/${payload.id}`, payload)
return data
}
const { data } = await http.post<RbacRole>('/rbac/roles', payload)
return data
}
export async function deleteRole(id: string): Promise<void> {
if (MOCK) return mockRbacDeleteRole(id)
await http.delete(`/rbac/roles/${id}`)
}
export async function fetchUsers(): Promise<RbacUserView[]> {
if (MOCK) return mockRbacUsers()
const { data } = await http.get<RbacUserView[]>('/rbac/users')
return data
}
export async function createUser(payload: CreateUserPayload): Promise<RbacUserView> {
if (MOCK) return mockRbacCreateUser(payload)
const { data } = await http.post<RbacUserView>('/rbac/users', payload)
return data
}
export async function updateUser(id: string, payload: UpdateUserPayload): Promise<RbacUserView> {
if (MOCK) return mockRbacUpdateUser(id, payload)
const { data } = await http.put<RbacUserView>(`/rbac/users/${id}`, payload)
return data
}
export async function setUserPassword(id: string, password: string): Promise<void> {
if (MOCK) return mockRbacSetPassword(id, password)
await http.put(`/rbac/users/${id}/password`, { password })
}
export async function deleteUser(id: string): Promise<void> {
if (MOCK) return mockRbacDeleteUser(id)
await http.delete(`/rbac/users/${id}`)
}