From 6bdfda9fd3438126f872c8c132fff6eeb2d9faca Mon Sep 17 00:00:00 2001 From: richarjiang Date: Sat, 30 Aug 2025 22:37:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E5=92=8C=E6=A0=87=E9=A2=98=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=81=A5=E5=BA=B7=E6=95=B0=E6=8D=AE=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=EF=BC=8C=E8=B0=83=E6=95=B4=E6=AD=A5=E6=95=B0?= =?UTF-8?q?=E5=92=8C=E5=81=A5=E5=BA=B7=E7=9B=B8=E5=85=B3=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(tabs)/_layout.tsx | 28 ++++---- app/(tabs)/statistics.tsx | 3 - components/BasalMetabolismCard.tsx | 3 +- components/DateSelector.tsx | 4 +- components/MoodCard.tsx | 1 - components/NutritionRadarCard.tsx | 30 ++++----- components/StepsCard.tsx | 3 +- components/StressMeter.tsx | 1 - components/statistic/HealthDataCard.tsx | 1 - components/weight/WeightHistoryCard.tsx | 24 +------ utils/health.ts | 88 ++++++++++--------------- 11 files changed, 68 insertions(+), 118 deletions(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 95898ca..65e3493 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -48,7 +48,7 @@ export default function TabLayout() { case 'goals': return { icon: 'flag.fill', title: '习惯' } as const; case 'statistics': - return { icon: 'chart.pie.fill', title: '统计' } as const; + return { icon: 'chart.pie.fill', title: '健康' } as const; case 'personal': return { icon: 'person.fill', title: '个人' } as const; default: @@ -132,15 +132,15 @@ export default function TabLayout() { }}> { - const isCoachSelected = pathname === '/coach'; + const isStatisticsSelected = pathname === '/statistics'; return ( - - {isCoachSelected && ( + + {isStatisticsSelected && ( - Seal + 健康 )} @@ -188,17 +188,16 @@ export default function TabLayout() { }, }} /> - { - const isStatisticsSelected = pathname === '/statistics'; + const isCoachSelected = pathname === '/coach'; return ( - - {isStatisticsSelected && ( + + {isCoachSelected && ( - 统计 + Seal )} @@ -217,6 +216,7 @@ export default function TabLayout() { }, }} /> + - {/* 体重历史记录卡片 */} - 健康数据 {/* 日期选择器 */} @@ -617,7 +615,6 @@ const styles = StyleSheet.create({ }, cardTitle: { fontSize: 14, - fontWeight: '800', color: '#192126', }, heartCard: { diff --git a/components/BasalMetabolismCard.tsx b/components/BasalMetabolismCard.tsx index e8edeeb..5edb9ff 100644 --- a/components/BasalMetabolismCard.tsx +++ b/components/BasalMetabolismCard.tsx @@ -115,8 +115,7 @@ const styles = StyleSheet.create({ borderBottomRightRadius: 2, }, title: { - fontSize: 16, - fontWeight: '700', + fontSize: 14, color: '#0F172A', }, statusBadge: { diff --git a/components/DateSelector.tsx b/components/DateSelector.tsx index 6d6346f..e584fdb 100644 --- a/components/DateSelector.tsx +++ b/components/DateSelector.tsx @@ -185,7 +185,7 @@ const styles = StyleSheet.create({ paddingVertical: 8, }, monthTitle: { - fontSize: 24, + fontSize: 18, fontWeight: '800', color: '#192126', marginBottom: 14, @@ -234,7 +234,7 @@ const styles = StyleSheet.create({ }, dayDate: { fontSize: 12, - fontWeight: '800', + fontWeight: '600', color: 'gray', }, dayDateSelected: { diff --git a/components/MoodCard.tsx b/components/MoodCard.tsx index 7562270..3f66785 100644 --- a/components/MoodCard.tsx +++ b/components/MoodCard.tsx @@ -42,7 +42,6 @@ const styles = StyleSheet.create({ cardTitle: { fontSize: 14, - fontWeight: '800', color: '#192126', }, diff --git a/components/NutritionRadarCard.tsx b/components/NutritionRadarCard.tsx index 67d4be4..ed0959f 100644 --- a/components/NutritionRadarCard.tsx +++ b/components/NutritionRadarCard.tsx @@ -100,7 +100,7 @@ export function NutritionRadarCard({ 更新: {dayjs(nutritionSummary?.updatedAt).format('MM-DD HH:mm')} - + @@ -185,11 +185,10 @@ const styles = StyleSheet.create({ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', - marginBottom: 16, + marginBottom: 8, }, cardTitle: { - fontSize: 18, - fontWeight: '800', + fontSize: 14, color: '#192126', }, cardRightContainer: { @@ -198,7 +197,7 @@ const styles = StyleSheet.create({ gap: 4, }, cardSubtitle: { - fontSize: 12, + fontSize: 10, color: '#9AA3AE', fontWeight: '600', }, @@ -230,15 +229,14 @@ const styles = StyleSheet.create({ marginRight: 8, }, statLabel: { - fontSize: 12, + fontSize: 10, color: '#9AA3AE', - fontWeight: '600', flex: 1, }, statValue: { fontSize: 12, color: '#192126', - fontWeight: '700', + fontWeight: '600', }, // 卡路里相关样式 calorieSection: { @@ -272,12 +270,12 @@ const styles = StyleSheet.create({ gap: 4, }, mainValue: { - fontSize: 24, - fontWeight: '800', + fontSize: 14, + fontWeight: '600', color: '#192126', }, calculationText: { - fontSize: 14, + fontSize: 12, fontWeight: '600', color: '#64748B', }, @@ -287,12 +285,12 @@ const styles = StyleSheet.create({ gap: 2, }, calculationLabel: { - fontSize: 10, + fontSize: 8, color: '#64748B', fontWeight: '500', }, calculationValue: { - fontSize: 12, + fontSize: 10, fontWeight: '700', color: '#192126', }, @@ -315,10 +313,10 @@ const styles = StyleSheet.create({ fontSize: 24, }, addButton: { - width: 18, - height: 18, + width: 16, + height: 16, borderRadius: 8, - backgroundColor: '#9AA3AE', + backgroundColor: '#e5e8ecff', marginLeft: 8, alignItems: 'center', justifyContent: 'center', diff --git a/components/StepsCard.tsx b/components/StepsCard.tsx index 4683591..d73b357 100644 --- a/components/StepsCard.tsx +++ b/components/StepsCard.tsx @@ -106,8 +106,7 @@ const styles = StyleSheet.create({ alignItems: 'center', }, title: { - fontSize: 16, - fontWeight: '700', + fontSize: 14, color: '#192126', }, footprintIcons: { diff --git a/components/StressMeter.tsx b/components/StressMeter.tsx index ff4575b..91b4a00 100644 --- a/components/StressMeter.tsx +++ b/components/StressMeter.tsx @@ -145,7 +145,6 @@ const styles = StyleSheet.create({ }, title: { fontSize: 14, - fontWeight: '800', color: '#192126', }, valueSection: { diff --git a/components/statistic/HealthDataCard.tsx b/components/statistic/HealthDataCard.tsx index 510b7af..281d2ac 100644 --- a/components/statistic/HealthDataCard.tsx +++ b/components/statistic/HealthDataCard.tsx @@ -55,7 +55,6 @@ const styles = StyleSheet.create({ fontSize: 14, color: '#192126', marginBottom: 14, - fontWeight: '800', }, valueContainer: { flexDirection: 'row', diff --git a/components/weight/WeightHistoryCard.tsx b/components/weight/WeightHistoryCard.tsx index 303c46b..4028ddf 100644 --- a/components/weight/WeightHistoryCard.tsx +++ b/components/weight/WeightHistoryCard.tsx @@ -11,13 +11,12 @@ import { LinearGradient } from 'expo-linear-gradient'; import React, { useEffect, useState } from 'react'; import { Dimensions, - Image, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, - View, + View } from 'react-native'; import Animated, { Extrapolation, @@ -201,9 +200,6 @@ export function WeightHistoryCard() { return ( - - - 体重记录 @@ -218,9 +214,6 @@ export function WeightHistoryCard() { return ( - - - 体重记录 @@ -254,9 +247,6 @@ export function WeightHistoryCard() { return ( - - - 体重记录 @@ -308,9 +298,6 @@ export function WeightHistoryCard() { return ( - - - 体重记录 { }); } -// 获取指定日期每小时步数数据 +// 获取指定日期每小时步数数据 (已弃用,使用 fetchHourlyStepSamples 替代) +// 保留此函数以防后向兼容需求 async function fetchHourlyStepCount(date: Date): Promise { - return new Promise((resolve) => { - const startOfDay = dayjs(date).startOf('day'); - 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); - }); - }); + // 直接调用更准确的样本数据获取函数 + return fetchHourlyStepSamples(date); } // 使用样本数据获取每小时步数 @@ -202,42 +174,48 @@ async function fetchHourlyStepSamples(date: Date): Promise { return new Promise((resolve) => { const startOfDay = dayjs(date).startOf('day'); const endOfDay = dayjs(date).endOf('day'); - - AppleHealthKit.getSamples( - { - startDate: startOfDay.toDate().toISOString(), - endDate: endOfDay.toDate().toISOString(), - type: 'StepCount', - }, + + // 使用正确的 getDailyStepCountSamples 方法,设置 period 为 60 分钟获取每小时数据 + const options = { + startDate: startOfDay.toDate().toISOString(), + endDate: endOfDay.toDate().toISOString(), + ascending: false, + period: 60, // 60分钟为一个时间段,获取每小时数据 + includeManuallyAdded: false, + }; + + AppleHealthKit.getDailyStepCountSamples( + options, (err: any, res: any[]) => { if (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); - + // 初始化24小时数据 - const hourlyData: HourlyStepData[] = Array.from({ length: 24 }, (_, i) => ({ - hour: i, - steps: 0 + const hourlyData: HourlyStepData[] = Array.from({ length: 24 }, (_, i) => ({ + hour: i, + steps: 0 })); - - // 将样本数据按小时分组并累加 + + // 将每小时的步数样本数据映射到对应的小时 res.forEach((sample: any) => { - if (sample && sample.startDate && sample.value) { + if (sample && sample.startDate && sample.value !== undefined) { const hour = dayjs(sample.startDate).hour(); 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); } );