pcp-tgu: статусы плана — актуальная легенда с тултипами + док жизненного цикла
- STATUS_STYLES в порядке жизненного цикла: убран легаси ACCEPTED, добавлены LAID_IN/NOT_ACCEPTED/LAYIN_FAILED, у каждого статуса человеческое описание. - Легенда вкладки «Планы»: тултипы по наведению (title=description), убрана устаревшая приписка про стрелки. - TimelineStatusStyle: добавлено обязательное поле description. - HandlePlanDecisionUseCase: TODO(layin-confirmed) — обработчик приёма события «план заложен» (AWAITING_LAYIN → LAID_IN) ещё не реализован. - docs/architect/PCP_TGU_PLAN_STATUS_LIFECYCLE.md: справочник по каждому статусу (когда наступает / что значит / какой переход), диаграмма, зарезервированный ACCEPTED.
This commit is contained in:
@@ -4,12 +4,11 @@ export function TguLegend() {
|
||||
return (
|
||||
<div className="tgu-legend" aria-label="Легенда статусов">
|
||||
{STATUS_STYLES.map((item) => (
|
||||
<span className="tgu-legend__item" key={item.label}>
|
||||
<span className="tgu-legend__item" key={item.label} title={item.description}>
|
||||
<span className={`tgu-legend__swatch ${item.className}`} />
|
||||
{item.label}
|
||||
</span>
|
||||
))}
|
||||
<span className="tgu-legend__note">Стрелки показывают следующий план того же КА по времени.</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,51 @@
|
||||
import type { TguPlanStatus } from "../../model/tguTypes";
|
||||
import type { TimelineStatusStyle } from "../../model/timelineTypes";
|
||||
|
||||
// Порядок — по жизненному циклу плана (см. docs/architect/PCP_TGU_PLAN_STATUS_LIFECYCLE.md).
|
||||
// ACCEPTED из enum бэка здесь намеренно отсутствует: приёмка переводит план сразу в AWAITING_LAYIN.
|
||||
// LAID_IN показан, хотя пока не возникает — нужен обработчик события подтверждения закладки
|
||||
// (AWAITING_LAYIN → LAID_IN), см. TODO в HandlePlanDecisionUseCase и док жизненного цикла.
|
||||
export const STATUS_STYLES: TimelineStatusStyle[] = [
|
||||
{ status: "ACCEPTED", label: "ACCEPTED", color: "#2f9e44", className: "status-accepted" },
|
||||
{ status: "REJECTED", label: "REJECTED", color: "#d64545", className: "status-rejected" },
|
||||
{ status: "WAITING_DECISION", label: "WAITING_DECISION", color: "#f0ad2e", className: "status-waiting" },
|
||||
{ status: "PLANNED", label: "PLANNED", color: "#8d99a6", className: "status-planned" },
|
||||
{ status: "ISSUING", label: "ISSUING", color: "#2f80ed", className: "status-issuing" },
|
||||
{ status: "START_AMBIGUOUS", label: "START_AMBIGUOUS", color: "#b42318", className: "status-ambiguous" },
|
||||
{ status: "DRAFT", label: "ЧЕРНОВИК", color: "#a98bdb", className: "status-draft" }
|
||||
{
|
||||
status: "DRAFT", label: "ЧЕРНОВИК", color: "#a98bdb", className: "status-draft",
|
||||
description: "Черновик: план в стадии правки, в выдачу пока не идёт."
|
||||
},
|
||||
{
|
||||
status: "PLANNED", label: "PLANNED", color: "#8d99a6", className: "status-planned",
|
||||
description: "Возможный будущий план (проекция цепочки)."
|
||||
},
|
||||
{
|
||||
status: "ISSUING", label: "ISSUING", color: "#2f80ed", className: "status-issuing",
|
||||
description: "Идёт выдача плана."
|
||||
},
|
||||
{
|
||||
status: "WAITING_DECISION", label: "WAITING_DECISION", color: "#f0ad2e", className: "status-waiting",
|
||||
description: "План выдан, ожидается решение (принять / отклонить)."
|
||||
},
|
||||
{
|
||||
status: "AWAITING_LAYIN", label: "AWAITING_LAYIN", color: "#2f9e44", className: "status-awaiting-layin",
|
||||
description: "План принят, ожидается подтверждение закладки."
|
||||
},
|
||||
{
|
||||
status: "LAID_IN", label: "LAID_IN", color: "#1b6b34", className: "status-laid-in",
|
||||
description: "Получено подтверждение закладки плана."
|
||||
},
|
||||
{
|
||||
status: "START_AMBIGUOUS", label: "START_AMBIGUOUS", color: "#b42318", className: "status-ambiguous",
|
||||
description: "Ошибка после старта процесса выдачи плана. Требуется оператор."
|
||||
},
|
||||
{
|
||||
status: "REJECTED", label: "REJECTED", color: "#d64545", className: "status-rejected",
|
||||
description: "План отклонён, цепочка поставлена на паузу."
|
||||
},
|
||||
{
|
||||
status: "NOT_ACCEPTED", label: "NOT_ACCEPTED", color: "#e8590c", className: "status-not-accepted",
|
||||
description: "План не принят, идёт срочная перевыдача на ближайшую ЗРВ."
|
||||
},
|
||||
{
|
||||
status: "LAYIN_FAILED", label: "LAYIN_FAILED", color: "#a61e4d", className: "status-layin-failed",
|
||||
description: "План не заложен, идёт срочная перевыдача на ближайшую ЗРВ."
|
||||
}
|
||||
];
|
||||
|
||||
const STATUS_BY_NAME = new Map(STATUS_STYLES.map((style) => [style.status, style]));
|
||||
@@ -19,7 +56,8 @@ export function statusStyle(status: TguPlanStatus): TimelineStatusStyle {
|
||||
status,
|
||||
label: status || "UNKNOWN",
|
||||
color: "#79828d",
|
||||
className: "status-unknown"
|
||||
className: "status-unknown",
|
||||
description: "Неизвестный статус."
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,4 +59,6 @@ export type TimelineStatusStyle = {
|
||||
label: string;
|
||||
color: string;
|
||||
className: string;
|
||||
/** Человеческое пояснение статуса — тултип в легенде. */
|
||||
description: string;
|
||||
};
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
white-space: nowrap;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.tgu-legend__swatch {
|
||||
@@ -159,18 +160,26 @@
|
||||
background: #79828d;
|
||||
}
|
||||
|
||||
.tgu-legend__note {
|
||||
color: var(--accent-strong);
|
||||
.status-awaiting-layin {
|
||||
background-color: #2f9e44;
|
||||
}
|
||||
|
||||
.status-accepted {
|
||||
background-color: #2f9e44;
|
||||
.status-laid-in {
|
||||
background-color: #1b6b34;
|
||||
}
|
||||
|
||||
.status-rejected {
|
||||
background-color: #d64545;
|
||||
}
|
||||
|
||||
.status-not-accepted {
|
||||
background-color: #e8590c;
|
||||
}
|
||||
|
||||
.status-layin-failed {
|
||||
background-color: #a61e4d;
|
||||
}
|
||||
|
||||
.status-waiting {
|
||||
background-color: #f0ad2e;
|
||||
}
|
||||
|
||||
+7
@@ -82,6 +82,13 @@ class HandlePlanDecisionUseCase(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(layin-confirmed): реализовать приём события «план заложен» (положительный фидбек по закладке).
|
||||
// Сейчас принятый план остаётся в AWAITING_LAYIN (оптимистично «заложен») и в LAID_IN никогда не
|
||||
// переходит — нет потребителя этого события. Нужно: Kafka-consumer (по аналогии с LayinFailedConsumer)
|
||||
// + handleLayinConfirmed, который по текущему базовому плану в AWAITING_LAYIN переводит его в
|
||||
// PlannedPlanStatus.LAID_IN (терминальный успех, «точка невозврата»: дальше только fork-forward).
|
||||
// См. docs/architect/PCP_TGU_PLAN_STATUS_LIFECYCLE.md.
|
||||
|
||||
/** Событие «не заложен» по базовому плану — срочная перевыдача на ближайшую ЗРВ. */
|
||||
@Transactional
|
||||
fun handleLayinFailed(message: PlanExecutionFeedbackMessage) {
|
||||
|
||||
Reference in New Issue
Block a user