rename users
This commit is contained in:
184
web/views/content_users/poll_page.py
Normal file
184
web/views/content_users/poll_page.py
Normal file
@@ -0,0 +1,184 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user