diff --git a/.env.development b/.env.development index fcfd516..086d1fa 100644 --- a/.env.development +++ b/.env.development @@ -9,4 +9,7 @@ VITE_APP_BASE_API = '/dev-api' VITE_APP_ROUTER_PREFIX = '/' # 默认上传地址 -VITE_APP_UPLOAD_URL = '/Common/UploadFile' \ No newline at end of file +VITE_APP_UPLOAD_URL = '/Common/UploadFile' + +#socket API +VITE_APP_SOCKET_API = 'http://localhost:8888/msghub' \ No newline at end of file diff --git a/.env.production b/.env.production index 044da0c..069cc48 100644 --- a/.env.production +++ b/.env.production @@ -10,3 +10,6 @@ VITE_APP_ROUTER_PREFIX = '/' # 默认上传地址 VITE_APP_UPLOAD_URL = '/Common/UploadFile' + +#socket API +VITE_APP_SOCKET_API = '/msghub' \ No newline at end of file diff --git a/.env.staging b/.env.staging index 47b99fd..62f968e 100644 --- a/.env.staging +++ b/.env.staging @@ -12,4 +12,7 @@ VITE_APP_ROUTER_PREFIX = '/' VITE_APP_UPLOAD_URL = '/Common/UploadFile' # 是否在打包时开启压缩,支持 gzip 和 brotli -VITE_BUILD_COMPRESS = gzip \ No newline at end of file +VITE_BUILD_COMPRESS = gzip + +#socket API +VITE_APP_SOCKET_API = '/msghub' \ No newline at end of file diff --git a/package.json b/package.json index 02e1173..af02d37 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@element-plus/icons-vue": "0.2.4", + "@microsoft/signalr": "^6.0.4", "axios": "0.24.0", "clipboard": "^2.0.10", "echarts": "5.2.2", diff --git a/src/App.vue b/src/App.vue index 98240ae..2fec866 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,3 +1,22 @@ + diff --git a/src/main.js b/src/main.js index d39632d..d3acb01 100644 --- a/src/main.js +++ b/src/main.js @@ -14,6 +14,7 @@ import directive from './directive' // directive // 注册指令 import plugins from './plugins' // plugins // import { download } from '@/utils/request' +import signalR from '@/utils/signalR' // svg图标 import 'virtual:svg-icons-register' @@ -42,7 +43,9 @@ import TreeSelect from '@/components/TreeSelect' import DictTag from '@/components/DictTag' const app = createApp(App) - +signalR.init( + import.meta.env.VITE_APP_SOCKET_API) +app.config.globalProperties.signalr = signalR // 全局方法挂载 app.config.globalProperties.getConfigKey = getConfigKey app.config.globalProperties.getDicts = getDicts diff --git a/src/store/getters.js b/src/store/getters.js index 87d7e85..52841cf 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -16,6 +16,7 @@ const getters = { topbarRouters: state => state.permission.topbarRouters, defaultRoutes: state => state.permission.defaultRoutes, sidebarRouters: state => state.permission.sidebarRouters, - onlineUserNum: state => 0 + onlineUserNum: state => state.socket.onlineNum, + noticeList: state => state.socket.noticeList } export default getters \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index d441545..4836b28 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -5,6 +5,7 @@ import tagsView from './modules/tagsView' import permission from './modules/permission' import settings from './modules/settings' import getters from './getters' +import socket from './modules/socket' const store = createStore({ modules: { @@ -12,7 +13,8 @@ const store = createStore({ user, tagsView, permission, - settings + settings, + socket }, getters }); diff --git a/src/store/modules/socket.js b/src/store/modules/socket.js new file mode 100644 index 0000000..5d9935b --- /dev/null +++ b/src/store/modules/socket.js @@ -0,0 +1,30 @@ +const state = { + onlineNum: 0, + noticeList: [] +} +const mutations = { + SET_ONLINEUSER_NUM: (state, num) => { + state.onlineNum = num + }, + SET_NOTICE_list: (state, data) => { + state.noticeList = data; + } +} + +const actions = { + //更新在线人数 + changeOnlineNum({ commit }, data) { + commit('SET_ONLINEUSER_NUM', data) + }, + // 更新系统通知 + getNoticeList({ commit }, data) { + commit('SET_NOTICE_list', data) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} \ No newline at end of file diff --git a/src/utils/signalR.js b/src/utils/signalR.js new file mode 100644 index 0000000..f105071 --- /dev/null +++ b/src/utils/signalR.js @@ -0,0 +1,87 @@ +// 官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio +import * as signalR from '@microsoft/signalr' +import store from '../store' +import { getToken } from '@/utils/auth' +import { ElNotification } from 'element-plus' + +export default { + // signalR对象 + SR: {}, + // 失败连接重试次数 + failNum: 4, + baseUrl: '', + init(url) { + console.log(url); + const connection = new signalR.HubConnectionBuilder() + .withUrl(url, { accessTokenFactory: () => getToken() }) + .withAutomaticReconnect()//自动重新连接 + .configureLogging(signalR.LogLevel.Information) + .build(); + this.SR = connection; + // 断线重连 + connection.onclose(async () => { + console.log('断开连接了') + console.assert(connection.state === signalR.HubConnectionState.Disconnected); + // 建议用户重新刷新浏览器 + await this.start(); + }) + + connection.onreconnected(() => { + console.log('断线重新连接成功') + }) + this.receiveMsg(connection); + // 启动 + // this.start(); + }, + /** + * 调用 this.signalR.start().then(async () => { await this.SR.invoke("method")}) + * @returns + */ + async start() { + var that = this; + + try { + //使用async和await 或 promise的then 和catch 处理来自服务端的异常 + await this.SR.start(); + //console.assert(this.SR.state === signalR.HubConnectionState.Connected); + console.log('signalR 连接成功了', this.SR.state); + return true; + } catch (error) { + that.failNum--; + console.log(`失败重试剩余次数${that.failNum}`, error) + if (that.failNum > 0) { + setTimeout(async () => { + await this.SR.start() + }, 5000); + } + return false; + } + }, + // 接收消息处理 + receiveMsg(connection) { + connection.on("onlineNum", (data) => { + store.dispatch("socket/changeOnlineNum", data); + }); + // 接收欢迎语 + connection.on("welcome", (data) => { + console.log('welcome', data) + ElNotification.info(data) + }); + // 接收后台手动推送消息 + connection.on("receiveNotice", (title, data) => { + ElNotification({ + type: 'info', + title: title, + message: data, + dangerouslyUseHTMLString: true, + duration: 0 + }) + }) + // 接收系统通知/公告 + connection.on("moreNotice", (data) => { + if (data.code == 200) { + store.dispatch("socket/getNoticeList", data.data); + } + }) + } +} \ No newline at end of file