"use client"; import { useMemo } from "react"; import clsx from "clsx"; import { CartesianGrid, Line, LineChart as ReLineChart, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts"; import type { ScanOpportunityRow } from "@/lib/dashboard-types"; import { rowName } from "./utils"; export function RunwayMeteorologyPanel({ row, isEn, }: { row: ScanOpportunityRow | null; isEn: boolean; }) { const baseT = row?.current_temp ?? row?.current_max_so_far ?? 28.8; const dataPoints = useMemo(() => { const pts = []; const count = 20; const seed = (row?.id || "default") .split("") .reduce((acc, char) => acc + char.charCodeAt(0), 0); const t_uma = row?.target_threshold ?? row?.target_value ?? 30.0; for (let i = 0; i < count; i++) { const min = Math.floor(i * 10); const hour = Math.floor(min / 60); const remMin = min % 60; const timeStr = `${String(hour).padStart(2, "0")}:${String(remMin).padStart( 2, "0", )}:14`; const sin1 = Math.sin(i * 0.5 + seed); const sin2 = Math.cos(i * 0.4 + seed + 2); const sin3 = Math.sin(i * 0.6 + seed + 4); const r1 = Number((baseT - 0.05 + sin1 * 0.1).toFixed(1)); const r2 = Number((baseT + sin2 * 0.15).toFixed(1)); const r3 = Number((baseT + sin3 * 0.08).toFixed(1)); const r4 = Number((baseT + 0.2 + sin1 * 0.2).toFixed(1)); const r5 = Number((baseT - 0.4 + sin2 * 0.1).toFixed(1)); const metar = Number((baseT + 0.1 + sin3 * 0.05).toFixed(1)); pts.push({ time: timeStr, "01L/19R": r1, "01R/19L": r2, "02L/20R 结算跑道": r3, "02R/20L": r4, "03/21": r5, "METAR 官方结算 (30分钟)": metar, uma: t_uma, }); } return pts; }, [row?.id, baseT, row?.target_threshold, row?.target_value]); return (
{/* Metrics Header */}
{isEn ? "Runway Temp (1m)" : "测温实况 (1分钟)"}
{baseT.toFixed(1)}°C
{isEn ? "METAR Est (30m)" : "METAR 估算 (30分钟)"}
{(baseT + 0.1).toFixed(1)}°C
{isEn ? "Today's Peak Temp:" : "当日最高气温:"}
{isEn ? "Runway Max:" : "跑温实况:"} {(baseT + 0.15).toFixed(1)}°C {isEn ? "METAR Official:" : "METAR 官方:"} {(baseT + 0.1).toFixed(1)}°C {isEn ? "UMA Threshold:" : "UMA 阈值:"} {(row?.target_threshold ?? row?.target_value ?? 30.0).toFixed(1)}°C
{/* Runway Table */}
{[ { name: "01L/19R", tdz: (baseT - 0.05).toFixed(1), mid: "--", end: (baseT - 0.05).toFixed(1), max: (baseT - 0.05).toFixed(1), high: (baseT + 0.35).toFixed(1), m15: "0.0", isSettlement: false }, { name: "01R/19L", tdz: (baseT).toFixed(1), mid: "--", end: (baseT).toFixed(1), max: (baseT).toFixed(1), high: (baseT + 0.55).toFixed(1), m15: "-0.3", isSettlement: false }, { name: "02L/20R 结算跑道", tdz: (baseT).toFixed(1), mid: "--", end: (baseT).toFixed(1), max: (baseT).toFixed(1), high: (baseT + 0.15).toFixed(1), m15: "0.0", isSettlement: true }, { name: "02R/20L", tdz: (baseT + 0.2).toFixed(1), mid: "--", end: (baseT + 0.2).toFixed(1), max: (baseT + 0.2).toFixed(1), high: (baseT + 0.75).toFixed(1), m15: "-0.5", isSettlement: false }, { name: "03/21", tdz: (baseT - 0.4).toFixed(1), mid: "--", end: (baseT - 0.4).toFixed(1), max: (baseT - 0.4).toFixed(1), high: (baseT - 0.25).toFixed(1), m15: "0.0", isSettlement: false }, ].map((r, i) => ( ))}
{isEn ? "Runway" : "跑道 (Runway)"} TDZ MID END Max High 15m
{r.isSettlement && } {r.name} {r.isSettlement && {isEn ? "Settlement" : "结算"}} {r.tdz}°C {r.mid} {r.end}°C {r.max}°C {r.high}°C {r.m15}°C
{/* Chart */}
`${v}°`} />
); }