From e0aa1ccf0e15bf029a0fde53bb48da3aeb0c2b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A1=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=D1=8C=D0=B5=D0=B2?= Date: Tue, 2 Jun 2026 11:25:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B0=D0=B9=D0=BC=D0=BB=D0=B0=D0=B9?= =?UTF-8?q?=D0=BD=20=D0=A2=D0=93=D0=A3:=20=D0=BF=D0=BE=20=D1=83=D0=BC?= =?UTF-8?q?=D0=BE=D0=BB=D1=87=D0=B0=D0=BD=D0=B8=D1=8E=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F=20=D1=86=D0=B5=D0=BF=D0=BE=D1=87=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BB=D0=B0=D0=BD=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раньше таймлайн рисовал планы всех статусов, включая историю версий (SUPERSEDED/EXPIRED/REJECTED), из-за чего активная цепочка тонула в наложении старых планов. Теперь по умолчанию показываются только актуальные планы (PLANNED/ISSUING/WAITING_DECISION/ACCEPTED), а историю версий можно включить чекбоксом над таймлайном. --- .../features/tgu-planning/TguPlanningPage.tsx | 23 +++++++++++++++++-- .../src/features/tgu-planning/tguStatus.ts | 13 +++++++++++ .../src/styles/tgu-planning.css | 21 +++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/services/pcp-tgu-ops-ui/src/features/tgu-planning/TguPlanningPage.tsx b/services/pcp-tgu-ops-ui/src/features/tgu-planning/TguPlanningPage.tsx index cd446e0..6712f23 100644 --- a/services/pcp-tgu-ops-ui/src/features/tgu-planning/TguPlanningPage.tsx +++ b/services/pcp-tgu-ops-ui/src/features/tgu-planning/TguPlanningPage.tsx @@ -10,6 +10,7 @@ import { TguPlanningLayout } from "./TguPlanningLayout"; import { TguSidebar } from "./TguSidebar"; import { TguTimeline } from "./TguTimeline"; import { TguToolbar } from "./TguToolbar"; +import { isActivePlanStatus } from "./tguStatus"; import { buildPlatformsForInterval, buildTimelineRows, mapPlans } from "./tguTimelineMapper"; const DAY_MS = 24 * 60 * 60 * 1000; @@ -28,6 +29,9 @@ export function TguPlanningPage() { const [selectedSpacecraftId, setSelectedSpacecraftId] = useState(); const [selectedPlanId, setSelectedPlanId] = useState(); const [activeTab, setActiveTab] = useState("timeline"); + // По умолчанию на таймлайне видна только актуальная цепочка; история версий + // (SUPERSEDED/EXPIRED/REJECTED и т.п.) скрыта, чтобы не было визуальной каши. + const [showHistory, setShowHistory] = useState(false); // Вкладки рендерятся в режиме keep-alive: каждую монтируем при первом открытии // и дальше держим смонтированной (скрытой через display:none), чтобы её // внутреннее состояние — загруженные заявки, выбор, слои, скролл — не сбрасывалось @@ -98,9 +102,14 @@ export function TguPlanningPage() { () => buildPlatformsForInterval(rawPlatforms, plans, appliedRange), [rawPlatforms, plans, appliedRange] ); + // Планы, показываемые на таймлайне: по умолчанию только актуальная цепочка. + const timelinePlans = useMemo( + () => (showHistory ? plans : plans.filter((plan) => isActivePlanStatus(plan.status))), + [plans, showHistory] + ); const rows = useMemo( - () => buildTimelineRows(plans, platforms, appliedRange, selectedSpacecraftId), - [plans, platforms, appliedRange, selectedSpacecraftId] + () => buildTimelineRows(timelinePlans, platforms, appliedRange, selectedSpacecraftId), + [timelinePlans, platforms, appliedRange, selectedSpacecraftId] ); const selectedPlan = useMemo(() => { const plan = plans.find((item) => item.planId === selectedPlanId); @@ -181,6 +190,16 @@ export function TguPlanningPage() { }} />
+
+ +
[style.status, style])); +/** Статусы актуальной цепочки: их показываем на таймлайне по умолчанию. */ +const ACTIVE_PLAN_STATUSES = new Set([ + "PLANNED", + "ISSUING", + "WAITING_DECISION", + "ACCEPTED" +]); + +/** Проверяет, относится ли план к актуальной цепочке (а не к истории версий). */ +export function isActivePlanStatus(status: TguPlanStatus): boolean { + return ACTIVE_PLAN_STATUSES.has(status); +} + export function statusStyle(status: TguPlanStatus): TimelineStatusStyle { return ( STATUS_BY_NAME.get(status) ?? { diff --git a/services/pcp-tgu-ops-ui/src/styles/tgu-planning.css b/services/pcp-tgu-ops-ui/src/styles/tgu-planning.css index 1152dd2..37e6639 100644 --- a/services/pcp-tgu-ops-ui/src/styles/tgu-planning.css +++ b/services/pcp-tgu-ops-ui/src/styles/tgu-planning.css @@ -346,6 +346,27 @@ background: #121516; } +.tgu-timeline-controls { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.6rem 0.85rem 0; +} + +.tgu-timeline-controls__toggle { + display: inline-flex; + align-items: center; + gap: 0.4rem; + font-size: 0.8rem; + color: var(--muted, #9aa4ad); + cursor: pointer; + user-select: none; +} + +.tgu-timeline-controls__toggle input { + cursor: pointer; +} + .tgu-timeline { min-width: 48rem; min-height: 100%;