diff --git a/src/dutylog/application/bot/admin_dialogs/admin_menu_dialog.py b/src/dutylog/application/bot/admin_dialogs/admin_menu_dialog.py index 4c99eca..8845072 100644 --- a/src/dutylog/application/bot/admin_dialogs/admin_menu_dialog.py +++ b/src/dutylog/application/bot/admin_dialogs/admin_menu_dialog.py @@ -68,6 +68,9 @@ from dutylog.application.bot.admin_dialogs.broadcast import ( from dutylog.application.bot.admin_dialogs.faq import ( admin_faq_window, ) +from dutylog.application.bot.admin_dialogs.top_residents import ( + top_residents_window, +) admin_menu_dialog = Dialog( @@ -121,4 +124,5 @@ admin_menu_dialog = Dialog( filter_select_window, filter_hours_input_window, filtered_results_window, + top_residents_window, ) diff --git a/src/dutylog/application/bot/admin_dialogs/main_menu.py b/src/dutylog/application/bot/admin_dialogs/main_menu.py index 044f90a..ea085d9 100644 --- a/src/dutylog/application/bot/admin_dialogs/main_menu.py +++ b/src/dutylog/application/bot/admin_dialogs/main_menu.py @@ -109,8 +109,6 @@ async def get_statistics_data( admins_count = len([u for u in all_users if u.is_admin]) total_rooms = len(all_rooms) - total_rooms_active_hours = sum(r.active_hours for r in all_rooms) - total_rooms_inactive_hours = sum(r.inactive_hours for r in all_rooms) stats_text = f"""
📊 Статистика системы@@ -131,10 +129,6 @@ async def get_statistics_data( 🚪 КОМНАТЫ 🏠 Всего комнат:
{total_rooms}
-
-🟢 Отработанных часов: {total_rooms_inactive_hours} ч
-🔴 Неотработанных часов: {total_rooms_active_hours} ч
-📊 Итого: {total_rooms_active_hours + total_rooms_inactive_hours} ч
"""
return {"stats_content": stats_text}
@@ -193,11 +187,16 @@ main_menu_window = Window(
state=AdminMenuSG.statistics,
),
SwitchTo(
- Const("❓ FAQ"),
- id="faq_btn",
- state=AdminMenuSG.faq,
+ Const("🏆 Топ"),
+ id="top_btn",
+ state=AdminMenuSG.top_residents,
),
),
+ SwitchTo(
+ Const("❓ FAQ"),
+ id="faq_btn",
+ state=AdminMenuSG.faq,
+ ),
SwitchTo(
Const("📢 Рассылка"),
id="broadcast_btn",
diff --git a/src/dutylog/application/bot/admin_dialogs/top_residents.py b/src/dutylog/application/bot/admin_dialogs/top_residents.py
new file mode 100644
index 0000000..b70d6eb
--- /dev/null
+++ b/src/dutylog/application/bot/admin_dialogs/top_residents.py
@@ -0,0 +1,57 @@
+from aiogram_dialog import Window
+from aiogram_dialog.widgets.text import Format, Const
+from aiogram_dialog.widgets.kbd import SwitchTo
+from dishka import FromDishka
+from dishka.integrations.aiogram_dialog import inject
+
+from dutylog.application.bot.user_dialogs.states import AdminMenuSG
+from dutylog.infrastructure.database.repositories.residents_repository import (
+ ResidentsRepository,
+)
+
+
+@inject
+async def get_top_residents_data(
+ residents_repository: FromDishka[ResidentsRepository],
+ **kwargs,
+) -> dict[str, str]:
+ all_residents = await residents_repository.get_all_residents()
+
+ residents_with_hours = [
+ r for r in all_residents
+ if (r.inactive_hours + r.active_hours) > 0
+ ]
+
+ sorted_residents = sorted(
+ residents_with_hours,
+ key=lambda r: r.inactive_hours + r.active_hours,
+ reverse=True
+ )
+
+ top_residents = sorted_residents[:5]
+
+ if not top_residents:
+ content = "🏆 Топ общежития\n\n⚠️ Нет данных для отображения топа."
+ else:
+ content = "🏆 Топ общежития\n\n"
+ medals = ["🥇", "🥈", "🥉", "4.", "5."]
+
+ for idx, resident in enumerate(top_residents):
+ total_hours = resident.inactive_hours + resident.active_hours
+ name = resident.real_name or "Без имени"
+
+ content += f"{medals[idx]} {name} — {total_hours} ч\n"
+
+ return {"content": content}
+
+
+top_residents_window = Window(
+ Format("{content}"),
+ SwitchTo(
+ Const("◀️ Назад"),
+ id="back_to_main",
+ state=AdminMenuSG.main,
+ ),
+ state=AdminMenuSG.top_residents,
+ getter=get_top_residents_data,
+)
diff --git a/src/dutylog/application/bot/creator_dialogs/admins_management.py b/src/dutylog/application/bot/creator_dialogs/admins_management.py
index e71b576..6e405ea 100644
--- a/src/dutylog/application/bot/creator_dialogs/admins_management.py
+++ b/src/dutylog/application/bot/creator_dialogs/admins_management.py
@@ -304,6 +304,11 @@ admins_list_window = Window(
id="history_btn",
state=CreatorMenuSG.transactions_history,
),
+ SwitchTo(
+ Const("🏆 Топ"),
+ id="top_btn",
+ state=CreatorMenuSG.top_residents,
+ ),
Button(
Const("◀️ Назад"),
id="back_to_main_from_admins",
diff --git a/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py b/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py
index b4b747c..8b985b8 100644
--- a/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py
+++ b/src/dutylog/application/bot/creator_dialogs/creator_menu_dialog.py
@@ -10,6 +10,9 @@ from dutylog.application.bot.creator_dialogs.admins_management import (
from dutylog.application.bot.creator_dialogs.transactions_history import (
transactions_history_window,
)
+from dutylog.application.bot.creator_dialogs.top_residents import (
+ top_residents_window,
+)
creator_menu_dialog = Dialog(
@@ -19,4 +22,5 @@ creator_menu_dialog = Dialog(
add_admin_select_user_window,
add_admin_confirm_window,
transactions_history_window,
+ top_residents_window,
)
diff --git a/src/dutylog/application/bot/creator_dialogs/top_residents.py b/src/dutylog/application/bot/creator_dialogs/top_residents.py
new file mode 100644
index 0000000..aa07f87
--- /dev/null
+++ b/src/dutylog/application/bot/creator_dialogs/top_residents.py
@@ -0,0 +1,53 @@
+from aiogram_dialog import Window
+from aiogram_dialog.widgets.text import Format, Const
+from aiogram_dialog.widgets.kbd import Back
+from dishka import FromDishka
+from dishka.integrations.aiogram_dialog import inject
+
+from dutylog.application.bot.user_dialogs.states import CreatorMenuSG
+from dutylog.infrastructure.database.repositories.residents_repository import (
+ ResidentsRepository,
+)
+
+
+@inject
+async def get_top_residents_data(
+ residents_repository: FromDishka[ResidentsRepository],
+ **kwargs,
+) -> dict[str, str]:
+ all_residents = await residents_repository.get_all_residents()
+
+ residents_with_hours = [
+ r for r in all_residents
+ if (r.inactive_hours + r.active_hours) > 0
+ ]
+
+ sorted_residents = sorted(
+ residents_with_hours,
+ key=lambda r: r.inactive_hours + r.active_hours,
+ reverse=True
+ )
+
+ top_residents = sorted_residents[:5]
+
+ if not top_residents:
+ content = "🏆 Топ общежития\n\n⚠️ Нет данных для отображения топа."
+ else:
+ content = "🏆 Топ общежития\n\n"
+ medals = ["🥇", "🥈", "🥉", "4.", "5."]
+
+ for idx, resident in enumerate(top_residents):
+ total_hours = resident.inactive_hours + resident.active_hours
+ name = resident.real_name or "Без имени"
+
+ content += f"{medals[idx]} {name} — {total_hours} ч\n"
+
+ return {"content": content}
+
+
+top_residents_window = Window(
+ Format("{content}"),
+ Back(Const("◀️ Назад")),
+ state=CreatorMenuSG.top_residents,
+ getter=get_top_residents_data,
+)
diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py
index f53c80e..ff13137 100644
--- a/src/dutylog/application/bot/user_dialogs/states.py
+++ b/src/dutylog/application/bot/user_dialogs/states.py
@@ -59,6 +59,7 @@ class AdminMenuSG(StatesGroup):
faq = State()
broadcast = State()
broadcast_confirm = State()
+ top_residents = State()
class CreatorMenuSG(StatesGroup):
@@ -68,6 +69,7 @@ class CreatorMenuSG(StatesGroup):
add_admin_select_user = State()
add_admin_confirm = State()
transactions_history = State()
+ top_residents = State()
class RegistrationSG(StatesGroup):