import 'package:flutter/material.dart'; // --- 潘通色定义 --- const Color kHealthGreen = Color(0xFF00B140); const Color kHealthYellow = Color(0xFFEFDF00); const Color kHealthOrange = Color(0xFFD75A16); /// 趋势图柱状图组件 class TrendChart extends StatelessWidget { final List> data; final int designCap; const TrendChart({super.key, required this.data, required this.designCap}); @override Widget build(BuildContext context) { List> displayData = data.isNotEmpty ? data : _getMockData(); List dates = displayData.map((e) { String date = e['date'] as String; var parts = date.split('-'); return '${parts[1]}/${parts[2]}'; }).toList(); List percents = displayData.map((e) { int cap = e['capacity'] as int; return (cap / designCap) * 100; }).toList(); while (percents.length < 15) { percents.insert(0, 0); dates.insert(0, ''); } if (percents.length > 15) { percents = percents.sublist(percents.length - 15); dates = dates.sublist(dates.length - 15); } int todayIndex = percents.length - 1; int sevenDaysAgoIndex = todayIndex - 7; bool showSevenDaysAgo = sevenDaysAgoIndex >= 0; String sevenDaysAgoDate = showSevenDaysAgo ? dates[sevenDaysAgoIndex] : ''; String todayDate = dates[todayIndex]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '容量百分比变动趋势(近15天)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), ), const SizedBox(height: 8), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 180, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: const [ Text( '100', style: TextStyle( fontSize: 10, color: Colors.grey, height: 1.0, ), ), Text( '70', style: TextStyle( fontSize: 10, color: Colors.grey, height: 1.0, ), ), ], ), ), const SizedBox(width: 4), Expanded( child: LayoutBuilder( builder: (context, constraints) { double totalWidth = constraints.maxWidth; double step = totalWidth / 15; return SizedBox( height: 180, child: Stack( children: [ Padding( padding: const EdgeInsets.only(bottom: 20), child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: List.generate(percents.length, (index) { double value = percents[index]; Color barColor; if (value > 0) { if (value >= 80) { barColor = kHealthGreen; } else if (value >= 70) { barColor = kHealthYellow; } else { barColor = Colors.red; } } else { barColor = Colors.grey.shade300; } double clampedValue = value.clamp(70.0, 100.0); double heightFactor = (clampedValue - 70.0) / 30.0; return Expanded( child: Align( alignment: Alignment.bottomCenter, child: Container( margin: const EdgeInsets.symmetric( horizontal: 2, ), height: 20 + (100 * heightFactor), width: 18, decoration: BoxDecoration( color: barColor, borderRadius: BorderRadius.circular(4), ), ), ), ); }), ), ), if (showSevenDaysAgo && sevenDaysAgoDate.isNotEmpty) Positioned( left: sevenDaysAgoIndex * step + (step / 2) - 14, bottom: 2, child: Text( sevenDaysAgoDate, style: const TextStyle( fontSize: 9, color: Colors.grey, height: 1.0, ), ), ), if (todayDate.isNotEmpty) Positioned( left: todayIndex * step + (step / 2) - 14, bottom: 2, child: Text( todayDate, style: const TextStyle( fontSize: 9, color: Colors.black, height: 1.0, fontWeight: FontWeight.w600, ), ), ), ], ), ); }, ), ), ], ), if (percents.every((v) => v == 0)) const Padding( padding: EdgeInsets.only(top: 8.0), child: Text( '暂无历史数据,请点击刷新按钮更新', style: TextStyle(fontSize: 12, color: Colors.grey), ), ), ], ); } List> _getMockData() { List mockDates = [ '2026-06-14', '2026-06-15', '2026-06-16', '2026-06-17', '2026-06-18', '2026-06-19', '2026-06-20', '2026-06-21', '2026-06-22', '2026-06-23', '2026-06-24', '2026-06-25', '2026-06-26', '2026-06-27', '2026-06-28', ]; List mockCap = [ 4635, 4632, 4628, 4625, 4620, 4618, 4615, 4610, 4608, 4605, 4600, 4598, 4595, 4590, 4585, ]; return List.generate( 15, (i) => {'date': mockDates[i], 'capacity': mockCap[i]}, ); } }