diff --git a/HISTORY.md b/HISTORY.md index 910a0b5..224993e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,10 @@ 迁移管理页面,在正式环境中,需要验证env中配置的密码参数才能打开 2025.05.15 0.1.6 +站内消息支持三种类型,admin发送,mobile订阅 +增加admin, mobile 消息io连接 +增加socketio 路由 支持 +增加socketio server 支持 修正文件分类后端api路由查询表名为file_categories 将react版本降为18.3.1 diff --git a/client/admin/pages_messages.tsx b/client/admin/pages_messages.tsx index 0e8cdf3..c6b6248 100644 --- a/client/admin/pages_messages.tsx +++ b/client/admin/pages_messages.tsx @@ -1,15 +1,20 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Button, Table, Space, Modal, Form, Input, Select, message } from 'antd'; +import { io, Socket } from 'socket.io-client'; 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'; +import { MessageStatusNameMap , MessageStatus, MessageType } from '../share/types.ts'; +import { useAuth } from "./hooks_sys.tsx"; -export const MessagesPage = () => { +export const MessagesPage = () => { + const { token } = useAuth(); + const [socket, setSocket] = useState(null); + const [isSocketConnected, setIsSocketConnected] = useState(false); const queryClient = useQueryClient(); const [form] = Form.useForm(); const [isModalVisible, setIsModalVisible] = useState(false); @@ -59,8 +64,58 @@ export const MessagesPage = () => { }); // 发送消息 + // 初始化Socket.IO连接 + useEffect(() => { + if (!token) return; + + const newSocket = io('/', { + path: '/socket.io', + transports: ['websocket'], + autoConnect: false, + query: { + socket_token: token + } + }); + + newSocket.on('connect', () => { + setIsSocketConnected(true); + message.success('实时消息连接已建立'); + }); + + newSocket.on('disconnect', () => { + setIsSocketConnected(false); + message.warning('实时消息连接已断开'); + }); + + newSocket.on('error', (err) => { + message.error(`实时消息错误: ${err}`); + }); + + newSocket.connect(); + setSocket(newSocket); + + return () => { + newSocket.disconnect(); + }; + }, [token]); + const sendMessageMutation = useMutation({ - mutationFn: (data: any) => MessageAPI.sendMessage(data), + mutationFn: async (data: any) => { + // 优先使用Socket.IO发送 + if (isSocketConnected && socket) { + return new Promise((resolve, reject) => { + socket.emit('message:send', data, (response: any) => { + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + }); + }); + } + // 回退到HTTP API + return MessageAPI.sendMessage(data); + }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['messages'] }); queryClient.invalidateQueries({ queryKey: ['unreadCount'] }); @@ -167,9 +222,9 @@ export const MessagesPage = () => { style={{ width: 120 }} allowClear options={[ - { value: 'SYSTEM', label: '系统消息' }, - { value: 'NOTICE', label: '公告' }, - { value: 'PERSONAL', label: '个人消息' }, + { value: MessageType.SYSTEM, label: '系统消息' }, + { value: MessageType.ANNOUNCE, label: '公告' }, + { value: MessageType.PRIVATE, label: '个人消息' }, ]} /> @@ -178,8 +233,8 @@ export const MessagesPage = () => { style={{ width: 120 }} allowClear options={[ - { value: 'UNREAD', label: '未读' }, - { value: 'READ', label: '已读' }, + { value: MessageStatus.UNREAD, label: '未读' }, + { value: MessageStatus.READ, label: '已读' }, ]} /> @@ -235,9 +290,9 @@ export const MessagesPage = () => { >