import React, { useState, useEffect } from 'react'; import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalCloseButton, Box, Tabs, TabList, TabPanels, Tab, TabPanel, Table, Thead, Tbody, Tr, Th, Td, Text, HStack, VStack, Badge, Spinner, Flex, Icon, Button, Input, useToast, } from '@chakra-ui/react'; import { FaTable, FaChartLine, FaCalendar, FaDownload } from 'react-icons/fa'; import { fetchMetricData, MetricDataResponse, TreeMetric } from '@services/categoryService'; import SimpleLineChart from './SimpleLineChart'; // 黑金主题配色 const themeColors = { bg: { primary: '#0a0a0a', secondary: '#1a1a1a', card: '#1e1e1e', cardHover: '#252525', }, text: { primary: '#ffffff', secondary: '#b8b8b8', muted: '#808080', gold: '#D4AF37', }, border: { default: 'rgba(255, 255, 255, 0.1)', gold: 'rgba(212, 175, 55, 0.3)', goldGlow: 'rgba(212, 175, 55, 0.5)', }, primary: { gold: '#D4AF37', goldLight: '#F4E3A7', goldDark: '#B8941F', }, }; interface MetricDataModalProps { isOpen: boolean; onClose: () => void; metric: TreeMetric; } const MetricDataModal: React.FC = ({ isOpen, onClose, metric }) => { const [loading, setLoading] = useState(false); const [metricData, setMetricData] = useState(null); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); const [limit, setLimit] = useState(100); const toast = useToast(); // 加载数据 useEffect(() => { if (isOpen && metric) { loadMetricData(); } }, [isOpen, metric]); const loadMetricData = async () => { setLoading(true); try { const data = await fetchMetricData(metric.metric_id, startDate, endDate, limit); setMetricData(data); } catch (error) { toast({ title: '加载失败', description: '无法加载指标数据', status: 'error', duration: 3000, isClosable: true, }); } finally { setLoading(false); } }; // 数据已经在 metricData 中,直接传递给 TradingViewChart // 导出CSV const handleExportCSV = () => { if (!metricData || !metricData.data) return; const csvContent = [ ['日期', '数值', '单位'].join(','), ...metricData.data.map((item) => [item.date, item.value ?? '', metricData.unit || ''].join(',')), ].join('\n'); const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `${metricData.metric_name}_${Date.now()}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); toast({ title: '导出成功', description: 'CSV 文件已下载', status: 'success', duration: 2000, }); }; return ( {metric.metric_name} {metric.source} {metric.frequency} ID: {metric.metric_id} {metric.unit && 单位: {metric.unit}} {loading ? ( 加载数据中... ) : ( <> {/* 筛选工具栏 */} setStartDate(e.target.value)} bg={themeColors.bg.card} borderColor={themeColors.border.default} color={themeColors.text.primary} _focus={{ borderColor: themeColors.primary.gold }} /> setEndDate(e.target.value)} bg={themeColors.bg.card} borderColor={themeColors.border.default} color={themeColors.text.primary} _focus={{ borderColor: themeColors.primary.gold }} /> 限制: setLimit(parseInt(e.target.value) || 100)} bg={themeColors.bg.card} borderColor={themeColors.border.default} color={themeColors.text.primary} _focus={{ borderColor: themeColors.primary.gold }} /> {/* 数据展示 */} {metricData && ( 折线图 数据表格 {/* 折线图 - 使用简单 Canvas 实现 */} {metricData && metricData.data.length > 0 ? ( ) : ( 暂无数据 )} {/* 数据表格 */} {metricData.data.map((item, index) => ( ))}
序号 日期 数值 {metricData.unit && `(${metricData.unit})`}
{index + 1} {item.date} {item.value !== null ? item.value.toLocaleString() : '-'}
{metricData.data.length === 0 && ( 暂无数据 )}
)} )}
); }; export default MetricDataModal;