diff --git a/backend/app/api/v1/endpoints/platform.py b/backend/app/api/v1/endpoints/platform.py index 5b36a2e..ba2b499 100644 --- a/backend/app/api/v1/endpoints/platform.py +++ b/backend/app/api/v1/endpoints/platform.py @@ -412,16 +412,16 @@ async def dashboard_stats() -> dict[str, Any]: # 服务状态 —— 通过对应接口连通性判断是否正常 service_checks = [ - ("模型训练", "/fine-tune", "模型训练"), - ("模型评测", "/model-eval", "模型评测"), - ("模型推理", "/model-inference", "模型推理"), - ("模型管理", "/model-manage", "模型管理"), - ("数据集管理", "/dataset-manage", "数据集管理"), - ("数据处理", "/data-process", "数据处理"), - ("数据类型转换", "/data-convert", "数据类型转换"), + ("模型训练", "/fine-tune", "模型训练"), + ("模型评测", "/model-eval", "模型评测"), + ("模型推理", "/model-inference", "模型推理"), + ("模型管理", "/model-manage", "模型管理"), + ("数据集管理", "/dataset-manage", "数据集管理"), + ("数据处理", "/data-process", "数据处理"), + ("数据类型转换", "/data-convert", "数据类型转换"), ] service_status = [] - for svc_type, path, _label in service_checks: + for svc_type, _path, _label in service_checks: try: svc_count = 0 if svc_type == "模型训练": diff --git a/frontend/src/api/modules/audit-visit.ts b/frontend/src/api/modules/audit-visit.ts deleted file mode 100644 index 5f58b3f..0000000 --- a/frontend/src/api/modules/audit-visit.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { post } from '../request' - -/** 记录用户访问某个业务模块(用于看板用户操作分布统计) */ -export const recordModuleVisit = (module: string, detail?: string) => - post('/system/audit/visit', { action: module, detail: detail || '' }) \ No newline at end of file diff --git a/frontend/src/api/modules/system.ts b/frontend/src/api/modules/system.ts index f0f355c..6b5cffb 100644 --- a/frontend/src/api/modules/system.ts +++ b/frontend/src/api/modules/system.ts @@ -8,6 +8,8 @@ import type { UpdateUserAccessPayload, } from '@/types' +export type { SystemUser } from '@/types' + /** 系统信息(CPU/内存/磁盘/GPU/网络/系统) */ export const getSystemInfo = () => get('/system-info') diff --git a/frontend/src/api/request.ts b/frontend/src/api/request.ts index bc9afa9..dcd54d6 100644 --- a/frontend/src/api/request.ts +++ b/frontend/src/api/request.ts @@ -1,37 +1,6 @@ import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios' import { ElMessage } from 'element-plus' -/** - * 用户操作分布:哪些模块路径算"业务操作"(用于看板统计) - * 请求命中这些路径时,会自动调用 record_visit 记录一次(同一模块 60 秒内去重) - */ -const VISIT_TRACKED_PREFIXES: Array<[string, string]> = [ - ['/fine-tune', 'fine-tune'], - ['/model-eval', 'model-eval'], - ['/model-inference', 'model-inference'], - ['/data-process', 'data-process'], - ['/data-convert', 'data-convert'], - ['/model-manage', 'model-manage'], - ['/dataset-manage', 'dataset'], -] - -function trackVisit(url: string | undefined) { - if (!url) return - for (const [prefix, module] of VISIT_TRACKED_PREFIXES) { - if (url.includes(prefix)) { - const key = `visit:${module}` - const last = Number(sessionStorage.getItem(key) || 0) - if (Date.now() - last < 60000) return // 60 秒内去重 - sessionStorage.setItem(key, String(Date.now())) - // fire-and-forget 调用后端记录接口 - import('./modules/audit-visit').then(({ recordModuleVisit }) => { - recordModuleVisit(module, url).catch(() => { /* ignore */ }) - }).catch(() => { /* ignore */ }) - return - } - } -} - /** * 后端统一响应格式 * code === 0 表示成功,data 为业务数据 @@ -91,8 +60,6 @@ service.interceptors.response.use( return response } if (res.code === 0) { - // 记录业务模块访问(用于看板用户操作分布统计) - trackVisit(response.config.url) return res.data } // 业务错误 diff --git a/frontend/src/views/dashboard/DashboardView.vue b/frontend/src/views/dashboard/DashboardView.vue index dfdbf3c..e23a5b7 100644 --- a/frontend/src/views/dashboard/DashboardView.vue +++ b/frontend/src/views/dashboard/DashboardView.vue @@ -66,8 +66,12 @@ const operationDistribution = ref<{ name: string; value: number }[]>([]) const serviceIcon: Record = { '模型推理': 'fa-cube', '模型微调': 'fa-sliders', + '模型训练': 'fa-sliders', '模型评测': 'fa-bar-chart', + '模型管理': 'fa-cubes', + '数据集管理': 'fa-file-text', '数据处理': 'fa-filter', + '数据类型转换': 'fa-exchange', } const roleLabel: Record = { admin: '超级管理员', @@ -115,7 +119,7 @@ const chartOption = computed(() => ({ borderWidth: 0, padding: [10, 12], textStyle: { color: '#ffffff', fontSize: 12 }, - valueFormatter: (value) => `${value}`, + valueFormatter: (value) => String(value ?? ''), }, xAxis: { type: 'category', @@ -252,7 +256,7 @@ const loginDurationChartOption = computed(() => { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, - valueFormatter: (value: number) => `${value} 小时`, + valueFormatter: (value: unknown) => String(Number(Array.isArray(value) ? value[0] : value) || 0) + ' 小时', }, xAxis: { type: 'value', @@ -738,10 +742,11 @@ function viewTask(task: DashboardTask) { .service-table { display: grid; - grid-template-rows: 36px repeat(4, minmax(48px, 1fr)); + grid-auto-rows: minmax(44px, auto); flex: 1 1 auto; margin-top: 12px; min-height: 0; + overflow-y: auto; } .service-row { @@ -935,7 +940,7 @@ function viewTask(task: DashboardTask) { } .service-table { - grid-template-rows: 32px repeat(4, minmax(40px, 1fr)); + grid-auto-rows: minmax(38px, auto); margin-top: 8px; } diff --git a/frontend/src/views/projects/ProjectListView.vue b/frontend/src/views/projects/ProjectListView.vue index ca8aaa2..b0f789a 100644 --- a/frontend/src/views/projects/ProjectListView.vue +++ b/frontend/src/views/projects/ProjectListView.vue @@ -99,23 +99,23 @@ onMounted(() => { 新建项目 - + - + diff --git a/frontend/src/views/tenants/TenantListView.vue b/frontend/src/views/tenants/TenantListView.vue index 78a7ebc..f9fdaaa 100644 --- a/frontend/src/views/tenants/TenantListView.vue +++ b/frontend/src/views/tenants/TenantListView.vue @@ -30,7 +30,7 @@ function formatQuota(quota: Record | undefined | null) { if (q.gpu > 0) parts.push(`GPU ${q.gpu}`) if (q.storage > 0) parts.push(`存储 ${q.storage}GB`) if (q.maxProjects > 0) parts.push(`项目 ${q.maxProjects}`) - return parts.length ? parts.join(' | ') : '—' + return parts.length ? parts.join(' | ') : '-' } async function load() { @@ -52,7 +52,7 @@ function asTenant(row: unknown): Tenant { function quotaText(row: unknown): string { const quota = asTenant(row).quota || {} - return Object.keys(quota).length ? JSON.stringify(quota) : '—' + return Object.keys(quota).length ? JSON.stringify(quota) : '-' } async function submitCreate() { @@ -118,13 +118,13 @@ onMounted(load)