import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../providers/data_providers.dart'; /// 趋势图表页面 class TrendPage extends ConsumerStatefulWidget { final String metricType; const TrendPage({super.key, required this.metricType}); @override ConsumerState createState() => _TrendPageState(); } class _TrendPageState extends ConsumerState { int _period = 7; @override Widget build(BuildContext context) { final labels = {'blood_pressure': '血压趋势', 'heart_rate': '心率趋势', 'glucose': '血糖趋势', 'spo2': '血氧趋势', 'weight': '体重趋势'}; final service = ref.watch(healthServiceProvider); return Scaffold( appBar: AppBar(title: Text(labels[widget.metricType] ?? '趋势图表')), body: Column(children: [ Padding( padding: const EdgeInsets.all(16), child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ _TimeChip(label: '7天', selected: _period == 7, onTap: () => setState(() => _period = 7)), const SizedBox(width: 8), _TimeChip(label: '30天', selected: _period == 30, onTap: () => setState(() => _period = 30)), const SizedBox(width: 8), _TimeChip(label: '90天', selected: _period == 90, onTap: () => setState(() => _period = 90)), ]), ), Expanded(child: FutureBuilder>>( future: service.getTrend(widget.metricType, period: _period), builder: (ctx, snap) { if (snap.connectionState == ConnectionState.waiting) return const Center(child: CircularProgressIndicator()); if (!snap.hasData || snap.data!.isEmpty) { return Center(child: Column(mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.show_chart, size: 64, color: Colors.grey[300]), const SizedBox(height: 12), Text('暂无足够数据', style: Theme.of(context).textTheme.bodyMedium), ])); } final records = snap.data!; return ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: records.length, itemBuilder: (ctx, i) { final r = records[i]; String value; if (widget.metricType == 'blood_pressure') { value = '${r['systolic'] ?? '--'}/${r['diastolic'] ?? '--'} mmHg'; } else { value = '${r['value'] ?? '--'}'; } final isAbnormal = r['isAbnormal'] == true; final date = r['recordedAt'] != null ? DateTime.parse(r['recordedAt']).toLocal().toString().substring(0, 16) : '--'; return ListTile( title: Text(value, style: TextStyle(fontSize: 16, color: isAbnormal ? const Color(0xFFE53935) : null)), subtitle: Text(date, style: const TextStyle(fontSize: 14, color: Color(0xFF999999))), trailing: isAbnormal ? const Icon(Icons.warning_amber, color: Color(0xFFE53935), size: 20) : const Icon(Icons.check_circle, color: Color(0xFF43A047), size: 20), ); }, ); }, )), ]), ); } } class _TimeChip extends StatelessWidget { final String label; final bool selected; final VoidCallback onTap; const _TimeChip({required this.label, required this.selected, required this.onTap}); @override Widget build(BuildContext context) => GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), decoration: BoxDecoration(color: selected ? const Color(0xFF635BFF) : Colors.white, borderRadius: BorderRadius.circular(20), border: Border.all(color: const Color(0xFF635BFF))), child: Text(label, style: TextStyle(fontSize: 14, color: selected ? Colors.white : const Color(0xFF635BFF))), ), ); }