feat: 更新统计标签和标题,优化健康数据卡片样式,调整步数和健康相关组件的样式
This commit is contained in:
@@ -48,7 +48,7 @@ export default function TabLayout() {
|
|||||||
case 'goals':
|
case 'goals':
|
||||||
return { icon: 'flag.fill', title: '习惯' } as const;
|
return { icon: 'flag.fill', title: '习惯' } as const;
|
||||||
case 'statistics':
|
case 'statistics':
|
||||||
return { icon: 'chart.pie.fill', title: '统计' } as const;
|
return { icon: 'chart.pie.fill', title: '健康' } as const;
|
||||||
case 'personal':
|
case 'personal':
|
||||||
return { icon: 'person.fill', title: '个人' } as const;
|
return { icon: 'person.fill', title: '个人' } as const;
|
||||||
default:
|
default:
|
||||||
@@ -132,15 +132,15 @@ export default function TabLayout() {
|
|||||||
}}>
|
}}>
|
||||||
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="coach"
|
name="statistics"
|
||||||
options={{
|
options={{
|
||||||
title: 'Seal',
|
title: '统计',
|
||||||
tabBarIcon: ({ color }) => {
|
tabBarIcon: ({ color }) => {
|
||||||
const isCoachSelected = pathname === '/coach';
|
const isStatisticsSelected = pathname === '/statistics';
|
||||||
return (
|
return (
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<IconSymbol size={22} name="person.3.fill" color={color} />
|
<IconSymbol size={22} name="chart.pie.fill" color={color} />
|
||||||
{isCoachSelected && (
|
{isStatisticsSelected && (
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={{
|
style={{
|
||||||
@@ -151,7 +151,7 @@ export default function TabLayout() {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
Seal
|
健康
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -188,17 +188,16 @@ export default function TabLayout() {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="statistics"
|
name="coach"
|
||||||
options={{
|
options={{
|
||||||
title: '统计',
|
title: 'Seal',
|
||||||
tabBarIcon: ({ color }) => {
|
tabBarIcon: ({ color }) => {
|
||||||
const isStatisticsSelected = pathname === '/statistics';
|
const isCoachSelected = pathname === '/coach';
|
||||||
return (
|
return (
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<IconSymbol size={22} name="chart.pie.fill" color={color} />
|
<IconSymbol size={22} name="person.3.fill" color={color} />
|
||||||
{isStatisticsSelected && (
|
{isCoachSelected && (
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={{
|
style={{
|
||||||
@@ -209,7 +208,7 @@ export default function TabLayout() {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
统计
|
Seal
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -217,6 +216,7 @@ export default function TabLayout() {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="goals"
|
name="goals"
|
||||||
options={{
|
options={{
|
||||||
|
|||||||
@@ -300,8 +300,6 @@ export default function ExploreScreen() {
|
|||||||
contentContainerStyle={{ paddingBottom: bottomPadding }}
|
contentContainerStyle={{ paddingBottom: bottomPadding }}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
{/* 体重历史记录卡片 */}
|
|
||||||
<Text style={styles.sectionTitle}>健康数据</Text>
|
|
||||||
<WeightHistoryCard />
|
<WeightHistoryCard />
|
||||||
|
|
||||||
{/* 日期选择器 */}
|
{/* 日期选择器 */}
|
||||||
@@ -617,7 +615,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
cardTitle: {
|
cardTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
heartCard: {
|
heartCard: {
|
||||||
|
|||||||
@@ -115,8 +115,7 @@ const styles = StyleSheet.create({
|
|||||||
borderBottomRightRadius: 2,
|
borderBottomRightRadius: 2,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
fontWeight: '700',
|
|
||||||
color: '#0F172A',
|
color: '#0F172A',
|
||||||
},
|
},
|
||||||
statusBadge: {
|
statusBadge: {
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ const styles = StyleSheet.create({
|
|||||||
paddingVertical: 8,
|
paddingVertical: 8,
|
||||||
},
|
},
|
||||||
monthTitle: {
|
monthTitle: {
|
||||||
fontSize: 24,
|
fontSize: 18,
|
||||||
fontWeight: '800',
|
fontWeight: '800',
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
marginBottom: 14,
|
marginBottom: 14,
|
||||||
@@ -234,7 +234,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
dayDate: {
|
dayDate: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: '800',
|
fontWeight: '600',
|
||||||
color: 'gray',
|
color: 'gray',
|
||||||
},
|
},
|
||||||
dayDateSelected: {
|
dayDateSelected: {
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ const styles = StyleSheet.create({
|
|||||||
|
|
||||||
cardTitle: {
|
cardTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export function NutritionRadarCard({
|
|||||||
<View style={styles.cardRightContainer}>
|
<View style={styles.cardRightContainer}>
|
||||||
<Text style={styles.cardSubtitle}>更新: {dayjs(nutritionSummary?.updatedAt).format('MM-DD HH:mm')}</Text>
|
<Text style={styles.cardSubtitle}>更新: {dayjs(nutritionSummary?.updatedAt).format('MM-DD HH:mm')}</Text>
|
||||||
<TouchableOpacity style={styles.addButton} onPress={handleAddFood}>
|
<TouchableOpacity style={styles.addButton} onPress={handleAddFood}>
|
||||||
<Ionicons name="add" size={16} color="#FFFFFF" />
|
<Ionicons name="add" size={12} color="#514b4bff" />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -185,11 +185,10 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: 16,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
cardTitle: {
|
cardTitle: {
|
||||||
fontSize: 18,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
cardRightContainer: {
|
cardRightContainer: {
|
||||||
@@ -198,7 +197,7 @@ const styles = StyleSheet.create({
|
|||||||
gap: 4,
|
gap: 4,
|
||||||
},
|
},
|
||||||
cardSubtitle: {
|
cardSubtitle: {
|
||||||
fontSize: 12,
|
fontSize: 10,
|
||||||
color: '#9AA3AE',
|
color: '#9AA3AE',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
},
|
},
|
||||||
@@ -230,15 +229,14 @@ const styles = StyleSheet.create({
|
|||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
},
|
},
|
||||||
statLabel: {
|
statLabel: {
|
||||||
fontSize: 12,
|
fontSize: 10,
|
||||||
color: '#9AA3AE',
|
color: '#9AA3AE',
|
||||||
fontWeight: '600',
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
statValue: {
|
statValue: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
fontWeight: '700',
|
fontWeight: '600',
|
||||||
},
|
},
|
||||||
// 卡路里相关样式
|
// 卡路里相关样式
|
||||||
calorieSection: {
|
calorieSection: {
|
||||||
@@ -272,12 +270,12 @@ const styles = StyleSheet.create({
|
|||||||
gap: 4,
|
gap: 4,
|
||||||
},
|
},
|
||||||
mainValue: {
|
mainValue: {
|
||||||
fontSize: 24,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
fontWeight: '600',
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
calculationText: {
|
calculationText: {
|
||||||
fontSize: 14,
|
fontSize: 12,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#64748B',
|
color: '#64748B',
|
||||||
},
|
},
|
||||||
@@ -287,12 +285,12 @@ const styles = StyleSheet.create({
|
|||||||
gap: 2,
|
gap: 2,
|
||||||
},
|
},
|
||||||
calculationLabel: {
|
calculationLabel: {
|
||||||
fontSize: 10,
|
fontSize: 8,
|
||||||
color: '#64748B',
|
color: '#64748B',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
calculationValue: {
|
calculationValue: {
|
||||||
fontSize: 12,
|
fontSize: 10,
|
||||||
fontWeight: '700',
|
fontWeight: '700',
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
@@ -315,10 +313,10 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
},
|
},
|
||||||
addButton: {
|
addButton: {
|
||||||
width: 18,
|
width: 16,
|
||||||
height: 18,
|
height: 16,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
backgroundColor: '#9AA3AE',
|
backgroundColor: '#e5e8ecff',
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
|||||||
@@ -106,8 +106,7 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
fontWeight: '700',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
footprintIcons: {
|
footprintIcons: {
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
},
|
},
|
||||||
valueSection: {
|
valueSection: {
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
marginBottom: 14,
|
marginBottom: 14,
|
||||||
fontWeight: '800',
|
|
||||||
},
|
},
|
||||||
valueContainer: {
|
valueContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|||||||
@@ -11,13 +11,12 @@ import { LinearGradient } from 'expo-linear-gradient';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
Image,
|
|
||||||
Modal,
|
Modal,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Animated, {
|
import Animated, {
|
||||||
Extrapolation,
|
Extrapolation,
|
||||||
@@ -201,9 +200,6 @@ export function WeightHistoryCard() {
|
|||||||
return (
|
return (
|
||||||
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
||||||
<View style={styles.cardHeader}>
|
<View style={styles.cardHeader}>
|
||||||
<View style={styles.iconSquare}>
|
|
||||||
<Image source={require('@/assets/images/icons/iconWeight.png')} style={{ width: 18, height: 18 }} />
|
|
||||||
</View>
|
|
||||||
<Text style={styles.cardTitle}>体重记录</Text>
|
<Text style={styles.cardTitle}>体重记录</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.emptyContent}>
|
<View style={styles.emptyContent}>
|
||||||
@@ -218,9 +214,6 @@ export function WeightHistoryCard() {
|
|||||||
return (
|
return (
|
||||||
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
||||||
<View style={styles.cardHeader}>
|
<View style={styles.cardHeader}>
|
||||||
<View style={styles.iconSquare}>
|
|
||||||
<Image source={require('@/assets/images/icons/iconWeight.png')} style={{ width: 18, height: 18 }} />
|
|
||||||
</View>
|
|
||||||
<Text style={styles.cardTitle}>体重记录</Text>
|
<Text style={styles.cardTitle}>体重记录</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -254,9 +247,6 @@ export function WeightHistoryCard() {
|
|||||||
return (
|
return (
|
||||||
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
||||||
<View style={styles.cardHeader}>
|
<View style={styles.cardHeader}>
|
||||||
<View style={styles.iconSquare}>
|
|
||||||
<Image source={require('@/assets/images/icons/iconWeight.png')} style={{ width: 18, height: 18 }} />
|
|
||||||
</View>
|
|
||||||
<Text style={styles.cardTitle}>体重记录</Text>
|
<Text style={styles.cardTitle}>体重记录</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -308,9 +298,6 @@ export function WeightHistoryCard() {
|
|||||||
return (
|
return (
|
||||||
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
|
||||||
<View style={styles.cardHeader}>
|
<View style={styles.cardHeader}>
|
||||||
<View style={styles.iconSquare}>
|
|
||||||
<Image source={require('@/assets/images/icons/iconWeight.png')} style={{ width: 18, height: 18 }} />
|
|
||||||
</View>
|
|
||||||
<Text style={styles.cardTitle}>体重记录</Text>
|
<Text style={styles.cardTitle}>体重记录</Text>
|
||||||
<View style={styles.headerButtons}>
|
<View style={styles.headerButtons}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -580,8 +567,8 @@ const styles = StyleSheet.create({
|
|||||||
card: {
|
card: {
|
||||||
backgroundColor: '#FFFFFF',
|
backgroundColor: '#FFFFFF',
|
||||||
borderRadius: 22,
|
borderRadius: 22,
|
||||||
padding: 18,
|
padding: 16,
|
||||||
marginBottom: 8,
|
marginBottom: 4,
|
||||||
shadowColor: '#000',
|
shadowColor: '#000',
|
||||||
shadowOffset: { width: 0, height: 2 },
|
shadowOffset: { width: 0, height: 2 },
|
||||||
shadowOpacity: 0.1,
|
shadowOpacity: 0.1,
|
||||||
@@ -591,7 +578,6 @@ const styles = StyleSheet.create({
|
|||||||
cardHeader: {
|
cardHeader: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: 16,
|
|
||||||
},
|
},
|
||||||
iconSquare: {
|
iconSquare: {
|
||||||
width: 30,
|
width: 30,
|
||||||
@@ -603,7 +589,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
cardTitle: {
|
cardTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '800',
|
|
||||||
color: '#192126',
|
color: '#192126',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
@@ -675,9 +660,6 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
paddingTop: 16,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: '#F0F0F0',
|
|
||||||
},
|
},
|
||||||
infoItem: {
|
infoItem: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@@ -162,39 +162,11 @@ async function fetchStepCount(date: Date): Promise<number> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取指定日期每小时步数数据
|
// 获取指定日期每小时步数数据 (已弃用,使用 fetchHourlyStepSamples 替代)
|
||||||
|
// 保留此函数以防后向兼容需求
|
||||||
async function fetchHourlyStepCount(date: Date): Promise<HourlyStepData[]> {
|
async function fetchHourlyStepCount(date: Date): Promise<HourlyStepData[]> {
|
||||||
return new Promise((resolve) => {
|
// 直接调用更准确的样本数据获取函数
|
||||||
const startOfDay = dayjs(date).startOf('day');
|
return fetchHourlyStepSamples(date);
|
||||||
const endOfDay = dayjs(date).endOf('day');
|
|
||||||
|
|
||||||
AppleHealthKit.getStepCount({
|
|
||||||
startDate: startOfDay.toDate().toISOString(),
|
|
||||||
endDate: endOfDay.toDate().toISOString(),
|
|
||||||
includeManuallyAdded: false,
|
|
||||||
}, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
logError('每小时步数', err);
|
|
||||||
return resolve(Array.from({ length: 24 }, (_, i) => ({ hour: i, steps: 0 })));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
|
||||||
logWarning('每小时步数', '为空');
|
|
||||||
return resolve(Array.from({ length: 24 }, (_, i) => ({ hour: i, steps: 0 })));
|
|
||||||
}
|
|
||||||
|
|
||||||
logSuccess('每小时步数', res);
|
|
||||||
|
|
||||||
// 初始化24小时数据
|
|
||||||
const hourlyData: HourlyStepData[] = Array.from({ length: 24 }, (_, i) => ({
|
|
||||||
hour: i,
|
|
||||||
steps: 0
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 如果返回的是累计数据,我们需要获取样本数据
|
|
||||||
resolve(hourlyData);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用样本数据获取每小时步数
|
// 使用样本数据获取每小时步数
|
||||||
@@ -202,42 +174,48 @@ async function fetchHourlyStepSamples(date: Date): Promise<HourlyStepData[]> {
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const startOfDay = dayjs(date).startOf('day');
|
const startOfDay = dayjs(date).startOf('day');
|
||||||
const endOfDay = dayjs(date).endOf('day');
|
const endOfDay = dayjs(date).endOf('day');
|
||||||
|
|
||||||
AppleHealthKit.getSamples(
|
// 使用正确的 getDailyStepCountSamples 方法,设置 period 为 60 分钟获取每小时数据
|
||||||
{
|
const options = {
|
||||||
startDate: startOfDay.toDate().toISOString(),
|
startDate: startOfDay.toDate().toISOString(),
|
||||||
endDate: endOfDay.toDate().toISOString(),
|
endDate: endOfDay.toDate().toISOString(),
|
||||||
type: 'StepCount',
|
ascending: false,
|
||||||
},
|
period: 60, // 60分钟为一个时间段,获取每小时数据
|
||||||
|
includeManuallyAdded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
AppleHealthKit.getDailyStepCountSamples(
|
||||||
|
options,
|
||||||
(err: any, res: any[]) => {
|
(err: any, res: any[]) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
logError('每小时步数样本', err);
|
logError('每小时步数样本', err);
|
||||||
return resolve(Array.from({ length: 24 }, (_, i) => ({ hour: i, steps: 0 })));
|
// 如果主方法失败,尝试使用备用方法
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
|
||||||
logWarning('每小时步数样本', '为空');
|
|
||||||
return resolve(Array.from({ length: 24 }, (_, i) => ({ hour: i, steps: 0 })));
|
|
||||||
}
|
|
||||||
|
|
||||||
logSuccess('每小时步数样本', res);
|
logSuccess('每小时步数样本', res);
|
||||||
|
|
||||||
// 初始化24小时数据
|
// 初始化24小时数据
|
||||||
const hourlyData: HourlyStepData[] = Array.from({ length: 24 }, (_, i) => ({
|
const hourlyData: HourlyStepData[] = Array.from({ length: 24 }, (_, i) => ({
|
||||||
hour: i,
|
hour: i,
|
||||||
steps: 0
|
steps: 0
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 将样本数据按小时分组并累加
|
// 将每小时的步数样本数据映射到对应的小时
|
||||||
res.forEach((sample: any) => {
|
res.forEach((sample: any) => {
|
||||||
if (sample && sample.startDate && sample.value) {
|
if (sample && sample.startDate && sample.value !== undefined) {
|
||||||
const hour = dayjs(sample.startDate).hour();
|
const hour = dayjs(sample.startDate).hour();
|
||||||
if (hour >= 0 && hour < 24) {
|
if (hour >= 0 && hour < 24) {
|
||||||
hourlyData[hour].steps += Math.round(sample.value);
|
// 使用样本中的步数值,如果有 metadata,优先使用 metadata 中的数据
|
||||||
|
const stepValue = sample.metadata && sample.metadata.length > 0
|
||||||
|
? sample.metadata.reduce((total: number, meta: any) => total + (meta.quantity || 0), 0)
|
||||||
|
: sample.value;
|
||||||
|
|
||||||
|
hourlyData[hour].steps = Math.round(stepValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
resolve(hourlyData);
|
resolve(hourlyData);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user