pcp-tgu интерфейс
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user