- 在 EditProfileScreen 中新增活动水平字段,支持用户设置和保存活动水平 - 更新个人信息卡片,增加活动水平的展示和编辑功能 - 在 ProfileCard 组件中优化样式,提升用户体验 - 更新 package.json 和 package-lock.json,新增 @react-native-picker/picker 依赖 - 在多个组件中引入 expo-image,优化图片加载和展示效果
175 lines
4.5 KiB
TypeScript
175 lines
4.5 KiB
TypeScript
import { TaskListItem } from '@/types/goals';
|
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
|
import { Image } from 'expo-image';
|
|
import { useRouter } from 'expo-router';
|
|
import React, { ReactNode } from 'react';
|
|
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
|
|
interface TaskProgressCardProps {
|
|
tasks: TaskListItem[];
|
|
headerButtons?: ReactNode;
|
|
}
|
|
|
|
export const TaskProgressCard: React.FC<TaskProgressCardProps> = ({
|
|
tasks,
|
|
headerButtons,
|
|
}) => {
|
|
const router = useRouter();
|
|
|
|
// 计算各状态的任务数量
|
|
const pendingTasks = tasks.filter(task => task.status === 'pending');
|
|
const completedTasks = tasks.filter(task => task.status === 'completed');
|
|
const skippedTasks = tasks.filter(task => task.status === 'skipped');
|
|
|
|
// 处理跳转到目标列表
|
|
const handleNavigateToGoals = () => {
|
|
router.push('/goals-list');
|
|
};
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{/* 标题区域 */}
|
|
<View style={styles.header}>
|
|
<View style={styles.titleContainer}>
|
|
<Text style={styles.title}>今日</Text>
|
|
<TouchableOpacity
|
|
style={styles.goalsIconButton}
|
|
onPress={handleNavigateToGoals}
|
|
>
|
|
<Image
|
|
source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/icons/icon-goal-edit.png' }}
|
|
style={{ width: 18, height: 18 }}
|
|
cachePolicy="memory-disk"
|
|
/>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={styles.headerActions}>
|
|
|
|
{headerButtons && (
|
|
<View style={styles.headerButtons}>
|
|
{headerButtons}
|
|
</View>
|
|
)}
|
|
</View>
|
|
</View>
|
|
|
|
{/* 状态卡片区域 */}
|
|
<View style={styles.statusCards}>
|
|
{/* 待完成 卡片 */}
|
|
<View style={styles.statusCard}>
|
|
<View style={styles.cardHeader}>
|
|
<MaterialIcons name="pending" size={16} color="#7A5AF8" />
|
|
<Text style={styles.cardLabel} numberOfLines={1}>待完成</Text>
|
|
</View>
|
|
<Text style={styles.cardCount}>{pendingTasks.length}</Text>
|
|
</View>
|
|
|
|
{/* 已完成 卡片 */}
|
|
<View style={styles.statusCard}>
|
|
<View style={styles.cardHeader}>
|
|
<MaterialIcons name="check-circle" size={16} color="#10B981" />
|
|
<Text style={styles.cardLabel} numberOfLines={1}>已完成</Text>
|
|
</View>
|
|
<Text style={styles.cardCount}>{completedTasks.length}</Text>
|
|
</View>
|
|
|
|
{/* 已跳过 卡片 */}
|
|
<View style={styles.statusCard}>
|
|
<View style={styles.cardHeader}>
|
|
<MaterialIcons name="skip-next" size={16} color="#F59E0B" />
|
|
<Text style={styles.cardLabel} numberOfLines={1}>已跳过</Text>
|
|
</View>
|
|
<Text style={styles.cardCount}>{skippedTasks.length}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
backgroundColor: '#FFFFFF',
|
|
borderRadius: 16,
|
|
padding: 20,
|
|
marginHorizontal: 20,
|
|
marginBottom: 20,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 8,
|
|
elevation: 4,
|
|
},
|
|
header: {
|
|
marginBottom: 20,
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
titleContainer: {
|
|
flex: 1,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 4,
|
|
},
|
|
headerButtons: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
},
|
|
headerActions: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
},
|
|
goalsIconButton: {
|
|
width: 24,
|
|
height: 24,
|
|
},
|
|
title: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
lineHeight: 24,
|
|
height: 24,
|
|
color: '#1F2937',
|
|
marginBottom: 4,
|
|
},
|
|
subtitle: {
|
|
fontSize: 14,
|
|
color: '#6B7280',
|
|
fontWeight: '400',
|
|
},
|
|
statusCards: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
gap: 8,
|
|
},
|
|
statusCard: {
|
|
flex: 1,
|
|
backgroundColor: '#FFFFFF',
|
|
borderRadius: 12,
|
|
padding: 12,
|
|
borderWidth: 1,
|
|
borderColor: '#E5E7EB',
|
|
alignItems: 'flex-start',
|
|
minHeight: 80,
|
|
},
|
|
cardHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 8,
|
|
gap: 6,
|
|
flexWrap: 'wrap',
|
|
},
|
|
cardLabel: {
|
|
fontSize: 11,
|
|
fontWeight: '500',
|
|
color: '#1F2937',
|
|
lineHeight: 14,
|
|
},
|
|
cardCount: {
|
|
fontSize: 24,
|
|
fontWeight: '700',
|
|
color: '#1F2937',
|
|
},
|
|
});
|