增强首页MySQL与Redis运行摘要卡片
- 为系统健康摘要接口补充 MySQL 连接负载、QPS、库体积、表数量等指标 - 为系统健康摘要接口补充 Redis key 数量、客户端数、OPS、命中率和运行时间等指标 - 调整首页基础设施卡片为服务摘要面板,分别展示 MySQL 与 Redis 的状态和关键运行信息
This commit is contained in:
@@ -148,6 +148,29 @@
|
||||
</div>
|
||||
<div class="health-item__value">{% raw %}{{ card.value }}{% endraw %}</div>
|
||||
<div class="health-item__summary">{% raw %}{{ card.summary }}{% endraw %}</div>
|
||||
<div v-if="card.serviceBlocks && card.serviceBlocks.length" class="health-service-grid">
|
||||
<div
|
||||
v-for="service in card.serviceBlocks"
|
||||
:key="service.key"
|
||||
class="health-service-panel"
|
||||
:class="`health-service-panel--${service.status}`">
|
||||
<div class="health-service-panel__head">
|
||||
<div>
|
||||
<div class="health-service-panel__title">{% raw %}{{ service.title }}{% endraw %}</div>
|
||||
<div class="health-service-panel__summary">{% raw %}{{ service.summary }}{% endraw %}</div>
|
||||
</div>
|
||||
<span class="health-service-panel__badge" :class="`health-service-panel__badge--${service.status}`">
|
||||
{% raw %}{{ getHealthStatusText(service.status) }}{% endraw %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="health-service-metrics">
|
||||
<div v-for="metric in service.metrics" :key="metric.label" class="health-service-metric">
|
||||
<span class="health-service-metric__label">{% raw %}{{ metric.label }}{% endraw %}</span>
|
||||
<span class="health-service-metric__value">{% raw %}{{ metric.value }}{% endraw %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="card.extra" class="health-item__extra">{% raw %}{{ card.extra }}{% endraw %}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -453,9 +476,10 @@
|
||||
key: 'infrastructure',
|
||||
title: '基础设施',
|
||||
status: infrastructure.status || 'warning',
|
||||
value: infrastructure.status === 'healthy' ? '正常' : '异常',
|
||||
value: `${this.countHealthyInfrastructureServices(infrastructure)} / 2`,
|
||||
summary: infrastructure.summary || '暂无状态',
|
||||
extra: `MySQL:${((infrastructure.mysql || {}).status === 'healthy') ? '正常' : '异常'} / Redis:${((infrastructure.redis || {}).status === 'healthy') ? '正常' : '异常'}`
|
||||
serviceBlocks: this.buildInfrastructureServiceBlocks(infrastructure),
|
||||
extra: '首页展示的是服务摘要;如果后续要做更深入的运维排查,再单独拆详细页会更合适。'
|
||||
},
|
||||
{
|
||||
key: 'ai_runtime',
|
||||
@@ -539,6 +563,100 @@
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
},
|
||||
formatCompactDuration(seconds) {
|
||||
const totalSeconds = parseInt(seconds) || 0;
|
||||
if (totalSeconds <= 0) return '-';
|
||||
const days = Math.floor(totalSeconds / 86400);
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
if (days > 0) return `${days}D ${hours}H`;
|
||||
if (hours > 0) return `${hours}H ${minutes}M`;
|
||||
return `${minutes}M`;
|
||||
},
|
||||
formatMetricNumber(value, fractionDigits = 0) {
|
||||
if (value === null || value === undefined || value === '') return '-';
|
||||
const numeric = Number(value);
|
||||
if (Number.isNaN(numeric)) return String(value);
|
||||
return numeric.toFixed(fractionDigits);
|
||||
},
|
||||
countHealthyInfrastructureServices(infrastructure) {
|
||||
const mysql = infrastructure.mysql || {};
|
||||
const redis = infrastructure.redis || {};
|
||||
let count = 0;
|
||||
if (mysql.status === 'healthy') count += 1;
|
||||
if (redis.status === 'healthy') count += 1;
|
||||
return count;
|
||||
},
|
||||
buildInfrastructureServiceBlocks(infrastructure) {
|
||||
const mysql = infrastructure.mysql || {};
|
||||
const redis = infrastructure.redis || {};
|
||||
return [
|
||||
{
|
||||
key: 'mysql',
|
||||
title: 'MySQL',
|
||||
status: mysql.status || 'warning',
|
||||
summary: mysql.summary || '暂无状态',
|
||||
metrics: [
|
||||
{
|
||||
label: '连接负载',
|
||||
value: `${this.formatMetricNumber(mysql.connection_usage_percent, 1)}%`
|
||||
},
|
||||
{
|
||||
label: '连接数',
|
||||
value: `${this.formatMetricNumber(mysql.threads_connected)} / ${mysql.max_connections || '-'}`
|
||||
},
|
||||
{
|
||||
label: '运行线程',
|
||||
value: this.formatMetricNumber(mysql.threads_running)
|
||||
},
|
||||
{
|
||||
label: 'QPS',
|
||||
value: this.formatMetricNumber(mysql.questions_per_second, 2)
|
||||
},
|
||||
{
|
||||
label: '库体积',
|
||||
value: `${this.formatMetricNumber(mysql.schema_size_mb, 2)} MB`
|
||||
},
|
||||
{
|
||||
label: '表数量',
|
||||
value: this.formatMetricNumber(mysql.table_count)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'redis',
|
||||
title: 'Redis',
|
||||
status: redis.status || 'warning',
|
||||
summary: redis.summary || '暂无状态',
|
||||
metrics: [
|
||||
{
|
||||
label: 'Key 数量',
|
||||
value: this.formatMetricNumber(redis.key_count)
|
||||
},
|
||||
{
|
||||
label: '客户端',
|
||||
value: this.formatMetricNumber(redis.connected_clients)
|
||||
},
|
||||
{
|
||||
label: 'OPS/s',
|
||||
value: this.formatMetricNumber(redis.ops_per_sec)
|
||||
},
|
||||
{
|
||||
label: '内存占用',
|
||||
value: redis.used_memory_human || '-'
|
||||
},
|
||||
{
|
||||
label: '命中率',
|
||||
value: `${this.formatMetricNumber(redis.hit_rate_percent, 1)}%`
|
||||
},
|
||||
{
|
||||
label: '运行时间',
|
||||
value: this.formatCompactDuration(redis.uptime_seconds)
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
},
|
||||
renderPieChart(chartId, usageValue, label) {
|
||||
const ctx = document.getElementById(chartId);
|
||||
if (!ctx) return;
|
||||
@@ -1095,6 +1213,104 @@
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.health-service-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.health-service-panel {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.14);
|
||||
background: rgba(248, 250, 252, 0.72);
|
||||
}
|
||||
|
||||
.health-service-panel--healthy {
|
||||
box-shadow: inset 0 0 0 1px rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
|
||||
.health-service-panel--warning {
|
||||
box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.10);
|
||||
}
|
||||
|
||||
.health-service-panel--danger {
|
||||
box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.10);
|
||||
}
|
||||
|
||||
.health-service-panel__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.health-service-panel__title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.health-service-panel__summary {
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.health-service-panel__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 44px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.health-service-panel__badge--healthy {
|
||||
color: #047857;
|
||||
background: rgba(16, 185, 129, 0.12);
|
||||
}
|
||||
|
||||
.health-service-panel__badge--warning {
|
||||
color: #b45309;
|
||||
background: rgba(245, 158, 11, 0.14);
|
||||
}
|
||||
|
||||
.health-service-panel__badge--danger {
|
||||
color: #b91c1c;
|
||||
background: rgba(239, 68, 68, 0.14);
|
||||
}
|
||||
|
||||
.health-service-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px 12px;
|
||||
}
|
||||
|
||||
.health-service-metric {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.health-service-metric__label {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.health-service-metric__value {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.health-item__extra {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
@@ -1450,6 +1666,10 @@
|
||||
.health-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.health-service-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -1559,6 +1779,10 @@
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.health-service-metrics {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.chart-container--large,
|
||||
.chart-container--panel {
|
||||
height: 220px;
|
||||
|
||||
Reference in New Issue
Block a user