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()}> 心情日历 {/* 日历视图 */} {/* 月份导航 */} {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, }, safeArea: { flex: 1, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 20, paddingVertical: 16, }, backButton: { fontSize: 24, color: '#666', }, headerTitle: { fontSize: 20, fontWeight: '600', color: '#333', flex: 1, textAlign: 'center', }, headerSpacer: { width: 24, }, content: { flex: 1, }, calendar: { backgroundColor: '#fff', margin: 16, borderRadius: 16, padding: 16, }, monthNavigation: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20, }, navButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#f8f9fa', justifyContent: 'center', alignItems: 'center', }, navButtonText: { fontSize: 20, color: '#333', fontWeight: '600', }, monthTitle: { fontSize: 18, fontWeight: '700', color: '#192126', }, weekHeader: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: 16, }, weekDay: { fontSize: 14, color: '#666', textAlign: 'center', width: (width - 96) / 7, }, weekRow: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: 16, }, dayContainer: { width: (width - 96) / 7, alignItems: 'center', }, dayButton: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', marginBottom: 8, }, dayButtonSelected: { backgroundColor: '#4CAF50', }, dayButtonToday: { borderWidth: 2, borderColor: '#4CAF50', }, dayContent: { position: 'relative', width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', }, dayNumber: { fontSize: 14, color: '#999', fontWeight: '500', position: 'absolute', top: 2, zIndex: 1, }, dayNumberSelected: { color: '#FFFFFF', fontWeight: '600', }, dayNumberToday: { color: '#4CAF50', fontWeight: '600', }, dayNumberDisabled: { color: '#ccc', }, moodIconContainer: { position: 'absolute', bottom: 2, width: 20, height: 20, borderRadius: 10, justifyContent: 'center', alignItems: 'center', }, moodIcon: { width: 16, height: 16, borderRadius: 8, backgroundColor: 'rgba(255,255,255,0.9)', justifyContent: 'center', alignItems: 'center', }, moodEmoji: { fontSize: 12, }, defaultMoodIcon: { position: 'absolute', bottom: 2, width: 20, height: 20, borderRadius: 10, borderWidth: 1, borderColor: '#ddd', borderStyle: 'dashed', justifyContent: 'center', alignItems: 'center', }, defaultMoodEmoji: { fontSize: 10, opacity: 0.3, }, selectedDateSection: { backgroundColor: '#fff', margin: 16, marginTop: 0, borderRadius: 16, padding: 16, }, selectedDateHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16, }, selectedDateTitle: { fontSize: 20, fontWeight: '700', color: '#192126', }, addMoodButton: { paddingHorizontal: 16, height: 32, borderRadius: 16, backgroundColor: '#4CAF50', justifyContent: 'center', alignItems: 'center', }, addMoodButtonText: { color: '#fff', fontSize: 14, fontWeight: '600', }, moodRecord: { flexDirection: 'row', alignItems: 'flex-start', paddingVertical: 12, }, recordIcon: { width: 48, height: 48, borderRadius: 24, backgroundColor: '#4CAF50', justifyContent: 'center', alignItems: 'center', marginRight: 12, }, recordContent: { flex: 1, }, recordMood: { fontSize: 16, color: '#333', fontWeight: '500', }, recordIntensity: { fontSize: 14, color: '#666', marginTop: 2, }, recordDescription: { fontSize: 14, color: '#666', marginTop: 4, fontStyle: 'italic', }, spacer: { flex: 1, }, recordTime: { fontSize: 14, color: '#999', }, emptyRecord: { alignItems: 'center', paddingVertical: 20, }, emptyRecordText: { fontSize: 16, color: '#666', marginBottom: 8, }, emptyRecordSubtext: { fontSize: 12, color: '#999', }, });