From 84df1fe56b596ebee2a8fc8a02fa67f8c39e3a6b Mon Sep 17 00:00:00 2001 From: kolo Date: Sun, 1 Mar 2026 01:53:17 +0300 Subject: [PATCH] update --- .../admin_dialogs/admin_menu_dialog.py | 26 ++ .../admin_dialogs/floors_management.py | 241 ++++++++++++ .../user_dialogs/admin_dialogs/main_menu.py | 4 +- .../admin_dialogs/residents_filter.py | 18 +- .../admin_dialogs/residents_management.py | 78 +++- .../admin_dialogs/rooms_management.py | 366 ++++++++++++++++++ .../application/bot/user_dialogs/states.py | 11 + .../repositories/floors_repository.py | 4 + 8 files changed, 734 insertions(+), 14 deletions(-) create mode 100644 src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py create mode 100644 src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py 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 2745455..111035f 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 @@ -8,6 +8,7 @@ from dutylog.application.bot.user_dialogs.admin_dialogs.residents_management imp residents_list_window, resident_info_window, resident_logout_confirm_window, + resident_delete_confirm_window, create_resident_name_window, create_resident_floor_window, create_resident_room_window, @@ -20,6 +21,20 @@ from dutylog.application.bot.user_dialogs.admin_dialogs.residents_filter import filter_hours_input_window, filtered_results_window, ) +from dutylog.application.bot.user_dialogs.admin_dialogs.floors_management import ( + floors_list_window, + floor_delete_confirm_window, + create_floor_input_window, + create_floor_confirm_window, +) +from dutylog.application.bot.user_dialogs.admin_dialogs.rooms_management import ( + rooms_select_floor_window, + rooms_list_window, + room_delete_confirm_window, + create_room_select_floor_window, + create_room_input_window, + create_room_confirm_window, +) from dutylog.application.bot.user_dialogs.admin_dialogs.hours_management import ( add_hours_select_window, remove_hours_select_window, @@ -39,6 +54,7 @@ admin_menu_dialog = Dialog( residents_list_window, resident_info_window, resident_logout_confirm_window, + resident_delete_confirm_window, add_hours_select_window, remove_hours_select_window, add_hours_custom_window, @@ -49,6 +65,16 @@ admin_menu_dialog = Dialog( create_resident_floor_window, create_resident_room_window, create_resident_confirm_window, + floors_list_window, + floor_delete_confirm_window, + create_floor_input_window, + create_floor_confirm_window, + rooms_select_floor_window, + rooms_list_window, + room_delete_confirm_window, + create_room_select_floor_window, + create_room_input_window, + create_room_confirm_window, statistics_window, broadcast_window, broadcast_confirm_window, diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py new file mode 100644 index 0000000..3874f3f --- /dev/null +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/floors_management.py @@ -0,0 +1,241 @@ +from aiogram.types import Message, CallbackQuery +from aiogram_dialog import Window, DialogManager +from aiogram_dialog.widgets.text import Format, Const +from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row +from aiogram_dialog.widgets.input import MessageInput +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.floors_repository import ( + FloorsRepository, +) + + +async def on_floors_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.floors) + + +@inject +async def get_floors_list_data( + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + all_floors = await floors_repository.get_all_floors() + all_floors.sort(key=lambda f: f.number) + + floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors] + + content = f""" +
🏢 Этажи
+ +Всего этажей: {len(all_floors)} + +Выберите этаж для удаления: +""" + + return { + "content": content, + "floors": floors_data, + } + + +async def on_floor_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["selected_floor_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.floor_delete_confirm) + + +async def on_add_floor_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.create_floor_input) + + +async def on_floor_number_input( + message: Message, + widget: MessageInput, + dialog_manager: DialogManager, +): + if not message.text: + await message.answer("⚠️ Пожалуйста, введите номер этажа") + return + + try: + floor_number = int(message.text) + if floor_number <= 0: + await message.answer("⚠️ Номер этажа должен быть положительным числом") + return + + dialog_manager.dialog_data["new_floor_number"] = floor_number + await dialog_manager.switch_to(AdminMenuSG.create_floor_confirm) + except ValueError: + await message.answer("⚠️ Пожалуйста, введите корректное число") + + +async def get_create_floor_confirm_data( + dialog_manager: DialogManager, + **kwargs, +): + floor_number = dialog_manager.dialog_data.get("new_floor_number", "???") + return {"floor_number": floor_number} + + +@inject +async def on_create_floor_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + floors_repository: FromDishka[FloorsRepository], +): + floor_number = dialog_manager.dialog_data.get("new_floor_number") + + if floor_number: + existing_floor = await floors_repository.get_floor_by_number(floor_number) + if existing_floor: + await callback.answer( + f"⚠️ Этаж {floor_number} уже существует!", + show_alert=True + ) + await dialog_manager.switch_to(AdminMenuSG.floors) + return + + await floors_repository.create_floor(floor_number) + await callback.answer("✅ Этаж создан!") + + await dialog_manager.switch_to(AdminMenuSG.floors) + + +async def on_create_floor_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.floors) + + +@inject +async def get_floor_delete_confirm_data( + dialog_manager: DialogManager, + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + floor_id = dialog_manager.dialog_data.get("selected_floor_id") + + if not floor_id: + return {"floor_number": "???"} + + floor = await floors_repository.get_floor_by_id(floor_id) + floor_number = floor.number if floor else "???" + + return {"floor_number": floor_number} + + +@inject +async def on_delete_floor_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + floors_repository: FromDishka[FloorsRepository], +): + floor_id = dialog_manager.dialog_data.get("selected_floor_id") + + if floor_id: + await floors_repository.delete_floor(floor_id) + await callback.answer("✅ Этаж удален!") + + await dialog_manager.switch_to(AdminMenuSG.floors) + + +async def on_delete_floor_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.floors) + + +floors_list_window = Window( + Format("{content}"), + ScrollingGroup( + Select( + Format("{item[0]}"), + id="floors_select", + item_id_getter=lambda x: x[1], + items="floors", + on_click=on_floor_selected, + ), + id="floors_scroll", + width=1, + height=7, + ), + Button( + Const("➕ Добавить этаж"), + id="add_floor_btn", + on_click=on_add_floor_click, + ), + SwitchTo( + Const("◀️ Назад"), + id="back_to_admin_menu_from_floors", + state=AdminMenuSG.main, + ), + state=AdminMenuSG.floors, + getter=get_floors_list_data, +) + +floor_delete_confirm_window = Window( + Format("
⚠️ Подтверждение удаления
\n\nВы точно хотите удалить этаж {floor_number}? Это действие необратимо и удалит все комнаты на этом этаже!"), + Row( + Button( + Const("✅ Да, удалить"), + id="confirm_delete_floor", + on_click=on_delete_floor_confirm, + ), + Button( + Const("❌ Отмена"), + id="cancel_delete_floor", + on_click=on_delete_floor_cancel, + ), + ), + state=AdminMenuSG.floor_delete_confirm, + getter=get_floor_delete_confirm_data, +) + +create_floor_input_window = Window( + Const("
Создание этажа
\n\nВведите номер этажа:"), + MessageInput(on_floor_number_input), + SwitchTo( + Const("◀️ Отмена"), + id="cancel_create_floor_input", + state=AdminMenuSG.floors, + ), + state=AdminMenuSG.create_floor_input, +) + +create_floor_confirm_window = Window( + Format("
Подтверждение
\n\nСоздать этаж {floor_number}?"), + Row( + Button( + Const("✅ Да"), + id="confirm_create_floor", + on_click=on_create_floor_confirm, + ), + Button( + Const("❌ Нет"), + id="cancel_create_floor", + on_click=on_create_floor_cancel, + ), + ), + state=AdminMenuSG.create_floor_confirm, + getter=get_create_floor_confirm_data, +) diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py index 89f3eee..5de0001 100644 --- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/main_menu.py @@ -84,11 +84,11 @@ async def get_statistics_data( async def on_rooms_click(callback, button, dialog_manager): - await callback.answer("⚠️ Функционал в разработке", show_alert=True) + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) async def on_floors_click(callback, button, dialog_manager): - await callback.answer("⚠️ Функционал в разработке", show_alert=True) + await dialog_manager.switch_to(AdminMenuSG.floors) main_menu_window = Window( diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py index be02718..8feeb7c 100644 --- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_filter.py @@ -13,6 +13,9 @@ from dutylog.infrastructure.database.repositories.residents_repository import ( from dutylog.infrastructure.database.repositories.rooms_repository import ( RoomsRepository, ) +from dutylog.infrastructure.database.repositories.floors_repository import ( + FloorsRepository, +) async def on_filter_residents( @@ -76,6 +79,7 @@ async def get_filtered_results_data( dialog_manager: DialogManager, residents_repository: FromDishka[ResidentsRepository], rooms_repository: FromDishka[RoomsRepository], + floors_repository: FromDishka[FloorsRepository], **kwargs, ): filter_type: str = dialog_manager.dialog_data["filter_type"] @@ -121,13 +125,19 @@ async def get_filtered_results_data( residents_with_rooms = [] for resident in filtered: 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)) + if room: + floor = await floors_repository.get_floor_by_id(room.on_floor) + floor_number = floor.number if floor else 999999 + room_number = room.number + else: + floor_number = 999999 + room_number = 999999 + residents_with_rooms.append((resident, floor_number, room_number)) - residents_with_rooms.sort(key=lambda x: x[1]) + residents_with_rooms.sort(key=lambda x: (x[1], x[2])) residents_data = [] - for resident, room_number in residents_with_rooms: + for resident, floor_number, room_number in residents_with_rooms: status = "🟢" if resident.is_busy else "⚪️" name = resident.real_name if resident.real_name else "Без имени" diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py index 27109aa..a17641a 100644 --- a/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/residents_management.py @@ -26,6 +26,7 @@ from dutylog.infrastructure.database.repositories.users_repository import ( async def get_residents_list_data( residents_repository: FromDishka[ResidentsRepository], rooms_repository: FromDishka[RoomsRepository], + floors_repository: FromDishka[FloorsRepository], **kwargs, ): all_residents = await residents_repository.get_all_residents() @@ -33,13 +34,19 @@ async def get_residents_list_data( 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)) + if room: + floor = await floors_repository.get_floor_by_id(room.on_floor) + floor_number = floor.number if floor else 999999 + room_number = room.number + else: + floor_number = 999999 + room_number = 999999 + residents_with_rooms.append((resident, floor_number, room_number)) - residents_with_rooms.sort(key=lambda x: x[1]) + residents_with_rooms.sort(key=lambda x: (x[1], x[2])) residents_data = [] - for resident, room_number in residents_with_rooms: + for resident, floor_number, room_number in residents_with_rooms: status = "🟢" if resident.is_busy else "⚪️" name = resident.real_name if resident.real_name else "Без имени" @@ -180,6 +187,30 @@ async def on_logout_resident_cancel( await dialog_manager.switch_to(AdminMenuSG.resident_info) +@inject +async def on_delete_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.delete_resident(resident_id) + await callback.answer("✅ Резидент удален!") + + await dialog_manager.switch_to(AdminMenuSG.residents) + + +async def on_delete_resident_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.resident_info) + + async def on_resident_name_input( message: Message, widget: MessageInput, @@ -304,6 +335,7 @@ async def get_search_results_data( dialog_manager: DialogManager, residents_repository: FromDishka[ResidentsRepository], rooms_repository: FromDishka[RoomsRepository], + floors_repository: FromDishka[FloorsRepository], users_repository: FromDishka[UsersRepository], **kwargs, ): @@ -329,13 +361,19 @@ async def get_search_results_data( residents_with_rooms = [] for resident in 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)) + if room: + floor = await floors_repository.get_floor_by_id(room.on_floor) + floor_number = floor.number if floor else 999999 + room_number = room.number + else: + floor_number = 999999 + room_number = 999999 + residents_with_rooms.append((resident, floor_number, room_number)) - residents_with_rooms.sort(key=lambda x: x[1]) + residents_with_rooms.sort(key=lambda x: (x[1], x[2])) residents_data = [] - for resident, room_number in residents_with_rooms: + for resident, floor_number, room_number in residents_with_rooms: status = "🟢" if resident.is_busy else "⚪️" name = resident.real_name if resident.real_name else "Без имени" @@ -430,6 +468,11 @@ resident_info_window = Window( on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_logout_confirm), when="is_busy", ), + Button( + Const("🗑 Удалить резидента"), + id="delete_resident_btn", + on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_delete_confirm), + ), SwitchTo( Const("◀️ Назад к результатам поиска"), id="back_to_search_results", @@ -581,3 +624,22 @@ search_results_window = Window( state=AdminMenuSG.residents_search_results, getter=get_search_results_data, ) + +resident_delete_confirm_window = Window( + Const( + "
⚠️ Подтверждение удаления
\n\nВы уверены, что хотите удалить этого резидента? Это действие необратимо!" + ), + Row( + Button( + Const("✅ Да, удалить"), + id="confirm_delete", + on_click=on_delete_resident_confirm, + ), + Button( + Const("❌ Отмена"), + id="cancel_delete", + on_click=on_delete_resident_cancel, + ), + ), + state=AdminMenuSG.resident_delete_confirm, +) diff --git a/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py b/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py new file mode 100644 index 0000000..8383137 --- /dev/null +++ b/src/dutylog/application/bot/user_dialogs/admin_dialogs/rooms_management.py @@ -0,0 +1,366 @@ +from aiogram.types import Message, CallbackQuery +from aiogram_dialog import Window, DialogManager +from aiogram_dialog.widgets.text import Format, Const +from aiogram_dialog.widgets.kbd import SwitchTo, Button, ScrollingGroup, Select, Row, Group +from aiogram_dialog.widgets.input import MessageInput +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.rooms_repository import ( + RoomsRepository, +) +from dutylog.infrastructure.database.repositories.floors_repository import ( + FloorsRepository, +) + + +async def on_rooms_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +@inject +async def get_rooms_floors_data( + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + all_floors = await floors_repository.get_all_floors() + all_floors.sort(key=lambda f: f.number) + + floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors] + + content = """ +
🚪 Комнаты
+ +Выберите этаж для просмотра комнат: +""" + + return { + "content": content, + "floors": floors_data, + } + + +async def on_rooms_floor_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["selected_floor_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +@inject +async def get_rooms_list_data( + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + floor_id = dialog_manager.dialog_data.get("selected_floor_id") + + if not floor_id: + return { + "content": "Ошибка: этаж не выбран", + "rooms": [], + "floor_number": "???", + } + + floor = await floors_repository.get_floor_by_id(floor_id) + floor_number = floor.number if floor else "???" + + rooms = await rooms_repository.get_rooms_by_floor(floor_id) + rooms.sort(key=lambda r: r.number) + + rooms_data = [(f"🚪 Комната {r.number}", r.id) for r in rooms] + + content = f""" +
🚪 Комнаты на этаже {floor_number}
+ +Всего комнат: {len(rooms)} + +Выберите комнату для удаления: +""" + + return { + "content": content, + "rooms": rooms_data, + "floor_number": floor_number, + } + + +async def on_room_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["selected_room_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.room_delete_confirm) + + +async def on_add_room_click( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.create_room_select_floor) + + +@inject +async def get_create_room_floors_data( + floors_repository: FromDishka[FloorsRepository], + **kwargs, +): + all_floors = await floors_repository.get_all_floors() + all_floors.sort(key=lambda f: f.number) + + floors_data = [(f"🏢 Этаж {f.number}", f.id) for f in all_floors] + + content = """ +
Создание комнаты
+ +Выберите этаж для новой комнаты: +""" + + return { + "content": content, + "floors": floors_data, + } + + +async def on_create_room_floor_selected( + callback: CallbackQuery, + widget: Select, + dialog_manager: DialogManager, + item_id: str, +): + dialog_manager.dialog_data["new_room_floor_id"] = int(item_id) + await dialog_manager.switch_to(AdminMenuSG.create_room_input) + + +async def on_room_number_input( + message: Message, + widget: MessageInput, + dialog_manager: DialogManager, +): + if not message.text: + await message.answer("⚠️ Пожалуйста, введите номер комнаты") + return + + try: + room_number = int(message.text) + if room_number <= 0: + await message.answer("⚠️ Номер комнаты должен быть положительным числом") + return + + dialog_manager.dialog_data["new_room_number"] = room_number + await dialog_manager.switch_to(AdminMenuSG.create_room_confirm) + except ValueError: + await message.answer("⚠️ Пожалуйста, введите корректное число") + + +async def get_create_room_confirm_data( + dialog_manager: DialogManager, + **kwargs, +): + room_number = dialog_manager.dialog_data.get("new_room_number", "???") + return {"room_number": room_number} + + +@inject +async def on_create_room_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], +): + room_number = dialog_manager.dialog_data.get("new_room_number") + floor_id = dialog_manager.dialog_data.get("new_room_floor_id") + + if room_number and floor_id: + existing_room = await rooms_repository.get_room_by_number(room_number) + if existing_room: + await callback.answer( + f"⚠️ Комната {room_number} уже существует!", + show_alert=True + ) + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + return + + await rooms_repository.create_room(room_number, floor_id) + await callback.answer("✅ Комната создана!") + + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +async def on_create_room_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_select_floor) + + +@inject +async def get_room_delete_confirm_data( + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], + **kwargs, +): + room_id = dialog_manager.dialog_data.get("selected_room_id") + + if not room_id: + return {"room_number": "???"} + + room = await rooms_repository.get_room_by_id(room_id) + room_number = room.number if room else "???" + + return {"room_number": room_number} + + +@inject +async def on_delete_room_confirm( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, + rooms_repository: FromDishka[RoomsRepository], +): + room_id = dialog_manager.dialog_data.get("selected_room_id") + + if room_id: + await rooms_repository.delete_room(room_id) + await callback.answer("✅ Комната удалена!") + + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +async def on_delete_room_cancel( + callback: CallbackQuery, + button: Button, + dialog_manager: DialogManager, +): + await dialog_manager.switch_to(AdminMenuSG.rooms_list) + + +rooms_select_floor_window = Window( + Format("{content}"), + Group( + Select( + Format("{item[0]}"), + id="rooms_floors_select", + item_id_getter=lambda x: x[1], + items="floors", + on_click=on_rooms_floor_selected, + ), + width=2, + ), + Button( + Const("➕ Добавить комнату"), + id="add_room_btn", + on_click=on_add_room_click, + ), + SwitchTo( + Const("◀️ Назад"), + id="back_to_admin_menu_from_rooms", + state=AdminMenuSG.main, + ), + state=AdminMenuSG.rooms_select_floor, + getter=get_rooms_floors_data, +) + +rooms_list_window = Window( + Format("{content}"), + ScrollingGroup( + Select( + Format("{item[0]}"), + id="rooms_select", + item_id_getter=lambda x: x[1], + items="rooms", + on_click=on_room_selected, + ), + id="rooms_scroll", + width=1, + height=7, + ), + SwitchTo( + Const("◀️ Назад к этажам"), + id="back_to_rooms_floors", + state=AdminMenuSG.rooms_select_floor, + ), + state=AdminMenuSG.rooms_list, + getter=get_rooms_list_data, +) + +room_delete_confirm_window = Window( + Format("
⚠️ Подтверждение удаления
\n\nВы точно хотите удалить комнату {room_number}? Это действие необратимо и удалит всех резидентов в этой комнате!"), + Row( + Button( + Const("✅ Да, удалить"), + id="confirm_delete_room", + on_click=on_delete_room_confirm, + ), + Button( + Const("❌ Отмена"), + id="cancel_delete_room", + on_click=on_delete_room_cancel, + ), + ), + state=AdminMenuSG.room_delete_confirm, + getter=get_room_delete_confirm_data, +) + +create_room_select_floor_window = Window( + Format("{content}"), + Group( + Select( + Format("{item[0]}"), + id="create_room_floors_select", + item_id_getter=lambda x: x[1], + items="floors", + on_click=on_create_room_floor_selected, + ), + width=2, + ), + SwitchTo( + Const("◀️ Отмена"), + id="cancel_create_room_floor", + state=AdminMenuSG.rooms_select_floor, + ), + state=AdminMenuSG.create_room_select_floor, + getter=get_create_room_floors_data, +) + +create_room_input_window = Window( + Const("
Создание комнаты
\n\nВведите номер комнаты:"), + MessageInput(on_room_number_input), + SwitchTo( + Const("◀️ Назад"), + id="back_to_create_room_floor", + state=AdminMenuSG.create_room_select_floor, + ), + state=AdminMenuSG.create_room_input, +) + +create_room_confirm_window = Window( + Format("
Подтверждение
\n\nСоздать комнату {room_number}?"), + Row( + Button( + Const("✅ Да"), + id="confirm_create_room", + on_click=on_create_room_confirm, + ), + Button( + Const("❌ Нет"), + id="cancel_create_room", + on_click=on_create_room_cancel, + ), + ), + state=AdminMenuSG.create_room_confirm, + getter=get_create_room_confirm_data, +) diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py index 8ce8bde..9bbce5f 100644 --- a/src/dutylog/application/bot/user_dialogs/states.py +++ b/src/dutylog/application/bot/user_dialogs/states.py @@ -17,6 +17,7 @@ class AdminMenuSG(StatesGroup): residents_filtered_results = State() resident_info = State() resident_logout_confirm = State() + resident_delete_confirm = State() add_hours_select = State() remove_hours_select = State() add_hours_custom = State() @@ -27,6 +28,16 @@ class AdminMenuSG(StatesGroup): create_resident_floor = State() create_resident_room = State() create_resident_confirm = State() + floors = State() + floor_delete_confirm = State() + create_floor_input = State() + create_floor_confirm = State() + rooms_select_floor = State() + rooms_list = State() + room_delete_confirm = State() + create_room_select_floor = State() + create_room_input = State() + create_room_confirm = State() statistics = State() broadcast = State() broadcast_confirm = State() diff --git a/src/dutylog/infrastructure/database/repositories/floors_repository.py b/src/dutylog/infrastructure/database/repositories/floors_repository.py index 87361f8..f8e2eb6 100644 --- a/src/dutylog/infrastructure/database/repositories/floors_repository.py +++ b/src/dutylog/infrastructure/database/repositories/floors_repository.py @@ -22,5 +22,9 @@ class FloorsRepository: async def get_all_floors(self) -> list[Floor]: return await self.floors_dao.get_all() + async def create_floor(self, number: int) -> Floor: + floor = Floor(number=number) + return await self.floors_dao.create(floor) + async def delete_floor(self, floor_id: int) -> None: await self.floors_dao.delete(floor_id)