/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import React, { useContext, useEffect } from 'react'; import { getRelativeTime } from '../../helpers'; import { UserContext } from '../../context/User'; import { StatusContext } from '../../context/Status'; import DashboardHeader from './DashboardHeader'; import StatsCards from './StatsCards'; import ChartsPanel from './ChartsPanel'; import ApiInfoPanel from './ApiInfoPanel'; import AnnouncementsPanel from './AnnouncementsPanel'; import FaqPanel from './FaqPanel'; import UptimePanel from './UptimePanel'; import SearchModal from './modals/SearchModal'; import { useDashboardData } from '../../hooks/dashboard/useDashboardData'; import { useDashboardStats } from '../../hooks/dashboard/useDashboardStats'; import { useDashboardCharts } from '../../hooks/dashboard/useDashboardCharts'; import { CHART_CONFIG, CARD_PROPS, FLEX_CENTER_GAP2, ILLUSTRATION_SIZE, ANNOUNCEMENT_LEGEND_DATA, UPTIME_STATUS_MAP, } from '../../constants/dashboard.constants'; import { getTrendSpec, handleCopyUrl, handleSpeedTest, getUptimeStatusColor, getUptimeStatusText, renderMonitorList, } from '../../helpers/dashboard'; const Dashboard = () => { // ========== Context ========== const [userState, userDispatch] = useContext(UserContext); const [statusState, statusDispatch] = useContext(StatusContext); // ========== 主要数据管理 ========== const dashboardData = useDashboardData(userState, userDispatch, statusState); // ========== 图表管理 ========== const dashboardCharts = useDashboardCharts( dashboardData.dataExportDefaultTime, dashboardData.setTrendData, dashboardData.setConsumeQuota, dashboardData.setTimes, dashboardData.setConsumeTokens, dashboardData.setPieData, dashboardData.setLineData, dashboardData.setModelColors, dashboardData.t, ); // ========== 统计数据 ========== const { groupedStatsData } = useDashboardStats( userState, dashboardData.consumeQuota, dashboardData.consumeTokens, dashboardData.times, dashboardData.trendData, dashboardData.performanceMetrics, dashboardData.navigate, dashboardData.t, ); // ========== 数据处理 ========== const initChart = async () => { await dashboardData.loadQuotaData().then((data) => { if (data && data.length > 0) { dashboardCharts.updateChartData(data); } }); await dashboardData.loadUptimeData(); }; const handleRefresh = async () => { const data = await dashboardData.refresh(); if (data && data.length > 0) { dashboardCharts.updateChartData(data); } }; const handleSearchConfirm = async () => { await dashboardData.handleSearchConfirm(dashboardCharts.updateChartData); }; // ========== 数据准备 ========== const apiInfoData = statusState?.status?.api_info || []; const announcementData = (statusState?.status?.announcements || []).map( (item) => { const pubDate = item?.publishDate ? new Date(item.publishDate) : null; const absoluteTime = pubDate && !isNaN(pubDate.getTime()) ? `${pubDate.getFullYear()}-${String(pubDate.getMonth() + 1).padStart(2, '0')}-${String(pubDate.getDate()).padStart(2, '0')} ${String(pubDate.getHours()).padStart(2, '0')}:${String(pubDate.getMinutes()).padStart(2, '0')}` : item?.publishDate || ''; const relativeTime = getRelativeTime(item.publishDate); return { ...item, time: absoluteTime, relative: relativeTime, }; }, ); const faqData = statusState?.status?.faq || []; const uptimeLegendData = Object.entries(UPTIME_STATUS_MAP).map( ([status, info]) => ({ status: Number(status), color: info.color, label: dashboardData.t(info.label), }), ); // ========== Effects ========== useEffect(() => { initChart(); }, []); return (
{/* API信息和图表面板 */}
{dashboardData.hasApiInfoPanel && ( handleCopyUrl(url, dashboardData.t)} handleSpeedTest={handleSpeedTest} CARD_PROPS={CARD_PROPS} FLEX_CENTER_GAP2={FLEX_CENTER_GAP2} ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} t={dashboardData.t} /> )}
{/* 系统公告和常见问答卡片 */} {dashboardData.hasInfoPanels && (
{/* 公告卡片 */} {dashboardData.announcementsEnabled && ( ({ ...item, label: dashboardData.t(item.label), }), )} CARD_PROPS={CARD_PROPS} ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} t={dashboardData.t} /> )} {/* 常见问答卡片 */} {dashboardData.faqEnabled && ( )} {/* 服务可用性卡片 */} {dashboardData.uptimeEnabled && ( renderMonitorList( monitors, (status) => getUptimeStatusColor(status, UPTIME_STATUS_MAP), (status) => getUptimeStatusText( status, UPTIME_STATUS_MAP, dashboardData.t, ), dashboardData.t, ) } CARD_PROPS={CARD_PROPS} ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} t={dashboardData.t} /> )}
)}
); }; export default Dashboard;