feat: 6 улучшений формы - S3 upload, draft, HEIC, email на step3

1.  Placeholder с тире E1000-302538524
   - Теперь в placeholder тоже тире

2.  Email перенесен на Step3
   - Убран с Step1 (проверка полиса)
   - Добавлен на Step3 (вместе с телефоном)
   - Теперь телефон + email + выплата на одном шаге

3.  HEIC формат + мультилоад
   - Добавлена поддержка .heic, .heif (iPhone формат)
   - Убран maxCount - неограниченная загрузка
   - Параметр multiple для множественной загрузки

4.  S3 Upload
   - Создан s3_service.py для работы с Timeweb S3
   - Новый endpoint: POST /api/v1/upload/files
   - Поддержка мультизагрузки файлов
   - Автоматическая генерация уникальных имен
   - Файлы грузятся в S3, не локально

5.  Draft автосохранение
   - Создана таблица claims_draft в PostgreSQL
   - Новый API: POST /api/v1/draft/save
   - GET /api/v1/draft/stats - статистика по шагам
   - GET /api/v1/draft/list - список последних драфтов
   - Для аналитики: где люди бросают заполнение

6.  Миграция БД
   - 002_create_claims_draft.sql применена
   - Индексы для быстрого поиска
   - JSONB поле для гибкости данных

Backend:
- s3_service.py - сервис для S3
- draft.py - API автосохранения
- upload.py - обновлен endpoint для S3
- main.py - добавлены роуты и подключения

Frontend:
- Step1Policy: убран email, добавлен HEIC
- Step3Payment: добавлен email после телефона

Статус:  Backend подключен к S3, таблица создана, всё работает
This commit is contained in:
AI Assistant
2025-10-24 21:24:00 +03:00
parent f2cfa54c9d
commit e34f7a598b
7 changed files with 420 additions and 26 deletions

View File

@@ -1,5 +1,5 @@
"""
Upload API Routes - Загрузка файлов с OCR
Upload API Routes - Загрузка файлов с OCR и S3
"""
from fastapi import APIRouter, UploadFile, File, HTTPException
from typing import List
@@ -7,6 +7,7 @@ import httpx
import uuid
import os
from ..config import settings
from ..services.s3_service import s3_service
import logging
router = APIRouter(prefix="/api/v1/upload", tags=["Upload"])
@@ -152,3 +153,67 @@ async def upload_passport(file: UploadFile = File(...)):
logger.error(f"Passport upload error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/files")
async def upload_files(files: List[UploadFile] = File(...), folder: str = "claims"):
"""
Универсальная загрузка файлов в S3
Поддерживает множественную загрузку
Args:
files: Список файлов для загрузки
folder: Папка в S3 (claims, policies, documents и т.д.)
Returns:
List[dict]: Список загруженных файлов с URLs
"""
try:
uploaded_files = []
for file in files:
try:
# Читаем содержимое файла
content = await file.read()
# Загружаем в S3
file_url = await s3_service.upload_file(
file_content=content,
filename=file.filename,
content_type=file.content_type or 'application/octet-stream',
folder=folder
)
if file_url:
uploaded_files.append({
"success": True,
"filename": file.filename,
"url": file_url,
"size": len(content),
"content_type": file.content_type
})
else:
uploaded_files.append({
"success": False,
"filename": file.filename,
"error": "S3 upload failed"
})
except Exception as file_error:
logger.error(f"Error uploading {file.filename}: {file_error}")
uploaded_files.append({
"success": False,
"filename": file.filename,
"error": str(file_error)
})
return {
"success": True,
"uploaded_count": len([f for f in uploaded_files if f.get("success")]),
"total_count": len(files),
"files": uploaded_files
}
except Exception as e:
logger.error(f"Batch upload error: {e}")
raise HTTPException(status_code=500, detail=str(e))