2025-10-25 09:27:56 +03:00
|
|
|
|
import { Form, Input, Button, Select, DatePicker, Upload, message } from 'antd';
|
2025-10-24 16:19:58 +03:00
|
|
|
|
import { UploadOutlined } from '@ant-design/icons';
|
|
|
|
|
|
import { useState } from 'react';
|
2025-10-25 09:27:56 +03:00
|
|
|
|
import type { UploadFile } from 'antd/es/upload/interface';
|
|
|
|
|
|
import dayjs from 'dayjs';
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
|
formData: any;
|
|
|
|
|
|
updateFormData: (data: any) => void;
|
|
|
|
|
|
onNext: () => void;
|
|
|
|
|
|
onPrev: () => void;
|
2025-10-25 09:27:56 +03:00
|
|
|
|
addDebugEvent?: (type: string, status: string, message: string, data?: any) => void;
|
2025-10-24 16:19:58 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-25 09:27:56 +03:00
|
|
|
|
// Типы страховых случаев из 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) {
|
2025-10-24 16:19:58 +03:00
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
2025-10-25 09:27:56 +03:00
|
|
|
|
const [uploading, setUploading] = useState(false);
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
const handleNext = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const values = await form.validateFields();
|
2025-10-25 09:27:56 +03:00
|
|
|
|
|
|
|
|
|
|
// Если есть файлы - загружаем
|
|
|
|
|
|
if (fileList.length > 0) {
|
|
|
|
|
|
setUploading(true);
|
|
|
|
|
|
|
|
|
|
|
|
addDebugEvent?.('upload', 'pending', `📤 Загружаю ${fileList.length} документ(ов) в S3...`, {
|
|
|
|
|
|
count: fileList.length
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
|
fileList.forEach((file: any) => {
|
|
|
|
|
|
if (file.originFileObj) {
|
|
|
|
|
|
formData.append('files', file.originFileObj);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const uploadResponse = await fetch('http://147.45.146.17:8100/api/v1/upload/files?folder=documents', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
body: formData,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const uploadResult = await uploadResponse.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (uploadResult.success) {
|
|
|
|
|
|
addDebugEvent?.('upload', 'success', `✅ Документы загружены: ${uploadResult.uploaded_count}/${uploadResult.total_count}`, {
|
|
|
|
|
|
files: uploadResult.files
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
updateFormData({
|
|
|
|
|
|
...values,
|
|
|
|
|
|
uploadedFiles: uploadResult.files
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
message.error('Ошибка загрузки документов');
|
|
|
|
|
|
setUploading(false);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setUploading(false);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
updateFormData(values);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
onNext();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.error('Заполните все обязательные поля');
|
2025-10-25 09:27:56 +03:00
|
|
|
|
setUploading(false);
|
2025-10-24 16:19:58 +03:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-10-25 09:27:56 +03:00
|
|
|
|
const handleUploadChange = ({ fileList: newFileList }: any) => {
|
|
|
|
|
|
setFileList(newFileList);
|
2025-10-24 16:19:58 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-10-25 10:12:41 +03:00
|
|
|
|
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';
|
|
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
return (
|
|
|
|
|
|
<Form
|
|
|
|
|
|
form={form}
|
|
|
|
|
|
layout="vertical"
|
|
|
|
|
|
initialValues={formData}
|
|
|
|
|
|
style={{ marginTop: 24 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Form.Item
|
2025-10-25 09:27:56 +03:00
|
|
|
|
label="Выберите тип события"
|
|
|
|
|
|
name="eventType"
|
|
|
|
|
|
rules={[{ required: true, message: 'Выберите тип события' }]}
|
2025-10-24 16:19:58 +03:00
|
|
|
|
>
|
2025-10-25 09:27:56 +03:00
|
|
|
|
<Select
|
|
|
|
|
|
placeholder="Выберите тип события"
|
|
|
|
|
|
size="large"
|
2025-10-25 10:12:41 +03:00
|
|
|
|
onChange={handleEventTypeChange}
|
2025-10-25 09:27:56 +03:00
|
|
|
|
>
|
|
|
|
|
|
{EVENT_TYPES.map(type => (
|
|
|
|
|
|
<Option key={type.value} value={type.value}>
|
|
|
|
|
|
{type.label}
|
|
|
|
|
|
</Option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</Select>
|
2025-10-24 16:19:58 +03:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
2025-10-25 09:27:56 +03:00
|
|
|
|
label="Дата наступления страхового случая"
|
|
|
|
|
|
name="incidentDate"
|
|
|
|
|
|
rules={[{ required: true, message: 'Укажите дату' }]}
|
2025-10-24 16:19:58 +03:00
|
|
|
|
>
|
2025-10-25 09:27:56 +03:00
|
|
|
|
<DatePicker
|
|
|
|
|
|
placeholder="Выберите дату"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
|
format="DD.MM.YYYY"
|
|
|
|
|
|
disabledDate={(current) => current && current > dayjs().endOf('day')}
|
|
|
|
|
|
/>
|
2025-10-24 16:19:58 +03:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
2025-10-25 10:12:41 +03:00
|
|
|
|
{/* Для стыковочного рейса - номер рейса прибытия */}
|
|
|
|
|
|
{showConnectionFields && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Укажите номер рейса прибытия"
|
|
|
|
|
|
name="arrivalFlightNumber"
|
|
|
|
|
|
rules={[{ required: true, message: 'Введите номер рейса прибытия' }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
placeholder="Введите номер"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{showConnectionFields && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Дата рейса прибытия"
|
|
|
|
|
|
name="arrivalFlightDate"
|
|
|
|
|
|
rules={[{ required: true, message: 'Укажите дату прибытия' }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatePicker
|
|
|
|
|
|
placeholder="Выберите дату"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
|
format="DD.MM.YYYY"
|
|
|
|
|
|
disabledDate={(current) => current && current > dayjs().endOf('day')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Для стыковочного рейса - номер рейса отправления */}
|
|
|
|
|
|
{showConnectionFields && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Укажите номер рейса отправления"
|
|
|
|
|
|
name="departureFlightNumber"
|
|
|
|
|
|
rules={[{ required: true, message: 'Введите номер рейса отправления' }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
placeholder="Введите номер рейса отправления"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{showConnectionFields && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Дата рейса отправления"
|
|
|
|
|
|
name="departureFlightDate"
|
|
|
|
|
|
rules={[{ required: true, message: 'Укажите дату отправления' }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatePicker
|
|
|
|
|
|
placeholder="Выберите дату"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
|
format="DD.MM.YYYY"
|
|
|
|
|
|
disabledDate={(current) => current && current > dayjs().endOf('day')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Для обычных рейсов */}
|
|
|
|
|
|
{!showConnectionFields && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Номер рейса/поезда/парома"
|
|
|
|
|
|
name="transportNumber"
|
|
|
|
|
|
rules={[{ required: true, message: 'Введите номер' }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
placeholder="Введите номер"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Дополнительные документы для отмены рейса */}
|
|
|
|
|
|
{showCancelFlightDocs && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Подтверждение уведомления об отмене рейса от АК"
|
|
|
|
|
|
name="cancelConfirmation"
|
|
|
|
|
|
tooltip="Уведомление от авиакомпании об отмене"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Upload
|
|
|
|
|
|
listType="picture"
|
|
|
|
|
|
beforeUpload={(file) => {
|
|
|
|
|
|
const isLt15M = file.size / 1024 / 1024 < 15;
|
|
|
|
|
|
if (!isLt15M) {
|
|
|
|
|
|
message.error(`${file.name}: файл больше 15MB`);
|
|
|
|
|
|
return Upload.LIST_IGNORE;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}}
|
|
|
|
|
|
accept="image/*,.pdf,.heic,.heif"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
maxCount={5}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Button icon={<UploadOutlined />} size="large" block>
|
|
|
|
|
|
Загрузить подтверждение отмены
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Upload>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
2025-10-25 09:27:56 +03:00
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Подтверждающие документы"
|
|
|
|
|
|
name="documents"
|
|
|
|
|
|
tooltip="Посадочный талон, билет, справка о задержке и т.д."
|
|
|
|
|
|
>
|
|
|
|
|
|
<Upload
|
|
|
|
|
|
listType="picture"
|
|
|
|
|
|
fileList={fileList}
|
|
|
|
|
|
onChange={handleUploadChange}
|
|
|
|
|
|
beforeUpload={(file) => {
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}}
|
|
|
|
|
|
accept="image/*,.pdf,.heic,.heif"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
maxCount={10}
|
|
|
|
|
|
showUploadList={{
|
|
|
|
|
|
showPreviewIcon: true,
|
|
|
|
|
|
showRemoveIcon: true,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Button icon={<UploadOutlined />} size="large" block disabled={fileList.length >= 10}>
|
|
|
|
|
|
Загрузить файлы (до 10 шт, макс 15MB каждый)
|
|
|
|
|
|
</Button>
|
2025-10-24 16:19:58 +03:00
|
|
|
|
</Upload>
|
2025-10-25 09:27:56 +03:00
|
|
|
|
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>
|
|
|
|
|
|
Загружено: {fileList.length}/10 файлов
|
2025-10-24 16:19:58 +03:00
|
|
|
|
</div>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item>
|
2025-10-25 09:27:56 +03:00
|
|
|
|
<div style={{ display: 'flex', gap: 8, marginTop: 32 }}>
|
|
|
|
|
|
<Button onClick={onPrev} size="large">Назад</Button>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
onClick={handleNext}
|
|
|
|
|
|
loading={uploading}
|
|
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
>
|
|
|
|
|
|
{uploading ? 'Загрузка документов...' : 'Далее'}
|
2025-10-24 16:19:58 +03:00
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|