354730fb6c
- конфликтные слоты нельзя добавить в выбор под бронь (клик по строке, Shift-диапазон, выбор полосы на карте, «выбрать все») — жёсткая блокировка; снятие выбора не блокируется (конфликт считается только для невыбранных) - слоты одной полосы между собой не конфликтуют (groupOf) — иначе нельзя было бы набрать полосу поштучным кликом - чекбокс «Конфликты» теперь и гасит, и блокирует выбор; выкл. — выбирать любые - переход на прохождение (◀/▶) больше не подсвечивает никакой слот: активная подсветка строки — только по явному клику; добавлена прокрутка к началу прохода - повторный Shift+клик по тому же концу снимает выделение (таблица и карта)
92 lines
4.2 KiB
TypeScript
92 lines
4.2 KiB
TypeScript
import type { CoverageResult } from "./coverage";
|
||
|
||
type CoveragePanelProps = {
|
||
/** Покрытие только забронированным набором. null — покрытие недоступно (нет геометрии/0 сэмплов). */
|
||
booked: CoverageResult | null;
|
||
/** Покрытие union(забронированное ∪ выбранное галочками). */
|
||
withSelection: CoverageResult | null;
|
||
/** Есть ли выбор сверх брони (показывать второй сегмент «с выбором»). */
|
||
hasSelection: boolean;
|
||
/** Геометрия заявки пригодна для расчёта (false → «недоступно»). */
|
||
available: boolean;
|
||
/** Тумблер следа покрытия на карте (D4 — локальный, вкл. по умолчанию). */
|
||
coverageOn: boolean;
|
||
onToggleCoverage: (on: boolean) => void;
|
||
/** Тумблер подсветки конфликтов выбора (тусклый слой) — рядом со следом на карте. */
|
||
showConflicts: boolean;
|
||
onToggleConflicts: (on: boolean) => void;
|
||
};
|
||
|
||
// Панель покрытия над списком слотов (D-D1): «забронировано NN% · с выбором MM%» + двухсегментный
|
||
// бар + явные состояния. Цвет = цвет слоя coverage на карте (violet) — единый язык «покрыто».
|
||
export function CoveragePanel({
|
||
booked,
|
||
withSelection,
|
||
hasSelection,
|
||
available,
|
||
coverageOn,
|
||
onToggleCoverage,
|
||
showConflicts,
|
||
onToggleConflicts,
|
||
}: CoveragePanelProps) {
|
||
const bookedPct = booked?.percent ?? 0;
|
||
const withPct = withSelection?.percent ?? bookedPct;
|
||
// Прирост от выбора (второй сегмент) — поверх забронированного.
|
||
const gainPct = Math.max(0, withPct - bookedPct);
|
||
const lowPrecision = !!(booked?.lowPrecision || withSelection?.lowPrecision);
|
||
|
||
return (
|
||
<div className="tgu-coverage">
|
||
<div className="tgu-coverage__head">
|
||
<span className="tgu-coverage__title">Покрытие заявки</span>
|
||
<div className="tgu-coverage__toggles">
|
||
<label className="tgu-coverage__toggle" title="Показывать след покрытия на карте">
|
||
<input
|
||
type="checkbox"
|
||
checked={coverageOn}
|
||
onChange={(event) => onToggleCoverage(event.target.checked)}
|
||
/>
|
||
След на карте
|
||
</label>
|
||
<label
|
||
className="tgu-coverage__toggle"
|
||
title="Гасить и блокировать выбор слотов, недоступных из-за текущего выбора (тот же КА, не хватает времени на манёвр). Выкл. — выбирать можно любые."
|
||
>
|
||
<input
|
||
type="checkbox"
|
||
checked={showConflicts}
|
||
onChange={(event) => onToggleConflicts(event.target.checked)}
|
||
/>
|
||
Конфликты
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
{!available ? (
|
||
<div className="tgu-coverage__unavailable">Покрытие недоступно — у заявки нет геометрии.</div>
|
||
) : (
|
||
<>
|
||
<div className="tgu-coverage__bar" role="presentation">
|
||
<div className="tgu-coverage__seg tgu-coverage__seg--booked" style={{ width: `${bookedPct}%` }} />
|
||
{hasSelection && gainPct > 0 && (
|
||
<div className="tgu-coverage__seg tgu-coverage__seg--sel" style={{ width: `${gainPct}%` }} />
|
||
)}
|
||
</div>
|
||
<div className="tgu-coverage__legend">
|
||
<span className="tgu-coverage__booked">забронировано {bookedPct}%</span>
|
||
{hasSelection && (
|
||
<span className="tgu-coverage__sel"> · с выбором {withPct}%</span>
|
||
)}
|
||
{lowPrecision && (
|
||
<span className="tgu-coverage__low" title="Заявка слишком мала для надёжной оценки">
|
||
{" "}
|
||
· низкая точность
|
||
</span>
|
||
)}
|
||
</div>
|
||
</>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|