fix install diogram

This commit is contained in:
2026-04-02 12:00:11 +05:00
parent 22bbc3a0a6
commit 8a189e310b
23 changed files with 1212 additions and 189 deletions

View File

@@ -9,16 +9,19 @@ class MainPageUser(ft.Column):
super().__init__(
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=self.spacing_groop,
controls=[
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
spacing=self.spacing_groop,
run_spacing=self.spacing_groop,
wrap=True,
controls=[
ft.Container(
border_radius=self.border_radius,
height=200,
width=200,
height=160,
width=160,
alignment=ft.Alignment(0.0, 0.0),
content=ft.Column(
alignment=ft.MainAxisAlignment.CENTER,
@@ -28,8 +31,8 @@ class MainPageUser(ft.Column):
controls=[
ft.Image(
src="icons/clipboard-question_16542596.svg",
width=120,
height=120,
width=100,
height=100,
)
]
),
@@ -47,8 +50,8 @@ class MainPageUser(ft.Column):
),
ft.Container(
border_radius=self.border_radius,
height=200,
width=200,
height=160,
width=160,
alignment=ft.Alignment(0.0, 0.0),
content=ft.Column(
alignment=ft.MainAxisAlignment.CENTER,
@@ -58,10 +61,10 @@ class MainPageUser(ft.Column):
controls=[
ft.Image(
src="icons/leaderboard-trophy_14227576.svg",
width=120,
height=120,
width=100,
height=100,
)
]
]
),
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,

View File

@@ -64,6 +64,7 @@ class MyTestsPage(ft.Column):
controls=[
ft.Column(
spacing=4,
expand=True,
controls=[
ds.CastomText(
text=title,

View File

@@ -1,8 +1,7 @@
import base64
import flet as ft
import base64
import designer as ds
import api_client
from radar_chart import RadarChart
class PollPage(ft.Column):
@@ -38,43 +37,64 @@ class PollPage(ft.Column):
self.controls = [ds.CastomText(text="Тест не найден", size=16, color="#FF6B6B")]
self.update()
def _build_choice_group(self, choices: list, qid: str) -> ft.Column:
"""Кастомные кнопки выбора с переносом текста вместо ft.Radio."""
containers: list[ft.Container] = []
def make_tile(choice_id: str, choice_text: str) -> ft.Container:
return ft.Container(
border_radius=8,
padding=ft.padding.symmetric(horizontal=12, vertical=10),
bgcolor=ds.clolors.laer3,
border=ft.border.all(2, ds.clolors.laer3),
content=ft.Row(
spacing=10,
vertical_alignment=ft.CrossAxisAlignment.CENTER,
controls=[
ft.Icon(
ft.Icons.RADIO_BUTTON_UNCHECKED,
color=ds.clolors.ferst,
size=20,
),
ft.Text(
value=choice_text,
color=ds.clolors.ferst,
size=14,
expand=True,
no_wrap=False,
),
],
),
data=choice_id,
)
def on_tile_click(e, _qid=qid, _containers=containers):
selected_id = e.control.data
self._answers[_qid] = selected_id
for tile in _containers:
is_selected = tile.data == selected_id
tile.bgcolor = ds.clolors.laer1 if is_selected else ds.clolors.laer3
tile.border = ft.border.all(2, ds.clolors.ferst if is_selected else ds.clolors.laer3)
row = tile.content
row.controls[0].name = ft.Icons.CHECK_CIRCLE if is_selected else ft.Icons.RADIO_BUTTON_UNCHECKED
tile.update()
for c in choices:
tile = make_tile(c["id"], c["text"])
tile.on_click = on_tile_click
tile.ink = True
containers.append(tile)
return ft.Column(controls=containers, spacing=6)
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),
)
input_widget = self._build_choice_group(choices, q["id"])
card = ft.Container(
border_radius=12,
@@ -122,9 +142,6 @@ class PollPage(ft.Column):
]
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:
@@ -170,49 +187,41 @@ class PollPage(ft.Column):
self.update()
radar = await api_client.get_radar_result(response_id)
svg_bytes = await api_client.get_radar_svg_bytes(response_id) if radar and radar.get("image_url") else None
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)
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, response_id)
success_controls.append(
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[RadarChart(items, max_val)],
ft.Container(
expand=True,
content=ft.Image(
src=data_uri,
expand=True,
height=380,
fit=ft.BoxFit.CONTAIN,
),
)
)
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")
async def _download(_evt, _url=download_url):
await self._page.launch_url(_url)
success_controls.append(
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[
ft.ElevatedButton(
ds.CastomIconButton(
text="Сохранить диаграмму",
icon=ft.Icons.DOWNLOAD,
on_click=_download,
style=ft.ButtonStyle(
color=ds.clolors.ferst,
bgcolor=ds.clolors.laer2,
),
)
],
)
@@ -228,6 +237,9 @@ class PollPage(ft.Column):
self.controls = [
ft.Container(
padding=20,
bgcolor=ds.clolors.laer3,
border_radius=16,
expand=True,
content=ft.Column(
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,

View File

@@ -1,8 +1,7 @@
import base64
import flet as ft
import base64
import designer as ds
import api_client
from radar_chart import RadarChart
class ResponsePage(ft.Column):
@@ -34,10 +33,11 @@ class ResponsePage(ft.Column):
return
radar = await api_client.get_radar_result(self._response_id)
self._render(response, poll, radar)
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):
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", " ")
@@ -52,20 +52,13 @@ class ResponsePage(ft.Column):
]
# ── Паутинная диаграмма ──────────────────────────────────────────────
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)
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, _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")
async def _download(_evt, _url=download_url):
await self._page.launch_url(_url)
controls.append(ft.Container(
border_radius=16,
@@ -76,21 +69,22 @@ class ResponsePage(ft.Column):
spacing=10,
controls=[
ds.CastomText(text="Результат", size=16, weight=ft.FontWeight.BOLD),
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[RadarChart(items, max_val)],
ft.Container(
expand=True,
content=ft.Image(
src=data_uri,
expand=True,
height=380,
fit=ft.BoxFit.CONTAIN,
),
),
ft.Row(
alignment=ft.MainAxisAlignment.CENTER,
controls=[
ft.ElevatedButton(
ds.CastomIconButton(
text="Сохранить диаграмму",
icon=ft.Icons.DOWNLOAD,
on_click=_download,
style=ft.ButtonStyle(
color=ds.clolors.ferst,
bgcolor=ds.clolors.laer2,
),
)
],
),
@@ -117,7 +111,7 @@ class ResponsePage(ft.Column):
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),
ft.Container(expand=True, content=ds.CastomText(text=c["text"], size=13)),
]),
))