feat: 新增任务管理功能及相关组件

- 将目标页面改为任务列表,支持任务的创建、完成和跳过功能
- 新增任务卡片和任务进度卡片组件,展示任务状态和进度
- 实现任务数据的获取和管理,集成Redux状态管理
- 更新API服务,支持任务相关的CRUD操作
- 编写任务管理功能实现文档,详细描述功能和组件架构
This commit is contained in:
richarjiang
2025-08-22 17:30:14 +08:00
parent 231620d778
commit 259f10540e
21 changed files with 2756 additions and 608 deletions

View File

@@ -0,0 +1,82 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
interface HealthDataCardProps {
title: string;
value: string;
unit: string;
icon: React.ReactNode;
style?: object;
}
const HealthDataCard: React.FC<HealthDataCardProps> = ({
title,
value,
unit,
icon,
style
}) => {
return (
<Animated.View
entering={FadeIn.duration(300)}
exiting={FadeOut.duration(300)}
style={[styles.card, style]}
>
<View style={styles.content}>
<Text style={styles.title}>{title}</Text>
<View style={styles.valueContainer}>
<Text style={styles.value}>{value}</Text>
<Text style={styles.unit}>{unit}</Text>
</View>
</View>
</Animated.View>
);
};
const styles = StyleSheet.create({
card: {
borderRadius: 16,
shadowColor: '#000',
paddingHorizontal: 16,
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 3.84,
elevation: 5,
marginVertical: 8,
flexDirection: 'row',
alignItems: 'center',
},
iconContainer: {
marginRight: 16,
},
content: {
flex: 1,
},
title: {
fontSize: 14,
color: '#666',
marginBottom: 4,
},
valueContainer: {
flexDirection: 'row',
alignItems: 'flex-end',
},
value: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
},
unit: {
fontSize: 14,
color: '#666',
marginLeft: 4,
marginBottom: 2,
},
});
export default HealthDataCard;

View File

@@ -0,0 +1,48 @@
import { Ionicons } from '@expo/vector-icons';
import React, { useEffect, useState } from 'react';
import { StyleSheet } from 'react-native';
import HealthDataService from '../../services/healthData';
import HealthDataCard from './HealthDataCard';
interface HeartRateCardProps {
resetToken: number;
style?: object;
}
const HeartRateCard: React.FC<HeartRateCardProps> = ({
resetToken,
style
}) => {
const [heartRate, setHeartRate] = useState<number | null>(null);
useEffect(() => {
const fetchHeartRate = async () => {
const data = await HealthDataService.getHeartRate();
setHeartRate(data);
};
fetchHeartRate();
}, [resetToken]);
const heartIcon = (
<Ionicons name="heart" size={24} color="#EF4444" />
);
return (
<HealthDataCard
title="心率"
value={heartRate !== null ? heartRate.toString() : '--'}
unit="bpm"
icon={heartIcon}
style={style}
/>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default HeartRateCard;

View File

@@ -0,0 +1,48 @@
import { Ionicons } from '@expo/vector-icons';
import React, { useEffect, useState } from 'react';
import { StyleSheet } from 'react-native';
import HealthDataService from '../../services/healthData';
import HealthDataCard from './HealthDataCard';
interface OxygenSaturationCardProps {
resetToken: number;
style?: object;
}
const OxygenSaturationCard: React.FC<OxygenSaturationCardProps> = ({
resetToken,
style
}) => {
const [oxygenSaturation, setOxygenSaturation] = useState<number | null>(null);
useEffect(() => {
const fetchOxygenSaturation = async () => {
const data = await HealthDataService.getOxygenSaturation();
setOxygenSaturation(data);
};
fetchOxygenSaturation();
}, [resetToken]);
const oxygenIcon = (
<Ionicons name="water" size={24} color="#3B82F6" />
);
return (
<HealthDataCard
title="血氧饱和度"
value={oxygenSaturation !== null ? oxygenSaturation.toString() : '--'}
unit="%"
icon={oxygenIcon}
style={style}
/>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default OxygenSaturationCard;