fix(ct): СТ по ссылке открывается после загрузки из SP

Шаги рендерились сразу, а СТ подгружалась позже. Шаг 1 запоминал выбор
при появлении — пустой, и при открытии из реестра показывал «Выберите
позиции», пока не обновить страницу. Теперь до загрузки — спиннер,
ошибка загрузки показывается в форме, а не только в консоли.
This commit is contained in:
Тимур Городецкий
2026-10-22 09:23:19 +05:00
parent 62ebcb2f32
commit f99732962b
2 changed files with 28 additions and 1 deletions
@@ -26,6 +26,13 @@
} }
} }
.loader {
display: flex;
align-items: center;
justify-content: center;
padding: 64px 0;
}
.content { .content {
flex: 1; flex: 1;
background: $surface; background: $surface;
@@ -14,6 +14,7 @@ import { buildOffersFromSpRecords } from './utils/spOffers';
import { isUserInApprovalChain } from './utils/approvalAccess'; import { isUserInApprovalChain } from './utils/approvalAccess';
import { CtAccess, getCtAccess, isCtAuthor } from './utils/ctAccess'; import { CtAccess, getCtAccess, isCtAuthor } from './utils/ctAccess';
import { noOfferRecordsToSuppliers, withNoOfferSuppliers } from './utils/noOfferSuppliers'; import { noOfferRecordsToSuppliers, withNoOfferSuppliers } from './utils/noOfferSuppliers';
import { Alert, Spinner } from '@tnsu/ui-kit';
import styles from './CtCreateForm.module.scss'; import styles from './CtCreateForm.module.scss';
import '@tnsu/ui-kit/styles.css'; import '@tnsu/ui-kit/styles.css';
@@ -35,6 +36,11 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
ensureHighestStep, ensureHighestStep,
} = useCtForm(); } = useCtForm();
// Открыта существующая СТ — шаги не показываем, пока она не загрузится из SP. Иначе шаг 1 успевал
// появиться с пустой сессией и запоминал пустой выбор: «Выберите позиции», хотя позиции в СТ есть.
const [isCtLoading, setIsCtLoading] = useState(!!initialCtId);
const [ctLoadError, setCtLoadError] = useState<string | undefined>(undefined);
// Режим формы — по тому, кто открыл и в каком статусе СТ (getCtAccess), а не по ctid/ctId в ссылке. // Режим формы — по тому, кто открыл и в каком статусе СТ (getCtAccess), а не по ctid/ctId в ссылке.
// Считается на каждом рендере из данных СТ — ничего не «прилипает» в сессии: после «Перезапустить // Считается на каждом рендере из данных СТ — ничего не «прилипает» в сессии: после «Перезапустить
// согласование» или возврата на доработку режим меняется сам. astel-k — цены не видит никогда. // согласование» или возврата на доработку режим меняется сам. astel-k — цены не видит никогда.
@@ -192,11 +198,14 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
markStepComplete(4); markStepComplete(4);
} }
} }
setIsCtLoading(false);
}).catch((err) => { }).catch((err) => {
// Раньше ошибка глоталась молча → при сбое любого запроса форма оставалась // Раньше ошибка глоталась молча → при сбое любого запроса форма оставалась
// на устаревшем статусе из session storage (напр. «Сформирована» вместо // на устаревшем статусе из session storage (напр. «Сформирована» вместо
// «На согласовании»). Теперь хотя бы видно, какой запрос упал. // «На согласовании»). Показываем ошибку, а шаги — по данным сессии, если они есть.
console.error("[CtCreateForm] загрузка СТ по ссылке упала:", err); console.error("[CtCreateForm] загрузка СТ по ссылке упала:", err);
setCtLoadError(`Не удалось загрузить СТ: ${(err as Error).message ?? 'неизвестная ошибка'}`);
setIsCtLoading(false);
}); });
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
@@ -256,8 +265,19 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
} }
}; };
if (isCtLoading) {
return ( return (
<div className={[styles.root, isDarkTheme ? styles.dark : ''].filter(Boolean).join(' ')}> <div className={[styles.root, isDarkTheme ? styles.dark : ''].filter(Boolean).join(' ')}>
<div className={styles.loader}>
<Spinner size="large" label="Загрузка СТ…" />
</div>
</div>
);
}
return (
<div className={[styles.root, isDarkTheme ? styles.dark : ''].filter(Boolean).join(' ')}>
{ctLoadError && <Alert variant="err">{ctLoadError}</Alert>}
<Breadcrumbs <Breadcrumbs
currentStep={currentStep} currentStep={currentStep}
ctNumber={formData.ct?.number} ctNumber={formData.ct?.number}