Files
api-copp/web/views/content_users/poll_page.py
2026-03-31 18:10:12 +05:00

185 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import flet as ft
import designer as ds
import api_client
class PollPage(ft.Column):
def __init__(self, page: ft.Page, poll_id: str):
self._page = page
self._poll_id = poll_id
self._answers: dict[str, str] = {} # question_id -> choice_id
self._error_text = ds.CastomText(text="", size=13, color="#FF6B6B")
self._submit_btn = ds.CastomButton(
text="Отправить ответы",
on_click=self._submit,
)
self._submit_btn.visible = False
self._loading = ft.ProgressRing(width=40, height=40, color=ds.clolors.laer1)
super().__init__(
alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.STRETCH,
spacing=10,
controls=[
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[self._loading],
)
],
)
async def load(self):
poll = await api_client.get_poll(self._poll_id)
if poll:
self._render_poll(poll)
else:
self.controls = [ds.CastomText(text="Тест не найден", size=16, color="#FF6B6B")]
self.update()
def _render_poll(self, poll: dict):
self._poll = poll
question_cards = []
for q in poll.get("questions", []):
choices = q.get("choices", [])
q_type = q.get("type", "single")
if q_type == "single":
radio_controls = [
ft.Radio(
value=c["id"],
label=c["text"],
fill_color=ds.clolors.laer1,
label_style=ft.TextStyle(color=ds.clolors.ferst, size=14),
)
for c in choices
]
input_widget = ft.RadioGroup(
content=ft.Column(controls=radio_controls, spacing=4),
on_change=lambda e, qid=q["id"]: self._on_single_answer(qid, e.control.value),
)
else:
# multiple / text — показываем как single если нет multiple в API
radio_controls = [
ft.Radio(
value=c["id"],
label=c["text"],
fill_color=ds.clolors.laer1,
label_style=ft.TextStyle(color=ds.clolors.ferst, size=14),
)
for c in choices
]
input_widget = ft.RadioGroup(
content=ft.Column(controls=radio_controls, spacing=4),
on_change=lambda e, qid=q["id"]: self._on_single_answer(qid, e.control.value),
)
card = ft.Container(
border_radius=12,
padding=16,
margin=ft.margin.only(bottom=8),
bgcolor=ds.clolors.laer2,
content=ft.Column(
spacing=10,
controls=[
ds.CastomText(
text=q.get("text", ""),
size=15,
weight=ft.FontWeight.BOLD,
),
input_widget,
],
),
)
question_cards.append(card)
self.controls = [
ft.Container(
padding=ft.padding.only(bottom=4),
content=ft.Column(
spacing=4,
controls=[
ds.CastomText(
text=poll.get("title", ""),
size=20,
weight=ft.FontWeight.BOLD,
),
ds.CastomText(
text=poll.get("description") or "",
size=13,
),
],
),
),
*question_cards,
self._error_text,
ft.Row(
alignment=ft.MainAxisAlignment.END,
controls=[self._submit_btn],
),
]
self._submit_btn.visible = True
def _on_single_answer(self, question_id: str, choice_id: str):
self._answers[question_id] = choice_id
async def _submit(self, e):
poll = getattr(self, "_poll", None)
if not poll:
return
questions = poll.get("questions", [])
unanswered = [q for q in questions if q["id"] not in self._answers]
if unanswered:
self._error_text.value = f"Ответьте на все вопросы ({len(unanswered)} осталось)"
self._error_text.update()
return
self._error_text.value = ""
self._submit_btn.disabled = True
self._submit_btn.update()
answers = [
{"question_id": qid, "choice_id": cid, "text": None}
for qid, cid in self._answers.items()
]
user_id = self._page.session.store.get("user_id")
group_id = self._page.session.store.get("group_id") or None
org_id = self._page.session.store.get("org_id") or None
response_id, error = await api_client.submit_response(
self._poll_id, answers, user_id, group_id, org_id
)
if error:
self._error_text.value = error
self._submit_btn.disabled = False
self._submit_btn.update()
self._error_text.update()
else:
url_key = self._page.session.store.get("url_key") or ""
# Заменяем контент на сообщение об успехе
self.controls = [
ft.Container(
alignment=ft.Alignment(0, 0),
padding=40,
content=ft.Column(
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=16,
controls=[
ft.Icon(ft.Icons.CHECK_CIRCLE_OUTLINE, size=64, color=ds.clolors.laer1),
ds.CastomText(
text="Ответы отправлены!",
size=20,
weight=ft.FontWeight.BOLD,
),
ds.CastomButton(
text="Вернуться к тестам",
on_click=lambda _: self._page.go(f"/take_test/{url_key}"),
),
],
),
)
]
self.update()