DataDisplayPage.tsx 12 KB
import { useState, useEffect } from "react";
import { Telescope, Clock, Calendar, TrendingUp, Moon, Sun, Activity } from "lucide-react";
import { fetchDataDisplay } from "../api/kioskApi";
import { PAGE_CONTENT_INSET } from "../pageContentInset";

type RealtimeRow = {
  id: number;
  name: string;
  time: string;
  telescope: string;
  exposure: string;
  image: string;
};

const FALLBACK_REALTIME: RealtimeRow[] = [
  {
    id: 1,
    name: "M42 猎户座大星云",
    time: "2026-03-27 20:15:32",
    telescope: "2.5米主镜",
    exposure: "300秒",
    image:
      "https://images.unsplash.com/photo-1628632642012-290ae1f4b1ac?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtaWxreSUyMHdheSUyMG5pZ2h0JTIwc2t5JTIwb2JzZXJ2YXRvcnl8ZW58MXx8fHwxNzc0NTg3MDQyfDA&ixlib=rb-4.1.0&q=80&w=400",
  },
  {
    id: 2,
    name: "NGC 7293 螺旋星云",
    time: "2026-03-27 21:30:45",
    telescope: "1.8米副镜",
    exposure: "450秒",
    image:
      "https://images.unsplash.com/photo-1631594274394-279ab758c1ed?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtb3VudGFpbiUyMGxha2UlMjByZWZsZWN0aW9uJTIwdGliZXR8ZW58MXx8fHwxNzc0NTg3MDQxfDA&ixlib=rb-4.1.0&q=80&w=400",
  },
  {
    id: 3,
    name: "木星及其卫星系统",
    time: "2026-03-27 22:05:18",
    telescope: "0.5米行星镜",
    exposure: "0.1秒",
    image:
      "https://images.unsplash.com/photo-1615653058464-841639bb85ba?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0ZWxlc2NvcGUlMjBhc3Ryb25vbXklMjBuaWdodHxlbnwxfHx8fDE3NzQ1ODcwNDJ8MA&ixlib=rb-4.1.0&q=80&w=400",
  },
];

const FALLBACK_HISTORICAL = [
  { date: "2026-03-27", observations: 45, quality: "优秀", weather: "晴朗" },
  { date: "2026-03-26", observations: 38, quality: "良好", weather: "多云" },
  { date: "2026-03-25", observations: 52, quality: "优秀", weather: "晴朗" },
  { date: "2026-03-24", observations: 28, quality: "一般", weather: "薄云" },
  { date: "2026-03-23", observations: 0, quality: "-", weather: "阴天" },
  { date: "2026-03-22", observations: 41, quality: "良好", weather: "晴朗" },
  { date: "2026-03-21", observations: 63, quality: "优秀", weather: "晴朗" },
];

const FALLBACK_STATUS = {
  weather: "晴朗",
  seeing: `0.8" (优秀)`,
  transparency: "95%",
  moonPhase: "下弦月 45%",
};

