import { Colors } from '@/constants/Colors';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useColorScheme } from '@/hooks/useColorScheme';
import {
BMI_CATEGORIES,
canCalculateBMI,
getBMIResult,
type BMIResult
} from '@/utils/bmi';
import { Ionicons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useState } from 'react';
import {
Dimensions,
Modal,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
import Toast from 'react-native-toast-message';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
interface BMICardProps {
weight?: number;
height?: number;
style?: any;
compact?: boolean;
}
export function BMICard({ weight, height, style, compact = false }: BMICardProps) {
const { pushIfAuthedElseLogin } = useAuthGuard();
const [showInfoModal, setShowInfoModal] = useState(false);
const canCalculate = canCalculateBMI(weight, height);
let bmiResult: BMIResult | null = null;
if (canCalculate && weight && height) {
try {
bmiResult = getBMIResult(weight, height);
} catch (error) {
console.warn('BMI 计算错误:', error);
}
}
const handleGoToProfile = () => {
Toast.show({
text1: '请先登录',
type: 'info',
});
pushIfAuthedElseLogin('/profile/edit');
};
const handleShowInfoModal = () => {
setShowInfoModal(true);
};
const handleHideInfoModal = () => {
setShowInfoModal(false);
};
const renderContent = () => {
if (!canCalculate) {
// 缺少数据的情况
return (
BMI
{!compact && (
)}
{compact ? (
{!weight && !height ? '完善身高体重' :
!weight ? '完善体重' : '完善身高'}
) : (
<>
{!weight && !height ? '请完善身高和体重信息' :
!weight ? '请完善体重信息' : '请完善身高信息'}
前往完善
>
)}
);
}
// 有完整数据的情况
return (
BMI
{!compact && (
)}
{compact ? (
{bmiResult?.value}
{bmiResult?.category.name}
) : (
<>
{bmiResult?.value}
{bmiResult?.category.name}
{bmiResult?.description}
{bmiResult?.category.encouragement}
>
)}
);
};
const colorScheme = useColorScheme();
const themeColors = Colors[colorScheme ?? 'light'];
return (
<>
{renderContent()}
{/* BMI 信息弹窗 */}
{/* 标题 */}
BMI 指数说明
{/* 介绍部分 */}
BMI(身体质量指数)是评估体重与身高关系的国际通用健康指标
计算公式:体重(kg) ÷ 身高²(m)
{/* BMI 分类标准 */}
BMI 分类标准
{BMI_CATEGORIES.map((category, index) => {
const colors = [
{ bg: '#FEF3C7', text: '#B45309', border: '#F59E0B' }, // 偏瘦
{ bg: '#E8F5E8', text: Colors.light.accentGreenDark, border: Colors.light.accentGreen }, // 正常
{ bg: '#FEF3C7', text: '#B45309', border: '#F59E0B' }, // 超重
{ bg: '#FEE2E2', text: '#B91C1C', border: '#EF4444' } // 肥胖
][index];
return (
{category.name}
{category.range}
{category.advice}
);
})}
{/* 健康建议 */}
健康建议
保持均衡饮食,控制热量摄入
每周至少150分钟中等强度运动
保证7-9小时充足睡眠
定期监测体重变化,及时调整
{/* 免责声明 */}
BMI 仅供参考,不能反映肌肉量、骨密度等指标。如有健康疑问,请咨询专业医生。
{/* 底部继续按钮 */}
继续
>
);
}
const styles = StyleSheet.create({
card: {
borderRadius: 22,
padding: 18,
overflow: 'hidden',
backgroundColor: '#FFFFFF',
},
cardHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 12,
},
titleRow: {
flexDirection: 'row',
alignItems: 'center',
},
iconSquare: {
width: 30,
height: 30,
borderRadius: 8,
backgroundColor: '#FFFFFF',
alignItems: 'center',
justifyContent: 'center',
marginRight: 10,
},
cardTitle: {
fontSize: 14,
fontWeight: '800',
color: '#192126',
},
infoButton: {
padding: 4,
},
// 缺少数据时的样式
incompleteContent: {
minHeight: 80,
backgroundColor: '#FFFFFF',
borderRadius: 22,
padding: 18,
margin: -18,
},
missingDataContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#FEF3C7',
borderRadius: 12,
padding: 12,
marginBottom: 12,
},
missingDataText: {
fontSize: 14,
color: '#B45309',
fontWeight: '600',
marginLeft: 8,
flex: 1,
},
completeButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ffffff',
borderRadius: 12,
paddingVertical: 12,
paddingHorizontal: 16,
},
completeButtonText: {
fontSize: 16,
fontWeight: '600',
color: '#6B7280',
marginRight: 4,
},
// 有完整数据时的样式
completeContent: {
minHeight: 80,
borderRadius: 22,
padding: 18,
margin: -18,
},
bmiValueContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
},
bmiValue: {
fontSize: 20,
fontWeight: '800',
marginRight: 12,
},
categoryBadge: {
paddingHorizontal: 12,
paddingVertical: 4,
borderRadius: 12,
},
categoryText: {
fontSize: 12,
fontWeight: '700',
},
bmiDescription: {
fontSize: 12,
fontWeight: '600',
marginBottom: 8,
},
encouragementText: {
fontSize: 10,
color: '#6B7280',
fontWeight: '500',
lineHeight: 18,
fontStyle: 'italic',
},
// 紧凑模式样式
compactIncompleteContent: {
minHeight: 80,
padding: 14,
margin: -14,
},
compactCompleteContent: {
minHeight: 80,
padding: 14,
margin: -14,
},
compactTitle: {
fontSize: 14,
},
compactMissingData: {
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
compactMissingText: {
fontSize: 12,
color: '#9AA3AE',
fontWeight: '500',
textAlign: 'center',
},
compactBMIContent: {
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
compactBMIValue: {
fontSize: 24,
fontWeight: '800',
marginBottom: 4,
},
compactBMICategory: {
fontSize: 12,
fontWeight: '700',
},
// 弹窗样式
modalBackdrop: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.6)',
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
modalContainer: {
width: screenWidth * 0.92,
backgroundColor: '#FFFFFF',
borderRadius: 24,
overflow: 'hidden',
elevation: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.3,
shadowRadius: 20,
},
modalHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: 20,
borderBottomWidth: 1,
borderBottomColor: '#F3F4F6',
backgroundColor: '#FAFAFA',
},
modalTitleContainer: {
flexDirection: 'row',
alignItems: 'center',
},
modalIconContainer: {
width: 40,
height: 40,
borderRadius: 12,
backgroundColor: '#EFF6FF',
alignItems: 'center',
justifyContent: 'center',
marginRight: 12,
},
modalTitle: {
fontSize: 20,
fontWeight: '800',
color: '#111827',
letterSpacing: -0.5,
},
closeButton: {
width: 36,
height: 36,
borderRadius: 18,
backgroundColor: '#F3F4F6',
alignItems: 'center',
justifyContent: 'center',
},
// 内容区域样式
modalContent: {
paddingHorizontal: 20,
paddingBottom: 24,
},
// 介绍部分
introSection: {
marginBottom: 20,
},
modalDescription: {
fontSize: 15,
color: '#374151',
lineHeight: 22,
textAlign: 'center',
marginBottom: 12,
},
formulaContainer: {
backgroundColor: '#F8FAFC',
borderRadius: 12,
padding: 16,
borderLeftWidth: 4,
borderLeftColor: '#3B82F6',
},
formulaText: {
fontSize: 15,
color: '#1F2937',
fontWeight: '600',
textAlign: 'center',
},
// 分类部分
categoriesSection: {
marginBottom: 18,
},
sectionTitle: {
fontSize: 16,
fontWeight: '800',
color: '#111827',
marginBottom: 12,
textAlign: 'center',
},
categoriesGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 8,
},
categoryCompact: {
flex: 1,
minWidth: '48%',
borderRadius: 12,
padding: 12,
marginBottom: 8,
},
categoryCompactHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 6,
},
categoryCompactName: {
fontSize: 14,
fontWeight: '700',
},
categoryCompactRange: {
fontSize: 12,
fontWeight: '600',
opacity: 0.8,
},
categoryCompactAdvice: {
fontSize: 11,
lineHeight: 16,
fontWeight: '500',
opacity: 0.9,
},
// 健康提示
healthTips: {
backgroundColor: '#F9FAFB',
borderRadius: 12,
padding: 14,
marginBottom: 16,
borderLeftWidth: 3,
borderLeftColor: '#EF4444',
},
tipsHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 6,
},
tipsTitle: {
fontSize: 14,
fontWeight: '700',
color: '#111827',
marginLeft: 6,
},
tipsContent: {
fontSize: 13,
color: '#374151',
lineHeight: 18,
},
// 免责声明紧凑版
disclaimerCompact: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#F9FAFB',
borderRadius: 8,
padding: 12,
marginTop: 4,
},
disclaimerCompactText: {
fontSize: 12,
color: '#6B7280',
fontStyle: 'italic',
lineHeight: 16,
marginLeft: 6,
flex: 1,
},
// 新样式 - 与StressAnalysisModal保持一致
newModalContainer: {
flex: 1,
},
newContent: {
flex: 1,
paddingHorizontal: 20,
},
newTitle: {
fontSize: 24,
fontWeight: '800',
color: '#111827',
textAlign: 'center',
marginTop: 20,
marginBottom: 32,
},
newIntroSection: {
marginBottom: 32,
},
newDescription: {
fontSize: 16,
color: '#374151',
lineHeight: 24,
textAlign: 'center',
marginBottom: 16,
},
newFormulaContainer: {
backgroundColor: '#F8FAFC',
borderRadius: 12,
padding: 16,
borderLeftWidth: 4,
borderLeftColor: '#3B82F6',
},
newFormulaText: {
fontSize: 15,
color: '#1F2937',
fontWeight: '600',
textAlign: 'center',
},
newSectionTitle: {
fontSize: 22,
fontWeight: '800',
color: '#111827',
marginBottom: 20,
},
newStatsCard: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 20,
marginBottom: 32,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.05,
shadowRadius: 8,
elevation: 2,
},
newStatItem: {
backgroundColor: '#FFFFFF',
borderRadius: 12,
padding: 16,
marginBottom: 12,
borderLeftWidth: 4,
},
newStatHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
newStatTitle: {
fontSize: 16,
fontWeight: '700',
},
newStatRange: {
fontSize: 14,
fontWeight: '600',
opacity: 0.8,
},
newStatAdvice: {
fontSize: 14,
lineHeight: 20,
fontWeight: '500',
opacity: 0.9,
},
newHealthTips: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 20,
marginBottom: 32,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.05,
shadowRadius: 8,
elevation: 2,
},
newTipsItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
newTipsText: {
fontSize: 15,
color: '#374151',
marginLeft: 12,
flex: 1,
},
newDisclaimer: {
flexDirection: 'row',
alignItems: 'flex-start',
backgroundColor: '#F9FAFB',
borderRadius: 12,
padding: 16,
marginBottom: 32,
},
newDisclaimerText: {
fontSize: 13,
color: '#6B7280',
lineHeight: 18,
marginLeft: 8,
flex: 1,
},
newBottomContainer: {
paddingHorizontal: 20,
paddingBottom: 34,
},
newContinueButton: {
borderRadius: 25,
overflow: 'hidden',
marginBottom: 8,
},
newButtonBackground: {
backgroundColor: Colors.light.accentGreen,
paddingVertical: 18,
alignItems: 'center',
justifyContent: 'center',
},
newButtonText: {
fontSize: 18,
fontWeight: '700',
color: '#192126',
},
newHomeIndicator: {
width: 134,
height: 5,
backgroundColor: '#000',
borderRadius: 3,
alignSelf: 'center',
},
});