feat(tgu-ui): бронирование слотов — виртуализация, автоподбор покрытия, эргономичный мультивыбор
Вкладка «Слоты» масштабирована под ~20k слотов/мес без торможения: - wktCache: контур слота парсится один раз (кэш по slotKey), не на каждый ререндер сцены - виртуализация таблицы (@tanstack/react-virtual): в DOM только видимое окно строк - автоподбор покрытия: проброс coverageStrategy (GREEDY/CONTINUOUS) в request-cover, результат — преднабор брони (solver не дублируется, используется бэкендный) - мультивыбор: Shift-диапазон по отсортированному списку, «все сутки»/«видимые», счётчик охвата выбора - бронь крупных наборов чанками (по 200) + подтверждение выше 500 + прогресс - отмена расчёта (AbortController), мягкая подсказка перегруза карты - чистая логика выбора/чанкинга вынесена в slotSelection.ts + юнит-тесты Тесты: 70/70 (17 новых). tsc -b и vite build чисто.
This commit is contained in:
@@ -925,11 +925,44 @@
|
||||
.tgu-slots-list {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid var(--line);
|
||||
background: var(--bg-panel);
|
||||
}
|
||||
|
||||
/* Прокручиваемая область таблицы слотов — scrollElement виртуализатора. */
|
||||
.tgu-slots-scroll {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Панель выбора над таблицей: счётчик охвата + действия (все сутки / снять). */
|
||||
.tgu-slots-selbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
padding: 0.4rem 0.55rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--bg-panel);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.tgu-slots-selbar__count {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tgu-slots-selbar__sub {
|
||||
color: var(--text-dim);
|
||||
}
|
||||
|
||||
.tgu-slots-selbar__actions {
|
||||
display: flex;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.tgu-slots-empty {
|
||||
padding: 1rem;
|
||||
color: var(--text-dim);
|
||||
@@ -1363,6 +1396,53 @@
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
/* Кнопка отмены внутри оверлея расчёта/автоподбора — на отдельной строке под текстом. */
|
||||
.tgu-map-overlay button {
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Подсказка о перегрузе карты слотами (карту не блокируем). */
|
||||
.tgu-slots-map-hint {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
left: 50%;
|
||||
bottom: 0.85rem;
|
||||
transform: translateX(-50%);
|
||||
max-width: 90%;
|
||||
padding: 0.4rem 0.7rem;
|
||||
border: 1px solid rgba(240, 173, 46, 0.42);
|
||||
border-radius: 7px;
|
||||
background: rgba(17, 19, 21, 0.88);
|
||||
color: #ffe7b5;
|
||||
font-size: 0.78rem;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
/* Баннер подтверждения крупной брони. */
|
||||
.tgu-slots-confirm {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
top: 0.85rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
background: rgba(17, 19, 21, 0.94);
|
||||
color: var(--text);
|
||||
font-size: 0.82rem;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.tgu-slots-confirm__actions {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.tgu-map-errors {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
|
||||
Reference in New Issue
Block a user