优化首页指标展示并修复群唯一用户统计

变更项:

1. 修复首页卡片等高问题,统一用户信息与右侧指标区高度,统一热门用户/群组/插件卡片高度。

2. 首页新增三个分析指标:新增用户数、群渗透率、群健康分,并完成前端数据绑定。

3. 优化仪表盘摘要接口,新增 new_users、avg_group_penetration、group_health_score 返回字段。

4. 修复 t_group_stats.unique_users 统计口径,改为按 group_id+plugin_name+command+user_id 去重统计,避免跨群串数据。

5. 新增 t_group_command_user_stats 表结构及索引,并补充到 init.sql。
This commit is contained in:
liuwei
2026-04-15 17:19:38 +08:00
parent b37396db50
commit d472b1523b
3 changed files with 169 additions and 12 deletions

View File

@@ -92,9 +92,23 @@
</el-col>
<el-col :span="8">
<el-card class="metric-card metric-card--soft" shadow="hover">
<div class="metric-label">系统运行时间</div>
<div class="metric-value">{% raw %}{{ formattedUptime }}{% endraw %}</div>
<div class="metric-footnote">当前实例持续在线时长</div>
<div class="metric-label">新增用户数</div>
<div class="metric-value">{% raw %}{{ newUsers }}{% endraw %}</div>
<div class="metric-footnote">统计周期内首次触发用户</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="metric-card" shadow="hover">
<div class="metric-label">群渗透率</div>
<div class="metric-value">{% raw %}{{ avgGroupPenetration.toFixed(2) }}{% endraw %}%</div>
<div class="metric-footnote">活跃群触发人数占成员比例(均值)</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="metric-card metric-card--soft" shadow="hover">
<div class="metric-label">群健康分</div>
<div class="metric-value">{% raw %}{{ groupHealthScore.toFixed(2) }}{% endraw %}</div>
<div class="metric-footnote">综合成功率与响应时延评分</div>
</el-card>
</el-col>
</el-row>
@@ -256,7 +270,10 @@
successRate: 0,
activeUsers: 0,
activeGroups: 0,
newUsers: 0,
avgResponseTime: 0,
avgGroupPenetration: 0,
groupHealthScore: 0,
topUsers: [],
topGroups: [],
topPlugins: [],
@@ -425,7 +442,10 @@
this.successRate = parseFloat(data.success_rate) || 0;
this.activeUsers = data.active_users || 0;
this.activeGroups = data.active_groups || 0;
this.newUsers = data.new_users || 0;
this.avgResponseTime = parseFloat(data.avg_response_time) || 0;
this.avgGroupPenetration = parseFloat(data.avg_group_penetration) || 0;
this.groupHealthScore = parseFloat(data.group_health_score) || 0;
this.topUsers = data.top_users || [];
this.topGroups = data.top_groups || [];
this.topPlugins = data.top_plugins || [];
@@ -791,8 +811,21 @@
margin-bottom: 16px;
}
.hero-row,
.stats-highlight-row {
display: flex;
flex-wrap: wrap;
align-items: stretch;
}
.hero-row > .el-col,
.stats-highlight-row > .el-col {
display: flex;
}
.hero-card {
min-height: 228px;
height: 100%;
}
.hero-card--profile {
@@ -894,10 +927,13 @@
.metric-grid .el-col {
margin-bottom: 16px;
display: flex;
}
.metric-card {
min-height: 106px;
width: 100%;
height: 100%;
}
.metric-card .el-card__body {
@@ -942,6 +978,11 @@
padding-top: 12px !important;
}
.insight-card {
width: 100%;
height: 100%;
}
.section-heading,
.chart-card-header {
display: flex;