Files
YMhut-box-C-/server/unified-management/web/admin/src/views/DashboardView.vue
T
QWQLwToo 1d0e862299 更新后端服务UI
客户端重构部分界面UI
2026-06-30 11:45:52 +08:00

132 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import VChart from "vue-echarts";
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { BarChart, GaugeChart, LineChart, PieChart } from "echarts/charts";
import { GridComponent, LegendComponent, TooltipComponent } from "echarts/components";
import { Activity, PauseCircle, PlayCircle } from "lucide-vue-next";
defineProps<{ ctx: any }>();
use([CanvasRenderer, LineChart, PieChart, BarChart, GaugeChart, GridComponent, TooltipComponent, LegendComponent]);
</script>
<template>
<section class="page-stack">
<div class="metric-grid">
<article class="metric"><span>反馈总数</span><strong>{{ ctx.kpis.feedbackTotal || 0 }}</strong><small>今日新增 {{ ctx.kpis.feedbackToday || 0 }}</small></article>
<article class="metric"><span>可见接口</span><strong>{{ ctx.kpis.sourceVisible || 0 }}</strong><small>接口总数 {{ ctx.kpis.sourceTotal || 0 }}</small></article>
<article class="metric"><span>版本日志</span><strong>{{ ctx.kpis.releaseNotices || 0 }}</strong><small>{{ ctx.latestNotice && ctx.latestNotice.version ? ctx.latestNotice.version : "暂无最新版本" }}</small></article>
<article class="metric"><span>邮件失败</span><strong>{{ ctx.kpis.mailFailed || 0 }}</strong><small>旧反馈兼容记录</small></article>
</div>
<div class="toolbar">
<button class="btn primary" @click="ctx.checkSources"><Activity :size="16" />立即服务端检测</button>
<button class="btn ghost" @click="ctx.toggleAutoRefresh">
<component :is="ctx.autoRefreshPaused ? PlayCircle : PauseCircle" :size="16" />
{{ ctx.autoRefreshPaused ? "恢复自动刷新" : "暂停自动刷新" }}
</button>
<span class="muted"> 15 秒自动刷新</span>
<span v-if="ctx.lastRefreshedAt" class="muted">上次刷新{{ ctx.lastRefreshedAt }}</span>
</div>
<section v-if="ctx.sourceCheckJobs.length" class="panel">
<div class="section-head"><h2>服务端检测任务</h2><span class="badge">{{ ctx.sourceCheckJobs[0].status }}</span></div>
<table>
<thead><tr><th>任务</th><th>进度</th><th>正常</th><th>重定向</th><th>降级</th><th>错误</th><th>开始时间</th></tr></thead>
<tbody>
<tr v-for="job in ctx.sourceCheckJobs.slice(0, 5)" :key="job.id">
<td class="mono">{{ job.id }}</td>
<td>{{ job.checked || 0 }} / {{ job.total || 0 }}</td>
<td>{{ (job.stats && job.stats.ok) || 0 }}</td>
<td>{{ (job.stats && job.stats.redirected) || 0 }}</td>
<td>{{ (job.stats && job.stats.degraded) || 0 }}</td>
<td>{{ (job.stats && job.stats.error) || 0 }}</td>
<td>{{ job.startedAt || "-" }}</td>
</tr>
</tbody>
</table>
</section>
<div class="chart-grid">
<section class="panel chart-panel chart-panel-relative">
<h2>服务端接口延迟</h2>
<VChart class="chart" :option="ctx.heartbeatOption" autoresize />
<div v-if="ctx.isHeartbeatChartEmpty" class="chart-empty">
<strong>暂无服务端检测记录</strong>
<span>点击立即服务端检测后会生成延迟曲线</span>
</div>
</section>
<section class="panel chart-panel"><h2>接口健康分布</h2><VChart class="chart" :option="ctx.healthOption" autoresize /></section>
<section class="panel chart-panel"><h2>反馈状态分布</h2><VChart class="chart" :option="ctx.feedbackOption" autoresize /></section>
<section class="panel chart-panel"><h2>服务可用率</h2><VChart class="chart" :option="ctx.availabilityOption" autoresize /></section>
</div>
<section class="panel">
<div class="section-head"><h2>最近服务端检测</h2><span class="badge">{{ ctx.heartbeats.length }} </span></div>
<table>
<thead><tr><th>接口</th><th>状态</th><th>延迟</th><th>输出</th><th>时间</th></tr></thead>
<tbody>
<tr v-for="item in ctx.heartbeats.slice(0, 10)" :key="item.id">
<td>{{ item.name || item.sourceId }}</td>
<td><span :class='["badge", ctx.statusTone(item.status)]'>{{ ctx.labelStatus(item.status) }}</span></td>
<td>{{ item.latencyMs || 0 }}ms</td>
<td class="hash">{{ ctx.formatHealthOutput(item) }}</td>
<td>{{ item.checkedAt || "-" }}</td>
</tr>
<tr v-if="ctx.heartbeats.length === 0"><td colspan="5">暂无检测记录点击立即服务端检测后会刷新</td></tr>
</tbody>
</table>
</section>
<section class="panel">
<div class="section-head"><h2>客户端调用上报</h2><span class="badge">{{ ctx.clientCalls.length }} </span></div>
<table>
<thead><tr><th>接口</th><th>状态</th><th>延迟</th><th>客户端</th><th>时间</th></tr></thead>
<tbody>
<tr v-for="item in ctx.clientCalls.slice(0, 8)" :key="item.id">
<td>{{ item.sourceId }}</td>
<td><span :class='["badge", ctx.statusTone(item.status)]'>{{ ctx.labelStatus(item.status) }}</span></td>
<td>{{ item.latencyMs || 0 }}ms</td>
<td class="hash">{{ item.client || "-" }}</td>
<td>{{ item.createdAt || "-" }}</td>
</tr>
<tr v-if="ctx.clientCalls.length === 0"><td colspan="5">暂无客户端调用上报</td></tr>
</tbody>
</table>
</section>
<section class="panel">
<div class="section-head">
<h2>系统日志</h2>
<div style="display:flex;gap:8px;align-items:center">
<select v-model="ctx.systemLogPage.category" style="width:100px" @change="ctx.loadSystemLogs">
<option value="">全部分类</option>
<option value="feedback">反馈</option>
<option value="release">发布</option>
<option value="auth">认证</option>
<option value="legacy">兼容</option>
<option value="source">接口</option>
<option value="database">数据库</option>
<option value="risk">风险</option>
</select>
<button class="btn ghost" style="padding:3px 10px;font-size:12px" @click="ctx.loadSystemLogs">刷新</button>
</div>
</div>
<table>
<thead><tr><th>分类</th><th>类型</th><th>状态</th><th>消息</th><th>时间</th></tr></thead>
<tbody>
<tr v-for="item in (ctx.systemLogPage.items || []).slice(0, 20)" :key="item.id">
<td><span class="badge neutral">{{ item.category || "-" }}</span></td>
<td class="mono">{{ item.type || "-" }}</td>
<td><span :class='["badge", ctx.statusTone(item.status)]'>{{ ctx.labelStatus(item.status) }}</span></td>
<td>{{ item.message || "-" }}</td>
<td>{{ item.createdAt || "-" }}</td>
</tr>
<tr v-if="!(ctx.systemLogPage.items || []).length"><td colspan="5">暂无系统日志</td></tr>
</tbody>
</table>
</section>
</section>
</template>