139 lines
5.8 KiB
Python
139 lines
5.8 KiB
Python
import base64
|
|
import flet as ft
|
|
import designer as ds
|
|
import api_client
|
|
from radar_chart import RadarChart
|
|
|
|
|
|
class ResponsePage(ft.Column):
|
|
def __init__(self, page: ft.Page, response_id: str):
|
|
self._page = page
|
|
self._response_id = response_id
|
|
self._loading = ft.ProgressRing(width=40, height=40, color=ds.clolors.laer1)
|
|
|
|
super().__init__(
|
|
alignment=ft.MainAxisAlignment.START,
|
|
horizontal_alignment=ft.CrossAxisAlignment.STRETCH,
|
|
spacing=8,
|
|
controls=[
|
|
ft.Row(alignment=ft.MainAxisAlignment.CENTER, controls=[self._loading])
|
|
],
|
|
)
|
|
|
|
async def load(self):
|
|
response = await api_client.get_response(self._response_id)
|
|
if not response:
|
|
self.controls = [ds.CastomText(text="Результат не найден", size=14, color="#FF6B6B")]
|
|
self.update()
|
|
return
|
|
|
|
poll = await api_client.get_poll(response["poll_id"])
|
|
if not poll:
|
|
self.controls = [ds.CastomText(text="Тест не найден", size=14, color="#FF6B6B")]
|
|
self.update()
|
|
return
|
|
|
|
radar = await api_client.get_radar_result(self._response_id)
|
|
self._render(response, poll, radar)
|
|
self.update()
|
|
|
|
def _render(self, response: dict, poll: dict, radar: dict | None):
|
|
questions_map = {q["id"]: q for q in poll.get("questions", [])}
|
|
submitted_at = response["submitted_at"][:19].replace("T", " ")
|
|
|
|
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
|
|
|
|
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),
|
|
]),
|
|
))
|
|
|
|
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,
|
|
]),
|
|
))
|
|
|
|
if answer_cards:
|
|
controls.append(ds.CastomText(text="Ответы", size=16, weight=ft.FontWeight.BOLD))
|
|
controls.extend(answer_cards)
|
|
|
|
self.controls = controls
|