|
|
@@ -1,6 +1,7 @@
|
|
|
-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';
|
|
|
@@ -8,8 +9,12 @@ 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 { useAuth } from "./hooks_sys.tsx";
|
|
|
|
|
|
-export const MessagesPage = () => {
|
|
|
+export const MessagesPage = () => {
|
|
|
+ const { token } = useAuth();
|
|
|
+ const [socket, setSocket] = useState<Socket | null>(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'] });
|
|
|
@@ -266,10 +321,11 @@ export const MessagesPage = () => {
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item>
|
|
|
- <Button
|
|
|
- type="primary"
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
htmlType="submit"
|
|
|
loading={sendMessageMutation.status === 'pending'}
|
|
|
+ icon={isSocketConnected ? <span style={{color:'green'}}>●</span> : <span style={{color:'red'}}>●</span>}
|
|
|
>
|
|
|
发送
|
|
|
</Button>
|