useSocketBus.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { ref, reactive } from 'vue'
  2. import { useWebSocket } from '@vueuse/core'
  3. type EventHandler = (data: any) => void
  4. export function useSocketBus(deviceCode: string) {
  5. const url = `${import.meta.env.VITE_BASE_URL}/ws/${deviceCode}`
  6. // const url = `ws://192.168.188.149:8080/ws/${deviceCode}`
  7. // 响应式状态
  8. const status = ref<'CONNECTING' | 'OPEN' | 'CLOSED'>('CLOSED')
  9. const messages = ref<any[]>([])
  10. // 事件总线
  11. const events: Record<string, EventHandler[]> = reactive({})
  12. // 创建 WebSocket
  13. const { ws, open, close, send } = useWebSocket(url, {
  14. immediate: false,
  15. autoReconnect: {
  16. retries: 5,
  17. delay: 1000
  18. },
  19. onConnected(_ws) {
  20. console.log('✅ WebSocket 已连接')
  21. status.value = 'OPEN'
  22. },
  23. onDisconnected() {
  24. console.log('🔌 WebSocket 已断开')
  25. status.value = 'CLOSED'
  26. },
  27. onMessage(_ws, event) {
  28. try {
  29. const msg = JSON.parse(event.data)
  30. messages.value.push(msg)
  31. if (msg.event && events[msg.event]) {
  32. events[msg.event].forEach((cb) => cb(msg.data))
  33. }
  34. anyHandlers.forEach((cb) => cb(msg))
  35. } catch (err) {
  36. console.warn('非 JSON 消息:', event.data)
  37. }
  38. }
  39. })
  40. const anyHandlers: EventHandler[] = reactive([])
  41. // 注册所有事件回调
  42. function onAny(cb: EventHandler) {
  43. anyHandlers.push(cb)
  44. }
  45. // 注册事件
  46. function on(eventName: string, cb: EventHandler) {
  47. if (!events[eventName]) events[eventName] = []
  48. events[eventName].push(cb)
  49. }
  50. // 注销事件
  51. function off(eventName: string, cb?: EventHandler) {
  52. if (!cb) {
  53. events[eventName] = []
  54. } else {
  55. events[eventName] = (events[eventName] || []).filter((fn) => fn !== cb)
  56. }
  57. }
  58. // 发送带事件名的消息
  59. function sendEvent(eventName: string, data: any) {
  60. if (ws.value?.readyState === WebSocket.OPEN) {
  61. send(JSON.stringify({ event: eventName, data }))
  62. } else {
  63. console.warn('⚠️ WebSocket 未连接')
  64. }
  65. }
  66. return { ws, status, messages, on, off, sendEvent, open, close, onAny }
  67. }
  68. export const formatIotValue = (val: any) => {
  69. if (val === null || val === undefined) return { value: '0', isText: true }
  70. const strVal = String(val)
  71. if (!/\d/.test(strVal)) {
  72. return { value: strVal, isText: true }
  73. }
  74. const match = strVal.match(/^(-?\d+(?:\.\d+)?)(.*)$/)
  75. if (match) {
  76. return {
  77. value: match[1],
  78. suffix: match[2] || '',
  79. isText: false
  80. }
  81. }
  82. return { value: strVal, isText: true }
  83. }
  84. export interface HeaderItem {
  85. label: string
  86. key: string
  87. judgment?: boolean
  88. }
  89. export interface Dimensions {
  90. identifier: string
  91. name: string
  92. value: string | number
  93. color: string
  94. bgHover: string
  95. bgActive: string
  96. response?: boolean
  97. suffix?: string
  98. isText?: boolean
  99. minValue?: number
  100. maxValue?: number
  101. id?: number
  102. }