Production Manager — кроссплатформенная система управления производственным конвейером с десктопным (PyQt6) и веб-интерфейсом (FastAPI). Автоматизирует учёт устройств, генерацию серийных номеров, отслеживание статусов на каждом этапе сборки и контроль действий сотрудников.
- Архитектура проекта
- Технологический стек
- Структура проекта
- Модели данных
- Роли и авторизация
- Десктопное приложение
- Веб-интерфейс
- Бизнес-логика и переходы
- Настройка и запуск
- Миграция на PostgreSQL
- Сборка и развёртывание
- Производительность и масштабирование
- Устранение проблем
- Передача фото на сетевую шару
- Глоссарий
Система состоит из трёх основных частей:
| Компонент | Технология | Назначение |
|---|---|---|
| Desktop-клиент | PyQt6 | Рабочее место сборщика/администратора с полнофункциональным GUI |
| Web-клиент | FastAPI + Jinja2 + Chart.js | Удалённый доступ, мониторинг и аналитика через браузер |
| База данных | SQLite / PostgreSQL | Единое хранилище для обоих интерфейсов |
Обе части приложения используют общий слой ORM-моделей (src/models.py) и конфигурации (src/config.py), что гарантирует согласованность данных.
graph TD
subgraph Clients["Клиентские интерфейсы"]
Qt["Desktop Клиент (PyQt6)"]
Web["Web Интерфейс (FastAPI)"]
end
subgraph Core["Ядро системы (Common)"]
Models["models.py (ORM)"]
Database["database.py (Connection)"]
Config["config.py (Env)"]
Workflow["workflow.py (Business Logic)"]
end
subgraph Storage["Хранение данных"]
DB_SQLITE[("SQLite (Dev)")]
DB_POSTGRES[("PostgreSQL (Prod)")]
end
Qt --> Core
Web --> Core
Core --> DB_SQLITE
Core --> DB_POSTGRES
| Зависимость | Версия | Назначение |
|---|---|---|
| Python | 3.10+ | Основной язык |
| SQLAlchemy | 2.x | ORM и работа с БД |
| python-dotenv | latest | Загрузка .env |
| Зависимость | Назначение |
|---|---|
| PyQt6 | Графический интерфейс |
| matplotlib | Графики и аналитика |
| Зависимость | Назначение |
|---|---|
| FastAPI | Веб-фреймворк и REST API |
| Uvicorn | ASGI-сервер |
| Jinja2 | Шаблонизатор |
| Chart.js | Визуализация данных в браузере |
| starlette.sessions | Cookie-сессии |
| Компонент | Назначение |
|---|---|
| SQLite | Локальная разработка, тестирование |
| PostgreSQL 16+ | Продакшн, сетевая работа нескольких пользователей |
| psycopg2-binary | Драйвер PostgreSQL для Python |
| Инструмент | Назначение |
|---|---|
| PyInstaller | Упаковка в .exe |
| Docker Compose | Быстрый запуск PostgreSQL |
appwin/
├── .env.example # Шаблон переменных окружения
├── .gitignore # Исключения Git
├── docker-compose.yml # PostgreSQL контейнер
├── db.sqlite3 # Локальная SQLite база
│
├── src/ # Ядро приложения (общее для Desktop и Web)
│ ├── __init__.py
│ ├── main.py # Точка входа Desktop-версии
│ ├── config.py # Конфигурация из .env
│ ├── database.py # SQLAlchemy engine и сессии
│ ├── models.py # ORM-модели (зеркало Django-моделей)
│ ├── logic/
│ │ └── workflow.py # WorkflowEngine — валидация переходов
│ └── ui/ # PyQt6 интерфейс
│ ├── styles.py # CSS-подобные стили для темной темы
│ ├── login_dialog.py # Диалог авторизации
│ ├── main_window.py # Главное окно с QTabWidget
│ ├── dashboard_tab.py # Вкладка: Дашборд
│ ├── projects_tab.py # Вкладка: Проекты
│ ├── pipeline_tab.py # Вкладка: Конвейер
│ ├── scan_tab.py # Вкладка: Сканирование
│ ├── device_status_tab.py # Вкладка: Статус SN
│ ├── sn_pool_tab.py # Вкладка: Пул SN
│ ├── analytics_tab.py # Вкладка: Аналитика
│ ├── admin_tab.py # Вкладка: Управление персоналом
│ └── widgets/ # Кастомные виджеты
│ └── pipeline_card.py # Карточка устройства для конвейера
│
├── web/ # Веб-интерфейс
│ ├── main.py # Точка входа FastAPI
│ ├── setup_db.py # Инициализация БД для веба
│ ├── api/ # REST API (JSON)
│ │ ├── dashboard_api.py
│ │ ├── analytics_api.py
│ │ ├── projects_api.py
│ │ ├── pipeline_api.py
│ │ ├── devices_api.py
│ │ ├── sn_pool_api.py
│ │ ├── admin_api.py
│ │ └── scan_api.py
│ ├── routes/ # HTML-маршруты
│ │ ├── auth.py
│ │ ├── dashboard.py
│ │ ├── analytics.py
│ │ ├── projects.py
│ │ ├── pipeline.py
│ │ ├── scan.py
│ │ ├── devices.py
│ │ ├── sn_pool.py
│ │ └── admin.py
│ ├── templates/ # Jinja2 HTML-шаблоны
│ │ ├── base.html
│ │ ├── login.html
│ │ ├── dashboard.html
│ │ ├── analytics.html
│ │ ├── projects.html
│ │ ├── pipeline.html
│ │ ├── scan.html
│ │ ├── devices.html
│ │ ├── sn_pool.html
│ │ └── admin.html
│ └── static/
│ ├── css/main.css
│ └── js/main.js
│
├── build.py # Скрипт сборки через PyInstaller
├── build_release.ps1 # PowerShell-скрипт сборки
├── production_manager.spec # Спецификация PyInstaller
├── run_web.ps1 # Запуск веб-сервера
├── migrate_sqlite_to_pg.py # Миграция SQLite → PostgreSQL (прямая)
└── migrate_to_postgres.py # Миграция SQLite → PostgreSQL (интерактивная)
Модели полностью совместимы с Django-бэкендом (office-task-manager) и используют те же имена таблиц с префиксами приложений.
accounts_user — учётные записи сотрудников
username,first_name,last_name,emailpassword— хэш в формате Djangopbkdf2_sha256$iterations$salt$hashrole—ADMIN,MANAGER,EMPLOYEE,WORKERaction_pin— 4-значный PIN для подтверждения операцийis_active,is_superuser,is_staff
auth_group — группы пользователей (стандартная Django-таблица)
accounts_user_groups — связь пользователь ↔ группа
tasks_project — производственный проект
code— уникальный внутренний кодname,descriptionmanager_id— ответственный менеджерstatus—PLANNING,ACTIVE,ON_HOLD,COMPLETED,CANCELLEDdeadline,spec_link,spec_code
tasks_devicemodel — модель устройства для генерации SN
category— категория (TIOGA,JBOX,MONITOR,RACKи т.д.)name— название моделиsn_prefix— префикс серийного номера (напр.60LXTRDC)
tasks_serialnumber — пул серийных номеров
sn— уникальный серийный номерmodel_id— привязка к моделиis_used— занят ли номер устройствомdevice_id— привязка к конкретному устройству
tasks_device — устройство
code— код устройстваproject_id— привязка к проектуname,serial_number,part_numberdevice_type— тип (COMPUTER,MONITOR,TIOGA,JBOX,RACKи др.)is_semifinished— является ли полуфабрикатомstatus— текущий статус (30+ значений конвейера)current_worker_id— текущий ответственный работникlocation— текущее местоположение
tasks_operation — операция над устройством
device_id— привязка к устройствуtitle,descriptionstatus—PENDING,IN_PROGRESS,COMPLETED,CANCELLEDgroup_id— группа-исполнительcreated_by_id— создатель операции
production_workplace — рабочее место (стенд)
name,workplace_type— тип (ASSEMBLY,VIBROSTAND,TECH_CONTROL_1_1и т.д.)is_pool— является ли пуломpool_limit— лимит устройств в пулеaccepts_semifinished— принимает ли полуфабрикатыrestrict_same_worker— ограничение на одного работникаdevice_status_on_enter— требуемый статус при входеorder— порядок в конвейераis_active
production_workplace_allowed_groups — связь workplace ↔ разрешённые группы
production_workplace_allowed_sources — связь workplace ↔ источники (откуда можно прийти)
production_worksession — сессия работника на рабочем месте
workplace_id,worker_idstarted_at,ended_atis_active
production_worklog — журнал производственных действий
worker_id,session_id,workplace_iddevice_id,project_idaction— тип действия (SCAN_IN,COMPLETED,DEFECTи т.д.)old_status,new_status— смена статусаserial_number,part_numbermissing_parts,defective_part_sn— информация о браке/недостачеnotes— комментарии
| Роль | Код | Доступ |
|---|---|---|
| Администратор | ADMIN |
Полный доступ ко всем вкладкам, управление проектами, справочниками, персоналом. Может удалять операции, сбрасывать пулы SN |
| Менеджер | MANAGER |
Создание и редактирование проектов, дашборды, аналитика. Доступ к админ-панели (с подтверждением пароля) |
| Сотрудник | EMPLOYEE |
Ограниченный доступ к основным рабочим вкладкам |
| Работник производства | WORKER |
Только вкладка «Сканирование». Не видит дашборды и настройки |
Desktop:
- При запуске появляется
LoginDialogс полями username/password - Пароль проверяется через Django-совместимый метод
User.check_password()(pbkdf2_sha256) - При успешном входе открывается
MainWindowс набором вкладок, зависящим от роли - Админ-панель требует повторного ввода пароля при каждом переходе
Web:
- Авторизация через
/loginс cookie-сессией - Сессия хранится 24 часа (
SessionMiddleware) - Каждая страница проверяет наличие
user_idв сессии
src/main.py → main()- Инициализация
QApplicationс High-DPI масштабированием - Отображение
LoginDialog— при отмене приложение завершается - Создание
MainWindow(user)с передачей авторизованного пользователя app.exec()— главный цикл событий Qt
- Сводная статистика: количество устройств по статусам, проектам, стендам
- Активные производственные сессии
- Быстрый взгляд на загруженность линии
- Создание и редактирование проектов
- Добавление оборудования из моделей «Пул SN»
- Генерация устройств с привязкой к серийным номерам
- При удалении проекта устройства аннулируются, SN остаются в истории
- Визуализация цепочки этапов производства
- Карточки устройств с текущими статусами
- Цветовая индикация этапов (согласно
Device.STATUS_COLORS)
- Основной рабочий интерфейс сборщика
- Выбор стенда → сканирование SN штрихкод-сканером
- Автоматическое определение устройства и продвижение статуса
- Запись в
WorkLog: штамп времени, стенд, PIN работника - Автофокус на поле ввода для непрерывного сканирования
- Поиск устройства по серийному номеру
- Текущий статус и полная история перемещений
- Привязка к проекту и партномеру
- Генерация серийных номеров по категориям и моделям
- Уникальные префиксы:
60LXTRDC(Tioga),50LXX4DC(JBOX),60MSO4IC(Мониторы) и др. - «Якоря» — ручной сдвиг счётчика для синхронизации с производством
- Защита от дубликатов (многопоточное резервирование)
- Графики matplotlib: статистика сборки, загрузка стендов
- Фильтрация по проектам и периодам
- Только для ADMIN/MANAGER с подтверждением пароля
- Управление пользователями и группами
Темная тема реализована через PyQt6 stylesheets (src/ui/styles.py). Автоподгонка колонок таблиц — через кастомные виджеты.
Веб-часть построена на FastAPI и полностью переиспользует модели и подключение из src/:
web/main.py
├── SessionMiddleware # Cookie-сессии (24ч)
├── CORSMiddleware # Кросс-доменные запросы
├── /static/ # CSS, JS
├── /templates/ # Jinja2 шаблоны
├── routes/ # HTML-страницы
└── api/ # JSON REST API
| URL | Метод | Описание |
|---|---|---|
/ |
GET | Редирект на /login |
/login |
GET/POST | Авторизация |
/dashboard |
GET | Дашборд с Chart.js |
/analytics |
GET | Аналитика |
/projects |
GET | Список проектов |
/pipeline |
GET | Конвейер устройств |
/scan |
GET/POST | Сканирование SN |
/devices |
GET | Таблица устройств с фильтрами |
/sn-pool |
GET | Управление SN |
/admin |
GET | Админ-панель |
Все эндпоинты требуют авторизации (проверка сессии):
| Endpoint | Метод | Описание |
|---|---|---|
/api/dashboard/ |
GET | Сводная статистика |
/api/dashboard/chart-data |
GET | Данные для графиков |
/api/analytics/ |
GET | Общая аналитика |
/api/analytics/devices |
GET | Аналитика по устройствам |
/api/analytics/users |
GET | Аналитика по пользователям |
/api/projects/ |
GET | Список проектов |
/api/projects/{id} |
GET | Детали проекта |
/api/pipeline/ |
GET | Устройства в производстве |
/api/devices/ |
GET | Устройства (?search=&status=) |
/api/devices/statuses |
GET | Статусы с количеством |
/api/sn-pool/ |
GET | Серийные номера |
/api/scan/workplaces |
GET | Список рабочих мест |
/api/scan/start-session |
POST | Старт рабочей сессии |
/api/scan/scan |
POST | Сканирование SN |
/api/scan/action |
POST | Действие: complete / defect / semifinished |
/api/scan/send-photos |
POST | Передача фото устройства на сетевую шару |
/api/scan/end-session |
POST | Завершение сессии |
/api/admin/users |
GET | Пользователи |
/api/admin/stats |
GET | Статистика админки |
Swagger-документация доступна по адресу http://host:8000/docs.
Таймер этапа — при принятии устройства в работу запускается обратный отсчёт (настраивается через timer_seconds в RouteConfigStage или ProjectRouteStage):
- Кнопки Готово / Брак блокируются до окончания таймера
- Кольцевой прогресс-бар: фиолетовый (ждём) → жёлтый (< 30 сек) → зелёный (готово)
- При завершении таймера кнопка Готово пульсирует
Передача фото — кнопка 📷 Отправить фото в фазе действий:
- Сервер ищет изображения в
IMG_SOURCE_DIRна локальном ПК - Подключается к сетевой шаре через Windows API (
WNetAddConnection2) - Перемещает файлы в
\\{server}\PR_DEP\Assembly\{проект}\{пост}\{SN}\ - Открывает Explorer в папке назначения
- Показывает результат в браузере без блокировки кнопок Готово/Брак
Класс, управляющий валидацией переходов между статусами устройств.
После смены статуса действует ограничение 5 минут до следующей смены (для роли WORKER). Администраторы и менеджеры не имеют ограничения.
graph TD
subgraph Strict["Строгие переходы (Strict)"]
ASSEMBLY --> WAITING_VIBROSTAND
VIBROSTAND --> WAITING_TC1["WAITING_TECH_CONTROL_1_*"]
TC1["TECH_CONTROL_1_*"] --> WAITING_FUNC_CONTROL
FUNC_CONTROL --> WAITING_TC2["WAITING_TECH_CONTROL_2_*"]
TC2["TECH_CONTROL_2_*"] --> WAITING_PACKING
end
subgraph Flex["Свободные переходы"]
REPAIR --> WAITING_VIBROSTAND
REPAIR --> WAITING_ASSEMBLY
REPAIR --> WAITING_PRE_PRODUCTION
ANY_ST --> REPAIR
ANY_ST --> DEFECT
end
REPAIR и DEFECT доступны из любого статуса.
| Тип стенда | Пакетный ввод | Лимит |
|---|---|---|
VIBROSTAND, FUNC_CONTROL, TECH_CONTROL_*, PACKING, ACCOUNTING, WAREHOUSE |
Да | 3 устройства |
| Остальные | Нет | 1 устройство |
WAITING_KITTING → WAITING_PRE_PRODUCTION → PRE_PRODUCTION →
WAITING_ASSEMBLY → ASSEMBLY →
WAITING_VIBROSTAND → VIBROSTAND →
WAITING_TECH_CONTROL_1_1 → TECH_CONTROL_1_1 →
WAITING_TECH_CONTROL_1_2 → TECH_CONTROL_1_2 →
WAITING_FUNC_CONTROL → FUNC_CONTROL →
WAITING_TECH_CONTROL_2_1 → TECH_CONTROL_2_1 →
WAITING_TECH_CONTROL_2_2 → TECH_CONTROL_2_2 →
WAITING_PACKING → PACKING →
WAITING_ACCOUNTING → ACCOUNTING →
WAREHOUSE / QC_PASSED
Параллельные ветки:
DEFECT,WAITING_PARTS,WAITING_SOFTWARE— проблемыREPAIR— ремонтный стенд (возврат на любой предыдущий этап)SHIPPED— отгружено
pip install -r requirements.txtСкопируйте шаблон:
copy .env.example .envДля разработки (SQLite):
DB_TYPE=sqlite
DB_PATH=db.sqlite3Для продакшена (PostgreSQL):
DB_TYPE=postgresql
DB_HOST=192.168.1.100
DB_PORT=5432
DB_NAME=production_db
DB_USER=prod_user
DB_PASSWORD=your_secure_password
DB_SSLMODE=disableНастройки передачи фото на пост:
# Локальная папка с фото (одна на всех ПК)
IMG_SOURCE_DIR=C:\Photos\Upload
# Сетевая шара (UNC)
IMG_NET_SERVER=\\192.168.106.29
IMG_NET_SHARE=PR_DEP
IMG_NET_USER=PR_DEP
IMG_NET_PASS=P@ssw0rd
IMG_NET_BASE=Assembly
# Форматы файлов
IMG_EXTENSIONS=jpg,jpeg,png,bmp,gif,webp,tiff,tifpython src/main.pyЧерез PowerShell:
.\run_web.ps1Или напрямую:
# Разработка (автообновление)
python -m uvicorn web.main:app --reload --port 8000
# Продакшн
python -m uvicorn web.main:app --host 0.0.0.0 --port 8000 --workers 4Откройте: http://localhost:8000
docker-compose up -dСоздастся контейнер production_postgres с:
- БД:
production_db - Пользователь:
prod_user - Пароль:
strong_password_here(измените вdocker-compose.yml) - Данные хранятся в именованном томе
pgdata
- Убедитесь, что PostgreSQL запущен
- Создайте БД и пользователя (см.
POSTGRES_SETUP.md) - Установите драйвер:
pip install psycopg2-binary - Настройте
.envс параметрами PostgreSQL
Вариант 1: migrate_sqlite_to_pg.py (автоматический)
- Читает данные из
db.sqlite3 - Подключается к PostgreSQL по параметрам из
.env - Создаёт таблицы и переносит данные
- Запуск:
python migrate_sqlite_to_pg.py
Вариант 2: migrate_to_postgres.py (интерактивный)
- Запрашивает параметры подключения в консоли
- Переносит данные модель за моделью с учётом внешних ключей
- Запуск:
python migrate_to_postgres.py
- Резервная копия SQLite:
copy db.sqlite3 db.sqlite3.backup - Настройте PostgreSQL и
.env - Запустите миграцию
- Проверьте подключение:
python src/main.py - Убедитесь, что данные отображаются корректно
Подробное руководство — в файле POSTGRES_SETUP.md.
Через Python-скрипт:
python build.pyЧерез PowerShell:
.\build_release.ps1Результат: dist/ProductionManager/ProductionManager.exe
Спецификация PyInstaller: production_manager.spec
- Включает все модули
src.ui.* - Включает
matplotlibи бэкенды - Упаковывает
.envиdb.sqlite3 - Исключает
tkinterдля уменьшения размера
Требования:
- PostgreSQL (локальный или Docker)
- Python 3.10+ с зависимостями
- Uvicorn (или Gunicorn с uvicorn-workers для продакшена)
Продакшн-запуск:
python -m uvicorn web.main:app --host 0.0.0.0 --port 8000 --workers 4Через Gunicorn (Linux):
gunicorn web.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000SQLite:
StaticPool— потокобезопасный единый пулcheck_same_thread=False— разрешение на многопоточный доступ
PostgreSQL:
QueuePoolс параметрами:pool_size=1(min соединений)max_overflow=39(до 40 суммарно)pool_pre_ping=True— проверка перед использованиемpool_timeout=30— таймаут ожидания
В моделях определены индексы для ускорения запросов:
Device.serial_number— поиск по SNDevice.part_number— поиск по партномеруDevice.status— фильтрация по статусуSerialNumber.sn— уникальность и поискWorkLog.serial_number— история по SNWorkLog.action— фильтрация по действиюWorkSession.is_active— поиск активных сессий
- Desktop: несколько клиентов подключаются к одной PostgreSQL
- Web: горизонтальное масштабирование через
--workers N - БД: PostgreSQL 16+ с поддержкой репликации
| Симптом | Причина | Решение |
|---|---|---|
could not connect to server |
PostgreSQL не запущен / порт закрыт | Проверьте сервис, брандмауэр, listen_addresses |
no pg_hba.conf entry |
Нет правила для IP | Добавьте правило в pg_hba.conf |
password authentication failed |
Неверный пароль | Проверьте DB_USER и DB_PASSWORD в .env |
database does not exist |
БД не создана | Создайте БД: CREATE DATABASE production_db |
| Симптом | Причина | Решение |
|---|---|---|
relation already exists |
Таблицы уже созданы | Нормально — данные вставляются в существующие таблицы |
duplicate key |
Повторная миграция | Очистите таблицы в PostgreSQL перед повторным запуском |
| Симптом | Причина | Решение |
|---|---|---|
ModuleNotFoundError |
Не установлены зависимости | pip install -r requirements.txt |
ImportError |
PYTHONPATH не настроен | Запускайте из корня проекта: python src/main.py |
No module named 'psycopg2' |
Нет драйвера PostgreSQL | pip install psycopg2-binary |
| Симптом | Причина | Решение |
|---|---|---|
Address already in use |
Порт 8000 занят | Используйте другой порт: --port 8001 |
ModuleNotFoundError: uvicorn |
Не установлен | pip install uvicorn |
Пользователь на посту нажимает кнопку 📷 Отправить фото — сервер находит изображения в фиксированной локальной папке и перемещает их в папку устройства на сетевой шаре.
\\192.168.106.29\PR_DEP\Assembly\{имя проекта}\{тип поста}\{SN устройства}\
| workplace_type | Подпапка на шаре |
|---|---|
| PRE_PRODUCTION | Complectation |
| VIBROSTAND | Vibrostand |
| TECH_CONTROL_* | OTK |
| FUNC_CONTROL | Tests |
| PACKING | Packing |
| WAREHOUSE | Warehouse |
Использует Windows API WNetAddConnection2 (через ctypes). Учётные данные задаются в .env через IMG_NET_USER / IMG_NET_PASS.
- Если папка
IMG_SOURCE_DIRпуста → жёлтый статус с подсказкой - Если нет подключения к шаре → красный статус с кодом ошибки Windows
- Файлы перемещаются (не копируются) из локальной папки
- Explorer открывается в папке назначения автоматически
- Кнопки Готово / Брак доступны параллельно
| Термин | Определение |
|---|---|
| SN (Серийный номер) | Уникальный идентификатор устройства (напр. 60LXTRDC000123) |
| Пул SN | Менеджер генерации и хранения серийных номеров |
| Якорь | Ручной сдвиг счётчика SN для синхронизации с реальным производством |
| Стенд (Workplace) | Физическое рабочее место на производственной линии |
| Конвейер (Pipeline) | Последовательность этапов производства устройства |
| WorkflowEngine | Движок валидации переходов между статусами |
| Кулдаун | 5-минутный запрет на повторную смену статуса (для работников) |
| Полуфабрикат | Устройство, не завершившее полный цикл, но временно учитываемое |
| Сессия (WorkSession) | Период работы сотрудника на конкретном стенде |
| WorkLog | Журнал всех производственных действий |
| Пакетный ввод | Возможность сканировать несколько устройств подряд без подтверждения |
| Таймер этапа | Обратный отсчёт, блокирующий завершение до истечения нормативного времени |
| IMG_SOURCE_DIR | Локальная папка на рабочем ПК, из которой берутся фото для передачи |
- Исходный код:
c:\Users\KnyshovDmitry\appwin - Логирование: включите
DEBUG=Trueв.envдля вывода SQL-запросов - API документация (Web):
http://localhost:8000/docs
Версия документа: 1.1.0
Дата: 21 апреля 2026
Проект: Production Manager (appwin)
© 2026 PR DEP