feat(tgu-ui): #50 слой поддержки решений по слотам + выбор полосами
Поверх ручного бронирования — информационный слой (достаточность судит оператор). M1 покрытие: coverage.ts (растровое Monte-Carlo % покрытия заявки, чистые функции + coverage.test.ts), CoveragePanel (живой % + бар), слой coverage на карте (drawCoverage, union контуров, клип по заявке). M2 эргономика: сортировка списка по вкладу в покрытие (жадный маргинальный прирост), по крену; колонка «Вклад» (+N%). M3 конфликты: бейдж держателя BUSY-слота (заявка + важность) из holders в SlotDTO. Выбор полосами (TASK_slot-strip-selection it.1): slotStrips.ts (groupStrips — same-roll цепочки по-КА, ε=0.01 с якорным креном, тотальный порядок) + slotStrips.test.ts; toggleStripSelection в slotSelection.ts; чип «полоса ×N» в строке, рельс по StripId в сортировке «время», подсветка полосы при наведении. Физику выполнимости не дублируем на фронте — это backend validate (it.2). Смежный баг: anchorIndexRef (якорь Shift-выбора) сбрасывается при смене видимого набора (фильтры/окно суток), не только сортировки.
This commit is contained in:
@@ -39,6 +39,29 @@ export function selectionAfterCheck(
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* Новое множество выбора после клика по чипу «полоса». Поведение зеркалит «выбрать видимые»,
|
||||
* но в рамках одной полосы: если ВСЕ её видимые выбираемые члены уже выбраны — снимаем их,
|
||||
* иначе добавляем все. Скрытые (отфильтрованные) и BUSY-члены сюда не передаются — выбираем
|
||||
* только то, что видно и можно бронировать (доверие счётчику «Выбрано»). Вход не мутируется.
|
||||
*
|
||||
* @param current Текущее множество выбранных ключей.
|
||||
* @param memberKeys Ключи видимых выбираемых членов полосы.
|
||||
*/
|
||||
export function toggleStripSelection(
|
||||
current: ReadonlySet<string>,
|
||||
memberKeys: readonly string[],
|
||||
): Set<string> {
|
||||
const next = new Set(current)
|
||||
if (memberKeys.length === 0) return next
|
||||
const allSelected = memberKeys.every((k) => current.has(k))
|
||||
for (const k of memberKeys) {
|
||||
if (allSelected) next.delete(k)
|
||||
else next.add(k)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* Разбивает массив на чанки заданного размера (для чанкованной брони крупных наборов).
|
||||
* @param items Исходный массив.
|
||||
|
||||
Reference in New Issue
Block a user