import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; import { useMoodData } from '@/hooks/useMoodData'; import { getMoodOptions } from '@/services/moodCheckins'; import dayjs from 'dayjs'; import { LinearGradient } from 'expo-linear-gradient'; import { router, useLocalSearchParams } from 'expo-router'; import React, { useEffect, useState } from 'react'; import { Dimensions, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; const { width } = Dimensions.get('window'); // 心情日历数据生成函数 const generateCalendarData = (targetDate: Date) => { const year = targetDate.getFullYear(); const month = targetDate.getMonth(); const daysInMonth = new Date(year, month + 1, 0).getDate(); const firstDayOfWeek = new Date(year, month, 1).getDay(); const calendar = []; const weeks = []; // 添加空白日期 for (let i = 0; i < firstDayOfWeek; i++) { weeks.push(null); } // 添加实际日期 for (let day = 1; day <= daysInMonth; day++) { weeks.push(day); } // 按周分组 for (let i = 0; i < weeks.length; i += 7) { calendar.push(weeks.slice(i, i + 7)); } return { calendar, today: new Date().getDate(), month: month + 1, year }; }; export default function MoodCalendarScreen() { const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const params = useLocalSearchParams(); const { fetchMoodRecords, fetchMoodHistoryRecords } = useMoodData(); const { selectedDate } = params; const initialDate = selectedDate ? dayjs(selectedDate as string).toDate() : new Date(); const [currentMonth, setCurrentMonth] = useState(initialDate); const [selectedDay, setSelectedDay] = useState(null); const [selectedDateMood, setSelectedDateMood] = useState(null); const [moodRecords, setMoodRecords] = useState>({}); const moodOptions = getMoodOptions(); const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; const monthNames = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; // 生成当前月份的日历数据 const { calendar, today, month, year } = generateCalendarData(currentMonth); // 初始化选中日期 useEffect(() => { if (selectedDate) { const date = dayjs(selectedDate as string); setCurrentMonth(date.toDate()); setSelectedDay(date.date()); const dateString = date.format('YYYY-MM-DD'); loadDailyMoodCheckins(dateString); } else { const today = new Date(); setCurrentMonth(today); setSelectedDay(today.getDate()); const dateString = dayjs().format('YYYY-MM-DD'); loadDailyMoodCheckins(dateString); } loadMonthMoodData(currentMonth); }, [selectedDate]); // 加载整个月份的心情数据 const loadMonthMoodData = async (targetMonth: Date) => { try { const startDate = dayjs(targetMonth).startOf('month').format('YYYY-MM-DD'); const endDate = dayjs(targetMonth).endOf('month').format('YYYY-MM-DD'); const historyData = await fetchMoodHistoryRecords({ startDate, endDate }); // 将历史记录按日期分组 const monthData: Record = {}; historyData.forEach(checkin => { const date = checkin.checkinDate; if (!monthData[date]) { monthData[date] = []; } monthData[date].push(checkin); }); setMoodRecords(monthData); } catch (error) { console.error('加载月份心情数据失败:', error); } }; // 加载选中日期的心情记录 const loadDailyMoodCheckins = async (dateString: string) => { try { const checkins = await fetchMoodRecords(dateString); if (checkins.length > 0) { setSelectedDateMood(checkins[0]); // 取最新的记录 } else { setSelectedDateMood(null); } } catch (error) { console.error('加载心情记录失败:', error); setSelectedDateMood(null); } }; // 月份切换函数 const goToPreviousMonth = () => { const newMonth = new Date(currentMonth); newMonth.setMonth(newMonth.getMonth() - 1); setCurrentMonth(newMonth); setSelectedDay(null); loadMonthMoodData(newMonth); }; const goToNextMonth = () => { const newMonth = new Date(currentMonth); newMonth.setMonth(newMonth.getMonth() + 1); setCurrentMonth(newMonth); setSelectedDay(null); loadMonthMoodData(newMonth); }; // 日期选择函数 const onSelectDate = (day: number) => { setSelectedDay(day); const selectedDateString = dayjs(currentMonth).date(day).format('YYYY-MM-DD'); loadDailyMoodCheckins(selectedDateString); }; // 跳转到心情编辑页面 const openMoodEdit = () => { const selectedDateString = selectedDay ? dayjs(currentMonth).date(selectedDay).format('YYYY-MM-DD') : dayjs().format('YYYY-MM-DD'); const moodId = selectedDateMood?.id; router.push({ pathname: '/mood/edit', params: { date: selectedDateString, ...(moodId && { moodId }) } }); }; const renderMoodIcon = (day: number | null, isSelected: boolean) => { if (!day) return null; // 检查该日期是否有心情记录 const dayDateString = dayjs(currentMonth).date(day).format('YYYY-MM-DD'); const dayRecords = moodRecords[dayDateString] || []; const moodRecord = dayRecords.length > 0 ? dayRecords[0] : null; if (moodRecord) { const mood = moodOptions.find(m => m.type === moodRecord.moodType); return ( {mood?.emoji || '😊'} ); } return ( 😊 ); }; // 使用统一的渐变背景色 const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const; return ( {/* 装饰性圆圈 */} router.back()} withSafeTop={false} transparent={true} tone="light" /> {/* 日历视图 */} {/* 月份导航 */} {year}年{monthNames[month - 1]} {weekDays.map((day, index) => ( {day} ))} {calendar.map((week, weekIndex) => ( {week.map((day, dayIndex) => { const isSelected = day === selectedDay; const isToday = day === today && month === new Date().getMonth() + 1 && year === new Date().getFullYear(); const isFutureDate = Boolean(day && dayjs(currentMonth).date(day).isAfter(dayjs(), 'day')); return ( {day && ( !isFutureDate && day && onSelectDate(day)} disabled={isFutureDate} > {day.toString().padStart(2, '0')} {renderMoodIcon(day, isSelected)} )} ); })} ))} {/* 选中日期的记录 */} {selectedDay ? dayjs(currentMonth).date(selectedDay).format('YYYY年M月D日') : '请选择日期'} 记录 {selectedDay ? ( selectedDateMood ? ( {moodOptions.find(m => m.type === selectedDateMood.moodType)?.emoji || '😊'} {moodOptions.find(m => m.type === selectedDateMood.moodType)?.label} 强度: {selectedDateMood.intensity} {selectedDateMood.description && ( {selectedDateMood.description} )} {dayjs(selectedDateMood.createdAt).format('HH:mm')} ) : ( 暂无心情记录 点击右上角"记录"按钮添加心情 ) ) : ( 请先选择一个日期 点击日历中的日期,然后点击"记录"按钮添加心情 )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradientBackground: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }, decorativeCircle1: { position: 'absolute', top: 40, right: 20, width: 60, height: 60, borderRadius: 30, backgroundColor: '#7a5af8', opacity: 0.08, }, decorativeCircle2: { position: 'absolute', bottom: -15, left: -15, width: 40, height: 40, borderRadius: 20, backgroundColor: '#7a5af8', opacity: 0.04, }, safeArea: { flex: 1, }, content: { flex: 1, }, calendar: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 16, borderRadius: 20, padding: 20, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 6, }, monthNavigation: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24, }, navButton: { width: 44, height: 44, borderRadius: 22, backgroundColor: 'rgba(122,90,248,0.1)', justifyContent: 'center', alignItems: 'center', shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2, }, navButtonText: { fontSize: 24, color: '#7a5af8', fontWeight: '700', }, monthTitle: { fontSize: 20, fontWeight: '800', color: '#192126', }, weekHeader: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: 20, }, weekDay: { fontSize: 13, color: '#5d6676', textAlign: 'center', width: (width - 96) / 7, fontWeight: '600', }, weekRow: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: 16, }, dayContainer: { width: (width - 96) / 7, alignItems: 'center', }, dayButton: { width: 44, height: 44, borderRadius: 22, justifyContent: 'center', alignItems: 'center', marginBottom: 8, backgroundColor: 'transparent', }, dayButtonSelected: { backgroundColor: '#FFFFFF', shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.15, shadowRadius: 6, elevation: 4, }, dayButtonToday: { borderWidth: 2, borderColor: '#7a5af8', }, dayContent: { position: 'relative', width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', }, dayNumber: { fontSize: 14, color: '#777f8c', fontWeight: '600', position: 'absolute', top: 2, zIndex: 1, }, dayNumberSelected: { color: '#192126', fontWeight: '700', }, dayNumberToday: { color: '#7a5af8', fontWeight: '700', }, dayNumberDisabled: { color: '#c0c4ca', }, moodIconContainer: { position: 'absolute', bottom: 2, width: 22, height: 22, borderRadius: 11, justifyContent: 'center', alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 1, }, moodIcon: { width: 18, height: 18, borderRadius: 9, backgroundColor: 'rgba(255,255,255,0.95)', justifyContent: 'center', alignItems: 'center', }, moodEmoji: { fontSize: 11, }, defaultMoodIcon: { position: 'absolute', bottom: 2, width: 22, height: 22, borderRadius: 11, borderWidth: 1.5, borderColor: 'rgba(122,90,248,0.3)', borderStyle: 'dashed', justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(122,90,248,0.05)', }, defaultMoodEmoji: { fontSize: 10, opacity: 0.4, color: '#7a5af8', }, selectedDateSection: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 16, marginTop: 0, borderRadius: 20, padding: 20, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 6, }, selectedDateHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20, }, selectedDateTitle: { fontSize: 22, fontWeight: '800', color: '#192126', }, addMoodButton: { paddingHorizontal: 20, height: 36, borderRadius: 18, backgroundColor: '#7a5af8', justifyContent: 'center', alignItems: 'center', shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, elevation: 3, }, addMoodButtonText: { color: '#fff', fontSize: 14, fontWeight: '700', }, moodRecord: { flexDirection: 'row', alignItems: 'flex-start', paddingVertical: 16, backgroundColor: 'rgba(122,90,248,0.05)', borderRadius: 16, paddingHorizontal: 16, }, recordIcon: { width: 52, height: 52, borderRadius: 26, backgroundColor: '#7a5af8', justifyContent: 'center', alignItems: 'center', marginRight: 16, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.15, shadowRadius: 4, elevation: 2, }, recordContent: { flex: 1, }, recordMood: { fontSize: 18, color: '#192126', fontWeight: '700', marginBottom: 4, }, recordIntensity: { fontSize: 14, color: '#5d6676', marginTop: 2, fontWeight: '500', }, recordDescription: { fontSize: 14, color: '#5d6676', marginTop: 6, fontStyle: 'italic', lineHeight: 20, }, spacer: { flex: 1, }, recordTime: { fontSize: 14, color: '#777f8c', fontWeight: '500', }, emptyRecord: { alignItems: 'center', paddingVertical: 32, }, emptyRecordText: { fontSize: 16, color: '#5d6676', marginBottom: 8, fontWeight: '600', }, emptyRecordSubtext: { fontSize: 13, color: '#777f8c', textAlign: 'center', lineHeight: 18, }, });