fix org
This commit is contained in:
158
web/designer.py
158
web/designer.py
@@ -170,6 +170,164 @@ class CastomDropdown(ft.Dropdown):
|
||||
self.on_select = on_change
|
||||
|
||||
|
||||
class SearchableDropdown(ft.Container):
|
||||
"""Выпадающий список с поисковой строкой — замена CastomDropdown для больших наборов данных."""
|
||||
|
||||
def __init__(self, label: str = "", hint_text: str = "", options=None, on_select=None):
|
||||
self._label_str = label
|
||||
self._hint_str = hint_text
|
||||
self._options: list = options or []
|
||||
self.on_select = on_select
|
||||
self._value = None
|
||||
|
||||
self._value_text = ft.Text(
|
||||
hint_text,
|
||||
color=colors.border,
|
||||
size=s(14),
|
||||
italic=True,
|
||||
expand=True,
|
||||
no_wrap=True,
|
||||
overflow=ft.TextOverflow.ELLIPSIS,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
content=ft.Column(
|
||||
spacing=s(2),
|
||||
tight=True,
|
||||
controls=[
|
||||
ft.Text(
|
||||
label,
|
||||
color=colors.text_secondary,
|
||||
size=s(13),
|
||||
weight=ft.FontWeight.W_500,
|
||||
),
|
||||
ft.Row(
|
||||
controls=[
|
||||
self._value_text,
|
||||
ft.Icon(ft.Icons.ARROW_DROP_DOWN, color=colors.text_secondary, size=s(20)),
|
||||
],
|
||||
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
),
|
||||
],
|
||||
),
|
||||
bgcolor=colors.surface,
|
||||
border=ft.border.all(1, colors.border),
|
||||
border_radius=s(10),
|
||||
padding=ft.padding.symmetric(horizontal=s(14), vertical=s(12)),
|
||||
on_click=self._open_dialog,
|
||||
ink=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, val):
|
||||
self._value = val
|
||||
if val is None:
|
||||
self._value_text.value = self._hint_str
|
||||
self._value_text.color = colors.border
|
||||
self._value_text.italic = True
|
||||
else:
|
||||
for opt in self._options:
|
||||
if opt.key == val:
|
||||
self._value_text.value = opt.text
|
||||
self._value_text.color = colors.text_primary
|
||||
self._value_text.italic = False
|
||||
break
|
||||
if self.page:
|
||||
self.update()
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
return self._options
|
||||
|
||||
@options.setter
|
||||
def options(self, opts):
|
||||
self._options = opts or []
|
||||
|
||||
@property
|
||||
def hint_text(self):
|
||||
return self._hint_str
|
||||
|
||||
@hint_text.setter
|
||||
def hint_text(self, val):
|
||||
self._hint_str = val
|
||||
if self._value is None:
|
||||
self._value_text.value = val
|
||||
if self.page:
|
||||
self.update()
|
||||
|
||||
def _open_dialog(self, e):
|
||||
search_field = CastomTextField_input(
|
||||
label="Поиск",
|
||||
hint_text="Введите для поиска...",
|
||||
prefix_icon=ft.Icons.SEARCH,
|
||||
autofocus=True,
|
||||
)
|
||||
items_list = ft.ListView(spacing=0, expand=True)
|
||||
|
||||
def _build_items(query: str = ""):
|
||||
q = query.lower()
|
||||
items_list.controls = [
|
||||
ft.ListTile(
|
||||
title=ft.Text(opt.text, color=colors.text_primary, size=s(14)),
|
||||
hover_color=colors.primary_light,
|
||||
on_click=lambda ev, o=opt: _select(o),
|
||||
)
|
||||
for opt in self._options
|
||||
if not q or q in opt.text.lower()
|
||||
]
|
||||
|
||||
def _on_search(ev):
|
||||
_build_items(search_field.value or "")
|
||||
items_list.update()
|
||||
|
||||
def _select(option):
|
||||
self._value = option.key
|
||||
self._value_text.value = option.text
|
||||
self._value_text.color = colors.text_primary
|
||||
self._value_text.italic = False
|
||||
dlg.open = False
|
||||
self.page.update()
|
||||
self.update()
|
||||
if self.on_select:
|
||||
self.on_select(type("_E", (), {"control": self})())
|
||||
|
||||
search_field.on_change = _on_search
|
||||
_build_items()
|
||||
|
||||
dlg = ft.AlertDialog(
|
||||
title=ft.Text(
|
||||
self._label_str,
|
||||
color=colors.text_primary,
|
||||
size=s(16),
|
||||
weight=ft.FontWeight.W_600,
|
||||
),
|
||||
content=ft.Container(
|
||||
content=ft.Column(
|
||||
controls=[
|
||||
search_field,
|
||||
ft.Divider(color=colors.border),
|
||||
items_list,
|
||||
],
|
||||
spacing=s(8),
|
||||
tight=True,
|
||||
),
|
||||
height=s(350),
|
||||
width=s(400),
|
||||
),
|
||||
bgcolor=colors.surface,
|
||||
shape=ft.RoundedRectangleBorder(radius=s(12)),
|
||||
)
|
||||
|
||||
self.page.overlay.append(dlg)
|
||||
dlg.open = True
|
||||
self.page.update()
|
||||
|
||||
|
||||
class CastomSwitch(ft.Switch):
|
||||
def __init__(self, label, on_change):
|
||||
super().__init__(
|
||||
|
||||
@@ -21,19 +21,19 @@ class ProfilePage(ft.Column):
|
||||
prefix_icon=ft.Icons.PERSON_OUTLINE,
|
||||
)
|
||||
|
||||
self._org_dropdown = ds.CastomDropdown(
|
||||
self._org_dropdown = ds.SearchableDropdown(
|
||||
label="Организация",
|
||||
hint_text="Загрузка...",
|
||||
)
|
||||
self._org_dropdown.on_select = self._on_org_change
|
||||
|
||||
self._group_dropdown = ds.CastomDropdown(
|
||||
self._group_dropdown = ds.SearchableDropdown(
|
||||
label="Группа",
|
||||
hint_text="Загрузка...",
|
||||
)
|
||||
|
||||
# ── Выбор темы ─────────────────────────────────────────────────
|
||||
self._theme_dropdown = ds.CastomDropdown(
|
||||
self._theme_dropdown = ds.SearchableDropdown(
|
||||
label="Тема интерфейса",
|
||||
hint_text="Выберите тему...",
|
||||
options=[
|
||||
|
||||
@@ -35,13 +35,13 @@ class RegView(ft.View):
|
||||
can_reveal_password=True,
|
||||
)
|
||||
|
||||
self._org_dropdown = ds.CastomDropdown(
|
||||
self._org_dropdown = ds.SearchableDropdown(
|
||||
label="Организация",
|
||||
hint_text="Загрузка...",
|
||||
)
|
||||
self._org_dropdown.on_select = self._on_org_change
|
||||
|
||||
self._group_dropdown = ds.CastomDropdown(
|
||||
self._group_dropdown = ds.SearchableDropdown(
|
||||
label="Группа",
|
||||
hint_text="Загрузка...",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user