训练图片管理面板,右侧统计从前十限制改为全部,并且支持点击直接显示。

This commit is contained in:
2026-03-04 17:00:54 +08:00
parent 1ff540045d
commit b2a5060a19
4 changed files with 35 additions and 10 deletions
+1
View File
@@ -96,6 +96,7 @@ class DataManagementApp:
on_download_history_callback=self._on_download_history, on_download_history_callback=self._on_download_history,
on_export_callback=self._on_export, on_export_callback=self._on_export,
on_settings_callback=self._on_settings, on_settings_callback=self._on_settings,
on_item_click_callback=lambda name: self.filter_panel.set_goods_name_and_query(name),
width=RIGHT_PANEL_WIDTH width=RIGHT_PANEL_WIDTH
) )
self.statistics_panel.pack(side="right", fill="y", padx=(5, 0)) self.statistics_panel.pack(side="right", fill="y", padx=(5, 0))
+1 -2
View File
@@ -270,7 +270,7 @@ class MySQLManager:
month_start = today_start.replace(day=1) month_start = today_start.replace(day=1)
month_count = base_query.filter(Model.create_time >= month_start).count() month_count = base_query.filter(Model.create_time >= month_start).count()
# TOP 10物品统计 # 全部物品统计(按数量降序)
from sqlalchemy import func from sqlalchemy import func
top_items = session.query( top_items = session.query(
Model.goods_name, Model.goods_name,
@@ -289,7 +289,6 @@ class MySQLManager:
top_items = top_items.group_by(Model.goods_name)\ top_items = top_items.group_by(Model.goods_name)\
.order_by(func.count(Model.id).desc())\ .order_by(func.count(Model.id).desc())\
.limit(10)\
.all() .all()
return { return {
+6
View File
@@ -276,3 +276,9 @@ class FilterPanel(ctk.CTkFrame):
self.query_button.configure(state="disabled", text="查询中...") self.query_button.configure(state="disabled", text="查询中...")
else: else:
self.query_button.configure(state="normal", text="查询") self.query_button.configure(state="normal", text="查询")
def set_goods_name_and_query(self, goods_name: str):
"""从排行榜点击物品名称时,填入筛选框并触发查询"""
self.goods_search_entry.delete(0, 'end')
self.goods_search_entry.insert(0, goods_name)
self._on_query()
+27 -8
View File
@@ -15,6 +15,7 @@ class StatisticsPanel(ctk.CTkFrame):
on_download_history_callback: Callable, on_download_history_callback: Callable,
on_export_callback: Callable, on_export_callback: Callable,
on_settings_callback: Callable, on_settings_callback: Callable,
on_item_click_callback: Optional[Callable] = None,
**kwargs **kwargs
): ):
super().__init__(parent, **kwargs) super().__init__(parent, **kwargs)
@@ -23,6 +24,7 @@ class StatisticsPanel(ctk.CTkFrame):
self.on_download_history_callback = on_download_history_callback self.on_download_history_callback = on_download_history_callback
self.on_export_callback = on_export_callback self.on_export_callback = on_export_callback
self.on_settings_callback = on_settings_callback self.on_settings_callback = on_settings_callback
self.on_item_click_callback = on_item_click_callback
self._create_widgets() self._create_widgets()
@@ -130,13 +132,13 @@ class StatisticsPanel(ctk.CTkFrame):
separator2 = ctk.CTkFrame(time_frame, height=2) separator2 = ctk.CTkFrame(time_frame, height=2)
separator2.pack(fill="x", pady=10, padx=15) separator2.pack(fill="x", pady=10, padx=15)
# ==================== TOP 10物品排行 ==================== # ==================== 物品排行(全部) ====================
top_frame = ctk.CTkFrame(self) top_frame = ctk.CTkFrame(self)
top_frame.pack(fill="both", expand=True, padx=15, pady=(0, 10)) top_frame.pack(fill="both", expand=True, padx=15, pady=(0, 10))
top_title = ctk.CTkLabel( top_title = ctk.CTkLabel(
top_frame, top_frame,
text="TOP 10 物品排行", text="物品排行(全部)",
font=("Arial", 12, "bold") font=("Arial", 12, "bold")
) )
top_title.pack(pady=(10, 5), padx=10) top_title.pack(pady=(10, 5), padx=10)
@@ -212,7 +214,7 @@ class StatisticsPanel(ctk.CTkFrame):
- today_count: 今日数量 - today_count: 今日数量
- week_count: 本周数量 - week_count: 本周数量
- month_count: 本月数量 - month_count: 本月数量
- top_items: TOP 10列表 [{'name': str, 'count': int}, ...] - top_items: 全部物品列表 [{'name': str, 'count': int}, ...]
""" """
# 查询结果 # 查询结果
total_count = stats.get('total_count', 0) total_count = stats.get('total_count', 0)
@@ -232,7 +234,7 @@ class StatisticsPanel(ctk.CTkFrame):
self._update_top_items(stats.get('top_items', [])) self._update_top_items(stats.get('top_items', []))
def _update_top_items(self, top_items: list): def _update_top_items(self, top_items: list):
"""更新TOP 10排行榜""" """更新物品排行(全部)"""
# 清空现有内容 # 清空现有内容
for widget in self.top_scroll.winfo_children(): for widget in self.top_scroll.winfo_children():
widget.destroy() widget.destroy()
@@ -247,7 +249,7 @@ class StatisticsPanel(ctk.CTkFrame):
no_data_label.pack(pady=10) no_data_label.pack(pady=10)
return return
# 显示TOP 10 # 显示全部物品
for i, item in enumerate(top_items, 1): for i, item in enumerate(top_items, 1):
item_frame = ctk.CTkFrame(self.top_scroll) item_frame = ctk.CTkFrame(self.top_scroll)
item_frame.pack(fill="x", pady=2, padx=5) item_frame.pack(fill="x", pady=2, padx=5)
@@ -261,15 +263,32 @@ class StatisticsPanel(ctk.CTkFrame):
) )
rank_label.pack(side="left", padx=(5, 2)) rank_label.pack(side="left", padx=(5, 2))
# 物品名称 # 物品名称(可点击筛选)
name_label = ctk.CTkLabel( name_label = ctk.CTkLabel(
item_frame, item_frame,
text=item['name'], text=item['name'],
font=("Arial", 10), font=("Arial", 10),
anchor="w" anchor="w",
cursor="hand2" # 鼠标悬浮时显示手型
) )
name_label.pack(side="left", fill="x", expand=True, padx=5) name_label.pack(side="left", fill="x", expand=True, padx=5)
# 绑定点击与悬浮事件
if self.on_item_click_callback:
item_name = item['name']
name_label.bind(
"<Button-1>",
lambda e, name=item_name: self.on_item_click_callback(name)
)
name_label.bind(
"<Enter>",
lambda e, lbl=name_label: lbl.configure(text_color="#4FC3F7")
)
name_label.bind(
"<Leave>",
lambda e, lbl=name_label: lbl.configure(text_color=ctk.ThemeManager.theme["CTkLabel"]["text_color"])
)
# 数量 # 数量
count_label = ctk.CTkLabel( count_label = ctk.CTkLabel(
item_frame, item_frame,
@@ -291,6 +310,6 @@ class StatisticsPanel(ctk.CTkFrame):
self.week_label.configure(text="本周: 0 张") self.week_label.configure(text="本周: 0 张")
self.month_label.configure(text="本月: 0 张") self.month_label.configure(text="本月: 0 张")
# 清空TOP 10 # 清空全部物品排行
for widget in self.top_scroll.winfo_children(): for widget in self.top_scroll.winfo_children():
widget.destroy() widget.destroy()