Revert "监控面板内容修改"

This reverts commit 455603de92.
This commit is contained in:
liuwei
2025-03-19 13:17:48 +08:00
parent 455603de92
commit 27b6fbf86f
4 changed files with 216 additions and 204 deletions

View File

@@ -353,120 +353,188 @@ class StatsDBOperator(BaseDBOperator):
""" """
return self.execute_query(sql, (error_id,), fetch_one=True) return self.execute_query(sql, (error_id,), fetch_one=True)
def get_dashboard_summary(self, days: int = 7) -> Dict[str, Any]: def get_dashboard_summary(self, days: int = 7) -> Dict:
"""获取仪表盘摘要数据""" """获取仪表盘摘要数据
try:
# 计算日期范围 Args:
days: 统计天数
Returns:
仪表盘摘要数据
"""
# 获取时间范围
end_date = datetime.now() end_date = datetime.now()
start_date = end_date - timedelta(days=days) start_date = end_date - timedelta(days=days)
start_date_str = start_date.strftime("%Y-%m-%d")
# 获取总调用次数 # 1. 总调用次数
total_calls_query = """ total_calls_sql = """
SELECT COUNT(*) as total_calls FROM plugin_calls SELECT SUM(total_calls) as total_calls
WHERE created_at >= ? AND created_at <= ? FROM t_plugin_stats
WHERE stat_date >= %s
""" """
total_calls_result = self.db_manager.execute_query(total_calls_query, (start_date, end_date)) total_calls_result = self.execute_query(total_calls_sql, (start_date_str,), fetch_one=True)
total_calls = total_calls_result[0]['total_calls'] if total_calls_result else 0 total_calls = total_calls_result['total_calls'] if total_calls_result and total_calls_result['total_calls'] else 0
# 获取成功率 # 2. 成功率
success_rate_query = """ success_rate_sql = """
SELECT SELECT SUM(success_calls) as success_calls, SUM(total_calls) as total_calls
ROUND((SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*)), 2) as success_rate FROM t_plugin_stats
FROM plugin_calls WHERE stat_date >= %s
WHERE created_at >= ? AND created_at <= ?
""" """
success_rate_result = self.db_manager.execute_query(success_rate_query, (start_date, end_date)) success_rate_result = self.execute_query(success_rate_sql, (start_date_str,), fetch_one=True)
success_rate = success_rate_result[0]['success_rate'] if success_rate_result and success_rate_result[0]['success_rate'] is not None else 0 success_rate = 0
if success_rate_result and success_rate_result['total_calls']:
success_rate = (success_rate_result['success_calls'] / success_rate_result['total_calls']) * 100
# 获取活跃用户数 # 3. 活跃用户数
active_users_query = """ active_users_sql = """
SELECT COUNT(DISTINCT user_id) as active_users FROM plugin_calls SELECT COUNT(DISTINCT user_id) as active_users
WHERE created_at >= ? AND created_at <= ? FROM t_user_stats
WHERE last_used_at >= %s
""" """
active_users_result = self.db_manager.execute_query(active_users_query, (start_date, end_date)) active_users_result = self.execute_query(active_users_sql, (start_date_str,), fetch_one=True)
active_users = active_users_result[0]['active_users'] if active_users_result else 0 active_users = active_users_result['active_users'] if active_users_result else 0
# 获取活跃群组数 # 4. 活跃群组数
active_groups_query = """ active_groups_sql = """
SELECT COUNT(DISTINCT group_id) as active_groups FROM plugin_calls SELECT COUNT(DISTINCT group_id) as active_groups
WHERE created_at >= ? AND created_at <= ? AND group_id != '' FROM t_group_stats
WHERE last_used_at >= %s
""" """
active_groups_result = self.db_manager.execute_query(active_groups_query, (start_date, end_date)) active_groups_result = self.execute_query(active_groups_sql, (start_date_str,), fetch_one=True)
active_groups = active_groups_result[0]['active_groups'] if active_groups_result else 0 active_groups = active_groups_result['active_groups'] if active_groups_result else 0
# 5. 错误数量
error_count_sql = """
SELECT COUNT(*) as error_count
FROM t_error_logs
WHERE created_at >= %s
"""
error_count_result = self.execute_query(error_count_sql, (start_date_str,), fetch_one=True)
error_count = error_count_result['error_count'] if error_count_result else 0
# 6. 平均响应时间
avg_response_time_sql = """
SELECT AVG(avg_process_time) as avg_response_time
FROM t_plugin_stats
WHERE stat_date >= %s
"""
avg_response_time_result = self.execute_query(avg_response_time_sql, (start_date_str,), fetch_one=True)
avg_response_time = avg_response_time_result['avg_response_time'] if avg_response_time_result and avg_response_time_result['avg_response_time'] else 0
# 7. 最常用的插件
top_plugins_sql = """
SELECT plugin_name, SUM(total_calls) as total_calls
FROM t_plugin_stats
WHERE stat_date >= %s
GROUP BY plugin_name
ORDER BY total_calls DESC
LIMIT 5
"""
top_plugins = self.execute_query(top_plugins_sql, (start_date_str,)) or []
# 8. 最活跃的用户
top_users_sql = """
SELECT user_id, SUM(total_calls) as total_calls
FROM t_user_stats
WHERE last_used_at >= %s
GROUP BY user_id
ORDER BY total_calls DESC
LIMIT 5
"""
top_users = self.execute_query(top_users_sql, (start_date_str,)) or []
# 9. 最活跃的群组
top_groups_sql = """
SELECT group_id, SUM(total_calls) as total_calls
FROM t_group_stats
WHERE last_used_at >= %s
GROUP BY group_id
ORDER BY total_calls DESC
LIMIT 5
"""
top_groups = self.execute_query(top_groups_sql, (start_date_str,)) or []
# 返回汇总数据
return { return {
"total_calls": total_calls, "total_calls": total_calls,
"success_rate": success_rate, "success_rate": success_rate,
"active_users": active_users, "active_users": active_users,
"active_groups": active_groups "active_groups": active_groups,
} "error_count": error_count,
except Exception as e: "avg_response_time": avg_response_time,
logging.error(f"获取仪表盘摘要数据出错: {e}") "top_plugins": top_plugins,
return { "top_users": top_users,
"total_calls": 0, "top_groups": top_groups
"success_rate": 0,
"active_users": 0,
"active_groups": 0
} }
def get_plugin_trend(self, plugin_name: str = '', days: int = 7) -> List[Dict[str, Any]]: def get_plugin_trend(self, plugin_name: str = "", days: int = 7) -> List[Dict]:
"""获取插件用趋势数据""" """获取插件使用趋势数据
try:
# 计算日期范围
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
# 构建查询条件 Args:
params = [start_date, end_date] plugin_name: 插件名称,为空则获取所有插件
plugin_condition = "" days: 统计天数
if plugin_name:
plugin_condition = "AND plugin_name = ?"
params.append(plugin_name)
# 按日期分组查询 Returns:
query = f""" 插件使用趋势数据
SELECT
date(created_at) as date,
COUNT(*) as call_count,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as success_count
FROM plugin_calls
WHERE created_at >= ? AND created_at <= ? {plugin_condition}
GROUP BY date(created_at)
ORDER BY date
""" """
# 获取时间范围内的每一天
end_date = datetime.now().date()
start_date = end_date - timedelta(days=days-1) # 包含今天所以减1
results = self.db_manager.execute_query(query, tuple(params)) if plugin_name:
# 获取特定插件的趋势
sql = """
SELECT stat_date, SUM(total_calls) as total_calls,
SUM(success_calls) as success_calls,
SUM(failed_calls) as failed_calls
FROM t_plugin_stats
WHERE plugin_name = %s AND stat_date >= %s
GROUP BY stat_date
ORDER BY stat_date
"""
params = (plugin_name, start_date)
else:
# 获取所有插件的趋势
sql = """
SELECT stat_date, SUM(total_calls) as total_calls,
SUM(success_calls) as success_calls,
SUM(failed_calls) as failed_calls
FROM t_plugin_stats
WHERE stat_date >= %s
GROUP BY stat_date
ORDER BY stat_date
"""
params = (start_date,)
results = self.execute_query(sql, params) or []
# 将结果转换为按日期的字典
trend_by_date = {r['stat_date'].strftime('%Y-%m-%d'): r for r in results}
# 确保每一天都有数据 # 确保每一天都有数据
date_format = "%Y-%m-%d"
trend_data = [] trend_data = []
# 创建日期范围内的所有日期
current_date = start_date current_date = start_date
while current_date <= end_date: while current_date <= end_date:
date_str = current_date.strftime(date_format) date_str = current_date.strftime('%Y-%m-%d')
if date_str in trend_by_date:
# 查找当前日期的数据 data = trend_by_date[date_str]
day_data = next((item for item in results if item['date'] == date_str), None)
if day_data:
trend_data.append({ trend_data.append({
"date": date_str, 'date': date_str,
"call_count": day_data['call_count'], 'total_calls': data['total_calls'],
"success_count": day_data['success_count'], 'success_calls': data['success_calls'],
"success_rate": round(day_data['success_count'] * 100 / day_data['call_count'], 2) if day_data['call_count'] > 0 else 0 'failed_calls': data['failed_calls'],
'success_rate': (data['success_calls'] / data['total_calls'] * 100) if data['total_calls'] > 0 else 0
}) })
else: else:
trend_data.append({ trend_data.append({
"date": date_str, 'date': date_str,
"call_count": 0, 'total_calls': 0,
"success_count": 0, 'success_calls': 0,
"success_rate": 0 'failed_calls': 0,
'success_rate': 0
}) })
current_date += timedelta(days=1) current_date += timedelta(days=1)
return trend_data return trend_data
except Exception as e:
logging.error(f"获取插件趋势数据出错: {e}")
return []

