new shems

This commit is contained in:
2026-04-01 14:18:52 +05:00
parent 4e9b89fbe5
commit 22bbc3a0a6
15 changed files with 1793 additions and 133 deletions

View File

@@ -1,6 +1,8 @@
import base64
import flet as ft
import designer as ds
import api_client
from radar_chart import RadarChart
class PollPage(ft.Column):
@@ -157,27 +159,80 @@ class PollPage(ft.Column):
self._error_text.update()
else:
url_key = self._page.session.store.get("url_key") or ""
# Заменяем контент на сообщение об успехе
# Показываем лоадер пока грузим радар
self.controls = [
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[ft.ProgressRing(width=40, height=40, color=ds.clolors.laer1)],
)
]
self.update()
radar = await api_client.get_radar_result(response_id)
success_controls: list[ft.Control] = [
ft.Icon(ft.Icons.CHECK_CIRCLE_OUTLINE, size=48, color=ds.clolors.laer1),
ds.CastomText(text="Тест пройден!", size=20, weight=ft.FontWeight.BOLD),
]
if radar and radar.get("items"):
items = sorted(
radar["items"],
key=lambda x: (
x.get("dimension_position") is None,
x.get("dimension_position", 0),
),
)
actual_max = max((it["value"] for it in items), default=1.0)
max_val = max(actual_max, 14.0)
success_controls.append(
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[RadarChart(items, max_val)],
)
)
async def _download(_evt, _rid=response_id):
svg_bytes = await api_client.get_radar_svg_bytes(_rid)
if svg_bytes:
b64 = base64.b64encode(svg_bytes).decode()
uri = f"data:image/svg+xml;base64,{b64}"
self._page.launch_url(uri, web_window_name="_blank")
success_controls.append(
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[
ft.ElevatedButton(
text="Сохранить диаграмму",
icon=ft.Icons.DOWNLOAD,
on_click=_download,
style=ft.ButtonStyle(
color=ds.clolors.ferst,
bgcolor=ds.clolors.laer2,
),
)
],
)
)
success_controls.append(
ds.CastomButton(
text="Вернуться к тестам",
on_click=lambda _: self._page.go(f"/take_test/{url_key}"),
)
)
self.controls = [
ft.Container(
alignment=ft.Alignment(0, 0),
padding=40,
padding=20,
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}"),
),
],
controls=success_controls,
),
)
]

View File

