feat: 移除目标管理功能模块

删除了完整的目标管理功能,包括目标创建、编辑、任务管理等相关页面和组件。同时移除了相关的API服务、Redux状态管理、类型定义和通知功能。应用版本从1.0.20升级到1.0.21。
This commit is contained in:
richarjiang
2025-10-31 08:49:22 +08:00
parent 7cd290d341
commit 16c2351160
31 changed files with 953 additions and 7884 deletions

View File

@@ -22,7 +22,6 @@ type TabConfig = {
const TAB_CONFIGS: Record<string, TabConfig> = {
statistics: { icon: 'chart.pie.fill', title: '健康' },
fasting: { icon: 'timer', title: '断食' },
goals: { icon: 'flag.fill', title: '习惯' },
challenges: { icon: 'trophy.fill', title: '挑战' },
personal: { icon: 'person.fill', title: '个人' },
};
@@ -38,7 +37,6 @@ export default function TabLayout() {
const routeMap: Record<string, string> = {
statistics: ROUTES.TAB_STATISTICS,
fasting: ROUTES.TAB_FASTING,
goals: ROUTES.TAB_GOALS,
challenges: ROUTES.TAB_CHALLENGES,
personal: ROUTES.TAB_PERSONAL,
};
@@ -182,10 +180,6 @@ export default function TabLayout() {
<Icon sf="timer" drawable="custom_android_drawable" />
<Label></Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="goals">
<Icon sf="flag.fill" drawable="custom_settings_drawable" />
<Label></Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="challenges">
<Icon sf="trophy.fill" drawable="custom_android_drawable" />
<Label></Label>
@@ -205,7 +199,6 @@ export default function TabLayout() {
<Tabs.Screen name="statistics" options={{ title: '健康' }} />
<Tabs.Screen name="fasting" options={{ title: '断食' }} />
<Tabs.Screen name="goals" options={{ title: '习惯' }} />
<Tabs.Screen name="challenges" options={{ title: '挑战' }} />
<Tabs.Screen name="personal" options={{ title: '个人' }} />
</Tabs>

View File

@@ -1,920 +0,0 @@
import CelebrationAnimation, { CelebrationAnimationRef } from '@/components/CelebrationAnimation';
import GoalTemplateModal from '@/components/GoalTemplateModal';
import { GoalsPageGuide } from '@/components/GoalsPageGuide';
import { GuideTestButton } from '@/components/GuideTestButton';
import { TaskCard } from '@/components/TaskCard';
import { TaskFilterTabs, TaskFilterType } from '@/components/TaskFilterTabs';
import { TaskProgressCard } from '@/components/TaskProgressCard';
import { CreateGoalModal } from '@/components/model/CreateGoalModal';
import { useGlobalDialog } from '@/components/ui/DialogProvider';
import { Colors } from '@/constants/Colors';
import { TAB_BAR_BOTTOM_OFFSET, TAB_BAR_HEIGHT } from '@/constants/TabBar';
import { GoalTemplate } from '@/constants/goalTemplates';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useColorScheme } from '@/hooks/useColorScheme';
import { clearErrors, createGoal } from '@/store/goalsSlice';
import { clearErrors as clearTaskErrors, fetchTasks, loadMoreTasks } from '@/store/tasksSlice';
import { CreateGoalRequest, TaskListItem } from '@/types/goals';
import { checkGuideCompleted, markGuideCompleted } from '@/utils/guideHelpers';
import { GoalNotificationHelpers } from '@/utils/notificationHelpers';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useFocusEffect } from '@react-navigation/native';
import dayjs from 'dayjs';
import * as Haptics from 'expo-haptics';
import { LinearGradient } from 'expo-linear-gradient';
import Lottie from 'lottie-react-native';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Alert, FlatList, Image, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
export default function GoalsScreen() {
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
const colorTokens = Colors[theme];
const dispatch = useAppDispatch();
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
const { showConfirm } = useGlobalDialog();
// Redux状态
const {
tasks,
tasksLoading,
tasksError,
tasksPagination,
completeError,
skipError,
} = useAppSelector((state) => state.tasks);
const {
createLoading,
createError
} = useAppSelector((state) => state.goals);
const userProfile = useAppSelector((state) => state.user.profile);
const [showTemplateModal, setShowTemplateModal] = useState(false);
const [showCreateModal, setShowCreateModal] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [selectedFilter, setSelectedFilter] = useState<TaskFilterType>('all');
const [modalKey, setModalKey] = useState(0); // 用于强制重新渲染弹窗
const [showGuide, setShowGuide] = useState(false); // 控制引导显示
const [selectedTemplateData, setSelectedTemplateData] = useState<Partial<CreateGoalRequest> | undefined>();
// 庆祝动画引用
const celebrationAnimationRef = useRef<CelebrationAnimationRef>(null);
// 页面聚焦时重新加载数据
useFocusEffect(
useCallback(() => {
console.log('useFocusEffect - loading tasks isLoggedIn', isLoggedIn);
if (isLoggedIn) {
loadTasks();
checkAndShowGuide();
}
}, [dispatch, isLoggedIn])
);
// 检查并显示用户引导
const checkAndShowGuide = async () => {
try {
const hasCompletedGuide = await checkGuideCompleted('GOALS_PAGE');
if (!hasCompletedGuide) {
// 延迟显示引导,确保页面完全加载
setTimeout(() => {
setShowGuide(true);
}, 1000);
}
} catch (error) {
console.error('检查引导状态失败:', error);
}
};
// 加载任务列表
const loadTasks = async () => {
try {
await dispatch(fetchTasks({
startDate: dayjs().startOf('day').toISOString(),
endDate: dayjs().endOf('day').toISOString(),
})).unwrap();
} catch (error) {
console.error('Failed to load tasks:', error);
}
};
// 下拉刷新
const onRefresh = async () => {
setRefreshing(true);
try {
if (!isLoggedIn) return
await loadTasks();
} finally {
setRefreshing(false);
}
};
// 加载更多任务
const handleLoadMoreTasks = async () => {
if (!isLoggedIn) return
if (tasksPagination.hasMore && !tasksLoading) {
try {
await dispatch(loadMoreTasks()).unwrap();
} catch (error) {
console.error('Failed to load more tasks:', error);
}
}
};
// 处理错误提示
useEffect(() => {
if (tasksError) {
Alert.alert('错误', tasksError);
dispatch(clearTaskErrors());
}
if (createError) {
Alert.alert('创建失败', createError);
dispatch(clearErrors());
}
if (completeError) {
Alert.alert('完成失败', completeError);
dispatch(clearTaskErrors());
}
if (skipError) {
Alert.alert('跳过失败', skipError);
dispatch(clearTaskErrors());
}
}, [tasksError, createError, completeError, skipError, dispatch]);
// 重置弹窗表单数据
const handleModalSuccess = () => {
// 不需要在这里改变 modalKey因为弹窗已经关闭了
// 下次打开时会自动使用新的 modalKey
setSelectedTemplateData(undefined);
};
// 处理模板选择
const handleSelectTemplate = (template: GoalTemplate) => {
setSelectedTemplateData(template.data);
setShowTemplateModal(false);
setModalKey(prev => prev + 1);
setShowCreateModal(true);
};
// 处理创建自定义目标
const handleCreateCustomGoal = () => {
setSelectedTemplateData(undefined);
setShowTemplateModal(false);
setModalKey(prev => prev + 1);
setShowCreateModal(true);
};
// 打开模板选择弹窗
const handleOpenTemplateModal = () => {
setSelectedTemplateData(undefined);
setShowTemplateModal(true);
};
// 创建目标处理函数
const handleCreateGoal = async (goalData: CreateGoalRequest) => {
try {
await dispatch(createGoal(goalData)).unwrap();
setShowCreateModal(false);
// 获取用户名
const userName = userProfile?.name || '主人';
// 创建目标成功后,设置定时推送
try {
if (goalData.hasReminder) {
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: goalData.title,
repeatType: goalData.repeatType,
frequency: goalData.frequency,
hasReminder: goalData.hasReminder,
reminderTime: goalData.reminderTime,
customRepeatRule: goalData.customRepeatRule,
startTime: goalData.startTime,
},
userName
);
console.log(`目标"${goalData.title}"的定时推送已创建通知ID`, notificationIds);
}
} catch (notificationError) {
console.error('创建目标定时推送失败:', notificationError);
// 通知创建失败不影响目标创建的成功
}
// 使用确认弹窗显示成功消息
showConfirm(
{
title: '目标创建成功',
message: '恭喜!您的目标已成功创建。系统将自动生成相应的任务,帮助您实现目标。',
confirmText: '确定',
cancelText: '',
icon: 'checkmark-circle',
iconColor: '#10B981',
},
() => {
// 用户点击确定后的回调
console.log('用户确认了目标创建成功');
}
);
// 创建目标后重新加载任务列表
loadTasks();
} catch (error) {
// 错误已在useEffect中处理
}
};
// 导航到任务列表页面
const handleNavigateToTasks = () => {
pushIfAuthedElseLogin('/task-list');
};
// 计算各状态的任务数量
const taskCounts = {
all: tasks.length,
pending: tasks.filter(task => task.status === 'pending').length,
completed: tasks.filter(task => task.status === 'completed').length,
skipped: tasks.filter(task => task.status === 'skipped').length,
};
// 根据筛选条件过滤任务,并将已完成的任务放到最后
const filteredTasks = React.useMemo(() => {
let filtered: TaskListItem[] = [];
switch (selectedFilter) {
case 'pending':
filtered = tasks.filter(task => task.status === 'pending');
break;
case 'completed':
filtered = tasks.filter(task => task.status === 'completed');
break;
case 'skipped':
filtered = tasks.filter(task => task.status === 'skipped');
break;
default:
filtered = tasks;
break;
}
// 对所有筛选结果进行排序:已完成的任务放到最后
return [...filtered].sort((a, b) => {
// 如果a已完成而b未完成a排在后面
if (a.status === 'completed' && b.status !== 'completed') {
return 1;
}
// 如果b已完成而a未完成b排在后面
if (b.status === 'completed' && a.status !== 'completed') {
return -1;
}
// 如果都已完成或都未完成,保持原有顺序
return 0;
});
}, [tasks, selectedFilter]);
// 处理筛选变化
const handleFilterChange = (filter: TaskFilterType) => {
setSelectedFilter(filter);
};
// 处理引导完成
const handleGuideComplete = async () => {
try {
await markGuideCompleted('GOALS_PAGE');
setShowGuide(false);
} catch (error) {
console.error('保存引导状态失败:', error);
setShowGuide(false);
}
};
// 处理任务完成
const handleTaskCompleted = (completedTask: TaskListItem) => {
// 触发震动反馈
if (process.env.EXPO_OS === 'ios') {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
}
// 播放庆祝动画
celebrationAnimationRef.current?.play();
console.log(`任务 "${completedTask.title}" 已完成,播放庆祝动画`);
};
// 渲染任务项
const renderTaskItem = ({ item }: { item: TaskListItem }) => (
<TaskCard
task={item}
onTaskCompleted={handleTaskCompleted}
/>
);
// 渲染空状态
const renderEmptyState = () => {
// 未登录状态下的引导
if (!isLoggedIn) {
return (
<View style={styles.emptyStateLogin}>
<LinearGradient
colors={['#F0F9FF', '#FEFEFE', '#F0F9FF']}
style={styles.emptyStateLoginBackground}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
/>
<View style={styles.emptyStateLoginContent}>
{/* 清新的图标设计 */}
<View style={styles.emptyStateLoginIconContainer}>
<LinearGradient
colors={[colorTokens.primary, '#9B8AFB']}
style={styles.emptyStateLoginIconGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<MaterialIcons name="person-outline" size={32} color="#FFFFFF" />
</LinearGradient>
</View>
{/* 主标题 */}
<Text style={[styles.emptyStateLoginTitle, { color: colorTokens.text }]}>
</Text>
{/* 副标题 */}
<Text style={[styles.emptyStateLoginSubtitle, { color: colorTokens.textSecondary }]}>
</Text>
{/* 登录按钮 */}
<TouchableOpacity
style={[styles.emptyStateLoginButton, { backgroundColor: colorTokens.primary }]}
onPress={() => pushIfAuthedElseLogin('/goals')}
>
<LinearGradient
colors={[colorTokens.primary, '#9B8AFB']}
style={styles.emptyStateLoginButtonGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<Text style={styles.emptyStateLoginButtonText}></Text>
<MaterialIcons name="arrow-forward" size={18} color="#FFFFFF" />
</LinearGradient>
</TouchableOpacity>
</View>
</View>
);
}
// 已登录但无任务的状态
let title = '暂无任务';
let subtitle = '创建目标后,系统会自动生成相应的任务';
if (selectedFilter === 'pending') {
title = '暂无待完成的任务';
subtitle = '当前没有待完成的任务';
} else if (selectedFilter === 'completed') {
title = '暂无已完成的任务';
subtitle = '完成一些任务后,它们会显示在这里';
} else if (selectedFilter === 'skipped') {
title = '暂无已跳过的任务';
subtitle = '跳过一些任务后,它们会显示在这里';
}
return (
<View style={styles.emptyState}>
<Image
source={require('@/assets/images/task/ImageEmpty.png')}
style={styles.emptyStateImage}
resizeMode="contain"
/>
<Text style={[styles.emptyStateTitle, { color: colorTokens.text }]}>
{title}
</Text>
<Text style={[styles.emptyStateSubtitle, { color: colorTokens.textSecondary }]}>
{subtitle}
</Text>
</View>
);
};
// 渲染加载更多
const renderLoadMore = () => {
if (!tasksPagination.hasMore) return null;
return (
<View style={styles.loadMoreContainer}>
<Text style={[styles.loadMoreText, { color: colorTokens.textSecondary }]}>
{tasksLoading ? '加载中...' : '上拉加载更多'}
</Text>
</View>
);
};
return (
<SafeAreaView style={styles.container}>
<StatusBar
backgroundColor="transparent"
translucent
/>
{/* 背景渐变 */}
<LinearGradient
colors={['#F0F9FF', '#E0F2FE']}
style={styles.gradientBackground}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
/>
<View style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: '#7A5AF8',
height: 233,
borderBottomLeftRadius: 24,
borderBottomRightRadius: 24,
}}>
{/* 右下角Lottie动画 */}
<Lottie
source={require('@/assets/lottie/Goal.json')}
style={styles.bottomRightImage}
autoPlay
loop
/>
</View>
<View style={styles.content}>
{/* 标题区域 */}
<View style={styles.header}>
<View>
<Text style={[styles.pageTitle, { color: '#FFFFFF' }]}>
</Text>
<Text style={[styles.pageTitle2, { color: '#FFFFFF' }]}>
</Text>
</View>
</View>
{/* 任务进度卡片 */}
<View >
<TaskProgressCard
tasks={tasks}
headerButtons={
<View style={styles.cardHeaderButtons}>
<TouchableOpacity
style={[styles.cardGoalsButton, { borderColor: colorTokens.primary }]}
onPress={handleNavigateToTasks}
>
<Text style={[styles.cardGoalsButtonText, { color: colorTokens.primary }]}>
</Text>
<MaterialIcons name="list" size={16} color={colorTokens.primary} />
</TouchableOpacity>
<TouchableOpacity
style={[styles.cardAddButton, { backgroundColor: colorTokens.primary }]}
onPress={handleOpenTemplateModal}
>
<Text style={styles.cardAddButtonText}>+</Text>
</TouchableOpacity>
</View>
}
/>
</View>
{/* 任务筛选标签 */}
<TaskFilterTabs
selectedFilter={selectedFilter}
onFilterChange={handleFilterChange}
taskCounts={taskCounts}
/>
{/* 任务列表 */}
<View style={styles.taskListContainer}>
<FlatList
data={filteredTasks}
renderItem={renderTaskItem}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.taskList}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={['#0EA5E9']}
tintColor="#0EA5E9"
/>
}
onEndReached={handleLoadMoreTasks}
onEndReachedThreshold={0.1}
ListEmptyComponent={renderEmptyState}
ListFooterComponent={renderLoadMore}
/>
</View>
{/* 目标模板选择弹窗 */}
<GoalTemplateModal
visible={showTemplateModal}
onClose={() => setShowTemplateModal(false)}
onSelectTemplate={handleSelectTemplate}
onCreateCustom={handleCreateCustomGoal}
/>
{/* 创建目标弹窗 */}
<CreateGoalModal
key={modalKey}
visible={showCreateModal}
onClose={() => {
setShowCreateModal(false);
setSelectedTemplateData(undefined);
}}
onSubmit={handleCreateGoal}
onSuccess={handleModalSuccess}
loading={createLoading}
initialData={selectedTemplateData}
/>
{/* 目标页面引导 */}
<GoalsPageGuide
visible={showGuide}
onComplete={handleGuideComplete}
tasks={tasks}
/>
{/* 开发测试按钮 */}
<GuideTestButton visible={__DEV__} />
{/* 目标通知测试按钮 */}
{__DEV__ && (
<TouchableOpacity
style={styles.testButton}
onPress={() => {
// 这里可以导航到测试页面或显示测试弹窗
Alert.alert(
'目标通知测试',
'选择要测试的通知类型',
[
{ text: '取消', style: 'cancel' },
{
text: '每日目标通知',
onPress: async () => {
try {
const userName = userProfile?.name || '';
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: '每日运动目标',
repeatType: 'daily',
frequency: 1,
hasReminder: true,
reminderTime: '09:00',
},
userName
);
Alert.alert('成功', `每日目标通知已创建ID: ${notificationIds.join(', ')}`);
} catch (error) {
Alert.alert('错误', `创建通知失败: ${error}`);
}
}
},
{
text: '每周目标通知',
onPress: async () => {
try {
const userName = userProfile?.name || '';
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: '每周运动目标',
repeatType: 'weekly',
frequency: 1,
hasReminder: true,
reminderTime: '10:00',
customRepeatRule: {
weekdays: [1, 3, 5], // 周一、三、五
},
},
userName
);
Alert.alert('成功', `每周目标通知已创建ID: ${notificationIds.join(', ')}`);
} catch (error) {
Alert.alert('错误', `创建通知失败: ${error}`);
}
}
},
{
text: '目标达成通知',
onPress: async () => {
try {
const userName = userProfile?.name || '';
await GoalNotificationHelpers.sendGoalAchievementNotification(userName, '每日运动目标');
Alert.alert('成功', '目标达成通知已发送');
} catch (error) {
Alert.alert('错误', `发送通知失败: ${error}`);
}
}
},
{
text: '测试庆祝动画',
onPress: () => {
celebrationAnimationRef.current?.play();
}
},
]
);
}}
>
<Text style={styles.testButtonText}></Text>
</TouchableOpacity>
)}
{/* 庆祝动画组件 */}
<CelebrationAnimation ref={celebrationAnimationRef} />
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
gradientBackground: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
opacity: 0.6,
},
decorativeCircle1: {
position: 'absolute',
top: -20,
right: -20,
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: '#0EA5E9',
opacity: 0.1,
},
decorativeCircle2: {
position: 'absolute',
bottom: -15,
left: -15,
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#0EA5E9',
opacity: 0.05,
},
content: {
flex: 1,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 16,
},
headerButtons: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
goalsButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 20,
backgroundColor: 'rgba(255, 255, 255, 0.8)',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
pageTitle: {
fontSize: 28,
fontWeight: '800',
marginBottom: 4,
},
pageTitle2: {
fontSize: 16,
fontWeight: '400',
color: '#FFFFFF',
lineHeight: 24,
},
addButton: {
width: 30,
height: 30,
borderRadius: 20,
backgroundColor: '#0EA5E9',
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
addButtonText: {
color: '#FFFFFF',
fontSize: 22,
fontWeight: '600',
lineHeight: 22,
},
taskListContainer: {
flex: 1,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
overflow: 'hidden',
},
taskList: {
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: TAB_BAR_HEIGHT + TAB_BAR_BOTTOM_OFFSET + 20, // 避让底部导航栏 + 额外间距
},
emptyState: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 60,
},
emptyStateImage: {
width: 223,
height: 59,
marginBottom: 20,
},
emptyStateTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 8,
},
emptyStateSubtitle: {
fontSize: 14,
textAlign: 'center',
lineHeight: 20,
},
// 未登录空状态样式
emptyStateLogin: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 24,
paddingVertical: 80,
position: 'relative',
},
emptyStateLoginBackground: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
borderRadius: 24,
},
emptyStateLoginContent: {
alignItems: 'center',
justifyContent: 'center',
zIndex: 1,
},
emptyStateLoginIconContainer: {
marginBottom: 24,
shadowColor: '#7A5AF8',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.15,
shadowRadius: 16,
elevation: 8,
},
emptyStateLoginIconGradient: {
width: 80,
height: 80,
borderRadius: 40,
alignItems: 'center',
justifyContent: 'center',
},
emptyStateLoginTitle: {
fontSize: 24,
fontWeight: '700',
marginBottom: 12,
textAlign: 'center',
letterSpacing: -0.5,
},
emptyStateLoginSubtitle: {
fontSize: 16,
lineHeight: 24,
textAlign: 'center',
marginBottom: 32,
paddingHorizontal: 8,
},
emptyStateLoginButton: {
borderRadius: 28,
shadowColor: '#7A5AF8',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.2,
shadowRadius: 12,
elevation: 6,
},
emptyStateLoginButtonGradient: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 32,
paddingVertical: 16,
borderRadius: 28,
gap: 8,
},
emptyStateLoginButtonText: {
color: '#FFFFFF',
fontSize: 17,
fontWeight: '600',
letterSpacing: -0.2,
},
loadMoreContainer: {
alignItems: 'center',
paddingVertical: 20,
},
loadMoreText: {
fontSize: 14,
fontWeight: '500',
},
bottomRightImage: {
position: 'absolute',
top: 40,
right: 36,
width: 120,
height: 120,
},
// 任务进度卡片中的按钮样式
cardHeaderButtons: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
cardGoalsButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
paddingHorizontal: 10,
paddingVertical: 6,
borderRadius: 16,
backgroundColor: '#F3F4F6',
borderWidth: 1,
},
cardGoalsListButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
paddingHorizontal: 10,
paddingVertical: 6,
borderRadius: 16,
backgroundColor: '#F3F4F6',
borderWidth: 1,
},
cardGoalsButtonText: {
fontSize: 12,
fontWeight: '600',
color: '#374151',
},
cardAddButton: {
width: 28,
height: 28,
borderRadius: 14,
alignItems: 'center',
justifyContent: 'center',
},
cardAddButtonText: {
color: '#FFFFFF',
fontSize: 18,
fontWeight: '600',
lineHeight: 18,
},
testButton: {
position: 'absolute',
top: 100,
right: 20,
backgroundColor: '#10B981',
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 8,
zIndex: 1000,
},
testButtonText: {
color: '#FFFFFF',
fontSize: 12,
fontWeight: '600',
},
});