🎨 organize websocket code structure
This commit is contained in:
@@ -16,5 +16,4 @@ VITE_TITLE_NAME='五味子云相册'
|
|||||||
VITE_APP_TOKEN_KEY='Bearer'
|
VITE_APP_TOKEN_KEY='Bearer'
|
||||||
|
|
||||||
# the websocket url
|
# the websocket url
|
||||||
#VITE_WEB_SOCKET_URL='ws://127.0.0.1:80/api/ws/gws'
|
VITE_WEB_SOCKET_URL='ws://127.0.0.1:80/api/ws/gws'
|
||||||
VITE_WEB_SOCKET_URL='wss://landaiqing.cn/api/ws/gws'
|
|
||||||
|
@@ -7,7 +7,7 @@ VITE_APP_BASE_API='/sys'
|
|||||||
VITE_APP_TITLE=生产环境
|
VITE_APP_TITLE=生产环境
|
||||||
|
|
||||||
# 网络请求公用地址
|
# 网络请求公用地址
|
||||||
VITE_API_BASE_URL='http://127.0.0.1:80'
|
VITE_API_BASE_URL='https://landaiqing.cn'
|
||||||
|
|
||||||
VITE_TITLE_NAME='五味子云相册'
|
VITE_TITLE_NAME='五味子云相册'
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ import {useThemeStore} from "@/store/modules/themeStore.ts";
|
|||||||
import {langStore} from "@/store/modules/langStore.ts";
|
import {langStore} from "@/store/modules/langStore.ts";
|
||||||
import {useClientStore} from "@/store/modules/clientStore.ts";
|
import {useClientStore} from "@/store/modules/clientStore.ts";
|
||||||
import {useCommentStore} from "@/store/modules/commentStore.ts";
|
import {useCommentStore} from "@/store/modules/commentStore.ts";
|
||||||
|
import {useWebSocketStore} from "@/store/modules/websocketStore.ts";
|
||||||
|
|
||||||
export default function useStore() {
|
export default function useStore() {
|
||||||
return {
|
return {
|
||||||
@@ -11,5 +12,6 @@ export default function useStore() {
|
|||||||
lang: langStore(),
|
lang: langStore(),
|
||||||
client: useClientStore(),
|
client: useClientStore(),
|
||||||
comment: useCommentStore(),
|
comment: useCommentStore(),
|
||||||
|
websocket: useWebSocketStore(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
45
src/store/modules/websocketStore.ts
Normal file
45
src/store/modules/websocketStore.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// useWebSocketStore.ts
|
||||||
|
import {defineStore} from 'pinia';
|
||||||
|
import {onUnmounted, reactive} from 'vue';
|
||||||
|
import {WebSocketService} from '@/utils/websocket/websocket.ts';
|
||||||
|
|
||||||
|
type MessageCallback = (data: any) => void;
|
||||||
|
type EventCallback = () => void;
|
||||||
|
export const useWebSocketStore = defineStore('websocket', () => {
|
||||||
|
const state = reactive({
|
||||||
|
wsService: null as WebSocketService | null,
|
||||||
|
});
|
||||||
|
|
||||||
|
function initialize(options: { url: string; protocols?: string | string[]; reconnectTimeout?: number }) {
|
||||||
|
state.wsService = new WebSocketService(options);
|
||||||
|
state.wsService.open();
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
state.wsService?.close(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage(data: any) {
|
||||||
|
state.wsService?.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function on(event: 'message', callback: MessageCallback) {
|
||||||
|
state.wsService?.on(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEvent(event: 'open' | 'error' | 'close', callback: EventCallback) {
|
||||||
|
state.wsService?.on(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
state.wsService?.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialize,
|
||||||
|
sendMessage,
|
||||||
|
on,
|
||||||
|
onEvent,
|
||||||
|
close,
|
||||||
|
};
|
||||||
|
});
|
@@ -1,6 +1,4 @@
|
|||||||
// src/utils/websocket.ts
|
// WebSocketService.ts
|
||||||
import {onUnmounted} from 'vue';
|
|
||||||
|
|
||||||
interface WebSocketOptions {
|
interface WebSocketOptions {
|
||||||
url: string;
|
url: string;
|
||||||
protocols?: string | string[];
|
protocols?: string | string[];
|
||||||
@@ -10,14 +8,13 @@ interface WebSocketOptions {
|
|||||||
type MessageCallback = (data: any) => void;
|
type MessageCallback = (data: any) => void;
|
||||||
type EventCallback = () => void;
|
type EventCallback = () => void;
|
||||||
|
|
||||||
class WebSocketService {
|
export class WebSocketService {
|
||||||
private ws: WebSocket | null = null;
|
private ws: WebSocket | null = null;
|
||||||
private callbacks: { [key: string]: (MessageCallback | EventCallback)[] } = {};
|
private callbacks: { [key: string]: (MessageCallback | EventCallback)[] } = {};
|
||||||
private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔
|
private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔
|
||||||
private heartbeatIntervalMs: number = 5000; // 默认5秒心跳间隔
|
private heartbeatIntervalMs: number = 5000; // 默认5秒心跳间隔
|
||||||
|
|
||||||
constructor(private options: WebSocketOptions) {
|
constructor(private options: WebSocketOptions) {}
|
||||||
}
|
|
||||||
|
|
||||||
public open(): void {
|
public open(): void {
|
||||||
this.ws = new WebSocket(this.options.url, this.options.protocols);
|
this.ws = new WebSocket(this.options.url, this.options.protocols);
|
||||||
@@ -25,6 +22,7 @@ class WebSocketService {
|
|||||||
this.ws.addEventListener('message', this.handleMessage);
|
this.ws.addEventListener('message', this.handleMessage);
|
||||||
this.ws.addEventListener('error', this.handleError);
|
this.ws.addEventListener('error', this.handleError);
|
||||||
this.ws.addEventListener('close', this.handleClose);
|
this.ws.addEventListener('close', this.handleClose);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
this.send("ping");
|
this.send("ping");
|
||||||
@@ -55,7 +53,6 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleOpen = (): void => {
|
private handleOpen = (): void => {
|
||||||
console.log('WebSocket连接已建立');
|
|
||||||
if (this.callbacks.open) {
|
if (this.callbacks.open) {
|
||||||
this.callbacks.open.forEach((cb) => (cb as EventCallback)());
|
this.callbacks.open.forEach((cb) => (cb as EventCallback)());
|
||||||
}
|
}
|
||||||
@@ -63,7 +60,6 @@ class WebSocketService {
|
|||||||
|
|
||||||
private handleMessage = (event: MessageEvent): void => {
|
private handleMessage = (event: MessageEvent): void => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
console.log('WebSocket接收到消息:', data);
|
|
||||||
if (this.callbacks.message) {
|
if (this.callbacks.message) {
|
||||||
this.callbacks.message.forEach((cb) => (cb as MessageCallback)(data));
|
this.callbacks.message.forEach((cb) => (cb as MessageCallback)(data));
|
||||||
}
|
}
|
||||||
@@ -94,19 +90,3 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useWebSocket(options: WebSocketOptions) {
|
|
||||||
const wsService = new WebSocketService(options);
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
wsService.close(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
open: wsService.open.bind(wsService),
|
|
||||||
close: wsService.close.bind(wsService),
|
|
||||||
reconnect: wsService.reconnect.bind(wsService),
|
|
||||||
on: wsService.on.bind(wsService),
|
|
||||||
send: wsService.send.bind(wsService)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@@ -11,17 +11,37 @@ import {useRequest} from "alova/client";
|
|||||||
import {getUserPermissions} from "@/api/user";
|
import {getUserPermissions} from "@/api/user";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import CommentReply from "@/components/CommentReply/index.vue";
|
import CommentReply from "@/components/CommentReply/index.vue";
|
||||||
|
import {h, onMounted} from "vue";
|
||||||
|
import {notification} from "ant-design-vue";
|
||||||
|
import {SmileOutlined} from "@ant-design/icons-vue";
|
||||||
|
|
||||||
|
const websocket = useStore().websocket;
|
||||||
|
const userInfo = useStore().user;
|
||||||
const {data, send} = useRequest(getUserPermissions, {
|
const {data, send} = useRequest(getUserPermissions, {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
const userInfo = useStore().user;
|
|
||||||
const userId: string = userInfo.user.uid;
|
const userId: string = userInfo.user.uid;
|
||||||
send(userId);
|
send(userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const wsOptions = {
|
||||||
|
url: import.meta.env.VITE_WEB_SOCKET_URL + "?client_id=" + userInfo.user.uid,
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
websocket.initialize(wsOptions);
|
||||||
|
websocket.on("message", async (data: any) => {
|
||||||
|
notification.open({
|
||||||
|
message: '消息来了',
|
||||||
|
description:
|
||||||
|
data,
|
||||||
|
icon: () => h(SmileOutlined, {style: 'color: #108ee9'}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -58,9 +58,9 @@ import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
|||||||
import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue";
|
import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue";
|
||||||
import {useRouter} from 'vue-router';
|
import {useRouter} from 'vue-router';
|
||||||
import {generateQrCode} from "@/api/oauth/wechat.ts";
|
import {generateQrCode} from "@/api/oauth/wechat.ts";
|
||||||
import {onMounted, onUnmounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import logo from "@/assets/svgs/logo-schisandra.svg";
|
import logo from "@/assets/svgs/logo-schisandra.svg";
|
||||||
import useWebSocket from "@/utils/websocket/websocket.ts";
|
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import {message} from "ant-design-vue";
|
import {message} from "ant-design-vue";
|
||||||
import {generateClientId, getUserDevice} from "@/api/oauth";
|
import {generateClientId, getUserDevice} from "@/api/oauth";
|
||||||
@@ -71,6 +71,7 @@ const router = useRouter();
|
|||||||
const client = useStore().client;
|
const client = useStore().client;
|
||||||
const qrcode = ref<string>('');
|
const qrcode = ref<string>('');
|
||||||
const status = ref<string>('loading');
|
const status = ref<string>('loading');
|
||||||
|
const websocket = useStore().websocket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取client_id
|
* 获取client_id
|
||||||
@@ -119,15 +120,14 @@ const wsOptions = {
|
|||||||
url: import.meta.env.VITE_WEB_SOCKET_URL + "?client_id=" + getLocalClientId(),
|
url: import.meta.env.VITE_WEB_SOCKET_URL + "?client_id=" + getLocalClientId(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const {open, close, on} = useWebSocket(wsOptions);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听消息
|
* 监听消息
|
||||||
*/
|
*/
|
||||||
async function handleListenMessage() {
|
async function handleListenMessage() {
|
||||||
open();
|
websocket.initialize(wsOptions);
|
||||||
// 注册消息接收处理函数
|
// 注册消息接收处理函数
|
||||||
on('message', async (data: any) => {
|
websocket.on('message', async (data: any) => {
|
||||||
if (data.code === 200 && data.data) {
|
if (data.code === 200 && data.data) {
|
||||||
const user = useStore().user;
|
const user = useStore().user;
|
||||||
const {access_token, refresh_token, uid, expires_at} = data.data;
|
const {access_token, refresh_token, uid, expires_at} = data.data;
|
||||||
@@ -148,10 +148,6 @@ async function handleListenMessage() {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getQrCode();
|
await getQrCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(async () => {
|
|
||||||
close(true);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style src="./index.scss" scoped>
|
<style src="./index.scss" scoped>
|
||||||
@import "@/assets/styles/global.scss";
|
@import "@/assets/styles/global.scss";
|
||||||
|
Reference in New Issue
Block a user