reports_page.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:asr_client/models/report.dart';
  4. import 'package:asr_client/pages/history/widgets/date_group_header.dart';
  5. import 'package:asr_client/pages/history/widgets/filter_chips.dart';
  6. import 'package:asr_client/pages/history/widgets/report_preview_card.dart';
  7. import 'package:asr_client/providers/report_providers.dart';
  8. import 'package:asr_client/theme/app_colors.dart';
  9. class ReportsPage extends ConsumerWidget {
  10. const ReportsPage({super.key});
  11. @override
  12. Widget build(BuildContext context, WidgetRef ref) {
  13. final groups = ref.watch(filteredReportsProvider);
  14. return Scaffold(
  15. backgroundColor: AppColors.bg,
  16. appBar: AppBar(
  17. backgroundColor: AppColors.card,
  18. foregroundColor: AppColors.ink,
  19. elevation: 0,
  20. title: const Text(
  21. '检测报告',
  22. style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700),
  23. ),
  24. centerTitle: true,
  25. ),
  26. body: Column(
  27. children: [
  28. Container(
  29. color: AppColors.card,
  30. padding: const EdgeInsets.fromLTRB(14, 12, 14, 12),
  31. child: const FilterChips(),
  32. ),
  33. Expanded(
  34. child: groups.isEmpty
  35. ? const _EmptyView()
  36. : ListView.builder(
  37. padding: const EdgeInsets.fromLTRB(14, 14, 14, 24),
  38. itemCount: groups.length * 2,
  39. itemBuilder: (context, index) {
  40. final groupIndex = index ~/ 2;
  41. final group = groups[groupIndex];
  42. if (index.isEven) {
  43. return DateGroupHeader(label: group.label);
  44. }
  45. return Column(
  46. children: group.reports
  47. .map((report) => _ReportCard(report: report))
  48. .toList(),
  49. );
  50. },
  51. ),
  52. ),
  53. ],
  54. ),
  55. );
  56. }
  57. }
  58. class _ReportCard extends StatelessWidget {
  59. const _ReportCard({required this.report});
  60. final Report report;
  61. @override
  62. Widget build(BuildContext context) {
  63. final (statusText, statusColor, statusBg) = switch (report.status) {
  64. ReportStatus.ok => ('合格', AppColors.ok, AppColors.okBg),
  65. ReportStatus.warn => ('预警', AppColors.danger, AppColors.dangerBg),
  66. ReportStatus.draft => ('草稿', AppColors.ink3, AppColors.line),
  67. };
  68. return Card(
  69. color: AppColors.card,
  70. elevation: 0,
  71. margin: const EdgeInsets.only(bottom: 10),
  72. shape: RoundedRectangleBorder(
  73. borderRadius: BorderRadius.circular(14),
  74. side: const BorderSide(color: AppColors.line),
  75. ),
  76. child: Padding(
  77. padding: const EdgeInsets.all(14),
  78. child: Column(
  79. crossAxisAlignment: CrossAxisAlignment.start,
  80. children: [
  81. Row(
  82. children: [
  83. Container(
  84. padding: const EdgeInsets.symmetric(
  85. horizontal: 8,
  86. vertical: 3,
  87. ),
  88. decoration: BoxDecoration(
  89. color: statusBg,
  90. borderRadius: BorderRadius.circular(6),
  91. ),
  92. child: Text(
  93. statusText,
  94. style: TextStyle(
  95. fontSize: 10.5,
  96. fontWeight: FontWeight.w700,
  97. color: statusColor,
  98. ),
  99. ),
  100. ),
  101. const Spacer(),
  102. Text(
  103. _formatDate(report.date),
  104. style: const TextStyle(fontSize: 11.5, color: AppColors.ink3),
  105. ),
  106. ],
  107. ),
  108. const SizedBox(height: 9),
  109. Text(
  110. report.name,
  111. style: const TextStyle(
  112. fontSize: 15,
  113. fontWeight: FontWeight.w700,
  114. color: AppColors.ink,
  115. ),
  116. ),
  117. const SizedBox(height: 3),
  118. Text(
  119. report.project,
  120. style: const TextStyle(fontSize: 12, color: AppColors.ink2),
  121. ),
  122. ReportPreviewCard(report: report),
  123. ],
  124. ),
  125. ),
  126. );
  127. }
  128. String _formatDate(DateTime date) {
  129. return '${date.year}-${date.month.toString().padLeft(2, '0')}-'
  130. '${date.day.toString().padLeft(2, '0')}';
  131. }
  132. }
  133. class _EmptyView extends StatelessWidget {
  134. const _EmptyView();
  135. @override
  136. Widget build(BuildContext context) {
  137. return const Center(
  138. child: Column(
  139. mainAxisAlignment: MainAxisAlignment.center,
  140. children: [
  141. Icon(Icons.description_outlined, size: 48, color: AppColors.ink3),
  142. SizedBox(height: 12),
  143. Text('该筛选条件下暂无报告', style: TextStyle(color: AppColors.ink3)),
  144. ],
  145. ),
  146. );
  147. }
  148. }