@@ -1,6 +1,8 @@
import base64
import flet as ft
import designer as ds
import api_client
from radar_chart import RadarChart
class ResponsePage(ft.Column):
@@ -14,10 +16,7 @@ class ResponsePage(ft.Column):
horizontal_alignment=ft.CrossAxisAlignment.STRETCH,
spacing=8,
controls=[
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[self._loading],
)
ft.Row(alignment=ft.MainAxisAlignment.CENTER, controls=[self._loading])
],
)
@@ -34,84 +33,106 @@ class ResponsePage(ft.Column):
self.update()
return
self._render(response, poll)
radar = await api_client.get_radar_result(self._response_id)
self._render(response, poll, radar)
self.update()
def _render(self, response: dict, poll: dict):
# Строим индексы для быстрого поиска
def _render(self, response: dict, poll: dict, radar: dict | None):
questions_map = {q["id"]: q for q in poll.get("questions", [])}
choices_map = {
c["id"]: c["text"]
for q in poll.get("questions", [])
for c in q.get("choices", [])
}
submitted_at = response["submitted_at"][:19].replace("T", " ")
answer_cards = []
controls: list[ft.Control] = [
ft.Container(
padding=ft.padding.only(bottom=8),
content=ft.Column(spacing=4, controls=[
ds.CastomText(text=poll.get("title", ""), size=20, weight=ft.FontWeight.BOLD),
ds.CastomText(text=f"Пройден: {submitted_at}", size=12),
]),
)
]
# ── Паутинная диаграмма ──────────────────────────────────────────────
if radar and radar.get("items"):
items = sorted(
radar["items"],
key=lambda x: (x.get("dimension_position") is None, x.get("dimension_position", 0)),
)
actual_max = max((it["value"] for it in items), default=1.0)
max_val = max(actual_max, 14.0)
async def _download(_evt, _rid=self._response_id):
svg_bytes = await api_client.get_radar_svg_bytes(_rid)
if svg_bytes:
b64 = base64.b64encode(svg_bytes).decode()
uri = f"data:image/svg+xml;base64,{b64}"
self._page.launch_url(uri, web_window_name="_blank")
controls.append(ft.Container(
border_radius=16,
padding=12,
bgcolor=ds.clolors.laer3,
content=ft.Column(
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=10,
controls=[
ds.CastomText(text="Результат", size=16, weight=ft.FontWeight.BOLD),
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[RadarChart(items, max_val)],
),
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[
ft.ElevatedButton(
text="Сохранить диаграмму",
icon=ft.Icons.DOWNLOAD,
on_click=_download,
style=ft.ButtonStyle(
color=ds.clolors.ferst,
bgcolor=ds.clolors.laer2,
),
)
],
),
],
),
))
# ── Ответы ───────────────────────────────────────────────────────────
answer_cards: list[ft.Control] = []
for answer in response.get("answers", []):
q = questions_map.get(answer["question_id"])
if not q:
continue
selected_text = choices_map.get(answer.get("choice_id") or "") or answer.get("text") or ""
# Варианты с подсветкой выбранного
choice_rows = []
for c in q.get("choices", []):
is_selected = c["id"] == answer.get("choice_id")
choice_rows.append(
ft.Container(
border_radius=8,
padding=ft.padding.symmetric(horizontal=12, vertical=6),
bgcolor=ds.clolors.laer1 if is_selected else ds.clolors.laer3,
content=ft.Row(
spacing=8,
controls=[
ft.Icon(
ft.Icons.CHECK_CIRCLE if is_selected else ft.Icons.RADIO_BUTTON_UNCHECKED,
color=ds.clolors.ferst,
size=16,
),
ds.CastomText(text=c["text"], size=13),
],
choice_rows.append(ft.Container(
border_radius=8,
padding=ft.padding.symmetric(horizontal=12, vertical=6),
bgcolor=ds.clolors.laer1 if is_selected else ds.clolors.laer3,
content=ft.Row(spacing=8, controls=[
ft.Icon(
ft.Icons.CHECK_CIRCLE if is_selected else ft.Icons.RADIO_BUTTON_UNCHECKED,
color=ds.clolors.ferst, size=16,
),
)
)
ds.CastomText(text=c["text"], size=13),
]),
))
answer_cards.append(
ft.Container(
border_radius=12,
padding=16,
bgcolor=ds.clolors.laer2,
content=ft.Column(
spacing=8,
controls=[
ds.CastomText(
text=q.get("text", ""),
size=14,
weight=ft.FontWeight.BOLD,
),
*choice_rows,
],
),
)
)
answer_cards.append(ft.Container(
border_radius=12,
padding=16,
bgcolor=ds.clolors.laer2,
content=ft.Column(spacing=8, controls=[
ds.CastomText(text=q.get("text", ""), size=14, weight=ft.FontWeight.BOLD),
*choice_rows,
]),
))
self.controls = [
ft.Container(
padding=ft.padding.only(bottom=8),
content=ft.Column(
spacing=4,
controls=[
ds.CastomText(
text=poll.get("title", ""),
size=20,
weight=ft.FontWeight.BOLD,
),
ds.CastomText(text=f"Пройден: {submitted_at}", size=12),
],
),
),
*answer_cards,
]
if answer_cards:
controls.append(ds.CastomText(text="Ответы", size=16, weight=ft.FontWeight.BOLD))
controls.extend(answer_cards)
self.controls = controls