feat: 更新心情记录功能和界面
- 调整启动画面中的图片宽度,提升视觉效果 - 移除引导页面相关组件,简化应用结构 - 新增心情统计页面,支持用户查看和分析心情数据 - 优化心情卡片组件,增强用户交互体验 - 更新登录页面标题,提升品牌一致性 - 新增心情日历和编辑功能,支持用户记录和管理心情
This commit is contained in:
199
components/MoodHistoryCard.tsx
Normal file
199
components/MoodHistoryCard.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
import { MoodCheckin, getMoodConfig } from '@/services/moodCheckins';
|
||||
import dayjs from 'dayjs';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
interface MoodHistoryCardProps {
|
||||
moodCheckins: MoodCheckin[];
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export function MoodHistoryCard({ moodCheckins, title = '心情记录' }: MoodHistoryCardProps) {
|
||||
// 计算心情统计
|
||||
const moodStats = React.useMemo(() => {
|
||||
const stats = {
|
||||
total: moodCheckins.length,
|
||||
averageIntensity: 0,
|
||||
moodDistribution: {} as Record<string, number>,
|
||||
mostFrequentMood: '',
|
||||
};
|
||||
|
||||
if (moodCheckins.length === 0) return stats;
|
||||
|
||||
// 计算平均强度
|
||||
const totalIntensity = moodCheckins.reduce((sum, checkin) => sum + checkin.intensity, 0);
|
||||
stats.averageIntensity = Math.round(totalIntensity / moodCheckins.length);
|
||||
|
||||
// 计算心情分布
|
||||
moodCheckins.forEach(checkin => {
|
||||
const moodLabel = getMoodConfig(checkin.moodType)?.label || checkin.moodType;
|
||||
stats.moodDistribution[moodLabel] = (stats.moodDistribution[moodLabel] || 0) + 1;
|
||||
});
|
||||
|
||||
// 找出最频繁的心情
|
||||
const sortedMoods = Object.entries(stats.moodDistribution)
|
||||
.sort(([, a], [, b]) => b - a);
|
||||
stats.mostFrequentMood = sortedMoods[0]?.[0] || '';
|
||||
|
||||
return stats;
|
||||
}, [moodCheckins]);
|
||||
|
||||
// 获取最近的心情记录
|
||||
const recentMoods = moodCheckins
|
||||
.sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf())
|
||||
.slice(0, 5);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
|
||||
{moodCheckins.length === 0 ? (
|
||||
<View style={styles.emptyState}>
|
||||
<Text style={styles.emptyText}>暂无心情记录</Text>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
{/* 统计信息 */}
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{moodStats.total}</Text>
|
||||
<Text style={styles.statLabel}>总记录</Text>
|
||||
</View>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{moodStats.averageIntensity}</Text>
|
||||
<Text style={styles.statLabel}>平均强度</Text>
|
||||
</View>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{moodStats.mostFrequentMood}</Text>
|
||||
<Text style={styles.statLabel}>最常见</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 最近记录 */}
|
||||
<View style={styles.recentContainer}>
|
||||
<Text style={styles.sectionTitle}>最近记录</Text>
|
||||
{recentMoods.map((checkin, index) => {
|
||||
const moodConfig = getMoodConfig(checkin.moodType);
|
||||
return (
|
||||
<View key={checkin.id} style={styles.moodItem}>
|
||||
<View style={styles.moodInfo}>
|
||||
<Text style={styles.moodEmoji}>{moodConfig?.emoji}</Text>
|
||||
<View style={styles.moodDetails}>
|
||||
<Text style={styles.moodLabel}>{moodConfig?.label}</Text>
|
||||
<Text style={styles.moodDate}>
|
||||
{dayjs(checkin.createdAt).format('MM月DD日 HH:mm')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.moodIntensity}>
|
||||
<Text style={styles.intensityText}>强度 {checkin.intensity}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
marginBottom: 16,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#192126',
|
||||
marginBottom: 16,
|
||||
},
|
||||
emptyState: {
|
||||
alignItems: 'center',
|
||||
paddingVertical: 32,
|
||||
},
|
||||
emptyText: {
|
||||
fontSize: 14,
|
||||
color: '#9CA3AF',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
statsContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
marginBottom: 20,
|
||||
paddingVertical: 16,
|
||||
backgroundColor: '#F8F9FA',
|
||||
borderRadius: 12,
|
||||
},
|
||||
statItem: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: '#192126',
|
||||
marginBottom: 4,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
},
|
||||
recentContainer: {
|
||||
marginTop: 8,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#192126',
|
||||
marginBottom: 12,
|
||||
},
|
||||
moodItem: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 8,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F3F4F6',
|
||||
},
|
||||
moodInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
moodEmoji: {
|
||||
fontSize: 20,
|
||||
marginRight: 12,
|
||||
},
|
||||
moodDetails: {
|
||||
flex: 1,
|
||||
},
|
||||
moodLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
color: '#192126',
|
||||
marginBottom: 2,
|
||||
},
|
||||
moodDate: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
},
|
||||
moodIntensity: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
intensityText: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user