Files
aiform_prod/frontend/src/pages/ClaimForm.tsx

1317 lines
60 KiB
TypeScript
Raw Normal View History

import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
import { Steps, Card, message, Row, Col, Space } from 'antd';
import Step1Phone from '../components/form/Step1Phone';
import StepDescription from '../components/form/StepDescription';
import Step1Policy from '../components/form/Step1Policy';
import StepDraftSelection from '../components/form/StepDraftSelection';
import StepWizardPlan from '../components/form/StepWizardPlan';
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
import StepClaimConfirmation from '../components/form/StepClaimConfirmation';
import Step2EventType from '../components/form/Step2EventType';
import StepDocumentUpload from '../components/form/StepDocumentUpload';
import Step3Payment from '../components/form/Step3Payment';
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
import DebugPanel from '../components/DebugPanel';
import { getDocumentsForEventType } from '../constants/documentConfigs';
import './ClaimForm.css';
// Используем относительные пути - Vite proxy перенаправит на backend
const { Step } = Steps;
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
/**
* Генерация UUID v4
* Формат: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
*/
function generateUUIDv4(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
interface FormData {
// Шаг 1: Phone
phone?: string;
contact_id?: string;
unified_id?: string; // ✅ Unified ID пользователя из PostgreSQL
is_new_contact?: boolean;
smsCode?: string;
clientIp?: string;
smsDebugCode?: string;
// Шаг 2: Policy
voucher: string;
claim_id?: string;
session_id?: string;
project_id?: string; // ✅ ID проекта в vTiger (полис)
is_new_project?: boolean; // ✅ Флаг: создан новый проект
problemDescription?: string;
wizardPlan?: any;
wizardPlanStatus?: 'pending' | 'ready' | 'answered';
wizardAnswers?: Record<string, any>;
wizardPrefill?: Record<string, any>;
wizardPrefillArray?: Array<{ name: string; value: any }>;
wizardCoverageReport?: any;
wizardUploads?: Record<string, any>;
wizardSkippedDocuments?: string[];
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
// Подтверждение заявления (после получения данных из claim:plan)
showClaimConfirmation?: boolean;
claimPlanData?: any; // Данные заявления от n8n из канала claim:plan
// Шаг 3: Event Type
eventType?: string;
ticket_id?: string; // ✅ ID заявки в vTiger (HelpDesk)
ticket_number?: string; // ✅ Номер заявки (HD001234)
// Шаги 4+: Documents
documents?: Record<string, {
uploaded: boolean;
data: any;
file_type: string;
skipped?: boolean;
}>;
// Последний шаг: Payment
fullName?: string;
email?: string;
paymentMethod?: string;
bankName?: string;
cardNumber?: string;
accountNumber?: string;
}
export default function ClaimForm() {
// ✅ claim_id будет создан n8n в Step1Phone после SMS верификации
// Не генерируем его локально!
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
// session_id будет получен от n8n при создании контакта
// Используем useRef чтобы sessionId не вызывал перерендер и был стабильным
const sessionIdRef = useRef(`sess-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
const claimPlanEventSourceRef = useRef<EventSource | null>(null);
const claimPlanTimeoutRef = useRef<NodeJS.Timeout | null>(null);
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
const [currentStep, setCurrentStep] = useState(0);
const [sessionRestored, setSessionRestored] = useState(false); // Флаг: пытались восстановить сессию
const [formData, setFormData] = useState<FormData>({
voucher: '',
claim_id: undefined, // ✅ Будет заполнен n8n в Step1Phone
session_id: sessionIdRef.current,
paymentMethod: 'sbp',
});
const [isPhoneVerified, setIsPhoneVerified] = useState(false);
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
const [debugEvents, setDebugEvents] = useState<any[]>([]);
const [isSubmitted, setIsSubmitted] = useState(false);
const [showDraftSelection, setShowDraftSelection] = useState(false);
const [selectedDraftId, setSelectedDraftId] = useState<string | null>(null);
const [hasDrafts, setHasDrafts] = useState(false);
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
useEffect(() => {
// 🔥 VERSION CHECK: Если видишь это в консоли - фронт обновился!
console.log('🔥 ClaimForm v3.8 - 2025-11-20 15:10 - Fix session_id priority in loadDraft');
}, []);
// ✅ Восстановление сессии при загрузке страницы
useEffect(() => {
const restoreSession = async () => {
console.log('🔑 🔑 🔑 НАЧАЛО ВОССТАНОВЛЕНИЯ СЕССИИ 🔑 🔑 🔑');
console.log('🔑 Все ключи в localStorage:', Object.keys(localStorage));
console.log('🔑 Значения всех ключей:', JSON.stringify(localStorage));
const savedSessionToken = localStorage.getItem('session_token');
if (!savedSessionToken) {
console.log('❌ Session token NOT found in localStorage');
setSessionRestored(true);
return;
}
console.log('✅ Found session_token in localStorage, verifying:', savedSessionToken);
addDebugEvent('session', 'info', '🔑 Проверка сохранённой сессии');
try {
const response = await fetch('/api/v1/session/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_token: savedSessionToken })
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
console.log('🔑 Session verify response:', data);
if (data.success && data.valid) {
// Сессия валидна! Восстанавливаем состояние
console.log('✅ Session valid! Restoring user data:', {
unified_id: data.unified_id,
phone: data.phone,
expires_in: data.expires_in_seconds
});
// Обновляем formData с данными сессии
updateFormData({
unified_id: data.unified_id,
phone: data.phone,
contact_id: data.contact_id,
session_id: savedSessionToken
});
// Устанавливаем session_id в ref
sessionIdRef.current = savedSessionToken;
// Помечаем телефон как верифицированный
setIsPhoneVerified(true);
// Проверяем черновики
const hasDraftsResult = await checkDrafts(data.unified_id, data.phone, savedSessionToken);
if (hasDraftsResult) {
// Есть черновики - показываем список
setShowDraftSelection(true);
setHasDrafts(true);
// Переходим к шагу выбора черновика
requestAnimationFrame(() => {
requestAnimationFrame(() => {
setCurrentStep(0);
});
});
message.success(`Добро пожаловать! Сессия восстановлена (${data.phone})`);
addDebugEvent('session', 'success', '✅ Сессия восстановлена, найдены черновики');
} else {
// Нет черновиков - переходим к описанию
setCurrentStep(1);
message.success(`Добро пожаловать! Сессия восстановлена (${data.phone})`);
addDebugEvent('session', 'success', '✅ Сессия восстановлена');
}
} else {
// Сессия невалидна - удаляем из localStorage
console.log('❌ Session invalid or expired, removing from localStorage');
localStorage.removeItem('session_token');
addDebugEvent('session', 'warning', '⚠️ Сессия истекла');
}
} catch (error) {
console.error('❌ Error verifying session:', error);
localStorage.removeItem('session_token');
addDebugEvent('session', 'error', '❌ Ошибка проверки сессии');
} finally {
setSessionRestored(true);
}
};
restoreSession();
}, []); // Запускаем только при загрузке
// Получаем IP клиента один раз при монтировании
useEffect(() => {
const fetchClientIp = async () => {
try {
const response = await fetch('/api/v1/utils/client-ip');
if (!response.ok) return;
const data = await response.json();
if (data?.ip) {
setFormData((prev) => ({ ...prev, clientIp: data.ip }));
}
} catch {
// Тихо игнорируем, IP всегда можно взять на бэке из request
}
};
fetchClientIp();
}, []);
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
// Автоматический переход к шагу подтверждения, когда данные готовы
useEffect(() => {
if (formData.showClaimConfirmation && formData.claimPlanData) {
// Вычисляем индекс шага подтверждения динамически
// Шаг подтверждения добавляется после StepWizardPlan
// После выбора черновика showDraftSelection = false, поэтому:
// - Шаг 0 = Step1Phone
// - Шаг 1 = StepDescription
// - Шаг 2 = StepWizardPlan
// - Шаг 3 = StepClaimConfirmation (если showClaimConfirmation=true)
const confirmationStepIndex = 3; // Фиксированный индекс для шага подтверждения
console.log('✅ Данные заявления готовы, переходим к шагу подтверждения:', confirmationStepIndex);
setTimeout(() => {
setCurrentStep(confirmationStepIndex);
}, 100);
}
}, [formData.showClaimConfirmation, formData.claimPlanData]);
// Динамически определяем список шагов на основе выбранного eventType
const documentConfigs = formData.eventType ? getDocumentsForEventType(formData.eventType) : [];
const totalDocumentSteps = documentConfigs.length;
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
const addDebugEvent = (type: string, status: string, message: string, data?: any) => {
const event = {
timestamp: new Date().toLocaleTimeString('ru-RU'),
type,
status,
message,
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
data: {
...data,
claim_id: formData.claim_id // ✅ Используем claim_id из formData (от n8n)
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
}
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
};
setDebugEvents(prev => [event, ...prev]);
};
// ✅ claim_id будет залогирован в Step1Phone после получения от n8n
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
const updateFormData = useCallback((data: Partial<FormData>) => {
setFormData((prev) => ({ ...prev, ...data }));
}, []);
const nextStep = useCallback(() => {
console.log('⏩ nextStep called');
setCurrentStep((prev) => {
console.log('📍 Current step:', prev, '→ Next:', prev + 1);
return prev + 1;
});
}, []);
const prevStep = useCallback(() => {
console.log('⏪ prevStep called');
setCurrentStep((prev) => {
console.log('📍 Current step:', prev, '→ Prev:', prev - 1);
return prev - 1;
});
}, []);
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Преобразование данных черновика в формат propertyName для формы подтверждения
const transformDraftToClaimPlanFormat = useCallback((data: {
claim: any;
payload: any;
body: any;
isTelegramFormat: boolean;
finalClaimId: string;
actualSessionId: string;
currentFormData: FormData;
}) => {
const { claim, payload, body, finalClaimId, actualSessionId, currentFormData } = data;
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
console.log('🔄 transformDraftToClaimPlanFormat: входные данные:', {
claimId: finalClaimId,
claimUnifiedId: claim.unified_id,
formDataUnifiedId: currentFormData.unified_id,
claimKeys: Object.keys(claim),
});
console.log('🔄 Данные из БД:', {
hasApplicantData: !!(body.applicant || payload.applicant),
hasCaseData: !!(body.case || payload.case),
hasContractData: !!(body.contract_or_service || payload.contract_or_service),
hasWizardAnswers: !!(body.answers || payload.answers || body.wizard_answers || payload.wizard_answers),
hasSendToFormApprove: !!(payload.send_to_form_approve && payload.send_to_form_approve.draft),
payloadKeys: Object.keys(payload),
bodyKeys: Object.keys(body),
});
// ✅ ПРИОРИТЕТ 1: Если есть данные в payload.send_to_form_approve.draft - используем их напрямую!
const sendToFormApproveDraft = payload.send_to_form_approve?.draft;
if (sendToFormApproveDraft) {
console.log('✅ Найдены данные в payload.send_to_form_approve.draft, используем их напрямую!');
console.log('✅ send_to_form_approve.draft:', sendToFormApproveDraft);
// Используем данные из send_to_form_approve.draft напрямую
const draftData = sendToFormApproveDraft;
// Формируем propertyName из draft данных
const propertyName = {
applicant: draftData.applicant || {},
case: draftData.case || {},
contract_or_service: draftData.contract_or_service || {},
offenders: draftData.offenders || [],
claim: draftData.claim || {},
meta: {
...(draftData.meta || {}),
claim_id: finalClaimId,
unified_id: draftData.meta?.unified_id || claim.unified_id || currentFormData.unified_id || null,
},
attachments: draftData.attachments || [],
attachments_count: draftData.attachments_count || 0,
attachments_names: draftData.attachments_names || [],
};
// Возвращаем данные в формате объекта (для компонента StepClaimConfirmation)
const result = {
propertyName: propertyName,
session_token: actualSessionId,
prefix: '',
telegram_id: null,
claim_id: finalClaimId,
unified_id: propertyName.meta.unified_id,
user_id: propertyName.meta.user_id || null,
};
console.log('🔄 transformDraftToClaimPlanFormat: результат из send_to_form_approve:', {
claim_id: result.claim_id,
unified_id: result.unified_id,
hasPropertyName: !!result.propertyName,
hasMeta: !!result.propertyName?.meta,
});
return result;
}
// ✅ ПРИОРИТЕТ 2: Если данных нет в send_to_form_approve, извлекаем из body/payload
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Извлекаем данные из body (telegram) или напрямую из payload (web_form)
const applicantData = body.applicant || payload.applicant || {};
const caseData = body.case || payload.case || {};
const contractData = body.contract_or_service || payload.contract_or_service || {};
const offendersData = body.offenders || payload.offenders || [];
const claimData = body.claim || payload.claim || {};
const metaData = body.meta || payload.meta || {};
const documentsMeta = body.documents_meta || payload.documents_meta || [];
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Извлекаем ответы на вопросы из wizard_answers
const wizardAnswers = body.answers || payload.answers || body.wizard_answers || payload.wizard_answers || {};
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
let answersParsed = wizardAnswers;
if (typeof wizardAnswers === 'string') {
try {
answersParsed = JSON.parse(wizardAnswers);
} catch (e) {
console.warn('⚠️ Не удалось распарсить answers:', e);
answersParsed = {};
}
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
}
console.log('🔄 wizard_answers parsed:', answersParsed);
// Преобразуем wizard_answers в формат propertyName, если данных нет в propertyName формате
// Маппинг полей из wizard_answers в propertyName структуру
const hasPropertyNameData = !!(applicantData.first_name || applicantData.last_name || caseData.category || contractData.subject);
if (!hasPropertyNameData && answersParsed && Object.keys(answersParsed).length > 0) {
console.log('🔄 Преобразуем wizard_answers в propertyName формат');
console.log('🔄 wizard_answers keys:', Object.keys(answersParsed));
// Маппинг полей из wizard_answers в contract_or_service
if (answersParsed.item && !contractData.subject) {
contractData.subject = answersParsed.item;
}
if (answersParsed.price && !contractData.amount_paid) {
// Нормализуем цену (убираем "рублей", пробелы и т.д.)
const priceStr = String(answersParsed.price).replace(/\s+/g, '').replace(/руб(лей|ль|\.)?/gi, '').replace(/₽|р\.|р$/gi, '');
contractData.amount_paid = priceStr;
contractData.amount_paid_fmt = priceStr;
}
if (answersParsed.place_date && !contractData.agreement_date) {
contractData.agreement_date = answersParsed.place_date;
contractData.agreement_date_fmt = answersParsed.place_date;
}
if (answersParsed.cancel_date && !contractData.period_start) {
contractData.period_start = answersParsed.cancel_date;
contractData.period_start_fmt = answersParsed.cancel_date;
}
// Маппинг полей из wizard_answers в claim
if (answersParsed.steps_taken && !claimData.description) {
claimData.description = answersParsed.steps_taken;
}
if (answersParsed.expectation && !claimData.reason) {
// expectation может быть "refund", "replacement", "compensation", "other"
claimData.reason = answersParsed.expectation === 'refund' ? 'consumer' : 'consumer';
}
// Маппинг в case
if (!caseData.category) {
caseData.category = 'consumer'; // По умолчанию consumer
}
if (!caseData.direction) {
caseData.direction = 'web_form';
}
// Если есть problem_description, используем его для claim.description
const problemDesc = payload.problem_description || body.problem_description;
if (problemDesc && !claimData.description) {
claimData.description = problemDesc;
}
if (problemDesc && !contractData.subject) {
contractData.subject = problemDesc;
}
}
// Данные заявителя берутся из других источников (phone, email из claim или formData)
// ФИО, дата рождения, ИНН будут заполняться в форме подтверждения
const applicantPhone = claim.phone || payload.phone || body.phone || currentFormData.phone || null;
const applicantEmail = claim.email || payload.email || body.email || currentFormData.email || null;
// Если есть данные заявителя в applicantData, используем их
if (!applicantData.phone && applicantPhone) {
applicantData.phone = applicantPhone;
}
if (!applicantData.email && applicantEmail) {
applicantData.email = applicantEmail;
}
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Формируем attachments_names из documents_meta
const attachmentsNames = documentsMeta.map((doc: any) => {
return doc.original_file_name || doc.file_name || doc.field_name || 'Документ';
});
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Формируем attachments с полной информацией
const attachments = documentsMeta.map((doc: any) => ({
label: doc.field_label || doc.original_file_name || doc.file_name || doc.field_name || 'Документ', // ✅ Используем field_label
field_label: doc.field_label || doc.field_name || doc.original_file_name || doc.file_name || 'Документ', // ✅ Добавляем field_label отдельно
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
url: doc.file_id ? `https://s3.twcstorage.ru${doc.file_id}` : '',
file_id: doc.file_id || '',
stored_file_name: doc.file_name || '',
original_file_name: doc.original_file_name || doc.file_name || '',
field_name: doc.field_name || '',
uploaded_at: doc.uploaded_at || new Date().toISOString(),
}));
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Формируем propertyName в нужном формате
const propertyName = {
applicant: {
first_name: applicantData.first_name || null,
middle_name: applicantData.middle_name || null,
last_name: applicantData.last_name || null,
full_name: applicantData.full_name || null,
birth_date: applicantData.birth_date || null,
birth_date_fmt: applicantData.birth_date_fmt || null,
birth_place: applicantData.birth_place || null,
inn: applicantData.inn || null,
address: applicantData.address || null,
phone: claim.phone || payload.phone || body.phone || currentFormData.phone || null,
email: claim.email || payload.email || body.email || currentFormData.email || null,
},
case: {
category: caseData.category || payload.case_type || 'consumer',
direction: caseData.direction || 'web_form',
country: caseData.country || null,
},
contract_or_service: {
agreement_date: contractData.agreement_date || null,
agreement_date_fmt: contractData.agreement_date_fmt || null,
amount_paid: contractData.amount_paid || null,
amount_paid_fmt: contractData.amount_paid_fmt || null,
subject: contractData.subject || payload.problem_description || body.problem_description || null,
period_start: contractData.period_start || null,
period_start_fmt: contractData.period_start_fmt || null,
period_end: contractData.period_end || null,
period_end_fmt: contractData.period_end_fmt || null,
period_text: contractData.period_text || null,
},
offenders: offendersData.length > 0 ? offendersData : [],
claim: {
reason: claimData.reason || caseData.category || 'consumer',
description: claimData.description || payload.problem_description || body.problem_description || null,
},
meta: {
claim_id: finalClaimId,
unified_id: claim.unified_id || currentFormData.unified_id || null,
status: claim.status_code || 'draft',
created_at: claim.created_at || new Date().toISOString(),
updated_at: claim.updated_at || new Date().toISOString(),
user_id: metaData.user_id || null,
},
attachments: attachments,
attachments_count: attachments.length,
attachments_names: attachmentsNames,
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
};
// Возвращаем данные в формате объекта (для компонента StepClaimConfirmation)
const result = {
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
propertyName: propertyName,
session_token: actualSessionId,
prefix: '',
telegram_id: null,
claim_id: finalClaimId,
unified_id: claim.unified_id || currentFormData.unified_id || null,
user_id: metaData.user_id || null,
};
console.log('🔄 transformDraftToClaimPlanFormat: результат:', {
claim_id: result.claim_id,
unified_id: result.unified_id,
hasPropertyName: !!result.propertyName,
hasMeta: !!result.propertyName?.meta,
});
return result;
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
}, []);
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
// Загрузка черновика
const loadDraft = useCallback(async (claimId: string) => {
try {
console.log('🔍 Загрузка черновика с ID:', claimId);
const url = `/api/v1/claims/drafts/${claimId}`;
console.log('🔍 URL запроса:', url);
const response = await fetch(url);
console.log('🔍 Статус ответа:', response.status, response.statusText);
if (!response.ok) {
const errorText = await response.text();
console.error('❌ Ошибка загрузки черновика:', response.status, errorText);
throw new Error(`Не удалось загрузить черновик: ${response.status} ${errorText}`);
}
const data = await response.json();
console.log('🔍 Данные черновика загружены:', data);
const claim = data.claim;
const payload = claim.payload || {};
// ✅ Для telegram черновиков данные могут быть в payload.body
const body = payload.body || {};
const isTelegramFormat = !!payload.body;
console.log('🔍 Claim объект:', claim);
console.log('🔍 claim.claim_id:', claim.claim_id);
console.log('🔍 claim.id:', claim.id);
console.log('🔍 claim.unified_id:', claim.unified_id);
console.log('🔍 Payload черновика:', payload);
console.log('🔍 payload.body:', body);
console.log('🔍 Формат:', isTelegramFormat ? 'telegram (body)' : 'web_form (прямой)');
// ✅ Извлекаем данные из body (telegram) или напрямую из payload (web_form)
const wizardPlanRaw = body.wizard_plan || payload.wizard_plan;
const answersRaw = body.answers || payload.answers;
// Ищем problem_description в разных местах (может быть в разных форматах)
const problemDescription =
body.problem_description ||
payload.problem_description ||
body.description ||
payload.description ||
payload.body?.problem_description || // Для вложенных структур
payload.body?.description ||
null;
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
const documentsMeta = body.documents_meta || payload.documents_meta || [];
// ✅ Парсим wizard_plan и answers, если они строки (JSON)
let wizardPlan = wizardPlanRaw;
if (typeof wizardPlanRaw === 'string') {
try {
wizardPlan = JSON.parse(wizardPlanRaw);
} catch (e) {
console.warn('⚠️ Не удалось распарсить wizard_plan:', e);
}
}
let answers = answersRaw;
if (typeof answersRaw === 'string') {
try {
answers = JSON.parse(answersRaw);
} catch (e) {
console.warn('⚠️ Не удалось распарсить answers:', e);
}
}
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
// ✅ Проверяем, заполнены ли все шаги
// Для problem_description: если его нет в payload, но есть wizard_plan и answers,
// значит описание уже было введено ранее (wizard_plan генерируется на основе описания)
const hasDescription = !!problemDescription || (!!wizardPlan && !!answers); // Если есть план и ответы - описание было
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
const hasWizardPlan = !!wizardPlan;
const hasAnswers = !!answers && Object.keys(answers).length > 0;
const hasDocuments = Array.isArray(documentsMeta) && documentsMeta.length > 0;
const isDraft = claim.status_code === 'draft';
const allStepsFilled = hasDescription && hasWizardPlan && hasAnswers && hasDocuments;
const isReadyForConfirmation = allStepsFilled && isDraft;
console.log('🔍 Проверка полноты черновика:', {
hasDescription,
hasWizardPlan,
hasAnswers,
hasDocuments,
isDraft,
allStepsFilled,
isReadyForConfirmation,
problemDescriptionFound: !!problemDescription,
inferredFromPlan: !problemDescription && !!wizardPlan && !!answers,
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
});
console.log('🔍 problem_description:', problemDescription ? 'есть' : (wizardPlan && answers ? 'выведено из наличия плана и ответов' : 'нет'));
console.log('🔍 wizard_plan:', wizardPlan ? 'есть' : 'нет');
console.log('🔍 answers:', answers ? 'есть' : 'нет');
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
console.log('🔍 documents_meta:', documentsMeta.length, 'документов');
console.log('🔍 Все ключи payload:', Object.keys(payload));
if (isTelegramFormat) {
console.log('🔍 Все ключи body:', Object.keys(body));
}
// ✅ Извлекаем claim_id из разных возможных мест
const finalClaimId = claim.claim_id || payload.claim_id || body.claim_id || claim.id || formData.claim_id || claimId;
console.log('🔍 Извлечённый claim_id:', finalClaimId);
// Восстанавливаем данные формы из черновика
console.log('🔄 Загрузка черновика: session_id из черновика:', claim.session_token);
console.log('🔄 Загрузка черновика: текущий sessionIdRef.current:', sessionIdRef.current);
console.log('🔄 Загрузка черновика: текущий formData.session_id:', formData.session_id);
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ При загрузке черновика используем session_id из черновика (для продолжения работы с той же жалобой)
// Если session_id из черновика есть - используем его, иначе текущий
const actualSessionId = claim.session_token || sessionIdRef.current || formData.session_id;
console.log('🔄 Загрузка черновика: ИСПОЛЬЗУЕМ session_id:', actualSessionId);
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ Обновляем sessionIdRef на сессию из черновика (если есть)
if (claim.session_token && claim.session_token !== sessionIdRef.current) {
sessionIdRef.current = claim.session_token;
console.log('🔄 Обновляем sessionIdRef на сессию из черновика:', claim.session_token);
}
// ✅ НОВЫЙ ФЛОУ: Извлекаем documents_required из payload
const documentsRequired = body.documents_required || payload.documents_required || [];
const documentsUploaded = body.documents_uploaded || payload.documents_uploaded || [];
const documentsSkipped = body.documents_skipped || payload.documents_skipped || [];
const currentDocIndex = body.current_doc_index ?? payload.current_doc_index ?? 0;
console.log('📋 Загрузка черновика - documents_required:', documentsRequired.length, 'шт.');
console.log('📋 Загрузка черновика - body.documents_required:', body.documents_required);
console.log('📋 Загрузка черновика - payload.documents_required:', payload.documents_required);
console.log('📋 Загрузка черновика - status_code:', claim.status_code);
console.log('📋 Загрузка черновика - все ключи payload:', Object.keys(payload));
updateFormData({
claim_id: finalClaimId, // ✅ Используем извлечённый claim_id
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
session_id: actualSessionId, // ✅ Используем session_id из черновика (если есть) или текущий
phone: body.phone || payload.phone || formData.phone,
email: body.email || payload.email || formData.email,
problemDescription: problemDescription || formData.problemDescription,
wizardPlan: wizardPlan || formData.wizardPlan,
wizardPlanStatus: wizardPlan ? (answers ? 'answered' : 'ready') : 'pending', // ✅ Устанавливаем статус
wizardAnswers: answers || formData.wizardAnswers,
wizardPrefill: (body.answers_prefill || payload.answers_prefill) ?
(body.answers_prefill || payload.answers_prefill).reduce((acc: any, item: any) => {
acc[item.name] = item.value;
return acc;
}, {}) : formData.wizardPrefill,
wizardPrefillArray: body.answers_prefill || payload.answers_prefill || formData.wizardPrefillArray,
wizardCoverageReport: body.coverage_report || payload.coverage_report || formData.wizardCoverageReport,
wizardUploads: {
documents: (body.documents_meta || payload.documents_meta) ? {} : formData.wizardUploads?.documents,
custom: formData.wizardUploads?.custom || [],
},
wizardSkippedDocuments: body.wizard_skipped_documents || payload.wizard_skipped_documents || formData.wizardSkippedDocuments,
eventType: body.event_type || payload.event_type || formData.eventType,
contact_id: body.contact_id || payload.contact_id || formData.contact_id,
project_id: body.project_id || payload.project_id || formData.project_id,
unified_id: formData.unified_id, // ✅ Сохраняем unified_id
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ НОВЫЙ ФЛОУ: Документы
documents_required: documentsRequired,
documents_uploaded: documentsUploaded,
documents_skipped: documentsSkipped,
current_doc_index: currentDocIndex,
});
setSelectedDraftId(finalClaimId);
setShowDraftSelection(false);
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
// ✅ Если все шаги заполнены и статус = draft → переходим к форме подтверждения
if (isReadyForConfirmation) {
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
console.log('✅ Все шаги заполнены, преобразуем данные для формы подтверждения');
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
setIsPhoneVerified(true);
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Преобразуем данные из БД в формат propertyName для формы подтверждения
const claimPlanData = transformDraftToClaimPlanFormat({
claim,
payload,
body,
isTelegramFormat,
finalClaimId,
actualSessionId,
currentFormData: formData,
});
// Сохраняем данные заявления в formData
updateFormData({
claimPlanData: claimPlanData,
showClaimConfirmation: true,
});
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
refactor: Load claim confirmation data from DB instead of SSE for drafts Problem: - When draft is fully filled, we subscribed to Redis SSE channel claim:plan - But all data already exists in PostgreSQL database - No need to wait for n8n to publish data - we can load it directly Solution: 1. Removed subscribeToClaimPlanForDraft() function - No longer subscribes to SSE channel for drafts - Removed EventSource cleanup code 2. Added transformDraftToClaimPlanFormat() function - Transforms draft data from DB format to propertyName format - Extracts data from payload/body (telegram/web_form formats) - Maps documents_meta to attachments array - Formats applicant, case, contract_or_service, offenders, claim, meta - Returns data in array format expected by confirmation form 3. Updated loadDraft() logic: - When draft is ready for confirmation (all steps filled + draft status) - Calls transformDraftToClaimPlanFormat() instead of subscribing to SSE - Immediately shows confirmation form with data from DB Flow: 1. User selects fully filled draft 2. System checks completeness (description, plan, answers, documents) 3. If ready → transforms DB data to propertyName format 4. Shows confirmation form immediately (no SSE wait) Benefits: - ✅ Faster: no waiting for n8n to publish data - ✅ More reliable: data always available from DB - ✅ Simpler: no SSE connection management for drafts - ✅ Works offline: doesn't depend on Redis pub/sub Files: - frontend/src/pages/ClaimForm.tsx: Added transform function, removed SSE subscription
2025-11-24 15:08:00 +03:00
// Переход к шагу подтверждения произойдёт автоматически через useEffect
setCurrentStep(2); // StepWizardPlan (временно, useEffect переключит на подтверждение)
feat: Auto-navigate to confirmation form when draft is fully filled Problem: - When user selects a draft with all steps filled (description, plan, answers, documents) - But claim status is still 'draft' (not submitted) - User has to manually navigate through all steps again Solution: 1. Added check in loadDraft() to detect fully filled drafts: - hasDescription: problem_description exists - hasWizardPlan: wizard_plan exists - hasAnswers: answers exist and not empty - hasDocuments: documents_meta array has items - isDraft: status_code === 'draft' - allStepsFilled: all checks pass 2. When draft is ready for confirmation: - Automatically subscribe to claim:plan SSE channel - Wait for claim data from n8n - Show loading message while waiting - On success: show confirmation form automatically 3. Added subscribeToClaimPlanForDraft() function: - Subscribes to /api/v1/claim-plan/{session_token} - Handles claim_plan_ready event - Updates formData with claimPlanData - Auto-navigates to confirmation step via useEffect 4. Added useEffect for auto-navigation: - Watches formData.showClaimConfirmation and formData.claimPlanData - When both true, navigates to step 3 (confirmation) - Handles cleanup of EventSource on unmount Flow: 1. User selects draft → loadDraft() checks completeness 2. If all filled + draft → subscribeToClaimPlanForDraft() 3. SSE receives data → updates formData 4. useEffect detects → navigates to confirmation step 5. User sees confirmation form immediately Files: - frontend/src/pages/ClaimForm.tsx: Added auto-navigation logic
2025-11-24 14:11:04 +03:00
return;
}
// ✅ Определяем шаг для перехода на основе данных черновика
// Приоритет: если есть wizard_plan → переходим к визарду (даже если нет problem_description)
// После выбора черновика showDraftSelection = false, поэтому:
// - Шаг 0 = Step1Phone (но мы его пропускаем, т.к. телефон уже верифицирован)
// - Шаг 1 = StepDescription
// - Шаг 2 = StepWizardPlan
let targetStep = 1; // По умолчанию - описание (шаг 1)
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ НОВЫЙ ФЛОУ: Если есть documents_required, показываем загрузку документов
if (documentsRequired.length > 0) {
targetStep = 2;
console.log('✅ Переходим к StepWizardPlan (шаг 2) - НОВЫЙ ФЛОУ: есть documents_required, показываем загрузку документов');
console.log('✅ documents_required:', documentsRequired.length, 'документов');
} else if (wizardPlan) {
// ✅ СТАРЫЙ ФЛОУ: Если есть wizard_plan - переходим к визарду (шаг 2)
// Пользователь уже описывал проблему, и есть план вопросов
targetStep = 2;
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
console.log('✅ Переходим к StepWizardPlan (шаг 2) - СТАРЫЙ ФЛОУ: есть wizard_plan');
console.log('✅ answers в черновике:', answers ? 'есть (показываем заполненную форму)' : 'нет (показываем пустую форму)');
} else if (problemDescription) {
// Если есть описание, но нет плана - переходим к визарду (шаг 2), чтобы получить план
targetStep = 2;
console.log('✅ Переходим к StepWizardPlan (шаг 2) - есть описание, план будет получен через SSE');
} else {
// Если нет ничего - переходим к описанию (шаг 1)
targetStep = 1;
console.log('✅ Переходим к StepDescription (шаг 1) - нет описания и плана');
}
console.log('🔍 Устанавливаем currentStep:', targetStep);
// ✅ Устанавливаем isPhoneVerified = true, чтобы пропустить шаг телефона
setIsPhoneVerified(true);
setCurrentStep(targetStep);
} catch (error) {
console.error('Ошибка загрузки черновика:', error);
message.error('Не удалось загрузить черновик');
}
}, [formData, updateFormData]);
// Обработчик выбора черновика
const handleSelectDraft = useCallback((claimId: string) => {
loadDraft(claimId);
}, [loadDraft]);
// Проверка наличия черновиков
const checkDrafts = useCallback(async (unified_id?: string, phone?: string, sessionId?: string) => {
try {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 ========== checkDrafts вызван ==========');
console.log('🔍 Параметры:', { unified_id, phone, sessionId });
const params = new URLSearchParams();
// Приоритет: unified_id > phone > session_id
if (unified_id) {
params.append('unified_id', unified_id);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Используем unified_id:', unified_id);
} else if (phone) {
params.append('phone', phone);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Используем phone:', phone);
} else if (sessionId) {
params.append('session_id', sessionId);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Используем session_id:', sessionId);
} else {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.warn('⚠️ Нет параметров для поиска черновиков');
return false;
}
const url = `/api/v1/claims/drafts/list?${params.toString()}`;
console.log('🔍 Запрос черновиков:', url);
const response = await fetch(url);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Статус ответа:', response.status, response.statusText);
if (!response.ok) {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
const errorText = await response.text();
console.error('❌ Ошибка запроса черновиков:', response.status, response.statusText, errorText);
return false;
}
const data = await response.json();
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Полный ответ API черновиков:', JSON.stringify(data, null, 2));
console.log('🔍 Debug info от backend:', data.debug_info || data.debug);
const count = data.count || 0;
console.log('🔍 Количество черновиков:', count);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Список черновиков:', data.drafts);
setHasDrafts(count > 0);
setShowDraftSelection(count > 0);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Установлены флаги: hasDrafts=', count > 0, 'showDraftSelection=', count > 0);
console.log('🔍 ========== checkDrafts завершён ==========');
return count > 0;
} catch (error) {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.error('❌ Ошибка проверки черновиков:', error);
console.error('❌ Stack trace:', (error as Error).stack);
return false;
}
}, []);
// Обработчик создания новой заявки
const handleNewClaim = useCallback(() => {
console.log('🆕 Начинаем новое обращение');
console.log('🆕 Текущий currentStep:', currentStep);
console.log('🆕 isPhoneVerified:', isPhoneVerified);
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ Генерируем НОВУЮ сессию для новой жалобы
const newSessionId = 'sess_' + generateUUIDv4();
console.log('🆕 Генерируем новую сессию для жалобы:', newSessionId);
console.log('🆕 Старая сессия:', sessionIdRef.current);
// ✅ Обновляем sessionIdRef на новую сессию
sessionIdRef.current = newSessionId;
// ✅ session_token в localStorage остаётся ПРЕЖНИМ (авторизация сохраняется)
const savedSessionToken = localStorage.getItem('session_token');
console.log('🆕 session_token в localStorage (авторизация):', savedSessionToken || '(не сохранён)');
console.log('🆕 Авторизация сохранена: unified_id=', formData.unified_id, 'phone=', formData.phone);
setShowDraftSelection(false);
setSelectedDraftId(null);
setHasDrafts(false); // ✅ Сбрасываем флаг наличия черновиков
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ Очищаем данные формы и устанавливаем НОВЫЙ session_id
// unified_id, phone, contact_id остаются прежними - авторизация сохранена!
updateFormData({
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
session_id: newSessionId, // ✅ Новая сессия для новой жалобы
claim_id: undefined,
problemDescription: undefined,
wizardPlan: undefined,
wizardAnswers: undefined,
wizardPrefill: undefined,
wizardPrefillArray: undefined,
wizardCoverageReport: undefined,
wizardUploads: undefined,
wizardSkippedDocuments: undefined,
eventType: undefined,
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
// ✅ unified_id, phone, contact_id НЕ очищаем - авторизация сохраняется!
});
console.log('🆕 Переходим к шагу описания проблемы (пропускаем Phone и DraftSelection)');
// ✅ Переходим к шагу описания проблемы
// После сброса флагов черновиков, steps будут:
// Шаг 0 - Phone (уже верифицирован, но в массиве есть)
// Шаг 1 - Description (сюда переходим)
// Шаг 2 - WizardPlan
setCurrentStep(1); // ✅ Переходим к описанию (индекс 1)
fix: Исправление загрузки документов и SQL запросов - Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
2025-11-26 19:54:51 +03:00
}, [updateFormData, currentStep, isPhoneVerified, formData.unified_id, formData.phone]);
const handleSubmit = useCallback(async () => {
try {
addDebugEvent('form', 'info', '📤 Отправка заявки в n8n через backend');
const payload = {
stage: 'final',
form_id: 'ticket_form',
session_id: formData.session_id ?? sessionIdRef.current,
client_ip: formData.clientIp,
sms_code: formData.smsCode,
// Базовые идентификаторы
claim_id: formData.claim_id,
contact_id: formData.contact_id,
project_id: formData.project_id,
ticket_id: formData.ticket_id,
is_new_contact: formData.is_new_contact,
is_new_project: formData.is_new_project,
// Основные поля формы (для удобства в n8n)
voucher: formData.voucher,
phone: formData.phone,
email: formData.email,
event_type: formData.eventType,
payment_method: formData.paymentMethod,
bank_name: formData.bankName,
card_number: formData.cardNumber,
account_number: formData.accountNumber,
// Старый блок документов + новые загрузки визарда (пока как есть)
documents: formData.documents || {},
wizard_uploads: formData.wizardUploads || {},
// Всё состояние формы целиком — на всякий случай
form: formData,
};
const response = await fetch('/api/v1/claims/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const text = await response.text();
let parsed: any = null;
try {
parsed = text ? JSON.parse(text) : null;
} catch {
parsed = null;
}
if (!response.ok) {
message.error('Ошибка при создании заявки (n8n)');
addDebugEvent('form', 'error', '❌ Ошибка создания заявки в n8n', {
status: response.status,
body: text,
});
return;
}
addDebugEvent('form', 'success', '✅ Финальный webhook в n8n отработал', {
response: parsed ?? text,
});
// Помечаем, что заявка отправлена, и показываем заглушку.
setIsSubmitted(true);
message.success('Данные отправлены, заявка принята в обработку.');
} catch (error) {
message.error('Ошибка соединения с сервером');
addDebugEvent('form', 'error', '❌ Ошибка соединения', { error: String(error) });
console.error(error);
}
}, [formData, addDebugEvent]);
// Динамически генерируем шаги на основе выбранного eventType
const steps = useMemo(() => {
const stepsArray: any[] = [];
// Шаг 0: Выбор черновика (показывается только если есть черновики)
// ✅ unified_id уже означает, что телефон верифицирован
// Показываем шаг, если showDraftSelection=true ИЛИ если есть unified_id и hasDrafts
if ((showDraftSelection || (formData.unified_id && hasDrafts)) && !selectedDraftId) {
stepsArray.push({
title: 'Черновики',
description: 'Выбор заявки',
content: (
<StepDraftSelection
phone={formData.phone || ''}
session_id={sessionIdRef.current}
unified_id={formData.unified_id} // ✅ Передаём unified_id
onSelectDraft={handleSelectDraft}
onNewClaim={handleNewClaim}
/>
),
});
}
// Шаг 1: Phone (телефон + SMS верификация)
stepsArray.push({
title: 'Телефон',
description: 'Подтверждение по SMS',
content: (
<Step1Phone
formData={{ ...formData, session_id: formData.session_id || sessionIdRef.current }} // ✅ Используем session_id из formData (от n8n) или временный
updateFormData={(data: any) => {
updateFormData(data);
// ✅ Если n8n вернул session_id, обновляем ref
if (data.session_id && data.session_id !== sessionIdRef.current) {
console.log('🔄 Обновляем sessionIdRef на значение от n8n:', data.session_id);
sessionIdRef.current = data.session_id;
}
// ❌ Убрано: проверка черновиков здесь избыточна, т.к. она уже есть в onNext
}}
onNext={async (unified_id?: string) => {
console.log('🔥 onNext вызван с unified_id:', unified_id);
console.log('🔥 formData.unified_id:', formData.unified_id);
console.log('🔥 isPhoneVerified:', isPhoneVerified);
console.log('🔥 selectedDraftId:', selectedDraftId);
// После верификации проверяем черновики
// Используем unified_id из параметра (если передан) или из formData
const finalUnifiedId = unified_id || formData.unified_id;
console.log('🔥 finalUnifiedId:', finalUnifiedId);
// ✅ Если передан unified_id, значит телефон уже верифицирован (даже если isPhoneVerified ещё false)
// Проверяем черновики, если есть unified_id или телефон верифицирован
const shouldCheckDrafts = finalUnifiedId || (formData.phone && isPhoneVerified);
if (shouldCheckDrafts && !selectedDraftId) {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Проверка черновиков с unified_id:', finalUnifiedId, 'phone:', formData.phone, 'sessionId:', sessionIdRef.current);
const hasDraftsResult = await checkDrafts(finalUnifiedId, formData.phone, sessionIdRef.current);
console.log('🔍 Результат checkDrafts:', hasDraftsResult);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('🔍 Текущие флаги после checkDrafts: hasDrafts=', hasDrafts, 'showDraftSelection=', showDraftSelection);
if (hasDraftsResult) {
console.log('✅ Есть черновики, переходим к шагу 0');
// ✅ ВАЖНО: Сначала устанавливаем флаги, потом переходим на шаг 0
setShowDraftSelection(true);
setHasDrafts(true);
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
// ✅ Используем setTimeout для гарантии, что React обновил состояние
setTimeout(() => {
console.log('🔄 Переходим на шаг 0 после установки флагов');
setCurrentStep(0); // Переходим к шагу выбора черновика
}, 100);
console.log('🛑 Остановка выполнения onNext - есть черновики');
return; // ✅ ВАЖНО: Не идём дальше, если есть черновики
} else {
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
console.log('❌ Нет черновиков, идем дальше к описанию проблемы');
// Нет черновиков - идём дальше
nextStep();
return;
}
} else {
console.log('⚠️ Условие не выполнено для проверки черновиков:', {
shouldCheckDrafts,
selectedDraftId,
finalUnifiedId,
phone: formData.phone,
isPhoneVerified
});
// Условие не выполнено - идём дальше
nextStep();
return;
}
// ❌ ЭТОТ КОД НЕ ДОЛЖЕН ВЫПОЛНЯТЬСЯ, если есть return выше
console.error('❌❌❌ КРИТИЧЕСКАЯ ОШИБКА: nextStep() вызван после return!');
nextStep();
}}
onPrev={prevStep}
isPhoneVerified={isPhoneVerified}
setIsPhoneVerified={(verified: boolean) => {
setIsPhoneVerified(verified);
// ❌ Убрано: проверка черновиков делается только в onNext
// onNext вызывается после успешной верификации и содержит unified_id
}}
addDebugEvent={addDebugEvent}
/>
),
});
// Шаг 2: свободное описание
stepsArray.push({
title: 'Описание',
description: 'Что случилось?',
content: (
<StepDescription
formData={formData}
updateFormData={updateFormData}
onPrev={prevStep}
onNext={nextStep}
/>
),
});
// Шаг 3: AI Рекомендации
stepsArray.push({
title: 'Рекомендации',
description: 'AI ассистент',
content: (
<StepWizardPlan
formData={formData}
updateFormData={updateFormData}
onPrev={prevStep}
onNext={nextStep}
addDebugEvent={addDebugEvent}
/>
),
});
feat: Add claim plan confirmation flow via Redis SSE Problem: - After wizard form submission, need to wait for claim data from n8n - Claim data comes via Redis channel claim:plan:{session_token} - Need to display confirmation form with claim data Solution: 1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token} - Subscribes to Redis channel claim:plan:{session_token} - Streams claim data from n8n to frontend - Handles timeouts and errors gracefully 2. Frontend: Added subscription to claim:plan channel - StepWizardPlan: After form submission, subscribes to SSE - Waits for claim_plan_ready event - Shows loading message while waiting - On success: saves claimPlanData and shows confirmation step 3. New component: StepClaimConfirmation - Displays claim confirmation form in iframe - Receives claimPlanData from parent - Generates HTML form (placeholder - should call n8n for real HTML) - Handles confirmation/cancellation via postMessage 4. ClaimForm: Added conditional step for confirmation - Shows StepClaimConfirmation when showClaimConfirmation=true - Step appears after StepWizardPlan - Only visible when claimPlanData is available Flow: 1. User fills wizard form → submits 2. Form data sent to n8n via /api/v1/claims/wizard 3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token} 4. n8n processes data → publishes to Redis claim:plan:{session_token} 5. Backend receives → streams to frontend via SSE 6. Frontend receives → shows StepClaimConfirmation 7. User confirms → proceeds to next step Files: - backend/app/api/events.py: Added stream_claim_plan endpoint - frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan - frontend/src/components/form/StepClaimConfirmation.tsx: New component - frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00
// Шаг подтверждения заявления (показывается после получения данных из claim:plan)
if (formData.showClaimConfirmation && formData.claimPlanData) {
stepsArray.push({
title: 'Подтверждение',
description: 'Проверка данных',
content: (
<StepClaimConfirmation
claimPlanData={formData.claimPlanData}
onPrev={prevStep}
onNext={nextStep}
/>
),
});
}
// Шаг 3: Policy (всегда)
stepsArray.push({
title: 'Проверка полиса',
description: 'Полис ERV',
content: (
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
<Step1Policy
formData={{ ...formData, session_id: sessionIdRef.current }} // ✅ claim_id уже в formData от n8n
feat: Интеграция n8n + Redis Pub/Sub + SSE для real-time обработки заявок 🎯 Основные изменения: Backend: - ✅ Добавлен SSE endpoint для real-time событий (/api/v1/events/{task_id}) - ✅ Redis Pub/Sub для публикации/подписки на события OCR/Vision - ✅ Удален aioboto3 из requirements.txt (конфликт зависимостей) - ✅ Добавлен OCR worker (deprecated, логика перенесена в n8n) Frontend (React): - ✅ Автогенерация claim_id и session_id - ✅ Клиентская конвертация файлов в PDF (JPG/PNG/HEIC/WEBP) - ✅ Сжатие изображений до 2MB перед конвертацией - ✅ SSE подписка на события OCR/Vision в Step1Policy - ✅ Валидация документов (полис vs неподходящий контент) - ✅ Real-time прогресс загрузки и обработки файлов - ✅ Интеграция с n8n webhooks для проверки полиса и загрузки файлов n8n Workflows: - ✅ Проверка полиса в MySQL + запись в PostgreSQL - ✅ Загрузка файлов в S3 + OCR + Vision AI - ✅ Публикация событий в Redis через backend API - ✅ Валидация документов (распознавание полисов ERV) Документация: - 📝 N8N_INTEGRATION.md - интеграция с n8n - 📝 N8N_SQL_QUERIES.md - SQL запросы для workflows - 📝 N8N_PDF_COMPRESS.md - сжатие PDF - 📝 N8N_STIRLING_COMPRESS.md - интеграция Stirling-PDF Утилиты: - 🔧 monitor_redis.py/sh - мониторинг Redis Pub/Sub - 🔧 test_redis_events.sh - тестирование событий - 🔧 pdfConverter.ts - клиентская конвертация в PDF Архитектура: React → n8n webhooks (sync) → MySQL/PostgreSQL/S3 → n8n workflows (async) → OCR/Vision → Redis Pub/Sub → SSE → React
2025-10-27 08:33:16 +03:00
updateFormData={updateFormData}
onNext={nextStep}
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
addDebugEvent={addDebugEvent}
/>
),
});
// Шаг 4: Event Type Selection (всегда)
stepsArray.push({
title: 'Тип события',
description: 'Выбор случая',
content: (
<Step2EventType
formData={formData}
updateFormData={updateFormData}
onNext={nextStep}
onPrev={prevStep}
addDebugEvent={addDebugEvent}
/>
),
});
// Шаги 3+: Document Upload (динамически, если выбран eventType)
if (formData.eventType && documentConfigs.length > 0) {
documentConfigs.forEach((docConfig, index) => {
stepsArray.push({
title: `Документ ${index + 1}`,
description: docConfig.name,
content: (
<StepDocumentUpload
key={`doc-${docConfig.file_type}`}
documentConfig={docConfig}
formData={formData}
updateFormData={updateFormData}
onNext={nextStep}
onPrev={prevStep}
isLastDocument={index === documentConfigs.length - 1}
currentDocNumber={index + 1}
totalDocs={documentConfigs.length}
/>
),
});
});
}
// Последний шаг: Payment (всегда)
stepsArray.push({
title: 'Оплата',
description: 'Контакты и выплата',
content: (
<Step3Payment
formData={formData} // ✅ claim_id уже в formData
updateFormData={updateFormData}
onPrev={prevStep}
onSubmit={handleSubmit}
isPhoneVerified={isPhoneVerified}
setIsPhoneVerified={setIsPhoneVerified}
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
addDebugEvent={addDebugEvent}
/>
),
});
return stepsArray;
}, [formData, documentConfigs, isPhoneVerified, nextStep, prevStep, updateFormData, handleSubmit, setIsPhoneVerified, addDebugEvent, showDraftSelection, selectedDraftId, hasDrafts, handleSelectDraft, handleNewClaim, checkDrafts]);
feat: 5 улучшений безопасности и UX 1. ✅ Прогресс бар загрузки: - Upload компонент с showUploadList - Кнопка показывает состояние 'Загрузка...' - Визуальный прогресс для каждого файла 2. ✅ OCR проверка полиса (заготовка): - TODO: проверка что загружен полис, а не шляпа - Если шляпа - помечаем себе в policyValidationWarning - Пользователю не говорим (silent validation) 3. ✅ Лимиты файлов: - Максимум 10 файлов - Каждый файл до 15MB - Валидация на фронте и бэкенде - Счетчик: 'Загружено: X/10 файлов' - Кнопка disabled при 10 файлах 4. ✅ Защита от инъекций и безопасность: Backend (upload.py): - Лимит файлов: if len(files) > 10 - Проверка размера: if len(content) > MAX_FILE_SIZE - Валидация типа: allowed_types = ['image/', 'application/pdf'] - Санитизация folder: allowed_folders whitelist Backend (draft.py): - Валидация session_id (max 255 chars) - Валидация step: only [1, 2, 3] - Параметризованные SQL запросы (защита от SQL injection) Frontend: - beforeUpload валидация размера - maxCount={10} - accept только разрешенные форматы 5. ✅ Кнопка 'Начать заново': - Показывается на шаге 2 и 3 (extra в Card) - Сбрасывает всю форму - Возвращает на шаг 1 - Очищает isPhoneVerified Безопасность: - SQL инъекции: параметризованные запросы ($1, $2) - XSS: Pydantic валидация всех inputs - File upload: type + size validation - Path traversal: folder whitelist - Rate limiting: TODO (Redis) UX: - Прогресс загрузки виден - Понятные лимиты (10 файлов по 15MB) - Возможность начать заново в любой момент
2025-10-24 21:34:50 +03:00
const handleReset = () => {
setIsSubmitted(false);
feat: 5 улучшений безопасности и UX 1. ✅ Прогресс бар загрузки: - Upload компонент с showUploadList - Кнопка показывает состояние 'Загрузка...' - Визуальный прогресс для каждого файла 2. ✅ OCR проверка полиса (заготовка): - TODO: проверка что загружен полис, а не шляпа - Если шляпа - помечаем себе в policyValidationWarning - Пользователю не говорим (silent validation) 3. ✅ Лимиты файлов: - Максимум 10 файлов - Каждый файл до 15MB - Валидация на фронте и бэкенде - Счетчик: 'Загружено: X/10 файлов' - Кнопка disabled при 10 файлах 4. ✅ Защита от инъекций и безопасность: Backend (upload.py): - Лимит файлов: if len(files) > 10 - Проверка размера: if len(content) > MAX_FILE_SIZE - Валидация типа: allowed_types = ['image/', 'application/pdf'] - Санитизация folder: allowed_folders whitelist Backend (draft.py): - Валидация session_id (max 255 chars) - Валидация step: only [1, 2, 3] - Параметризованные SQL запросы (защита от SQL injection) Frontend: - beforeUpload валидация размера - maxCount={10} - accept только разрешенные форматы 5. ✅ Кнопка 'Начать заново': - Показывается на шаге 2 и 3 (extra в Card) - Сбрасывает всю форму - Возвращает на шаг 1 - Очищает isPhoneVerified Безопасность: - SQL инъекции: параметризованные запросы ($1, $2) - XSS: Pydantic валидация всех inputs - File upload: type + size validation - Path traversal: folder whitelist - Rate limiting: TODO (Redis) UX: - Прогресс загрузки виден - Понятные лимиты (10 файлов по 15MB) - Возможность начать заново в любой момент
2025-10-24 21:34:50 +03:00
setFormData({
voucher: '',
claim_id: undefined, // ✅ Очищаем для новой заявки
session_id: sessionIdRef.current,
feat: 5 улучшений безопасности и UX 1. ✅ Прогресс бар загрузки: - Upload компонент с showUploadList - Кнопка показывает состояние 'Загрузка...' - Визуальный прогресс для каждого файла 2. ✅ OCR проверка полиса (заготовка): - TODO: проверка что загружен полис, а не шляпа - Если шляпа - помечаем себе в policyValidationWarning - Пользователю не говорим (silent validation) 3. ✅ Лимиты файлов: - Максимум 10 файлов - Каждый файл до 15MB - Валидация на фронте и бэкенде - Счетчик: 'Загружено: X/10 файлов' - Кнопка disabled при 10 файлах 4. ✅ Защита от инъекций и безопасность: Backend (upload.py): - Лимит файлов: if len(files) > 10 - Проверка размера: if len(content) > MAX_FILE_SIZE - Валидация типа: allowed_types = ['image/', 'application/pdf'] - Санитизация folder: allowed_folders whitelist Backend (draft.py): - Валидация session_id (max 255 chars) - Валидация step: only [1, 2, 3] - Параметризованные SQL запросы (защита от SQL injection) Frontend: - beforeUpload валидация размера - maxCount={10} - accept только разрешенные форматы 5. ✅ Кнопка 'Начать заново': - Показывается на шаге 2 и 3 (extra в Card) - Сбрасывает всю форму - Возвращает на шаг 1 - Очищает isPhoneVerified Безопасность: - SQL инъекции: параметризованные запросы ($1, $2) - XSS: Pydantic валидация всех inputs - File upload: type + size validation - Path traversal: folder whitelist - Rate limiting: TODO (Redis) UX: - Прогресс загрузки виден - Понятные лимиты (10 файлов по 15MB) - Возможность начать заново в любой момент
2025-10-24 21:34:50 +03:00
paymentMethod: 'sbp',
});
setCurrentStep(0);
setIsPhoneVerified(false);
message.info('Форма сброшена');
addDebugEvent('system', 'info', '🔄 Форма сброшена');
feat: 5 улучшений безопасности и UX 1. ✅ Прогресс бар загрузки: - Upload компонент с showUploadList - Кнопка показывает состояние 'Загрузка...' - Визуальный прогресс для каждого файла 2. ✅ OCR проверка полиса (заготовка): - TODO: проверка что загружен полис, а не шляпа - Если шляпа - помечаем себе в policyValidationWarning - Пользователю не говорим (silent validation) 3. ✅ Лимиты файлов: - Максимум 10 файлов - Каждый файл до 15MB - Валидация на фронте и бэкенде - Счетчик: 'Загружено: X/10 файлов' - Кнопка disabled при 10 файлах 4. ✅ Защита от инъекций и безопасность: Backend (upload.py): - Лимит файлов: if len(files) > 10 - Проверка размера: if len(content) > MAX_FILE_SIZE - Валидация типа: allowed_types = ['image/', 'application/pdf'] - Санитизация folder: allowed_folders whitelist Backend (draft.py): - Валидация session_id (max 255 chars) - Валидация step: only [1, 2, 3] - Параметризованные SQL запросы (защита от SQL injection) Frontend: - beforeUpload валидация размера - maxCount={10} - accept только разрешенные форматы 5. ✅ Кнопка 'Начать заново': - Показывается на шаге 2 и 3 (extra в Card) - Сбрасывает всю форму - Возвращает на шаг 1 - Очищает isPhoneVerified Безопасность: - SQL инъекции: параметризованные запросы ($1, $2) - XSS: Pydantic валидация всех inputs - File upload: type + size validation - Path traversal: folder whitelist - Rate limiting: TODO (Redis) UX: - Прогресс загрузки виден - Понятные лимиты (10 файлов по 15MB) - Возможность начать заново в любой момент
2025-10-24 21:34:50 +03:00
};
// Обработчик кнопки "Выход" - завершить сессию и вернуться к Step1Phone
const handleExitToList = useCallback(async () => {
console.log('🚪 Выход из системы');
addDebugEvent('system', 'info', '🚪 Выход из системы');
// Получаем session_token из localStorage
const sessionToken = localStorage.getItem('session_token') || formData.session_id;
if (sessionToken) {
try {
// Вызываем API logout для удаления сессии из Redis
const response = await fetch('/api/v1/session/logout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_token: sessionToken })
});
if (response.ok) {
console.log('✅ Сессия удалена из Redis');
addDebugEvent('session', 'success', '✅ Сессия завершена');
}
} catch (error) {
console.warn('⚠️ Ошибка при завершении сессии:', error);
}
}
// Удаляем session_token из localStorage
localStorage.removeItem('session_token');
// Сбрасываем форму
handleReset();
message.info('Сессия завершена. До свидания!');
}, [formData.session_id, addDebugEvent]);
return (
<div className="claim-form-container" style={{ padding: '20px', background: '#ffffff' }}>
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
<Row gutter={16}>
{/* Левая часть - Форма */}
<Col xs={24} lg={14}>
<Card
title="Подать заявку на выплату"
className="claim-form-card"
extra={
!isSubmitted && (
<Space>
{/* Кнопка "Выход" - показываем если телефон верифицирован */}
{isPhoneVerified && (
<button
onClick={handleExitToList}
style={{
padding: '4px 12px',
background: '#fff',
border: '1px solid #ff4d4f',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '14px',
color: '#ff4d4f'
}}
>
🚪 Выход
</button>
)}
{/* Кнопка "Начать заново" - показываем только после шага телефона */}
{currentStep > 0 && (
<button
onClick={handleReset}
style={{
padding: '4px 12px',
background: '#fff',
border: '1px solid #d9d9d9',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '14px'
}}
>
🔄 Начать заново
</button>
)}
</Space>
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
)
}
>
{isSubmitted ? (
<div style={{ padding: '40px 0', textAlign: 'center' }}>
<h3 style={{ fontSize: 22, marginBottom: 8 }}>Мы изучаем ваш вопрос и документы</h3>
<p style={{ color: '#666666', maxWidth: 480, margin: '0 auto 24px' }}>
Заявка отправлена в работу. Юристы проверят информацию и свяжутся с вами по указанным контактам.
</p>
</div>
) : (
<>
<Steps current={currentStep} className="steps">
{steps.map((item, index) => (
<Step
key={`step-${index}`}
title={item.title}
description={item.description}
/>
))}
</Steps>
<div className="steps-content">
{steps[currentStep] ? steps[currentStep].content : (
<div style={{ padding: '40px 0', textAlign: 'center' }}>
<p>Загрузка шага...</p>
</div>
)}
</div>
</>
)}
feat: Split-screen с Debug панелью в реальном времени! Новый UI: ✅ Split-screen layout: - Слева (60%): форма заявки - Справа (40%): Debug Console в реальном времени Компонент DebugPanel.tsx: ✅ Темная тема (VS Code style) ✅ Timeline с событиями ✅ Real-time обновления ✅ Показывает: - Form Data (JSON в реальном времени) - Events Log с иконками и цветами - Детали каждого события События которые отображаются: 1. policy_check: - ✅ Полис найден в MySQL БД - ⚠️ Полис не найден - Показывает: voucher, found status 2. upload: - 📤 Загружаю X файлов в S3 - ✅ Загружено в S3: X/Y - Показывает: file_id, size, S3 URL 3. ocr: - 🔍 Запущен OCR - 📄 OCR завершен: XXX символов - Показывает: текст preview 4. ai_analysis: - 🤖 AI: policy/garbage, confidence: 95% - 🗑️ ШЛЯПА DETECTED! (пользователю не говорим) - Показывает: document_type, is_valid, confidence, extracted_data 5. sms: - 📱 Отправляю SMS - ✅ SMS отправлен (DEBUG mode) - 🔐 Проверяю код - ✅ Телефон подтвержден - Показывает: phone, debug_code UX: - Sticky panel (прилипает при скролле) - Monospace шрифт для данных - Цветовая кодировка статусов - JSON форматирование Layout: - Row + Col от Ant Design - Responsive: mobile = 1 column, desktop = split Теперь видно ВСЁ что происходит в реальном времени! 🔍
2025-10-24 22:13:52 +03:00
</Card>
</Col>
{/* Правая часть - Debug консоль */}
<Col xs={24} lg={10}>
<DebugPanel events={debugEvents} formData={formData} />
</Col>
</Row>
</div>
);
}