This commit is contained in:
2026-03-01 01:03:00 +03:00
parent 29504c5502
commit b8a5569ab9
9 changed files with 373 additions and 15 deletions
@@ -5,6 +5,7 @@ from aiogram_dialog import Dialog, Window, DialogManager
from aiogram_dialog.widgets.text import Format, Const
from aiogram_dialog.widgets.kbd import Row, SwitchTo, Button, ScrollingGroup, Select, Group
from aiogram_dialog.widgets.input import MessageInput
from magic_filter import F
from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject
@@ -213,12 +214,12 @@ async def get_resident_info_data(
resident_id = dialog_manager.dialog_data.get("selected_resident_id")
if not resident_id:
return {"info_content": "Ошибка: резидент не выбран"}
return {"info_content": "Ошибка: резидент не выбран", "is_busy": False, "from_search": False}
resident = await residents_repository.get_resident_by_id(resident_id)
if not resident:
return {"info_content": "Ошибка: резидент не найден"}
return {"info_content": "Ошибка: резидент не найден", "is_busy": False, "from_search": False}
room = await rooms_repository.get_room_by_id(resident.room)
room_number = room.number if room else "???"
@@ -251,9 +252,12 @@ async def get_resident_info_data(
🔴 <b>Неотработанные часы:</b> <code>{resident.active_hours}</code> ч
"""
from_search = dialog_manager.dialog_data.get("from_search", False)
return {
"info_content": info_content,
"is_busy": resident.is_busy,
"from_search": from_search,
}
@@ -264,6 +268,7 @@ async def on_resident_selected(
item_id: str,
):
dialog_manager.dialog_data["selected_resident_id"] = int(item_id)
dialog_manager.dialog_data["from_search"] = False
await dialog_manager.switch_to(AdminMenuSG.resident_info)
@@ -389,7 +394,7 @@ async def on_search_residents(
button: Button,
dialog_manager: DialogManager,
):
await callback.answer("⚠️ Функционал в разработке", show_alert=True)
await dialog_manager.switch_to(AdminMenuSG.residents_search_input)
async def on_rooms_click(
@@ -578,6 +583,94 @@ async def on_hours_cancel(
await dialog_manager.switch_to(AdminMenuSG.resident_info)
async def on_search_input(
message: Message,
widget: MessageInput,
dialog_manager: DialogManager,
):
if not message.text or len(message.text.strip()) < 1:
await message.answer("⚠️ Пожалуйста, введите поисковый запрос")
return
query = message.text.strip()
if query.startswith("@"):
query = query[1:]
dialog_manager.dialog_data["search_query"] = query
dialog_manager.dialog_data["is_search_active"] = True
await dialog_manager.switch_to(AdminMenuSG.residents_search_results)
@inject
async def get_search_results_data(
dialog_manager: DialogManager,
residents_repository: FromDishka[ResidentsRepository],
rooms_repository: FromDishka[RoomsRepository],
users_repository: FromDishka[UsersRepository],
**kwargs,
):
query = dialog_manager.dialog_data.get("search_query", "")
residents, search_type = await residents_repository.search_residents(
query, users_repository
)
if not residents:
return {
"content": f"""
<blockquote>🔍 <b>Результаты поиска</b></blockquote>
<b>Запрос:</b> <code>{query}</code>
❌ Ничего не найдено
""",
"residents": [],
"has_results": False,
}
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))
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"""
<blockquote>🔍 <b>Результаты поиска по {search_type}</b></blockquote>
<b>Найдено резидентов:</b> <code>{len(residents)}</code>
Выберите резидента для просмотра информации:
"""
return {
"content": content,
"residents": residents_data,
"has_results": True,
}
async def on_search_resident_selected(
callback: CallbackQuery,
widget: Select,
dialog_manager: DialogManager,
item_id: str,
):
dialog_manager.dialog_data["selected_resident_id"] = int(item_id)
dialog_manager.dialog_data["from_search"] = True
await dialog_manager.switch_to(AdminMenuSG.resident_info)
admin_menu_dialog = Dialog(
Window(
Format("{content}"),
@@ -670,10 +763,17 @@ admin_menu_dialog = Dialog(
on_click=lambda c, b, m: m.switch_to(AdminMenuSG.resident_logout_confirm),
when="is_busy",
),
SwitchTo(
Const("◀️ Назад к результатам"),
id="back_to_search_results",
state=AdminMenuSG.residents_search_results,
when="from_search",
),
SwitchTo(
Const("◀️ Назад к списку"),
id="back_to_residents_list",
state=AdminMenuSG.residents,
when=~F["from_search"],
),
state=AdminMenuSG.resident_info,
getter=get_resident_info_data,
@@ -897,4 +997,42 @@ admin_menu_dialog = Dialog(
),
state=AdminMenuSG.broadcast_confirm,
),
Window(
Const("<blockquote>🔍 <b>Поиск резидентов</b></blockquote>\n\n<i>Введите номер комнаты, имя резидента или username пользователя. Можно указать только часть имени или username для поиска.</i>"),
MessageInput(on_search_input),
SwitchTo(
Const("◀️ Отмена"),
id="cancel_search",
state=AdminMenuSG.residents,
),
state=AdminMenuSG.residents_search_input,
),
Window(
Format("{content}"),
ScrollingGroup(
Select(
Format("{item[0]}"),
id="search_residents_select",
item_id_getter=lambda x: x[1],
items="residents",
on_click=on_search_resident_selected,
),
id="search_residents_scroll",
width=1,
height=7,
when="has_results",
),
SwitchTo(
Const("🔍 Новый поиск"),
id="new_search",
state=AdminMenuSG.residents_search_input,
),
SwitchTo(
Const("◀️ К списку резидентов"),
id="back_to_residents_from_search",
state=AdminMenuSG.residents,
),
state=AdminMenuSG.residents_search_results,
getter=get_search_results_data,
),
)
@@ -16,6 +16,9 @@ from dutylog.infrastructure.database.repositories.rooms_repository import (
from dutylog.infrastructure.database.repositories.residents_repository import (
ResidentsRepository,
)
from dutylog.infrastructure.database.repositories.users_repository import (
UsersRepository,
)
@inject
@@ -114,10 +117,18 @@ async def on_resident_selected(
dialog_manager: DialogManager,
item_id: str,
residents_repository: FromDishka[ResidentsRepository],
users_repository: FromDishka[UsersRepository],
):
user_id = callback.from_user.id
resident_id = int(item_id)
await users_repository.get_or_create_user(
user_id=user_id,
username=callback.from_user.username,
first_name=callback.from_user.first_name,
last_name=callback.from_user.last_name,
)
await residents_repository.bind_user_to_resident(resident_id, user_id)
await callback.answer("✅ Регистрация успешна!")
@@ -127,7 +138,7 @@ async def on_resident_selected(
registration_dialog = Dialog(
Window(
Const(
"<blockquote>🏢 <b>Выбор этажа</b></blockquote>\n\n<blockquote>⚠️ <b>Внимание!</b> Перерегистрацию может выполнить только администратор. Выбирайте внимательно!</blockquote>\n\nВыберите этаж, на котором вы живете:",
"<blockquote>🏢 <b>Выбор этажа</b></blockquote>\n\n<blockquote>⚠️ <b>Внимание!</b>\nПеререгистрацию может выполнить только администратор.\nВыбирайте внимательно!</blockquote>\n\nВыберите этаж, на котором вы живете:",
when="has_available",
),
Const(
@@ -10,6 +10,8 @@ class MainMenuSG(StatesGroup):
class AdminMenuSG(StatesGroup):
main = State()
residents = State()
residents_search_input = State()
residents_search_results = State()
resident_info = State()
resident_logout_confirm = State()
add_hours_select = State()