Добавлено логирование для отладки черновиков
- Добавлены логи в frontend (ClaimForm.tsx) для отслеживания unified_id и запросов к API - Добавлены логи в backend (claims.py) для отладки SQL запросов - Создан лог сессии с описанием проблемы и текущего состояния - Проблема: API возвращает 0 черновиков, хотя в БД есть данные
This commit is contained in:
255
frontend/src/components/form/StepDraftSelection.tsx
Normal file
255
frontend/src/components/form/StepDraftSelection.tsx
Normal file
@@ -0,0 +1,255 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Button, Card, List, Typography, Space, Empty, Popconfirm, message, Spin, Tag } from 'antd';
|
||||
import { FileTextOutlined, DeleteOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
// Форматирование даты без date-fns (если библиотека не установлена)
|
||||
const formatDate = (dateStr: string) => {
|
||||
try {
|
||||
const date = new Date(dateStr);
|
||||
const day = date.getDate();
|
||||
const month = date.toLocaleDateString('ru-RU', { month: 'long' });
|
||||
const year = date.getFullYear();
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${day} ${month} ${year}, ${hours}:${minutes}`;
|
||||
} catch {
|
||||
return dateStr;
|
||||
}
|
||||
};
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
interface Draft {
|
||||
id: string;
|
||||
claim_id: string;
|
||||
session_token: string;
|
||||
status_code: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
problem_description?: string;
|
||||
wizard_plan: boolean;
|
||||
wizard_answers: boolean;
|
||||
has_documents: boolean;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
phone: string;
|
||||
session_id?: string;
|
||||
onSelectDraft: (claimId: string) => void;
|
||||
onNewClaim: () => void;
|
||||
}
|
||||
|
||||
export default function StepDraftSelection({
|
||||
phone,
|
||||
session_id,
|
||||
onSelectDraft,
|
||||
onNewClaim,
|
||||
}: Props) {
|
||||
const [drafts, setDrafts] = useState<Draft[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
|
||||
const loadDrafts = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const params = new URLSearchParams();
|
||||
if (session_id) {
|
||||
params.append('session_id', session_id);
|
||||
} else if (phone) {
|
||||
params.append('phone', phone);
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/v1/claims/drafts/list?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Не удалось загрузить черновики');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setDrafts(data.drafts || []);
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки черновиков:', error);
|
||||
message.error('Не удалось загрузить список черновиков');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDrafts();
|
||||
}, [phone, session_id]);
|
||||
|
||||
const handleDelete = async (claimId: string) => {
|
||||
try {
|
||||
setDeletingId(claimId);
|
||||
const response = await fetch(`/api/v1/claims/drafts/${claimId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Не удалось удалить черновик');
|
||||
}
|
||||
|
||||
message.success('Черновик удален');
|
||||
await loadDrafts();
|
||||
} catch (error) {
|
||||
console.error('Ошибка удаления черновика:', error);
|
||||
message.error('Не удалось удалить черновик');
|
||||
} finally {
|
||||
setDeletingId(null);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getProgressInfo = (draft: Draft) => {
|
||||
const parts: string[] = [];
|
||||
if (draft.problem_description) parts.push('Описание');
|
||||
if (draft.wizard_plan) parts.push('План вопросов');
|
||||
if (draft.wizard_answers) parts.push('Ответы');
|
||||
if (draft.has_documents) parts.push('Документы');
|
||||
return parts.length > 0 ? parts.join(', ') : 'Начато';
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: 800, margin: '0 auto', padding: '24px 0' }}>
|
||||
<Card
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
border: '1px solid #d9d9d9',
|
||||
background: '#fff',
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Title level={3} style={{ marginBottom: 8 }}>
|
||||
Продолжить заполнение или создать новую заявку?
|
||||
</Title>
|
||||
<Paragraph type="secondary">
|
||||
У вас есть незавершенные черновики. Вы можете продолжить заполнение или создать новую заявку.
|
||||
</Paragraph>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
) : drafts.length === 0 ? (
|
||||
<Empty
|
||||
description="У вас нет незавершенных черновиков"
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={onNewClaim} size="large">
|
||||
Создать новую заявку
|
||||
</Button>
|
||||
</Empty>
|
||||
) : (
|
||||
<>
|
||||
<List
|
||||
dataSource={drafts}
|
||||
renderItem={(draft) => (
|
||||
<List.Item
|
||||
style={{
|
||||
padding: '16px',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: 8,
|
||||
marginBottom: 12,
|
||||
background: '#fff',
|
||||
}}
|
||||
actions={[
|
||||
<Button
|
||||
key="continue"
|
||||
type="primary"
|
||||
onClick={() => onSelectDraft(draft.claim_id!)}
|
||||
icon={<FileTextOutlined />}
|
||||
>
|
||||
Продолжить
|
||||
</Button>,
|
||||
<Popconfirm
|
||||
key="delete"
|
||||
title="Удалить черновик?"
|
||||
description="Это действие нельзя отменить"
|
||||
onConfirm={() => handleDelete(draft.claim_id!)}
|
||||
okText="Да, удалить"
|
||||
cancelText="Отмена"
|
||||
>
|
||||
<Button
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
loading={deletingId === draft.claim_id}
|
||||
disabled={deletingId === draft.claim_id}
|
||||
>
|
||||
Удалить
|
||||
</Button>
|
||||
</Popconfirm>,
|
||||
]}
|
||||
>
|
||||
<List.Item.Meta
|
||||
avatar={<FileTextOutlined style={{ fontSize: 24, color: '#595959' }} />}
|
||||
title={
|
||||
<Space>
|
||||
<Text strong>Черновик {draft.claim_id}</Text>
|
||||
<Tag color="default">Черновик</Tag>
|
||||
</Space>
|
||||
}
|
||||
description={
|
||||
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
Обновлен: {formatDate(draft.updated_at)}
|
||||
</Text>
|
||||
{draft.problem_description && (
|
||||
<Text
|
||||
ellipsis={{ tooltip: draft.problem_description }}
|
||||
style={{ fontSize: 13 }}
|
||||
>
|
||||
{draft.problem_description}
|
||||
</Text>
|
||||
)}
|
||||
<Space size="small">
|
||||
<Tag color={draft.wizard_plan ? 'green' : 'default'}>
|
||||
{draft.wizard_plan ? '✓ План' : 'План'}
|
||||
</Tag>
|
||||
<Tag color={draft.wizard_answers ? 'green' : 'default'}>
|
||||
{draft.wizard_answers ? '✓ Ответы' : 'Ответы'}
|
||||
</Tag>
|
||||
<Tag color={draft.has_documents ? 'green' : 'default'}>
|
||||
{draft.has_documents ? '✓ Документы' : 'Документы'}
|
||||
</Tag>
|
||||
</Space>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
Прогресс: {getProgressInfo(draft)}
|
||||
</Text>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div style={{ textAlign: 'center', marginTop: 24 }}>
|
||||
<Button
|
||||
type="dashed"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={onNewClaim}
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
Создать новую заявку
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={loadDrafts}
|
||||
loading={loading}
|
||||
>
|
||||
Обновить список
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user