Files
flutterApp/lib/features/v2/home/presentation/widgets/power_trend_chart.dart

200 lines
6.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:maibu_satabot_v2/features/v2/home/domain/entities/home_entity.dart';
class PowerTrendChart extends StatelessWidget {
final List<PowerTrendPoint> data;
final String trendType;
final Function(String) onToggleType;
const PowerTrendChart({
super.key,
required this.data,
required this.trendType,
required this.onToggleType,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'发电趋势(今日)',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF1D2129),
),
),
Container(
height: 32,
decoration: BoxDecoration(
color: const Color(0xFFF5F7FA),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
_buildTypeButton('kW'),
_buildTypeButton('周'),
],
),
),
],
),
const SizedBox(height: 12),
Container(
height: 220,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: const [
BoxShadow(
color: Color(0x0D000000),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: LineChart(
LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: true,
horizontalInterval: 200,
verticalInterval: 6,
getDrawingHorizontalLine: (value) {
return FlLine(
color: const Color(0xFFE5E6EB).withOpacity(0.3),
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: const Color(0xFFE5E6EB).withOpacity(0.3),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
interval: 6,
getTitlesWidget: (value, meta) {
final index = value.toInt();
if (index == 0 || index == 6 || index == 12 || index == 18 || index == 23) {
String time;
if (index == 23) {
time = '23:00';
} else {
time = '${index.toString().padLeft(2, '0')}:00';
}
return Text(
time,
style: const TextStyle(
color: Color(0xFF86909C),
fontSize: 12,
),
);
}
return const Text('');
},
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 40,
interval: 200,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: const TextStyle(
color: Color(0xFF86909C),
fontSize: 12,
),
);
},
),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
borderData: FlBorderData(show: false),
minX: 0,
maxX: 23,
minY: 0,
maxY: 1000,
lineBarsData: [
LineChartBarData(
spots: data
.asMap()
.entries
.map((e) => FlSpot(e.key.toDouble(), e.value.power))
.toList(),
isCurved: true,
color: const Color(0xFF165DFF),
barWidth: 2,
dotData: FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 2,
color: const Color(0xFF165DFF),
);
},
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
const Color(0xFF165DFF).withOpacity(0.2),
const Color(0xFF165DFF).withOpacity(0.0),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
],
),
),
),
],
);
}
Widget _buildTypeButton(String type) {
final isSelected = trendType == type;
return GestureDetector(
onTap: () => onToggleType(type),
child: Container(
width: 50,
height: 32,
decoration: BoxDecoration(
color: isSelected ? const Color(0xFF165DFF) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
alignment: Alignment.center,
child: Text(
type,
style: TextStyle(
color: isSelected ? Colors.white : const Color(0xFF86909C),
fontSize: 14,
),
),
),
);
}
}