feat: requests detail view - stage 2: backend разработка

Этап 2 разработки включает:

✅ Создан RequestDetailView класс в views_front.py:
  - Наследуется от LoginRequiredMixin, TemplateView
  - Загружает данные о заявлении через API (/api/v1/requests/{pk}/)
  - Загружает комментарии к заявлению
  - Проверяет права доступа (обрабатывает 404, 403)
  - Форматирует даты для отображения

✅ Обновлены URLs (urls_front.py):
  - Добавлен маршрут: path('<int:pk>/', RequestDetailView.as_view(), name='request_detail')
  - Импортирован RequestDetailView

✅ Обновлен шаблон request_detail.html:
  - Раскомментированы комментарии (были закрыты)
  - Добавлена обработка ошибок (404, 403)
  - Оформлено отображение заявления и комментариев
  - Включен функционал добавления комментариев

� URLs в notification_signals.py уже правильные (проверено)

Готово для следующего этапа 3: Frontend разработка
This commit is contained in:
Игорь Надеин 2025-12-26 15:59:16 +03:00
parent 92b3b0725a
commit f19862ec6b
3 changed files with 99 additions and 2 deletions

View File

@ -2,6 +2,7 @@
from django.urls import path
from .views_front import (
RequestsView,
RequestDetailView,
request_comments,
request_comment_add,
)
@ -10,6 +11,7 @@ app_name = "requests"
urlpatterns = [
path("", RequestsView.as_view(), name="request_list"),
path("<int:pk>/", RequestDetailView.as_view(), name="request_detail"),
path("comments/<int:pk>/", request_comments, name="request_comments"),
path(
"comments/<int:pk>/add/",

View File

@ -274,6 +274,81 @@ class RequestsView(LoginRequiredMixin, TemplateView):
return ctx
class RequestDetailView(LoginRequiredMixin, TemplateView):
"""
Детальный просмотр заявления.
Загружает одно заявление и его комментарии через API.
Может быть использовано как для отдельной страницы, так и для модального окна.
GET /requests/{pk}/:
- Загружает заявление через GET /api/v1/requests/{pk}/
- Загружает комментарии через GET /api/v1/requests/{pk}/comments/
- Проверяет права доступа (делает ошибку если нет прав)
Контекст:
- request_obj: dict с данными заявления
- comments: list[dict] с комментариями
- can_process: bool - может ли пользователь обрабатывать заявку
- error: str - описание ошибки (если она была)
- error_code: int - HTTP код ошибки
"""
template_name = "requests_app/request_detail.html"
def get_context_data(self, pk: int, **kwargs: Any) -> Dict[str, Any]:
"""
Загружает данные заявления и комментарии.
Args:
pk: ID заявления
Returns:
Dict с контекстом для шаблона
"""
ctx = super().get_context_data(**kwargs)
request = self.request
api = get_api_client(request)
# Загружаем основные данные заявления
ok, data, status = _api_unpack(api.get(f"v1/requests/{pk}/"))
if not ok:
# Обработка ошибок (404, 403 и т.д.)
error_msg = data.get("detail", f"HTTP {status}")
if isinstance(error_msg, list):
error_msg = "; ".join(str(e) for e in error_msg)
ctx.update({
"request_obj": None,
"comments": [],
"can_process": _user_can_process_requests(request.user),
"error": error_msg,
"error_code": status,
})
return ctx
request_data = data
# Загружаем комментарии
comments = []
ok_c, data_c, st_c = _api_unpack(api.get(f"v1/requests/{pk}/comments/"))
if ok_c:
results_c, _, _, _ = _parse_page_payload(data_c)
comments = _format_datetime_fields(
results_c,
fields=("created_at", "updated_at")
)
ctx.update({
"request_obj": _format_datetime_fields([request_data], fields=("created_at", "updated_at", "decided_at"))[0],
"comments": comments,
"can_process": _user_can_process_requests(request.user),
})
return ctx
def request_comments(request: HttpRequest, pk: int) -> JsonResponse:
"""Прокси: список комментариев (JSON) для заявки.
Требует авторизации (используем ту же обёртку клиента, что и основная вью).

View File

@ -8,7 +8,22 @@
<div class="row gx-0">
<div class="col-12">
{# — Шапка — #}
{% if error %}
{# — Ошибка при загрузке — #}
<div class="alert alert-danger mb-3" role="alert">
<i class="bi-exclamation-circle"></i>
{% if error_code == 404 %}
<strong>Заявление не найдено.</strong> Возможно, оно было удалено.
{% elif error_code == 403 %}
<strong>Доступ запрещен.</strong> Вы не можете просмотреть это заявление.
{% else %}
<strong>Ошибка при загрузке.</strong> {{ error }}
{% endif %}
</div>
<a href="{% url 'requests:request_list' %}" class="btn btn-secondary">
<i class="bi-arrow-left"></i> К списку заявлений
</a>
{% elif request_obj %}
<div class="section-header">
<i class="bi-file-earmark-text fs-2 text-primary"></i>
<h2 class="title mb-0">Детали заявления</h2>
@ -150,7 +165,12 @@
</div>
</form>
</div>
</article> -->
</article>
{% else %}
<div class="alert alert-info mb-3" role="alert">
Загрузка...
</div>
{% endif %}
</div>
</div>