import { fetchHRVForDate } from '@/utils/health'; import dayjs from 'dayjs'; import { Image } from 'expo-image'; import { LinearGradient } from 'expo-linear-gradient'; import React, { useEffect, useState } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { StressAnalysisModal } from './StressAnalysisModal'; interface StressMeterProps { curDate: Date } export function StressMeter({ curDate }: StressMeterProps) { // 格式化更新时间显示 const formatUpdateTime = (date: Date): string => { const now = dayjs(); const updateTime = dayjs(date); const diffMinutes = now.diff(updateTime, 'minute'); const diffHours = now.diff(updateTime, 'hour'); const diffDays = now.diff(updateTime, 'day'); if (diffMinutes < 1) { return '刚刚更新'; } else if (diffMinutes < 60) { return `${diffMinutes}分钟前更新`; } else if (diffHours < 24) { return `${diffHours}小时前更新`; } else if (diffDays < 7) { return `${diffDays}天前更新`; } else { return updateTime.format('MM-DD HH:mm'); } }; // 将HRV值转换为压力指数(0-100) // HRV值范围:30-110ms,映射到压力指数100-0 // HRV值越高,压力越小;HRV值越低,压力越大 const convertHrvToStressIndex = (hrv: number | null): number | null => { if (hrv === null || hrv === 0) return null; // HRV 范围: 30-110ms,对应压力指数: 100-0 // 线性映射: stressIndex = 100 - ((hrv - 30) / (110 - 30)) * 100 const normalizedHrv = Math.max(30, Math.min(130, hrv)); const stressIndex = 100 - ((normalizedHrv - 30) / (130 - 30)) * 100; return Math.round(stressIndex); }; const [hrvValue, setHrvValue] = useState(0) useEffect(() => { getHrvData() }, [curDate]) const getHrvData = async () => { try { const data = await fetchHRVForDate(curDate) if (data) { setHrvValue(data) } } catch (error) { } } // 使用传入的 hrvValue 进行转换 const stressIndex = convertHrvToStressIndex(hrvValue); // 调试信息 console.log('StressMeter 调试:', { hrvValue, stressIndex, progressPercentage: stressIndex !== null ? Math.max(0, Math.min(100, stressIndex)) : 0 }); // 计算进度条位置(0-100%) // 压力指数越高,进度条越满(红色区域越多) const progressPercentage = stressIndex !== null ? Math.max(0, Math.min(100, stressIndex)) : 0; // 在组件内部添加状态 const [showStressModal, setShowStressModal] = useState(false); // 修改 onPress 处理函数 const handlePress = () => { setShowStressModal(true); }; return ( <> {/* 头部区域 */} 压力 {/* {updateTime && ( {formatUpdateTime(updateTime)} )} */} {/* 数值显示区域 */} {hrvValue || '--'} ms {/* 进度条区域 */} {/* 渐变背景进度条 */} {/* 白色圆形指示器 */} {/* 压力分析浮窗 */} setShowStressModal(false)} hrvValue={hrvValue} // updateTime={updateTime || new Date()} /> ); } const styles = StyleSheet.create({ container: { flex: 1, shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.08, shadowRadius: 8, elevation: 3, position: 'relative', overflow: 'hidden', }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8, }, leftSection: { flexDirection: 'row', alignItems: 'center', }, iconContainer: { width: 24, height: 24, borderRadius: 6, backgroundColor: '#EBF4FF', alignItems: 'center', justifyContent: 'center', marginRight: 6, }, titleIcon: { width: 16, height: 16, marginRight: 6, resizeMode: 'contain', }, title: { fontSize: 14, color: '#192126', fontWeight: '600' }, valueSection: { flexDirection: 'row', alignItems: 'baseline', marginBottom: 12, }, value: { fontSize: 20, fontWeight: '600', color: '#192126', lineHeight: 20, marginTop: 2, }, unit: { fontSize: 12, fontWeight: '500', color: '#9AA3AE', marginLeft: 4, }, progressContainer: { height: 6, }, progressTrack: { height: 6, borderRadius: 4, position: 'relative', overflow: 'visible', }, progressBar: { height: '100%', borderRadius: 4, overflow: 'hidden', }, gradientBar: { height: '100%', borderRadius: 4, }, indicator: { position: 'absolute', top: -2, width: 10, height: 10, borderRadius: 8, backgroundColor: '#FFFFFF', shadowColor: '#000', shadowOffset: { width: 0, height: 1, }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, borderWidth: 1.5, borderColor: '#E5E7EB', }, updateTime: { fontSize: 10, color: '#9AA3AE', textAlign: 'right', marginTop: 2, }, headerUpdateTime: { fontSize: 11, color: '#9AA3AE', fontWeight: '500', }, });