feat: 添加心情记录功能
在统计页面新增心情卡片和弹窗组件,支持用户记录和查看每日心情状态。
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
||||
import { BMICard } from '@/components/BMICard';
|
||||
import { FitnessRingsCard } from '@/components/FitnessRingsCard';
|
||||
import { MoodModal } from '@/components/MoodModal';
|
||||
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
||||
import { ProgressBar } from '@/components/ProgressBar';
|
||||
import { StressMeter } from '@/components/StressMeter';
|
||||
@@ -88,7 +89,7 @@ export default function ExploreScreen() {
|
||||
|
||||
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
||||
|
||||
// 使用 dayjs:当月日期与默认选中“今天”
|
||||
// 使用 dayjs:当月日期与默认选中"今天"
|
||||
const days = getMonthDaysZh();
|
||||
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
||||
const tabBarHeight = useBottomTabBarHeight();
|
||||
@@ -161,11 +162,29 @@ export default function ExploreScreen() {
|
||||
const [nutritionSummary, setNutritionSummary] = useState<NutritionSummary | null>(null);
|
||||
const [isNutritionLoading, setIsNutritionLoading] = useState(false);
|
||||
|
||||
// 记录最近一次请求的“日期键”,避免旧请求覆盖新结果
|
||||
// 心情相关状态
|
||||
const [moodModalVisible, setMoodModalVisible] = useState(false);
|
||||
const [moodRecords, setMoodRecords] = useState<Array<{ mood: string, date: string, time: string }>>([]);
|
||||
|
||||
// 记录最近一次请求的"日期键",避免旧请求覆盖新结果
|
||||
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 newRecord = {
|
||||
mood,
|
||||
date: dateString,
|
||||
time
|
||||
};
|
||||
|
||||
setMoodRecords(prev => [newRecord, ...prev]);
|
||||
setMoodModalVisible(false);
|
||||
};
|
||||
|
||||
const loadHealthData = async (targetDate?: Date) => {
|
||||
try {
|
||||
@@ -288,7 +307,6 @@ export default function ExploreScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 使用统一的渐变背景色
|
||||
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
||||
|
||||
@@ -404,6 +422,26 @@ export default function ExploreScreen() {
|
||||
showLabel={false}
|
||||
/>
|
||||
</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>
|
||||
</FloatingCard>
|
||||
</View>
|
||||
|
||||
{/* 右列 */}
|
||||
@@ -413,7 +451,6 @@ export default function ExploreScreen() {
|
||||
weight={userProfile?.weight ? parseFloat(userProfile.weight) : undefined}
|
||||
height={userProfile?.height ? parseFloat(userProfile.height) : undefined}
|
||||
style={styles.bmiCardOverride}
|
||||
// compact={true}
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
@@ -441,15 +478,19 @@ export default function ExploreScreen() {
|
||||
<Text style={styles.sleepValue}>——</Text>
|
||||
)}
|
||||
</FloatingCard>
|
||||
|
||||
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
|
||||
{/* 心情弹窗 */}
|
||||
<MoodModal
|
||||
visible={moodModalVisible}
|
||||
onClose={() => setMoodModalVisible(false)}
|
||||
onSave={handleMoodSave}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -580,7 +621,6 @@ const styles = StyleSheet.create({
|
||||
trainingCard: {
|
||||
backgroundColor: '#EEE9FF',
|
||||
},
|
||||
|
||||
cardTitleSecondary: {
|
||||
color: '#9AA3AE',
|
||||
fontSize: 10,
|
||||
@@ -823,4 +863,49 @@ const styles = StyleSheet.create({
|
||||
top: 0,
|
||||
padding: 4,
|
||||
},
|
||||
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