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 Теперь видно ВСЁ что происходит в реальном времени! 🔍
This commit is contained in:
@@ -7,6 +7,7 @@ interface Props {
|
||||
formData: any;
|
||||
updateFormData: (data: any) => void;
|
||||
onNext: () => void;
|
||||
addDebugEvent?: (type: string, status: string, message: string, data?: any) => void;
|
||||
}
|
||||
|
||||
// Расширенная функция автозамены кириллицы на латиницу
|
||||
@@ -49,7 +50,7 @@ const formatVoucher = (value: string): string => {
|
||||
}
|
||||
};
|
||||
|
||||
export default function Step1Policy({ formData, updateFormData, onNext }: Props) {
|
||||
export default function Step1Policy({ formData, updateFormData, onNext, addDebugEvent }: Props) {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [policyNotFound, setPolicyNotFound] = useState(false);
|
||||
@@ -77,6 +78,8 @@ export default function Step1Policy({ formData, updateFormData, onNext }: Props)
|
||||
setLoading(true);
|
||||
setPolicyNotFound(false);
|
||||
|
||||
addDebugEvent?.('policy_check', 'pending', `Проверяю полис: ${values.voucher}`, { voucher: values.voucher });
|
||||
|
||||
// Проверка полиса через API
|
||||
const response = await fetch('http://147.45.146.17:8100/api/v1/policy/check', {
|
||||
method: 'POST',
|
||||
@@ -92,15 +95,24 @@ export default function Step1Policy({ formData, updateFormData, onNext }: Props)
|
||||
if (response.ok) {
|
||||
if (result.found) {
|
||||
// Полис найден - переходим дальше
|
||||
addDebugEvent?.('policy_check', 'success', `✅ Полис найден в MySQL БД (33,963 полисов)`, {
|
||||
found: true,
|
||||
voucher: values.voucher
|
||||
});
|
||||
message.success('Полис найден в базе данных');
|
||||
updateFormData(values);
|
||||
onNext();
|
||||
} else {
|
||||
// Полис НЕ найден - показываем загрузку скана
|
||||
addDebugEvent?.('policy_check', 'warning', `⚠️ Полис не найден → требуется загрузка скана`, {
|
||||
found: false,
|
||||
voucher: values.voucher
|
||||
});
|
||||
message.warning('Полис не найден в базе. Загрузите скан полиса');
|
||||
setPolicyNotFound(true);
|
||||
}
|
||||
} else {
|
||||
addDebugEvent?.('policy_check', 'error', `❌ Ошибка API: ${result.detail}`, { error: result.detail });
|
||||
message.error(result.detail || 'Ошибка проверки полиса');
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -133,6 +145,10 @@ export default function Step1Policy({ formData, updateFormData, onNext }: Props)
|
||||
setUploading(true);
|
||||
const values = await form.validateFields(['voucher']);
|
||||
|
||||
addDebugEvent?.('upload', 'pending', `📤 Загружаю ${fileList.length} файл(ов) в S3...`, {
|
||||
count: fileList.length
|
||||
});
|
||||
|
||||
// Загружаем файлы в S3 с OCR проверкой
|
||||
const formData = new FormData();
|
||||
fileList.forEach((file: any) => {
|
||||
@@ -150,19 +166,59 @@ export default function Step1Policy({ formData, updateFormData, onNext }: Props)
|
||||
const uploadResult = await uploadResponse.json();
|
||||
|
||||
if (uploadResult.success) {
|
||||
// TODO: OCR проверка что это полис, а не шляпа
|
||||
// Если шляпа - помечаем себе, пользователю не говорим
|
||||
addDebugEvent?.('upload', 'success', `✅ Загружено в S3: ${uploadResult.uploaded_count}/${uploadResult.total_count}`, {
|
||||
uploaded_count: uploadResult.uploaded_count,
|
||||
files: uploadResult.files
|
||||
});
|
||||
|
||||
// Проверяем OCR результаты
|
||||
if (uploadResult.files && uploadResult.files.length > 0) {
|
||||
const firstFile = uploadResult.files[0];
|
||||
|
||||
addDebugEvent?.('ocr', 'pending', `🔍 Запущен OCR для: ${firstFile.filename}`, {
|
||||
file_id: firstFile.file_id,
|
||||
filename: firstFile.filename
|
||||
});
|
||||
|
||||
// Если есть OCR результат
|
||||
if (firstFile.ocr_result) {
|
||||
const ocr = firstFile.ocr_result;
|
||||
|
||||
addDebugEvent?.('ocr', 'success', `📄 OCR завершен: ${ocr.ocr_text?.length || 0} символов`, {
|
||||
text: ocr.ocr_text?.substring(0, 300)
|
||||
});
|
||||
|
||||
if (ocr.ai_analysis) {
|
||||
const isGarbage = ocr.document_type === 'garbage';
|
||||
|
||||
addDebugEvent?.(
|
||||
'ai_analysis',
|
||||
isGarbage ? 'warning' : 'success',
|
||||
isGarbage
|
||||
? `🗑️ ШЛЯПА DETECTED! (пользователю не говорим)`
|
||||
: `🤖 AI: ${ocr.document_type}, confidence: ${(ocr.confidence * 100).toFixed(0)}%`,
|
||||
{
|
||||
document_type: ocr.document_type,
|
||||
is_valid: ocr.is_valid,
|
||||
confidence: ocr.confidence,
|
||||
extracted_data: ocr.extracted_data
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateFormData({
|
||||
...values,
|
||||
policyScanUploaded: true,
|
||||
policyScanFiles: uploadResult.files,
|
||||
policyValidationWarning: '' // TODO: OCR validation
|
||||
policyValidationWarning: '' // Silent validation
|
||||
});
|
||||
|
||||
message.success(`Загружено файлов: ${uploadResult.uploaded_count}`);
|
||||
onNext();
|
||||
} else {
|
||||
addDebugEvent?.('upload', 'error', `❌ Ошибка загрузки файлов`, { error: 'Upload failed' });
|
||||
message.error('Ошибка загрузки файлов');
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user