diff --git a/.env.development b/.env.development index 488868c..a300aa4 100644 --- a/.env.development +++ b/.env.development @@ -13,4 +13,6 @@ VITE_APP_ROUTER_PREFIX = '/' VITE_APP_UPLOAD_URL = '/Common/UploadFile' #socket API -VITE_APP_SOCKET_API = '/msghub' \ No newline at end of file +VITE_APP_SOCKET_API = '/msghub' + +VITE_APP_PBL_API = '/pblhub' \ No newline at end of file diff --git a/.env.production b/.env.production index 56ccea2..0ee27a4 100644 --- a/.env.production +++ b/.env.production @@ -13,6 +13,7 @@ VITE_APP_UPLOAD_URL = '/Common/UploadFile' #socket API VITE_APP_SOCKET_API = '/msghub' +VITE_APP_PBL_API = '/pblhub' # 是否在打包时开启压缩,支持 gzip 和 brotli VITE_BUILD_COMPRESS = gzip \ No newline at end of file diff --git a/.env.staging b/.env.staging index 62f968e..b642ae8 100644 --- a/.env.staging +++ b/.env.staging @@ -15,4 +15,5 @@ VITE_APP_UPLOAD_URL = '/Common/UploadFile' VITE_BUILD_COMPRESS = gzip #socket API -VITE_APP_SOCKET_API = '/msghub' \ No newline at end of file +VITE_APP_SOCKET_API = '/msghub' +VITE_APP_PBL_API = '/pblhub' \ No newline at end of file diff --git a/src/main.js b/src/main.js index b53ef6e..b8ed0f7 100644 --- a/src/main.js +++ b/src/main.js @@ -54,10 +54,11 @@ const app = createApp(App) // 初始化 SignalR 服务,使用环境变量中的 Socket API 地址 signalR.init(import.meta.env.VITE_APP_SOCKET_API) - +import PBLSignalR from '@/signalr/signalr' +PBLSignalR.initPBL(import.meta.env.VITE_APP_PBL_API) // 在应用的全局属性中添加 signalR 实例,以便在应用中的任何地方都可以访问 app.config.globalProperties.signalr = signalR - +app.config.globalProperties.PBLSignalR = PBLSignalR // 全局方法挂载 app.config.globalProperties.getConfigKey = getConfigKey app.config.globalProperties.getDicts = getDicts diff --git a/src/signalr/signalr.js b/src/signalr/signalr.js index 0c3d1df..03c425b 100644 --- a/src/signalr/signalr.js +++ b/src/signalr/signalr.js @@ -8,8 +8,10 @@ import analysis from '@/signalr/analysis' export default { // signalR对象 SR: {}, + PBL_SR: {}, // 失败连接重试次数 failNum: 4, + PBL_failNum: 5, init(url) { var socketUrl = window.location.origin + url + '?clientId=' + cache.local.get('clientId') const connection = new signalR.HubConnectionBuilder() @@ -44,6 +46,7 @@ export default { // 启动 // this.start(); }, + /** * 调用 this.signalR.start().then(async () => { await this.SR.invoke("method")}) * @returns @@ -69,5 +72,58 @@ export default { } return false } + }, + initPBL(url) { + var socketUrl = window.location.origin + url + '?clientId=' + cache.local.get('clientId') + const connection = new signalR.HubConnectionBuilder() + .withUrl(socketUrl, { accessTokenFactory: () => getToken() }) + .withAutomaticReconnect() //自动重新连接 + .configureLogging(signalR.LogLevel.Warning) + .build() + this.PBL_SR = connection + // 断线重连 + connection.onclose(async (error) => { + console.error('PBL后台断开连接了' + error) + console.assert(connection.state === signalR.HubConnectionState.Disconnected) + // 建议用户重新刷新浏览器 + await this.doPblSrStart() + }) + + connection.onreconnected((connectionId) => { + ElMessage({ + message: '与服务器通讯已连接成功', + type: 'success', + duration: 2000 + }) + console.log('断线重新连接成功' + connectionId) + }) + + connection.onreconnecting(async () => { + console.log('断线重新连接中... ') + + await this.doPblSrStart() + }) + }, + async doPblSrStart() { + try { + console.log('PBL_signalR-1', this.PBL_SR.state) + //使用async和await 或 promise的then 和catch 处理来自服务端的异常 + if (this.PBL_SR.state === signalR.HubConnectionState.Disconnected) { + await this.doPblSrStart() + } + + console.log('PBL_signalR-2', this.PBL_SR.state) + return true + } catch (error) { + console.error(error) + this.PBL_failNum-- + // console.log(`失败重试剩余次数${that.PBL_failNum}`, error) + if (this.PBL_failNum > 0 && this.PBL_SR.state.Disconnected) { + setTimeout(async () => { + await this.doPblSrStart() + }, 5000) + } + return false + } } } diff --git a/src/utils/signalR.js b/src/utils/signalR.js index 72770d8..a9f0022 100644 --- a/src/utils/signalR.js +++ b/src/utils/signalR.js @@ -7,6 +7,7 @@ import { Notification } from 'element-ui' export default { // signalR对象 SR: {}, + PBL_SR: {}, // 失败连接重试次数 failNum: 4, baseUrl: '', @@ -73,7 +74,7 @@ export default { title: title, message: data, dangerouslyUseHTMLString: true, - duration: 0, + duration: 0 }) }) // 接收系统通知/公告 @@ -84,5 +85,5 @@ export default { }) connection.on('onlineInfo', () => {}) connection.on('connId', () => {}) - }, + } } diff --git a/src/views/PBL/TVScreen/index.vue b/src/views/PBL/TVScreen/index.vue index 5dc4c3b..0abbba4 100644 --- a/src/views/PBL/TVScreen/index.vue +++ b/src/views/PBL/TVScreen/index.vue @@ -63,6 +63,20 @@ + + + + +
+
+
+
+ +
{{ PBL_bom_except_Message }}
+
+
+
+
@@ -77,7 +91,7 @@ import BoardTable from './components/BoardTable.vue' /// ======================== SignalR ============================== const { proxy } = getCurrentInstance() -const PBL_bom_except_Message = ref('') +const PBL_bom_except_Message = ref('无消息') // 定义 SignalR 监听器和清理函数 function initSignalR() { const handler = (data) => { @@ -90,15 +104,23 @@ function initSignalR() { } try { - console.log('初始化 SignalR PBL_bom_except消息……') - proxy.signalr.SR.on('PBL_bom_except', handler) + console.log('初始化 SignalR PBL_bom_except消息……', proxy.PBLSignalR) + proxy.PBLSignalR.PBL_SR.on('PBL_bom_except', handler) + // proxy.PBLSignalR.doPblSrStart().then(async (res) => { + // if (res) { + // console.log('PBL_bom_except消息已连接', res) + // proxy.PBLSignalR.PBL_SR.on('PBL_bom_except', handler) + // } else { + // console.log('PBL_bom_except已断开连接', res) + // } + // }) } catch (error) { console.error('初始化 SignalR 连接失败:', error) } // 返回一个函数来清理事件监听器 return () => { - proxy.signalr.SR.off('PBL_bom_except', handler) + proxy.PBLSignalR.PBL_SR.off('PBL_bom_except', handler) } } // 在组件挂载时初始化 SignalR 并注册清理函数 @@ -358,4 +380,31 @@ onUnmounted(() => { font-size: 24px; padding: 10px !important; } +.sr-message-box { + width: 100%; + min-height: 280px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 36px; +} +.light-red { + width: 80px; + height: 80px; + border-radius: 90%; + background-color: red; +} +.light-yellow { + width: 80px; + height: 80px; + border-radius: 90%; + background-color: yellow; +} +.light-green { + width: 80px; + height: 80px; + border-radius: 90%; + background-color: green; +} diff --git a/vite.config.js b/vite.config.js index 5f7c63d..d785e3b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,64 +4,69 @@ import createVitePlugins from './vite/plugins' // https://vitejs.dev/config/ export default defineConfig(({ mode, command }) => { - const env = loadEnv(mode, process.cwd()) + const env = loadEnv(mode, process.cwd()) - const alias = { - // 设置路径 - '~': path.resolve(__dirname, './'), - // 设置别名 - '@': path.resolve(__dirname, './src') - } - if (command === 'serve') { - // 解决警告You are running the esm-bundler build of vue-i18n. - alias['vue-i18n'] = 'vue-i18n/dist/vue-i18n.cjs.js' - } - return { - plugins: createVitePlugins(env, command === 'build'), - resolve: { - // https://cn.vitejs.dev/config/#resolve-alias - alias: alias, - // 导入时想要省略的扩展名列表 - // https://cn.vitejs.dev/config/#resolve-extensions - extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] - }, - css: { - devSourcemap: true //开发模式时启用 - }, - base: env.VITE_APP_ROUTER_PREFIX, - // 打包配置 - build: { - sourcemap: command === 'build' ? false : 'inline', - outDir: 'dist', //指定输出目录 - assetsDir: 'assets', //指定静态资源存储目录(相对于outDir) - chunkSizeWarningLimit: 2000, //Adjust the limit to your desired value in KB - // 将js、css文件分离到单独文件夹 - rollupOptions: { - output: { - chunkFileNames: 'static/js/[name]-[hash].js', - entryFileNames: 'static/js/[name]-[hash].js', - assetFileNames: 'static/[ext]/[name]-[hash].[ext]' - } - } - }, - // vite 相关配置 - server: { - port: 8887, - host: true, - open: true, - proxy: { - // https://cn.vitejs.dev/config/#server-proxy - '/dev-api': { - target: env.VITE_APP_API_HOST, - changeOrigin: true, - rewrite: (path) => path.replace(/^\/dev-api/, '') - }, - '/msghub': { - target: env.VITE_APP_API_HOST, - ws: true, - rewrite: (path) => path.replace(/^\/msgHub/, '') - } - } - } - } -}) \ No newline at end of file + const alias = { + // 设置路径 + '~': path.resolve(__dirname, './'), + // 设置别名 + '@': path.resolve(__dirname, './src') + } + if (command === 'serve') { + // 解决警告You are running the esm-bundler build of vue-i18n. + alias['vue-i18n'] = 'vue-i18n/dist/vue-i18n.cjs.js' + } + return { + plugins: createVitePlugins(env, command === 'build'), + resolve: { + // https://cn.vitejs.dev/config/#resolve-alias + alias: alias, + // 导入时想要省略的扩展名列表 + // https://cn.vitejs.dev/config/#resolve-extensions + extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] + }, + css: { + devSourcemap: true //开发模式时启用 + }, + base: env.VITE_APP_ROUTER_PREFIX, + // 打包配置 + build: { + sourcemap: command === 'build' ? false : 'inline', + outDir: 'dist', //指定输出目录 + assetsDir: 'assets', //指定静态资源存储目录(相对于outDir) + chunkSizeWarningLimit: 2000, //Adjust the limit to your desired value in KB + // 将js、css文件分离到单独文件夹 + rollupOptions: { + output: { + chunkFileNames: 'static/js/[name]-[hash].js', + entryFileNames: 'static/js/[name]-[hash].js', + assetFileNames: 'static/[ext]/[name]-[hash].[ext]' + } + } + }, + // vite 相关配置 + server: { + port: 8887, + host: true, + open: true, + proxy: { + // https://cn.vitejs.dev/config/#server-proxy + '/dev-api': { + target: env.VITE_APP_API_HOST, + changeOrigin: true, + rewrite: (path) => path.replace(/^\/dev-api/, '') + }, + '/msghub': { + target: env.VITE_APP_API_HOST, + ws: true, + rewrite: (path) => path.replace(/^\/msgHub/, '') + }, + '/pblhub': { + target: env.VITE_APP_API_HOST, + ws: true, + rewrite: (path) => path.replace(/^\/pblHub/, '') + } + } + } + } +})