|
|
@@ -187,7 +187,10 @@
|
|
|
</div>
|
|
|
<div class="health-info">
|
|
|
<div class="health-label">系统版本</div>
|
|
|
- <div class="health-value">{{ version }}</div>
|
|
|
+ <div class="health-value">
|
|
|
+ {{ version }}
|
|
|
+ <el-link type="primary" :underline="false" style="font-size:12px;margin-left:6px" @click="showChangelog">查看变更日志</el-link>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="health-item">
|
|
|
@@ -208,6 +211,33 @@
|
|
|
<div class="health-value">~45 个</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div class="health-item">
|
|
|
+ <div class="health-icon health-icon--uptime">
|
|
|
+ <i class="el-icon-time"></i>
|
|
|
+ </div>
|
|
|
+ <div class="health-info">
|
|
|
+ <div class="health-label">服务器运行时长</div>
|
|
|
+ <div class="health-value">{{ serverHealth.uptime }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="health-item">
|
|
|
+ <div class="health-icon health-icon--cpu">
|
|
|
+ <i class="el-icon-cpu"></i>
|
|
|
+ </div>
|
|
|
+ <div class="health-info">
|
|
|
+ <div class="health-label">CPU 使用率</div>
|
|
|
+ <div class="health-value">{{ serverHealth.cpuUsagePercent }}% ({{ serverHealth.cpuCores }}核)</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="health-item">
|
|
|
+ <div class="health-icon health-icon--memory">
|
|
|
+ <i class="el-icon-coffee"></i>
|
|
|
+ </div>
|
|
|
+ <div class="health-info">
|
|
|
+ <div class="health-label">JVM 内存</div>
|
|
|
+ <div class="health-value">{{ serverHealth.memUsed }} / {{ serverHealth.memMax }} ({{ serverHealth.memUsagePercent }}%)</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div class="health-links">
|
|
|
<el-button size="mini" icon="el-icon-s-order" @click="$router.push('/tasks')">任务管理</el-button>
|
|
|
@@ -275,16 +305,27 @@
|
|
|
<div class="action-label">系统设置</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
</el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+<!-- 变更日志弹窗 -->
|
|
|
+<el-dialog
|
|
|
+ title="变更日志"
|
|
|
+ :visible.sync="changelogVisible"
|
|
|
+ width="700px"
|
|
|
+ custom-class="changelog-dialog"
|
|
|
+ append-to-body
|
|
|
+>
|
|
|
+ <div v-loading="changelogLoading" class="changelog-body" v-html="changelogContent"></div>
|
|
|
+</el-dialog>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import * as echarts from 'echarts'
|
|
|
-import { getDashboardStats, getMembershipStats, getTrendStats, getDashboardOverview } from '@/api/admin'
|
|
|
+import { getDashboardStats, getMembershipStats, getTrendStats, getDashboardOverview, getSystemHealth } from '@/api/admin'
|
|
|
|
|
|
export default {
|
|
|
name: 'Dashboard',
|
|
|
@@ -337,6 +378,7 @@ mounted() {
|
|
|
this.loadDashboardData()
|
|
|
this.loadTrend()
|
|
|
this.loadMembership()
|
|
|
+ this.loadServerHealth()
|
|
|
this.resizeHandler = () => {
|
|
|
this.trendChart && this.trendChart.resize()
|
|
|
this.memberChart && this.memberChart.resize()
|
|
|
@@ -373,6 +415,25 @@ beforeDestroy() {
|
|
|
console.error('加载仪表盘数据失败:', error)
|
|
|
}
|
|
|
},
|
|
|
+ async loadServerHealth() {
|
|
|
+ try {
|
|
|
+ const res = await getSystemHealth()
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ const d = res.data
|
|
|
+ this.serverHealth = {
|
|
|
+ uptime: d.uptime || '--',
|
|
|
+ memUsed: d.memUsed || '--',
|
|
|
+ memMax: d.memMax || '--',
|
|
|
+ memUsagePercent: d.memUsagePercent || '--',
|
|
|
+ cpuCores: d.cpuCores || '--',
|
|
|
+ cpuLoad: d.cpuLoad || '--',
|
|
|
+ cpuUsagePercent: d.cpuUsagePercent || '--'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载服务器状态失败:', error)
|
|
|
+ }
|
|
|
+ },
|
|
|
showChangelog() {
|
|
|
this.changelogVisible = true
|
|
|
if (this.changelogContent) return
|
|
|
@@ -720,6 +781,18 @@ initMemberPieChart() {
|
|
|
background: linear-gradient(135deg, #0EA5E9, #0284C7);
|
|
|
}
|
|
|
|
|
|
+.health-icon--uptime {
|
|
|
+ background: linear-gradient(135deg, #8B5CF6, #7C3AED);
|
|
|
+}
|
|
|
+
|
|
|
+.health-icon--cpu {
|
|
|
+ background: linear-gradient(135deg, #EF4444, #F87171);
|
|
|
+}
|
|
|
+
|
|
|
+.health-icon--memory {
|
|
|
+ background: linear-gradient(135deg, #10B981, #059669);
|
|
|
+}
|
|
|
+
|
|
|
.health-info {
|
|
|
flex: 1;
|
|
|
}
|
|
|
@@ -884,3 +957,75 @@ initMemberPieChart() {
|
|
|
width: 100%;
|
|
|
}
|
|
|
</style>
|
|
|
+
|
|
|
+<style>
|
|
|
+.changelog-dialog .el-dialog__body {
|
|
|
+ max-height: 500px;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+.changelog-body {
|
|
|
+ padding: 8px 4px;
|
|
|
+ line-height: 1.8;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #374151;
|
|
|
+}
|
|
|
+.changelog-body h1 {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 700;
|
|
|
+ margin: 16px 0 8px;
|
|
|
+ color: #1E293B;
|
|
|
+}
|
|
|
+.changelog-body h2 {
|
|
|
+ font-size: 17px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin: 14px 0 6px;
|
|
|
+ color: #1E293B;
|
|
|
+ border-left: 3px solid #6366F1;
|
|
|
+ padding-left: 8px;
|
|
|
+}
|
|
|
+.changelog-body h3 {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin: 10px 0 4px;
|
|
|
+ color: #374151;
|
|
|
+}
|
|
|
+.changelog-body ul {
|
|
|
+ margin: 4px 0 8px;
|
|
|
+ padding-left: 20px;
|
|
|
+}
|
|
|
+.changelog-body li {
|
|
|
+ margin: 2px 0;
|
|
|
+}
|
|
|
+.changelog-body .cl-item {
|
|
|
+ margin: 4px 0;
|
|
|
+}
|
|
|
+.changelog-body .cl-empty {
|
|
|
+ text-align: center;
|
|
|
+ color: #94A3B8;
|
|
|
+ padding: 32px 0;
|
|
|
+}
|
|
|
+.changelog-body code {
|
|
|
+ background: #F1F5F9;
|
|
|
+ padding: 2px 6px;
|
|
|
+ border-radius: 3px;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+.changelog-body pre {
|
|
|
+ background: #F8FAFC;
|
|
|
+ border: 1px solid #E2E8F0;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 12px;
|
|
|
+ overflow-x: auto;
|
|
|
+}
|
|
|
+.changelog-body pre code {
|
|
|
+ background: none;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+.changelog-body a {
|
|
|
+ color: #6366F1;
|
|
|
+ text-decoration: none;
|
|
|
+}
|
|
|
+.changelog-body a:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+}
|
|
|
+</style>
|