import { Check, Copy, Database, X } from "lucide-react"; import type { ComponentType } from "react"; import { useEffect, useRef, useState } from "react"; import type { WorkbenchAccess } from "../api/request-context"; import { MAP_FOCUS_SURFACE_CLASS_NAME, MAP_MAJOR_PANEL_RADIUS_CLASS_NAME, showMapNotice } from "@/features/map/core"; import { cn } from "@/shared/ui/cn"; import { Disclosure } from "@/shared/ui/disclosure"; import { StatusBadge, StatusDot, type StatusTone } from "@/shared/ui/status"; import type { WaterNetworkSourceId } from "../map/sources"; import type { DetailFeature } from "../types"; import { useElementGisProperties } from "../hooks/use-element-gis-properties"; import { getFeaturePanelModel, type FeaturePanelBadgeTone } from "../utils/feature-properties"; import { presentGisAttributeGroup } from "../utils/gis-attribute-presentation"; import { PipeFeatureIcon, JunctionFeatureIcon, PumpFeatureIcon, ReservoirFeatureIcon, ScadaFeatureIcon, ValveFeatureIcon, type SupplyFeatureIconProps } from "./supply-feature-icons"; import { FeaturePropertyList } from "./feature-property-list"; type FeaturePopoverProps = { feature: DetailFeature | null; projectId: string | null; getAccessToken?: WorkbenchAccess; onClose: () => void; }; const FEATURE_LAYER_META: Partial; label: string; headerClassName: string; labelClassName: string; iconClassName: string; } >> = { pipes: { icon: PipeFeatureIcon, label: "管线", headerClassName: "bg-teal-50/70", labelClassName: "text-teal-800", iconClassName: "bg-teal-700 text-white ring-teal-900/10" }, junctions: { icon: JunctionFeatureIcon, label: "节点", headerClassName: "bg-[var(--action-soft)]/70", labelClassName: "text-[var(--action-blue-pressed)]", iconClassName: "bg-sky-700 text-white ring-sky-900/10" }, valves: { icon: ValveFeatureIcon, label: "阀门", headerClassName: "bg-[var(--action-soft)]/70", labelClassName: "text-[var(--action-blue-pressed)]", iconClassName: "bg-[var(--action-blue)] text-white ring-[var(--action-blue)]/10" }, reservoirs: { icon: ReservoirFeatureIcon, label: "水库", headerClassName: "bg-sky-50/70", labelClassName: "text-sky-900", iconClassName: "bg-sky-800 text-white ring-sky-900/10" }, scada: { icon: ScadaFeatureIcon, label: "SCADA", headerClassName: "bg-[var(--surface-reading)]/80", labelClassName: "text-slate-800", iconClassName: "bg-slate-700 text-white ring-slate-900/10" }, pumps: { icon: PumpFeatureIcon, label: "泵", headerClassName: "bg-cyan-50/70", labelClassName: "text-cyan-800", iconClassName: "bg-cyan-800 text-white ring-cyan-900/10" }, tanks: { icon: ReservoirFeatureIcon, label: "水箱", headerClassName: "bg-teal-50/70", labelClassName: "text-teal-800", iconClassName: "bg-teal-700 text-white ring-teal-900/10" }, water_quality_monitoring_points: { icon: ScadaFeatureIcon, label: "水质监测点", headerClassName: "bg-teal-50/70", labelClassName: "text-teal-800", iconClassName: "bg-teal-700 text-white ring-teal-900/10" } }; const SOURCE_GIS_LAYER_META = { icon: JunctionFeatureIcon, label: "GIS 交付要素", headerClassName: "bg-[var(--surface-reading)]/80", labelClassName: "text-slate-700", iconClassName: "bg-slate-600 text-white ring-slate-900/10" }; const badgeTones = { active: "success", inactive: "neutral", warning: "warning", critical: "danger", info: "info" } satisfies Record; export function FeaturePopover({ feature, projectId, getAccessToken, onClose }: FeaturePopoverProps) { const [copiedId, setCopiedId] = useState(null); const [expandedGisFeatureKey, setExpandedGisFeatureKey] = useState(null); const copyResetTimeoutRef = useRef | null>(null); const gisProperties = useElementGisProperties(feature, projectId, getAccessToken); const featureKey = feature ? `${feature.layer}:${feature.id}` : null; const gisExpanded = featureKey !== null && expandedGisFeatureKey === featureKey; useEffect(() => () => { if (copyResetTimeoutRef.current) { clearTimeout(copyResetTimeoutRef.current); } }, []); if (!feature) { return null; } const panelModel = getFeaturePanelModel(feature.layer, feature.properties, feature.id); const layerMeta = FEATURE_LAYER_META[feature.layer] ?? SOURCE_GIS_LAYER_META; const LayerIcon = layerMeta.icon; const copied = copiedId === panelModel.id; const canCopy = panelModel.id !== "暂无"; const handleCopyId = async () => { try { if (!navigator.clipboard) { throw new Error("Clipboard API unavailable"); } await navigator.clipboard.writeText(panelModel.id); setCopiedId(panelModel.id); if (copyResetTimeoutRef.current) { clearTimeout(copyResetTimeoutRef.current); } copyResetTimeoutRef.current = setTimeout(() => setCopiedId(null), 1500); } catch { showMapNotice({ tone: "error", title: "无法复制编号", message: "请手动选择编号后复制。" }); } }; return ( ); }