feat: 更新前端UI,增强审计和日志视图功能
This commit is contained in:
@@ -1,15 +1,20 @@
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import LogTrendChart from '../../components/charts/LogTrendChart.vue'
|
||||
import DonutChart from '../../components/charts/DonutChart.vue'
|
||||
import { fetchAgentRuns } from '../../services/agentAssets.js'
|
||||
import { fetchSystemLogEntries } from '../../services/systemLogs.js'
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import { isManagerUser } from '../../utils/accessControl.js'
|
||||
|
||||
const POLL_INTERVAL_MS = 5000
|
||||
import LogTrendChart from '../../components/charts/LogTrendChart.vue'
|
||||
import DonutChart from '../../components/charts/DonutChart.vue'
|
||||
import { fetchAgentRuns } from '../../services/agentAssets.js'
|
||||
import { fetchSystemLogEntries } from '../../services/systemLogs.js'
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import {
|
||||
AGENT_RUN_POLL_INTERVAL_MS,
|
||||
formatAgentRunElapsed,
|
||||
formatAgentRunProgress,
|
||||
resolveAgentRunHeartbeat,
|
||||
resolveAgentRunStatus
|
||||
} from '../../utils/agentRunMonitor.js'
|
||||
import { isManagerUser } from '../../utils/accessControl.js'
|
||||
|
||||
const SOURCE_LABELS = {
|
||||
schedule: '定时任务',
|
||||
@@ -30,37 +35,13 @@ function formatDateTime(value) {
|
||||
return date.toLocaleString('zh-CN', { hour12: false })
|
||||
}
|
||||
|
||||
function resolveStatusLabel(status) {
|
||||
if (status === 'running') {
|
||||
return '运行中'
|
||||
}
|
||||
if (status === 'succeeded') {
|
||||
return '已完成'
|
||||
}
|
||||
if (status === 'failed') {
|
||||
return '失败'
|
||||
}
|
||||
if (status === 'blocked') {
|
||||
return '待确认'
|
||||
}
|
||||
return status || '未知'
|
||||
}
|
||||
|
||||
function resolveStatusTone(status) {
|
||||
if (status === 'running') {
|
||||
return 'warning'
|
||||
}
|
||||
if (status === 'succeeded') {
|
||||
return 'success'
|
||||
}
|
||||
if (status === 'failed') {
|
||||
return 'danger'
|
||||
}
|
||||
if (status === 'blocked') {
|
||||
return 'muted'
|
||||
}
|
||||
return 'muted'
|
||||
}
|
||||
function resolveStatusLabel(run) {
|
||||
return resolveAgentRunStatus(run).label
|
||||
}
|
||||
|
||||
function resolveStatusTone(run) {
|
||||
return resolveAgentRunStatus(run).tone
|
||||
}
|
||||
|
||||
function resolveRunSourceLabel(source) {
|
||||
return SOURCE_LABELS[source] || source || '未标记'
|
||||
@@ -88,16 +69,20 @@ function resolveRunTitle(run) {
|
||||
return `Hermes 调用 · ${resolveRunModuleLabel(run)}`
|
||||
}
|
||||
|
||||
function resolveRunLevel(run) {
|
||||
const progress = run?.route_json?.progress || {}
|
||||
if (run?.status === 'failed' || run?.error_message) {
|
||||
return 'ERROR'
|
||||
}
|
||||
if (run?.status === 'blocked' || Number(progress.failed_documents || 0) > 0) {
|
||||
return 'WARN'
|
||||
}
|
||||
if (run?.status === 'running') {
|
||||
return 'INFO'
|
||||
function resolveRunLevel(run) {
|
||||
const progress = run?.route_json?.progress || {}
|
||||
const statusInfo = resolveAgentRunStatus(run)
|
||||
if (run?.status === 'failed' || run?.error_message) {
|
||||
return 'ERROR'
|
||||
}
|
||||
if (statusInfo.isSuspicious) {
|
||||
return 'WARN'
|
||||
}
|
||||
if (run?.status === 'blocked' || Number(progress.failed_documents || 0) > 0) {
|
||||
return 'WARN'
|
||||
}
|
||||
if (run?.status === 'running') {
|
||||
return 'INFO'
|
||||
}
|
||||
return 'INFO'
|
||||
}
|
||||
@@ -115,7 +100,7 @@ function resolveLevelTone(level) {
|
||||
return 'muted'
|
||||
}
|
||||
|
||||
function formatSummary(summary) {
|
||||
function formatSummary(summary) {
|
||||
const text = String(summary || '').trim()
|
||||
if (!text) {
|
||||
return '暂无摘要。'
|
||||
@@ -123,8 +108,39 @@ function formatSummary(summary) {
|
||||
if (text.length <= 64) {
|
||||
return text
|
||||
}
|
||||
return `${text.slice(0, 64)}...`
|
||||
}
|
||||
return `${text.slice(0, 64)}...`
|
||||
}
|
||||
|
||||
function resolveRunSummaryMeta(run) {
|
||||
const statusInfo = resolveAgentRunStatus(run)
|
||||
const progressText = formatAgentRunProgress(run)
|
||||
const elapsedLabel = run?.status === 'running' ? '已运行' : '耗时'
|
||||
const elapsedText = formatAgentRunElapsed(run)
|
||||
const parts = [`阶段 ${statusInfo.phaseLabel}`]
|
||||
|
||||
if (progressText) {
|
||||
parts.push(progressText)
|
||||
}
|
||||
if (elapsedText !== '—') {
|
||||
parts.push(`${elapsedLabel} ${elapsedText}`)
|
||||
}
|
||||
|
||||
return parts.join(' · ')
|
||||
}
|
||||
|
||||
function resolveRunStatusNote(run) {
|
||||
const statusInfo = resolveAgentRunStatus(run)
|
||||
if (statusInfo.note) {
|
||||
return statusInfo.note
|
||||
}
|
||||
|
||||
const heartbeat = resolveAgentRunHeartbeat(run)
|
||||
if (heartbeat.at !== null) {
|
||||
return `最后心跳 ${formatDateTime(heartbeat.at)}`
|
||||
}
|
||||
|
||||
return '暂无额外状态'
|
||||
}
|
||||
|
||||
function resolveSystemLevelTone(level) {
|
||||
if (level === 'ERROR' || level === 'CRITICAL') {
|
||||
@@ -368,9 +384,9 @@ export default {
|
||||
stopPolling()
|
||||
pollTimer = window.setInterval(() => {
|
||||
loadHermesRuns()
|
||||
loadSystemLogs()
|
||||
}, POLL_INTERVAL_MS)
|
||||
}
|
||||
loadSystemLogs()
|
||||
}, AGENT_RUN_POLL_INTERVAL_MS)
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollTimer) {
|
||||
@@ -442,11 +458,13 @@ export default {
|
||||
pageSizes,
|
||||
resolveLevelTone,
|
||||
resolveRunLevel,
|
||||
resolveRunModuleLabel,
|
||||
resolveRunSourceLabel,
|
||||
resolveRunTitle,
|
||||
resolveStatusLabel,
|
||||
resolveStatusTone,
|
||||
resolveRunModuleLabel,
|
||||
resolveRunSourceLabel,
|
||||
resolveRunStatusNote,
|
||||
resolveRunSummaryMeta,
|
||||
resolveRunTitle,
|
||||
resolveStatusLabel,
|
||||
resolveStatusTone,
|
||||
resolveSystemLevelTone,
|
||||
resolveSystemOutcomeTone,
|
||||
runningRunCount,
|
||||
|
||||
Reference in New Issue
Block a user