From cfd84e0f9d09191df9a11ef03e897742a4b8117a Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Fri, 24 Oct 2025 20:40:44 +0300 Subject: [PATCH] =?UTF-8?q?refactor:=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D1=8B=20-=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=BB=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B2=D0=BE=D0=BC=20=D1=88?= =?UTF-8?q?=D0=B0=D0=B3=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Изменения в UX: - Шаг 1: Проверка полиса (было: телефон + SMS) - Шаг 2: Детали происшествия (без изменений) - Шаг 3: Телефон + SMS + Выплата (было: только выплата) Обновленные компоненты: - Удален: Step1Phone.tsx - Создан: Step1Policy.tsx - проверка полиса через API - Обновлен: Step3Payment.tsx - добавлена SMS верификация - Обновлен: ClaimForm.tsx - новая структура шагов Логика: сначала проверяем полис, потом детали, в конце верификация телефона и выплата --- SESSION_LOG_2025-10-24.md | 20 +- frontend/src/components/form/Step1Phone.tsx | 199 ------------ frontend/src/components/form/Step1Policy.tsx | 118 +++++++ frontend/src/components/form/Step3Payment.tsx | 292 ++++++++++++++---- frontend/src/pages/ClaimForm.tsx | 12 +- 5 files changed, 375 insertions(+), 266 deletions(-) delete mode 100644 frontend/src/components/form/Step1Phone.tsx create mode 100644 frontend/src/components/form/Step1Policy.tsx diff --git a/SESSION_LOG_2025-10-24.md b/SESSION_LOG_2025-10-24.md index 0806973..0a5336e 100644 --- a/SESSION_LOG_2025-10-24.md +++ b/SESSION_LOG_2025-10-24.md @@ -420,7 +420,7 @@ pip install python-multipart==0.0.20 - **API endpoints:** 8 - **Сервисов интегрировано:** 6 (PostgreSQL, Redis, RabbitMQ, MySQL, OCR, SMS) - **Проблем решено:** 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 (git commit + перезапуск)* *Платформа: ERV Insurance Platform v1.0.0* *Tech Stack: Python FastAPI + React TypeScript + PostgreSQL + Redis + RabbitMQ* diff --git a/frontend/src/components/form/Step1Phone.tsx b/frontend/src/components/form/Step1Phone.tsx deleted file mode 100644 index b0835df..0000000 --- a/frontend/src/components/form/Step1Phone.tsx +++ /dev/null @@ -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 ( -
- - } - placeholder="+79001234567" - disabled={isPhoneVerified} - maxLength={12} - /> - - - {!isPhoneVerified && ( - <> - - - - - {codeSent && ( - - - } - placeholder="123456" - maxLength={6} - style={{ width: '70%' }} - /> - - - - )} - - )} - - {isPhoneVerified && ( - <> - - - - - - - - - - } placeholder="123456789" /> - - - - - - - - - - - )} -
- ); -} - diff --git a/frontend/src/components/form/Step1Policy.tsx b/frontend/src/components/form/Step1Policy.tsx new file mode 100644 index 0000000..5feae19 --- /dev/null +++ b/frontend/src/components/form/Step1Policy.tsx @@ -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 ( +
+ + } + placeholder="123456789" + size="large" + /> + + + + + + + + + + + + + + + + + + +
+

+ 💡 Если полис не найден в базе, на следующем шаге вы сможете загрузить его скан +

+
+
+ ); +} + diff --git a/frontend/src/components/form/Step3Payment.tsx b/frontend/src/components/form/Step3Payment.tsx index 115e111..92af3b1 100644 --- a/frontend/src/components/form/Step3Payment.tsx +++ b/frontend/src/components/form/Step3Payment.tsx @@ -1,6 +1,6 @@ -import { Form, Button, Select, message } from 'antd'; -import { QrcodeOutlined } from '@ant-design/icons'; 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; @@ -9,12 +9,89 @@ interface Props { updateFormData: (data: any) => void; onPrev: () => 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 [codeSent, setCodeSent] = useState(false); + const [loading, setLoading] = useState(false); + const [verifyLoading, setVerifyLoading] = 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 () => { try { const values = await form.validateFields(); @@ -36,65 +113,162 @@ export default function Step3Payment({ formData, updateFormData, onPrev, onSubmi initialValues={formData} style={{ marginTop: 24 }} > - -
- - СБП (Система быстрых платежей) -

- Выплата поступит на ваш счет в течение нескольких минут -

-
-
- - - - - - -
- - + + + {codeSent && ( + + + } + placeholder="123456" + maxLength={6} + style={{ width: '70%' }} + size="large" + /> + + + + )} + + )} + + {isPhoneVerified && ( +
+ ✅ Телефон подтвержден +
+ )} +
+ + {/* Блок выплаты (показывается только после верификации) */} + {isPhoneVerified && ( + <> + + +

💳 Способ получения выплаты

+ + - Отправить заявку - - - +
+ + СБП (Система быстрых платежей) +

+ Выплата поступит на ваш счет в течение нескольких минут +

+
+
+ + + + + + +
+ + +
+
+ + )} ); } - diff --git a/frontend/src/pages/ClaimForm.tsx b/frontend/src/pages/ClaimForm.tsx index 1f4ffef..142ba75 100644 --- a/frontend/src/pages/ClaimForm.tsx +++ b/frontend/src/pages/ClaimForm.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; 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 Step3Payment from '../components/form/Step3Payment'; import './ClaimForm.css'; @@ -96,14 +96,12 @@ export default function ClaimForm() { const steps = [ { - title: 'Телефон и полис', + title: 'Проверка полиса', content: ( - ), }, @@ -119,13 +117,15 @@ export default function ClaimForm() { ), }, { - title: 'Способ выплаты', + title: 'Телефон и выплата', content: ( ), },