refactor: ♻️ 存入localStorage移除前缀,websocket hook重构优化
This commit is contained in:
@@ -9,7 +9,7 @@ VITE_APP_API_URL=https://api.youlai.tech # 线上
|
||||
# VITE_APP_API_URL=http://localhost:8989 # 本地
|
||||
|
||||
# WebSocket 端点(不配置则关闭),线上 ws://api.youlai.tech/ws ,本地 ws://localhost:8989/ws
|
||||
VITE_APP_WS_ENDPOINT=
|
||||
VITE_APP_WS_ENDPOINT=ws://localhost:8989/ws
|
||||
|
||||
# 启用 Mock 服务
|
||||
VITE_MOCK_DEV_SERVER=false
|
||||
|
||||
151
src/hooks/useStomp.ts
Normal file
151
src/hooks/useStomp.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { Client, IMessage, StompSubscription } from "@stomp/stompjs";
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
|
||||
export interface UseStompOptions {
|
||||
/** WebSocket 地址,不传时使用 VITE_APP_WS_ENDPOINT 环境变量 */
|
||||
brokerURL?: string;
|
||||
/** 用于鉴权的 token,不传时使用 getToken() 的返回值 */
|
||||
token?: string;
|
||||
/** 重连延迟,单位毫秒,默认为 5000 */
|
||||
reconnectDelay?: number;
|
||||
/** 是否开启调试日志 */
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export function useStomp(options: UseStompOptions = {}) {
|
||||
// 默认值:brokerURL 从环境变量中获取,token 从 getAccessToken() 获取
|
||||
const defaultBrokerURL = import.meta.env.VITE_APP_WS_ENDPOINT || "";
|
||||
const defaultToken = getAccessToken();
|
||||
|
||||
// 将 brokerURL 定义为响应式 ref,便于动态修改
|
||||
const brokerURL = ref(options.brokerURL ?? defaultBrokerURL);
|
||||
const token = options.token ?? defaultToken;
|
||||
|
||||
// 连接状态标记
|
||||
const isConnected = ref(false);
|
||||
// 存储所有订阅
|
||||
const subscriptions = new Map<string, StompSubscription>();
|
||||
|
||||
// 用于保存 STOMP 客户端的实例
|
||||
let client: Client | null = null;
|
||||
|
||||
/**
|
||||
* 初始化 STOMP 客户端
|
||||
* 只有在 brokerURL 非空时才会初始化客户端
|
||||
*/
|
||||
const initializeClient = () => {
|
||||
if (!brokerURL.value) {
|
||||
console.warn(
|
||||
"brokerURL is required. Please set the WebSocket URL in your .env file (VITE_APP_WS_ENDPOINT)."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client) {
|
||||
client = new Client({
|
||||
brokerURL: brokerURL.value,
|
||||
reconnectDelay: options.reconnectDelay ?? 5000,
|
||||
debug: options.debug ? (msg) => console.log("[STOMP]", msg) : () => {},
|
||||
connectHeaders: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
heartbeatIncoming: 4000,
|
||||
heartbeatOutgoing: 4000,
|
||||
});
|
||||
|
||||
client.onConnect = (frame) => {
|
||||
isConnected.value = true;
|
||||
console.log("STOMP connected", frame);
|
||||
};
|
||||
|
||||
client.onStompError = (frame) => {
|
||||
console.error("Broker reported error: " + frame.headers["message"]);
|
||||
console.error("Additional details: " + frame.body);
|
||||
};
|
||||
|
||||
client.onWebSocketClose = (evt) => {
|
||||
isConnected.value = false;
|
||||
console.warn("WebSocket closed", evt);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 brokerURL 的变化,若地址改变则重新初始化
|
||||
watch(brokerURL, (newURL, oldURL) => {
|
||||
if (newURL !== oldURL) {
|
||||
console.log(`brokerURL changed from ${oldURL} to ${newURL}`);
|
||||
// 断开当前连接,重新激活客户端
|
||||
if (client && client.connected) {
|
||||
client.deactivate();
|
||||
}
|
||||
brokerURL.value = newURL;
|
||||
initializeClient(); // 重新初始化客户端
|
||||
}
|
||||
});
|
||||
|
||||
// 在组件挂载时检查并初始化客户端
|
||||
onMounted(() => {
|
||||
initializeClient();
|
||||
});
|
||||
|
||||
/**
|
||||
* 激活连接(如果已经连接或正在激活则直接返回)
|
||||
*/
|
||||
const connect = () => {
|
||||
if (client && (client.connected || client.active)) {
|
||||
console.log("Already connected or connecting, skipping connect() call.");
|
||||
return;
|
||||
}
|
||||
client?.activate();
|
||||
};
|
||||
|
||||
/**
|
||||
* 订阅指定主题
|
||||
* @param destination 目标主题地址
|
||||
* @param callback 接收到消息时的回调函数
|
||||
* @returns 返回订阅 id,用于后续取消订阅
|
||||
*/
|
||||
const subscribe = (destination: string, callback: (message: IMessage) => void): string => {
|
||||
if (client) {
|
||||
const subscription = client.subscribe(destination, callback);
|
||||
subscriptions.set(subscription.id, subscription);
|
||||
return subscription.id;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消指定订阅
|
||||
* @param subscriptionId 要取消的订阅 id
|
||||
*/
|
||||
const unsubscribe = (subscriptionId: string) => {
|
||||
const subscription = subscriptions.get(subscriptionId);
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscriptions.delete(subscriptionId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 主动断开连接(如果未连接则不执行)
|
||||
*/
|
||||
const disconnect = () => {
|
||||
if (client && !(client.connected || client.active)) {
|
||||
console.log("Already disconnected, skipping disconnect() call.");
|
||||
return;
|
||||
}
|
||||
client?.deactivate();
|
||||
isConnected.value = false;
|
||||
};
|
||||
|
||||
return {
|
||||
client,
|
||||
isConnected,
|
||||
connect,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
disconnect,
|
||||
brokerURL, // 暴露 brokerURL 以便组件中动态修改
|
||||
};
|
||||
}
|
||||
@@ -167,8 +167,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import NoticeAPI, { NoticePageVO } from "@/api/system/notice";
|
||||
import WebSocketManager from "@/utils/websocket";
|
||||
import router from "@/router";
|
||||
import { useStomp } from "@/hooks/useStomp";
|
||||
|
||||
const activeTab = ref("notice");
|
||||
const notices = ref<NoticePageVO[]>([]);
|
||||
@@ -176,15 +176,23 @@ const messages = ref<any[]>([]);
|
||||
const tasks = ref<any[]>([]);
|
||||
const noticeDetailRef = ref();
|
||||
|
||||
// 初始化 useStomp hook(这里仅用于订阅通知消息),同时调用 connect 建立连接
|
||||
const { connect, subscribe, disconnect } = useStomp({
|
||||
debug: true,
|
||||
});
|
||||
|
||||
// 获取未读消息列表并连接 WebSocket
|
||||
onMounted(() => {
|
||||
NoticeAPI.getMyNoticePage({ pageNum: 1, pageSize: 5, isRead: 0 }).then((data) => {
|
||||
notices.value = data.list;
|
||||
});
|
||||
|
||||
WebSocketManager.subscribeToTopic("/user/queue/message", (message) => {
|
||||
// 建立连接
|
||||
connect();
|
||||
|
||||
subscribe("/user/queue/message", (message) => {
|
||||
console.log("收到消息:", message);
|
||||
const data = JSON.parse(message);
|
||||
const data = JSON.parse(message.body);
|
||||
const id = data.id;
|
||||
if (!notices.value.some((notice) => notice.id == id)) {
|
||||
notices.value.unshift({
|
||||
@@ -224,6 +232,11 @@ function markAllAsRead() {
|
||||
notices.value = [];
|
||||
});
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 如果需要取消订阅,可以在这里调用 disconnect 或 unsubscribe(本示例直接断开连接)
|
||||
disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dropdown trigger="click">
|
||||
<div class="flex-center h100% p13px">
|
||||
<img :src="userStore.userInfo.avatar" class="rounded-full mr-10px w24px h24px" />
|
||||
<img :src="userStore.userInfo.avatar" class="rounded-full mr10px w24px h24px" />
|
||||
<span>{{ userStore.userInfo.username }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
|
||||
@@ -6,7 +6,6 @@ import { setupRouter } from "@/router";
|
||||
import { setupStore } from "@/store";
|
||||
import { setupElIcons } from "./icons";
|
||||
import { setupPermission } from "./permission";
|
||||
import webSocketManager from "@/utils/websocket";
|
||||
import { InstallCodeMirror } from "codemirror-editor-vue3";
|
||||
|
||||
export default {
|
||||
@@ -23,8 +22,6 @@ export default {
|
||||
setupElIcons(app);
|
||||
// 路由守卫
|
||||
setupPermission();
|
||||
// 初始化 WebSocket
|
||||
webSocketManager.setupWebSocket();
|
||||
// 注册 CodeMirror
|
||||
app.use(InstallCodeMirror);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { NavigationGuardNext, RouteLocationNormalized, RouteRecordRaw } from "vue-router";
|
||||
import NProgress from "@/utils/nprogress";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
import router from "@/router";
|
||||
import { usePermissionStore, useUserStore } from "@/store";
|
||||
|
||||
@@ -11,7 +11,7 @@ export function setupPermission() {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
|
||||
const isLogin = !!getToken(); // 判断是否登录
|
||||
const isLogin = !!getAccessToken(); // 判断是否登录
|
||||
if (isLogin) {
|
||||
if (to.path === "/login") {
|
||||
// 已登录,访问登录页,跳转到首页
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useDictStoreHook } from "@/store/modules/dict";
|
||||
import AuthAPI, { type LoginFormData } from "@/api/auth";
|
||||
import UserAPI, { type UserInfo } from "@/api/system/user";
|
||||
|
||||
import { setToken, setRefreshToken, getRefreshToken, clearToken } from "@/utils/auth";
|
||||
import { setAccessToken, setRefreshToken, getRefreshToken, clearToken } from "@/utils/auth";
|
||||
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
const userInfo = useStorage<UserInfo>("userInfo", {} as UserInfo);
|
||||
@@ -20,8 +20,8 @@ export const useUserStore = defineStore("user", () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
AuthAPI.login(LoginFormData)
|
||||
.then((data) => {
|
||||
const { tokenType, accessToken, refreshToken } = data;
|
||||
setToken(tokenType + " " + accessToken); // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
|
||||
const { accessToken, refreshToken } = data;
|
||||
setAccessToken(accessToken); // eyJhbGciOiJIUzI1NiJ9.xxx.xxx
|
||||
setRefreshToken(refreshToken);
|
||||
resolve();
|
||||
})
|
||||
@@ -77,8 +77,8 @@ export const useUserStore = defineStore("user", () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
AuthAPI.refreshToken(refreshToken)
|
||||
.then((data) => {
|
||||
const { tokenType, accessToken, refreshToken } = data;
|
||||
setToken(tokenType + " " + accessToken);
|
||||
const { accessToken, refreshToken } = data;
|
||||
setAccessToken(accessToken);
|
||||
setRefreshToken(refreshToken);
|
||||
resolve();
|
||||
})
|
||||
|
||||
@@ -3,11 +3,11 @@ const ACCESS_TOKEN_KEY = "access_token";
|
||||
// 刷新 token 缓存的 key
|
||||
const REFRESH_TOKEN_KEY = "refresh_token";
|
||||
|
||||
function getToken(): string {
|
||||
function getAccessToken(): string {
|
||||
return localStorage.getItem(ACCESS_TOKEN_KEY) || "";
|
||||
}
|
||||
|
||||
function setToken(token: string) {
|
||||
function setAccessToken(token: string) {
|
||||
localStorage.setItem(ACCESS_TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
@@ -24,4 +24,4 @@ function clearToken() {
|
||||
localStorage.removeItem(REFRESH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export { getToken, setToken, clearToken, getRefreshToken, setRefreshToken };
|
||||
export { getAccessToken, setAccessToken, clearToken, getRefreshToken, setRefreshToken };
|
||||
|
||||
@@ -2,7 +2,7 @@ import axios, { type InternalAxiosRequestConfig, type AxiosResponse } from "axio
|
||||
import qs from "qs";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { ResultEnum } from "@/enums/ResultEnum";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
import router from "@/router";
|
||||
|
||||
// 创建 axios 实例
|
||||
@@ -16,10 +16,10 @@ const service = axios.create({
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
const accessToken = getToken();
|
||||
const accessToken = getAccessToken();
|
||||
// 如果 Authorization 设置为 no-auth,则不携带 Token,用于登录、刷新 Token 等接口
|
||||
if (config.headers.Authorization !== "no-auth" && accessToken) {
|
||||
config.headers.Authorization = accessToken;
|
||||
config.headers.Authorization = `Bearer ${accessToken}`;
|
||||
} else {
|
||||
delete config.headers.Authorization;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ async function handleTokenRefresh(config: InternalAxiosRequestConfig) {
|
||||
return new Promise((resolve) => {
|
||||
// 封装需要重试的请求
|
||||
const retryRequest = () => {
|
||||
config.headers.Authorization = getToken();
|
||||
config.headers.Authorization = getAccessToken();
|
||||
resolve(service(config));
|
||||
};
|
||||
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import { Client } from "@stomp/stompjs";
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
class WebSocketManager {
|
||||
private client: Client | null = null;
|
||||
private messageHandlers: Map<string, ((message: string) => void)[]> = new Map();
|
||||
private reconnectAttempts = 0;
|
||||
private maxReconnectAttempts = 3; // 自定义最大重试次数
|
||||
private reconnectDelay = 5000; // 重试延迟(单位:毫秒)
|
||||
|
||||
// 初始化 WebSocket 客户端
|
||||
setupWebSocket() {
|
||||
const endpoint = import.meta.env.VITE_APP_WS_ENDPOINT;
|
||||
|
||||
// 如果没有配置 WebSocket 端点或显式关闭,直接返回
|
||||
if (!endpoint) {
|
||||
console.log("WebSocket 已被禁用,如需打开请在配置文件中配置 VITE_APP_WS_ENDPOINT");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.client && this.client.connected) {
|
||||
console.log("客户端已存在并且连接正常");
|
||||
return this.client;
|
||||
}
|
||||
|
||||
this.client = new Client({
|
||||
brokerURL: endpoint,
|
||||
connectHeaders: {
|
||||
Authorization: getToken(),
|
||||
},
|
||||
heartbeatIncoming: 30000,
|
||||
heartbeatOutgoing: 30000,
|
||||
reconnectDelay: 0, // 设置为 0 禁用重连
|
||||
onConnect: () => {
|
||||
console.log(`连接到 WebSocket 服务器: ${endpoint}`);
|
||||
this.reconnectAttempts = 0; // 重置重连计数
|
||||
this.messageHandlers.forEach((handlers, topic) => {
|
||||
handlers.forEach((handler) => {
|
||||
this.subscribeToTopic(topic, handler);
|
||||
});
|
||||
});
|
||||
},
|
||||
onStompError: (frame) => {
|
||||
console.error(`连接错误: ${frame.headers["message"]}`);
|
||||
console.error(`错误详情: ${frame.body}`);
|
||||
},
|
||||
onDisconnect: () => {
|
||||
console.log(`WebSocket 连接已断开: ${endpoint}`);
|
||||
this.reconnectAttempts++;
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
console.log(`正在尝试重连... 尝试次数: ${this.reconnectAttempts}`);
|
||||
} else {
|
||||
console.log("重连次数已达上限,停止重连");
|
||||
this.client?.deactivate();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.client.activate();
|
||||
}
|
||||
|
||||
// 订阅主题
|
||||
public subscribeToTopic(topic: string, onMessage: (message: string) => void) {
|
||||
console.log(`正在订阅主题: ${topic}`);
|
||||
if (!this.client || !this.client.connected) {
|
||||
this.setupWebSocket();
|
||||
}
|
||||
|
||||
if (this.messageHandlers.has(topic)) {
|
||||
this.messageHandlers.get(topic)?.push(onMessage);
|
||||
} else {
|
||||
this.messageHandlers.set(topic, [onMessage]);
|
||||
}
|
||||
|
||||
if (this.client?.connected) {
|
||||
this.client.subscribe(topic, (message) => {
|
||||
const handlers = this.messageHandlers.get(topic);
|
||||
handlers?.forEach((handler) => handler(message.body));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 断开 WebSocket 连接
|
||||
public disconnect() {
|
||||
if (this.client) {
|
||||
console.log("断开 WebSocket 连接");
|
||||
this.client.deactivate();
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new WebSocketManager();
|
||||
@@ -13,6 +13,7 @@
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<!-- 输入框允许修改 websocket 地址(注意:修改后不会自动更新已创建的 hook 实例) -->
|
||||
<el-input v-model="socketEndpoint" class="w-220px" />
|
||||
<el-button
|
||||
type="primary"
|
||||
@@ -94,98 +95,88 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Client } from "@stomp/stompjs";
|
||||
|
||||
import { useStomp } from "@/hooks/useStomp";
|
||||
import { getAccessToken } from "@/utils/auth"; // 此处可与 hook 内 getToken 保持一致
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const isConnected = ref(false);
|
||||
// 用于手动调整 WebSocket 地址
|
||||
const socketEndpoint = ref(import.meta.env.VITE_APP_WS_ENDPOINT);
|
||||
|
||||
const receiver = ref("root");
|
||||
|
||||
// 同步连接状态
|
||||
const isConnected = ref(false);
|
||||
// 消息接收列表
|
||||
interface MessageType {
|
||||
type?: string;
|
||||
sender?: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
const messages = ref<MessageType[]>([]);
|
||||
// 广播消息内容
|
||||
const topicMessage = ref("亲爱的朋友们,系统已恢复最新状态。");
|
||||
// 点对点消息内容(默认示例)
|
||||
const queneMessage = ref("Hi, " + userStore.userInfo.username + " 这里是点对点消息示例!");
|
||||
const receiver = ref("root");
|
||||
|
||||
const topicMessage = ref("亲爱的大冤种们,由于一只史诗级的BUG,系统版本已经被迫回退到了0.0.1。"); // 广播消息
|
||||
// 调用 useStomp hook,默认使用 socketEndpoint 和 token(此处用 getAccessToken())
|
||||
const {
|
||||
isConnected: stompConnected,
|
||||
connect,
|
||||
subscribe,
|
||||
disconnect,
|
||||
client,
|
||||
} = useStomp({
|
||||
brokerURL: socketEndpoint.value,
|
||||
token: getAccessToken(),
|
||||
reconnectDelay: 5000,
|
||||
debug: true,
|
||||
});
|
||||
|
||||
const queneMessage = ref(
|
||||
"hi , " + receiver.value + " , 我是" + userStore.userInfo.username + " , 想和你交个朋友 ! "
|
||||
);
|
||||
|
||||
let stompClient: Client;
|
||||
|
||||
function connectWebSocket() {
|
||||
stompClient = new Client({
|
||||
brokerURL: socketEndpoint.value,
|
||||
connectHeaders: {
|
||||
Authorization: getToken(),
|
||||
},
|
||||
debug: (str: any) => {
|
||||
console.log(str);
|
||||
},
|
||||
onConnect: () => {
|
||||
console.log("连接成功");
|
||||
isConnected.value = true;
|
||||
// 同步 hook 的连接状态到组件
|
||||
watch(stompConnected, (newVal) => {
|
||||
isConnected.value = newVal;
|
||||
if (newVal) {
|
||||
// 连接成功后,订阅广播和点对点消息主题
|
||||
subscribe("/topic/notice", (res) => {
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已连接",
|
||||
type: "tip",
|
||||
content: res.body,
|
||||
});
|
||||
|
||||
stompClient.subscribe("/topic/notice", (res: any) => {
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: res.body,
|
||||
});
|
||||
});
|
||||
|
||||
stompClient.subscribe("/user/queue/greeting", (res: any) => {
|
||||
const messageData = JSON.parse(res.body) as MessageType;
|
||||
messages.value.push({
|
||||
sender: messageData.sender,
|
||||
content: messageData.content,
|
||||
});
|
||||
});
|
||||
},
|
||||
onStompError: (frame: any) => {
|
||||
console.error("Broker reported error: " + frame.headers["message"]);
|
||||
console.error("Additional details: " + frame.body);
|
||||
},
|
||||
onDisconnect: () => {
|
||||
isConnected.value = false;
|
||||
});
|
||||
subscribe("/user/queue/greeting", (res) => {
|
||||
const messageData = JSON.parse(res.body) as MessageType;
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已断开",
|
||||
type: "tip",
|
||||
sender: messageData.sender,
|
||||
content: messageData.content,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
stompClient.activate();
|
||||
}
|
||||
|
||||
function disconnectWebSocket() {
|
||||
if (stompClient && stompClient.connected) {
|
||||
stompClient.deactivate();
|
||||
isConnected.value = false;
|
||||
});
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已连接",
|
||||
type: "tip",
|
||||
});
|
||||
} else {
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已断开",
|
||||
type: "tip",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 连接 WebSocket
|
||||
function connectWebSocket() {
|
||||
connect();
|
||||
}
|
||||
|
||||
// 断开 WebSocket
|
||||
function disconnectWebSocket() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
// 发送广播消息
|
||||
function sendToAll() {
|
||||
if (stompClient.connected) {
|
||||
stompClient.publish({
|
||||
if (client && client.connected) {
|
||||
client.publish({
|
||||
destination: "/topic/notice",
|
||||
body: topicMessage.value,
|
||||
});
|
||||
@@ -196,9 +187,10 @@ function sendToAll() {
|
||||
}
|
||||
}
|
||||
|
||||
// 发送点对点消息
|
||||
function sendToUser() {
|
||||
if (stompClient.connected) {
|
||||
stompClient.publish({
|
||||
if (client && client.connected) {
|
||||
client.publish({
|
||||
destination: "/app/sendToUser/" + receiver.value,
|
||||
body: queneMessage.value,
|
||||
});
|
||||
@@ -212,6 +204,10 @@ function sendToUser() {
|
||||
onMounted(() => {
|
||||
connectWebSocket();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
disconnectWebSocket();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -219,40 +215,33 @@ onMounted(() => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.message--sent {
|
||||
align-self: flex-end;
|
||||
background-color: #dcf8c6;
|
||||
}
|
||||
|
||||
.message--received {
|
||||
align-self: flex-start;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.message-sender {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-receiver {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tip-message {
|
||||
align-self: center;
|
||||
padding: 5px 10px;
|
||||
|
||||
Reference in New Issue
Block a user