diff --git a/apps/web-antd/.env.development b/apps/web-antd/.env.development index d522a706..aa18ed97 100644 --- a/apps/web-antd/.env.development +++ b/apps/web-antd/.env.development @@ -20,6 +20,8 @@ VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj6 VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= # 客户端id VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e +# 开启WEBSOCKET +VITE_APP_WEBSOCKET=true # 开启SSE VITE_GLOB_SSE_ENABLE=true diff --git a/apps/web-antd/.env.production b/apps/web-antd/.env.production index d228ac48..a26175cd 100644 --- a/apps/web-antd/.env.production +++ b/apps/web-antd/.env.production @@ -26,6 +26,8 @@ VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj6 VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= # 客户端id VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e +# 开启WEBSOCKET +VITE_APP_WEBSOCKET=true # 开启SSE VITE_GLOB_SSE_ENABLE=true diff --git a/apps/web-antd/src/api/property/energyManagement/meterInfo/index.ts b/apps/web-antd/src/api/property/energyManagement/meterInfo/index.ts index bf722395..b6af3266 100644 --- a/apps/web-antd/src/api/property/energyManagement/meterInfo/index.ts +++ b/apps/web-antd/src/api/property/energyManagement/meterInfo/index.ts @@ -72,5 +72,5 @@ export function queryTree(params?: any) { * 获取水/电/气表当前读数/状态 */ export function currentReading(params?: any) { - return requestClient.get(`/property/meterInfo/currentReading`, { params }) + return requestClient.get(`/property/meterInfo/currentReading`, { params }) } \ No newline at end of file diff --git a/apps/web-antd/src/api/websocket.ts b/apps/web-antd/src/api/websocket.ts new file mode 100644 index 00000000..8a136fbb --- /dev/null +++ b/apps/web-antd/src/api/websocket.ts @@ -0,0 +1,162 @@ +import { useAccessStore } from '@vben/stores'; + +interface WebSocketCallbacks { + onOpen?: (event: Event) => void; + onMessage?: (event: MessageEvent) => void; + onError?: (error: Event) => void; + onClose?: (event: CloseEvent) => void; +} + +export default class WebSocketService { + private webSocket: WebSocket | null = null; + private webSocketURL: string = ''; + + // 默认回调函数 + private onOpenCallback: (event: Event) => void; + private onMessageCallback: (event: MessageEvent) => void; + private onErrorCallback: (error: Event) => void; + private onCloseCallback: (event: CloseEvent) => void; + + constructor(callbacks?: WebSocketCallbacks) { + // 设置回调函数,使用自定义回调或默认回调 + this.onOpenCallback = callbacks?.onOpen || this.defaultOnOpen; + this.onMessageCallback = callbacks?.onMessage || this.defaultOnMessage; + this.onErrorCallback = callbacks?.onError || this.defaultOnError; + this.onCloseCallback = callbacks?.onClose || this.defaultOnClose; + } + + // 初始化WebSocket连接 + initWebSocket(webSocketURL: string): void { + this.webSocketURL = webSocketURL; + try { + this.webSocket = new WebSocket(webSocketURL); + + this.webSocket.onopen = this.onOpenCallback; + this.webSocket.onmessage = this.onMessageCallback; + this.webSocket.onerror = this.onErrorCallback; + this.webSocket.onclose = this.onCloseCallback; + } catch (error) { + console.error('Failed to initialize WebSocket:', error); + } + } + + // 设置onOpen回调并更新WebSocket事件处理器 + setOnOpenCallback(callback: (event: Event) => void): void { + this.onOpenCallback = callback; + if (this.webSocket) { + this.webSocket.onopen = this.onOpenCallback; + } + } + + // 设置onMessage回调并更新WebSocket事件处理器 + setOnMessageCallback(callback: (event: MessageEvent) => void): void { + this.onMessageCallback = callback; + if (this.webSocket) { + this.webSocket.onmessage = this.onMessageCallback; + } + } + + // 设置onError回调并更新WebSocket事件处理器 + setOnErrorCallback(callback: (error: Event) => void): void { + this.onErrorCallback = callback; + if (this.webSocket) { + this.webSocket.onerror = this.onErrorCallback; + } + } + + // 设置onClose回调并更新WebSocket事件处理器 + setOnCloseCallback(callback: (event: CloseEvent) => void): void { + this.onCloseCallback = callback; + if (this.webSocket) { + this.webSocket.onclose = this.onCloseCallback; + } + } + + // 默认连接建立成功的回调 + private defaultOnOpen(event: Event): void { + console.log('WebSocket连接建立成功', event); + } + + // 默认收到服务器消息的回调 + private defaultOnMessage(event: MessageEvent): void { + console.log('收到服务器消息', event.data); + // 通常这里会解析数据并更新页面 + // const data = JSON.parse(event.data); + // 根据消息类型处理不同业务... + } + + // 默认发生错误的回调 + private defaultOnError(error: Event): void { + console.error('WebSocket连接错误', error); + } + + // 默认连接关闭的回调 + private defaultOnClose(event: CloseEvent): void { + console.log('WebSocket连接关闭', event); + } + + // 关闭连接 + close(): void { + if (this.webSocket) { + this.webSocket.close(); + this.webSocket = null; + } + } + + // 发送消息 + sendMessage(message: string | object): void { + if (this.webSocket && this.webSocket.readyState === WebSocket.OPEN) { + const dataToSend = typeof message === 'string' ? message : JSON.stringify(message); + this.webSocket.send(dataToSend); + } else { + console.error('WebSocket连接未就绪'); + } + } + + // 获取当前WebSocket状态 + getReadyState(): number | null { + return this.webSocket ? this.webSocket.readyState : null; + } + + // 获取WebSocket URL + getWebSocketURL(): string { + return this.webSocketURL; + } + + // 重新连接 + reconnect(): void { + if (this.webSocketURL) { + this.close(); + this.initWebSocket(this.webSocketURL); + } + } +} + +// 创建一个可导出的WebSocket实例 +let globalWebSocketService: WebSocketService | null = null; + +/** + * 初始化WebSocket连接的可导出方法 + * @param url WebSocket服务器地址 + * @param callbacks 回调函数对象(可选) + * @returns WebSocketService实例 + */ +export function initWebSocket(callbacks?: WebSocketCallbacks): void { + if (!globalWebSocketService) { + globalWebSocketService = new WebSocketService(callbacks); + } + const accessStore = useAccessStore(); + const clinetId = import.meta.env.VITE_GLOB_APP_CLIENT_ID; + const api = import.meta.env.VITE_GLOB_API_URL; + const host = window.location.host; + const url = `ws://${host}${api}/resource/websocket?clientid=${clinetId}&Authorization=Bearer ${accessStore.accessToken}`; + globalWebSocketService.initWebSocket(url); +} + +/** + * 获取全局WebSocket服务实例 + * @returns WebSocketService实例或null + */ +export function getWebSocketService(): WebSocketService | null { + return globalWebSocketService; +} \ No newline at end of file diff --git a/apps/web-antd/src/bootstrap.ts b/apps/web-antd/src/bootstrap.ts index 45d2df24..e1c883d1 100644 --- a/apps/web-antd/src/bootstrap.ts +++ b/apps/web-antd/src/bootstrap.ts @@ -1,30 +1,31 @@ -import { createApp, watchEffect } from 'vue'; +import { createApp, watchEffect } from 'vue' -import { registerAccessDirective } from '@vben/access'; -import { registerLoadingDirective } from '@vben/common-ui/es/loading'; -import { preferences } from '@vben/preferences'; -import { initStores } from '@vben/stores'; -import '@vben/styles'; -import '@vben/styles/antd'; +import { registerAccessDirective } from '@vben/access' +import { registerLoadingDirective } from '@vben/common-ui/es/loading' +import { preferences } from '@vben/preferences' +import { initStores } from '@vben/stores' +import '@vben/styles' +import '@vben/styles/antd' -import { useTitle } from '@vueuse/core'; +import { useTitle } from '@vueuse/core' -import { setupGlobalComponent } from '#/components/global'; -import { $t, setupI18n } from '#/locales'; +import { setupGlobalComponent } from '#/components/global' +import { $t, setupI18n } from '#/locales' -import { initComponentAdapter } from './adapter/component'; -import { initSetupVbenForm } from './adapter/form'; -import App from './app.vue'; -import { router } from './router'; +import { initComponentAdapter } from './adapter/component' +import { initSetupVbenForm } from './adapter/form' +import App from './app.vue' +import { router } from './router' +import { initWebSocket } from '#/api/websocket' async function bootstrap(namespace: string) { // 初始化组件适配器 - await initComponentAdapter(); + await initComponentAdapter() // 初始化表单组件 - await initSetupVbenForm(); + await initSetupVbenForm() // // 设置弹窗的默认配置 // setDefaultModalProps({ @@ -35,49 +36,53 @@ async function bootstrap(namespace: string) { // zIndex: 1020, // }); - const app = createApp(App); + + const app = createApp(App) // 全局组件 - setupGlobalComponent(app); + setupGlobalComponent(app) // 注册v-loading指令 registerLoadingDirective(app, { loading: 'loading', // 在这里可以自定义指令名称,也可以明确提供false表示不注册这个指令 spinning: 'spinning', - }); + }) // 国际化 i18n 配置 - await setupI18n(app); + await setupI18n(app) // 配置 pinia-tore - await initStores(app, { namespace }); + await initStores(app, { namespace }) + + // 初始化WebSocket + initWebSocket() // 安装权限指令 - registerAccessDirective(app); + registerAccessDirective(app) // 初始化 tippy - const { initTippy } = await import('@vben/common-ui/es/tippy'); - initTippy(app); + const { initTippy } = await import('@vben/common-ui/es/tippy') + initTippy(app) // 配置路由及路由守卫 - app.use(router); + app.use(router) // 配置Motion插件 - const { MotionPlugin } = await import('@vben/plugins/motion'); - app.use(MotionPlugin); + const { MotionPlugin } = await import('@vben/plugins/motion') + app.use(MotionPlugin) // 动态更新标题 watchEffect(() => { if (preferences.app.dynamicTitle) { - const routeTitle = router.currentRoute.value.meta?.title; + const routeTitle = router.currentRoute.value.meta?.title const pageTitle = - (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name; - useTitle(pageTitle); + (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name + useTitle(pageTitle) } - }); + }) - app.mount('#app'); + app.mount('#app') } -export { bootstrap }; +export { bootstrap } diff --git a/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue b/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue index c4a2fef2..4b6b1c7d 100644 --- a/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue +++ b/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue @@ -1,13 +1,44 @@