pcp-tgu: пауза цепочки после REJECTED + режим «Черновики» + UI цепочек/ЗРВ

Бэкенд (pcp-tgu-service):
- REJECTED трактуется как «план неправильный»: авто-перевыдача больше НЕ
  взводится, цепочка встаёт на паузу (новый флаг
  SpacecraftPlanningStateEntity.pausedAfterReject, миграция V13). Технические
  негативы («не заложен»/«не принят») по-прежнему дают срочную перевыдачу.
- Пауза централизована в PlanProjectionService.project(): для отклонённой
  цепочки проекция пустая, воркер выдачи ничего не материализует. Флаг
  снимается при ручной выдаче/промоуте черновика/приёмке (оператор вмешался).
- Режим «Черновики»: GET /plans/drafts (опц. ?spacecraftId) -> только DRAFT.
- Гард дублей черновиков: (КА + начало + конец) уникальны среди DRAFT,
  повторное создание окна -> 409.
- ZrvWindowMatcher: сравнение по истинной abs-длительности Duration (<=1с),
  устойчиво к усечению ISO на фронте до целых секунд.

Фронт (pcp-tgu-ops-ui): вкладка «Планы» — таймлайн цепочек, детали плана,
панель ЗРВ (TguZrvPanel), диалог создания цепочки, режим черновиков.

Удалён устаревший docs/tasks/TASK_tgu-plan-versioning-manual-reissue.md.
This commit is contained in:
Дмитрий Соловьев
2026-06-04 00:04:47 +03:00
parent 3638afdb85
commit 5049395911
34 changed files with 1062 additions and 458 deletions
@@ -192,6 +192,11 @@
background-color: #79828d;
}
.status-draft {
background-color: #a98bdb;
outline: 1px dashed #e7dbff;
}
.tgu-workspace {
display: grid;
grid-template-columns: 18.5rem minmax(0, 1fr) 22rem;
@@ -382,6 +387,13 @@
font-size: 11px;
}
.tgu-timeline__paused-badge {
fill: #f0a73d;
font-size: 11px;
font-weight: 600;
cursor: help;
}
.tgu-timeline__now {
stroke: #f46e4f;
stroke-width: 1.7;
@@ -426,6 +438,11 @@
stroke-width: 13;
}
/* Черновик на таймлайне — пунктирная линия, чтобы отличить кандидата от реальных планов. */
.tgu-timeline-plan__bar.status-draft {
stroke-dasharray: 7 5;
}
.tgu-timeline-plan__selection {
stroke: #efffff;
stroke-linecap: round;
@@ -536,6 +553,11 @@
padding-top: 0.35rem;
}
/* Действия над черновиком — переносим на несколько строк, чтобы три кнопки помещались. */
.tgu-details__actions--draft {
flex-wrap: wrap;
}
.tgu-alert {
border: 1px solid var(--line);
border-radius: 7px;
@@ -834,6 +856,14 @@
stroke-width: 2;
}
.tgu-2d-map__overlay polyline.is-selected {
stroke: #f0ad2e;
stroke-width: 7;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.85;
}
.tgu-2d-map__overlay circle {
fill: rgba(104, 195, 189, 0.12);
stroke: rgba(130, 222, 216, 0.9);
@@ -1362,10 +1392,26 @@
/* «Создать план»: кнопка над таймлайном + модальный диалог новой цепочки. */
.tgu-center__actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1rem;
padding: 0.5rem 0.75rem 0;
}
.tgu-center__toggle {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.82rem;
color: #c4ced0;
cursor: pointer;
user-select: none;
}
.tgu-center__toggle input {
cursor: pointer;
}
.tgu-chain-dialog__backdrop {
position: fixed;
inset: 0;
@@ -1434,11 +1480,25 @@
color: var(--text-muted, #9fb0b3);
}
/* ЗРВ выбранного КА на таймлайне — лёгкая подсветка доступных зон. */
/* ЗРВ выбранного КА на таймлайне — отдельный страйп снизу строки, не перекрывает планы. */
.tgu-timeline__zrv {
fill: rgba(90, 170, 200, 0.16);
stroke: rgba(90, 170, 200, 0.5);
fill: rgba(90, 170, 200, 0.22);
stroke: rgba(90, 170, 200, 0.6);
stroke-width: 1;
rx: 2;
pointer-events: all;
}
.tgu-timeline__zrv.is-selected {
fill: rgba(240, 173, 46, 0.35);
stroke: #f0ad2e;
stroke-width: 1.6;
}
/* Подпись страйпа ЗРВ слева — как имя КА над цепочкой планов. */
.tgu-timeline__zrv-label {
fill: rgba(90, 170, 200, 0.85);
font-size: 11px;
font-weight: 700;
letter-spacing: 0.04em;
}