export function DataDisplayPage() {
  const [realtimeImages, setRealtimeImages] = useState<RealtimeRow[]>(FALLBACK_REALTIME);
  const [historicalData, setHistoricalData] = useState(FALLBACK_HISTORICAL);
  const [status, setStatus] = useState(FALLBACK_STATUS);
  const [selectedImage, setSelectedImage] = useState<RealtimeRow>(FALLBACK_REALTIME[0]!);

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      const data = await fetchDataDisplay();
      if (cancelled || !data) {
        if (!cancelled && !data) {
          console.warn("[kiosk] data-display 接口不可用,使用本地演示数据");
        }
        return;
      }
      const rt = data.realtimeImages;
      if (rt.length > 0) {
        setRealtimeImages(rt);
        setSelectedImage(rt[0]!);
      }
      setStatus({
        weather: data.status.weather,
        seeing: data.status.seeing,
        transparency: data.status.transparency,
        moonPhase: data.status.moonPhase,
      });
      if (data.historicalData.length > 0) {
        setHistoricalData(data.historicalData);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  return (
    <div className={`w-full min-w-0 max-w-full ${PAGE_CONTENT_INSET}`}>
      {/* 页面标题 */}
      <div className="mb-6 sm:mb-10 lg:mb-12 landscape:max-lg:mb-4">
        <h1 className="mb-2 flex items-center gap-2 text-2xl font-bold text-white sm:mb-3 sm:gap-3 sm:text-3xl lg:text-4xl">
          <Activity className="h-8 w-8 shrink-0 text-sky-400 sm:h-9 sm:w-9 lg:h-10 lg:w-10" />
          数据展示中心
        </h1>
        <p className="text-base text-blue-200 sm:text-lg landscape:max-lg:text-sm">
          实时观测图像与历史数据记录
        </p>
      </div>

      <div className="grid gap-4 lg:grid-cols-3 lg:gap-8 landscape:max-lg:grid-cols-1">
        {/* 左侧:实时图像列表 */}
        <div className="space-y-4 lg:col-span-1 landscape:max-lg:max-h-[min(42dvh,22rem)] landscape:max-lg:overflow-y-auto landscape:lg:max-h-none">
          <div className="rounded-xl border border-white/20 bg-white/10 p-4 backdrop-blur-xl sm:p-6 landscape:max-lg:p-4">
            <h2 className="text-xl font-bold text-white mb-4 flex items-center gap-2">
              <Telescope className="w-5 h-5 text-sky-400" />
              实时观测图像
            </h2>
            <div className="space-y-3">
              {realtimeImages.map((img) => (
                <div
                  key={img.id}
                  onClick={() => setSelectedImage(img)}
                  className={`p-4 rounded-lg cursor-pointer transition-all ${
                    selectedImage.id === img.id
                      ? "bg-sky-500/20 border-2 border-sky-400"
                      : "bg-white/5 border border-white/10 hover:bg-white/10"
                  }`}
                >
                  <h3 className="font-medium text-white mb-2">{img.name}</h3>
                  <div className="space-y-1 text-sm text-blue-200">
                    <div className="flex items-center gap-2">
                      <Clock className="w-3.5 h-3.5" />
                      {img.time}
                    </div>
                    <div className="text-xs text-blue-300">
                      {img.telescope} · 曝光 {img.exposure}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* 观测状态 */}
          <div className="rounded-xl border border-white/20 bg-white/10 p-4 backdrop-blur-xl sm:p-6 landscape:max-lg:p-4">
            <h3 className="mb-3 text-base font-bold text-white sm:mb-4 sm:text-lg">
              当前观测状态
            </h3>
            <div className="space-y-4">
              <div className="flex items-center justify-between">
                <span className="text-blue-200">天气状况</span>
                <div className="flex items-center gap-2">
                  <Sun className="w-4 h-4 text-sky-400" />
                  <span className="text-white font-medium">{status.weather}</span>
                </div>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-blue-200">视宁度</span>
                <span className="text-green-400 font-medium">{status.seeing}</span>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-blue-200">透明度</span>
                <span className="text-green-400 font-medium">{status.transparency}</span>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-blue-200">月相</span>
                <div className="flex items-center gap-2">
                  <Moon className="w-4 h-4 text-blue-300" />
                  <span className="text-white font-medium">{status.moonPhase}</span>
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* 中间:大图显示 */}
        <div className="space-y-4 sm:space-y-6 lg:col-span-2">
          <div className="overflow-hidden rounded-xl border border-white/20 bg-white/10 backdrop-blur-xl">
            <div className="relative aspect-video max-h-[min(56dvh,100%)] bg-black sm:max-h-none landscape:max-lg:aspect-[21/9] landscape:max-lg:max-h-[48dvh]">
              <img
                src={selectedImage.image}
                alt={selectedImage.name}
                className="w-full h-full object-cover"
              />
              <div className="absolute inset-0 bg-gradient-to-t from-blue-950/90 via-transparent to-transparent" />
              <div className="absolute bottom-0 left-0 right-0 p-3 sm:p-6 landscape:max-lg:p-3">
                <h2 className="mb-1 text-lg font-bold text-white sm:mb-2 sm:text-2xl">
                  {selectedImage.name}
                </h2>
                <div className="flex flex-wrap gap-2 text-xs text-blue-200 sm:gap-4 sm:text-sm">
                  <span className="flex items-center gap-1.5">
                    <Clock className="w-4 h-4" />
                    {selectedImage.time}
                  </span>
                  <span className="flex items-center gap-1.5">
                    <Telescope className="w-4 h-4" />
                    {selectedImage.telescope}
                  </span>
                  <span>曝光时间: {selectedImage.exposure}</span>
                </div>
              </div>
            </div>
          </div>

          {/* 历史观测记录 */}
          <div className="rounded-xl border border-white/20 bg-white/10 p-4 backdrop-blur-xl sm:p-6 landscape:max-lg:p-4">
            <h2 className="mb-4 flex items-center gap-2 text-lg font-bold text-white sm:mb-6 sm:text-xl">
              <Calendar className="w-5 h-5 text-sky-400" />
              历史观测记录
            </h2>
            <div className="overflow-x-auto">
              <table className="w-full">
                <thead>
                  <tr className="border-b border-white/10">
                    <th className="text-left py-3 px-4 text-sm font-medium text-blue-200">
                      日期
                    </th>
                    <th className="text-center py-3 px-4 text-sm font-medium text-blue-200">
                      观测次数
                    </th>
                    <th className="text-center py-3 px-4 text-sm font-medium text-blue-200">
                      数据质量
                    </th>
                    <th className="text-center py-3 px-4 text-sm font-medium text-blue-200">
                      天气状况
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {historicalData.map((record, index) => (
                    <tr
                      key={record.date}
                      className={`border-b border-white/5 hover:bg-white/5 transition-colors ${
                        index === 0 ? "bg-sky-500/10" : ""
                      }`}
                    >
                      <td className="py-4 px-4 text-white font-medium">
                        {record.date}
                        {index === 0 && (
                          <span className="ml-2 text-xs px-2 py-0.5 rounded-full bg-sky-500/20 text-sky-300">
                            今天
                          </span>
                        )}
                      </td>
                      <td className="text-center py-4 px-4">
                        <span className="inline-flex items-center gap-1 text-white">
                          <TrendingUp className="w-4 h-4 text-green-400" />
                          {record.observations}
                        </span>
                      </td>
                      <td className="text-center py-4 px-4">
                        <span
                          className={`inline-block px-3 py-1 rounded-full text-sm font-medium ${
                            record.quality === "优秀"
                              ? "bg-green-500/20 text-green-300"
                              : record.quality === "良好"
                                ? "bg-blue-500/20 text-blue-300"
                                : record.quality === "一般"
                                  ? "bg-sky-500/20 text-sky-300"
                                  : "bg-gray-500/20 text-gray-300"
                          }`}
                        >
                          {record.quality}
                        </span>
                      </td>
                      <td className="text-center py-4 px-4 text-blue-200">
                        {record.weather}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}