refactor: Изменен порядок формы - проверка полиса на первом шаге
Изменения в UX: - Шаг 1: Проверка полиса (было: телефон + SMS) - Шаг 2: Детали происшествия (без изменений) - Шаг 3: Телефон + SMS + Выплата (было: только выплата) Обновленные компоненты: - Удален: Step1Phone.tsx - Создан: Step1Policy.tsx - проверка полиса через API - Обновлен: Step3Payment.tsx - добавлена SMS верификация - Обновлен: ClaimForm.tsx - новая структура шагов Логика: сначала проверяем полис, потом детали, в конце верификация телефона и выплата
This commit is contained in:
@@ -420,7 +420,7 @@ pip install python-multipart==0.0.20
|
|||||||
- **API endpoints:** 8
|
- **API endpoints:** 8
|
||||||
- **Сервисов интегрировано:** 6 (PostgreSQL, Redis, RabbitMQ, MySQL, OCR, SMS)
|
- **Сервисов интегрировано:** 6 (PostgreSQL, Redis, RabbitMQ, MySQL, OCR, SMS)
|
||||||
- **Проблем решено:** 9 критических
|
- **Проблем решено:** 9 критических
|
||||||
- **Коммитов:** 0 (еще не закоммитили!)
|
- **Коммитов:** 3 (последний: `8b0bd15` - перезапуск платформы)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -501,8 +501,24 @@ docker ps | grep frontend
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📦 Git Commits
|
||||||
|
|
||||||
|
### Коммит #3: `8b0bd15` - Перезапуск платформы
|
||||||
|
**Дата:** 24 октября 2025
|
||||||
|
**Сообщение:** fix: Перезапуск платформы - исправлены зависимости и TypeScript ошибки
|
||||||
|
|
||||||
|
**Изменения:**
|
||||||
|
- 9 файлов изменено (+918 / -134 строк)
|
||||||
|
- Новые файлы: SESSION_LOG, policy.py, upload.py, policy_service.py
|
||||||
|
- Обновлены: requirements.txt, Step3Payment.tsx, config.py, main.py, sms_service.py
|
||||||
|
|
||||||
|
**Статус:** ✅ Успешно запушено в origin/main
|
||||||
|
**Gitea:** http://147.45.146.17:3002/negodiy/erv-platform/commit/8b0bd15
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
*Документ создан: 24 октября 2025*
|
*Документ создан: 24 октября 2025*
|
||||||
*Последнее обновление: 24 октября 2025 (перезапуск сервисов)*
|
*Последнее обновление: 24 октября 2025 (git commit + перезапуск)*
|
||||||
*Платформа: ERV Insurance Platform v1.0.0*
|
*Платформа: ERV Insurance Platform v1.0.0*
|
||||||
*Tech Stack: Python FastAPI + React TypeScript + PostgreSQL + Redis + RabbitMQ*
|
*Tech Stack: Python FastAPI + React TypeScript + PostgreSQL + Redis + RabbitMQ*
|
||||||
|
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { Form, Input, Button, message, Space } from 'antd';
|
|
||||||
import { PhoneOutlined, SafetyOutlined, FileProtectOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
formData: any;
|
|
||||||
updateFormData: (data: any) => void;
|
|
||||||
onNext: () => void;
|
|
||||||
isPhoneVerified: boolean;
|
|
||||||
setIsPhoneVerified: (verified: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Step1Phone({ formData, updateFormData, onNext, isPhoneVerified, setIsPhoneVerified }: Props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const [codeSent, setCodeSent] = useState(false);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [verifyLoading, setVerifyLoading] = useState(false);
|
|
||||||
|
|
||||||
const sendCode = async () => {
|
|
||||||
try {
|
|
||||||
const phone = form.getFieldValue('phone');
|
|
||||||
if (!phone) {
|
|
||||||
message.error('Введите номер телефона');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
const response = await fetch('http://147.45.146.17:8100/api/v1/sms/send', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ phone }),
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
message.success('Код отправлен на ваш телефон');
|
|
||||||
setCodeSent(true);
|
|
||||||
if (result.debug_code) {
|
|
||||||
message.info(`DEBUG: Код ${result.debug_code}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.error(result.detail || 'Ошибка отправки кода');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message.error('Ошибка соединения с сервером');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const verifyCode = async () => {
|
|
||||||
try {
|
|
||||||
const phone = form.getFieldValue('phone');
|
|
||||||
const code = form.getFieldValue('smsCode');
|
|
||||||
|
|
||||||
if (!code) {
|
|
||||||
message.error('Введите код из SMS');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setVerifyLoading(true);
|
|
||||||
const response = await fetch('http://147.45.146.17:8100/api/v1/sms/verify', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ phone, code }),
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
message.success('Телефон подтвержден!');
|
|
||||||
setIsPhoneVerified(true);
|
|
||||||
} else {
|
|
||||||
message.error(result.detail || 'Неверный код');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
message.error('Ошибка соединения с сервером');
|
|
||||||
} finally {
|
|
||||||
setVerifyLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNext = async () => {
|
|
||||||
try {
|
|
||||||
const values = await form.validateFields();
|
|
||||||
updateFormData(values);
|
|
||||||
onNext();
|
|
||||||
} catch (error) {
|
|
||||||
message.error('Заполните все обязательные поля');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
initialValues={formData}
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label="Номер телефона"
|
|
||||||
name="phone"
|
|
||||||
rules={[
|
|
||||||
{ required: true, message: 'Введите номер телефона' },
|
|
||||||
{ pattern: /^\+7\d{10}$/, message: 'Формат: +79001234567' }
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
prefix={<PhoneOutlined />}
|
|
||||||
placeholder="+79001234567"
|
|
||||||
disabled={isPhoneVerified}
|
|
||||||
maxLength={12}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{!isPhoneVerified && (
|
|
||||||
<>
|
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={sendCode}
|
|
||||||
loading={loading}
|
|
||||||
disabled={codeSent}
|
|
||||||
>
|
|
||||||
{codeSent ? 'Код отправлен' : 'Отправить код'}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{codeSent && (
|
|
||||||
<Form.Item
|
|
||||||
label="Код из SMS"
|
|
||||||
name="smsCode"
|
|
||||||
rules={[{ required: true, message: 'Введите код' }, { len: 6, message: '6 цифр' }]}
|
|
||||||
>
|
|
||||||
<Space.Compact style={{ width: '100%' }}>
|
|
||||||
<Input
|
|
||||||
prefix={<SafetyOutlined />}
|
|
||||||
placeholder="123456"
|
|
||||||
maxLength={6}
|
|
||||||
style={{ width: '70%' }}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={verifyCode}
|
|
||||||
loading={verifyLoading}
|
|
||||||
style={{ width: '30%' }}
|
|
||||||
>
|
|
||||||
Проверить
|
|
||||||
</Button>
|
|
||||||
</Space.Compact>
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isPhoneVerified && (
|
|
||||||
<>
|
|
||||||
<Form.Item
|
|
||||||
label="Email (необязательно)"
|
|
||||||
name="email"
|
|
||||||
rules={[{ type: 'email', message: 'Неверный формат email' }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="example@mail.ru" />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="ИНН (необязательно)"
|
|
||||||
name="inn"
|
|
||||||
>
|
|
||||||
<Input placeholder="1234567890" maxLength={12} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="Номер полиса"
|
|
||||||
name="policyNumber"
|
|
||||||
rules={[{ required: true, message: 'Введите номер полиса' }]}
|
|
||||||
>
|
|
||||||
<Input prefix={<FileProtectOutlined />} placeholder="123456789" />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="Серия полиса (необязательно)"
|
|
||||||
name="policySeries"
|
|
||||||
>
|
|
||||||
<Input placeholder="AB" />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item>
|
|
||||||
<Button type="primary" onClick={handleNext} size="large" block>
|
|
||||||
Далее
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
118
frontend/src/components/form/Step1Policy.tsx
Normal file
118
frontend/src/components/form/Step1Policy.tsx
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Form, Input, Button, message } from 'antd';
|
||||||
|
import { FileProtectOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
formData: any;
|
||||||
|
updateFormData: (data: any) => void;
|
||||||
|
onNext: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Step1Policy({ formData, updateFormData, onNext }: Props) {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const checkPolicy = async () => {
|
||||||
|
try {
|
||||||
|
const values = await form.validateFields();
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
// Проверка полиса через API
|
||||||
|
const response = await fetch('http://147.45.146.17:8100/api/v1/policy/check', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
policy_number: values.policyNumber,
|
||||||
|
policy_series: values.policySeries,
|
||||||
|
inn: values.inn,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
if (result.found) {
|
||||||
|
message.success(`Полис найден! ${result.holder_name}`);
|
||||||
|
updateFormData(values);
|
||||||
|
onNext();
|
||||||
|
} else {
|
||||||
|
message.warning('Полис не найден. Загрузите скан полиса на следующем шаге.');
|
||||||
|
updateFormData(values);
|
||||||
|
onNext();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(result.detail || 'Ошибка проверки полиса');
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.errorFields) {
|
||||||
|
message.error('Заполните все обязательные поля');
|
||||||
|
} else {
|
||||||
|
message.error('Ошибка соединения с сервером');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={formData}
|
||||||
|
style={{ marginTop: 24 }}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label="Номер полиса"
|
||||||
|
name="policyNumber"
|
||||||
|
rules={[{ required: true, message: 'Введите номер полиса' }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
prefix={<FileProtectOutlined />}
|
||||||
|
placeholder="123456789"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Серия полиса (необязательно)"
|
||||||
|
name="policySeries"
|
||||||
|
>
|
||||||
|
<Input placeholder="AB" size="large" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="ИНН (необязательно)"
|
||||||
|
name="inn"
|
||||||
|
>
|
||||||
|
<Input placeholder="1234567890" maxLength={12} size="large" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Email (необязательно)"
|
||||||
|
name="email"
|
||||||
|
rules={[{ type: 'email', message: 'Неверный формат email' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="example@mail.ru" size="large" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={checkPolicy}
|
||||||
|
loading={loading}
|
||||||
|
size="large"
|
||||||
|
block
|
||||||
|
>
|
||||||
|
Проверить полис и продолжить
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 16, padding: 12, background: '#f0f9ff', borderRadius: 8 }}>
|
||||||
|
<p style={{ margin: 0, fontSize: 13, color: '#666' }}>
|
||||||
|
💡 Если полис не найден в базе, на следующем шаге вы сможете загрузить его скан
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Form, Button, Select, message } from 'antd';
|
|
||||||
import { QrcodeOutlined } from '@ant-design/icons';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { Form, Input, Button, Select, message, Space, Divider } from 'antd';
|
||||||
|
import { PhoneOutlined, SafetyOutlined, QrcodeOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@@ -9,12 +9,89 @@ interface Props {
|
|||||||
updateFormData: (data: any) => void;
|
updateFormData: (data: any) => void;
|
||||||
onPrev: () => void;
|
onPrev: () => void;
|
||||||
onSubmit: () => void;
|
onSubmit: () => void;
|
||||||
|
isPhoneVerified: boolean;
|
||||||
|
setIsPhoneVerified: (verified: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Step3Payment({ formData, updateFormData, onPrev, onSubmit }: Props) {
|
export default function Step3Payment({
|
||||||
|
formData,
|
||||||
|
updateFormData,
|
||||||
|
onPrev,
|
||||||
|
onSubmit,
|
||||||
|
isPhoneVerified,
|
||||||
|
setIsPhoneVerified
|
||||||
|
}: Props) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [codeSent, setCodeSent] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [verifyLoading, setVerifyLoading] = useState(false);
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
|
||||||
|
const sendCode = async () => {
|
||||||
|
try {
|
||||||
|
const phone = form.getFieldValue('phone');
|
||||||
|
if (!phone) {
|
||||||
|
message.error('Введите номер телефона');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
const response = await fetch('http://147.45.146.17:8100/api/v1/sms/send', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ phone }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
message.success('Код отправлен на ваш телефон');
|
||||||
|
setCodeSent(true);
|
||||||
|
if (result.debug_code) {
|
||||||
|
message.info(`DEBUG: Код ${result.debug_code}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(result.detail || 'Ошибка отправки кода');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
message.error('Ошибка соединения с сервером');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const verifyCode = async () => {
|
||||||
|
try {
|
||||||
|
const phone = form.getFieldValue('phone');
|
||||||
|
const code = form.getFieldValue('smsCode');
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
message.error('Введите код из SMS');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setVerifyLoading(true);
|
||||||
|
const response = await fetch('http://147.45.146.17:8100/api/v1/sms/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ phone, code }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
message.success('Телефон подтвержден!');
|
||||||
|
setIsPhoneVerified(true);
|
||||||
|
} else {
|
||||||
|
message.error(result.detail || 'Неверный код');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
message.error('Ошибка соединения с сервером');
|
||||||
|
} finally {
|
||||||
|
setVerifyLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
@@ -36,65 +113,162 @@ export default function Step3Payment({ formData, updateFormData, onPrev, onSubmi
|
|||||||
initialValues={formData}
|
initialValues={formData}
|
||||||
style={{ marginTop: 24 }}
|
style={{ marginTop: 24 }}
|
||||||
>
|
>
|
||||||
<Form.Item
|
{/* Блок верификации телефона */}
|
||||||
label="Способ выплаты"
|
<div style={{
|
||||||
name="paymentMethod"
|
padding: 16,
|
||||||
initialValue="sbp"
|
background: '#f6f8fa',
|
||||||
>
|
borderRadius: 8,
|
||||||
<div style={{ padding: '12px', background: '#f0f9ff', borderRadius: '8px', border: '1px solid #91d5ff' }}>
|
marginBottom: 24
|
||||||
<QrcodeOutlined style={{ fontSize: 20, color: '#1890ff', marginRight: 8 }} />
|
}}>
|
||||||
<strong>СБП (Система быстрых платежей)</strong>
|
<h3 style={{ marginTop: 0 }}>📱 Подтверждение телефона</h3>
|
||||||
<p style={{ margin: '8px 0 0 0', color: '#666', fontSize: 13 }}>
|
|
||||||
Выплата поступит на ваш счет в течение нескольких минут
|
<Form.Item
|
||||||
</p>
|
label="Номер телефона"
|
||||||
</div>
|
name="phone"
|
||||||
</Form.Item>
|
rules={[
|
||||||
|
{ required: true, message: 'Введите номер телефона' },
|
||||||
<Form.Item
|
{ pattern: /^\+7\d{10}$/, message: 'Формат: +79001234567' }
|
||||||
label="Выберите ваш банк"
|
]}
|
||||||
name="bankName"
|
|
||||||
rules={[{ required: true, message: 'Выберите банк для получения выплаты' }]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
placeholder="Выберите банк"
|
|
||||||
size="large"
|
|
||||||
showSearch
|
|
||||||
filterOption={(input: string, option: any) => {
|
|
||||||
const children = option?.children;
|
|
||||||
if (typeof children === 'string') {
|
|
||||||
return children.toLowerCase().includes(input.toLowerCase());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Option value="sberbank">🟢 Сбербанк</Option>
|
<Input
|
||||||
<Option value="tinkoff">🟡 Тинькофф</Option>
|
prefix={<PhoneOutlined />}
|
||||||
<Option value="vtb">🔵 ВТБ</Option>
|
placeholder="+79001234567"
|
||||||
<Option value="alfabank">🔴 Альфа-Банк</Option>
|
disabled={isPhoneVerified}
|
||||||
<Option value="raiffeisen">🟡 Райффайзенбанк</Option>
|
maxLength={12}
|
||||||
<Option value="gazprombank">🔵 Газпромбанк</Option>
|
|
||||||
<Option value="rosbank">🔴 Росбанк</Option>
|
|
||||||
<Option value="sovcombank">🟢 Совкомбанк</Option>
|
|
||||||
<Option value="otkritie">🔵 Открытие</Option>
|
|
||||||
<Option value="other">💳 Другой банк</Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item>
|
|
||||||
<div style={{ display: 'flex', gap: 8, marginTop: 32 }}>
|
|
||||||
<Button onClick={onPrev}>Назад</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
loading={submitting}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
size="large"
|
size="large"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{!isPhoneVerified && (
|
||||||
|
<>
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={sendCode}
|
||||||
|
loading={loading}
|
||||||
|
disabled={codeSent}
|
||||||
|
block
|
||||||
|
>
|
||||||
|
{codeSent ? 'Код отправлен' : 'Отправить код'}
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{codeSent && (
|
||||||
|
<Form.Item
|
||||||
|
label="Код из SMS"
|
||||||
|
name="smsCode"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: 'Введите код' },
|
||||||
|
{ len: 6, message: '6 цифр' }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<Input
|
||||||
|
prefix={<SafetyOutlined />}
|
||||||
|
placeholder="123456"
|
||||||
|
maxLength={6}
|
||||||
|
style={{ width: '70%' }}
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={verifyCode}
|
||||||
|
loading={verifyLoading}
|
||||||
|
style={{ width: '30%' }}
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
Проверить
|
||||||
|
</Button>
|
||||||
|
</Space.Compact>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isPhoneVerified && (
|
||||||
|
<div style={{
|
||||||
|
padding: 12,
|
||||||
|
background: '#f0f9ff',
|
||||||
|
borderRadius: 8,
|
||||||
|
border: '1px solid #91d5ff'
|
||||||
|
}}>
|
||||||
|
✅ Телефон подтвержден
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Блок выплаты (показывается только после верификации) */}
|
||||||
|
{isPhoneVerified && (
|
||||||
|
<>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<h3>💳 Способ получения выплаты</h3>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Способ выплаты"
|
||||||
|
name="paymentMethod"
|
||||||
|
initialValue="sbp"
|
||||||
>
|
>
|
||||||
Отправить заявку
|
<div style={{
|
||||||
</Button>
|
padding: '12px',
|
||||||
</div>
|
background: '#f0f9ff',
|
||||||
</Form.Item>
|
borderRadius: '8px',
|
||||||
|
border: '1px solid #91d5ff'
|
||||||
|
}}>
|
||||||
|
<QrcodeOutlined style={{ fontSize: 20, color: '#1890ff', marginRight: 8 }} />
|
||||||
|
<strong>СБП (Система быстрых платежей)</strong>
|
||||||
|
<p style={{ margin: '8px 0 0 0', color: '#666', fontSize: 13 }}>
|
||||||
|
Выплата поступит на ваш счет в течение нескольких минут
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Выберите ваш банк"
|
||||||
|
name="bankName"
|
||||||
|
rules={[{ required: true, message: 'Выберите банк для получения выплаты' }]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="Выберите банк"
|
||||||
|
size="large"
|
||||||
|
showSearch
|
||||||
|
filterOption={(input: string, option: any) => {
|
||||||
|
const children = option?.children;
|
||||||
|
if (typeof children === 'string') {
|
||||||
|
return children.toLowerCase().includes(input.toLowerCase());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Option value="sberbank">🟢 Сбербанк</Option>
|
||||||
|
<Option value="tinkoff">🟡 Тинькофф</Option>
|
||||||
|
<Option value="vtb">🔵 ВТБ</Option>
|
||||||
|
<Option value="alfabank">🔴 Альфа-Банк</Option>
|
||||||
|
<Option value="raiffeisen">🟡 Райффайзенбанк</Option>
|
||||||
|
<Option value="gazprombank">🔵 Газпромбанк</Option>
|
||||||
|
<Option value="rosbank">🔴 Росбанк</Option>
|
||||||
|
<Option value="sovcombank">🟢 Совкомбанк</Option>
|
||||||
|
<Option value="otkritie">🔵 Открытие</Option>
|
||||||
|
<Option value="other">💳 Другой банк</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<div style={{ display: 'flex', gap: 8, marginTop: 32 }}>
|
||||||
|
<Button onClick={onPrev} size="large">Назад</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
loading={submitting}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
Отправить заявку
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Steps, Card, message } from 'antd';
|
import { Steps, Card, message } from 'antd';
|
||||||
import Step1Phone from '../components/form/Step1Phone';
|
import Step1Policy from '../components/form/Step1Policy';
|
||||||
import Step2Details from '../components/form/Step2Details';
|
import Step2Details from '../components/form/Step2Details';
|
||||||
import Step3Payment from '../components/form/Step3Payment';
|
import Step3Payment from '../components/form/Step3Payment';
|
||||||
import './ClaimForm.css';
|
import './ClaimForm.css';
|
||||||
@@ -96,14 +96,12 @@ export default function ClaimForm() {
|
|||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{
|
{
|
||||||
title: 'Телефон и полис',
|
title: 'Проверка полиса',
|
||||||
content: (
|
content: (
|
||||||
<Step1Phone
|
<Step1Policy
|
||||||
formData={formData}
|
formData={formData}
|
||||||
updateFormData={updateFormData}
|
updateFormData={updateFormData}
|
||||||
onNext={nextStep}
|
onNext={nextStep}
|
||||||
isPhoneVerified={isPhoneVerified}
|
|
||||||
setIsPhoneVerified={setIsPhoneVerified}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -119,13 +117,15 @@ export default function ClaimForm() {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Способ выплаты',
|
title: 'Телефон и выплата',
|
||||||
content: (
|
content: (
|
||||||
<Step3Payment
|
<Step3Payment
|
||||||
formData={formData}
|
formData={formData}
|
||||||
updateFormData={updateFormData}
|
updateFormData={updateFormData}
|
||||||
onPrev={prevStep}
|
onPrev={prevStep}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
isPhoneVerified={isPhoneVerified}
|
||||||
|
setIsPhoneVerified={setIsPhoneVerified}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user