Files
CloudHome-Ops/lib/screens/alerts/alerts_page.dart

141 lines
4.2 KiB
Dart
Raw Permalink Normal View History

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/alert.dart';
import '../../app/theme.dart';
import '../../providers/devices_provider.dart';
import '../../utils/formatters.dart';
/// 告警列表页(底部导航第 2 个 tab)。
class AlertsPage extends ConsumerWidget {
const AlertsPage({super.key});
Color _levelColor(BuildContext context, AlertLevel level) {
final semantic = Theme.of(context).extension<AppSemanticColors>();
switch (level) {
case AlertLevel.critical:
return Colors.red;
case AlertLevel.warning:
return Colors.orange;
case AlertLevel.info:
return semantic?.info ?? Theme.of(context).colorScheme.primary;
}
}
IconData _levelIcon(AlertLevel level) {
switch (level) {
case AlertLevel.critical:
return Icons.error;
case AlertLevel.warning:
return Icons.warning_amber;
case AlertLevel.info:
return Icons.info_outline;
}
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final alertsAsync = ref.watch(alertsProvider);
return Scaffold(
appBar: AppBar(title: const Text('告警中心')),
body: alertsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('告警列表加载失败'),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () => ref.refresh(alertsProvider),
child: const Text('重试'),
),
],
),
),
data: (alerts) {
if (alerts.isEmpty) {
return const Center(child: Text('暂无告警'));
}
return RefreshIndicator(
onRefresh: () async => ref.refresh(alertsProvider.future),
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: alerts.length,
itemBuilder: (context, index) =>
_buildAlertCard(context, alerts[index]),
),
);
},
),
);
}
Widget _buildAlertCard(BuildContext context, Alert alert) {
final color = _levelColor(context, alert.level);
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(_levelIcon(alert.level), color: color, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
alert.title,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
_buildLevelTag(alert, color),
],
),
const SizedBox(height: 8),
Text(
alert.message,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text(
alert.deviceName,
style: Theme.of(context).textTheme.bodySmall,
),
),
Text(
Formatters.formatDateTime(alert.occurredAt),
style: Theme.of(context).textTheme.bodySmall,
),
],
),
],
),
),
);
}
Widget _buildLevelTag(Alert alert, Color color) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: color.withOpacity(0.15),
borderRadius: BorderRadius.circular(999),
),
child: Text(
alert.acknowledged ? '${alert.level.label}·已确认' : alert.level.label,
style: TextStyle(
color: color,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
);
}
}