// info-card.js - Unified info card module import { showStatusMessage } from './ui.js'; let currentType = null; const CARD_CONFIG = { cable: { icon: '🛥️', title: '电缆详情', className: 'cable', fields: [ { key: 'name', label: '名称' }, { key: 'owner', label: '所有者' }, { key: 'status', label: '状态' }, { key: 'length', label: '长度' }, { key: 'coords', label: '经纬度' }, { key: 'rfs', label: '投入使用' } ] }, satellite: { icon: '🛰️', title: '卫星详情', className: 'satellite', fields: [ { key: 'name', label: '名称' }, { key: 'norad_id', label: 'NORAD ID' }, { key: 'inclination', label: '倾角', unit: '°' }, { key: 'period', label: '周期', unit: '分钟' }, { key: 'perigee', label: '近地点', unit: 'km' }, { key: 'apogee', label: '远地点', unit: 'km' } ] }, bgp: { icon: '📡', title: 'BGP事件详情', className: 'bgp', fields: [ { key: 'anomaly_type', label: '事件类型' }, { key: 'severity', label: '严重度' }, { key: 'status', label: '状态' }, { key: 'route_change', label: '事件特征' }, { key: 'prefix', label: '前缀' }, { key: 'as_path_display', label: '传播路径' }, { key: 'origin_asn', label: '涉及 ASN' }, { key: 'new_origin_asn', label: '关联 ASN' }, { key: 'confidence', label: '置信度' }, { key: 'collector', label: '主观测站' }, { key: 'observed_by', label: '观测范围' }, { key: 'impacted_scope', label: '影响区域' }, { key: 'related_cables', label: '附近基础设施' }, { key: 'related_satellites', label: '附近卫星' }, { key: 'location', label: '观测位置' }, { key: 'created_at', label: '事件时间' }, { key: 'summary', label: '摘要' } ] }, bgp_collector: { icon: '📍', title: 'BGP观测站详情', className: 'bgp', fields: [ { key: 'collector', label: '采集器' }, { key: 'location', label: '观测位置' }, { key: 'anomaly_count', label: '当前事件数' }, { key: 'observation_count', label: '观测事件数' }, { key: 'recent_24h_observation_count', label: '近24h事件数' }, { key: 'recent_7d_observation_count', label: '近7d事件数' }, { key: 'prefix_count', label: '观测前缀数' }, { key: 'origin_asn_count', label: '观测 ASN 数' }, { key: 'top_event_types', label: '主要事件类型' }, { key: 'coverage_halo', label: '日常活跃度' }, { key: 'related_satellites', label: '附近卫星' }, { key: 'latest_event_type', label: '最近事件类型' }, { key: 'latest_observed_at', label: '最近活跃时间' }, { key: 'baseline_scope', label: '日常覆盖范围' }, { key: 'status', label: '状态' } ] }, supercomputer: { icon: '🖥️', title: '超算详情', className: 'supercomputer', fields: [ { key: 'name', label: '名称' }, { key: 'rank', label: '排名' }, { key: 'r_max', label: 'Rmax', unit: 'GFlops' }, { key: 'r_peak', label: 'Rpeak', unit: 'GFlops' }, { key: 'country', label: '国家' }, { key: 'city', label: '城市' } ] }, gpu_cluster: { icon: '🎮', title: 'GPU集群详情', className: 'gpu_cluster', fields: [ { key: 'name', label: '名称' }, { key: 'country', label: '国家' }, { key: 'city', label: '城市' } ] } }; export function initInfoCard() { const card = document.getElementById('info-card'); const content = document.getElementById('info-card-content'); if (!card || !content) return; if (card.dataset.interactionBound !== 'true') { const stopEvent = (event) => { event.stopPropagation(); }; [ 'mousemove', 'mousedown', 'mouseup', 'click', 'dblclick', 'wheel', 'pointerdown', 'pointerup', 'pointermove', 'touchstart', 'touchmove', 'touchend', ].forEach((eventName) => { card.addEventListener(eventName, stopEvent, { passive: false }); }); card.dataset.interactionBound = 'true'; } if (content.dataset.copyBound === 'true') return; content.addEventListener('click', async (event) => { const label = event.target.closest('.info-card-label'); if (!label) return; const property = label.closest('.info-card-property'); const valueEl = property?.querySelector('.info-card-value'); const value = valueEl?.textContent?.trim(); if (!value || value === '-') { showStatusMessage('无可复制内容', 'warning'); return; } try { await navigator.clipboard.writeText(value); showStatusMessage(`已复制${label.textContent}:${value}`, 'success'); } catch (error) { console.error('Copy failed:', error); showStatusMessage('复制失败', 'error'); } }); content.dataset.copyBound = 'true'; } export function setInfoCardNoBorder(noBorder = true) { const card = document.getElementById('info-card'); if (card) { card.classList.toggle('no-border', noBorder); } } export function showInfoCard(type, data) { const config = CARD_CONFIG[type]; if (!config) { console.warn('Unknown info card type:', type); return; } currentType = type; const card = document.getElementById('info-card'); const icon = document.getElementById('info-card-icon'); const title = document.getElementById('info-card-title'); const content = document.getElementById('info-card-content'); card.className = 'info-card ' + config.className; icon.textContent = config.icon; title.textContent = config.title; let html = ''; for (const field of config.fields) { let value = data[field.key]; if (value === undefined || value === null || value === '') { value = '-'; } else if (typeof value === 'number') { value = value.toLocaleString(); } if (field.unit && value !== '-') { value = value + ' ' + field.unit; } html += `