From e4b1e10a42452e710d57b9b616f7b42ef48cc70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:26:57 +0800 Subject: [PATCH] Add files via upload --- web/static/css/style.css | 259 +++++++++++++++++++++++++++++++++++++ web/static/js/dashboard.js | 97 +++++++++++--- web/templates/index.html | 88 +++++++++++-- 3 files changed, 417 insertions(+), 27 deletions(-) diff --git a/web/static/css/style.css b/web/static/css/style.css index 2adfc4a0..d03c4c3c 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -8150,6 +8150,265 @@ header { color: var(--text-primary); } +/* 运行概览优化样式 */ +.dashboard-overview-content { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 8px; +} + +.dashboard-overview-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 2px; +} + +.dashboard-overview-total { + font-size: 0.75rem; + font-weight: 600; + color: var(--text-secondary); + background: rgba(0, 102, 255, 0.08); + padding: 2px 8px; + border-radius: 12px; +} + +.dashboard-overview-success-rate { + font-size: 0.75rem; + font-weight: 600; + color: #10b981; + background: rgba(16, 185, 129, 0.1); + padding: 2px 8px; + border-radius: 12px; +} + +.dashboard-overview-status { + font-size: 0.75rem; + font-weight: 600; + color: var(--text-secondary); + background: rgba(0, 0, 0, 0.05); + padding: 2px 8px; + border-radius: 12px; +} + +.dashboard-overview-stats { + display: flex; + gap: 16px; + flex-wrap: wrap; +} + +.dashboard-overview-stat { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.8125rem; +} + +.dashboard-overview-stat-badge { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +.dashboard-overview-stat-badge.badge-pending { + background: #f59e0b; + box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); +} + +.dashboard-overview-stat-badge.badge-running { + background: #3b82f6; + box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7); + animation: pulse-running 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +.dashboard-overview-stat-badge.badge-done { + background: #10b981; +} + +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +@keyframes pulse-running { + 0%, 100% { + opacity: 1; + box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7); + } + 50% { + opacity: 0.8; + box-shadow: 0 0 0 4px rgba(59, 130, 246, 0); + } +} + +.dashboard-overview-stat-value { + font-weight: 700; + font-size: 0.9375rem; + color: var(--text-primary); + font-variant-numeric: tabular-nums; +} + +.dashboard-overview-stat-label { + color: var(--text-secondary); + font-size: 0.8125rem; +} + +.dashboard-overview-progress { + margin-top: 4px; +} + +.dashboard-overview-progress-bar { + height: 6px; + background: #f1f5f9; + border-radius: 3px; + overflow: hidden; + display: flex; + position: relative; +} + +.dashboard-overview-progress-segment { + height: 100%; + transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; +} + +.dashboard-overview-progress-pending { + background: linear-gradient(90deg, #fbbf24, #f59e0b); +} + +.dashboard-overview-progress-running { + background: linear-gradient(90deg, #60a5fa, #3b82f6); + animation: shimmer 2s infinite; +} + +.dashboard-overview-progress-done { + background: linear-gradient(90deg, #34d399, #10b981); +} + +@keyframes shimmer { + 0% { + opacity: 1; + } + 50% { + opacity: 0.8; + } + 100% { + opacity: 1; + } +} + +.dashboard-overview-value-group { + display: flex; + align-items: baseline; + gap: 4px; + flex-wrap: wrap; +} + +.dashboard-overview-value-large { + font-size: 1.25rem; + font-weight: 800; + color: var(--text-primary); + font-variant-numeric: tabular-nums; + letter-spacing: -0.02em; + line-height: 1.2; +} + +.dashboard-overview-value-normal { + font-size: 0.9375rem; + font-weight: 600; + color: var(--text-primary); + font-variant-numeric: tabular-nums; +} + +.dashboard-overview-value-unit { + font-size: 0.8125rem; + color: var(--text-secondary); + font-weight: 500; +} + +.dashboard-overview-value-separator { + color: var(--text-secondary); + opacity: 0.4; + margin: 0 2px; +} + +/* 不同模块的图标颜色 */ +.dashboard-overview-icon-batch { + background: rgba(245, 158, 11, 0.1); + color: #d97706; +} + +.dashboard-overview-icon-tools { + background: rgba(59, 130, 246, 0.1); + color: #2563eb; +} + +.dashboard-overview-icon-knowledge { + background: rgba(139, 92, 246, 0.1); + color: #7c3aed; +} + +.dashboard-overview-icon-skills { + background: rgba(236, 72, 153, 0.1); + color: #db2777; +} + +/* 悬停效果增强 */ +.dashboard-overview-item:hover .dashboard-overview-icon { + transform: scale(1.1); + transition: transform 0.2s ease; +} + +.dashboard-overview-item:hover .dashboard-overview-value-large { + color: #0066ff; + transition: color 0.2s ease; +} + +.dashboard-overview-item-batch:hover { + border-color: rgba(245, 158, 11, 0.3); + background: linear-gradient(135deg, rgba(245,158,11,0.06) 0%, rgba(245,158,11,0.08) 100%); +} + +.dashboard-overview-item-tools:hover { + border-color: rgba(59, 130, 246, 0.3); + background: linear-gradient(135deg, rgba(59,130,246,0.06) 0%, rgba(59,130,246,0.08) 100%); +} + +.dashboard-overview-item-knowledge:hover { + border-color: rgba(139, 92, 246, 0.3); + background: linear-gradient(135deg, rgba(139,92,246,0.06) 0%, rgba(139,92,246,0.08) 100%); +} + +.dashboard-overview-item-skills:hover { + border-color: rgba(236, 72, 153, 0.3); + background: linear-gradient(135deg, rgba(236,72,153,0.06) 0%, rgba(236,72,153,0.08) 100%); +} + +/* 响应式优化 */ +@media (max-width: 768px) { + .dashboard-overview-stats { + gap: 12px; + } + + .dashboard-overview-value-group { + flex-direction: column; + align-items: flex-start; + gap: 2px; + } + + .dashboard-overview-value-separator { + display: none; + } +} + .dashboard-chart-wrap { display: flex; flex-direction: column; diff --git a/web/static/js/dashboard.js b/web/static/js/dashboard.js index f9fcc84f..8e70968c 100644 --- a/web/static/js/dashboard.js +++ b/web/static/js/dashboard.js @@ -63,7 +63,7 @@ async function refreshDashboard() { }); } - // 批量任务队列:按状态统计 + // 批量任务队列:按状态统计(优化版) if (batchRes && Array.isArray(batchRes.queues)) { const queues = batchRes.queues; let pending = 0, running = 0, done = 0; @@ -73,16 +73,36 @@ async function refreshDashboard() { else if (s === 'running') running++; else if (s === 'completed' || s === 'cancelled') done++; }); + const total = pending + running + done; setEl('dashboard-batch-pending', String(pending)); setEl('dashboard-batch-running', String(running)); setEl('dashboard-batch-done', String(done)); + setEl('dashboard-batch-total', total > 0 ? `共 ${total} 个` : '暂无任务'); + + // 更新进度条 + if (total > 0) { + const pendingPct = (pending / total * 100).toFixed(1); + const runningPct = (running / total * 100).toFixed(1); + const donePct = (done / total * 100).toFixed(1); + updateProgressBar('dashboard-batch-progress-pending', pendingPct); + updateProgressBar('dashboard-batch-progress-running', runningPct); + updateProgressBar('dashboard-batch-progress-done', donePct); + } else { + updateProgressBar('dashboard-batch-progress-pending', '0'); + updateProgressBar('dashboard-batch-progress-running', '0'); + updateProgressBar('dashboard-batch-progress-done', '0'); + } } else { setEl('dashboard-batch-pending', '-'); setEl('dashboard-batch-running', '-'); setEl('dashboard-batch-done', '-'); + setEl('dashboard-batch-total', '-'); + updateProgressBar('dashboard-batch-progress-pending', '0'); + updateProgressBar('dashboard-batch-progress-running', '0'); + updateProgressBar('dashboard-batch-progress-done', '0'); } - // 工具调用:monitor/stats 为 { toolName: { totalCalls, successCalls, failedCalls, ... } } + // 工具调用:monitor/stats 为 { toolName: { totalCalls, successCalls, failedCalls, ... } }(优化版) if (monitorRes && typeof monitorRes === 'object') { const names = Object.keys(monitorRes); let totalCalls = 0, totalSuccess = 0, totalFailed = 0; @@ -96,40 +116,68 @@ async function refreshDashboard() { if (typeof f === 'number') totalFailed += f; }); setEl('dashboard-tools-count', String(names.length)); - setEl('dashboard-tools-calls', String(totalCalls)); + setEl('dashboard-tools-calls', formatNumber(totalCalls)); setEl('dashboard-kpi-tools-calls', String(totalCalls)); var rateStr = totalCalls > 0 ? ((totalSuccess / totalCalls) * 100).toFixed(1) + '%' : '-'; setEl('dashboard-kpi-success-rate', rateStr); + setEl('dashboard-tools-success-rate', rateStr !== '-' ? `成功率 ${rateStr}` : '-'); renderDashboardToolsBar(monitorRes); } else { setEl('dashboard-tools-count', '-'); setEl('dashboard-tools-calls', '-'); setEl('dashboard-kpi-tools-calls', '-'); setEl('dashboard-kpi-success-rate', '-'); + setEl('dashboard-tools-success-rate', '-'); renderDashboardToolsBar(null); } - // 知识:{ enabled, total_categories, total_items, ... } - const knowledgeValueEl = document.getElementById('dashboard-knowledge-value'); + // 知识:{ enabled, total_categories, total_items, ... }(优化版) + const knowledgeItemsEl = document.getElementById('dashboard-knowledge-items'); + const knowledgeCategoriesEl = document.getElementById('dashboard-knowledge-categories'); if (knowledgeRes && typeof knowledgeRes === 'object') { if (knowledgeRes.enabled === false) { - if (knowledgeValueEl) knowledgeValueEl.textContent = '知识功能暂未启用'; + if (knowledgeItemsEl) knowledgeItemsEl.textContent = '未启用'; + if (knowledgeCategoriesEl) knowledgeCategoriesEl.textContent = '-'; } else { const categories = knowledgeRes.total_categories ?? 0; const items = knowledgeRes.total_items ?? 0; - if (knowledgeValueEl) knowledgeValueEl.textContent = `${categories} 个分类,共 ${items} 项`; + if (knowledgeItemsEl) knowledgeItemsEl.textContent = formatNumber(items); + if (knowledgeCategoriesEl) knowledgeCategoriesEl.textContent = formatNumber(categories); } } else { - if (knowledgeValueEl) knowledgeValueEl.textContent = '-'; + if (knowledgeItemsEl) knowledgeItemsEl.textContent = '-'; + if (knowledgeCategoriesEl) knowledgeCategoriesEl.textContent = '-'; } - // Skills:{ total_skills, total_calls, ... } + // Skills:{ total_skills, total_calls, ... }(优化版) if (skillsRes && typeof skillsRes === 'object') { - setEl('dashboard-skills-count', String(skillsRes.total_skills ?? '-')); - setEl('dashboard-skills-calls', String(skillsRes.total_calls ?? '-')); + const totalSkills = skillsRes.total_skills ?? 0; + const totalCalls = skillsRes.total_calls ?? 0; + setEl('dashboard-skills-count', formatNumber(totalSkills)); + setEl('dashboard-skills-calls', formatNumber(totalCalls)); + + // 设置状态标签 + const statusEl = document.getElementById('dashboard-skills-status'); + if (statusEl) { + if (totalCalls === 0) { + statusEl.textContent = '待使用'; + statusEl.style.background = 'rgba(0, 0, 0, 0.05)'; + statusEl.style.color = 'var(--text-secondary)'; + } else if (totalCalls < 10) { + statusEl.textContent = '活跃'; + statusEl.style.background = 'rgba(16, 185, 129, 0.1)'; + statusEl.style.color = '#10b981'; + } else { + statusEl.textContent = '高频'; + statusEl.style.background = 'rgba(59, 130, 246, 0.1)'; + statusEl.style.color = '#3b82f6'; + } + } } else { setEl('dashboard-skills-count', '-'); setEl('dashboard-skills-calls', '-'); + const statusEl = document.getElementById('dashboard-skills-status'); + if (statusEl) statusEl.textContent = '-'; } } catch (e) { console.warn('仪表盘拉取统计失败', e); @@ -150,10 +198,29 @@ function setEl(id, text) { } function setDashboardOverviewPlaceholder(t) { - ['dashboard-batch-pending', 'dashboard-batch-running', 'dashboard-batch-done', - 'dashboard-tools-count', 'dashboard-tools-calls', 'dashboard-skills-count', 'dashboard-skills-calls'].forEach(id => setEl(id, t)); - const knowledgeValueEl = document.getElementById('dashboard-knowledge-value'); - if (knowledgeValueEl) knowledgeValueEl.textContent = t; + ['dashboard-batch-pending', 'dashboard-batch-running', 'dashboard-batch-done', 'dashboard-batch-total', + 'dashboard-tools-count', 'dashboard-tools-calls', 'dashboard-tools-success-rate', + 'dashboard-skills-count', 'dashboard-skills-calls', 'dashboard-skills-status', + 'dashboard-knowledge-items', 'dashboard-knowledge-categories'].forEach(id => setEl(id, t)); + updateProgressBar('dashboard-batch-progress-pending', '0'); + updateProgressBar('dashboard-batch-progress-running', '0'); + updateProgressBar('dashboard-batch-progress-done', '0'); +} + +// 格式化数字,添加千位分隔符 +function formatNumber(num) { + if (typeof num !== 'number' || isNaN(num)) return '-'; + if (num === 0) return '0'; + return num.toLocaleString('zh-CN'); +} + +// 更新进度条宽度 +function updateProgressBar(id, percentage) { + const el = document.getElementById(id); + if (el) { + const pct = parseFloat(percentage) || 0; + el.style.width = Math.max(0, Math.min(100, pct)) + '%'; + } } // Top 30 工具执行次数柱状图颜色(30 色不重复,柔和、易区分) diff --git a/web/templates/index.html b/web/templates/index.html index 5eb8249b..68d8a27a 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -245,21 +245,85 @@

运行概览

-
- -
批量任务队列- 待执行 / - 执行中 / - 已完成
+
+ +
+
+ 批量任务队列 + - +
+
+ + + - + 待执行 + + + + - + 执行中 + + + + - + 已完成 + +
+
+
+
+
+
+
+
+
-
- -
工具调用- 个工具,共 -
+
+ +
+
+ 工具调用 + - +
+
+ - + 次调用 + · + - + 个工具 +
+
-
- -
知识-
+
+ +
+
+ 知识 +
+
+ - + 项知识 + · + - + 个分类 +
+
-
- -
Skills- 个 Skill,共 - 次调用
+
+ +
+
+ Skills + - +
+
+ - + 次调用 + · + - + 个 Skill +
+