# 07-个人中心页面(原型) ## 目标 实现 APP 端个人中心和健康档案管理页面原型。 --- ## UI 设计参考 > 参考设计稿:`files/ui/我的.png` --- ## 前置要求 - 导航配置完成 - 认证状态 Store 已创建 - 体质状态 Store 已创建 --- ## 实施步骤 ### 步骤 1:个人中心页面 创建 `src/screens/profile/ProfileHomeScreen.tsx`: ```typescript import React from 'react' import { View, ScrollView, StyleSheet, Alert, Linking } from 'react-native' import { Text, Avatar, Card, List, Button, Divider } from 'react-native-paper' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { useNavigation } from '@react-navigation/native' import { useAuthStore } from '../../stores/useAuthStore' import { useConstitutionStore } from '../../stores/useConstitutionStore' import { constitutionNames } from '../../mock/constitution' const ProfileHomeScreen = () => { const navigation = useNavigation() const { user, logout } = useAuthStore() const { result } = useConstitutionStore() const handleLogout = () => { Alert.alert('提示', '确定要退出登录吗?', [ { text: '取消', style: 'cancel' }, { text: '确定', style: 'destructive', onPress: () => logout() }, ]) } return ( {/* 用户信息卡片 */} {user?.nickname || '用户'} {user?.phone} {result && ( {constitutionNames[result.primaryType]} )} {/* 健康管理 */} ( )} right={(props) => } onPress={() => navigation.navigate('HealthRecord')} style={styles.listItem} /> ( )} right={(props) => } onPress={() => navigation.navigate('ConstitutionTab', { screen: 'ConstitutionResult' })} style={styles.listItem} /> ( )} right={(props) => } onPress={() => navigation.navigate('ChatTab')} style={styles.listItem} /> {/* 其他设置 */} ( )} right={(props) => } onPress={() => Linking.openURL('https://mall.example.com')} style={styles.listItem} /> ( )} right={(props) => } onPress={() => Alert.alert('关于我们', '健康AI助手 v1.0.0\n\n结合中医体质辨识理论,为您提供个性化健康建议。')} style={styles.listItem} /> {/* 退出登录 */} 版本 1.0.0(原型版) ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F3F4F6' }, headerCard: { backgroundColor: '#10B981', padding: 20, paddingTop: 40 }, userInfo: { flexDirection: 'row', alignItems: 'center' }, avatar: { backgroundColor: 'rgba(255,255,255,0.2)' }, userText: { marginLeft: 16 }, nickname: { fontSize: 20, fontWeight: '600', color: '#fff' }, phone: { fontSize: 14, color: 'rgba(255,255,255,0.8)', marginTop: 4 }, constitutionTag: { flexDirection: 'row', alignItems: 'center', marginTop: 8, backgroundColor: 'rgba(255,255,255,0.2)', paddingHorizontal: 8, paddingVertical: 4, borderRadius: 12 }, constitutionText: { fontSize: 12, color: '#fff', marginLeft: 4 }, menuCard: { margin: 16, marginBottom: 0, borderRadius: 12 }, menuTitle: { fontSize: 14, color: '#6B7280' }, listItem: { paddingVertical: 4 }, iconBg: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', marginLeft: 8 }, logoutButton: { margin: 16, borderColor: '#EF4444', borderRadius: 8 }, version: { textAlign: 'center', fontSize: 12, color: '#9CA3AF', marginBottom: 32 }, }) export default ProfileHomeScreen ``` ### 步骤 2:健康档案页面 创建 `src/screens/profile/HealthRecordScreen.tsx`: ```typescript import React from 'react' import { View, ScrollView, StyleSheet } from 'react-native' import { Text, Card, Chip } from 'react-native-paper' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { useAuthStore } from '../../stores/useAuthStore' import { useConstitutionStore } from '../../stores/useConstitutionStore' import { constitutionNames, constitutionDescriptions } from '../../mock/constitution' const HealthRecordScreen = () => { const { user } = useAuthStore() const { result } = useConstitutionStore() // 模拟健康档案数据 const mockProfile = { basicInfo: { name: user?.nickname || '用户', gender: '男', age: 45, height: 170, weight: 68, bloodType: 'A型', }, medicalHistory: ['高血压', '轻度脂肪肝'], allergyRecords: ['青霉素'], lifestyleInfo: { sleepTime: '23:00', wakeTime: '07:00', exerciseFrequency: '每周2-3次', }, } const bmi = (mockProfile.basicInfo.weight / Math.pow(mockProfile.basicInfo.height / 100, 2)).toFixed(1) return ( {/* 基础信息 */} } /> {/* 体质信息 */} } /> {result ? ( {constitutionNames[result.primaryType]} {constitutionDescriptions[result.primaryType].description} 测评时间:{new Date(result.assessedAt).toLocaleDateString()} ) : ( 暂无体质测评记录 )} {/* 既往病史 */} } /> {mockProfile.medicalHistory.length > 0 ? ( {mockProfile.medicalHistory.map((item, index) => ( {item} ))} ) : ( 暂无病史记录 )} {/* 过敏信息 */} } /> {mockProfile.allergyRecords.length > 0 ? ( {mockProfile.allergyRecords.map((item, index) => ( {item} ))} ) : ( 暂无过敏信息 )} {/* 生活习惯 */} } /> 以上为模拟数据,后续将支持编辑和同步 ) } const InfoItem = ({ label, value }: { label: string; value: string }) => ( {label} {value} ) const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F3F4F6', padding: 16 }, card: { borderRadius: 12, marginBottom: 16 }, infoGrid: { flexDirection: 'row', flexWrap: 'wrap' }, infoItem: { width: '50%', marginBottom: 16 }, infoLabel: { fontSize: 12, color: '#9CA3AF', marginBottom: 4 }, infoValue: { fontSize: 15, color: '#1F2937' }, constitutionInfo: { alignItems: 'center' }, constitutionChip: { backgroundColor: '#10B981' }, constitutionChipText: { color: '#fff', fontSize: 16 }, constitutionDesc: { marginTop: 12, fontSize: 14, color: '#6B7280', textAlign: 'center', lineHeight: 22 }, assessedTime: { marginTop: 8, fontSize: 12, color: '#9CA3AF' }, tagList: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 }, tag: { backgroundColor: '#ECFDF5' }, allergyTag: { backgroundColor: '#FEE2E2' }, emptyText: { color: '#9CA3AF', textAlign: 'center', paddingVertical: 16 }, note: { fontSize: 12, color: '#9CA3AF', textAlign: 'center', marginBottom: 24 }, }) export default HealthRecordScreen ``` --- ## 验收标准 - [ ] 个人中心页面正常显示 - [ ] 用户信息显示正确 - [ ] 体质标签显示(如已测评) - [ ] 菜单导航正常 - [ ] 健康档案数据显示 - [ ] 退出登录功能正常 --- ## 预计耗时 25-30 分钟 --- ## 完成 恭喜!APP 原型开发任务全部完成! --- ## 下一步 进入 `03-Web原型开发/01-项目初始化和模拟数据.md`