Zimo 14 時間 前
コミット
3bf0be0ebb
2 ファイル変更216 行追加0 行削除
  1. 122 0
      src/utils/mqtt.ts
  2. 94 0
      src/views/pms/mqtt/mqtt.vue

+ 122 - 0
src/utils/mqtt.ts

@@ -0,0 +1,122 @@
+import { ElMessage } from 'element-plus'
+import mqtt, { MqttClient, IClientOptions, IClientSubscribeOptions } from 'mqtt' // 静态导入 mqtt
+
+// 定义 MQTT 配置类型接口
+interface MqttConfig {
+  host: string
+  options: IClientOptions
+  topic: string
+}
+
+// 定义消息回调函数类型
+type MessageCallback = (data: { topic: string; message: Record<string, any> }) => void
+
+// MQTT 连接配置
+const MQTT_CONFIG: MqttConfig = {
+  // 替换为你的 MQTT 服务器地址(ws/wss 协议)
+  host: 'ws://172.21.10.65:8083/mqtt',
+  // MQTT 连接选项
+  options: {
+    username: 'yanfan', // 替换为你的用户名(无则省略)
+    password: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjY0YmM2NjJlLWZhMjQtNGY1Ny1hOTk1LWZiMGM2YjNhYzI4OCJ9.9nxoDUNGTk1szRlZHHG0AcWZctLrzJ16UA5rsBagHNcD10PC-LIMTgAr2CK1Ppafa6cW5XPdn7RqBF6iZjHtww', // 替换为你的密码(无则省略)
+    clean: true,
+    reconnectPeriod: 5000, // 重连间隔 5 秒
+    clientId: 'web-' + Math.random().toString(16).substr(2),
+    connectTimeout: 10000, // 连接超时 10 秒
+  },
+  // 要监听的主题
+  topic: '/657/YF1562/property/post'
+}
+
+// 创建 MQTT 客户端实例(添加类型注解)
+let client: MqttClient | null = null
+// 消息回调函数
+let messageCallback: MessageCallback | null = null
+
+/**
+ * 初始化 MQTT 连接
+ * @param callback 接收消息的回调函数
+ */
+export const initMqtt = (callback: MessageCallback): void => {
+  // 保存消息回调
+  messageCallback = callback
+
+  // 避免重复连接
+  if (client && client.connected) {
+    ElMessage.info('MQTT 已连接')
+    return
+  }
+
+  try {
+    // 直接使用静态导入的 mqtt 创建连接(核心修复点)
+    client = mqtt.connect(MQTT_CONFIG.host, MQTT_CONFIG.options)
+
+    // 连接成功
+    client.on('connect', () => {
+      ElMessage.success('MQTT 连接成功')
+      // 订阅指定主题
+      const subscribeOptions: IClientSubscribeOptions = { qos: 0 }
+      client?.subscribe(MQTT_CONFIG.topic, subscribeOptions, (err) => {
+        if (err) {
+          ElMessage.error(`订阅主题失败:${err.message}`)
+        } else {
+          ElMessage.info(`已订阅主题:${MQTT_CONFIG.topic}`)
+        }
+      })
+    })
+
+    // 接收消息
+    client.on('message', (topic: string, payload: Buffer) => {
+      if (topic === MQTT_CONFIG.topic) {
+        try {
+          const messageStr = payload.toString()
+          const messageObj = JSON.parse(messageStr) as Record<string, any>
+          // 调用回调函数,将消息传递给组件
+          messageCallback?.({
+            topic,
+            message: messageObj
+          })
+        } catch (parseErr) {
+          ElMessage.error(`消息解析失败:${(parseErr as Error).message}`)
+          // 解析失败时直接返回字符串
+          messageCallback?.({
+            topic,
+            message: { raw: payload.toString() }
+          })
+        }
+      }
+    })
+
+    // 连接断开
+    client.on('close', () => {
+      ElMessage.warning('MQTT 连接已断开')
+    })
+
+    // 连接错误
+    client.on('error', (err: Error) => {
+      ElMessage.error(`MQTT 连接错误:${err.message}`)
+      client?.end()
+    })
+  } catch (err) {
+    const error = err as Error
+    ElMessage.error(`MQTT 初始化失败:${error.message}`)
+  }
+}
+
+/**
+ * 断开 MQTT 连接
+ */
+export const disconnectMqtt = (): void => {
+  if (client) {
+    client.end()
+    client = null
+    ElMessage.info('MQTT 已断开连接')
+  }
+}
+
+/**
+ * 获取当前 MQTT 连接状态
+ */
+export const getMqttStatus = (): boolean => {
+  return !!client?.connected
+}

+ 94 - 0
src/views/pms/mqtt/mqtt.vue

@@ -0,0 +1,94 @@
+<template>
+  <el-card title="MQTT 消息监听(TS 版本)">
+    <el-alert
+      v-if="mqttMessage"
+      title="收到新消息"
+      type="success"
+      :description="JSON.stringify(mqttMessage, null, 2)"
+      show-icon
+      style="margin-bottom: 20px;"
+    />
+    <el-button
+      type="primary"
+      @click="initMqttConnect"
+      :disabled="isConnected"
+    >
+      连接 MQTT
+    </el-button>
+    <el-button
+      type="danger"
+      @click="disconnectMqttConnect"
+      :disabled="!isConnected"
+      style="margin-left: 10px;"
+    >
+      断开连接
+    </el-button>
+    <el-tag v-if="isConnected" type="success">已连接</el-tag>
+    <el-tag v-else type="danger">未连接</el-tag>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, onUnmounted, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { initMqtt, disconnectMqtt, getMqttStatus } from '@/utils/mqtt'
+
+// 定义消息类型接口
+interface MqttReceivedMessage {
+  topic: string
+  message: Record<string, any>
+}
+
+// 响应式数据(添加类型注解)
+const mqttMessage = ref<MqttReceivedMessage | null>(null)
+const isConnected = ref<boolean>(false)
+
+// 计算属性:实时获取连接状态
+const mqttStatus = computed(() => getMqttStatus())
+
+// 初始化 MQTT 连接
+const initMqttConnect = (): void => {
+  initMqtt((message: MqttReceivedMessage) => {
+    // 接收消息并更新到页面
+    mqttMessage.value = message
+    // 业务逻辑处理
+    console.log('收到 MQTT 消息:', message)
+    ElMessage.success(`收到主题 [${message.topic}] 的新消息`)
+  })
+  isConnected.value = true
+}
+
+// 断开 MQTT 连接
+const disconnectMqttConnect = (): void => {
+  disconnectMqtt()
+  isConnected.value = false
+  mqttMessage.value = null
+}
+
+// 组件挂载时检查连接状态
+onMounted(() => {
+  isConnected.value = mqttStatus.value
+  // 自动连接(可选)
+  // if (!isConnected.value) {
+  //   initMqttConnect()
+  // }
+})
+
+// 组件卸载时断开连接,避免内存泄漏
+onUnmounted(() => {
+  if (isConnected.value) {
+    disconnectMqttConnect()
+  }
+})
+</script>
+
+<style scoped>
+.el-card {
+  width: 800px;
+  margin: 20px auto;
+}
+
+.el-tag {
+  margin-left: 10px;
+}
+</style>