pages_messages.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import React from 'react';
  2. import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
  3. import dayjs from 'dayjs';
  4. import 'dayjs/locale/zh-cn';
  5. import { BellIcon } from '@heroicons/react/24/outline';
  6. import { MessageStatus } from '../share/types.ts';
  7. // 添加通知页面组件
  8. import { MessageAPI } from './api.ts';
  9. export const NotificationsPage = () => {
  10. const queryClient = useQueryClient();
  11. // 获取消息列表
  12. const { data: messages, isLoading } = useQuery({
  13. queryKey: ['messages'],
  14. queryFn: () => MessageAPI.getMessages(),
  15. });
  16. // 获取未读消息数量
  17. const { data: unreadCount } = useQuery({
  18. queryKey: ['unreadCount'],
  19. queryFn: () => MessageAPI.getUnreadCount(),
  20. });
  21. // 标记消息为已读
  22. const markAsReadMutation = useMutation({
  23. mutationFn: (id: number) => MessageAPI.markAsRead(id),
  24. onSuccess: () => {
  25. queryClient.invalidateQueries({ queryKey: ['messages'] });
  26. queryClient.invalidateQueries({ queryKey: ['unreadCount'] });
  27. },
  28. });
  29. // 删除消息
  30. const deleteMutation = useMutation({
  31. mutationFn: (id: number) => MessageAPI.deleteMessage(id),
  32. onSuccess: () => {
  33. queryClient.invalidateQueries({ queryKey: ['messages'] });
  34. },
  35. });
  36. const handleMarkAsRead = (id: number) => {
  37. markAsReadMutation.mutate(id);
  38. };
  39. const handleDelete = (id: number) => {
  40. if (confirm('确定要删除这条消息吗?')) {
  41. deleteMutation.mutate(id);
  42. }
  43. };
  44. if (isLoading) {
  45. return (
  46. <div className="p-4">
  47. <h1 className="text-2xl font-bold mb-4">通知</h1>
  48. <div className="flex justify-center items-center h-40">
  49. <div className="w-8 h-8 border-4 border-blue-200 border-t-blue-600 rounded-full animate-spin"></div>
  50. </div>
  51. </div>
  52. );
  53. }
  54. return (
  55. <div className="p-4">
  56. <div className="flex items-center justify-between mb-4">
  57. <h1 className="text-2xl font-bold">通知</h1>
  58. {unreadCount && unreadCount.count > 0 ? (
  59. <div className="flex items-center">
  60. <BellIcon className="h-5 w-5 text-red-500 mr-1" />
  61. <span className="text-sm text-red-500">{unreadCount.count}条未读</span>
  62. </div>
  63. ) : null}
  64. </div>
  65. <div className="bg-white rounded-lg shadow divide-y">
  66. {messages?.data.map((message) => (
  67. <div key={message.id} className="p-4">
  68. <div className="flex justify-between items-start">
  69. <h3 className="font-medium">{message.title}</h3>
  70. <div className="flex space-x-2">
  71. {message.user_status === MessageStatus.UNREAD && (
  72. <button
  73. type="button"
  74. onClick={() => handleMarkAsRead(message.id)}
  75. className="text-xs text-blue-600 hover:text-blue-800"
  76. >
  77. 标记已读
  78. </button>
  79. )}
  80. <button
  81. type="button"
  82. onClick={() => handleDelete(message.id)}
  83. className="text-xs text-red-600 hover:text-red-800"
  84. >
  85. 删除
  86. </button>
  87. </div>
  88. </div>
  89. <p className="text-gray-500 text-sm mt-1">{message.content}</p>
  90. <p className="text-xs text-gray-400 mt-2">
  91. {dayjs(message.created_at).format('YYYY-MM-DD HH:mm')}
  92. </p>
  93. </div>
  94. ))}
  95. </div>
  96. </div>
  97. );
  98. };