feat: 平台治理与权限体系完善,存储进度/GPU预留/审批中心与日志整合
- 平台治理: 租户用户权限层次、资源ACL、审批中心与审批模板、访问申请 - 存储: MinIO 存储进度迁移、对象存储安全加固与测试 - 计算: GPU 资源预留、compute 轮询与同步增强 - 权限: permission v2 迁移、权限安全验收测试 - 日志: 后端运行日志中文说明、操作日志整合 - 数据处理/评测: 数据转换与模型评测优化 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }>
|
||||
}
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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`)
|
||||
|
||||
Reference in New Issue
Block a user