feat: 更新 CLAUDE.md 文件及多个组件以优化用户体验和功能
- 更新 CLAUDE.md 文件,重构架构部分,增加认证和数据层的描述 - 在 GoalsScreen 中新增目标模板选择功能,支持用户选择和创建目标 - 在 CreateGoalModal 中添加初始数据支持,优化目标创建体验 - 新增 GoalTemplateModal 组件,提供目标模板选择界面 - 更新 NotificationHelpers,支持构建深度链接以便于导航 - 在 CoachScreen 中处理路由参数,增强用户交互体验 - 更新多个组件的样式和逻辑,提升整体用户体验 - 删除不再使用的中文回复规则文档
This commit is contained in:
570
utils/health.ts
570
utils/health.ts
@@ -2,6 +2,12 @@ import dayjs from 'dayjs';
|
||||
import type { HealthActivitySummary, HealthKitPermissions } from 'react-native-health';
|
||||
import AppleHealthKit from 'react-native-health';
|
||||
|
||||
type HealthDataOptions = {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
};
|
||||
|
||||
|
||||
const PERMISSIONS: HealthKitPermissions = {
|
||||
permissions: {
|
||||
read: [
|
||||
@@ -61,271 +67,163 @@ export async function ensureHealthPermissions(): Promise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchHealthDataForDate(date: Date): Promise<TodayHealthData> {
|
||||
console.log('开始获取指定日期健康数据...', date);
|
||||
|
||||
const start = dayjs(date).startOf('day').toDate();
|
||||
const end = dayjs(date).endOf('day').toDate();
|
||||
|
||||
const options = {
|
||||
startDate: start.toISOString(),
|
||||
endDate: end.toISOString()
|
||||
} as any;
|
||||
|
||||
const activitySummaryOptions = {
|
||||
startDate: start.toISOString(),
|
||||
endDate: end.toISOString()
|
||||
};
|
||||
|
||||
console.log('查询选项:', options);
|
||||
|
||||
// 并行获取所有健康数据,包括ActivitySummary、血氧饱和度和心率
|
||||
const [steps, calories, basalMetabolism, sleepDuration, hrv, activitySummary, oxygenSaturation, heartRate] = await Promise.all([
|
||||
// 获取步数
|
||||
new Promise<number>((resolve) => {
|
||||
AppleHealthKit.getStepCount({
|
||||
date: dayjs(date).toISOString()
|
||||
}, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取步数失败:', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res) {
|
||||
console.warn('步数数据为空');
|
||||
return resolve(0);
|
||||
}
|
||||
console.log('步数数据:', res);
|
||||
resolve(res.value || 0);
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取消耗卡路里
|
||||
new Promise<number>((resolve) => {
|
||||
AppleHealthKit.getActiveEnergyBurned(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取消耗卡路里失败:', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('卡路里数据为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
console.log('卡路里数据:', res);
|
||||
// 求和该日内的所有记录(单位:千卡)
|
||||
const total = res.reduce((acc: number, item: any) => acc + (item?.value || 0), 0);
|
||||
resolve(total);
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取基础代谢率
|
||||
new Promise<number>((resolve) => {
|
||||
AppleHealthKit.getBasalEnergyBurned(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取基础代谢失败:', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('基础代谢数据为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
console.log('基础代谢数据:', res);
|
||||
// 求和该日内的所有记录(单位:千卡)
|
||||
const total = res.reduce((acc: number, item: any) => acc + (item?.value || 0), 0);
|
||||
resolve(total);
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取睡眠时长
|
||||
new Promise<number>((resolve) => {
|
||||
AppleHealthKit.getSleepSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取睡眠数据失败:', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('睡眠数据为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
console.log('睡眠数据:', res);
|
||||
|
||||
// 计算总睡眠时间(单位:分钟)
|
||||
let totalSleepDuration = 0;
|
||||
res.forEach((sample: any) => {
|
||||
if (sample && sample.startDate && sample.endDate) {
|
||||
const startTime = new Date(sample.startDate).getTime();
|
||||
const endTime = new Date(sample.endDate).getTime();
|
||||
const durationMinutes = (endTime - startTime) / (1000 * 60);
|
||||
totalSleepDuration += durationMinutes;
|
||||
}
|
||||
});
|
||||
|
||||
resolve(totalSleepDuration);
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取HRV数据
|
||||
new Promise<number | null>((resolve) => {
|
||||
AppleHealthKit.getHeartRateVariabilitySamples(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取HRV数据失败:', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('HRV数据为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
console.log('HRV数据:', res);
|
||||
|
||||
// 获取最新的HRV值
|
||||
const latestHrv = res[res.length - 1];
|
||||
if (latestHrv && latestHrv.value) {
|
||||
resolve(Math.round(latestHrv.value * 1000));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取ActivitySummary数据(健身圆环数据)
|
||||
new Promise<HealthActivitySummary | null>((resolve) => {
|
||||
AppleHealthKit.getActivitySummary(
|
||||
activitySummaryOptions,
|
||||
(err: Object, results: HealthActivitySummary[]) => {
|
||||
if (err) {
|
||||
console.error('获取ActivitySummary失败:', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!results || results.length === 0) {
|
||||
console.warn('ActivitySummary数据为空');
|
||||
return resolve(null);
|
||||
}
|
||||
console.log('ActivitySummary数据:', results[0]);
|
||||
resolve(results[0]);
|
||||
},
|
||||
);
|
||||
}),
|
||||
|
||||
// 获取血氧饱和度数据
|
||||
new Promise<number | null>((resolve) => {
|
||||
AppleHealthKit.getOxygenSaturationSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取血氧饱和度失败:', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('血氧饱和度数据为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
console.log('血氧饱和度数据:', res);
|
||||
// 获取最新的血氧饱和度值
|
||||
const latestOxygen = res[res.length - 1];
|
||||
if (latestOxygen && latestOxygen.value !== undefined && latestOxygen.value !== null) {
|
||||
let value = Number(latestOxygen.value);
|
||||
|
||||
// 检查数据格式:如果值小于1,可能是小数形式(0.0-1.0),需要转换为百分比
|
||||
if (value > 0 && value < 1) {
|
||||
value = value * 100;
|
||||
console.log('血氧饱和度数据从小数转换为百分比:', latestOxygen.value, '->', value);
|
||||
}
|
||||
|
||||
// 血氧饱和度通常在0-100之间,验证数据有效性
|
||||
if (value >= 0 && value <= 100) {
|
||||
resolve(Number(value.toFixed(1)));
|
||||
} else {
|
||||
console.warn('血氧饱和度数据异常:', value);
|
||||
resolve(null);
|
||||
}
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
}),
|
||||
|
||||
// 获取心率数据
|
||||
new Promise<number | null>((resolve) => {
|
||||
AppleHealthKit.getHeartRateSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取心率失败:', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('心率数据为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
console.log('心率数据:', res);
|
||||
// 获取最新的心率值
|
||||
const latestHeartRate = res[res.length - 1];
|
||||
if (latestHeartRate && latestHeartRate.value !== undefined && latestHeartRate.value !== null) {
|
||||
// 心率通常在30-200之间,验证数据有效性
|
||||
const value = Number(latestHeartRate.value);
|
||||
if (value >= 30 && value <= 200) {
|
||||
resolve(Math.round(value));
|
||||
} else {
|
||||
console.warn('心率数据异常:', value);
|
||||
resolve(null);
|
||||
}
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
})
|
||||
]);
|
||||
|
||||
console.log('指定日期健康数据获取完成:', { steps, calories, basalMetabolism, sleepDuration, hrv, activitySummary, oxygenSaturation, heartRate });
|
||||
|
||||
// 日期工具函数
|
||||
function createDateRange(date: Date): HealthDataOptions {
|
||||
return {
|
||||
steps,
|
||||
activeEnergyBurned: calories,
|
||||
basalEnergyBurned: basalMetabolism,
|
||||
sleepDuration,
|
||||
hrv,
|
||||
// 健身圆环数据
|
||||
activeCalories: Math.round(activitySummary?.activeEnergyBurned || 0),
|
||||
activeCaloriesGoal: Math.round(activitySummary?.activeEnergyBurnedGoal || 350),
|
||||
exerciseMinutes: Math.round(activitySummary?.appleExerciseTime || 0),
|
||||
exerciseMinutesGoal: Math.round(activitySummary?.appleExerciseTimeGoal || 30),
|
||||
standHours: Math.round(activitySummary?.appleStandHours || 0),
|
||||
standHoursGoal: Math.round(activitySummary?.appleStandHoursGoal || 12),
|
||||
// 血氧饱和度和心率数据
|
||||
oxygenSaturation,
|
||||
heartRate
|
||||
startDate: dayjs(date).startOf('day').toDate().toISOString(),
|
||||
endDate: dayjs(date).endOf('day').toDate().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchTodayHealthData(): Promise<TodayHealthData> {
|
||||
return fetchHealthDataForDate(new Date());
|
||||
// 睡眠时长计算
|
||||
function calculateSleepDuration(samples: any[]): number {
|
||||
return samples.reduce((total, sample) => {
|
||||
if (sample && sample.startDate && sample.endDate) {
|
||||
const startTime = dayjs(sample.startDate).valueOf();
|
||||
const endTime = dayjs(sample.endDate).valueOf();
|
||||
const durationMinutes = (endTime - startTime) / (1000 * 60);
|
||||
return total + durationMinutes;
|
||||
}
|
||||
return total;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 新增:专门获取HRV数据的函数
|
||||
export async function fetchHRVForDate(date: Date): Promise<number | null> {
|
||||
console.log('开始获取指定日期HRV数据...', date);
|
||||
// 通用错误处理
|
||||
function logError(operation: string, error: any): void {
|
||||
console.error(`获取${operation}失败:`, error);
|
||||
}
|
||||
|
||||
const start = new Date(date);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
const end = new Date(date);
|
||||
end.setHours(23, 59, 59, 999);
|
||||
function logWarning(operation: string, message: string): void {
|
||||
console.warn(`${operation}数据${message}`);
|
||||
}
|
||||
|
||||
const options = {
|
||||
startDate: start.toISOString(),
|
||||
endDate: end.toISOString()
|
||||
} as any;
|
||||
function logSuccess(operation: string, data: any): void {
|
||||
console.log(`${operation}数据:`, data);
|
||||
}
|
||||
|
||||
return new Promise<number | null>((resolve) => {
|
||||
// 数值验证和转换
|
||||
function validateOxygenSaturation(value: any): number | null {
|
||||
if (value === undefined || value === null) return null;
|
||||
|
||||
let numValue = Number(value);
|
||||
|
||||
// 如果值小于1,可能是小数形式(0.0-1.0),需要转换为百分比
|
||||
if (numValue > 0 && numValue < 1) {
|
||||
numValue = numValue * 100;
|
||||
}
|
||||
|
||||
// 血氧饱和度通常在0-100之间,验证数据有效性
|
||||
if (numValue >= 0 && numValue <= 100) {
|
||||
return Number(numValue.toFixed(1));
|
||||
}
|
||||
|
||||
console.warn('血氧饱和度数据异常:', numValue);
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateHeartRate(value: any): number | null {
|
||||
if (value === undefined || value === null) return null;
|
||||
|
||||
const numValue = Number(value);
|
||||
|
||||
// 心率通常在30-200之间,验证数据有效性
|
||||
if (numValue >= 30 && numValue <= 200) {
|
||||
return Math.round(numValue);
|
||||
}
|
||||
|
||||
console.warn('心率数据异常:', numValue);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 健康数据获取函数
|
||||
async function fetchStepCount(date: Date): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getStepCount({
|
||||
date: dayjs(date).toDate().toISOString()
|
||||
}, (err, res) => {
|
||||
if (err) {
|
||||
logError('步数', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res) {
|
||||
logWarning('步数', '为空');
|
||||
return resolve(0);
|
||||
}
|
||||
logSuccess('步数', res);
|
||||
resolve(res.value || 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchActiveEnergyBurned(options: HealthDataOptions): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getActiveEnergyBurned(options, (err, res) => {
|
||||
if (err) {
|
||||
logError('消耗卡路里', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
logWarning('卡路里', '为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
logSuccess('卡路里', res);
|
||||
const total = res.reduce((acc: number, item: any) => acc + (item?.value || 0), 0);
|
||||
resolve(total);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchBasalEnergyBurned(options: HealthDataOptions): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getBasalEnergyBurned(options, (err, res) => {
|
||||
if (err) {
|
||||
logError('基础代谢', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
logWarning('基础代谢', '为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
logSuccess('基础代谢', res);
|
||||
const total = res.reduce((acc: number, item: any) => acc + (item?.value || 0), 0);
|
||||
resolve(total);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchSleepDuration(options: HealthDataOptions): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getSleepSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
logError('睡眠数据', err);
|
||||
return resolve(0);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
logWarning('睡眠', '为空或格式错误');
|
||||
return resolve(0);
|
||||
}
|
||||
logSuccess('睡眠', res);
|
||||
resolve(calculateSleepDuration(res));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchHeartRateVariability(options: HealthDataOptions): Promise<number | null> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getHeartRateVariabilitySamples(options, (err, res) => {
|
||||
if (err) {
|
||||
console.error('获取HRV数据失败:', err);
|
||||
logError('HRV数据', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
console.warn('HRV数据为空或格式错误');
|
||||
logWarning('HRV', '为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
console.log('HRV数据:', res);
|
||||
logSuccess('HRV', res);
|
||||
|
||||
// 获取最新的HRV值
|
||||
const latestHrv = res[res.length - 1];
|
||||
if (latestHrv && latestHrv.value) {
|
||||
resolve(latestHrv.value);
|
||||
resolve(Math.round(latestHrv.value * 1000));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
@@ -333,9 +231,155 @@ export async function fetchHRVForDate(date: Date): Promise<number | null> {
|
||||
});
|
||||
}
|
||||
|
||||
// 新增:获取今日HRV数据
|
||||
async function fetchActivitySummary(options: HealthDataOptions): Promise<HealthActivitySummary | null> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getActivitySummary(
|
||||
options,
|
||||
(err: Object, results: HealthActivitySummary[]) => {
|
||||
if (err) {
|
||||
logError('ActivitySummary', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!results || results.length === 0) {
|
||||
logWarning('ActivitySummary', '为空');
|
||||
return resolve(null);
|
||||
}
|
||||
logSuccess('ActivitySummary', results[0]);
|
||||
resolve(results[0]);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchOxygenSaturation(options: HealthDataOptions): Promise<number | null> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getOxygenSaturationSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
logError('血氧饱和度', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
logWarning('血氧饱和度', '为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
logSuccess('血氧饱和度', res);
|
||||
|
||||
const latestOxygen = res[res.length - 1];
|
||||
return resolve(validateOxygenSaturation(latestOxygen?.value));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchHeartRate(options: HealthDataOptions): Promise<number | null> {
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getHeartRateSamples(options, (err, res) => {
|
||||
if (err) {
|
||||
logError('心率', err);
|
||||
return resolve(null);
|
||||
}
|
||||
if (!res || !Array.isArray(res) || res.length === 0) {
|
||||
logWarning('心率', '为空或格式错误');
|
||||
return resolve(null);
|
||||
}
|
||||
logSuccess('心率', res);
|
||||
|
||||
const latestHeartRate = res[res.length - 1];
|
||||
return resolve(validateHeartRate(latestHeartRate?.value));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 默认健康数据
|
||||
function getDefaultHealthData(): TodayHealthData {
|
||||
return {
|
||||
steps: 0,
|
||||
activeEnergyBurned: 0,
|
||||
basalEnergyBurned: 0,
|
||||
sleepDuration: 0,
|
||||
hrv: null,
|
||||
activeCalories: 0,
|
||||
activeCaloriesGoal: 350,
|
||||
exerciseMinutes: 0,
|
||||
exerciseMinutesGoal: 30,
|
||||
standHours: 0,
|
||||
standHoursGoal: 12,
|
||||
oxygenSaturation: null,
|
||||
heartRate: null
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchHealthDataForDate(date: Date): Promise<TodayHealthData> {
|
||||
try {
|
||||
console.log('开始获取指定日期健康数据...', date);
|
||||
|
||||
const options = createDateRange(date);
|
||||
console.log('查询选项:', options);
|
||||
|
||||
// 并行获取所有健康数据
|
||||
const [
|
||||
steps,
|
||||
activeEnergyBurned,
|
||||
basalEnergyBurned,
|
||||
sleepDuration,
|
||||
hrv,
|
||||
activitySummary,
|
||||
oxygenSaturation,
|
||||
heartRate
|
||||
] = await Promise.all([
|
||||
fetchStepCount(date),
|
||||
fetchActiveEnergyBurned(options),
|
||||
fetchBasalEnergyBurned(options),
|
||||
fetchSleepDuration(options),
|
||||
fetchHeartRateVariability(options),
|
||||
fetchActivitySummary(options),
|
||||
fetchOxygenSaturation(options),
|
||||
fetchHeartRate(options)
|
||||
]);
|
||||
|
||||
console.log('指定日期健康数据获取完成:', {
|
||||
steps,
|
||||
activeEnergyBurned,
|
||||
basalEnergyBurned,
|
||||
sleepDuration,
|
||||
hrv,
|
||||
activitySummary,
|
||||
oxygenSaturation,
|
||||
heartRate
|
||||
});
|
||||
|
||||
return {
|
||||
steps,
|
||||
activeEnergyBurned,
|
||||
basalEnergyBurned,
|
||||
sleepDuration,
|
||||
hrv,
|
||||
activeCalories: Math.round(activitySummary?.activeEnergyBurned || 0),
|
||||
activeCaloriesGoal: Math.round(activitySummary?.activeEnergyBurnedGoal || 350),
|
||||
exerciseMinutes: Math.round(activitySummary?.appleExerciseTime || 0),
|
||||
exerciseMinutesGoal: Math.round(activitySummary?.appleExerciseTimeGoal || 30),
|
||||
standHours: Math.round(activitySummary?.appleStandHours || 0),
|
||||
standHoursGoal: Math.round(activitySummary?.appleStandHoursGoal || 12),
|
||||
oxygenSaturation,
|
||||
heartRate
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取指定日期健康数据失败:', error);
|
||||
return getDefaultHealthData();
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchTodayHealthData(): Promise<TodayHealthData> {
|
||||
return fetchHealthDataForDate(dayjs().toDate());
|
||||
}
|
||||
|
||||
export async function fetchHRVForDate(date: Date): Promise<number | null> {
|
||||
console.log('开始获取指定日期HRV数据...', date);
|
||||
const options = createDateRange(date);
|
||||
return fetchHeartRateVariability(options);
|
||||
}
|
||||
|
||||
export async function fetchTodayHRV(): Promise<number | null> {
|
||||
return fetchHRVForDate(new Date());
|
||||
return fetchHRVForDate(dayjs().toDate());
|
||||
}
|
||||
|
||||
// 更新healthkit中的体重
|
||||
@@ -354,17 +398,10 @@ export async function updateWeight(weight: number) {
|
||||
});
|
||||
}
|
||||
|
||||
// 新增:测试血氧饱和度数据获取
|
||||
export async function testOxygenSaturationData(date: Date = new Date()): Promise<void> {
|
||||
export async function testOxygenSaturationData(date: Date = dayjs().toDate()): Promise<void> {
|
||||
console.log('=== 开始测试血氧饱和度数据获取 ===');
|
||||
|
||||
const start = dayjs(date).startOf('day').toDate();
|
||||
const end = dayjs(date).endOf('day').toDate();
|
||||
|
||||
const options = {
|
||||
startDate: start.toISOString(),
|
||||
endDate: end.toISOString()
|
||||
} as any;
|
||||
const options = createDateRange(date);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
AppleHealthKit.getOxygenSaturationSamples(options, (err, res) => {
|
||||
@@ -392,23 +429,14 @@ export async function testOxygenSaturationData(date: Date = new Date()): Promise
|
||||
});
|
||||
});
|
||||
|
||||
// 获取最新的血氧饱和度值
|
||||
// 获取最新的血氧饱和度值并验证
|
||||
const latestOxygen = res[res.length - 1];
|
||||
if (latestOxygen && latestOxygen.value !== undefined && latestOxygen.value !== null) {
|
||||
let value = Number(latestOxygen.value);
|
||||
if (latestOxygen?.value !== undefined && latestOxygen?.value !== null) {
|
||||
const processedValue = validateOxygenSaturation(latestOxygen.value);
|
||||
|
||||
console.log('处理前的值:', latestOxygen.value);
|
||||
console.log('转换为数字后的值:', value);
|
||||
|
||||
// 检查数据格式:如果值小于1,可能是小数形式(0.0-1.0),需要转换为百分比
|
||||
if (value > 0 && value < 1) {
|
||||
const originalValue = value;
|
||||
value = value * 100;
|
||||
console.log('血氧饱和度数据从小数转换为百分比:', originalValue, '->', value);
|
||||
}
|
||||
|
||||
console.log('最终处理后的值:', value);
|
||||
console.log('数据有效性检查:', value >= 0 && value <= 100 ? '有效' : '无效');
|
||||
console.log('最终处理后的值:', processedValue);
|
||||
console.log('数据有效性检查:', processedValue !== null ? '有效' : '无效');
|
||||
}
|
||||
|
||||
console.log('=== 血氧饱和度数据测试完成 ===');
|
||||
|
||||
Reference in New Issue
Block a user