mirror of
https://github.com/koloideal/DutyLog.git
synced 2026-06-10 10:25:29 +03:00
update
This commit is contained in:
@@ -15,6 +15,11 @@ from dutylog.application.bot.user_dialogs.admin_dialogs.residents_management imp
|
||||
search_input_window,
|
||||
search_results_window,
|
||||
)
|
||||
from dutylog.application.bot.user_dialogs.admin_dialogs.residents_filter import (
|
||||
filter_select_window,
|
||||
filter_hours_input_window,
|
||||
filtered_results_window,
|
||||
)
|
||||
from dutylog.application.bot.user_dialogs.admin_dialogs.hours_management import (
|
||||
add_hours_select_window,
|
||||
remove_hours_select_window,
|
||||
@@ -49,4 +54,7 @@ admin_menu_dialog = Dialog(
|
||||
broadcast_confirm_window,
|
||||
search_input_window,
|
||||
search_results_window,
|
||||
filter_select_window,
|
||||
filter_hours_input_window,
|
||||
filtered_results_window,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
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, 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.residents_repository import (
|
||||
ResidentsRepository,
|
||||
)
|
||||
from dutylog.infrastructure.database.repositories.rooms_repository import (
|
||||
RoomsRepository,
|
||||
)
|
||||
|
||||
|
||||
async def on_filter_residents(
|
||||
callback: CallbackQuery,
|
||||
button: Button,
|
||||
dialog_manager: DialogManager,
|
||||
):
|
||||
await dialog_manager.switch_to(AdminMenuSG.residents_filter_select)
|
||||
|
||||
|
||||
async def get_filter_options_data(**kwargs):
|
||||
filter_options = [
|
||||
("busy", "🟢 Только занятые"),
|
||||
("free", "⚪️ Только свободные"),
|
||||
("hours_more", "🔴 Неотработанных часов > X"),
|
||||
("hours_less", "🔴 Неотработанных часов < X"),
|
||||
("worked_more", "🟢 Отработанных часов > X"),
|
||||
("worked_less", "🟢 Отработанных часов < X"),
|
||||
]
|
||||
return {"filter_options": filter_options}
|
||||
|
||||
|
||||
async def on_filter_selected(
|
||||
callback: CallbackQuery,
|
||||
widget: Select,
|
||||
dialog_manager: DialogManager,
|
||||
item_id: str,
|
||||
):
|
||||
dialog_manager.dialog_data["filter_type"] = item_id
|
||||
|
||||
if item_id in ["hours_more", "hours_less", "worked_more", "worked_less"]:
|
||||
await dialog_manager.switch_to(AdminMenuSG.residents_filter_hours_input)
|
||||
else:
|
||||
dialog_manager.dialog_data["filter_hours"] = None
|
||||
await dialog_manager.switch_to(AdminMenuSG.residents_filtered_results)
|
||||
|
||||
|
||||
async def on_filter_hours_input(
|
||||
message: Message,
|
||||
widget: MessageInput,
|
||||
dialog_manager: DialogManager,
|
||||
):
|
||||
if not message.text:
|
||||
await message.answer("⚠️ Пожалуйста, введите число")
|
||||
return
|
||||
|
||||
try:
|
||||
hours = int(message.text)
|
||||
if hours < 0:
|
||||
await message.answer("⚠️ Количество часов не может быть отрицательным")
|
||||
return
|
||||
|
||||
dialog_manager.dialog_data["filter_hours"] = hours
|
||||
await dialog_manager.switch_to(AdminMenuSG.residents_filtered_results)
|
||||
except ValueError:
|
||||
await message.answer("⚠️ Пожалуйста, введите корректное число")
|
||||
|
||||
|
||||
@inject
|
||||
async def get_filtered_results_data(
|
||||
dialog_manager: DialogManager,
|
||||
residents_repository: FromDishka[ResidentsRepository],
|
||||
rooms_repository: FromDishka[RoomsRepository],
|
||||
**kwargs,
|
||||
):
|
||||
filter_type = dialog_manager.dialog_data.get("filter_type", "")
|
||||
filter_hours = dialog_manager.dialog_data.get("filter_hours")
|
||||
|
||||
all_residents = await residents_repository.get_all_residents()
|
||||
|
||||
if filter_type == "busy":
|
||||
filtered = [r for r in all_residents if r.is_busy]
|
||||
filter_description = "занятым резидентам"
|
||||
elif filter_type == "free":
|
||||
filtered = [r for r in all_residents if not r.is_busy]
|
||||
filter_description = "свободным резидентам"
|
||||
elif filter_type == "hours_more":
|
||||
filtered = [r for r in all_residents if r.active_hours > filter_hours]
|
||||
filter_description = f"неотработанных часов > {filter_hours}"
|
||||
elif filter_type == "hours_less":
|
||||
filtered = [r for r in all_residents if r.active_hours < filter_hours]
|
||||
filter_description = f"неотработанных часов < {filter_hours}"
|
||||
elif filter_type == "worked_more":
|
||||
filtered = [r for r in all_residents if r.inactive_hours > filter_hours]
|
||||
filter_description = f"отработанных часов > {filter_hours}"
|
||||
elif filter_type == "worked_less":
|
||||
filtered = [r for r in all_residents if r.inactive_hours < filter_hours]
|
||||
filter_description = f"отработанных часов < {filter_hours}"
|
||||
else:
|
||||
filtered = all_residents
|
||||
filter_description = "всем резидентам"
|
||||
|
||||
if not filtered:
|
||||
return {
|
||||
"content": f"""
|
||||
<blockquote>🔽 <b>Результаты фильтрации</b></blockquote>
|
||||
|
||||
<b>Фильтр:</b> {filter_description}
|
||||
|
||||
❌ Ничего не найдено
|
||||
""",
|
||||
"residents": [],
|
||||
"has_results": False,
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
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>Результаты фильтрации по {filter_description}</b></blockquote>
|
||||
|
||||
<b>Найдено резидентов:</b> <code>{len(filtered)}</code>
|
||||
|
||||
Выберите резидента для просмотра информации:
|
||||
"""
|
||||
|
||||
return {
|
||||
"content": content,
|
||||
"residents": residents_data,
|
||||
"has_results": True,
|
||||
}
|
||||
|
||||
|
||||
async def on_filtered_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_filter"] = True
|
||||
await dialog_manager.switch_to(AdminMenuSG.resident_info)
|
||||
|
||||
|
||||
filter_select_window = Window(
|
||||
Const("<blockquote>🔽 <b>Фильтрация резидентов</b></blockquote>\n\n<blockquote>Выберите критерий фильтрации для отображения нужных резидентов.</blockquote>"),
|
||||
Group(
|
||||
Select(
|
||||
Format("{item[1]}"),
|
||||
id="filter_select",
|
||||
item_id_getter=lambda x: x[0],
|
||||
items="filter_options",
|
||||
on_click=on_filter_selected,
|
||||
),
|
||||
width=1,
|
||||
),
|
||||
SwitchTo(
|
||||
Const("◀️ Отмена"),
|
||||
id="cancel_filter",
|
||||
state=AdminMenuSG.residents,
|
||||
),
|
||||
state=AdminMenuSG.residents_filter_select,
|
||||
getter=get_filter_options_data,
|
||||
)
|
||||
|
||||
filter_hours_input_window = Window(
|
||||
Const("<blockquote>🔽 <b>Фильтрация по часам</b></blockquote>\n\n<blockquote>Введите количество часов для фильтрации.</blockquote>"),
|
||||
MessageInput(on_filter_hours_input),
|
||||
SwitchTo(
|
||||
Const("◀️ Назад"),
|
||||
id="back_to_filter_select",
|
||||
state=AdminMenuSG.residents_filter_select,
|
||||
),
|
||||
state=AdminMenuSG.residents_filter_hours_input,
|
||||
)
|
||||
|
||||
filtered_results_window = Window(
|
||||
Format("{content}"),
|
||||
ScrollingGroup(
|
||||
Select(
|
||||
Format("{item[0]}"),
|
||||
id="filtered_residents_select",
|
||||
item_id_getter=lambda x: x[1],
|
||||
items="residents",
|
||||
on_click=on_filtered_resident_selected,
|
||||
),
|
||||
id="filtered_residents_scroll",
|
||||
width=1,
|
||||
height=7,
|
||||
when="has_results",
|
||||
),
|
||||
SwitchTo(
|
||||
Const("🔽 Новый фильтр"),
|
||||
id="new_filter",
|
||||
state=AdminMenuSG.residents_filter_select,
|
||||
),
|
||||
SwitchTo(
|
||||
Const("◀️ К списку резидентов"),
|
||||
id="back_to_residents_from_filter",
|
||||
state=AdminMenuSG.residents,
|
||||
),
|
||||
state=AdminMenuSG.residents_filtered_results,
|
||||
getter=get_filtered_results_data,
|
||||
)
|
||||
@@ -72,12 +72,12 @@ async def get_resident_info_data(
|
||||
resident_id = dialog_manager.dialog_data.get("selected_resident_id")
|
||||
|
||||
if not resident_id:
|
||||
return {"info_content": "Ошибка: резидент не выбран", "is_busy": False, "from_search": False}
|
||||
return {"info_content": "Ошибка: резидент не выбран", "is_busy": False, "from_search": False, "from_filter": False}
|
||||
|
||||
resident = await residents_repository.get_resident_by_id(resident_id)
|
||||
|
||||
if not resident:
|
||||
return {"info_content": "Ошибка: резидент не найден", "is_busy": False, "from_search": False}
|
||||
return {"info_content": "Ошибка: резидент не найден", "is_busy": False, "from_search": False, "from_filter": False}
|
||||
|
||||
room = await rooms_repository.get_room_by_id(resident.room)
|
||||
room_number = room.number if room else "???"
|
||||
@@ -111,11 +111,13 @@ async def get_resident_info_data(
|
||||
"""
|
||||
|
||||
from_search = dialog_manager.dialog_data.get("from_search", False)
|
||||
from_filter = dialog_manager.dialog_data.get("from_filter", False)
|
||||
|
||||
return {
|
||||
"info_content": info_content,
|
||||
"is_busy": resident.is_busy,
|
||||
"from_search": from_search,
|
||||
"from_filter": from_filter,
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +129,7 @@ async def on_resident_selected(
|
||||
):
|
||||
dialog_manager.dialog_data["selected_resident_id"] = int(item_id)
|
||||
dialog_manager.dialog_data["from_search"] = False
|
||||
dialog_manager.dialog_data["from_filter"] = False
|
||||
await dialog_manager.switch_to(AdminMenuSG.resident_info)
|
||||
|
||||
|
||||
@@ -143,7 +146,7 @@ async def on_filter_residents(
|
||||
button: Button,
|
||||
dialog_manager: DialogManager,
|
||||
):
|
||||
await callback.answer("⚠️ Функционал в разработке", show_alert=True)
|
||||
await dialog_manager.switch_to(AdminMenuSG.residents_filter_select)
|
||||
|
||||
|
||||
async def on_search_residents(
|
||||
@@ -363,6 +366,7 @@ async def on_search_resident_selected(
|
||||
):
|
||||
dialog_manager.dialog_data["selected_resident_id"] = int(item_id)
|
||||
dialog_manager.dialog_data["from_search"] = True
|
||||
dialog_manager.dialog_data["from_filter"] = False
|
||||
await dialog_manager.switch_to(AdminMenuSG.resident_info)
|
||||
|
||||
|
||||
@@ -427,16 +431,22 @@ resident_info_window = Window(
|
||||
when="is_busy",
|
||||
),
|
||||
SwitchTo(
|
||||
Const("◀️ Назад к результатам"),
|
||||
Const("◀️ Назад к результатам поиска"),
|
||||
id="back_to_search_results",
|
||||
state=AdminMenuSG.residents_search_results,
|
||||
when="from_search",
|
||||
),
|
||||
SwitchTo(
|
||||
Const("◀️ Назад к результатам фильтра"),
|
||||
id="back_to_filter_results",
|
||||
state=AdminMenuSG.residents_filtered_results,
|
||||
when="from_filter",
|
||||
),
|
||||
SwitchTo(
|
||||
Const("◀️ Назад к списку"),
|
||||
id="back_to_residents_list",
|
||||
state=AdminMenuSG.residents,
|
||||
when=~F["from_search"],
|
||||
when=~F["from_search"] & ~F["from_filter"],
|
||||
),
|
||||
state=AdminMenuSG.resident_info,
|
||||
getter=get_resident_info_data,
|
||||
|
||||
@@ -12,6 +12,9 @@ class AdminMenuSG(StatesGroup):
|
||||
residents = State()
|
||||
residents_search_input = State()
|
||||
residents_search_results = State()
|
||||
residents_filter_select = State()
|
||||
residents_filter_hours_input = State()
|
||||
residents_filtered_results = State()
|
||||
resident_info = State()
|
||||
resident_logout_confirm = State()
|
||||
add_hours_select = State()
|
||||
|
||||
Reference in New Issue
Block a user