diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py index d8261cd..6eedaa7 100644 --- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/admin_menu_dialog.py @@ -3,7 +3,7 @@ from aiogram import Bot from aiogram.exceptions import TelegramForbiddenError, TelegramBadRequest from aiogram_dialog import Dialog, Window, DialogManager from aiogram_dialog.widgets.text import Format, Const -from aiogram_dialog.widgets.kbd import Row, SwitchTo, Button +from aiogram_dialog.widgets.kbd import Row, SwitchTo, Button, ScrollingGroup, Select from aiogram_dialog.widgets.input import MessageInput from dishka import FromDishka from dishka.integrations.aiogram_dialog import inject @@ -11,6 +11,7 @@ from dishka.integrations.aiogram_dialog import inject from dutylog.application.bot.user_dialogs.states import AdminMenuSG from dutylog.infrastructure.database.repositories.users_repository import UsersRepository from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository +from dutylog.infrastructure.database.repositories.rooms_repository import RoomsRepository from dutylog.infrastructure.utils.config import Config @@ -152,6 +153,156 @@ async def on_broadcast_cancel( await dialog_manager.switch_to(AdminMenuSG.main) +@inject +async def get_residents_list_data( + residents_repository: FromDishka[ResidentsRepository], + rooms_repository: FromDishka[RoomsRepository], + **kwargs, +): + all_residents = await residents_repository.get_all_residents() + + residents_with_rooms = [] + for resident in all_residents: + room = await rooms_repository.get_room_by_id(resident.room) + room_number = room.number if room else 999999 + residents_with_rooms.append((resident, room_number)) + + residents_with_rooms.sort(key=lambda x: x[1]) + + residents_data = [] + for resident, room_number in residents_with_rooms: + status = "🟢" if resident.is_busy else "⚪️" + name = resident.real_name if resident.real_name else "Без имени" + + residents_data.append(( + f"{name} | Комната {room_number} | {status}", + resident.id + )) + + content = f""" +
🏠 Резиденты+ +Всего резидентов:
{len(all_residents)}
+
+Выберите резидента для просмотра информации:
+"""
+
+ return {
+ "content": content,
+ "residents": residents_data,
+ }
+
+
+@inject
+async def get_resident_info_data(
+ dialog_manager: DialogManager,
+ residents_repository: FromDishka[ResidentsRepository],
+ rooms_repository: FromDishka[RoomsRepository],
+ users_repository: FromDishka[UsersRepository],
+ **kwargs,
+):
+ resident_id = dialog_manager.dialog_data.get("selected_resident_id")
+
+ if not resident_id:
+ return {"info_content": "Ошибка: резидент не выбран"}
+
+ resident = await residents_repository.get_resident_by_id(resident_id)
+
+ if not resident:
+ return {"info_content": "Ошибка: резидент не найден"}
+
+ room = await rooms_repository.get_room_by_id(resident.room)
+ room_number = room.number if room else "???"
+
+ name = resident.real_name if resident.real_name else "Без имени"
+ status = "🟢 Занят" if resident.is_busy else "⚪️ Свободен"
+
+ user_info = "Не привязан"
+ if resident.user_entity:
+ user = await users_repository.get_user_by_id(resident.user_entity)
+ if user:
+ username = f"@{user.username}" if user.username else "без username"
+ user_info = f"{user.first_name} ({username})"
+
+ info_content = f"""
+👤 Информация о резиденте+ +ID:
{resident.id}
+Имя: {name}
+Комната: {room_number}
+Статус: {status}
+Пользователь: {user_info}
+
+━━━━━━━━━━━━━━━━━━━━
+
+🟢 Активные часы: {resident.active_hours} ч
+🔴 Неактивные часы: {resident.inactive_hours} ч
+📊 Всего часов: {resident.active_hours + resident.inactive_hours} ч
+"""
+
+ return {
+ "info_content": info_content,
+ "is_busy": resident.is_busy,
+ }
+
+
+async def on_resident_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ item_id: str,
+):
+ dialog_manager.dialog_data["selected_resident_id"] = int(item_id)
+ await dialog_manager.switch_to(AdminMenuSG.resident_info)
+
+
+async def on_add_resident(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await callback.answer("⚠️ Функционал в разработке", show_alert=True)
+
+
+async def on_filter_residents(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await callback.answer("⚠️ Функционал в разработке", show_alert=True)
+
+
+async def on_search_residents(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await callback.answer("⚠️ Функционал в разработке", show_alert=True)
+
+
+@inject
+async def on_logout_resident_confirm(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+ residents_repository: FromDishka[ResidentsRepository],
+):
+ resident_id = dialog_manager.dialog_data.get("selected_resident_id")
+
+ if resident_id:
+ await residents_repository.unbind_user_from_resident(resident_id)
+
+ await dialog_manager.switch_to(AdminMenuSG.resident_info)
+
+
+async def on_logout_resident_cancel(
+ callback: CallbackQuery,
+ button: Button,
+ dialog_manager: DialogManager,
+):
+ await dialog_manager.switch_to(AdminMenuSG.resident_info)
+
+
admin_menu_dialog = Dialog(
Window(
Format("{content}"),
@@ -179,9 +330,75 @@ admin_menu_dialog = Dialog(
getter=get_admin_menu_data,
),
Window(
- Const("🏠 Резиденты\n\nФункционал в разработке"), - SwitchTo(Const("◀️ Назад"), id="back_from_residents", state=AdminMenuSG.main), + Format("{content}"), + Row( + Button( + Const("🔍 Поиск"), + id="search_residents_btn", + on_click=on_search_residents, + ), + Button( + Const("🔽 Фильтр"), + id="filter_residents_btn", + on_click=on_filter_residents, + ), + ), + ScrollingGroup( + Select( + Format("{item[0]}"), + id="residents_select", + item_id_getter=lambda x: x[1], + items="residents", + on_click=on_resident_selected, + ), + id="residents_scroll", + width=1, + height=7, + ), + Button( + Const("➕ Добавить резидента"), + id="add_resident_btn", + on_click=on_add_resident, + ), + SwitchTo( + Const("◀️ Назад"), + id="back_to_admin_menu", + state=AdminMenuSG.main, + ), state=AdminMenuSG.residents, + getter=get_residents_list_data, + ), + Window( + Format("{info_content}"), + Button( + Const("🚪 Разлогинить"), + id="logout_resident_btn", + on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_logout_confirm), + when="is_busy", + ), + SwitchTo( + Const("◀️ Назад к списку"), + id="back_to_residents_list", + state=AdminMenuSG.residents, + ), + state=AdminMenuSG.resident_info, + getter=get_resident_info_data, + ), + Window( + Const("
⚠️ Подтверждение\n\nВы уверены, что хотите разлогинить этого резидента?"), + Row( + Button( + Const("✅ Да"), + id="confirm_logout", + on_click=on_logout_resident_confirm, + ), + Button( + Const("❌ Нет"), + id="cancel_logout", + on_click=on_logout_resident_cancel, + ), + ), + state=AdminMenuSG.resident_logout_confirm, ), Window( Const("
👥 Пользователи\n\nФункционал в разработке"), diff --git a/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py b/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py index d1efc24..517f7ea 100644 --- a/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py +++ b/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py @@ -8,6 +8,7 @@ from dishka.integrations.aiogram_dialog import inject from dutylog.application.bot.user_dialogs.states import MainMenuSG from dutylog.infrastructure.database.repositories.users_repository import UsersRepository from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository +from dutylog.infrastructure.database.repositories.rooms_repository import RoomsRepository from dutylog.infrastructure.database.repositories.hours_transactions_repository import HoursTransactionsRepository from dutylog.infrastructure.utils.config import Config @@ -17,6 +18,7 @@ async def get_main_menu_data( event_from_user: User, users_repository: FromDishka[UsersRepository], residents_repository: FromDishka[ResidentsRepository], + rooms_repository: FromDishka[RoomsRepository], config: FromDishka[Config], **kwargs, ): @@ -35,7 +37,14 @@ async def get_main_menu_data( elif is_admin: greeting = "👨💼 Администратор" else: - greeting = f"👋 Привет, {event_from_user.first_name}!" + resident = await residents_repository.get_resident_by_user_id(event_from_user.id) + if resident: + room = await rooms_repository.get_room_by_id(resident.room) + room_number = room.number if room else "???" + real_name = resident.real_name if resident.real_name else event_from_user.first_name + greeting = f"👋 Привет, {real_name}!\n🚪 Комната
{room_number}"
+ else:
+ greeting = f"👋 Привет, {event_from_user.first_name}!"
if not is_admin and not is_creator:
resident = await residents_repository.get_resident_by_user_id(event_from_user.id)
diff --git a/src/dutylog/application/bot/user_dialogs/registration_dialog.py b/src/dutylog/application/bot/user_dialogs/registration_dialog.py
index c79f111..762f675 100644
--- a/src/dutylog/application/bot/user_dialogs/registration_dialog.py
+++ b/src/dutylog/application/bot/user_dialogs/registration_dialog.py
@@ -112,13 +112,13 @@ async def on_resident_selected(
await residents_repository.bind_user_to_resident(resident_id, user_id)
- await callback.answer("✅ Вы успешно зарегистрированы!")
+ await callback.answer("✅ Регистрация успешна!")
await dialog_manager.start(MainMenuSG.main)
registration_dialog = Dialog(
Window(
- Const("🏢 Выбор этажа\n\n⚠️ Внимание! Перерегистрацию может выполнить только администратор. Выбирайте внимательно!\n\nВыберите этаж, на котором вы живете:", when="has_available"), + Const("
🏢 Выбор этажа\n\n
⚠️ Внимание! Перерегистрацию может выполнить только администратор. Выбирайте внимательно!\n\nВыберите этаж, на котором вы живете:", when="has_available"), Const("
⚠️ Нет доступных резидентов\n\nВсе резиденты уже заняты.\nОбратитесь к администратору.", when=~F["has_available"]), Group( Select( diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py index 0d6fb3c..d337734 100644 --- a/src/dutylog/application/bot/user_dialogs/states.py +++ b/src/dutylog/application/bot/user_dialogs/states.py @@ -10,6 +10,8 @@ class MainMenuSG(StatesGroup): class AdminMenuSG(StatesGroup): main = State() residents = State() + resident_info = State() + resident_logout_confirm = State() users = State() statistics = State() broadcast = State()