133 lines
5.7 KiB
Python
133 lines
5.7 KiB
Python
import flet as ft
|
|
import base64
|
|
import designer as ds
|
|
import api_client
|
|
|
|
|
|
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=ds.s(40), height=ds.s(40), color=ds.colors.secondary_light)
|
|
|
|
super().__init__(
|
|
alignment=ft.MainAxisAlignment.START,
|
|
horizontal_alignment=ft.CrossAxisAlignment.STRETCH,
|
|
spacing=ds.s(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)
|
|
svg_bytes = await api_client.get_radar_svg_bytes(self._response_id) if radar and radar.get("image_url") else None
|
|
self._render(response, poll, radar, svg_bytes)
|
|
self.update()
|
|
|
|
def _render(self, response: dict, poll: dict, radar: dict | None, svg_bytes: bytes | None = 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=ds.s(8)),
|
|
content=ft.Column(spacing=ds.s(4), controls=[
|
|
ds.CastomText(text=poll.get("title", ""), size=20, weight=ft.FontWeight.BOLD),
|
|
ds.CastomText(text=f"Пройден: {submitted_at}", size=12),
|
|
]),
|
|
)
|
|
]
|
|
|
|
# ── Паутинная диаграмма ──────────────────────────────────────────────
|
|
if svg_bytes and radar and radar.get("image_url"):
|
|
b64 = base64.b64encode(svg_bytes).decode()
|
|
data_uri = f"data:image/svg+xml;base64,{b64}"
|
|
download_url = api_client.build_radar_download_url(self._page.url, self._response_id)
|
|
|
|
async def _download(_evt, _url=download_url):
|
|
await self._page.launch_url(_url)
|
|
|
|
controls.append(ft.Container(
|
|
border_radius=ds.s(16),
|
|
padding=ds.s(12),
|
|
bgcolor=ds.colors.surface_alt,
|
|
content=ft.Column(
|
|
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
spacing=ds.s(10),
|
|
controls=[
|
|
ds.CastomText(text="Результат", size=16, weight=ft.FontWeight.BOLD),
|
|
ft.Container(
|
|
expand=True,
|
|
content=ft.Image(
|
|
src=data_uri,
|
|
expand=True,
|
|
height=ds.s(380),
|
|
fit=ft.BoxFit.CONTAIN,
|
|
),
|
|
),
|
|
ft.Row(
|
|
alignment=ft.MainAxisAlignment.CENTER,
|
|
controls=[
|
|
ds.CastomIconButton(
|
|
text="Сохранить диаграмму",
|
|
icon=ft.Icons.DOWNLOAD,
|
|
on_click=_download,
|
|
)
|
|
],
|
|
),
|
|
],
|
|
),
|
|
))
|
|
|
|
# ── Ответы ───────────────────────────────────────────────────────────
|
|
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=ds.s(8),
|
|
padding=ft.padding.symmetric(horizontal=ds.s(12), vertical=ds.s(6)),
|
|
bgcolor=ds.colors.primary_light if is_selected else ds.colors.surface_alt,
|
|
content=ft.Row(spacing=ds.s(8), controls=[
|
|
ft.Icon(
|
|
ft.Icons.CHECK_CIRCLE if is_selected else ft.Icons.RADIO_BUTTON_UNCHECKED,
|
|
color=ds.colors.primary, size=ds.s(16),
|
|
),
|
|
ft.Container(expand=True, content=ds.CastomText(text=c["text"], size=13)),
|
|
]),
|
|
))
|
|
|
|
answer_cards.append(ft.Container(
|
|
border_radius=ds.s(12),
|
|
padding=ds.s(16),
|
|
bgcolor=ds.colors.surface,
|
|
content=ft.Column(spacing=ds.s(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
|