完善角色权限与数据隔离

This commit is contained in:
yml2213
2026-07-26 14:00:50 +08:00
parent b483cbc26d
commit 16d9ab0e5e
38 changed files with 2847 additions and 292 deletions
+48
View File
@@ -587,6 +587,7 @@ export const createStaff = (data: { username: string; password: string; nickname
post<StaffUser>('/staff', data)
export const updateStaff = (id: number, data: { nickname?: string; role?: string; status?: string; password?: string }) =>
put<StaffUser>(`/staff/${id}`, data)
export const batchStaff = (data: { ids: number[]; action: string; new_role?: string }) => post('/staff/batch', data)
export const deleteStaff = (id: number) => del(`/staff/${id}`)
// Tenant settings
@@ -678,3 +679,50 @@ export const createAnnouncement = (data: { title: string; content: string; statu
export const updateAnnouncement = (id: number, data: Partial<Announcement>) =>
put<Announcement>(`/admin/announcements/${id}`, data)
export const deleteAnnouncement = (id: number) => del(`/admin/announcements/${id}`)
// 权限管理
export interface Permission {
id: number
code: string
name: string
module: string
category: string
sort_order: number
}
export interface RoleWithStats {
id: number
tenant_id: number
name: string
code: string
type: 'builtin' | 'custom'
desc: string
member_count: number
perm_count: number
created_at: string
updated_at: string
}
export interface RoleDetail {
role: RoleWithStats
permissions: string[]
data_scopes: Record<string, 'all' | 'self'>
member_count: number
}
export interface MePermissions {
role: string
permissions: string[]
}
export const getPermissions = () => get<Permission[]>('/roles/permissions')
export const getRoles = () => get<RoleWithStats[]>('/roles')
export const getRoleDetail = (id: number) => get<RoleDetail>(`/roles/${id}`)
export const createRole = (data: { name: string; desc?: string; permissions: string[]; data_scopes?: Record<string, string> }) =>
post<RoleWithStats>('/roles', data)
export const updateRole = (id: number, data: { name?: string; desc?: string; permissions: string[]; data_scopes: Record<string, string> }) =>
put<RoleWithStats>(`/roles/${id}`, data)
export const updateBuiltinRole = (id: number, data: { desc?: string; permissions: string[]; data_scopes: Record<string, string> }) =>
put<RoleWithStats>(`/roles/${id}/builtin`, data)
export const deleteRole = (id: number) => del(`/roles/${id}`)
export const mePermissions = () => get<MePermissions>('/me/permissions')
+16 -3
View File
@@ -1,8 +1,14 @@
const BASE = '/api'
let token = ''
export const PERMISSIONS_CHANGED_EVENT = 'permissions-changed'
export function setToken(t: string) { token = t }
let token = ''
let permissionVersion = ''
export function setToken(t: string) {
if (token !== t) permissionVersion = ''
token = t
}
export function getToken() { return token }
interface Response<T = unknown> {
@@ -32,6 +38,14 @@ async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
if (token) headers['Authorization'] = `Bearer ${token}`
const res = await fetch(`${BASE}${url}`, { ...options, headers })
const nextPermissionVersion = res.headers.get('X-Permission-Version') || ''
if (nextPermissionVersion) {
const changed = permissionVersion !== '' && permissionVersion !== nextPermissionVersion
permissionVersion = nextPermissionVersion
if (changed && typeof window !== 'undefined') {
window.dispatchEvent(new Event(PERMISSIONS_CHANGED_EVENT))
}
}
const json = await res.json()
if (json.code !== 0) {
@@ -87,4 +101,3 @@ export async function downloadFile(path: string, fallbackName: string) {
a.remove()
URL.revokeObjectURL(url)
}