From 6fe14598a105ffc073ba938db70ff7a86b8b4f8b Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 28 Oct 2025 11:32:07 +0300 Subject: [PATCH] =?UTF-8?q?backup:=20=D0=A1=D0=BE=D1=85=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D1=91=D0=BD=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D0=B9=20Step2Deta?= =?UTF-8?q?ils=20=D1=81=20=D1=80=D1=83=D1=87=D0=BD=D1=8B=D0=BC=20=D0=B2?= =?UTF-8?q?=D0=B2=D0=BE=D0=B4=D0=BE=D0=BC=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Создана копия Step2Details.OLD_MANUAL_INPUT.tsx перед переходом на умную форму с автоматическим распознаванием документов через OCR/AI. В случае необходимости можно вернуться к ручному вводу. --- .../form/Step2Details.OLD_MANUAL_INPUT.tsx | 402 ++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 frontend/src/components/form/Step2Details.OLD_MANUAL_INPUT.tsx diff --git a/frontend/src/components/form/Step2Details.OLD_MANUAL_INPUT.tsx b/frontend/src/components/form/Step2Details.OLD_MANUAL_INPUT.tsx new file mode 100644 index 0000000..76632fd --- /dev/null +++ b/frontend/src/components/form/Step2Details.OLD_MANUAL_INPUT.tsx @@ -0,0 +1,402 @@ +import { Form, Input, Button, Select, DatePicker, Upload, message, Spin, Alert } from 'antd'; +import { UploadOutlined, LoadingOutlined } from '@ant-design/icons'; +import { useState } from 'react'; +import type { UploadFile } from 'antd/es/upload/interface'; +import dayjs from 'dayjs'; + +const { Option } = Select; + +interface Props { + formData: any; + updateFormData: (data: any) => void; + onNext: () => void; + onPrev: () => void; + addDebugEvent?: (type: string, status: string, message: string, data?: any) => void; +} + +// Типы страховых случаев из erv_ticket +const EVENT_TYPES = [ + { value: 'delay_flight', label: 'Задержка авиарейса (более 3 часов)' }, + { value: 'cancel_flight', label: 'Отмена авиарейса' }, + { value: 'miss_connection', label: 'Пропуск (задержка прибытия) стыковочного рейса (авиа/жд/паром и тд)' }, + { value: 'emergency_landing', label: 'Посадка воздушного судна на запасной аэродром' }, + { value: 'delay_train', label: 'Задержка отправки поезда' }, + { value: 'cancel_train', label: 'Отмена поезда' }, + { value: 'delay_ferry', label: 'Задержка/отмена отправки парома/круизного судна' }, +]; + +export default function Step2Details({ formData, updateFormData, onNext, onPrev, addDebugEvent }: Props) { + const [form] = Form.useForm(); + const [fileList, setFileList] = useState([]); + const [uploading, setUploading] = useState(false); + const [uploadProgress, setUploadProgress] = useState(''); + + const handleNext = async () => { + try { + const values = await form.validateFields(); + + // Если есть файлы - загружаем + if (fileList.length > 0) { + setUploading(true); + setUploadProgress('📤 Подготавливаем документы...'); + + addDebugEvent?.('upload', 'pending', `📤 Загружаю ${fileList.length} документ(ов) в S3 через n8n...`, { + count: fileList.length + }); + + // Используем claim_id из formData (уже сгенерирован в Step1) + const claimId = formData.claim_id; + + // Загружаем каждый документ через n8n вебхук + const uploadedFiles = []; + + for (let i = 0; i < fileList.length; i++) { + const file = fileList[i]; + if (!file.originFileObj) continue; + + setUploadProgress(`📡 Загружаем документ ${i + 1} из ${fileList.length}: ${file.name}...`); + + const uploadFormData = new FormData(); + uploadFormData.append('claim_id', claimId); + uploadFormData.append('file_type', `document_${i + 1}`); // document_1, document_2, etc + uploadFormData.append('filename', file.name); + uploadFormData.append('voucher', formData.voucher || ''); + uploadFormData.append('session_id', sessionStorage.getItem('session_id') || 'unknown'); + uploadFormData.append('upload_timestamp', new Date().toISOString()); + uploadFormData.append('file', file.originFileObj); + + const uploadResponse = await fetch('https://n8n.clientright.pro/webhook/7e2abc64-eaca-4671-86e4-12786700fe95', { + method: 'POST', + body: uploadFormData, + }); + + setUploadProgress(`🔍 Обрабатываем документ ${i + 1} из ${fileList.length}...`); + const uploadResult = await uploadResponse.json(); + + const resultData = Array.isArray(uploadResult) ? uploadResult[0] : uploadResult; + if (resultData?.success) { + uploadedFiles.push({ + filename: file.name, + success: true + }); + } + } + + const uploadResult = { + success: uploadedFiles.length > 0, + uploaded_count: uploadedFiles.length, + total_count: fileList.length, + files: uploadedFiles + }; + + if (uploadResult.success) { + addDebugEvent?.('upload', 'success', `✅ Документы загружены через n8n: ${uploadResult.uploaded_count}/${uploadResult.total_count}`, { + files: uploadResult.files, + claim_id: claimId + }); + + updateFormData({ + ...values, + uploadedFiles: uploadResult.files + }); + } else { + message.error('Ошибка загрузки документов'); + setUploading(false); + setUploadProgress(''); + return; + } + + setUploading(false); + setUploadProgress(''); + } else { + updateFormData(values); + } + + onNext(); + } catch (error) { + message.error('Заполните все обязательные поля'); + setUploading(false); + setUploadProgress(''); + } + }; + + const handleUploadChange = ({ fileList: newFileList }: any) => { + setFileList(newFileList); + }; + + const [eventType, setEventType] = useState(formData.eventType || ''); + + const handleEventTypeChange = (value: string) => { + setEventType(value); + form.setFieldValue('eventType', value); + }; + + // Проверяем нужны ли дополнительные поля для стыковочного рейса + const showConnectionFields = eventType === 'miss_connection'; + const showCancelFlightDocs = eventType === 'cancel_flight'; + + return ( +
+ + + + + + current && current > dayjs().endOf('day')} + /> + + + {/* Для стыковочного рейса - номер рейса прибытия */} + {showConnectionFields && ( + + + + )} + + {showConnectionFields && ( + + current && current > dayjs().endOf('day')} + /> + + )} + + {/* Для стыковочного рейса - номер рейса отправления */} + {showConnectionFields && ( + + + + )} + + {showConnectionFields && ( + + current && current > dayjs().endOf('day')} + /> + + )} + + {/* Для обычных рейсов */} + {!showConnectionFields && ( + + + + )} + + {/* Дополнительные документы для отмены рейса */} + {showCancelFlightDocs && ( + + { + const isLt15M = file.size / 1024 / 1024 < 15; + if (!isLt15M) { + message.error(`${file.name}: файл больше 15MB`); + return Upload.LIST_IGNORE; + } + + const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'application/pdf']; + const validExtensions = /\.(jpg|jpeg|png|pdf|heic|heif|webp)$/i; + + if (!validTypes.includes(file.type) && !validExtensions.test(file.name)) { + message.error(`${file.name}: неподдерживаемый формат`); + return Upload.LIST_IGNORE; + } + + return false; + }} + accept="image/*,.pdf,.heic,.heif,.webp" + multiple + maxCount={5} + > + + + + )} + + + { + const isLt15M = file.size / 1024 / 1024 < 15; + if (!isLt15M) { + message.error(`${file.name}: файл больше 15MB`); + return Upload.LIST_IGNORE; + } + + if (fileList.length >= 10) { + message.error('Максимум 10 файлов'); + return Upload.LIST_IGNORE; + } + + const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'application/pdf']; + const validExtensions = /\.(jpg|jpeg|png|pdf|heic|heif|webp)$/i; + + if (!validTypes.includes(file.type) && !validExtensions.test(file.name)) { + message.error(`${file.name}: неподдерживаемый формат`); + return Upload.LIST_IGNORE; + } + + return false; + }} + accept="image/*,.pdf,.heic,.heif,.webp" + multiple + maxCount={10} + showUploadList={{ + showPreviewIcon: true, + showRemoveIcon: true, + }} + > + + +
+ Загружено: {fileList.length}/10 файлов +
+
+ + {/* Прогресс обработки */} + {uploading && uploadProgress && ( + } />} + style={{ marginBottom: 16, marginTop: 16 }} + /> + )} + + +
+ + +
+
+ + {/* 🔧 Технические кнопки для разработки */} +
+
+ 🔧 DEV MODE - Быстрая навигация (без валидации) +
+
+ + +
+
+ + ); +}