update
This commit is contained in:
15
frontend/src/api/modules/acl.ts
Normal file
15
frontend/src/api/modules/acl.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { get, put } from '../request'
|
||||
|
||||
export interface AclEntry {
|
||||
subject_type: string
|
||||
subject_id: string
|
||||
permissions: string[]
|
||||
}
|
||||
|
||||
/** 资源 ACL 查询 */
|
||||
export const getAcl = (resourceType: string, resourceId: string) =>
|
||||
get<AclEntry[]>(`/resources/${resourceType}/${resourceId}/acl`)
|
||||
|
||||
/** 资源 ACL 设置 */
|
||||
export const setAcl = (resourceType: string, resourceId: string, entries: AclEntry[]) =>
|
||||
put<AclEntry[]>(`/resources/${resourceType}/${resourceId}/acl`, { entries })
|
||||
50
frontend/src/api/modules/approval.ts
Normal file
50
frontend/src/api/modules/approval.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { get, post } from '../request'
|
||||
|
||||
export interface ApprovalStep {
|
||||
approver_id?: string | null
|
||||
status: string
|
||||
}
|
||||
|
||||
export interface ApprovalTemplate {
|
||||
id: string
|
||||
name: string
|
||||
steps: ApprovalStep[]
|
||||
create_time?: string
|
||||
}
|
||||
|
||||
export interface ApprovalInstance {
|
||||
id: string
|
||||
template_id?: string | null
|
||||
resource_type: string
|
||||
resource_id: string
|
||||
applicant_id: string
|
||||
status: string
|
||||
current_step: number
|
||||
create_time?: string
|
||||
steps: Array<ApprovalStep & { step_index: number; comment?: string | null; time?: string | null }>
|
||||
}
|
||||
|
||||
export const getApprovalTemplates = () =>
|
||||
get<ApprovalTemplate[]>('/approvals/templates')
|
||||
|
||||
export const createApprovalTemplate = (payload: { name: string; steps: ApprovalStep[] }) =>
|
||||
post<ApprovalTemplate>('/approvals/templates', payload)
|
||||
|
||||
export const getApprovalInstances = (status?: string) =>
|
||||
get<ApprovalInstance[]>('/approvals', { status })
|
||||
|
||||
export const createApprovalInstance = (payload: {
|
||||
template_id?: string
|
||||
resource_type: string
|
||||
resource_id: string
|
||||
applicant_id: string
|
||||
}) => post<ApprovalInstance>('/approvals', payload)
|
||||
|
||||
export const getApprovalInstance = (id: string) =>
|
||||
get<ApprovalInstance>(`/approvals/${id}`)
|
||||
|
||||
export const decideApproval = (
|
||||
id: string,
|
||||
step_index: number,
|
||||
payload: { approver_id: string; approved: boolean; comment?: string },
|
||||
) => post<ApprovalInstance>(`/approvals/${id}/steps/${step_index}/decision`, payload)
|
||||
40
frontend/src/api/modules/audit.ts
Normal file
40
frontend/src/api/modules/audit.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { get } from '../request'
|
||||
import request from '../request'
|
||||
|
||||
export interface AuditLog {
|
||||
id: string
|
||||
tenant_id?: string
|
||||
project_id?: string
|
||||
actor_id?: string
|
||||
action?: string
|
||||
target_type?: string
|
||||
target_id?: string
|
||||
detail?: string
|
||||
client_ip?: string
|
||||
time?: string
|
||||
}
|
||||
|
||||
export interface AuditQuery {
|
||||
tenant_id?: string
|
||||
project_id?: string
|
||||
actor_id?: string
|
||||
action?: string
|
||||
target_type?: string
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
limit?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
/** 审计日志查询:使用 get 辅助函数,拦截器已解包,直接返回 { items, total } */
|
||||
export const getAuditLogs = (query: AuditQuery = {}) =>
|
||||
get<{ items: AuditLog[]; total: number }>('/system/audit-logs', query)
|
||||
|
||||
/** 审计日志导出 CSV:blob 响应走完整 axios response,需手动取 data */
|
||||
export const exportAuditLogs = (query: AuditQuery = {}) =>
|
||||
request<Blob>({
|
||||
url: '/system/audit-logs/export',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob',
|
||||
}).then((res) => res.data)
|
||||
35
frontend/src/api/modules/dashboard.ts
Normal file
35
frontend/src/api/modules/dashboard.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { get } from '../request'
|
||||
|
||||
export interface ServiceStatusStat {
|
||||
type: string
|
||||
status: 'normal' | 'busy' | 'error'
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface TrainingTaskStat {
|
||||
id: string
|
||||
name: string
|
||||
status: string
|
||||
train_type: string
|
||||
train_method: string
|
||||
base_model: string
|
||||
progress: number
|
||||
accuracy: number | null
|
||||
started_at: string
|
||||
}
|
||||
|
||||
export interface DashboardStats {
|
||||
online_services: number
|
||||
running_tasks: number
|
||||
pending_alerts: number
|
||||
training_7d: { date: string; train: number; gpu: number; accuracy: number | null }[]
|
||||
service_status: ServiceStatusStat[]
|
||||
training_tasks: TrainingTaskStat[]
|
||||
operation_distribution: { name: string; value: number }[]
|
||||
login_duration_rank: { user: string; role: string; duration: number }[]
|
||||
recent_login_users: { user: string; role: string; last_login: string }[]
|
||||
}
|
||||
|
||||
export function getDashboardStats() {
|
||||
return get<DashboardStats>('/dashboard/stats')
|
||||
}
|
||||
55
frontend/src/api/modules/project.ts
Normal file
55
frontend/src/api/modules/project.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { del, get, post, put } from '../request'
|
||||
|
||||
export interface Project {
|
||||
id: string
|
||||
tenant_id: string
|
||||
name: string
|
||||
code: string
|
||||
description?: string
|
||||
status: string
|
||||
quota?: Record<string, unknown>
|
||||
member_count?: number
|
||||
task_count?: number
|
||||
create_time?: string
|
||||
}
|
||||
|
||||
export interface ProjectMember {
|
||||
user_id: string
|
||||
role: string
|
||||
joined_at?: string
|
||||
}
|
||||
|
||||
/** 项目列表(按租户过滤,默认 default) */
|
||||
export const getProjects = (tenantId = 'default') =>
|
||||
get<Project[]>('/projects', { tenant_id: tenantId })
|
||||
|
||||
/** 项目详情 */
|
||||
export const getProject = (id: string) => get<Project>(`/projects/${id}`)
|
||||
|
||||
/** 创建项目 */
|
||||
export const createProject = (payload: Partial<Project>) =>
|
||||
post<Project>('/projects', payload)
|
||||
|
||||
/** 更新项目 */
|
||||
export const updateProject = (id: string, payload: Partial<Project>) =>
|
||||
put<Project>(`/projects/${id}`, payload)
|
||||
|
||||
/** 归档项目 */
|
||||
export const archiveProject = (id: string) =>
|
||||
post<Project>(`/projects/${id}/archive`)
|
||||
|
||||
/** 项目成员列表 */
|
||||
export const getProjectMembers = (id: string) =>
|
||||
get<ProjectMember[]>(`/projects/${id}/members`)
|
||||
|
||||
/** 添加成员 */
|
||||
export const addProjectMember = (id: string, payload: { user_id: string; role: string }) =>
|
||||
post<ProjectMember>(`/projects/${id}/members`, payload)
|
||||
|
||||
/** 更新成员角色 */
|
||||
export const updateProjectMember = (id: string, userId: string, role: string) =>
|
||||
put<ProjectMember>(`/projects/${id}/members/${userId}`, { role })
|
||||
|
||||
/** 移除成员 */
|
||||
export const removeProjectMember = (id: string, userId: string) =>
|
||||
del(`/projects/${id}/members/${userId}`)
|
||||
29
frontend/src/api/modules/retention.ts
Normal file
29
frontend/src/api/modules/retention.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { del, get, post, put } from '../request'
|
||||
|
||||
export interface RetentionPolicy {
|
||||
id: string
|
||||
name: string
|
||||
scope?: string | null
|
||||
rule?: string | null
|
||||
status: string
|
||||
create_time?: string
|
||||
create_by?: string | null
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
/** 留存策略列表 */
|
||||
export const getRetentionPolicies = () => get<RetentionPolicy[]>('/retention-policies')
|
||||
|
||||
/** 留存策略详情 */
|
||||
export const getRetentionPolicy = (id: string) => get<RetentionPolicy>(`/retention-policies/${id}`)
|
||||
|
||||
/** 创建留存策略 */
|
||||
export const createRetentionPolicy = (payload: Partial<RetentionPolicy>) =>
|
||||
post<RetentionPolicy>('/retention-policies', payload)
|
||||
|
||||
/** 更新留存策略 */
|
||||
export const updateRetentionPolicy = (id: string, payload: Partial<RetentionPolicy>) =>
|
||||
put<RetentionPolicy>(`/retention-policies/${id}`, payload)
|
||||
|
||||
/** 删除留存策略 */
|
||||
export const deleteRetentionPolicy = (id: string) => del(`/retention-policies/${id}`)
|
||||
@@ -25,12 +25,14 @@ export const getUsers = () => get<SystemUser[]>('/users')
|
||||
export const createUser = (payload: CreateUserPayload) =>
|
||||
post<SystemUser>('/users', payload)
|
||||
|
||||
/** 删除用户,currentUsername 用于防止删除当前登录账号 */
|
||||
export const deleteUser = (id: string, currentUsername: string) =>
|
||||
del<{ deleted: string }>(`/users/${encodeURIComponent(id)}`, {
|
||||
current_username: currentUsername,
|
||||
})
|
||||
|
||||
/** 更新用户角色、状态及页面权限 */
|
||||
export const updateUserAccess = (id: string, payload: UpdateUserAccessPayload) =>
|
||||
put<SystemUser>(`/users/${encodeURIComponent(id)}`, payload)
|
||||
|
||||
/** 重置用户密码 */
|
||||
export const resetUserPassword = (id: string, password?: string) =>
|
||||
post<{ reset: string }>(`/users/${encodeURIComponent(id)}/reset-password`, { password })
|
||||
|
||||
/** 删除用户(protected 管理员账号不允许删除) */
|
||||
export const deleteUser = (id: string) =>
|
||||
del<{ deleted: string }>(`/users/${encodeURIComponent(id)}`)
|
||||
|
||||
34
frontend/src/api/modules/tenant.ts
Normal file
34
frontend/src/api/modules/tenant.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { get, post, put } from '../request'
|
||||
|
||||
export interface Tenant {
|
||||
id: string
|
||||
name: string
|
||||
code: string
|
||||
status: string
|
||||
owner_user_id?: string | null
|
||||
quota: Record<string, unknown>
|
||||
retention_policy_id?: string | null
|
||||
create_time?: string
|
||||
}
|
||||
|
||||
/** 租户列表 */
|
||||
export const getTenants = () => get<Tenant[]>('/tenants')
|
||||
|
||||
/** 租户详情 */
|
||||
export const getTenant = (id: string) => get<Tenant>(`/tenants/${id}`)
|
||||
|
||||
/** 创建租户 */
|
||||
export const createTenant = (payload: Partial<Tenant>) =>
|
||||
post<Tenant>('/tenants', payload)
|
||||
|
||||
/** 更新租户 */
|
||||
export const updateTenant = (id: string, payload: Partial<Tenant>) =>
|
||||
put<Tenant>(`/tenants/${id}`, payload)
|
||||
|
||||
/** 设置租户配额 */
|
||||
export const setTenantQuota = (id: string, quota: Record<string, unknown>) =>
|
||||
put<Tenant>(`/tenants/${id}/quota`, { quota })
|
||||
|
||||
/** 设置租户留存策略 */
|
||||
export const setTenantRetention = (id: string, retention_policy_id: string) =>
|
||||
put<Tenant>(`/tenants/${id}/retention-policy`, { retention_policy_id })
|
||||
@@ -1,6 +1,5 @@
|
||||
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { touchSessionActivity } from '@/utils/sessionActivity'
|
||||
|
||||
/**
|
||||
* 后端统一响应格式
|
||||
@@ -18,9 +17,37 @@ const service: AxiosInstance = axios.create({
|
||||
timeout: 30000,
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
/**
|
||||
* 从 localStorage 取当前用户 token(登录时后端返回 platform-token-{user_id})。
|
||||
* 后端鉴权中间件依赖此 header 解析当前用户身份。
|
||||
*/
|
||||
function getAuthToken(): string | null {
|
||||
const USER_STORAGE_KEY = 'currentUser'
|
||||
const raw = localStorage.getItem(USER_STORAGE_KEY)
|
||||
if (raw) {
|
||||
try {
|
||||
const user = JSON.parse(raw)
|
||||
// 后端 login 返回的 token 格式为 platform-token-{user.id}
|
||||
if (user?.id) return `platform-token-${user.id}`
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
// 兼容改造前 admin 会话
|
||||
if (localStorage.getItem('username') === 'admin') return 'platform-token-admin'
|
||||
return null
|
||||
}
|
||||
|
||||
// 请求拦截器:注入 Authorization header
|
||||
service.interceptors.request.use(
|
||||
(config) => config,
|
||||
(config) => {
|
||||
const token = getAuthToken()
|
||||
if (token) {
|
||||
config.headers = config.headers || {}
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
(error) => Promise.reject(error),
|
||||
)
|
||||
|
||||
@@ -30,12 +57,9 @@ service.interceptors.response.use(
|
||||
const res = response.data as ApiResult
|
||||
// 二进制流等非 JSON 响应直接返回
|
||||
if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') {
|
||||
touchSessionActivity()
|
||||
return response
|
||||
}
|
||||
if (res.code === 0) {
|
||||
// 生成进度轮询也属于用户正在使用系统,避免长任务结束后被误判为会话过期。
|
||||
touchSessionActivity()
|
||||
return res.data
|
||||
}
|
||||
// 业务错误
|
||||
|
||||
Reference in New Issue
Block a user