import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.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': '体重趋势'}; return Scaffold( backgroundColor: Colors.white, appBar: AppBar(backgroundColor: Colors.white, elevation: 0, leading: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)), title: Text(labels[widget.metricType] ?? '趋势图表', style: const TextStyle(color: Color(0xFF1A1A1A), fontWeight: FontWeight.w600)), centerTitle: true), body: Column(children: [ Container(padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ _TimeChip(label: '7天', selected: _period == 7, onTap: () => setState(() => _period = 7)), const SizedBox(width: 12), _TimeChip(label: '30天', selected: _period == 30, onTap: () => setState(() => _period = 30)), const SizedBox(width: 12), _TimeChip(label: '90天', selected: _period == 90, onTap: () => setState(() => _period = 90)), ])), Container(margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(20), decoration: BoxDecoration(color: const Color(0xFFF8F9FF), borderRadius: BorderRadius.circular(20), border: Border.all(color: const Color(0xFFE8E6FF))), child: Column(children: [ Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(widget.metricType == 'blood_pressure' ? '血压趋势' : labels[widget.metricType] ?? '', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), Row(children: [Container(width: 10, height: 10, decoration: BoxDecoration(color: const Color(0xFF635BFF), shape: BoxShape.circle)), const SizedBox(width: 4), Text('收缩压', style: TextStyle(fontSize: 12, color: Colors.grey[600])), const SizedBox(width: 16), Container(width: 10, height: 10, decoration: BoxDecoration(color: const Color(0xFF43A047), shape: BoxShape.circle)), const SizedBox(width: 4), Text('舒张压', style: TextStyle(fontSize: 12, color: Colors.grey[600]))])]), const SizedBox(height: 24), SizedBox(height: 200, child: CustomPaint(painter: _LineChartPainter(period: _period), size: Size.infinite)), ])), if (widget.metricType == 'blood_pressure') Container(margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration(borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFFEEEEEE))), child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [const _StatItem(label: '最高', value: '145', unit: '', color: Color(0xFFE53935)), const _StatItem(label: '最低', value: '78', unit: '', color: Color(0xFF43A047)), const _StatItem(label: '平均', value: '120', unit: '/80', color: Color(0xFF635BFF))])), ]), ); } } 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: 22, vertical: 8), decoration: BoxDecoration(color: selected ? const Color(0xFF635BFF) : Colors.white, borderRadius: BorderRadius.circular(20), border: Border.all(color: selected ? const Color(0xFF635BFF) : const Color(0xFFE0E0E0))), child: Text(label, style: TextStyle(fontSize: 14, fontWeight: selected ? FontWeight.w600 : FontWeight.normal, color: selected ? Colors.white : const Color(0xFF757575)))), ); } class _StatItem extends StatelessWidget { final String label; final String value; final String unit; final Color color; const _StatItem({required this.label, required this.value, required this.unit, required this.color}); @override Widget build(BuildContext context) => Column(children: [Text(value + unit, style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: color)), const SizedBox(height: 4), Text(label, style: TextStyle(fontSize: 13, color: Colors.grey[500]))]); } class _LineChartPainter extends CustomPainter { final int period; _LineChartPainter({required this.period}); @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = const Color(0xFF635BFF)..strokeWidth = 2..style = PaintingStyle.stroke; final paint2 = Paint()..color = const Color(0xFF43A047)..strokeWidth = 2..style = PaintingStyle.stroke; final fillPaint1 = Paint()..color = const Color(0xFF635BFF)..style = PaintingStyle.fill; final fillPaint2 = Paint()..color = const Color(0xFF43A047)..style = PaintingStyle.fill; final whitePaint = Paint()..color = Colors.white..style = PaintingStyle.fill; final points1 = []; final points2 = []; if (period <= 1) return; for (int i = 0; i < period; i++) { final x = size.width * i / (period - 1); points1.add(Offset(x, size.height * 0.3 + (i % 3) * 15)); points2.add(Offset(x, size.height * 0.6 + (i % 4) * 10)); } if (points1.length > 1) { final path1 = Path()..moveTo(points1[0].dx, points1[0].dy); for (var p in points1.skip(1)) path1.lineTo(p.dx, p.dy); canvas.drawPath(path1, paint); final path2 = Path()..moveTo(points2[0].dx, points2[0].dy); for (var p in points2.skip(1)) path2.lineTo(p.dx, p.dy); canvas.drawPath(path2, paint2); } for (var p in points1) { canvas.drawCircle(p, 4, whitePaint); canvas.drawCircle(p, 3, fillPaint1); } for (var p in points2) { canvas.drawCircle(p, 4, whitePaint); canvas.drawCircle(p, 3, fillPaint2); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => oldDelegate is! _LineChartPainter || oldDelegate.period != period; }