feat: 更新后端平台模块、前端组件及构建产物,新增工作计划文档

- 更新 backend 平台 API endpoints 及 platform_store
- 更新前端 ComputeNodesView、DataProcessCreateView、FineTuneCreateView 等组件
- 更新前端 API 模块(compute、fineTune)
- 重构 frontend/dist 构建产物(新 hash)
- 新增 docs/2026-07-24-work-plan.md 工作计划文档

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
wuyongtao
2026-07-24 10:27:52 +08:00
parent b28cfbc6fa
commit 2b10c013ce
151 changed files with 925 additions and 181 deletions

View File

@@ -8,7 +8,7 @@ import TrainingTaskOverview from './training-log/TrainingTaskOverview.vue'
import { usePolling } from '@/composables/usePolling'
import '@/plugins/echarts-training-log'
import { useModelsStore } from '@/stores/models'
import { getFineTune, getFineTuneLogs } from '@/api/modules/fineTune'
import { getFineTune, getFineTuneDiagnostics, getFineTuneLogs, type TrainingDiagnostic } from '@/api/modules/fineTune'
import { getTrainingLogFiles, getTrainingLogContent } from '@/api/modules/log'
import { getDataset } from '@/api/modules/dataset'
import { getSystemInfo } from '@/api/modules/system'
@@ -35,6 +35,7 @@ const logContent = ref('')
const gpuPool = ref<GpuInfo[]>([])
const gpuUpdatedAt = ref<Date | null>(null)
const gpuLoadError = ref('')
const diagnostics = ref<TrainingDiagnostic[]>([])
/** 初始加载状态:首次数据返回前显示 loading避免空白闪烁 */
const loading = ref(true)
@@ -247,6 +248,19 @@ async function loadLog(currentTask: FineTuneTask) {
}
}
async function loadDiagnostics(currentTask: FineTuneTask) {
if (currentTask.status !== 'failed') {
diagnostics.value = []
return
}
try {
const result = await getFineTuneDiagnostics(currentTask.id)
diagnostics.value = result.diagnostics || []
} catch {
diagnostics.value = []
}
}
async function refreshAll() {
if (refreshInFlight) return
refreshInFlight = true
@@ -262,7 +276,7 @@ async function refreshAll() {
const datasetPromise = currentTask.train_dataset_id
? loadDataset(currentTask.train_dataset_id)
: Promise.resolve()
await Promise.all([datasetPromise, loadLog(currentTask), loadGpuStatus()])
await Promise.all([datasetPromise, loadLog(currentTask), loadGpuStatus(), loadDiagnostics(currentTask)])
} finally {
loading.value = false
refreshInFlight = false
@@ -535,6 +549,15 @@ onMounted(async () => {
</div>
</PageCard>
<PageCard v-if="diagnostics.length" class="diagnostics-card" title="失败诊断" subtitle="根据训练日志和失败原因生成的排查建议">
<div class="diagnostics-list">
<article v-for="item in diagnostics" :key="item.title" class="diagnostics-item">
<strong>{{ item.title }}</strong>
<p>{{ item.suggestion }}</p>
</article>
</div>
</PageCard>
<!-- 原始日志 -->
<PageCard class="log-card" title="训练日志" subtitle="查看训练任务的原始运行输出">
<template #extra><span class="log-meta">{{ logLineCount }} · 5 秒刷新</span></template>
@@ -634,6 +657,7 @@ onMounted(async () => {
.summary-card,
.parameters-card,
.metrics-panel,
.diagnostics-card,
.log-card {
margin-bottom: 0;
border: 1px solid #e4e7ed !important;
@@ -641,6 +665,28 @@ onMounted(async () => {
box-shadow: none !important;
}
.diagnostics-list {
display: grid;
gap: 10px;
}
.diagnostics-item {
border: 1px solid #fecaca;
border-radius: 8px;
padding: 12px 14px;
background: #fef2f2;
strong {
color: #991b1b;
}
p {
margin: 6px 0 0;
color: #374151;
line-height: 1.7;
}
}
.overview-card-header {
display: flex;
align-items: flex-start;