2025-11-19 18:46:48 +03:00
|
|
|
|
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 {
|
2025-11-20 18:31:42 +03:00
|
|
|
|
phone?: string;
|
2025-11-19 18:46:48 +03:00
|
|
|
|
session_id?: string;
|
2025-11-20 18:31:42 +03:00
|
|
|
|
unified_id?: string; // ✅ Добавляем unified_id
|
2025-11-19 18:46:48 +03:00
|
|
|
|
onSelectDraft: (claimId: string) => void;
|
|
|
|
|
|
onNewClaim: () => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function StepDraftSelection({
|
|
|
|
|
|
phone,
|
|
|
|
|
|
session_id,
|
2025-11-20 18:31:42 +03:00
|
|
|
|
unified_id, // ✅ Добавляем unified_id
|
2025-11-19 18:46:48 +03:00
|
|
|
|
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();
|
2025-11-20 18:31:42 +03:00
|
|
|
|
// ✅ Приоритет: unified_id > phone > session_id
|
|
|
|
|
|
if (unified_id) {
|
|
|
|
|
|
params.append('unified_id', unified_id);
|
|
|
|
|
|
console.log('🔍 StepDraftSelection: загружаем черновики по unified_id:', unified_id);
|
2025-11-19 18:46:48 +03:00
|
|
|
|
} else if (phone) {
|
|
|
|
|
|
params.append('phone', phone);
|
2025-11-20 18:31:42 +03:00
|
|
|
|
console.log('🔍 StepDraftSelection: загружаем черновики по phone:', phone);
|
|
|
|
|
|
} else if (session_id) {
|
|
|
|
|
|
params.append('session_id', session_id);
|
|
|
|
|
|
console.log('🔍 StepDraftSelection: загружаем черновики по session_id:', session_id);
|
2025-11-19 18:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 18:31:42 +03:00
|
|
|
|
const url = `/api/v1/claims/drafts/list?${params.toString()}`;
|
|
|
|
|
|
console.log('🔍 StepDraftSelection: запрос:', url);
|
|
|
|
|
|
|
|
|
|
|
|
const response = await fetch(url);
|
2025-11-19 18:46:48 +03:00
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
throw new Error('Не удалось загрузить черновики');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const data = await response.json();
|
2025-11-20 18:31:42 +03:00
|
|
|
|
console.log('🔍 StepDraftSelection: ответ API:', data);
|
|
|
|
|
|
console.log('🔍 StepDraftSelection: количество черновиков:', data.count);
|
2025-11-19 18:46:48 +03:00
|
|
|
|
setDrafts(data.drafts || []);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Ошибка загрузки черновиков:', error);
|
|
|
|
|
|
message.error('Не удалось загрузить список черновиков');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
loadDrafts();
|
2025-11-20 18:31:42 +03:00
|
|
|
|
}, [phone, session_id, unified_id]); // ✅ Добавляем unified_id в зависимости
|
2025-11-19 18:46:48 +03:00
|
|
|
|
|
|
|
|
|
|
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>
|
2025-11-20 18:31:42 +03:00
|
|
|
|
<Title level={2} style={{ marginBottom: 8, color: '#1890ff' }}>
|
|
|
|
|
|
📋 Ваши черновики заявок
|
2025-11-19 18:46:48 +03:00
|
|
|
|
</Title>
|
2025-11-20 18:31:42 +03:00
|
|
|
|
<Paragraph type="secondary" style={{ fontSize: 14, marginBottom: 16 }}>
|
|
|
|
|
|
Выберите черновик, чтобы продолжить заполнение, или создайте новую заявку.
|
2025-11-19 18:46:48 +03:00
|
|
|
|
</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"
|
2025-11-20 18:31:42 +03:00
|
|
|
|
onClick={() => {
|
|
|
|
|
|
console.log('🔍 Выбран черновик:', draft.claim_id, 'id:', draft.id);
|
|
|
|
|
|
// Используем id (UUID) если claim_id отсутствует
|
|
|
|
|
|
const draftId = draft.claim_id || draft.id;
|
|
|
|
|
|
console.log('🔍 Загружаем черновик с ID:', draftId);
|
|
|
|
|
|
onSelectDraft(draftId);
|
|
|
|
|
|
}}
|
2025-11-19 18:46:48 +03:00
|
|
|
|
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>
|
2025-11-24 13:36:14 +03:00
|
|
|
|
<Text strong>Черновик</Text>
|
2025-11-19 18:46:48 +03:00
|
|
|
|
<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>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|