import { MoodHistoryCard } from '@/components/MoodHistoryCard'; import { Colors } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { useColorScheme } from '@/hooks/useColorScheme'; import { fetchMoodHistory, fetchMoodStatistics, selectMoodLoading, selectMoodRecords, selectMoodStatistics } from '@/store/moodSlice'; import { HeaderBar } from '@/components/ui/HeaderBar'; import dayjs from 'dayjs'; import { LinearGradient } from 'expo-linear-gradient'; import { router } from 'expo-router'; import React, { useEffect } from 'react'; import { ActivityIndicator, SafeAreaView, ScrollView, StyleSheet, Text, View, } from 'react-native'; export default function MoodStatisticsScreen() { const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const { isLoggedIn } = useAuthGuard(); const dispatch = useAppDispatch(); // 从 Redux 获取数据 const moodRecords = useAppSelector(selectMoodRecords); const statistics = useAppSelector(selectMoodStatistics); const loading = useAppSelector(selectMoodLoading); // 获取最近30天的心情数据 const loadMoodData = async () => { if (!isLoggedIn) return; try { const endDate = dayjs().format('YYYY-MM-DD'); const startDate = dayjs().subtract(30, 'days').format('YYYY-MM-DD'); // 并行加载历史记录和统计数据 await Promise.all([ dispatch(fetchMoodHistory({ startDate, endDate })), dispatch(fetchMoodStatistics({ startDate, endDate })) ]); } catch (error) { console.error('加载心情数据失败:', error); } }; useEffect(() => { loadMoodData(); }, [isLoggedIn, dispatch]); // 将 moodRecords 转换为数组格式 const moodCheckins = Object.values(moodRecords).flat(); // 使用统一的渐变背景色 const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const; if (!isLoggedIn) { return ( 请先登录查看心情统计 ); } return ( router.back()} withSafeTop={false} transparent={true} tone="light" /> {loading.history || loading.statistics ? ( 加载中... ) : ( <> {/* 统计概览 */} {statistics && ( 统计概览 {statistics.totalCheckins} 总打卡次数 {statistics.averageIntensity.toFixed(1)} 平均强度 {statistics.mostFrequentMood ? statistics.moodDistribution[statistics.mostFrequentMood] || 0 : 0} 最常见心情 )} {/* 心情历史记录 */} {/* 心情分布 */} {statistics && ( 心情分布 {Object.entries(statistics.moodDistribution) .sort(([, a], [, b]) => b - a) .map(([moodType, count]) => ( {moodType} {count} ({((count / statistics.totalCheckins) * 100).toFixed(1)}%) ))} )} )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradientBackground: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }, safeArea: { flex: 1, }, scrollView: { flex: 1, paddingHorizontal: 20, }, centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loginPrompt: { fontSize: 16, color: '#666', textAlign: 'center', }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingVertical: 60, }, loadingText: { fontSize: 16, color: '#666', marginTop: 16, }, sectionTitle: { fontSize: 20, fontWeight: '700', color: '#192126', marginBottom: 16, }, statsOverview: { marginBottom: 24, }, statsGrid: { flexDirection: 'row', justifyContent: 'space-between', gap: 12, }, statCard: { flex: 1, backgroundColor: '#FFFFFF', borderRadius: 16, padding: 20, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 3.84, elevation: 5, }, statNumber: { fontSize: 24, fontWeight: '800', color: '#192126', marginBottom: 8, }, statLabel: { fontSize: 14, color: '#6B7280', textAlign: 'center', }, distributionContainer: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 16, marginBottom: 24, shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 3.84, elevation: 5, }, distributionList: { gap: 12, }, distributionItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 8, }, moodType: { fontSize: 16, fontWeight: '500', color: '#192126', }, countContainer: { flexDirection: 'row', alignItems: 'center', gap: 8, }, count: { fontSize: 16, fontWeight: '600', color: '#192126', }, percentage: { fontSize: 14, color: '#6B7280', }, });