- Реструктуризация: src/ разбит на middleware/, utils/, repositories/ (удалены), routes/ (удалены) - Добавлен src/original-html.ts — полный HTML с reportModal - Добавлен src/index.tsx.backup — React-компонент с reportModal - Миграции переименованы (0001_initial_schema.sql) - Добавлена миграция 0018 (удалена позже) - Docker: multi-stage build, wrangler.toml - Frontend: public/static/app.js + style.css - seed.sql добавлен - Документация: CHANGELOG, CHANGES_v4.1.0-4.1.9, PROJECT_STRUCTURE
382 lines
16 KiB
Markdown
382 lines
16 KiB
Markdown
# 📋 ЛОГИКА ДАТ И ЧЕКБОКСОВ - ПОЛНОЕ РУКОВОДСТВО
|
||
|
||
**Версия**: v4.1.17
|
||
**Дата**: 2026-01-14
|
||
**Обновление**: Исправлены права доступа (см. ACCESS_RIGHTS.md)
|
||
|
||
---
|
||
|
||
## ⚠️ **ВАЖНО: ПРАВА ДОСТУПА**
|
||
|
||
**Детальная информация о правах доступа находится в файле:**
|
||
📄 **[ACCESS_RIGHTS.md](./ACCESS_RIGHTS.md)**
|
||
|
||
**Краткая сводка:**
|
||
- **Admin**: полный доступ (календари + toggle)
|
||
- **User**: подтверждение MAT-1/MAT-2 + toggle всех полей
|
||
- **Guest**: только просмотр
|
||
|
||
---
|
||
|
||
## 🔄 **TÖÖLEHTI (WORKSHEETS) - 3-ШАГОВЫЙ ЦИКЛ**
|
||
|
||
### **Как работает:**
|
||
|
||
#### **ШАГ 1: Пусто → Серый фон с датой**
|
||
- **Состояние**: Пустая ячейка `-`
|
||
- **Действие**: Клик по ячейке
|
||
- **Результат**:
|
||
- Появляется **текущая дата**
|
||
- Фон **СЕРЫЙ** (не подтверждено)
|
||
- `worksheets_date` = TODAY
|
||
- `worksheets_confirmed` = 0
|
||
|
||
#### **ШАГ 2: Серый → Зеленый фон (подтверждение)**
|
||
- **Состояние**: Дата с серым фоном
|
||
- **Действие**: Клик по ячейке
|
||
- **Результат**:
|
||
- Дата **остается**
|
||
- Фон становится **ЗЕЛЕНЫЙ** (подтверждено)
|
||
- `worksheets_date` = **сохраняется**
|
||
- `worksheets_confirmed` = 1
|
||
|
||
#### **ШАГ 3: Зеленый → Пусто (сброс)**
|
||
- **Состояние**: Дата с зеленым фоном
|
||
- **Действие**: Клик по ячейке
|
||
- **Результат**:
|
||
- Дата **удаляется**
|
||
- Ячейка становится **пустой** `-`
|
||
- `worksheets_date` = NULL
|
||
- `worksheets_confirmed` = 0
|
||
|
||
### **Визуальная схема:**
|
||
```
|
||
┌─────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────┐
|
||
│ ПУСТО │ Клик 1 │ СЕРЫЙ ФОН │ Клик 2 │ ЗЕЛЕНЫЙ ФОН │ Клик 3 │ ПУСТО │
|
||
│ - │ ──────> │ 14.01.2026 │ ──────> │ 14.01.2026 │ ──────> │ - │
|
||
│ │ │ (не подтверждено)│ │ (подтверждено) │ │ │
|
||
└─────────────┘ └──────────────────┘ └──────────────────┘ └─────────────┘
|
||
^ │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||
Цикл повторяется
|
||
```
|
||
|
||
---
|
||
|
||
## 🟢 **MAT-1 (MATERIAL) - КАЛЕНДАРЬ + ПОДТВЕРЖДЕНИЕ**
|
||
|
||
### **Функционал:**
|
||
- **Календарь**: Клик по ячейке → открывается календарь
|
||
- **Выбор даты**: Выбрать дату → сохраняется `material_date`
|
||
- **Кнопка подтверждения** ✓: Клик → зеленая рамка
|
||
- `material_confirmed` = 1
|
||
- Ячейка с зеленой рамкой
|
||
|
||
### **Кто может изменять:**
|
||
- ✅ Admin
|
||
- ✅ Public User (все)
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.material_date` (TEXT)
|
||
- `status_checkboxes.material_confirmed` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 🔒 **MAT-2 (MATERIAL2) - ЗАВИСИТ ОТ MAT-1**
|
||
|
||
### **Блокировка:**
|
||
- **Заблокировано**: Если MAT-1 пустая
|
||
- **Показывается**: 🔒 с подсказкой "MAT-1 peab olema täidetud"
|
||
- **Разблокировано**: Когда MAT-1 заполнена
|
||
|
||
### **Функционал (когда разблокирована):**
|
||
- **Календарь**: Клик → открывается календарь
|
||
- **Выбор даты**: Выбрать дату → сохраняется `material2_date`
|
||
- **Кнопка подтверждения** ✓: Клик → зеленая рамка
|
||
- `material2_confirmed` = 1
|
||
|
||
### **Кто может изменять:**
|
||
- ✅ Admin
|
||
- ✅ Public User (если MAT-1 заполнена)
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.material2_date` (TEXT)
|
||
- `status_checkboxes.material2_confirmed` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 📦 **PAKETT (PACKAGE) - КАЛЕНДАРЬ**
|
||
|
||
### **Функционал:**
|
||
- **Календарь**: Клик → открывается календарь
|
||
- **Выбор даты**: Выбрать дату → сохраняется `package_date`
|
||
- **Нет подтверждения**: Только дата (без кнопки ✓)
|
||
|
||
### **Кто может изменять:**
|
||
- ✅ Admin
|
||
- ✅ Public User (все)
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.package_date` (TEXT)
|
||
|
||
---
|
||
|
||
## 🔴 **LÕIKUS (CUTTING) - ТОЛЬКО ADMIN**
|
||
|
||
### **Функционал:**
|
||
- **Toggle**: Клик → дата появляется/исчезает
|
||
- **Автоматическая дата**: Устанавливается на **сегодня**
|
||
- **Ошибка-флаг** 🚫: `cutting_error`
|
||
- Если установлена → красная метка
|
||
- Блокирует **VALMIS** и **VÄLJAS**
|
||
|
||
### **Кто может изменять:**
|
||
- 🔴 **ТОЛЬКО Admin**
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.cutting_date` (TEXT)
|
||
- `status_checkboxes.cutting_error` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 🔴 **KLAAS (GLAZING) - ТОЛЬКО ADMIN**
|
||
|
||
### **Функционал:**
|
||
- **Toggle**: Клик → дата появляется/исчезает
|
||
- **Автоматическая дата**: Устанавливается на **сегодня**
|
||
- **Ошибка-флаг** 🚫: `glazing_error`
|
||
- Если установлена → красная метка
|
||
- Блокирует **VALMIS** и **VÄLJAS**
|
||
|
||
### **Кто может изменять:**
|
||
- 🔴 **ТОЛЬКО Admin**
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.glazing_date` (TEXT)
|
||
- `status_checkboxes.glazing_error` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 🔒 **VALMIS (READY) - Admin/User Toggle + БЛОКИРОВКА ТОЛЬКО ПО ERROR ФЛАГАМ**
|
||
|
||
### **ВАЖНО: ТЕКСТ ПРОБЛЕМЫ НЕ БЛОКИРУЕТ!**
|
||
Текст в поле "Probleemid" (серая метка ⚠️) **НЕ** блокирует VALMIS!
|
||
|
||
### **Блокировка:**
|
||
Поле **ЗАБЛОКИРОВАНО ТОЛЬКО**, если установлен **ЛЮБОЙ error флаг** (красная галочка ✗):
|
||
- `worksheets_error = 1`
|
||
- `cutting_error = 1`
|
||
- `glazing_error = 1`
|
||
- `ready_error = 1`
|
||
- `issued_error = 1`
|
||
|
||
**НЕ блокируется**, если:
|
||
- Есть только текст в `production_records.problems` (серая метка ⚠️)
|
||
- Все error флаги = 0
|
||
|
||
### **Визуальное отображение:**
|
||
- **Заблокировано**: 🔒 + сообщение "Vigade märked on seatud (punased kolmnurgad)"
|
||
- **Разблокировано**: Toggle как обычно
|
||
|
||
### **Функционал (когда разблокирована):**
|
||
- **Toggle**: Клик → дата появляется/исчезает
|
||
- **Автоматическая дата**: Устанавливается на **сегодня**
|
||
|
||
### **Кто может изменять:**
|
||
- ✅ **Admin + User** (изменено в v4.1.18)
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.ready_date` (TEXT)
|
||
- `status_checkboxes.ready_error` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 🔒 **VÄLJAS (ISSUED) - Admin/User Toggle + БЛОКИРОВКА ТОЛЬКО ПО ERROR ФЛАГАМ**
|
||
|
||
### **ВАЖНО: ТЕКСТ ПРОБЛЕМЫ НЕ БЛОКИРУЕТ!**
|
||
Текст в поле "Probleemid" (серая метка ⚠️) **НЕ** блокирует VÄLJAS!
|
||
|
||
### **Блокировка:**
|
||
**ТА ЖЕ ЛОГИКА** что и **VALMIS**:
|
||
- Блокируется **ТОЛЬКО** если установлен **ЛЮБОЙ error флаг** (красная галочка ✗)
|
||
- **НЕ** блокируется если есть только текст в `production_records.problems`
|
||
|
||
### **Функционал (когда разблокирована):**
|
||
- **Toggle**: Клик → дата появляется/исчезает
|
||
- **Автоматическая дата**: Устанавливается на **сегодня**
|
||
|
||
### **Кто может изменять:**
|
||
- ✅ **Admin + User** (изменено в v4.1.18)
|
||
|
||
### **Кто может изменять:**
|
||
- 🔴 **ТОЛЬКО Admin**
|
||
|
||
### **База данных:**
|
||
- `status_checkboxes.issued_date` (TEXT)
|
||
- `status_checkboxes.issued_error` (INTEGER, 0 или 1)
|
||
|
||
---
|
||
|
||
## 📊 **СВОДНАЯ ТАБЛИЦА**
|
||
|
||
| Поле | Тип | Доступ | Логика | Подтверждение | Блокировка |
|
||
|------|-----|--------|--------|---------------|-----------|
|
||
| **MAT-1** | Календарь | Все | Календарь | ✓ Да | Нет |
|
||
| **MAT-2** | Календарь | Все | Календарь | ✓ Да | Если MAT-1 пуста |
|
||
| **PAKETT** | Календарь | Все | Календарь | Нет | Нет |
|
||
| **Töölehti** | 3-цикл | Admin | Серый→Зеленый→Пусто | Да | Нет |
|
||
| **LÕIKUS** | Toggle | Admin | Появляется/Исчезает | Нет | Нет |
|
||
| **KLAAS** | Toggle | Admin | Появляется/Исчезает | Нет | Нет |
|
||
| **VALMIS** | Toggle | Admin/User | Появляется/Исчезает | Нет | ТОЛЬКО если error флаги (НЕ текст проблемы) |
|
||
| **VÄLJAS** | Toggle | Admin/User | Появляется/Исчезает | Нет | ТОЛЬКО если error флаги (НЕ текст проблемы) |
|
||
|
||
---
|
||
|
||
## 🔐 **ПРАВА ДОСТУПА**
|
||
|
||
### **Admin** (admin, aknaproff):
|
||
- ✅ Все поля (MAT-1, MAT-2, PAKETT, Töölehti, LÕIKUS, KLAAS, VALMIS, VÄLJAS)
|
||
- ✅ Добавление записей
|
||
- ✅ Редактирование записей
|
||
- ✅ Удаление записей
|
||
- ✅ Изменение проблем и ошибок
|
||
|
||
### **Public User** (kasutaja):
|
||
- ✅ MAT-1 (календарь + подтверждение)
|
||
- ✅ MAT-2 (календарь + подтверждение, если MAT-1 заполнена)
|
||
- ✅ PAKETT (календарь)
|
||
- ❌ Töölehti, LÕIKUS, KLAAS, VALMIS, VÄLJAS (только просмотр)
|
||
- ❌ Добавление/редактирование/удаление записей
|
||
|
||
---
|
||
|
||
## 🎨 **ВИЗУАЛЬНЫЕ ИНДИКАТОРЫ**
|
||
|
||
### **Цвета:**
|
||
- 🟢 **Зеленая рамка**: MAT-1/MAT-2 подтверждены
|
||
- 🟢 **Зеленый фон**: Töölehti подтверждено (confirmed=1)
|
||
- ⬜ **Серый фон**: Töölehti не подтверждено (confirmed=0)
|
||
- 🔴 **Красная метка**: Ошибка-флаг установлен
|
||
- 🔒 **Замок**: Поле заблокировано
|
||
|
||
### **Подсказки:**
|
||
- **MAT-2 заблокирована**: "MAT-1 peab olema täidetud"
|
||
- **VALMIS/VÄLJAS заблокированы**: Текст проблемы из `production_records.problems`
|
||
- **Töölehti Шаг 1**: "Klõps 1: Lisa kuupäev"
|
||
- **Töölehti Шаг 2**: "Klõps 2: Kinnita"
|
||
- **Töölehti Шаг 3**: "Klõps 3: Tühjenda"
|
||
|
||
---
|
||
|
||
## 📝 **AUDIT LOG**
|
||
|
||
Каждое изменение даты записывается в таблицу `audit_log`:
|
||
```sql
|
||
INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
|
||
VALUES (?, ?, ?, ?, ?, 'toggle_status')
|
||
```
|
||
|
||
**Поля:**
|
||
- `user_id`: ID пользователя (1=admin, 2=aknaproff, 4=kasutaja)
|
||
- `record_id`: ID записи
|
||
- `field`: Название поля (worksheets, cutting, glazing, ready, issued)
|
||
- `old_value`: Старое значение даты
|
||
- `new_value`: Новое значение даты
|
||
- `action`: Тип действия ('toggle_status', 'worksheets_cycle')
|
||
|
||
---
|
||
|
||
## ✅ **ПРОВЕРКА**
|
||
|
||
### **Test Töölehti 3-цикл:**
|
||
```bash
|
||
# Шаг 1: Пусто → Серый
|
||
PATCH /api/records/2/worksheets-cycle
|
||
→ {"date": "2026-01-14", "confirmed": 0}
|
||
|
||
# Шаг 2: Серый → Зеленый
|
||
PATCH /api/records/2/worksheets-cycle
|
||
→ {"date": "2026-01-14", "confirmed": 1}
|
||
|
||
# Шаг 3: Зеленый → Пусто
|
||
PATCH /api/records/2/worksheets-cycle
|
||
→ {"date": null, "confirmed": 0}
|
||
```
|
||
|
||
### **Test блокировка MAT-2:**
|
||
```bash
|
||
# MAT-1 пустая → MAT-2 заблокирована
|
||
SELECT material_date FROM status_checkboxes WHERE record_id = 5
|
||
→ NULL
|
||
# UI показывает: 🔒 "MAT-1 peab olema täidetud"
|
||
```
|
||
|
||
### **Test блокировка VALMIS:**
|
||
```bash
|
||
# Есть проблемы → VALMIS заблокирована
|
||
SELECT problems FROM production_records WHERE id = 10
|
||
→ "Aken vajab parandust"
|
||
# UI показывает: 🔒 + текст проблемы
|
||
```
|
||
|
||
---
|
||
|
||
**Версия**: v4.1.16
|
||
**Статус**: ✅ Работает корректно
|
||
**Дата**: 2026-01-14
|
||
|
||
---
|
||
|
||
## 🔒 **ВАЖНО: ПРАВИЛО БЛОКИРОВКИ VALMIS/VÄLJAS**
|
||
|
||
### **Версия**: v4.1.19
|
||
### **Дата изменения**: 2026-01-14
|
||
|
||
**КРИТИЧЕСКИ ВАЖНО**: Блокировка VALMIS/VÄLJAS работает **ТОЛЬКО** по error флагам!
|
||
|
||
### **Блокируется**, если установлен **ЛЮБОЙ** из error флагов (красная галочка ✗):
|
||
- `worksheets_error = 1`
|
||
- `cutting_error = 1`
|
||
- `glazing_error = 1`
|
||
- `ready_error = 1`
|
||
- `issued_error = 1`
|
||
|
||
### **НЕ БЛОКИРУЕТСЯ**, если:
|
||
- Есть **ТОЛЬКО** текст в `production_records.problems` (серая метка ⚠️)
|
||
- Все error флаги = 0
|
||
|
||
### **Визуальные индикаторы:**
|
||
- **VALMIS/VÄLJAS заблокированы**: 🔒 + сообщение "Vigade märked on seatud (punased kolmnurgad)"
|
||
- **Серая метка с ⚠️**: Указывает на текст проблемы в поле "Probleemid", **НЕ блокирует** VALMIS/VÄLJAS
|
||
|
||
### **Код проверки блокировки** (backend):
|
||
```typescript
|
||
if (field === 'ready' || field === 'issued') {
|
||
const statusCheckbox = await c.env.DB.prepare(
|
||
'SELECT worksheets_error, cutting_error, glazing_error, ready_error, issued_error FROM status_checkboxes WHERE record_id = ?'
|
||
).bind(recordId).first()
|
||
|
||
const hasErrorFlags = statusCheckbox && (
|
||
statusCheckbox.worksheets_error ||
|
||
statusCheckbox.cutting_error ||
|
||
statusCheckbox.glazing_error ||
|
||
statusCheckbox.ready_error ||
|
||
statusCheckbox.issued_error
|
||
)
|
||
|
||
if (hasErrorFlags) {
|
||
return c.json({
|
||
error: 'blocked',
|
||
message: 'Vigade märked on seatud (punased kolmnurgad)'
|
||
}, 403)
|
||
}
|
||
}
|
||
```
|
||
|
||
### **Тестирование** (результаты от 2026-01-14):
|
||
✅ **Test 1**: Только текст problems → НЕ блокируется → `{"success":true}`
|
||
✅ **Test 2**: Установлен error flag → БЛОКИРУЕТСЯ → `{"error":"blocked","message":"..."}`
|
||
|
||
---
|