View File

@@ -112,10 +112,6 @@ class DashboardServer:
trend = self.stats_db.get_plugin_trend(plugin_name, days) trend = self.stats_db.get_plugin_trend(plugin_name, days)
return jsonify({"success": True, "data": trend}) return jsonify({"success": True, "data": trend})
@app.route('/errors')
def errors():
return render_template('errors.html')
return app return app
def run(self) -> None: def run(self) -> None:

View File

@@ -82,24 +82,25 @@
background-color="#545c64" background-color="#545c64"
text-color="#fff" text-color="#fff"
active-text-color="#ffd04b" active-text-color="#ffd04b"
@select="handleSelect"> @select="handleSelect"
<el-menu-item index="/"> router>
<el-menu-item index="1" route="/">
<i class="el-icon-s-home"></i> <i class="el-icon-s-home"></i>
<span slot="title">首页概览</span> <span slot="title">首页概览</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/plugins"> <el-menu-item index="2" route="/plugins">
<i class="el-icon-s-data"></i> <i class="el-icon-s-grid"></i>
<span slot="title">插件统计</span> <span slot="title">插件统计</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/users"> <el-menu-item index="3" route="/users">
<i class="el-icon-user"></i> <i class="el-icon-user"></i>
<span slot="title">用户统计</span> <span slot="title">用户统计</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/groups"> <el-menu-item index="4" route="/groups">
<i class="el-icon-s-cooperation"></i> <i class="el-icon-s-cooperation"></i>
<span slot="title">群组统计</span> <span slot="title">群组统计</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/errors"> <el-menu-item index="5" route="/errors">
<i class="el-icon-warning"></i> <i class="el-icon-warning"></i>
<span slot="title">错误日志</span> <span slot="title">错误日志</span>
</el-menu-item> </el-menu-item>

