feat: 平台治理与权限体系完善,存储进度/GPU预留/审批中心与日志整合

- 平台治理: 租户用户权限层次、资源ACL、审批中心与审批模板、访问申请
- 存储: MinIO 存储进度迁移、对象存储安全加固与测试
- 计算: GPU 资源预留、compute 轮询与同步增强
- 权限: permission v2 迁移、权限安全验收测试
- 日志: 后端运行日志中文说明、操作日志整合
- 数据处理/评测: 数据转换与模型评测优化

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
wuyongtao
2026-08-21 09:49:48 +08:00
parent 080ef6ab00
commit 6f0e82f351
94 changed files with 9547 additions and 1045 deletions

View File

@@ -21,17 +21,49 @@ export interface ApprovalInstance {
status: string
current_step: number
create_time?: string
action?: string | null
tenant_id?: string | null
execution_status?: string | null
steps: Array<ApprovalStep & { step_index: number; comment?: string | null; time?: string | null }>
}
export interface ResourceAccessRequest {
id: string
tenant_id: string
resource_type: string
resource_id: string
applicant_id: string
principal_type: string
principal_id: string
requested_permissions: string[]
reason?: string | null
approval_id?: string | null
status: string
expires_at?: string | null
created_at?: string
cancelled_at?: string | null
cancelled_by?: string | null
}
export interface GpuRequestOption {
id: string
code: string
name: string
gpus: Array<{
index: number
name: string
memory_total_gb: number
}>
}
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 getApprovalInstances = (status?: string, mine = false) =>
get<ApprovalInstance[]>('/approvals', { status, mine: mine || undefined })
export const createApprovalInstance = (payload: {
template_id?: string
@@ -46,5 +78,31 @@ export const getApprovalInstance = (id: string) =>
export const decideApproval = (
id: string,
step_index: number,
payload: { approver_id: string; approved: boolean; comment?: string },
payload: { approved: boolean; comment?: string },
) => post<ApprovalInstance>(`/approvals/${id}/steps/${step_index}/decision`, payload)
export const createResourceAccessRequest = (payload: {
resource_type: string
resource_id: string
principal_type?: 'user' | 'role'
principal_id?: string
requested_permissions: string[]
reason?: string
expires_at?: string
}) => post<ResourceAccessRequest>('/approvals/resource-access/requests', payload)
export const getResourceAccessRequests = (status?: string) =>
get<ResourceAccessRequest[]>('/approvals/resource-access/requests', { status })
export const cancelResourceAccessRequest = (id: string) =>
post<ResourceAccessRequest>(`/approvals/resource-access/requests/${id}/cancel`, {})
export const getGpuRequestOptions = () =>
get<{ nodes: GpuRequestOption[] }>('/approvals/gpu-options')
export const requestGpuAccess = (payload: {
assignments: Array<{ node_id: string; gpu_index: number }>
reason?: string
}) => post<{ approval_required?: boolean; approval_id?: string; approval?: ApprovalInstance }>(
'/approvals/gpu-requests', payload,
)

View File

@@ -11,6 +11,11 @@ export interface AuditLog {
target_id?: string
detail?: string
client_ip?: string
result?: string
reason?: string
request_id?: string
session_id?: string
metadata?: string | Record<string, unknown>
time?: string
}

View File

@@ -1,4 +1,4 @@
import { get, post, del } from '../request'
import { get, post, del, getAuthHeaders } from '../request'
import type { CompareTask, CompareModelRef } from '@/types'
const INFERENCE_START_TIMEOUT_MS = 15 * 60 * 1000
@@ -78,7 +78,10 @@ export const streamChatReal = (data: any): Promise<Response> => {
}
return fetch('/modelTF/model-compare/stream-chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
...getAuthHeaders(),
},
body: JSON.stringify({
messages,
temperature: data.temperature ?? 0.7,

View File

@@ -10,7 +10,12 @@ export interface DataConvertTask {
output_count: number
error_message: string
create_time: string
update_time?: string
update_time?: string
created_by?: string | null
creator_name?: string | null
processed_by?: string | null
processor_name?: string | null
processed_at?: string | null
input_files?: Array<{ name: string; size: number }>
}

View File

@@ -38,6 +38,10 @@ export interface ModelExportJob {
payload?: Record<string, unknown>
create_time?: string
completed_at?: string
created_by?: string
tenant_id?: string
archive_status?: string
archive_error?: string
}
/** 模型列表 */
@@ -51,7 +55,7 @@ export const getModelByName = (name: string) => get<ModelItem>(`/model-manage/na
/** 本地模型路径列表 */
export const getLocalModels = () =>
get<{ models: { path: string; name: string; source?: string }[] }>('/model-manage/local-models')
get<{ models: { path: string; name: string; storage_status?: string }[] }>('/model-manage/local-models')
/** 已训练模型列表 */
export const getTrainedModels = () =>
@@ -97,9 +101,16 @@ export const mergeModel = (data: {
output_model_name?: string
}) => post('/model-manage/merge', data, { timeout: 15 * 60 * 1000 })
/** 导出已训练模型权重 */
export const exportModelUrl = (modelName: string) =>
`/modelTF/model-manage/trained-models/${encodeURIComponent(modelName)}/export`
/** 导出已训练模型权重,沿用节点缓存和 MinIO 归档流程 */
export const exportModel = (data: {
trained_model_id?: string | number
model_name?: string
base_model_path?: string
adapter_path?: string
compute_node_id?: string
output_model_name?: string
export_quantization_bit?: 0 | 4 | 8
}) => post('/model-manage/export', data, { timeout: 15 * 60 * 1000 })
/** 测试在线模型连通性 */
export const testOnlineModel = (data: {

View File

@@ -9,11 +9,37 @@ export interface Tenant {
quota: Record<string, unknown>
retention_policy_id?: string | null
create_time?: string
deleted_at?: string | null
deleted_by?: string | null
}
export interface TenantMember {
tenant_id: string
user_id: string
username?: string
display_name?: string
role: 'owner' | 'admin' | 'member' | 'viewer'
status: 'active' | 'pending' | 'disabled' | 'expired'
invited_by?: string | null
joined_at?: string | null
expires_at?: string | null
}
export interface TenantQuotaUsage {
tenant_id: string
quota: Record<string, unknown>
gpu_limit: number
gpu_reserved: number
storage_reserved: number
reservations: number
}
/** 租户列表 */
export const getTenants = () => get<Tenant[]>('/tenants')
/** 当前用户可切换的 active 租户及成员角色 */
export const getMyTenants = () => get<Tenant[]>('/tenants/mine')
/** 租户详情 */
export const getTenant = (id: string) => get<Tenant>(`/tenants/${id}`)
@@ -28,6 +54,10 @@ export const updateTenant = (id: string, payload: Partial<Tenant>) =>
/** 删除租户 */
export const deleteTenant = (id: string) => del(`/tenants/${id}`)
/** 恢复软删除租户 */
export const restoreTenant = (id: string) =>
post<Tenant>(`/tenants/${id}/restore`, {})
/** 设置租户配额 */
export const setTenantQuota = (id: string, quota: Record<string, unknown>) =>
put<Tenant>(`/tenants/${id}/quota`, quota)
@@ -35,3 +65,26 @@ export const setTenantQuota = (id: string, quota: Record<string, unknown>) =>
/** 设置租户留存策略 */
export const setTenantRetention = (id: string, retention_policy_id: string) =>
put<Tenant>(`/tenants/${id}/retention-policy`, { retention_policy_id })
export const getTenantMembers = (id: string) =>
get<TenantMember[]>(`/tenants/${id}/members`)
export const inviteTenantMember = (
id: string,
payload: { user_id: string; role?: TenantMember['role']; expires_at?: string },
) => post<TenantMember>(`/tenants/${id}/members/invite`, payload)
export const updateTenantMember = (id: string, userId: string, payload: Partial<TenantMember>) =>
put<TenantMember>(`/tenants/${id}/members/${userId}`, payload)
export const removeTenantMember = (id: string, userId: string) =>
del(`/tenants/${id}/members/${userId}`)
export const acceptTenantInvitation = (id: string, userId: string) =>
post<TenantMember>(`/tenants/${id}/members/${userId}/accept`, {})
export const getTenantInvitations = () =>
get<TenantMember[]>('/tenants/invitations')
export const getTenantQuotaUsage = (id: string) =>
get<TenantQuotaUsage>(`/tenants/${id}/quota/usage`)