feat: 实现目标列表左滑删除功能及相关组件
- 在目标列表中添加左滑删除功能,用户可通过左滑手势显示删除按钮并确认删除目标 - 修改 GoalCard 组件,使用 Swipeable 组件包装卡片内容,支持删除操作 - 更新目标列表页面,集成删除目标的逻辑,确保与 Redux 状态管理一致 - 添加开发模式下的模拟数据,方便测试删除功能 - 更新相关文档,详细描述左滑删除功能的实现和使用方法
This commit is contained in:
@@ -197,9 +197,9 @@ export default function GoalsScreen() {
|
||||
|
||||
|
||||
|
||||
// 导航到目标管理页面
|
||||
const handleNavigateToGoals = () => {
|
||||
router.push('/goals-detail');
|
||||
// 导航到任务列表页面
|
||||
const handleNavigateToTasks = () => {
|
||||
router.push('/task-list');
|
||||
};
|
||||
|
||||
// 计算各状态的任务数量
|
||||
@@ -210,18 +210,38 @@ export default function GoalsScreen() {
|
||||
skipped: tasks.filter(task => task.status === 'skipped').length,
|
||||
};
|
||||
|
||||
// 根据筛选条件过滤任务
|
||||
// 根据筛选条件过滤任务,并将已完成的任务放到最后
|
||||
const filteredTasks = React.useMemo(() => {
|
||||
let filtered: TaskListItem[] = [];
|
||||
|
||||
switch (selectedFilter) {
|
||||
case 'pending':
|
||||
return tasks.filter(task => task.status === 'pending');
|
||||
filtered = tasks.filter(task => task.status === 'pending');
|
||||
break;
|
||||
case 'completed':
|
||||
return tasks.filter(task => task.status === 'completed');
|
||||
filtered = tasks.filter(task => task.status === 'completed');
|
||||
break;
|
||||
case 'skipped':
|
||||
return tasks.filter(task => task.status === 'skipped');
|
||||
filtered = tasks.filter(task => task.status === 'skipped');
|
||||
break;
|
||||
default:
|
||||
return tasks;
|
||||
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]);
|
||||
|
||||
// 处理筛选变化
|
||||
@@ -346,12 +366,12 @@ export default function GoalsScreen() {
|
||||
<View style={styles.cardHeaderButtons}>
|
||||
<TouchableOpacity
|
||||
style={[styles.cardGoalsButton, { borderColor: colorTokens.primary }]}
|
||||
onPress={handleNavigateToGoals}
|
||||
onPress={handleNavigateToTasks}
|
||||
>
|
||||
<Text style={[styles.cardGoalsButtonText, { color: colorTokens.primary }]}>
|
||||
回顾
|
||||
历史
|
||||
</Text>
|
||||
<MaterialIcons name="flag" size={16} color={colorTokens.primary} />
|
||||
<MaterialIcons name="list" size={16} color={colorTokens.primary} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.cardAddButton, { backgroundColor: colorTokens.primary }]}
|
||||
@@ -652,6 +672,16 @@ const styles = StyleSheet.create({
|
||||
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',
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { calculateNutritionSummary, getDietRecords, NutritionSummary } from '@/services/dietRecords';
|
||||
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { getMonthDaysZh, getTodayIndexInMonth } from '@/utils/date';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate } from '@/utils/health';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate, testOxygenSaturationData } from '@/utils/health';
|
||||
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -309,6 +309,13 @@ export default function ExploreScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
// 测试血氧饱和度数据
|
||||
const testOxygenData = async () => {
|
||||
console.log('开始测试血氧饱和度数据...');
|
||||
const currentDate = getCurrentSelectedDate();
|
||||
await testOxygenSaturationData(currentDate);
|
||||
};
|
||||
|
||||
// 使用统一的渐变背景色
|
||||
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
||||
|
||||
@@ -450,6 +457,13 @@ export default function ExploreScreen() {
|
||||
style={styles.basalMetabolismCardOverride}
|
||||
oxygenSaturation={oxygenSaturation}
|
||||
/>
|
||||
{/* 测试按钮 - 开发时使用 */}
|
||||
<Text
|
||||
style={styles.testButton}
|
||||
onPress={testOxygenData}
|
||||
>
|
||||
测试血氧数据
|
||||
</Text>
|
||||
</FloatingCard>
|
||||
|
||||
{/* 心率卡片 */}
|
||||
@@ -794,4 +808,11 @@ const styles = StyleSheet.create({
|
||||
moodCard: {
|
||||
backgroundColor: '#F0FDF4',
|
||||
},
|
||||
testButton: {
|
||||
fontSize: 12,
|
||||
color: '#3B82F6',
|
||||
textAlign: 'center',
|
||||
marginTop: 8,
|
||||
padding: 4,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user