调整趋势图功能,加入了查询数据库,分析群聊聊天数量的功能
This commit is contained in:
@@ -85,3 +85,26 @@ class MessageStorageDB(BaseDBOperator):
|
|||||||
"""
|
"""
|
||||||
params = (group_id, wx_id, date, count)
|
params = (group_id, wx_id, date, count)
|
||||||
return self.execute_update(sql, params)
|
return self.execute_update(sql, params)
|
||||||
|
|
||||||
|
|
||||||
|
def get_message_trend(self, group_id: str, days: int = 7) -> List[Dict]:
|
||||||
|
"""获取指定群组的消息趋势数据
|
||||||
|
|
||||||
|
Args:
|
||||||
|
group_id: 群组ID
|
||||||
|
days: 获取最近几天的数据,默认7天
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含日期和消息数量的列表
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
DATE(timestamp) as date,
|
||||||
|
COUNT(*) as message_count
|
||||||
|
FROM messages
|
||||||
|
WHERE group_id = %s
|
||||||
|
AND timestamp >= DATE_SUB(CURDATE(), INTERVAL %s DAY)
|
||||||
|
GROUP BY DATE(timestamp)
|
||||||
|
ORDER BY date
|
||||||
|
"""
|
||||||
|
return self.execute_query(sql, (group_id, days)) or []
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, Optional
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory
|
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory
|
||||||
|
|
||||||
from db.connection import DBConnectionManager
|
from db.connection import DBConnectionManager
|
||||||
|
from db.message_storage import MessageStorageDB
|
||||||
from db.stats_db import StatsDBOperator
|
from db.stats_db import StatsDBOperator
|
||||||
from utils.wechat.contact_manager import ContactManager
|
from utils.wechat.contact_manager import ContactManager
|
||||||
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||||
@@ -24,6 +26,7 @@ class DashboardServer:
|
|||||||
# 修正:使用单例模式获取数据库连接
|
# 修正:使用单例模式获取数据库连接
|
||||||
self.db_manager = DBConnectionManager.get_instance()
|
self.db_manager = DBConnectionManager.get_instance()
|
||||||
self.stats_db = StatsDBOperator(self.db_manager)
|
self.stats_db = StatsDBOperator(self.db_manager)
|
||||||
|
self.message_storage = MessageStorageDB(self.db_manager)
|
||||||
# 获取联系人管理器实例
|
# 获取联系人管理器实例
|
||||||
self.contact_manager = ContactManager.get_instance()
|
self.contact_manager = ContactManager.get_instance()
|
||||||
self.app = self._create_app()
|
self.app = self._create_app()
|
||||||
@@ -286,6 +289,40 @@ class DashboardServer:
|
|||||||
self.logger.info(f"看板主页/api/plugin_trend: {trend}")
|
self.logger.info(f"看板主页/api/plugin_trend: {trend}")
|
||||||
return jsonify({"success": True, "data": trend})
|
return jsonify({"success": True, "data": trend})
|
||||||
|
|
||||||
|
@app.route('/api/robot/group/<group_id>/message_trend', methods=['GET'])
|
||||||
|
def get_group_message_trend(group_id):
|
||||||
|
"""获取群组消息趋势数据"""
|
||||||
|
try:
|
||||||
|
days = request.args.get('days', default=7, type=int)
|
||||||
|
# 获取消息存储实例
|
||||||
|
trend_data = self.message_storage.get_message_trend(group_id, days)
|
||||||
|
|
||||||
|
# 格式化数据为前端需要的格式
|
||||||
|
dates = []
|
||||||
|
counts = []
|
||||||
|
for item in trend_data:
|
||||||
|
# 将日期转换为字符串
|
||||||
|
if isinstance(item['date'], datetime):
|
||||||
|
date_str = item['date'].strftime('%Y-%m-%d')
|
||||||
|
else:
|
||||||
|
date_str = str(item['date'])
|
||||||
|
|
||||||
|
dates.append(date_str)
|
||||||
|
counts.append(item['message_count'])
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'data': {
|
||||||
|
'dates': dates,
|
||||||
|
'counts': counts
|
||||||
|
}
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
'success': False,
|
||||||
|
'error': str(e)
|
||||||
|
})
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="200">
|
<el-table-column label="操作" width="280">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
@@ -59,6 +59,12 @@
|
|||||||
@click="toggleRobotStatus(scope.row)">
|
@click="toggleRobotStatus(scope.row)">
|
||||||
{% raw %}{{ scope.row.robot_status === 'enabled' ? '关闭' : '启用' }}{% endraw %}
|
{% raw %}{{ scope.row.robot_status === 'enabled' ? '关闭' : '启用' }}{% endraw %}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="info"
|
||||||
|
@click="viewMessageTrend(scope.row)">
|
||||||
|
消息趋势
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -130,6 +136,27 @@
|
|||||||
<el-button type="primary" @click="submitAddGroup">确定</el-button>
|
<el-button type="primary" @click="submitAddGroup">确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 群组消息趋势图对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
:title="currentGroupName + ' 消息趋势'"
|
||||||
|
:visible.sync="trendDialogVisible"
|
||||||
|
width="70%">
|
||||||
|
<div v-if="trendLoading" style="text-align: center; padding: 20px;">
|
||||||
|
<i class="el-icon-loading"></i>
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<canvas id="messageTrendChart" style="width: 100%; height: 400px;"></canvas>
|
||||||
|
<div style="margin-top: 20px; text-align: center;">
|
||||||
|
<el-radio-group v-model="trendDays" @change="loadMessageTrend">
|
||||||
|
<el-radio-button :label="7">最近7天</el-radio-button>
|
||||||
|
<el-radio-button :label="14">最近14天</el-radio-button>
|
||||||
|
<el-radio-button :label="30">最近30天</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -157,7 +184,12 @@
|
|||||||
{ required: true, message: '请输入群组ID', trigger: 'blur' },
|
{ required: true, message: '请输入群组ID', trigger: 'blur' },
|
||||||
{ pattern: /^\S+$/, message: '群组ID不能包含空格', trigger: 'blur' }
|
{ pattern: /^\S+$/, message: '群组ID不能包含空格', trigger: 'blur' }
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
// 趋势图相关数据
|
||||||
|
trendDialogVisible: false,
|
||||||
|
trendLoading: false,
|
||||||
|
trendDays: 7,
|
||||||
|
trendChart: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -481,6 +513,94 @@
|
|||||||
this.$message.error('批量移除失败: ' + error.message);
|
this.$message.error('批量移除失败: ' + error.message);
|
||||||
});
|
});
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
},
|
||||||
|
// 查看消息趋势
|
||||||
|
viewMessageTrend(group) {
|
||||||
|
this.currentGroupId = group.group_id;
|
||||||
|
this.currentGroupName = group.group_name || group.group_id;
|
||||||
|
this.trendDialogVisible = true;
|
||||||
|
this.loadMessageTrend();
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMessageTrend() {
|
||||||
|
this.trendLoading = true;
|
||||||
|
|
||||||
|
axios.get(`/api/robot/group/${this.currentGroupId}/message_trend?days=${this.trendDays}`)
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.success) {
|
||||||
|
this.renderTrendChart(response.data.data);
|
||||||
|
} else {
|
||||||
|
this.$message.error('加载消息趋势失败');
|
||||||
|
}
|
||||||
|
this.trendLoading = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('加载消息趋势失败:', error);
|
||||||
|
this.$message.error('加载消息趋势失败: ' + error.message);
|
||||||
|
this.trendLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTrendChart(data) {
|
||||||
|
// 确保DOM元素已经渲染
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 如果已有图表,先销毁
|
||||||
|
if (this.trendChart) {
|
||||||
|
this.trendChart.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取canvas元素
|
||||||
|
const ctx = document.getElementById('messageTrendChart').getContext('2d');
|
||||||
|
|
||||||
|
// 创建新图表
|
||||||
|
this.trendChart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: data.dates,
|
||||||
|
datasets: [{
|
||||||
|
label: '消息数量',
|
||||||
|
data: data.counts,
|
||||||
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||||
|
borderColor: 'rgba(75, 192, 192, 1)',
|
||||||
|
borderWidth: 2,
|
||||||
|
tension: 0.3,
|
||||||
|
fill: true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: '群聊消息数量趋势'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: '消息数量'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
ticks: {
|
||||||
|
maxRotation: 45,
|
||||||
|
minRotation: 45
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user