backend/mobileApps/fletFormTest.py

322 lines
13 KiB
Python
Raw Permalink Normal View History

2025-03-23 21:24:08 +10:00
import flet as ft
from datetime import datetime
def main(page: ft.Page):
# Состояние формы
state = {
"current_step": 0,
"operators_name": "",
"factory": "",
"line": "",
"error_zone": "",
"problems": set(), # будем накапливать выбранные значения
"downtime_reasons": set(),
"custom_problem": "",
"custom_reason": "",
"fix_method": "",
"start_at": "",
"end_at": "",
# Зависимые опции:
"line_options": [],
"zone_options": [],
"problem_options": [],
"reason_options": [],
}
# Справочники (аналогичные примерам в React/Ionic)
factory_line_map = {
"Славда": ["ПЭТ", "19л", ""],
"Скит": ["Sipa", "Devin", "JR", "19 Литров", "5 Литров"]
}
line_zone_map = {
"Sipa": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
"Devin": ["Сериализация", "Упаковка", "Сборка палеты"],
"JR": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
"19 Литров": ["Валидация", "Тонкий клиент"],
"5 Литров": ["Валидация", "Тонкий клиент"],
"ПЭТ": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
"": ["Сериализация", "Упаковка", "Сборка палеты", "Закрытие палеты"],
"19л": ["Валидация", "Тонкий клиент"],
}
common_problems = {
"Славда": ["Не печатает код", "Камера не считывает код", "Сбой принтера"],
"Скит": ["Не печатает код", "Камера не считывает код", "Сбой принтера"],
}
common_downtime_reasons = {
"Славда": ["Сбой камеры", "Ошибка валидации", "Проблема с печатью"],
"Скит": ["Сбой камеры", "Ошибка валидации", "Проблема с печатью"],
}
# Элементы UI, которые будут обновляться
operators_name_field = ft.TextField(label="Имя оператора *", width=300)
factory_dropdown = ft.Dropdown(
label="Завод *",
options=[
ft.dropdown.Option("Славда"),
ft.dropdown.Option("Скит")
],
width=300
)
line_dropdown = ft.Dropdown(label="Линия *", width=300)
zone_dropdown = ft.Dropdown(label="Зона *", width=300)
fix_method_field = ft.TextField(label="Как решили проблему? *", width=300)
start_at_field = ft.TextField(label="Начало простоя (YYYY-MM-DD HH:MM) *", width=300)
end_at_field = ft.TextField(label="Окончание простоя (YYYY-MM-DD HH:MM) *", width=300)
custom_problem_field = ft.TextField(label="Своя проблема (необязательно)", width=300)
custom_reason_field = ft.TextField(label="Своя причина (необязательно)", width=300)
# Для выбора нескольких вариантов используем колонки с чекбоксами
problems_checkboxes = ft.Column()
reasons_checkboxes = ft.Column()
# Функция для показа уведомлений (SnackBar)
def show_snackbar(message, bgcolor):
page.snack_bar = ft.SnackBar(ft.Text(message), bgcolor=bgcolor)
page.snack_bar.open = True
page.update()
# Обновление зависимых списков при выборе завода
def update_factory_dependent():
factory = state["factory"]
state["line_options"] = factory_line_map.get(factory, [])
line_dropdown.options = [ft.dropdown.Option(opt) for opt in state["line_options"]]
line_dropdown.value = None
state["line"] = ""
state["problem_options"] = common_problems.get(factory, [])
state["reason_options"] = common_downtime_reasons.get(factory, [])
update_problems_checkboxes()
update_reasons_checkboxes()
page.update()
# Обновление списка зон при выборе линии
def update_line_dependent():
line = state["line"]
state["zone_options"] = line_zone_map.get(line, [])
zone_dropdown.options = [ft.dropdown.Option(opt) for opt in state["zone_options"]]
zone_dropdown.value = None
state["error_zone"] = ""
page.update()
def update_problems_checkboxes():
problems_checkboxes.controls.clear()
for prob in state["problem_options"]:
chk = ft.Checkbox(label=prob, value=False)
def on_change(e, label=prob):
if e.control.value:
state["problems"].add(label)
else:
state["problems"].discard(label)
chk.on_change = on_change
problems_checkboxes.controls.append(chk)
page.update()
def update_reasons_checkboxes():
reasons_checkboxes.controls.clear()
for reason in state["reason_options"]:
chk = ft.Checkbox(label=reason, value=False)
def on_change(e, label=reason):
if e.control.value:
state["downtime_reasons"].add(label)
else:
state["downtime_reasons"].discard(label)
chk.on_change = on_change
reasons_checkboxes.controls.append(chk)
page.update()
# Функция валидации этапов
def validate_step():
step = state["current_step"]
if step == 0:
if not operators_name_field.value.strip() or not factory_dropdown.value:
show_snackbar("Введите имя и выберите завод", ft.colors.RED)
return False
elif step == 1:
if not line_dropdown.value or not zone_dropdown.value:
show_snackbar("Выберите линию и зону", ft.colors.RED)
return False
elif step == 2:
total_problems = set(state["problems"])
if custom_problem_field.value and custom_problem_field.value.strip():
total_problems.add(custom_problem_field.value.strip())
total_reasons = set(state["downtime_reasons"])
if custom_reason_field.value and custom_reason_field.value.strip():
total_reasons.add(custom_reason_field.value.strip())
if not total_problems:
show_snackbar("Укажите хотя бы одну проблему", ft.colors.RED)
return False
if not total_reasons:
show_snackbar("Укажите хотя бы одну причину простоя", ft.colors.RED)
return False
elif step == 3:
if not fix_method_field.value.strip():
show_snackbar("Опишите, как решили проблему", ft.colors.RED)
return False
if not start_at_field.value.strip() or not end_at_field.value.strip():
show_snackbar("Укажите время начала и окончания", ft.colors.RED)
return False
try:
datetime.strptime(start_at_field.value.strip(), "%Y-%m-%d %H:%M")
datetime.strptime(end_at_field.value.strip(), "%Y-%m-%d %H:%M")
except ValueError:
show_snackbar("Неверный формат даты/времени", ft.colors.RED)
return False
return True
# Контейнер для отображения содержимого этапа
content_column = ft.Column()
# Прогресс-бар (значение от 0 до 1)
progress_bar = ft.ProgressBar(value=(state["current_step"]+1)/4)
# Кнопки навигации
next_button = ft.ElevatedButton(text="Далее")
back_button = ft.ElevatedButton(text="Назад")
submit_button = ft.ElevatedButton(text="Отправить")
# Обновление UI в зависимости от этапа
def update_ui():
content_column.controls.clear()
progress_bar.value = (state["current_step"]+1)/4
if state["current_step"] == 0:
content_column.controls.extend([
operators_name_field,
factory_dropdown,
])
elif state["current_step"] == 1:
content_column.controls.extend([
line_dropdown,
zone_dropdown,
])
elif state["current_step"] == 2:
content_column.controls.extend([
ft.Text("Проблемы (можно выбрать несколько):"),
problems_checkboxes,
custom_problem_field,
ft.Text("Причины простоя (можно выбрать несколько):"),
reasons_checkboxes,
custom_reason_field,
])
elif state["current_step"] == 3:
content_column.controls.extend([
fix_method_field,
start_at_field,
end_at_field,
])
# Кнопки навигации
nav_buttons = []
if state["current_step"] > 0:
nav_buttons.append(back_button)
if state["current_step"] < 3:
nav_buttons.append(next_button)
if state["current_step"] == 3:
nav_buttons.append(submit_button)
content_column.controls.append(ft.Row(controls=nav_buttons, spacing=20))
page.update()
# Обработчики кнопок
def on_next(e):
if validate_step():
if state["current_step"] == 0:
state["operators_name"] = operators_name_field.value
state["factory"] = factory_dropdown.value
update_factory_dependent()
elif state["current_step"] == 1:
state["line"] = line_dropdown.value
state["error_zone"] = zone_dropdown.value
state["current_step"] += 1
update_ui()
def on_back(e):
state["current_step"] -= 1
update_ui()
def on_submit(e):
if not validate_step():
return
state["fix_method"] = fix_method_field.value
state["start_at"] = start_at_field.value
state["end_at"] = end_at_field.value
total_problems = list(state["problems"])
if custom_problem_field.value and custom_problem_field.value.strip():
total_problems.append(custom_problem_field.value.strip())
total_reasons = list(state["downtime_reasons"])
if custom_reason_field.value and custom_reason_field.value.strip():
total_reasons.append(custom_reason_field.value.strip())
payload = {
"factory": state["factory"],
"line": state["line"],
"operators_name": state["operators_name"],
"error_zone": state["error_zone"],
"problem": ", ".join(total_problems),
"downtime_reason": ", ".join(total_reasons),
"fix_method": state["fix_method"],
"start_at": state["start_at"],
"end_at": state["end_at"],
}
print("[DEBUG] Отправляем JSON:", payload)
show_snackbar("Данные успешно отправлены!", ft.colors.GREEN)
# Сброс формы
state.update({
"current_step": 0,
"operators_name": "",
"factory": "",
"line": "",
"error_zone": "",
"problems": set(),
"downtime_reasons": set(),
"custom_problem": "",
"custom_reason": "",
"fix_method": "",
"start_at": "",
"end_at": "",
"line_options": [],
"zone_options": [],
"problem_options": [],
"reason_options": [],
})
operators_name_field.value = ""
factory_dropdown.value = None
line_dropdown.value = None
zone_dropdown.value = None
fix_method_field.value = ""
start_at_field.value = ""
end_at_field.value = ""
custom_problem_field.value = ""
custom_reason_field.value = ""
problems_checkboxes.controls.clear()
reasons_checkboxes.controls.clear()
update_ui()
next_button.on_click = on_next
back_button.on_click = on_back
submit_button.on_click = on_submit
def on_factory_change(e):
state["factory"] = factory_dropdown.value
update_factory_dependent()
factory_dropdown.on_change = on_factory_change
def on_line_change(e):
state["line"] = line_dropdown.value
update_line_dependent()
line_dropdown.on_change = on_line_change
def on_zone_change(e):
state["error_zone"] = zone_dropdown.value
zone_dropdown.on_change = on_zone_change
page.title = "Журнал простоев (мобильная версия) - Flet"
page.add(progress_bar, content_column)
update_ui()
ft.app(target=main)