fix: Исправление логики загрузки документов и расчёта прогресса
- Исправлена ошибка порядка объявления allDocsProcessed (Cannot access before initialization) - Исправлена логика поиска незагруженного документа: поиск с начала, если сохранённый индекс уже обработан - Исправлен расчёт прогресса: теперь используется количество обработанных документов (uploadedDocs + skippedDocs), а не currentDocIndex - Убрана синхронизация currentDocIndex из formData, которая перезаписывала правильный индекс - Добавлена логика автоматического пропуска уже загруженных документов при открытии формы - Добавлено подробное логирование для отладки состояния документов - Исправлена логика определения завершённости: проверяется каждый документ из documentsRequired Результат: - Форма корректно показывает следующий незагруженный документ - Прогресс правильно отображает процент обработанных документов (75% при 3 из 4) - Система не требует повторной загрузки уже загруженных документов
This commit is contained in:
@@ -249,15 +249,15 @@ export default function StepWizardPlan({
|
||||
: '';
|
||||
|
||||
return [
|
||||
...blocks,
|
||||
{
|
||||
id: generateBlockId(docId),
|
||||
fieldName: docId,
|
||||
...blocks,
|
||||
{
|
||||
id: generateBlockId(docId),
|
||||
fieldName: docId,
|
||||
description: autoDescription,
|
||||
category: category,
|
||||
docLabel: docLabel,
|
||||
files: [],
|
||||
},
|
||||
docLabel: docLabel,
|
||||
files: [],
|
||||
},
|
||||
];
|
||||
});
|
||||
};
|
||||
@@ -602,14 +602,14 @@ export default function StepWizardPlan({
|
||||
// Для обязательных документов описание не требуется
|
||||
// Для предопределённых документов описание не требуется
|
||||
if (!doc.required && !isPredefinedDoc) {
|
||||
const missingDescription = blocks.some(
|
||||
(block) => block.files.length > 0 && !block.description?.trim()
|
||||
);
|
||||
if (missingDescription) {
|
||||
const missingDescription = blocks.some(
|
||||
(block) => block.files.length > 0 && !block.description?.trim()
|
||||
);
|
||||
if (missingDescription) {
|
||||
return `Заполните описание для документа "${doc.name}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const customMissingDescription = customFileBlocks.some(
|
||||
(block) => block.files.length > 0 && !block.description?.trim()
|
||||
@@ -737,8 +737,8 @@ export default function StepWizardPlan({
|
||||
}
|
||||
if (cat.includes('payment') || cat.includes('cheque') || cat.includes('receipt') ||
|
||||
cat.includes('подтверждение') || cat === 'payment_proof') {
|
||||
return 'upload_payment';
|
||||
}
|
||||
return 'upload_payment';
|
||||
}
|
||||
if (cat.includes('correspondence') || cat.includes('chat') || cat.includes('переписка')) {
|
||||
return 'upload_correspondence';
|
||||
}
|
||||
@@ -906,7 +906,7 @@ export default function StepWizardPlan({
|
||||
eventSourceRef.current = null;
|
||||
|
||||
// Переходим к следующему шагу (форма подтверждения)
|
||||
onNext();
|
||||
onNext();
|
||||
} else if (data.event_type === 'claim_plan_error' || data.status === 'error') {
|
||||
message.destroy();
|
||||
message.error(data.message || 'Ошибка получения данных заявления');
|
||||
@@ -1049,14 +1049,14 @@ export default function StepWizardPlan({
|
||||
// Кнопка "Удалить" только если это дополнительный блок (idx > 0)
|
||||
// Первый блок предустановленного документа удалять нельзя
|
||||
(currentBlocks.length > 1 && idx > 0) && (
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
size="small"
|
||||
onClick={() => removeDocumentBlock(docId, block.id)}
|
||||
>
|
||||
Удалить
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
size="small"
|
||||
onClick={() => removeDocumentBlock(docId, block.id)}
|
||||
>
|
||||
Удалить
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -1064,28 +1064,28 @@ export default function StepWizardPlan({
|
||||
{/* Поле описания показываем только для дополнительных блоков (idx > 0)
|
||||
или для общих документов (docs_exist) */}
|
||||
{(idx > 0 || !isPredefinedDoc) && (
|
||||
<Input
|
||||
<Input
|
||||
placeholder="Уточните тип документа (например: Претензия от 12.05)"
|
||||
value={block.description}
|
||||
onChange={(e) =>
|
||||
updateDocumentBlock(docId, block.id, { description: e.target.value })
|
||||
}
|
||||
/>
|
||||
value={block.description}
|
||||
onChange={(e) =>
|
||||
updateDocumentBlock(docId, block.id, { description: e.target.value })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Выпадашка категорий только для общих вопросов (docs_exist, correspondence_exist) */}
|
||||
{!isPredefinedDoc && (
|
||||
<Select
|
||||
value={block.category || docId}
|
||||
onChange={(value) => updateDocumentBlock(docId, block.id, { category: value })}
|
||||
placeholder="Категория блока"
|
||||
>
|
||||
{documentCategoryOptions.map((option) => (
|
||||
<Option key={`${docId}-${option.value}`} value={option.value}>
|
||||
{option.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
value={block.category || docId}
|
||||
onChange={(value) => updateDocumentBlock(docId, block.id, { category: value })}
|
||||
placeholder="Категория блока"
|
||||
>
|
||||
{documentCategoryOptions.map((option) => (
|
||||
<Option key={`${docId}-${option.value}`} value={option.value}>
|
||||
{option.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
<Dragger
|
||||
@@ -1129,15 +1129,15 @@ export default function StepWizardPlan({
|
||||
))}
|
||||
{/* Кнопка "Добавить" только если документ не пропущен */}
|
||||
{!isSkipped && (!isPredefinedDoc || currentBlocks.length === 0) && (
|
||||
<Button
|
||||
icon={<PlusOutlined />}
|
||||
<Button
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => addDocumentBlock(docId, docLabel, docList)}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{isPredefinedDoc && currentBlocks.length === 0
|
||||
? `Загрузить ${singleDocName || docLabel}`
|
||||
: `Добавить документы (${docLabel})`}
|
||||
</Button>
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
);
|
||||
@@ -1258,14 +1258,14 @@ export default function StepWizardPlan({
|
||||
return prev[question.ask_if!.field] !== curr[question.ask_if!.field];
|
||||
} : true} // ✅ Для безусловных полей shouldUpdate=true, чтобы render function работала
|
||||
>
|
||||
{() => {
|
||||
const values = form.getFieldsValue(true);
|
||||
if (!evaluateCondition(question.ask_if, values)) {
|
||||
{() => {
|
||||
const values = form.getFieldsValue(true);
|
||||
if (!evaluateCondition(question.ask_if, values)) {
|
||||
console.log(`⏭️ Question ${question.name} skipped: condition not met`, question.ask_if, values);
|
||||
return null;
|
||||
}
|
||||
const questionDocs = documentGroups[question.name] || [];
|
||||
const questionValue = values?.[question.name];
|
||||
return null;
|
||||
}
|
||||
const questionDocs = documentGroups[question.name] || [];
|
||||
const questionValue = values?.[question.name];
|
||||
|
||||
// Скрываем вопросы, которые связаны с загрузкой документов
|
||||
// Если в плане визарда есть документы, не показываем поля про загрузку (text/textarea/file)
|
||||
@@ -1308,23 +1308,23 @@ export default function StepWizardPlan({
|
||||
|
||||
console.log(`✅ Question ${question.name} will render:`, { input_type: question.input_type, label: question.label, required: question.required });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
label={question.label}
|
||||
name={question.name}
|
||||
rules={[
|
||||
{
|
||||
required: question.required,
|
||||
message: 'Поле обязательно для заполнения',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{renderQuestionField(question)}
|
||||
</Form.Item>
|
||||
{questionDocs.length > 0 && isAffirmative(questionValue) && (
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<Text strong>Загрузите документы:</Text>
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
label={question.label}
|
||||
name={question.name}
|
||||
rules={[
|
||||
{
|
||||
required: question.required,
|
||||
message: 'Поле обязательно для заполнения',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{renderQuestionField(question)}
|
||||
</Form.Item>
|
||||
{questionDocs.length > 0 && isAffirmative(questionValue) && (
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<Text strong>Загрузите документы:</Text>
|
||||
<Space direction="vertical" style={{ width: '100%', marginTop: 16 }}>
|
||||
{questionDocs.map((doc) => {
|
||||
// Используем doc.id как ключ для отдельного хранения блоков каждого документа
|
||||
@@ -1336,12 +1336,12 @@ export default function StepWizardPlan({
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1354,7 +1354,7 @@ export default function StepWizardPlan({
|
||||
</Form>
|
||||
{renderCustomUploads()}
|
||||
</>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
if (!formData.session_id) {
|
||||
@@ -1383,18 +1383,191 @@ export default function StepWizardPlan({
|
||||
});
|
||||
|
||||
// Состояние для поэкранной загрузки документов (новый флоу)
|
||||
const [currentDocIndex, setCurrentDocIndex] = useState(formData.current_doc_index || 0);
|
||||
// Убираем дубликаты при инициализации
|
||||
const initialUploadedDocs = formData.documents_uploaded?.map((d: any) => d.type || d.id) || [];
|
||||
const [uploadedDocs, setUploadedDocs] = useState<string[]>(Array.from(new Set(initialUploadedDocs)));
|
||||
const [skippedDocs, setSkippedDocs] = useState<string[]>(formData.documents_skipped || []);
|
||||
|
||||
// Отладка: логируем инициализацию
|
||||
useEffect(() => {
|
||||
console.log('🔍 Инициализация документов:', {
|
||||
documentsRequiredCount: documentsRequired.length,
|
||||
initialUploadedDocs,
|
||||
uploadedDocs,
|
||||
skippedDocs,
|
||||
formDataCurrentDocIndex: formData.current_doc_index,
|
||||
});
|
||||
}, []); // Только при первой загрузке
|
||||
|
||||
// Находим первый незагруженный документ при инициализации
|
||||
const findFirstUnprocessedDoc = useCallback((startIndex: number = 0) => {
|
||||
for (let i = startIndex; i < documentsRequired.length; i++) {
|
||||
const doc = documentsRequired[i];
|
||||
const docId = doc.id || doc.name;
|
||||
if (!uploadedDocs.includes(docId) && !skippedDocs.includes(docId)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return documentsRequired.length; // Все документы обработаны
|
||||
}, [documentsRequired, uploadedDocs, skippedDocs]);
|
||||
|
||||
const [currentDocIndex, setCurrentDocIndex] = useState(() => {
|
||||
const savedIndex = formData.current_doc_index || 0;
|
||||
// Используем initialUploadedDocs и formData.documents_skipped для инициализации
|
||||
const initUploaded = Array.from(new Set(initialUploadedDocs));
|
||||
const initSkipped = formData.documents_skipped || [];
|
||||
|
||||
// Находим первый незагруженный документ
|
||||
// Сначала проверяем с сохранённого индекса, потом с начала
|
||||
let firstUnprocessed = documentsRequired.length; // По умолчанию - все обработаны
|
||||
|
||||
// Проверяем с сохранённого индекса до конца
|
||||
for (let i = savedIndex; i < documentsRequired.length; i++) {
|
||||
const doc = documentsRequired[i];
|
||||
const docId = doc.id || doc.name;
|
||||
if (!initUploaded.includes(docId) && !initSkipped.includes(docId)) {
|
||||
firstUnprocessed = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Если не нашли с сохранённого индекса, проверяем с начала до сохранённого
|
||||
if (firstUnprocessed === documentsRequired.length) {
|
||||
for (let i = 0; i < savedIndex; i++) {
|
||||
const doc = documentsRequired[i];
|
||||
const docId = doc.id || doc.name;
|
||||
if (!initUploaded.includes(docId) && !initSkipped.includes(docId)) {
|
||||
firstUnprocessed = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 Инициализация currentDocIndex:', {
|
||||
savedIndex,
|
||||
firstUnprocessed,
|
||||
documentsRequiredLength: documentsRequired.length,
|
||||
initUploaded,
|
||||
initSkipped,
|
||||
documentsRequiredList: documentsRequired.map((d: any) => ({
|
||||
id: d.id || d.name,
|
||||
name: d.name,
|
||||
uploaded: initUploaded.includes(d.id || d.name),
|
||||
skipped: initSkipped.includes(d.id || d.name),
|
||||
})),
|
||||
});
|
||||
// Убеждаемся, что индекс не выходит за границы
|
||||
return Math.min(firstUnprocessed, documentsRequired.length);
|
||||
});
|
||||
|
||||
// Исправляем currentDocIndex только если он выходит за границы или указывает на уже обработанный документ
|
||||
useEffect(() => {
|
||||
if (documentsRequired.length === 0) return;
|
||||
|
||||
// Если текущий индекс выходит за границы, исправляем
|
||||
if (currentDocIndex >= documentsRequired.length) {
|
||||
const firstUnprocessed = findFirstUnprocessedDoc(0);
|
||||
console.log('🔄 Исправление currentDocIndex (выход за границы):', {
|
||||
currentIndex: currentDocIndex,
|
||||
documentsRequiredLength: documentsRequired.length,
|
||||
firstUnprocessed,
|
||||
});
|
||||
setCurrentDocIndex(firstUnprocessed);
|
||||
updateFormData({ current_doc_index: firstUnprocessed });
|
||||
return;
|
||||
}
|
||||
|
||||
// Если текущий документ уже обработан, переходим к следующему
|
||||
const currentDoc = documentsRequired[currentDocIndex];
|
||||
if (currentDoc) {
|
||||
const docId = currentDoc.id || currentDoc.name;
|
||||
if (uploadedDocs.includes(docId) || skippedDocs.includes(docId)) {
|
||||
const firstUnprocessed = findFirstUnprocessedDoc(currentDocIndex + 1);
|
||||
console.log('🔄 Исправление currentDocIndex (документ уже обработан):', {
|
||||
currentIndex: currentDocIndex,
|
||||
currentDocId: docId,
|
||||
firstUnprocessed,
|
||||
});
|
||||
setCurrentDocIndex(firstUnprocessed);
|
||||
updateFormData({ current_doc_index: firstUnprocessed });
|
||||
}
|
||||
}
|
||||
}, [currentDocIndex, documentsRequired.length, uploadedDocs, skippedDocs, findFirstUnprocessedDoc, updateFormData]);
|
||||
|
||||
const [docChoice, setDocChoice] = useState<'upload' | 'none'>('upload'); // Выбор: загрузить или нет документа (по умолчанию - загрузить)
|
||||
const [currentUploadedFiles, setCurrentUploadedFiles] = useState<any[]>([]); // Массив загруженных файлов
|
||||
|
||||
// Текущий документ для загрузки
|
||||
const currentDoc = documentsRequired[currentDocIndex];
|
||||
const isLastDoc = currentDocIndex >= documentsRequired.length - 1;
|
||||
const allDocsProcessed = currentDocIndex >= documentsRequired.length;
|
||||
|
||||
// Проверяем, что ВСЕ документы либо загружены, либо пропущены
|
||||
const allDocsProcessed = useMemo(() => {
|
||||
// Проверяем каждый документ из documentsRequired
|
||||
const allRequiredDocsProcessed = documentsRequired.every((doc: any) => {
|
||||
const docId = doc.id || doc.name;
|
||||
return uploadedDocs.includes(docId) || skippedDocs.includes(docId);
|
||||
});
|
||||
|
||||
const processedCount = uploadedDocs.length + skippedDocs.length;
|
||||
const allProcessed = allRequiredDocsProcessed && processedCount >= documentsRequired.length;
|
||||
|
||||
console.log('🔍 Проверка завершённости:', {
|
||||
uploadedDocs: uploadedDocs.length,
|
||||
skippedDocs: skippedDocs.length,
|
||||
totalRequired: documentsRequired.length,
|
||||
processedCount,
|
||||
allRequiredDocsProcessed,
|
||||
allProcessed,
|
||||
uploadedDocsList: uploadedDocs,
|
||||
skippedDocsList: skippedDocs,
|
||||
requiredDocsList: documentsRequired.map((d: any) => {
|
||||
const docId = d.id || d.name;
|
||||
return {
|
||||
id: docId,
|
||||
name: d.name,
|
||||
uploaded: uploadedDocs.includes(docId),
|
||||
skipped: skippedDocs.includes(docId),
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
return allProcessed;
|
||||
}, [uploadedDocs, skippedDocs, documentsRequired]);
|
||||
|
||||
// Отладка: логируем состояние текущего документа
|
||||
useEffect(() => {
|
||||
console.log('🔍 Текущий документ для загрузки:', {
|
||||
currentDocIndex,
|
||||
documentsRequiredLength: documentsRequired.length,
|
||||
currentDoc: currentDoc ? { id: currentDoc.id, name: currentDoc.name } : null,
|
||||
uploadedDocs,
|
||||
skippedDocs,
|
||||
allDocsProcessed,
|
||||
});
|
||||
}, [currentDocIndex, documentsRequired.length, currentDoc, uploadedDocs, skippedDocs, allDocsProcessed]);
|
||||
|
||||
// Автоматически пропускаем уже загруженные документы
|
||||
useEffect(() => {
|
||||
if (!currentDoc || allDocsProcessed) return;
|
||||
|
||||
const docId = currentDoc.id || currentDoc.name;
|
||||
const isAlreadyUploaded = uploadedDocs.includes(docId);
|
||||
const isAlreadySkipped = skippedDocs.includes(docId);
|
||||
|
||||
if (isAlreadyUploaded || isAlreadySkipped) {
|
||||
console.log(`⏭️ Документ "${currentDoc.name}" уже обработан, переходим к следующему`);
|
||||
const nextIndex = findFirstUnprocessedDoc(currentDocIndex + 1);
|
||||
|
||||
// Обновляем только если следующий индекс отличается от текущего
|
||||
if (nextIndex !== currentDocIndex) {
|
||||
setCurrentDocIndex(nextIndex);
|
||||
updateFormData({
|
||||
current_doc_index: nextIndex,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [currentDoc, uploadedDocs, skippedDocs, currentDocIndex, allDocsProcessed, findFirstUnprocessedDoc, updateFormData]);
|
||||
|
||||
// Обработчик выбора файлов (НЕ отправляем сразу, только сохраняем)
|
||||
const handleFilesChange = (fileList: any[]) => {
|
||||
@@ -1418,13 +1591,26 @@ export default function StepWizardPlan({
|
||||
const newSkipped = [...skippedDocs, currentDoc.id];
|
||||
setSkippedDocs(newSkipped);
|
||||
|
||||
// Находим следующий незагруженный документ (используем обновлённый список)
|
||||
const findNextUnprocessed = (startIndex: number) => {
|
||||
for (let i = startIndex; i < documentsRequired.length; i++) {
|
||||
const doc = documentsRequired[i];
|
||||
const docId = doc.id || doc.name;
|
||||
if (!uploadedDocs.includes(docId) && !newSkipped.includes(docId)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return documentsRequired.length;
|
||||
};
|
||||
const nextIndex = findNextUnprocessed(currentDocIndex + 1);
|
||||
|
||||
updateFormData({
|
||||
documents_skipped: newSkipped,
|
||||
current_doc_index: currentDocIndex + 1,
|
||||
current_doc_index: nextIndex,
|
||||
});
|
||||
|
||||
// Переход к следующему (сброс состояния в useEffect)
|
||||
setCurrentDocIndex(prev => prev + 1);
|
||||
// Переход к следующему незагруженному документу
|
||||
setCurrentDocIndex(nextIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1488,13 +1674,26 @@ export default function StepWizardPlan({
|
||||
: [...uploadedDocs, currentDoc.id];
|
||||
setUploadedDocs(newUploaded);
|
||||
|
||||
// Находим следующий незагруженный документ (используем обновлённый список)
|
||||
const findNextUnprocessed = (startIndex: number) => {
|
||||
for (let i = startIndex; i < documentsRequired.length; i++) {
|
||||
const doc = documentsRequired[i];
|
||||
const docId = doc.id || doc.name;
|
||||
if (!newUploaded.includes(docId) && !skippedDocs.includes(docId)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return documentsRequired.length;
|
||||
};
|
||||
const nextIndex = findNextUnprocessed(currentDocIndex + 1);
|
||||
|
||||
updateFormData({
|
||||
documents_uploaded: uploadedDocsData,
|
||||
current_doc_index: currentDocIndex + 1,
|
||||
current_doc_index: nextIndex,
|
||||
});
|
||||
|
||||
// Переход к следующему (сброс состояния в useEffect)
|
||||
setCurrentDocIndex(prev => prev + 1);
|
||||
// Переход к следующему незагруженному документу
|
||||
setCurrentDocIndex(nextIndex);
|
||||
|
||||
} catch (error: any) {
|
||||
message.error(`Ошибка загрузки: ${error.message}`);
|
||||
@@ -1540,16 +1739,16 @@ export default function StepWizardPlan({
|
||||
}}
|
||||
>
|
||||
{/* ✅ НОВЫЙ ФЛОУ: Поэкранная загрузка документов */}
|
||||
{hasNewFlowDocs && !allDocsProcessed && currentDoc && (
|
||||
{hasNewFlowDocs && !allDocsProcessed && currentDocIndex < documentsRequired.length && currentDoc ? (
|
||||
<div style={{ padding: '24px 0' }}>
|
||||
{/* Прогресс */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
|
||||
<Text type="secondary">Документ {currentDocIndex + 1} из {documentsRequired.length}</Text>
|
||||
<Text type="secondary">{Math.round((currentDocIndex / documentsRequired.length) * 100)}% завершено</Text>
|
||||
<Text type="secondary">{Math.round(((uploadedDocs.length + skippedDocs.length) / documentsRequired.length) * 100)}% завершено</Text>
|
||||
</div>
|
||||
<Progress
|
||||
percent={Math.round((currentDocIndex / documentsRequired.length) * 100)}
|
||||
percent={Math.round(((uploadedDocs.length + skippedDocs.length) / documentsRequired.length) * 100)}
|
||||
showInfo={false}
|
||||
strokeColor="#595959"
|
||||
/>
|
||||
@@ -1659,20 +1858,52 @@ export default function StepWizardPlan({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ✅ НОВЫЙ ФЛОУ: Все документы загружены */}
|
||||
{hasNewFlowDocs && allDocsProcessed && (
|
||||
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
||||
<Title level={4}>✅ Все документы загружены!</Title>
|
||||
<Paragraph type="secondary">
|
||||
) : hasNewFlowDocs && !allDocsProcessed && currentDocIndex >= documentsRequired.length ? (
|
||||
<div style={{ padding: '24px 0', textAlign: 'center' }}>
|
||||
<Text type="warning">
|
||||
⚠️ Ошибка: индекс документа ({currentDocIndex}) выходит за границы массива ({documentsRequired.length}).
|
||||
<br />
|
||||
Загружено: {uploadedDocs.length}, пропущено: {skippedDocs.length}
|
||||
</Paragraph>
|
||||
<Button type="primary" size="large" onClick={handleAllDocsComplete}>
|
||||
Продолжить →
|
||||
</Text>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginTop: 16 }}
|
||||
onClick={() => {
|
||||
const nextIndex = findFirstUnprocessedDoc(0);
|
||||
setCurrentDocIndex(nextIndex);
|
||||
updateFormData({ current_doc_index: nextIndex });
|
||||
}}
|
||||
>
|
||||
Исправить и продолжить
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{/* ✅ НОВЫЙ ФЛОУ: Все документы загружены */}
|
||||
{hasNewFlowDocs && allDocsProcessed && (() => {
|
||||
// Правильно считаем загруженные и пропущенные документы из documentsRequired
|
||||
const uploadedCount = documentsRequired.filter((doc: any) => {
|
||||
const docId = doc.id || doc.name;
|
||||
return uploadedDocs.includes(docId);
|
||||
}).length;
|
||||
|
||||
const skippedCount = documentsRequired.filter((doc: any) => {
|
||||
const docId = doc.id || doc.name;
|
||||
return skippedDocs.includes(docId);
|
||||
}).length;
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
||||
<Title level={4}>✅ Все документы обработаны!</Title>
|
||||
<Paragraph type="secondary">
|
||||
Загружено: {uploadedCount} из {documentsRequired.length}, пропущено: {skippedCount}
|
||||
</Paragraph>
|
||||
<Button type="primary" size="large" onClick={handleAllDocsComplete}>
|
||||
Продолжить →
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* СТАРЫЙ ФЛОУ: Ожидание визарда */}
|
||||
{!hasNewFlowDocs && isWaiting && (
|
||||
@@ -1719,41 +1950,41 @@ export default function StepWizardPlan({
|
||||
|
||||
{documents.length > 0 && (
|
||||
<>
|
||||
<Card
|
||||
size="small"
|
||||
style={{
|
||||
<Card
|
||||
size="small"
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
background: '#fff',
|
||||
background: '#fff',
|
||||
border: '1px solid #d9d9d9',
|
||||
marginBottom: 24,
|
||||
}}
|
||||
title="Документы, которые понадобятся"
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
{documents.map((doc: any) => (
|
||||
<div
|
||||
key={doc.id}
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Text strong>{doc.name}</Text>
|
||||
<Paragraph type="secondary" style={{ marginBottom: 0 }}>
|
||||
{doc.hints}
|
||||
</Paragraph>
|
||||
</div>
|
||||
<Tag color={doc.required ? 'volcano' : 'geekblue'}>
|
||||
{doc.required ? 'Обязательно' : 'Опционально'}
|
||||
</Tag>
|
||||
marginBottom: 24,
|
||||
}}
|
||||
title="Документы, которые понадобятся"
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
{documents.map((doc: any) => (
|
||||
<div
|
||||
key={doc.id}
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Text strong>{doc.name}</Text>
|
||||
<Paragraph type="secondary" style={{ marginBottom: 0 }}>
|
||||
{doc.hints}
|
||||
</Paragraph>
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
<Tag color={doc.required ? 'volcano' : 'geekblue'}>
|
||||
{doc.required ? 'Обязательно' : 'Опционально'}
|
||||
</Tag>
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
{/* Блоки загрузки для каждого документа из плана */}
|
||||
<div style={{ marginTop: 16, marginBottom: 24 }}>
|
||||
|
||||
Reference in New Issue
Block a user