import 'package:flutter/material.dart'; import '../../core/app_theme.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/navigation_provider.dart'; import '../../providers/data_providers.dart'; import '../../services/health_service.dart'; class ProfileDetailPage extends ConsumerWidget { const ProfileDetailPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final latestHealth = ref.watch(latestHealthProvider); final userService = ref.watch(userServiceProvider); return Scaffold( backgroundColor: AppTheme.bg, appBar: AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)), title: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.person_outline, size: 23, color: Colors.grey[600]), const SizedBox(width: 6), Text('健康档案', style: TextStyle(color: Colors.grey[800], fontWeight: FontWeight.w600)), ]), centerTitle: true, ), body: SafeArea(child: SingleChildScrollView(padding: const EdgeInsets.all(16), child: Column(children: [_buildUserCard(userService), const SizedBox(height: 16), _buildHealthOverview(latestHealth), const SizedBox(height: 16), _buildHistoryList(), const SizedBox(height: 16), SizedBox(width: double.infinity, height: 48, child: OutlinedButton(onPressed: () => pushRoute(ref, 'settings'), style: OutlinedButton.styleFrom(foregroundColor: AppTheme.primary, side: const BorderSide(color: AppTheme.primary), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24))), child: const Text('退出档案')))]))), ); } Widget _buildUserCard(UserService userService) { return FutureBuilder?>( future: userService.getProfile(), builder: (ctx, snap) { final p = snap.data; final name = (p != null && p['name'] != null && (p['name'] as String).isNotEmpty) ? p['name'] : '用户'; final gender = p?['gender'] ?? ''; final birth = p?['birthDate'] ?? ''; final ageStr = birth.toString().isNotEmpty ? _calcAge(birth.toString()) : ''; final info = [if (ageStr.isNotEmpty) ageStr, if (gender.toString().isNotEmpty) gender].join(' · '); return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: AppTheme.primary.withAlpha(10), blurRadius: 8, offset: const Offset(0, 2))]), child: Row(children: [ CircleAvatar(radius: 32, backgroundColor: AppTheme.primaryLight, child: Text(name.toString().isNotEmpty ? name.toString()[0] : '?', style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold, color: AppTheme.primary))), const SizedBox(width: 16), Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(name.toString(), style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold, color: Color(0xFF1A1A1A))), if (info.isNotEmpty) const SizedBox(height: 4), if (info.isNotEmpty) Text(info, style: TextStyle(fontSize: 17, color: Colors.grey[500])), ])), Icon(Icons.chevron_right, size: 28, color: Colors.grey[400]), ]), ); }, ); } String _calcAge(String birthDate) { final d = DateTime.tryParse(birthDate); if (d == null) return ''; final now = DateTime.now(); var age = now.year - d.year; if (now.month < d.month || (now.month == d.month && now.day < d.day)) age--; return '$age岁'; } Widget _buildHealthOverview(AsyncValue> healthData) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: AppTheme.primary.withAlpha(10), blurRadius: 8, offset: const Offset(0, 2))]), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('健康概览', style: TextStyle(fontSize: 21, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), const SizedBox(height: 4), Text('(最近测量)', style: TextStyle(fontSize: 16, color: Colors.grey[500])), const SizedBox(height: 16), healthData.when(data: (data) => _buildMetricsList(data), loading: () => const Center(child: Padding(padding: EdgeInsets.all(24), child: CircularProgressIndicator(strokeWidth: 2, color: AppTheme.primary))), error: (_, e) => _buildMetricsEmpty()), ]), ); } Widget _buildMetricsList(Map data) { return Column(children: [_metricRow(Icons.favorite, '血压', _formatBP(data['BloodPressure'])), const Divider(), _metricRow(Icons.monitor_heart, '心率', _formatMetric(data['HeartRate'], '次/分')), const Divider(), _metricRow(Icons.bloodtype, '血糖', _formatMetric(data['Glucose'], 'mmol/L')), const Divider(), _metricRow(Icons.air, '血氧', _formatMetric(data['SpO2'], '%')), const Divider(), _metricRow(Icons.monitor_weight, '体重', _formatMetric(data['Weight'], 'kg'))]); } Widget _buildMetricsEmpty() { return Column(children: [_metricRow(Icons.favorite, '血压', '--/--'), const Divider(), _metricRow(Icons.monitor_heart, '心率', '-- 次/分'), const Divider(), _metricRow(Icons.bloodtype, '血糖', '-- mmol/L'), const Divider(), _metricRow(Icons.air, '血氧', '-- %'), const Divider(), _metricRow(Icons.monitor_weight, '体重', '-- kg')]); } String _formatBP(dynamic bp) { if (bp is Map) { final s = bp['systolic']; final d = bp['diastolic']; if (s != null && d != null) return '$s/$d'; } return '--/--'; } String _formatMetric(dynamic val, String unit) { if (val is Map) { final v = val['value']; if (v != null) return '$v$unit'; } return '-- $unit'; } Widget _metricRow(IconData icon, String label, String value) => InkWell(onTap: () {}, borderRadius: BorderRadius.circular(12), child: Padding(padding: const EdgeInsets.symmetric(vertical: 14), child: Row(children: [Container(width: 40, height: 40, decoration: BoxDecoration(color: AppTheme.primaryLight, borderRadius: BorderRadius.circular(10)), child: Icon(icon, size: 21, color: AppTheme.primary)), const SizedBox(width: 12), Expanded(child: Text(label, style: const TextStyle(fontSize: 18, color: Color(0xFF333333)))), Text(value, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), const SizedBox(width: 8), Icon(Icons.chevron_right, size: 21, color: Colors.grey[400])]))); Widget _buildHistoryList() { final items = [{'date': '05-31', 'label': '血压 · 餐前', 'value': '128/82', 'status': 'normal'}, {'date': '05-30', 'label': '血压 · 餐后', 'value': '135/85', 'status': 'warning'}, {'date': '05-29', 'label': '血压 · 餐前', 'value': '122/78', 'status': 'normal'}, {'date': '05-28', 'label': '血压 · 餐前', 'value': '118/76', 'status': 'normal'}, {'date': '05-27', 'label': '血糖 · 空腹', 'value': '5.6', 'status': 'normal'}, {'date': '05-26', 'label': '血压 · 餐前', 'value': '120/80', 'status': 'normal'}]; return Container(decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: AppTheme.primary.withAlpha(10), blurRadius: 8, offset: const Offset(0, 2))]), child: Column(children: [Container(padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), child: Row(children: [const Text('历史记录', style: TextStyle(fontSize: 21, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), const Spacer(), Text('查看更多', style: TextStyle(fontSize: 16, color: AppTheme.primary))])), ...items.map(_historyItem)])); } Widget _historyItem(Map item) { final isNormal = item['status'] == 'normal'; return Container(margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration(borderRadius: BorderRadius.circular(12)), child: Row(children: [Text(item['date']?.toString() ?? '', style: const TextStyle(fontSize: 17, color: Color(0xFF9E9E9E))), const SizedBox(width: 8), Expanded(child: Text(item['label']?.toString() ?? '', style: const TextStyle(fontSize: 17, color: Color(0xFF333333)))), Text(item['value']?.toString() ?? '', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), const SizedBox(width: 8), Container(padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration(color: isNormal ? AppTheme.success.withAlpha(20) : const Color(0xFFFF9800).withAlpha(20), borderRadius: BorderRadius.circular(10)), child: Text(isNormal ? '正常' : '偏高', style: TextStyle(fontSize: 14, color: isNormal ? AppTheme.success : const Color(0xFFFF9800))))])); } }