pcp-tgu интерфейс

This commit is contained in:
Дмитрий Соловьев
2026-05-29 16:09:36 +03:00
parent 913b3d7c9b
commit 9fca4d4051
34 changed files with 3163 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
import {
TguApiError,
type TguPlan,
type TguPlanDecision,
type TguPlanDecisionMessage,
type TguPlatform
} from "../model/tguTypes";
export async function fetchPlatforms(): Promise<TguPlatform[]> {
return fetchJson<TguPlatform[]>("/api/tgu-planning/platforms");
}
export async function fetchPlans(historyDays: number, spacecraftId?: string): Promise<TguPlan[]> {
const query = new URLSearchParams({ historyDays: String(historyDays) });
const path = spacecraftId
? `/api/tgu-planning/spacecraft/${encodeURIComponent(spacecraftId)}/plans?${query}`
: `/api/tgu-planning/plans?${query}`;
return fetchJson<TguPlan[]>(path);
}
export async function sendPlanDecision(
planId: string,
decision: TguPlanDecision,
reason?: string
): Promise<TguPlanDecisionMessage> {
const query = new URLSearchParams({ decision });
if (reason?.trim()) {
query.set("reason", reason.trim());
}
return fetchJson<TguPlanDecisionMessage>(
`/api/tgu-planning/plans/${encodeURIComponent(planId)}/decision?${query}`,
{ method: "POST" },
true
);
}
async function fetchJson<T>(url: string, init?: RequestInit, decisionRequest = false): Promise<T> {
let response: Response;
try {
response = await fetch(url, {
headers: { Accept: "application/json" },
...init
});
} catch (error) {
throw new TguApiError("Не удалось подключиться к backend API.", "network");
}
const text = await response.text();
if (!response.ok) {
throw new TguApiError(errorMessage(response.status, text, decisionRequest), "http", response.status);
}
if (!text.trim()) {
return undefined as T;
}
return JSON.parse(text) as T;
}
function errorMessage(status: number, body: string, decisionRequest: boolean): string {
if (decisionRequest && status === 404) {
return "План не найден.";
}
if (decisionRequest && status === 409) {
return "План не является активным планом, ожидающим решения, или для него нет active attempt.";
}
if (decisionRequest && status >= 500) {
return "Ошибка сервиса при отправке решения.";
}
return extractErrorText(body) || "Ошибка backend API.";
}
function extractErrorText(body: string): string {
const trimmed = body.trim();
if (!trimmed) return "";
try {
const parsed = JSON.parse(trimmed) as Record<string, unknown>;
for (const field of ["reason", "message", "error", "detail"]) {
const value = parsed[field];
if (typeof value === "string" && value.trim()) {
return value;
}
}
} catch {
return trimmed;
}
return trimmed;
}