第一次提交
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)
|
||||
80
frontend/src/api/modules/compare.ts
Normal file
80
frontend/src/api/modules/compare.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { get, post, del } from '../request'
|
||||
import type { CompareTask, CompareModelRef } from '@/types'
|
||||
|
||||
/** 推理/对比任务列表 */
|
||||
export const getCompareList = () => get<CompareTask[]>('/model-compare')
|
||||
|
||||
/** 任务详情 */
|
||||
export const getCompare = (id: string | number) => get<CompareTask>(`/model-compare/${id}`)
|
||||
|
||||
/** 创建任务 */
|
||||
export const createCompare = (data: Partial<CompareTask>) =>
|
||||
post<{ id: string | number }>('/model-compare', data)
|
||||
|
||||
/** 删除任务 */
|
||||
export const deleteCompare = (id: string | number) => del(`/model-compare/${id}`)
|
||||
|
||||
/** 更新任务加载状态 */
|
||||
export const updateLoadStatus = (id: string | number, load_status: any) =>
|
||||
post(`/model-compare/${id}/load-status`, { load_status })
|
||||
|
||||
/** 查询任务加载状态 */
|
||||
export const getLoadStatus = (id: string | number) =>
|
||||
get<{ all_ready: boolean; loaded_models: any[] }>(`/model-compare/${id}/load-status`)
|
||||
|
||||
/** 停止所有旧模型服务 */
|
||||
export const stopAllModels = () => post('/model-compare/all/stop-all')
|
||||
|
||||
/** 启动单个模型服务 */
|
||||
export const startModel = (id: string | number, data: Partial<CompareModelRef>) =>
|
||||
post<{ pid: number; port: number }>(`/model-compare/${id}/start-model`, data)
|
||||
|
||||
/** 按 PID 停止模型进程 */
|
||||
export const stopModelByPid = (pid: number) =>
|
||||
post('/model-compare/stop-by-pid', { pid })
|
||||
|
||||
/** 加载任务 */
|
||||
export const loadCompare = (id: string | number) => post(`/model-compare/${id}/load`)
|
||||
|
||||
/** 卸载任务 */
|
||||
export const unloadCompare = (id: string | number) => post(`/model-compare/${id}/unload`)
|
||||
|
||||
/** 流式对话(mock 模式下返回非流式响应,调用方需兼容) */
|
||||
export const streamChat = async (data: any): Promise<any> => {
|
||||
// Mock 环境:返回非流式响应对象,调用方检测 content-type 决定如何处理
|
||||
const resp = await post<{ response: string }>('/model-compare/stream-chat', data)
|
||||
return {
|
||||
ok: true,
|
||||
body: {
|
||||
getReader: () => {
|
||||
// 模拟流式读取:把整个响应切成小块逐个返回
|
||||
const text = resp?.response || ''
|
||||
const encoder = new TextEncoder()
|
||||
const chunks = [text.slice(0, text.length / 3), text.slice(text.length / 3, 2 * text.length / 3), text.slice(2 * text.length / 3)]
|
||||
let i = 0
|
||||
return {
|
||||
read: async () => {
|
||||
if (i >= chunks.length) return { done: true, value: undefined }
|
||||
const value = encoder.encode(chunks[i++])
|
||||
return { done: false, value }
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/** 非流式对话(按端口代理) */
|
||||
export const chatWithPort = (data: any) => post('/model-compare/chat-with-port', data)
|
||||
|
||||
/** 批量对话(API 类型模型) */
|
||||
export const batchChat = (data: any) => post('/model-chat/batch', data)
|
||||
|
||||
/** 本地 transformers 模型对话 */
|
||||
export const localChat = (data: any) => post('/model-chat/local/chat', data)
|
||||
|
||||
/** 预加载本地模型 */
|
||||
export const preloadLocalModel = (data: any) => post('/model-chat/local/preload', data)
|
||||
|
||||
/** 预加载已训练模型 */
|
||||
export const preloadTrainedModel = (data: any) => post('/model-chat/trained/preload', data)
|
||||
85
frontend/src/api/modules/compute.ts
Normal file
85
frontend/src/api/modules/compute.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { get, post, put } from '../request'
|
||||
|
||||
export interface ComputeNode {
|
||||
id: string
|
||||
code: string
|
||||
name: string
|
||||
api_base_url: string
|
||||
file_gateway_url: string
|
||||
enabled: boolean
|
||||
scheduler_status: string
|
||||
scheduler_weight: number
|
||||
tags: string[]
|
||||
gpu_count: number
|
||||
current_running_jobs: number
|
||||
max_parallel_jobs: number
|
||||
data_root: string
|
||||
model_root: string
|
||||
log_root: string
|
||||
last_health_check_at?: string
|
||||
}
|
||||
|
||||
export interface ComputeGpu {
|
||||
id: number
|
||||
node_id: string
|
||||
node_code: string
|
||||
node_name: string
|
||||
name: string
|
||||
uuid: string
|
||||
status: string
|
||||
gpu_percent: number
|
||||
memory_used_gb: number
|
||||
memory_total_gb: number
|
||||
memory_percent: number
|
||||
temperature: number
|
||||
power_w: number
|
||||
power_limit_w: number
|
||||
processes?: Array<{
|
||||
pid: number
|
||||
name: string
|
||||
memory_used_gb: number
|
||||
task_name?: string
|
||||
user?: string
|
||||
}>
|
||||
}
|
||||
|
||||
export interface ComputeQueueItem {
|
||||
id: string
|
||||
name: string
|
||||
status: string
|
||||
progress: number
|
||||
compute_node_id?: string
|
||||
gpus: number[]
|
||||
create_time?: string
|
||||
}
|
||||
|
||||
export interface ResourceReplica {
|
||||
id: string
|
||||
node_id: string
|
||||
resource_type: string
|
||||
resource_id: string
|
||||
local_path: string
|
||||
status: string
|
||||
sync_status: string
|
||||
create_time: string
|
||||
}
|
||||
|
||||
export const getComputeNodes = () => get<ComputeNode[]>('/compute/nodes')
|
||||
|
||||
export const updateComputeNode = (id: string, data: Partial<ComputeNode>) =>
|
||||
put<ComputeNode>(`/compute/nodes/${id}`, data)
|
||||
|
||||
export const testComputeNode = (id: string) =>
|
||||
post<{ node_id: string; success: boolean; latency_ms: number }>(`/compute/nodes/${id}/test-connection`)
|
||||
|
||||
export const enableComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/enable`)
|
||||
|
||||
export const disableComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/disable`)
|
||||
|
||||
export const drainComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/drain`)
|
||||
|
||||
export const getComputeGpus = () => get<ComputeGpu[]>('/compute/gpus')
|
||||
|
||||
export const getComputeQueue = () => get<ComputeQueueItem[]>('/compute/queue')
|
||||
|
||||
export const getNodeReplicas = (id: string) => get<ResourceReplica[]>(`/compute/nodes/${id}/replicas`)
|
||||
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: string }[]
|
||||
recent_login_users: { user: string; role: string; last_login: string }[]
|
||||
}
|
||||
|
||||
export function getDashboardStats() {
|
||||
return get<DashboardStats>('/dashboard/stats')
|
||||
}
|
||||
98
frontend/src/api/modules/dataset.ts
Normal file
98
frontend/src/api/modules/dataset.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { get, post, put, del } from '../request'
|
||||
import type { DatasetItem, DatasetVersion, DatasetVersionList } from '@/types'
|
||||
|
||||
/** 数据集列表 */
|
||||
export const getDatasetList = () => get<DatasetItem[]>('/dataset-manage')
|
||||
|
||||
/** 数据集详情 */
|
||||
export const getDataset = (id: string | number) => get<DatasetItem>(`/dataset-manage/${id}`)
|
||||
|
||||
/** 创建数据集 */
|
||||
export const createDataset = (data: Partial<DatasetItem>) =>
|
||||
post<{ id: string | number }>('/dataset-manage', data)
|
||||
|
||||
/** 更新数据集 */
|
||||
export const updateDataset = (id: string | number, data: Partial<DatasetItem>) =>
|
||||
put(`/dataset-manage/${id}`, data)
|
||||
|
||||
/** 删除数据集 */
|
||||
export const deleteDataset = (id: string | number) => del(`/dataset-manage/${id}`)
|
||||
|
||||
/** 上传数据集文件(multipart,字段名 files) */
|
||||
export const uploadDatasetFiles = (datasetId: string | number, files: File[]) => {
|
||||
const formData = new FormData()
|
||||
files.forEach((f) => formData.append('files', f))
|
||||
return post(`/dataset-manage/upload/${datasetId}`, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
}
|
||||
|
||||
/** 预览数据集文件内容 */
|
||||
export const previewDatasetFile = (fileId: string | number) =>
|
||||
get<{ content: string }>(`/dataset-manage/preview/${encodeURIComponent(fileId)}`)
|
||||
|
||||
/** 数据集文件版本列表 */
|
||||
export const getDatasetFileVersions = (fileId: string | number) =>
|
||||
get<DatasetVersionList>(`/dataset-manage/versions/${encodeURIComponent(fileId)}`)
|
||||
|
||||
/** 读取指定历史版本内容(不改变当前版本) */
|
||||
export const getDatasetFileVersionContent = (fileId: string | number, versionId: string) =>
|
||||
get<{ version: DatasetVersion; content: string }>(
|
||||
`/dataset-manage/versions/${encodeURIComponent(fileId)}/${encodeURIComponent(versionId)}`,
|
||||
)
|
||||
|
||||
/** 保存为新版本,并自动设为当前版本 */
|
||||
export const createDatasetFileVersion = (
|
||||
fileId: string | number,
|
||||
content: string,
|
||||
options: {
|
||||
description?: string
|
||||
baseVersionId: string
|
||||
expectedCurrentVersionId: string
|
||||
},
|
||||
) =>
|
||||
post<{ version: DatasetVersion; content: string }>(
|
||||
`/dataset-manage/versions/${encodeURIComponent(fileId)}`,
|
||||
{
|
||||
content,
|
||||
description: options.description || '在线编辑',
|
||||
base_version_id: options.baseVersionId,
|
||||
expected_current_version_id: options.expectedCurrentVersionId,
|
||||
},
|
||||
)
|
||||
|
||||
/** 切换当前使用的数据集版本 */
|
||||
export const activateDatasetFileVersion = (
|
||||
fileId: string | number,
|
||||
versionId: string,
|
||||
expectedCurrentVersionId: string,
|
||||
) =>
|
||||
put<{ version: DatasetVersion; content: string }>(
|
||||
`/dataset-manage/versions/${encodeURIComponent(fileId)}/active`,
|
||||
{ version_id: versionId, expected_current_version_id: expectedCurrentVersionId },
|
||||
)
|
||||
|
||||
/** 删除非当前、非初始的历史版本 */
|
||||
export const deleteDatasetFileVersion = (
|
||||
fileId: string | number,
|
||||
versionId: string,
|
||||
expectedCurrentVersionId: string,
|
||||
) =>
|
||||
del<DatasetVersionList>(
|
||||
`/dataset-manage/versions/${encodeURIComponent(fileId)}/${encodeURIComponent(versionId)}`,
|
||||
{ expected_current_version_id: expectedCurrentVersionId },
|
||||
)
|
||||
|
||||
/** 下载文件 URL */
|
||||
export const downloadFileUrl = (
|
||||
datasetId: string | number,
|
||||
fileId: string | number,
|
||||
versionId?: string,
|
||||
) => {
|
||||
const baseUrl = `/modelTF/dataset-manage/download/${datasetId}/${fileId}`
|
||||
return versionId ? `${baseUrl}?version_id=${encodeURIComponent(versionId)}` : baseUrl
|
||||
}
|
||||
|
||||
/** 打包下载数据集 URL */
|
||||
export const downloadDatasetUrl = (datasetId: string | number) =>
|
||||
`/modelTF/dataset-manage/download/${datasetId}`
|
||||
31
frontend/src/api/modules/eval.ts
Normal file
31
frontend/src/api/modules/eval.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { get, post, put, del } from '../request'
|
||||
import type { EvalTask, EvalTaskDetail, Dimension, StartEvalPayload } from '@/types'
|
||||
|
||||
/** 评测任务列表 */
|
||||
export const getEvalList = () => get<EvalTask[]>('/model-eval')
|
||||
|
||||
/** 评测任务详情 */
|
||||
export const getEvalDetail = (id: string | number) => get<EvalTaskDetail>(`/model-eval/${id}`)
|
||||
|
||||
/** 删除评测任务 */
|
||||
export const deleteEval = (id: string | number) => del(`/model-eval/${id}`)
|
||||
|
||||
/** 启动评测 */
|
||||
export const startEval = (data: StartEvalPayload) => post('/model-eval/start', data)
|
||||
|
||||
/** 评测维度列表 */
|
||||
export const getDimensionList = () => get<Dimension[]>('/dimension')
|
||||
|
||||
/** 评测维度详情 */
|
||||
export const getDimension = (id: string | number) => get<Dimension>(`/dimension/${id}`)
|
||||
|
||||
/** 创建维度 */
|
||||
export const createDimension = (data: Partial<Dimension>) =>
|
||||
post<{ id: string | number }>('/dimension', data)
|
||||
|
||||
/** 编辑维度 */
|
||||
export const updateDimension = (id: string | number, data: Partial<Dimension>) =>
|
||||
put(`/dimension/${id}`, data)
|
||||
|
||||
/** 删除维度 */
|
||||
export const deleteDimension = (id: string | number) => del(`/dimension/${id}`)
|
||||
40
frontend/src/api/modules/fineTune.ts
Normal file
40
frontend/src/api/modules/fineTune.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { get, post, put, del } from '../request'
|
||||
import type { FineTuneStartPayload, FineTuneTask, TrainingProgress } from '@/types'
|
||||
|
||||
/** 训练任务列表 */
|
||||
export const getFineTuneList = () => get<FineTuneTask[]>('/fine-tune')
|
||||
|
||||
/** 训练任务详情 */
|
||||
export const getFineTune = (id: string | number) => get<FineTuneTask>(`/fine-tune/${id}`)
|
||||
|
||||
/** 任务名查重 */
|
||||
export const checkFineTuneName = (name: string) =>
|
||||
get<{ exists: boolean }>('/fine-tune/check-name', { name })
|
||||
|
||||
/** 创建训练任务记录(第一步) */
|
||||
export const createFineTune = (data: Partial<FineTuneTask>) =>
|
||||
post<{ id: string | number }>('/fine-tune', data)
|
||||
|
||||
/** 启动训练(第二步) */
|
||||
export const startFineTune = (data: FineTuneStartPayload) => post('/fine-tune/start', data)
|
||||
|
||||
/** 更新训练任务 */
|
||||
export const updateFineTune = (id: string | number, data: Partial<FineTuneTask>) =>
|
||||
put(`/fine-tune/${id}`, data)
|
||||
|
||||
/** 停止训练任务 */
|
||||
export const stopFineTune = (id: string | number) => post(`/fine-tune/stop/${id}`)
|
||||
|
||||
/** 删除训练任务 */
|
||||
export const deleteFineTune = (id: string | number) => del(`/fine-tune/${id}`)
|
||||
|
||||
/** 获取训练进度 */
|
||||
export const getFineTuneProgress = (id: string | number) =>
|
||||
get<TrainingProgress>(`/fine-tune/progress/${id}`)
|
||||
|
||||
/** 启动 TensorBoard */
|
||||
export const startTensorboard = () => post('/fine-tune/tensorboard/start')
|
||||
|
||||
/** 提交 Web 日志 */
|
||||
export const sendWebLog = (level: string, message: string, page: string) =>
|
||||
post('/web-log', { level, message, page, timestamp: new Date().toISOString() })
|
||||
18
frontend/src/api/modules/log.ts
Normal file
18
frontend/src/api/modules/log.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { get } from '../request'
|
||||
import type { LogFile, LogContent, TrainingLogFile } from '@/types'
|
||||
|
||||
/** 按日期获取系统日志文件列表 */
|
||||
export const getLogFiles = (date: string) =>
|
||||
get<LogFile[]>('/log-files', { date })
|
||||
|
||||
/** 获取系统日志内容 */
|
||||
export const getLogContent = (file: string) =>
|
||||
get<LogContent>('/log-content', { file })
|
||||
|
||||
/** 训练日志文件列表 */
|
||||
export const getTrainingLogFiles = () =>
|
||||
get<TrainingLogFile[]>('/training-log-files')
|
||||
|
||||
/** 训练日志内容 */
|
||||
export const getTrainingLogContent = (file: string) =>
|
||||
get<LogContent>('/training-log-content', { file })
|
||||
48
frontend/src/api/modules/model.ts
Normal file
48
frontend/src/api/modules/model.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { get, post, put, del } from '../request'
|
||||
import type { ModelItem, ModelForm, TrainedModel } from '@/types'
|
||||
|
||||
/** 模型列表 */
|
||||
export const getModelList = () => get<ModelItem[]>('/model-manage')
|
||||
|
||||
/** 模型详情 */
|
||||
export const getModel = (id: string | number) => get<ModelItem>(`/model-manage/${id}`)
|
||||
|
||||
/** 按名称查模型 */
|
||||
export const getModelByName = (name: string) => get<ModelItem>(`/model-manage/name/${name}`)
|
||||
|
||||
/** 本地模型路径列表 */
|
||||
export const getLocalModels = () =>
|
||||
get<{ models: { path: string; name: string }[] }>('/model-manage/local-models')
|
||||
|
||||
/** 已训练模型列表 */
|
||||
export const getTrainedModels = () =>
|
||||
get<{ models: TrainedModel[] }>('/model-manage/trained-models')
|
||||
|
||||
/** 创建模型 */
|
||||
export const createModel = (data: ModelForm) => post('/model-manage', data)
|
||||
|
||||
/** 编辑模型 */
|
||||
export const updateModel = (id: string | number, data: ModelForm) =>
|
||||
put(`/model-manage/${id}`, data)
|
||||
|
||||
/** 删除模型 */
|
||||
export const deleteModel = (id: string | number) => del(`/model-manage/${id}`)
|
||||
|
||||
/** 删除已训练模型(合并权重) */
|
||||
export const deleteTrainedModel = (id: string | number, type: 'merged' | 'lora' = 'merged') =>
|
||||
del(`/model-manage/trained-models/${id}`, { type })
|
||||
|
||||
/** 更新模型用途 */
|
||||
export const updateModelPurpose = (id: string | number, purpose: string) =>
|
||||
put(`/model-manage/${id}/purpose`, { purpose })
|
||||
|
||||
/** 合并 LoRA 权重 */
|
||||
export const mergeModel = (data: {
|
||||
model_name: string
|
||||
train_method: string
|
||||
base_model_path: string
|
||||
}) => post('/model-manage/merge', data)
|
||||
|
||||
/** 导出已训练模型权重 */
|
||||
export const exportModelUrl = (modelName: string) =>
|
||||
`/modelTF/model-manage/trained-models/${encodeURIComponent(modelName)}/export`
|
||||
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}`)
|
||||
57
frontend/src/api/modules/system.ts
Normal file
57
frontend/src/api/modules/system.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { del, get, post, put } from '../request'
|
||||
import type {
|
||||
CreateUserPayload,
|
||||
HealthMetrics,
|
||||
LoginResponse,
|
||||
PermissionCode,
|
||||
SystemInfo,
|
||||
SystemUser,
|
||||
UpdateUserAccessPayload,
|
||||
} from '@/types'
|
||||
|
||||
/** 系统信息(CPU/内存/磁盘/GPU/网络/系统) */
|
||||
export const getSystemInfo = () => get<SystemInfo>('/system-info')
|
||||
|
||||
/** 健康指标(顶部栏轻量指标) */
|
||||
export const getHealth = () => get<HealthMetrics>('/health')
|
||||
|
||||
/** 登录 */
|
||||
export const login = (username: string, password: string) =>
|
||||
post<LoginResponse>('/login', { username, password })
|
||||
|
||||
/** 用户列表 */
|
||||
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)
|
||||
|
||||
/** 重置用户密码,password 留空则重置为默认密码 platform123 */
|
||||
export const resetUserPassword = (id: string, password: string) =>
|
||||
post<{ id: string }>(`/users/${encodeURIComponent(id)}/reset-password`, { password })
|
||||
|
||||
/** 角色定义 */
|
||||
export interface RoleInfo {
|
||||
id: string
|
||||
name: string
|
||||
display_name: string
|
||||
permissions: PermissionCode[]
|
||||
}
|
||||
|
||||
/** 权限码清单 */
|
||||
export const getPermissionCodes = () =>
|
||||
get<{ codes: PermissionCode[] }>('/system/permissions/codes')
|
||||
|
||||
/** 权限码清单 + 角色定义 */
|
||||
export const getPermissions = () =>
|
||||
get<{ codes: PermissionCode[]; roles: RoleInfo[] }>('/system/permissions')
|
||||
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 })
|
||||
77
frontend/src/api/request.ts
Normal file
77
frontend/src/api/request.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
/**
|
||||
* 后端统一响应格式
|
||||
* code === 0 表示成功,data 为业务数据
|
||||
*/
|
||||
export interface ApiResult<T = any> {
|
||||
code: number
|
||||
message?: string
|
||||
data: T
|
||||
}
|
||||
|
||||
const service: AxiosInstance = axios.create({
|
||||
// Use a relative path; Vite proxies /modelTF to http://localhost:17861 in local development.
|
||||
baseURL: '/modelTF',
|
||||
timeout: 30000,
|
||||
})
|
||||
|
||||
// 请求拦截器:携带认证令牌
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = localStorage.getItem('authToken')
|
||||
if (token) {
|
||||
config.headers = config.headers || {}
|
||||
;(config.headers as Record<string, string>).Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
(error) => Promise.reject(error),
|
||||
)
|
||||
|
||||
// 响应拦截器:统一解包 { code, data, message }
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const res = response.data as ApiResult
|
||||
// 二进制流等非 JSON 响应直接返回
|
||||
if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') {
|
||||
return response
|
||||
}
|
||||
if (res.code === 0) {
|
||||
return res.data
|
||||
}
|
||||
// 业务错误
|
||||
const message = res.message || '请求失败'
|
||||
ElMessage.error(message)
|
||||
return Promise.reject(new Error(message))
|
||||
},
|
||||
(error) => {
|
||||
const detail = error.response?.data?.detail
|
||||
const message = detail?.message || error.response?.data?.message || detail || error.message || '网络异常'
|
||||
ElMessage.error(message)
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
/** GET 请求,返回已解包的 data */
|
||||
export function get<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return service.get(url, { params, ...config }) as unknown as Promise<T>
|
||||
}
|
||||
|
||||
/** POST 请求 */
|
||||
export function post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return service.post(url, data, config) as unknown as Promise<T>
|
||||
}
|
||||
|
||||
/** PUT 请求 */
|
||||
export function put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return service.put(url, data, config) as unknown as Promise<T>
|
||||
}
|
||||
|
||||
/** DELETE 请求 */
|
||||
export function del<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return service.delete(url, { params, ...config }) as unknown as Promise<T>
|
||||
}
|
||||
|
||||
export default service
|
||||
Reference in New Issue
Block a user