diff --git a/admin/dashboard/blueprints/messages.py b/admin/dashboard/blueprints/messages.py
index 601ed85..94d5651 100644
--- a/admin/dashboard/blueprints/messages.py
+++ b/admin/dashboard/blueprints/messages.py
@@ -92,3 +92,39 @@ def get_groups():
except Exception as e:
logger.error(f"获取群组列表失败: {e}")
return jsonify({'error': str(e)}), 500
+
+
+@messages_bp.route('/api/hourly_message_trend', methods=['GET'])
+@login_required
+def get_hourly_message_trend():
+ """获取按小时聊天趋势数据API"""
+ try:
+ server = current_app.dashboard_server
+ # 获取查询参数
+ group_id = request.args.get('group_id')
+ days = int(request.args.get('days', 1))
+
+ # 调用数据库方法获取按小时消息趋势数据
+ trend_data = server.message_storage.get_hourly_message_trend(group_id=group_id, days=days)
+
+ # 格式化数据为前端需要的格式
+ hours = []
+ counts = []
+ for item in trend_data:
+ hours.append(item['hour_slot'])
+ counts.append(item['message_count'])
+
+ # 获取群组名称
+ group_name = server.contact_manager.get_nickname(group_id) if group_id else "所有群组"
+
+ return jsonify({
+ 'success': True,
+ 'data': {
+ 'hours': hours,
+ 'counts': counts,
+ 'group_name': group_name
+ }
+ })
+ except Exception as e:
+ logger.error(f"获取按小时聊天趋势数据失败: {e}")
+ return jsonify({'success': False, 'error': str(e)}), 500
\ No newline at end of file
diff --git a/admin/dashboard/templates/index.html b/admin/dashboard/templates/index.html
index 83e8b01..623f1a7 100644
--- a/admin/dashboard/templates/index.html
+++ b/admin/dashboard/templates/index.html
@@ -143,6 +143,29 @@
+
+
+
+
+
+
按小时聊天趋势
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -261,6 +284,23 @@
disk_usage: 0,
uptime: 0,
timestamp: '-'
+ },
+ groups: [],
+ selectedGroupForHourlyTrend: '',
+ hourlyTrendDays: 1,
+ hourlyMessageTrendData: {
+ hours: [],
+ counts: []
+ },
+ hourlyMessageTrendLoading: true,
+ charts: {
+ pluginChart: null,
+ successRateChart: null,
+ trendChart: null,
+ cpuChart: null,
+ memoryChart: null,
+ diskChart: null,
+ hourlyMessageTrendChart: null // 添加这一行
}
}
},
@@ -287,6 +327,7 @@
this.loadSystemInfo();
// 加载当前用户信息
this.loadCurrentUserInfo();
+ this.loadGroups(); // 添加这一行
// 设置定时刷新系统信息(每30秒)
this.systemInfoTimer = setInterval(this.loadSystemInfo, 30000);
},
@@ -598,6 +639,87 @@
}
}
});
+ },
+ loadGroups() {
+ axios.get('/api/groups')
+ .then(response => {
+ if (response.data && response.data.groups) {
+ this.groups = response.data.groups;
+ if (this.groups.length > 0) {
+ this.selectedGroupForHourlyTrend = this.groups[0].group_id;
+ this.loadHourlyMessageTrend();
+ }
+ }
+ })
+ .catch(error => {
+ console.error('加载群组列表失败:', error);
+ this.$message.error('加载群组列表失败');
+ });
+ },
+ loadHourlyMessageTrend() {
+ if (!this.selectedGroupForHourlyTrend) return;
+
+ this.hourlyMessageTrendLoading = true;
+ axios.get('/api/hourly_message_trend', {
+ params: {
+ group_id: this.selectedGroupForHourlyTrend,
+ days: this.hourlyTrendDays
+ }
+ })
+ .then(response => {
+ if (response.data && response.data.success) {
+ this.hourlyMessageTrendData = response.data.data;
+ this.$nextTick(() => {
+ this.renderHourlyMessageTrendChart();
+ });
+ } else {
+ this.$message.error(response.data.error || '加载按小时聊天趋势数据失败');
+ }
+ this.hourlyMessageTrendLoading = false;
+ })
+ .catch(error => {
+ console.error('加载按小时聊天趋势数据失败:', error);
+ this.$message.error('加载按小时聊天趋势数据失败');
+ this.hourlyMessageTrendLoading = false;
+ });
+ },
+ renderHourlyMessageTrendChart() {
+ const ctx = document.getElementById('hourlyMessageTrendChart').getContext('2d');
+
+ // 销毁旧图表
+ if (this.charts.hourlyMessageTrendChart) {
+ this.charts.hourlyMessageTrendChart.destroy();
+ }
+
+ // 创建新图表
+ this.charts.hourlyMessageTrendChart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: this.hourlyMessageTrendData.hours,
+ datasets: [{
+ label: '消息数量',
+ data: this.hourlyMessageTrendData.counts,
+ fill: false,
+ backgroundColor: 'rgba(255, 99, 132, 0.6)',
+ borderColor: 'rgba(255, 99, 132, 1)',
+ tension: 0.1
+ }]
+ },
+ options: {
+ responsive: true,
+ scales: {
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ title: {
+ display: true,
+ text: `${this.hourlyMessageTrendData.group_name || '未知群组'} 的聊天趋势`
+ }
+ }
+ }
+ });
}
}
});
diff --git a/db/message_storage.py b/db/message_storage.py
index 1497f9a..9cd8723 100644
--- a/db/message_storage.py
+++ b/db/message_storage.py
@@ -208,3 +208,37 @@ class MessageStorageDB(BaseDBOperator):
# 使用已有的日志记录方式
print(f"更新消息图片路径出错: {e}")
return False
+
+
+ def get_hourly_message_trend(self, group_id: str = None, days: int = 1) -> List[Dict]:
+ """获取指定群组的按小时消息趋势数据
+
+ Args:
+ group_id: 群组ID,如果为None则获取所有群组的数据
+ days: 获取最近几天的数据,默认1天
+
+ Returns:
+ 包含小时和消息数量的列表
+ """
+ sql = """
+ SELECT
+ DATE_FORMAT(timestamp, '%Y-%m-%d %H:00') as hour_slot,
+ COUNT(*) as message_count
+ FROM messages
+ WHERE timestamp >= DATE_SUB(NOW(), INTERVAL %s DAY)
+ """
+
+ params = [days]
+
+ # 如果指定了群组ID,则添加群组筛选条件
+ if group_id:
+ sql += "AND group_id = %s "
+ params.append(group_id)
+
+ # 按小时分组并排序
+ sql += """
+ GROUP BY hour_slot
+ ORDER BY hour_slot
+ """
+
+ return self.execute_query(sql, tuple(params)) or []