feat(management): add API permission client
This commit is contained in:
209
clinical-web/src/api/management/permissions.ts
Normal file
209
clinical-web/src/api/management/permissions.ts
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import { unwrapApiResponse, unwrapNullableApiResponse } from '@/utils/api-response'
|
||||||
|
import { request } from '@/utils/request'
|
||||||
|
import type { ApiResponse, PageResult } from '@/types/common'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ApiPermissionListResponse,
|
||||||
|
ApiPermissionQuery,
|
||||||
|
ApiPermissionRecord,
|
||||||
|
ApiPermissionResponseDto,
|
||||||
|
BackendPage,
|
||||||
|
CreateApiPermissionRequest,
|
||||||
|
UpdateApiPermissionRequest,
|
||||||
|
} from './types'
|
||||||
|
|
||||||
|
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||||
|
|
||||||
|
export const isApiPermissionMockEnabled = useMockData
|
||||||
|
|
||||||
|
const mockRecords: ApiPermissionRecord[] = [
|
||||||
|
{
|
||||||
|
id: 'api-permission-001',
|
||||||
|
parentId: null,
|
||||||
|
code: 'system:user:query',
|
||||||
|
name: '查询用户',
|
||||||
|
resourceType: 'USER',
|
||||||
|
resourcePath: '/api/v1/users',
|
||||||
|
action: 'QUERY',
|
||||||
|
status: 'ENABLED',
|
||||||
|
createdAt: '2026-08-27 09:00',
|
||||||
|
updatedAt: '2026-08-27 09:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'api-permission-002',
|
||||||
|
parentId: null,
|
||||||
|
code: 'system:sign-task:create',
|
||||||
|
name: '创建签署任务',
|
||||||
|
resourceType: 'SIGN_TASK',
|
||||||
|
resourcePath: '/api/v1/sign-tasks',
|
||||||
|
action: 'CREATE',
|
||||||
|
status: 'ENABLED',
|
||||||
|
createdAt: '2026-08-27 09:02',
|
||||||
|
updatedAt: '2026-08-27 09:02',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
function formatDateTime(value: string | null | undefined) {
|
||||||
|
if (!value) {
|
||||||
|
return '—'
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(value)
|
||||||
|
|
||||||
|
if (Number.isNaN(date.getTime())) {
|
||||||
|
return value
|
||||||
|
.replace('T', ' ')
|
||||||
|
.replace(/\.\d+Z$/, '')
|
||||||
|
.replace(/Z$/, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const pad = (part: number) => String(part).padStart(2, '0')
|
||||||
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(
|
||||||
|
date.getHours(),
|
||||||
|
)}:${pad(date.getMinutes())}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapPermission(dto: ApiPermissionResponseDto): ApiPermissionRecord {
|
||||||
|
return {
|
||||||
|
id: dto.id,
|
||||||
|
parentId: dto.parentId ?? null,
|
||||||
|
code: dto.code,
|
||||||
|
name: dto.name,
|
||||||
|
resourceType: dto.resourceType,
|
||||||
|
resourcePath: dto.resourcePath ?? '',
|
||||||
|
action: dto.action ?? 'QUERY',
|
||||||
|
status: dto.status ?? 'ENABLED',
|
||||||
|
createdAt: formatDateTime(dto.createdAt),
|
||||||
|
updatedAt: formatDateTime(dto.updatedAt ?? dto.createdAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePage<T>(
|
||||||
|
data: BackendPage<T> | T[],
|
||||||
|
fallbackPage: number,
|
||||||
|
fallbackPageSize: number,
|
||||||
|
): PageResult<T> {
|
||||||
|
const records = Array.isArray(data) ? data : (data.records ?? data.items ?? data.content ?? [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
records,
|
||||||
|
total: Array.isArray(data) ? records.length : (data.total ?? records.length),
|
||||||
|
page: Array.isArray(data) ? fallbackPage : (data.page ?? fallbackPage),
|
||||||
|
pageSize: Array.isArray(data) ? fallbackPageSize : (data.size ?? fallbackPageSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toBackendQuery(query: ApiPermissionQuery) {
|
||||||
|
const params: Record<string, string | number> = {
|
||||||
|
page: Math.max(query.page, 1),
|
||||||
|
size: Math.min(Math.max(query.pageSize, 1), 200),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.keyword?.trim()) {
|
||||||
|
params.keyword = query.keyword.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPermissions(query: ApiPermissionQuery): Promise<ApiPermissionListResponse> {
|
||||||
|
if (!useMockData) {
|
||||||
|
return request
|
||||||
|
.get<ApiResponse<BackendPage<ApiPermissionResponseDto>>>('/v1/permissions', {
|
||||||
|
params: toBackendQuery(query),
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const page = normalizePage(unwrapApiResponse(response), query.page, query.pageSize)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...page,
|
||||||
|
records: page.records.map(mapPermission),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyword = query.keyword?.trim().toLowerCase()
|
||||||
|
const filteredRecords = mockRecords.filter((record) => {
|
||||||
|
return (
|
||||||
|
!keyword ||
|
||||||
|
[record.code, record.name, record.resourceType, record.resourcePath]
|
||||||
|
.join(' ')
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(keyword)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
const page = Math.max(query.page, 1)
|
||||||
|
const pageSize = Math.max(query.pageSize, 1)
|
||||||
|
const start = (page - 1) * pageSize
|
||||||
|
|
||||||
|
return Promise.resolve({
|
||||||
|
records: filteredRecords.slice(start, start + pageSize).map((record) => ({ ...record })),
|
||||||
|
total: filteredRecords.length,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPermission(id: string): Promise<ApiPermissionRecord | null> {
|
||||||
|
if (useMockData) {
|
||||||
|
const record = mockRecords.find((item) => item.id === id)
|
||||||
|
return record ? { ...record } : null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request.get<ApiResponse<ApiPermissionResponseDto>>(
|
||||||
|
`/v1/permissions/${encodeURIComponent(id)}`,
|
||||||
|
)
|
||||||
|
return mapPermission(unwrapApiResponse(response))
|
||||||
|
} catch (error) {
|
||||||
|
if (axios.isAxiosError(error) && error.response?.status === 404) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createPermission(
|
||||||
|
payload: CreateApiPermissionRequest,
|
||||||
|
): Promise<ApiPermissionRecord> {
|
||||||
|
if (useMockData) {
|
||||||
|
return Promise.reject(new Error('Mock 模式不执行 API 权限写操作'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
.post<ApiResponse<ApiPermissionResponseDto>>('/v1/permissions', payload)
|
||||||
|
.then(unwrapApiResponse)
|
||||||
|
.then(mapPermission)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updatePermission(
|
||||||
|
id: string,
|
||||||
|
payload: UpdateApiPermissionRequest,
|
||||||
|
): Promise<ApiPermissionRecord> {
|
||||||
|
if (useMockData) {
|
||||||
|
return Promise.reject(new Error('Mock 模式不执行 API 权限写操作'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
.put<ApiResponse<ApiPermissionResponseDto>>(
|
||||||
|
`/v1/permissions/${encodeURIComponent(id)}`,
|
||||||
|
payload,
|
||||||
|
)
|
||||||
|
.then(unwrapApiResponse)
|
||||||
|
.then(mapPermission)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deletePermission(id: string): Promise<void> {
|
||||||
|
if (useMockData) {
|
||||||
|
return Promise.reject(new Error('Mock 模式不执行 API 权限写操作'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return request
|
||||||
|
.delete<ApiResponse<null>>(`/v1/permissions/${encodeURIComponent(id)}`)
|
||||||
|
.then((response) => {
|
||||||
|
unwrapNullableApiResponse(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -146,6 +146,60 @@ export interface CreateRoleRequest {
|
|||||||
|
|
||||||
export type UpdateRoleRequest = Partial<CreateRoleRequest>
|
export type UpdateRoleRequest = Partial<CreateRoleRequest>
|
||||||
|
|
||||||
|
export type ApiPermissionStatus = 'ENABLED' | 'DISABLED'
|
||||||
|
export type ApiPermissionAction = 'QUERY' | 'CREATE' | 'UPDATE' | 'DISABLE'
|
||||||
|
|
||||||
|
export interface ApiPermissionQuery extends PageQuery {
|
||||||
|
keyword?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiPermissionRecord {
|
||||||
|
id: string
|
||||||
|
parentId: string | null
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
resourceType: string
|
||||||
|
resourcePath: string
|
||||||
|
action: ApiPermissionAction | string
|
||||||
|
status: ApiPermissionStatus
|
||||||
|
createdAt: string
|
||||||
|
updatedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiPermissionResponseDto {
|
||||||
|
id: string
|
||||||
|
parentId?: string | null
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
resourceType: string
|
||||||
|
resourcePath?: string | null
|
||||||
|
action?: ApiPermissionAction | string | null
|
||||||
|
status?: ApiPermissionStatus | null
|
||||||
|
createdAt?: string | null
|
||||||
|
updatedAt?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateApiPermissionRequest {
|
||||||
|
parentId?: string | null
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
resourceType: string
|
||||||
|
resourcePath?: string
|
||||||
|
action?: ApiPermissionAction
|
||||||
|
status?: ApiPermissionStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateApiPermissionRequest {
|
||||||
|
parentId?: string | null
|
||||||
|
name: string
|
||||||
|
resourceType: string
|
||||||
|
resourcePath?: string
|
||||||
|
action?: ApiPermissionAction
|
||||||
|
status: ApiPermissionStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ApiPermissionListResponse = PageResult<ApiPermissionRecord>
|
||||||
|
|
||||||
export interface CampusRecord {
|
export interface CampusRecord {
|
||||||
id: string
|
id: string
|
||||||
code: string
|
code: string
|
||||||
|
|||||||
Reference in New Issue
Block a user