| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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 = () => { |
| |
| 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), |
| }), |
| ); |
|
|
| |
| useEffect(() => { |
| initChart(); |
| }, []); |
|
|
| return ( |
| <div className='h-full'> |
| <DashboardHeader |
| getGreeting={dashboardData.getGreeting} |
| greetingVisible={dashboardData.greetingVisible} |
| showSearchModal={dashboardData.showSearchModal} |
| refresh={handleRefresh} |
| loading={dashboardData.loading} |
| t={dashboardData.t} |
| /> |
| |
| <SearchModal |
| searchModalVisible={dashboardData.searchModalVisible} |
| handleSearchConfirm={handleSearchConfirm} |
| handleCloseModal={dashboardData.handleCloseModal} |
| isMobile={dashboardData.isMobile} |
| isAdminUser={dashboardData.isAdminUser} |
| inputs={dashboardData.inputs} |
| dataExportDefaultTime={dashboardData.dataExportDefaultTime} |
| timeOptions={dashboardData.timeOptions} |
| handleInputChange={dashboardData.handleInputChange} |
| t={dashboardData.t} |
| /> |
| |
| <StatsCards |
| groupedStatsData={groupedStatsData} |
| loading={dashboardData.loading} |
| getTrendSpec={getTrendSpec} |
| CARD_PROPS={CARD_PROPS} |
| CHART_CONFIG={CHART_CONFIG} |
| /> |
| |
| {/* API信息和图表面板 */} |
| <div className='mb-4'> |
| <div |
| className={`grid grid-cols-1 gap-4 ${dashboardData.hasApiInfoPanel ? 'lg:grid-cols-4' : ''}`} |
| > |
| <ChartsPanel |
| activeChartTab={dashboardData.activeChartTab} |
| setActiveChartTab={dashboardData.setActiveChartTab} |
| spec_line={dashboardCharts.spec_line} |
| spec_model_line={dashboardCharts.spec_model_line} |
| spec_pie={dashboardCharts.spec_pie} |
| spec_rank_bar={dashboardCharts.spec_rank_bar} |
| CARD_PROPS={CARD_PROPS} |
| CHART_CONFIG={CHART_CONFIG} |
| FLEX_CENTER_GAP2={FLEX_CENTER_GAP2} |
| hasApiInfoPanel={dashboardData.hasApiInfoPanel} |
| t={dashboardData.t} |
| /> |
| |
| {dashboardData.hasApiInfoPanel && ( |
| <ApiInfoPanel |
| apiInfoData={apiInfoData} |
| handleCopyUrl={(url) => handleCopyUrl(url, dashboardData.t)} |
| handleSpeedTest={handleSpeedTest} |
| CARD_PROPS={CARD_PROPS} |
| FLEX_CENTER_GAP2={FLEX_CENTER_GAP2} |
| ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} |
| t={dashboardData.t} |
| /> |
| )} |
| </div> |
| </div> |
| |
| {/* 系统公告和常见问答卡片 */} |
| {dashboardData.hasInfoPanels && ( |
| <div className='mb-4'> |
| <div className='grid grid-cols-1 lg:grid-cols-4 gap-4'> |
| {/* 公告卡片 */} |
| {dashboardData.announcementsEnabled && ( |
| <AnnouncementsPanel |
| announcementData={announcementData} |
| announcementLegendData={ANNOUNCEMENT_LEGEND_DATA.map( |
| (item) => ({ |
| ...item, |
| label: dashboardData.t(item.label), |
| }), |
| )} |
| CARD_PROPS={CARD_PROPS} |
| ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} |
| t={dashboardData.t} |
| /> |
| )} |
| |
| {/* 常见问答卡片 */} |
| {dashboardData.faqEnabled && ( |
| <FaqPanel |
| faqData={faqData} |
| CARD_PROPS={CARD_PROPS} |
| FLEX_CENTER_GAP2={FLEX_CENTER_GAP2} |
| ILLUSTRATION_SIZE={ILLUSTRATION_SIZE} |
| t={dashboardData.t} |
| /> |
| )} |
| |
| {/* 服务可用性卡片 */} |
| {dashboardData.uptimeEnabled && ( |
| <UptimePanel |
| uptimeData={dashboardData.uptimeData} |
| uptimeLoading={dashboardData.uptimeLoading} |
| activeUptimeTab={dashboardData.activeUptimeTab} |
| setActiveUptimeTab={dashboardData.setActiveUptimeTab} |
| loadUptimeData={dashboardData.loadUptimeData} |
| uptimeLegendData={uptimeLegendData} |
| renderMonitorList={(monitors) => |
| 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} |
| /> |
| )} |
| </div> |
| </div> |
| )} |
| </div> |
| ); |
| }; |
|
|
| export default Dashboard; |
|
|