View File

@@ -232,102 +232,49 @@
} }
// 准备数据 // 准备数据
const dates = trendData.map(item => item.date); const labels = trendData.map(item => item.stat_date);
const callCounts = trendData.map(item => item.call_count); const totalData = trendData.map(item => item.total_calls);
const successRates = trendData.map(item => item.success_rate); const successData = trendData.map(item => item.success_calls);
const errorData = trendData.map(item => item.error_calls);
// 创建图表 // 创建图表
this.charts.trendChart = new Chart(ctx, { this.charts.trendChart = new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
labels: dates, labels: labels,
datasets: [ datasets: [
{ {
label: '调用次数', label: '调用',
data: callCounts, data: totalData,
backgroundColor: 'rgba(54, 162, 235, 0.2)', fill: false,
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)', borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1, tension: 0.1
yAxisID: 'y-axis-1'
}, },
{ {
label: '成功率(%)', label: '成功调用',
data: successRates, data: successData,
backgroundColor: 'rgba(255, 99, 132, 0.2)', fill: false,
borderColor: 'rgba(255, 99, 132, 1)', backgroundColor: 'rgba(75, 192, 192, 0.6)',
borderWidth: 1,
yAxisID: 'y-axis-2'
}
]
},
options: {
responsive: true,
scales: {
yAxes: [
{
id: 'y-axis-1',
type: 'linear',
position: 'left',
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: '调用次数'
}
},
{
id: 'y-axis-2',
type: 'linear',
position: 'right',
ticks: {
beginAtZero: true,
max: 100
},
scaleLabel: {
display: true,
labelString: '成功率(%)'
}
}
]
}
}
});
},
renderSuccessRateChart() {
const ctx = document.getElementById('successRateChart').getContext('2d');
// 销毁旧图表
if (this.charts.successRateChart) {
this.charts.successRateChart.destroy();
}
// 准备数据
const plugins = this.pluginStats.map(item => item.plugin_name);
const successRates = this.pluginStats.map(item => item.success_rate);
// 创建图表
this.charts.successRateChart = new Chart(ctx, {
type: 'bar',
data: {
labels: plugins,
datasets: [{
label: '成功率(%)',
data: successRates,
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgba(75, 192, 192, 1)', borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1 tension: 0.1
}] },
{
label: '失败调用',
data: errorData,
fill: false,
backgroundColor: 'rgba(255, 99, 132, 0.6)',
borderColor: 'rgba(255, 99, 132, 1)',
tension: 0.1
}
]
}, },
options: { options: {
responsive: true, responsive: true,
scales: { scales: {
yAxes: [{ y: {
ticks: { beginAtZero: true
beginAtZero: true,
max: 100
} }
}]
} }
} }
}); });