message_list_page.dart 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:go_router/go_router.dart';
  4. import 'package:tdesign_flutter/tdesign_flutter.dart';
  5. import '../../core/theme/app_colors.dart';
  6. import '../../shared/widgets/empty_state.dart';
  7. import '../../shared/widgets/loading_widget.dart';
  8. import 'message_controller.dart';
  9. import 'message_model.dart';
  10. class MessageListPage extends ConsumerWidget {
  11. const MessageListPage({super.key});
  12. @override
  13. Widget build(BuildContext context, WidgetRef ref) {
  14. final messagesAsync = ref.watch(messageListProvider);
  15. return Scaffold(
  16. appBar: TDNavBar(
  17. title: '消息',
  18. titleColor: Colors.white,
  19. backgroundColor: const Color(0xFF00ABF3),
  20. centerTitle: false,
  21. useDefaultBack: false,
  22. ),
  23. body: messagesAsync.when(
  24. loading: () => const LoadingWidget(),
  25. error: (_, __) => const EmptyState(message: '加载失败'),
  26. data: (messages) => messages.isEmpty
  27. ? const EmptyState(message: '暂无消息')
  28. : ListView.separated(
  29. itemCount: messages.length,
  30. separatorBuilder: (_, __) => const TDDivider(),
  31. itemBuilder: (_, i) => _buildItem(context, messages[i]),
  32. ),
  33. ),
  34. );
  35. }
  36. Widget _buildItem(BuildContext context, MessageModel msg) {
  37. return TDCell(
  38. imageWidget: TDAvatar(
  39. type: TDAvatarType.icon,
  40. size: TDAvatarSize.medium,
  41. shape: TDAvatarShape.circle,
  42. icon: msg.msgType == 'announcement'
  43. ? Icons.campaign
  44. : msg.msgType == 'approval_result'
  45. ? Icons.check_circle_outline
  46. : Icons.assignment_outlined,
  47. backgroundColor:
  48. msg.isRead ? const Color(0xFFF0F0F0) : AppColors.primaryLight,
  49. ),
  50. title: msg.title,
  51. description: msg.content,
  52. note: _formatTime(msg.createTime),
  53. arrow: true,
  54. onClick: (_) => _navigateToBiz(context, msg),
  55. );
  56. }
  57. String _formatTime(DateTime time) {
  58. final now = DateTime.now();
  59. final diff = now.difference(time);
  60. if (diff.inMinutes < 60) return '${diff.inMinutes}分钟前';
  61. if (diff.inHours < 24) return '${diff.inHours}小时前';
  62. if (diff.inDays < 7) return '${diff.inDays}天前';
  63. return '${time.month}/${time.day}';
  64. }
  65. void _navigateToBiz(BuildContext context, MessageModel msg) {
  66. if (msg.bizType == null || msg.bizId == null) return;
  67. switch (msg.bizType) {
  68. case 'expense':
  69. context.push('/expense/detail/${msg.bizId}');
  70. break;
  71. case 'overtime':
  72. context.push('/overtime/detail/${msg.bizId}');
  73. break;
  74. case 'vehicle':
  75. context.push('/vehicle/detail/${msg.bizId}');
  76. break;
  77. case 'announcement':
  78. context.push('/announcement/detail/${msg.bizId}');
  79. break;
  80. case 'expense_application':
  81. context.push('/expense-apply/detail/${msg.bizId}');
  82. break;
  83. }
  84. }
  85. }