feat: 更新心情记录功能和界面
- 调整启动画面中的图片宽度,提升视觉效果 - 移除引导页面相关组件,简化应用结构 - 新增心情统计页面,支持用户查看和分析心情数据 - 优化心情卡片组件,增强用户交互体验 - 更新登录页面标题,提升品牌一致性 - 新增心情日历和编辑功能,支持用户记录和管理心情
This commit is contained in:
@@ -1,23 +1,25 @@
|
||||
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
||||
import { BMICard } from '@/components/BMICard';
|
||||
import { FitnessRingsCard } from '@/components/FitnessRingsCard';
|
||||
import { MoodModal } from '@/components/MoodModal';
|
||||
import { MoodCard } from '@/components/MoodCard';
|
||||
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
||||
import { ProgressBar } from '@/components/ProgressBar';
|
||||
import { StressMeter } from '@/components/StressMeter';
|
||||
import { WeightHistoryCard } from '@/components/WeightHistoryCard';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
||||
import { useAppSelector } from '@/hooks/redux';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { calculateNutritionSummary, getDietRecords, NutritionSummary } from '@/services/dietRecords';
|
||||
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { getMonthDaysZh, getMonthTitleZh, getTodayIndexInMonth } from '@/utils/date';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate } from '@/utils/health';
|
||||
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import dayjs from 'dayjs';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { router } from 'expo-router';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Animated,
|
||||
@@ -163,29 +165,45 @@ export default function ExploreScreen() {
|
||||
const [isNutritionLoading, setIsNutritionLoading] = useState(false);
|
||||
|
||||
// 心情相关状态
|
||||
const [moodModalVisible, setMoodModalVisible] = useState(false);
|
||||
const [moodRecords, setMoodRecords] = useState<Array<{ mood: string, date: string, time: string }>>([]);
|
||||
const dispatch = useAppDispatch();
|
||||
const [isMoodLoading, setIsMoodLoading] = useState(false);
|
||||
|
||||
// 从 Redux 获取当前日期的心情记录
|
||||
const currentMoodCheckin = useAppSelector(selectLatestMoodRecordByDate(
|
||||
days[selectedIndex]?.date?.format('YYYY-MM-DD') || dayjs().format('YYYY-MM-DD')
|
||||
));
|
||||
|
||||
// 记录最近一次请求的"日期键",避免旧请求覆盖新结果
|
||||
const latestRequestKeyRef = useRef<string | null>(null);
|
||||
|
||||
const getDateKey = (d: Date) => `${dayjs(d).year()}-${dayjs(d).month() + 1}-${dayjs(d).date()}`;
|
||||
|
||||
// 心情保存处理函数
|
||||
const handleMoodSave = (mood: string, time: string) => {
|
||||
const today = new Date();
|
||||
const dateString = `${today.getFullYear()}年${today.getMonth() + 1}月${today.getDate()}日`;
|
||||
// 加载心情数据
|
||||
const loadMoodData = async (targetDate?: Date) => {
|
||||
if (!isLoggedIn) return;
|
||||
|
||||
const newRecord = {
|
||||
mood,
|
||||
date: dateString,
|
||||
time
|
||||
};
|
||||
try {
|
||||
setIsMoodLoading(true);
|
||||
|
||||
setMoodRecords(prev => [newRecord, ...prev]);
|
||||
setMoodModalVisible(false);
|
||||
// 确定要查询的日期:优先使用传入的日期,否则使用当前选中索引对应的日期
|
||||
let derivedDate: Date;
|
||||
if (targetDate) {
|
||||
derivedDate = targetDate;
|
||||
} else {
|
||||
derivedDate = days[selectedIndex]?.date?.toDate() ?? new Date();
|
||||
}
|
||||
|
||||
const dateString = dayjs(derivedDate).format('YYYY-MM-DD');
|
||||
await dispatch(fetchDailyMoodCheckins(dateString));
|
||||
} catch (error) {
|
||||
console.error('加载心情数据失败:', error);
|
||||
} finally {
|
||||
setIsMoodLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const loadHealthData = async (targetDate?: Date) => {
|
||||
try {
|
||||
console.log('=== 开始HealthKit初始化流程 ===');
|
||||
@@ -290,6 +308,7 @@ export default function ExploreScreen() {
|
||||
loadHealthData(currentDate);
|
||||
if (isLoggedIn) {
|
||||
loadNutritionData(currentDate);
|
||||
loadMoodData(currentDate);
|
||||
}
|
||||
}
|
||||
}, [selectedIndex])
|
||||
@@ -303,6 +322,7 @@ export default function ExploreScreen() {
|
||||
loadHealthData(target);
|
||||
if (isLoggedIn) {
|
||||
loadNutritionData(target);
|
||||
loadMoodData(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -424,23 +444,11 @@ export default function ExploreScreen() {
|
||||
</FloatingCard>
|
||||
{/* 心情卡片 */}
|
||||
<FloatingCard style={[styles.masonryCard, styles.moodCard]} delay={1500}>
|
||||
<TouchableOpacity onPress={() => setMoodModalVisible(true)} style={styles.moodCardContent}>
|
||||
<View style={styles.cardHeaderRow}>
|
||||
<View style={styles.moodIconContainer}>
|
||||
<Text style={styles.moodIcon}>😊</Text>
|
||||
</View>
|
||||
<Text style={styles.cardTitle}>心情</Text>
|
||||
</View>
|
||||
<Text style={styles.moodSubtitle}>记录你的每日心情</Text>
|
||||
{moodRecords.length > 0 ? (
|
||||
<View style={styles.moodPreview}>
|
||||
<Text style={styles.moodPreviewText}>今日:{moodRecords[0].mood}</Text>
|
||||
<Text style={styles.moodPreviewTime}>{moodRecords[0].time}</Text>
|
||||
</View>
|
||||
) : (
|
||||
<Text style={styles.moodEmptyText}>点击记录心情</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<MoodCard
|
||||
moodCheckin={currentMoodCheckin}
|
||||
onPress={() => router.push('/mood/calendar')}
|
||||
isLoading={isMoodLoading}
|
||||
/>
|
||||
</FloatingCard>
|
||||
</View>
|
||||
|
||||
@@ -484,13 +492,6 @@ export default function ExploreScreen() {
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
|
||||
{/* 心情弹窗 */}
|
||||
<MoodModal
|
||||
visible={moodModalVisible}
|
||||
onClose={() => setMoodModalVisible(false)}
|
||||
onSave={handleMoodSave}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -866,46 +867,4 @@ const styles = StyleSheet.create({
|
||||
moodCard: {
|
||||
backgroundColor: '#F0FDF4',
|
||||
},
|
||||
moodCardContent: {
|
||||
width: '100%',
|
||||
},
|
||||
moodIconContainer: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#DCFCE7',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 10,
|
||||
},
|
||||
moodIcon: {
|
||||
fontSize: 14,
|
||||
},
|
||||
moodSubtitle: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
marginTop: 4,
|
||||
marginBottom: 8,
|
||||
},
|
||||
moodPreview: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: 4,
|
||||
},
|
||||
moodPreviewText: {
|
||||
fontSize: 14,
|
||||
color: '#059669',
|
||||
fontWeight: '600',
|
||||
},
|
||||
moodPreviewTime: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
},
|
||||
moodEmptyText: {
|
||||
fontSize: 12,
|
||||
color: '#9CA3AF',
|
||||
fontStyle: 'italic',
|
||||
marginTop: 4,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user