wing-ops/frontend/src/tabs/prediction/services/predictionApi.ts

221 lines
5.3 KiB
TypeScript

import { api } from '@common/services/api';
export interface PredictionAnalysis {
acdntSn: number;
acdntNm: string;
occurredAt: string;
analysisDate: string;
requestor: string;
duration: string;
oilType: string;
volume: number | null;
location: string;
lat: number | null;
lon: number | null;
kospsStatus: string;
poseidonStatus: string;
opendriftStatus: string;
backtrackStatus: string;
analyst: string;
officeName: string;
acdntSttsCd: string;
}
export interface PredictionDetail {
acdnt: {
acdntSn: number;
acdntNm: string;
occurredAt: string;
lat: number | null;
lon: number | null;
location: string;
analyst: string;
officeName: string;
};
spill: {
oilType: string;
volume: number | null;
unit: string;
fcstHr: number | null;
} | null;
vessels: Array<{
vesselInfoSn: number;
imoNo: string;
vesselNm: string;
vesselTp: string;
loaM: number | null;
breadthM: number | null;
draftM: number | null;
gt: number | null;
dwt: number | null;
builtYr: number | null;
flagCd: string;
callsign: string;
engineDc: string;
insuranceData: unknown;
}>;
weather: Array<{
obsDtm: string;
locNm: string;
temp: string;
weatherDc: string;
wind: string;
wave: string;
humid: string;
vis: string;
sst: string;
}>;
}
export interface BacktrackResult {
backtrackSn: number;
acdntSn: number;
estSpilDtm: string | null;
anlysRange: string | null;
lon: number | null;
lat: number | null;
srchRadiusNm: number | null;
totalVessels: number | null;
execSttsCd: string;
rsltData: Record<string, unknown> | null;
}
export const fetchPredictionAnalyses = async (params?: {
search?: string;
}): Promise<PredictionAnalysis[]> => {
const response = await api.get<PredictionAnalysis[]>('/prediction/analyses', { params });
return response.data;
};
export const fetchPredictionDetail = async (acdntSn: number): Promise<PredictionDetail> => {
const response = await api.get<PredictionDetail>(`/prediction/analyses/${acdntSn}`);
return response.data;
};
export const fetchBacktrack = async (sn: number): Promise<BacktrackResult> => {
const response = await api.get<BacktrackResult>(`/prediction/backtrack/${sn}`);
return response.data;
};
export const fetchBacktrackByAcdnt = async (
acdntSn: number,
): Promise<BacktrackResult | null> => {
const response = await api.get<BacktrackResult[]>('/prediction/backtrack', {
params: { acdntSn },
});
return response.data.length > 0 ? response.data[0] : null;
};
export const createBacktrack = async (input: {
acdntSn: number;
lon: number;
lat: number;
srchRadiusNm?: number;
anlysRange?: string;
}): Promise<{ backtrackSn: number }> => {
const response = await api.post<{ backtrackSn: number }>('/prediction/backtrack', input);
return response.data;
};
// ============================================================
// 확산 예측 시뮬레이션 (OpenDrift 연동)
// ============================================================
export interface SimulationRunResponse {
success: boolean;
execSn: number;
acdntSn: number | null;
status: 'RUNNING';
}
export interface WindPoint {
lat: number;
lon: number;
wind_speed: number;
wind_direction: number;
}
export interface HydrGrid {
lonInterval: number[];
boundLonLat: { top: number; bottom: number; left: number; right: number };
rows: number;
cols: number;
latInterval: number[];
}
export interface HydrDataStep {
value: [number[][], number[][]]; // [u_2d, v_2d]
grid: HydrGrid;
}
export interface CenterPoint {
lat: number;
lon: number;
time: number;
}
export interface OilParticle {
lat: number;
lon: number;
time: number;
particle?: number;
stranded?: 0 | 1;
}
export interface SimulationSummary {
remainingVolume: number;
weatheredVolume: number;
pollutionArea: number;
beachedVolume: number;
pollutionCoastLength: number;
}
export interface SimulationStatusResponse {
status: 'PENDING' | 'RUNNING' | 'DONE' | 'ERROR';
progress?: number;
trajectory?: OilParticle[];
summary?: SimulationSummary;
centerPoints?: CenterPoint[];
windData?: WindPoint[][];
hydrData?: (HydrDataStep | null)[];
error?: string;
}
export interface TrajectoryResponse {
trajectory: OilParticle[] | null;
summary: SimulationSummary | null;
centerPoints?: CenterPoint[];
windData?: WindPoint[][];
hydrData?: (HydrDataStep | null)[];
}
export const fetchAnalysisTrajectory = async (acdntSn: number): Promise<TrajectoryResponse> => {
const response = await api.get<TrajectoryResponse>(`/prediction/analyses/${acdntSn}/trajectory`);
return response.data;
};
// ============================================================
// 이미지 업로드 분석
// ============================================================
export interface ImageAnalyzeResult {
acdntSn: number;
lat: number;
lon: number;
oilType: string;
area: number;
volume: number;
fileId: string;
occurredAt: string;
}
export const analyzeImage = async (file: File): Promise<ImageAnalyzeResult> => {
const formData = new FormData();
formData.append('image', file);
const response = await api.post<ImageAnalyzeResult>('/prediction/image-analyze', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 330_000,
});
return response.data;
};