backend/mobileApps/fletFormTest.py
2025-03-23 21:24:08 +10:00

322 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)