pcp-tgu: связь планов на таймлайне по basePlanId вместо стрелок/нумерации по времени

Стрелки и бейджи-цифры цепочки строились по ВРЕМЕНИ (соседние по времени
планы КА) и ложно сцепляли два черновика с одной предысторией как «один —
предок другого». Убираем эту логику целиком (buildSequentialLinks,
buildPlanChains, CHAIN_COLORS/chainColor, тип TimelineLink) и показываем
связь только по реальному basePlanId:

- В деталях плана — строка basePlanId (рендерится, если задан).
- При выборе плана на таймлайне подсвечиваем гало два соседних звена по
  basePlanId: предыдущий (planId == basePlanId выбранного) — тёплый янтарь,
  следующий (basePlanId == выбранный) — бирюза. Следующих может быть
  несколько (черновики с одной предысторией) — подсвечиваются все.

Бэкенд: basePlanId/projected проброшены через PlanResponse (pcp-tgu-service)
и TguPlanResponse (pcp-ui-service — прокси /api/tgu-planning/plans, иначе
Jackson срезал бы неизвестные поля). Требует рестарт обоих сервисов.

Заодно: очистка нотиса деталей при смене фокуса (план/ЗРВ) и блок
«Включения» (счётчики съёмок/сбросов) в правой панели.
This commit is contained in:
Дмитрий Соловьев
2026-06-04 11:44:28 +03:00
parent 294b17757d
commit a5a1cdfa64
10 changed files with 150 additions and 96 deletions
@@ -31,7 +31,21 @@ data class PlanResponse(
val kppId: String,
/** Статус persisted плана в жизненном цикле выдачи. */
val status: PlannedPlanStatus
val status: PlannedPlanStatus,
/**
* Непосредственный предшественник плана в цепочке (`base_plan_id`). `null` — у плана нет
* предыстории: это начало новой цепочки (создан «без истории») либо самый первый план.
* Фронт по этому полю решает, рисовать ли входящую стрелку: в старт цепочки она не ведёт.
*/
val basePlanId: UUID? = null,
/**
* `true` — это вычисленная на лету проекция будущего (в БД не записана), а не persisted-план.
* У проекции предшественник не хранится, но цепочку она продолжает — фронт связывает её
* соседние звенья по времени, поэтому начало цепочки определяется ТОЛЬКО для persisted.
*/
val projected: Boolean = false
) {
companion object {
@@ -46,7 +60,9 @@ data class PlanResponse(
startTime = plan.startTime,
endTime = plan.endTime,
kppId = plan.kppId,
status = plan.status
status = plan.status,
basePlanId = plan.basePlanId,
projected = false
)
/**
@@ -62,7 +78,9 @@ data class PlanResponse(
startTime = plan.startTime,
endTime = plan.endTime,
kppId = plan.kppId,
status = PlannedPlanStatus.PLANNED
status = PlannedPlanStatus.PLANNED,
basePlanId = null,
projected = true
)
private fun deterministicPlanId(plan: CalculatedPlan): UUID {