| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import React, { useState } from 'react';
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
- import { Button, Table, Space, Modal, Form, Input, Select, message } from 'antd';
- import type { TableProps } from 'antd';
- import dayjs from 'dayjs';
- import 'dayjs/locale/zh-cn';
- import { MessageAPI , UserAPI } from './api/index.ts';
- import type { UserMessage } from '../share/types.ts';
- import { MessageStatusNameMap , MessageStatus} from '../share/types.ts';
- export const MessagesPage = () => {
- const queryClient = useQueryClient();
- const [form] = Form.useForm();
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [searchParams, setSearchParams] = useState({
- page: 1,
- pageSize: 10,
- type: undefined,
- status: undefined,
- search: undefined
- });
- // 获取消息列表
- const { data: messages, isLoading } = useQuery({
- queryKey: ['messages', searchParams],
- queryFn: () => MessageAPI.getMessages(searchParams),
- });
- // 获取用户列表
- const { data: users } = useQuery({
- queryKey: ['users'],
- queryFn: () => UserAPI.getUsers({ page: 1, limit: 1000 }),
- });
- // 获取未读消息数
- const { data: unreadCount } = useQuery({
- queryKey: ['unreadCount'],
- queryFn: () => MessageAPI.getUnreadCount(),
- });
- // 标记消息为已读
- const markAsReadMutation = useMutation({
- mutationFn: (id: number) => MessageAPI.markAsRead(id),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['messages'] });
- queryClient.invalidateQueries({ queryKey: ['unreadCount'] });
- message.success('标记已读成功');
- },
- });
- // 删除消息
- const deleteMutation = useMutation({
- mutationFn: (id: number) => MessageAPI.deleteMessage(id),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['messages'] });
- message.success('删除成功');
- },
- });
- // 发送消息
- const sendMessageMutation = useMutation({
- mutationFn: (data: any) => MessageAPI.sendMessage(data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['messages'] });
- queryClient.invalidateQueries({ queryKey: ['unreadCount'] });
- message.success('发送成功');
- setIsModalVisible(false);
- form.resetFields();
- },
- });
- const columns: TableProps<UserMessage>['columns'] = [
- {
- title: '标题',
- dataIndex: 'title',
- key: 'title',
- },
- {
- title: '类型',
- dataIndex: 'type',
- key: 'type',
- },
- {
- title: '发送人',
- dataIndex: 'sender_name',
- key: 'sender_name',
- },
- {
- title: '状态',
- dataIndex: 'user_status',
- key: 'user_status',
- render: (user_status: MessageStatus) => (
- <span style={{ color: user_status === MessageStatus.UNREAD ? 'red' : 'green' }}>
- {MessageStatusNameMap[user_status]}
- </span>
- ),
- },
- {
- title: '发送时间',
- dataIndex: 'created_at',
- key: 'created_at',
- render: (date: string) => dayjs(date).format('YYYY-MM-DD HH:mm'),
- },
- {
- title: '操作',
- key: 'action',
- render: (_: any, record) => (
- <Space size="middle">
- <Button
- type="link"
- onClick={() => markAsReadMutation.mutate(record.id)}
- disabled={record.user_status === MessageStatus.READ}
- >
- 标记已读
- </Button>
- <Button
- type="link"
- danger
- onClick={() => deleteMutation.mutate(record.id)}
- >
- 删除
- </Button>
- </Space>
- ),
- },
- ];
- const handleSearch = (values: any) => {
- setSearchParams({
- ...searchParams,
- ...values,
- page: 1
- });
- };
- const handleTableChange = (pagination: any) => {
- setSearchParams({
- ...searchParams,
- page: pagination.current,
- pageSize: pagination.pageSize
- });
- };
- const handleSendMessage = (values: any) => {
- sendMessageMutation.mutate(values);
- };
- return (
- <div className="p-4">
- <div className="flex justify-between items-center mb-4">
- <h1 className="text-2xl font-bold">消息管理</h1>
- <div className="flex items-center space-x-4">
- {unreadCount && unreadCount.count > 0 && (
- <span className="text-red-500">{unreadCount.count}条未读</span>
- )}
- <Button type="primary" onClick={() => setIsModalVisible(true)}>
- 发送消息
- </Button>
- </div>
- </div>
- <div className="bg-white p-4 rounded shadow">
- <Form layout="inline" onFinish={handleSearch} className="mb-4">
- <Form.Item name="type" label="类型">
- <Select
- style={{ width: 120 }}
- allowClear
- options={[
- { value: 'SYSTEM', label: '系统消息' },
- { value: 'NOTICE', label: '公告' },
- { value: 'PERSONAL', label: '个人消息' },
- ]}
- />
- </Form.Item>
- <Form.Item name="status" label="状态">
- <Select
- style={{ width: 120 }}
- allowClear
- options={[
- { value: 'UNREAD', label: '未读' },
- { value: 'READ', label: '已读' },
- ]}
- />
- </Form.Item>
- <Form.Item name="search" label="搜索">
- <Input placeholder="输入标题或内容" />
- </Form.Item>
- <Form.Item>
- <Button type="primary" htmlType="submit">
- 搜索
- </Button>
- </Form.Item>
- </Form>
- <Table
- columns={columns}
- dataSource={messages?.data}
- loading={isLoading}
- rowKey="id"
- pagination={{
- current: searchParams.page,
- pageSize: searchParams.pageSize,
- total: messages?.pagination?.total,
- showSizeChanger: true,
- }}
- onChange={handleTableChange}
- />
- </div>
- <Modal
- title="发送消息"
- visible={isModalVisible}
- onCancel={() => setIsModalVisible(false)}
- footer={null}
- width={800}
- >
- <Form
- form={form}
- layout="vertical"
- onFinish={handleSendMessage}
- >
- <Form.Item
- name="title"
- label="标题"
- rules={[{ required: true, message: '请输入标题' }]}
- >
- <Input placeholder="请输入消息标题" />
- </Form.Item>
- <Form.Item
- name="type"
- label="消息类型"
- rules={[{ required: true, message: '请选择消息类型' }]}
- >
- <Select
- options={[
- { value: 'SYSTEM', label: '系统消息' },
- { value: 'NOTICE', label: '公告' },
- { value: 'PERSONAL', label: '个人消息' },
- ]}
- />
- </Form.Item>
- <Form.Item
- name="receiver_ids"
- label="接收人"
- rules={[{ required: true, message: '请选择接收人' }]}
- >
- <Select
- mode="multiple"
- placeholder="请选择接收人"
- options={users?.data?.map((user: any) => ({
- value: user.id,
- label: user.username,
- }))}
- />
- </Form.Item>
- <Form.Item
- name="content"
- label="内容"
- rules={[{ required: true, message: '请输入消息内容' }]}
- >
- <Input.TextArea rows={6} placeholder="请输入消息内容" />
- </Form.Item>
- <Form.Item>
- <Button
- type="primary"
- htmlType="submit"
- loading={sendMessageMutation.status === 'pending'}
- >
- 发送
- </Button>
- </Form.Item>
- </Form>
- </Modal>
- </div>
- );
- };
|