297 lines
9.4 KiB
Python
297 lines
9.4 KiB
Python
"""
|
|
右侧统计面板
|
|
"""
|
|
import customtkinter as ctk
|
|
from typing import Dict, Callable, Optional
|
|
|
|
|
|
class StatisticsPanel(ctk.CTkFrame):
|
|
"""右侧统计面板"""
|
|
|
|
def __init__(
|
|
self,
|
|
parent,
|
|
on_refresh_callback: Callable,
|
|
on_download_history_callback: Callable,
|
|
on_export_callback: Callable,
|
|
on_settings_callback: Callable,
|
|
**kwargs
|
|
):
|
|
super().__init__(parent, **kwargs)
|
|
|
|
self.on_refresh_callback = on_refresh_callback
|
|
self.on_download_history_callback = on_download_history_callback
|
|
self.on_export_callback = on_export_callback
|
|
self.on_settings_callback = on_settings_callback
|
|
|
|
self._create_widgets()
|
|
|
|
def _create_widgets(self):
|
|
"""创建UI组件"""
|
|
# 标题
|
|
title_label = ctk.CTkLabel(
|
|
self,
|
|
text="统计信息",
|
|
font=("Arial", 16, "bold")
|
|
)
|
|
title_label.pack(pady=(15, 10), padx=15)
|
|
|
|
# ==================== 当前数据源信息 ====================
|
|
datasource_frame = ctk.CTkFrame(self)
|
|
datasource_frame.pack(fill="x", padx=15, pady=(0, 10))
|
|
|
|
datasource_title = ctk.CTkLabel(
|
|
datasource_frame,
|
|
text="当前数据源",
|
|
font=("Arial", 12, "bold")
|
|
)
|
|
datasource_title.pack(pady=(10, 5), padx=10)
|
|
|
|
self.datasource_label = ctk.CTkLabel(
|
|
datasource_frame,
|
|
text="菜品",
|
|
font=("Arial", 14, "bold"),
|
|
text_color="blue"
|
|
)
|
|
self.datasource_label.pack(pady=(0, 10), padx=10)
|
|
|
|
# ==================== 数据统计 ====================
|
|
stats_frame = ctk.CTkFrame(self)
|
|
stats_frame.pack(fill="x", padx=15, pady=(0, 10))
|
|
|
|
stats_title = ctk.CTkLabel(
|
|
stats_frame,
|
|
text="数据统计",
|
|
font=("Arial", 12, "bold")
|
|
)
|
|
stats_title.pack(pady=(10, 5), padx=10)
|
|
|
|
# 查询结果
|
|
self.query_result_label = ctk.CTkLabel(
|
|
stats_frame,
|
|
text="查询结果: 0 张",
|
|
font=("Arial", 11),
|
|
anchor="w"
|
|
)
|
|
self.query_result_label.pack(fill="x", pady=2, padx=15)
|
|
|
|
# 已选择
|
|
self.selected_label = ctk.CTkLabel(
|
|
stats_frame,
|
|
text="已选择: 0 张",
|
|
font=("Arial", 11),
|
|
anchor="w"
|
|
)
|
|
self.selected_label.pack(fill="x", pady=2, padx=15)
|
|
|
|
# 分隔线
|
|
separator1 = ctk.CTkFrame(stats_frame, height=2)
|
|
separator1.pack(fill="x", pady=10, padx=15)
|
|
|
|
# ==================== 时间分布 ====================
|
|
time_frame = ctk.CTkFrame(self)
|
|
time_frame.pack(fill="x", padx=15, pady=(0, 10))
|
|
|
|
time_title = ctk.CTkLabel(
|
|
time_frame,
|
|
text="时间分布",
|
|
font=("Arial", 12, "bold")
|
|
)
|
|
time_title.pack(pady=(10, 5), padx=10)
|
|
|
|
# 今日
|
|
self.today_label = ctk.CTkLabel(
|
|
time_frame,
|
|
text="今日: 0 张",
|
|
font=("Arial", 11),
|
|
anchor="w"
|
|
)
|
|
self.today_label.pack(fill="x", pady=2, padx=15)
|
|
|
|
# 本周
|
|
self.week_label = ctk.CTkLabel(
|
|
time_frame,
|
|
text="本周: 0 张",
|
|
font=("Arial", 11),
|
|
anchor="w"
|
|
)
|
|
self.week_label.pack(fill="x", pady=2, padx=15)
|
|
|
|
# 本月
|
|
self.month_label = ctk.CTkLabel(
|
|
time_frame,
|
|
text="本月: 0 张",
|
|
font=("Arial", 11),
|
|
anchor="w"
|
|
)
|
|
self.month_label.pack(fill="x", pady=2, padx=15)
|
|
|
|
# 分隔线
|
|
separator2 = ctk.CTkFrame(time_frame, height=2)
|
|
separator2.pack(fill="x", pady=10, padx=15)
|
|
|
|
# ==================== TOP 10物品排行 ====================
|
|
top_frame = ctk.CTkFrame(self)
|
|
top_frame.pack(fill="both", expand=True, padx=15, pady=(0, 10))
|
|
|
|
top_title = ctk.CTkLabel(
|
|
top_frame,
|
|
text="TOP 10 物品排行",
|
|
font=("Arial", 12, "bold")
|
|
)
|
|
top_title.pack(pady=(10, 5), padx=10)
|
|
|
|
# 可滚动的排行榜
|
|
self.top_scroll = ctk.CTkScrollableFrame(top_frame, height=200)
|
|
self.top_scroll.pack(fill="both", expand=True, padx=10, pady=(0, 10))
|
|
|
|
# ==================== 快捷操作 ====================
|
|
actions_frame = ctk.CTkFrame(self)
|
|
actions_frame.pack(fill="x", padx=15, pady=(0, 15))
|
|
|
|
actions_title = ctk.CTkLabel(
|
|
actions_frame,
|
|
text="快捷操作",
|
|
font=("Arial", 12, "bold")
|
|
)
|
|
actions_title.pack(pady=(10, 5), padx=10)
|
|
|
|
# 刷新按钮
|
|
refresh_btn = ctk.CTkButton(
|
|
actions_frame,
|
|
text="🔄 刷新",
|
|
command=self.on_refresh_callback,
|
|
height=30
|
|
)
|
|
refresh_btn.pack(fill="x", padx=10, pady=2)
|
|
|
|
# 下载历史按钮
|
|
history_btn = ctk.CTkButton(
|
|
actions_frame,
|
|
text="📜 下载历史",
|
|
command=self.on_download_history_callback,
|
|
height=30,
|
|
fg_color="purple",
|
|
hover_color="darkviolet"
|
|
)
|
|
history_btn.pack(fill="x", padx=10, pady=2)
|
|
|
|
# 导出按钮
|
|
export_btn = ctk.CTkButton(
|
|
actions_frame,
|
|
text="📊 导出数据",
|
|
command=self.on_export_callback,
|
|
height=30,
|
|
fg_color="orange",
|
|
hover_color="darkorange"
|
|
)
|
|
export_btn.pack(fill="x", padx=10, pady=2)
|
|
|
|
# 设置按钮
|
|
settings_btn = ctk.CTkButton(
|
|
actions_frame,
|
|
text="⚙️ 设置",
|
|
command=self.on_settings_callback,
|
|
height=30,
|
|
fg_color="gray",
|
|
hover_color="darkgray"
|
|
)
|
|
settings_btn.pack(fill="x", padx=10, pady=(2, 10))
|
|
|
|
def update_datasource(self, datasource: str):
|
|
"""更新当前数据源显示"""
|
|
self.datasource_label.configure(text=datasource)
|
|
|
|
def update_statistics(self, stats: Dict):
|
|
"""
|
|
更新统计信息
|
|
|
|
Args:
|
|
stats: 统计数据字典,包含:
|
|
- total_count: 总数量
|
|
- today_count: 今日数量
|
|
- week_count: 本周数量
|
|
- month_count: 本月数量
|
|
- top_items: TOP 10列表 [{'name': str, 'count': int}, ...]
|
|
"""
|
|
# 查询结果
|
|
total_count = stats.get('total_count', 0)
|
|
self.query_result_label.configure(text=f"查询结果: {total_count} 张")
|
|
|
|
# 时间分布
|
|
today_count = stats.get('today_count', 0)
|
|
self.today_label.configure(text=f"今日: {today_count} 张")
|
|
|
|
week_count = stats.get('week_count', 0)
|
|
self.week_label.configure(text=f"本周: {week_count} 张")
|
|
|
|
month_count = stats.get('month_count', 0)
|
|
self.month_label.configure(text=f"本月: {month_count} 张")
|
|
|
|
# TOP 10排行
|
|
self._update_top_items(stats.get('top_items', []))
|
|
|
|
def _update_top_items(self, top_items: list):
|
|
"""更新TOP 10排行榜"""
|
|
# 清空现有内容
|
|
for widget in self.top_scroll.winfo_children():
|
|
widget.destroy()
|
|
|
|
if not top_items:
|
|
no_data_label = ctk.CTkLabel(
|
|
self.top_scroll,
|
|
text="暂无数据",
|
|
font=("Arial", 11),
|
|
text_color="gray"
|
|
)
|
|
no_data_label.pack(pady=10)
|
|
return
|
|
|
|
# 显示TOP 10
|
|
for i, item in enumerate(top_items, 1):
|
|
item_frame = ctk.CTkFrame(self.top_scroll)
|
|
item_frame.pack(fill="x", pady=2, padx=5)
|
|
|
|
# 排名
|
|
rank_label = ctk.CTkLabel(
|
|
item_frame,
|
|
text=f"{i}.",
|
|
font=("Arial", 11, "bold"),
|
|
width=30
|
|
)
|
|
rank_label.pack(side="left", padx=(5, 2))
|
|
|
|
# 物品名称
|
|
name_label = ctk.CTkLabel(
|
|
item_frame,
|
|
text=item['name'],
|
|
font=("Arial", 10),
|
|
anchor="w"
|
|
)
|
|
name_label.pack(side="left", fill="x", expand=True, padx=5)
|
|
|
|
# 数量
|
|
count_label = ctk.CTkLabel(
|
|
item_frame,
|
|
text=f"{item['count']}张",
|
|
font=("Arial", 10),
|
|
text_color="blue"
|
|
)
|
|
count_label.pack(side="right", padx=5)
|
|
|
|
def update_selected_count(self, count: int):
|
|
"""更新已选择数量"""
|
|
self.selected_label.configure(text=f"已选择: {count} 张")
|
|
|
|
def clear_statistics(self):
|
|
"""清空统计信息"""
|
|
self.query_result_label.configure(text="查询结果: 0 张")
|
|
self.selected_label.configure(text="已选择: 0 张")
|
|
self.today_label.configure(text="今日: 0 张")
|
|
self.week_label.configure(text="本周: 0 张")
|
|
self.month_label.configure(text="本月: 0 张")
|
|
|
|
# 清空TOP 10
|
|
for widget in self.top_scroll.winfo_children():
|
|
widget.destroy()
|