|
|
@@ -0,0 +1,180 @@
|
|
|
+<!-- MqttComp.vue -->
|
|
|
+<template>
|
|
|
+ <div class="mqtt-comp" style="display: none"></div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import mqtt from "mqtt/dist/mqtt.min.js";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "MqttComp",
|
|
|
+ props: {
|
|
|
+ mqttUrl: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({
|
|
|
+ head: "ws", // ws 或 wss
|
|
|
+ host: "8.148.78.124",
|
|
|
+ port: 8083,
|
|
|
+ path: "/mqtt",
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ mqttOpts: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({
|
|
|
+ keepalive: 60,
|
|
|
+ clientId: "clientId-" + Math.random().toString(16).substr(2, 8),
|
|
|
+ username: "",
|
|
|
+ password: "",
|
|
|
+ clean: true,
|
|
|
+ connectTimeout: 10 * 1000,
|
|
|
+ reconnectPeriod: 2000,
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ topics: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [], // 可一次性传入多个 topic
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ client: null,
|
|
|
+ isConnected: false,
|
|
|
+ subscribedTopics: [], // 内部管理的已订阅 topic
|
|
|
+ };
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ topics: {
|
|
|
+ handler(newTopics) {
|
|
|
+ if (!this.client || !this.isConnected) return;
|
|
|
+
|
|
|
+ // 取消订阅已经移除的 topic
|
|
|
+ this.subscribedTopics.forEach((t) => {
|
|
|
+ if (!newTopics.includes(t)) {
|
|
|
+ this.unsubscribeTopic(t);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 订阅新增 topic
|
|
|
+ newTopics.forEach((t) => {
|
|
|
+ if (!this.subscribedTopics.includes(t)) {
|
|
|
+ this.subscribeTopic(t);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 初始化 MQTT 连接
|
|
|
+ initMqtt() {
|
|
|
+ const { head, host, port, path } = this.mqttUrl;
|
|
|
+ const connectUrl = `${head}://${host}:${port}${path || ""}`;
|
|
|
+ console.log("MQTT连接地址:", connectUrl);
|
|
|
+
|
|
|
+ this.client = mqtt.connect(connectUrl, this.mqttOpts);
|
|
|
+
|
|
|
+ this.client.on("connect", () => {
|
|
|
+ this.isConnected = true;
|
|
|
+ console.log("✅ MQTT 已连接");
|
|
|
+ this.$emit("mqtt-connected");
|
|
|
+
|
|
|
+ // 自动订阅传入的 topic
|
|
|
+ this.topics.forEach((topic) => this.subscribeTopic(topic));
|
|
|
+ });
|
|
|
+
|
|
|
+ this.client.on("message", (topic, message) => {
|
|
|
+ let msg;
|
|
|
+ try {
|
|
|
+ msg = JSON.parse(message.toString());
|
|
|
+ } catch {
|
|
|
+ msg = message.toString();
|
|
|
+ }
|
|
|
+ this.$emit("message-received", { topic, message: msg });
|
|
|
+ });
|
|
|
+
|
|
|
+ this.client.on("reconnect", () => {
|
|
|
+ console.log("♻️ MQTT 正在重连...");
|
|
|
+ this.$emit("mqtt-reconnect");
|
|
|
+ });
|
|
|
+
|
|
|
+ this.client.on("error", (err) => {
|
|
|
+ console.error("❌ MQTT连接失败:", err);
|
|
|
+ this.$emit("mqtt-error", err);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.client.on("close", () => {
|
|
|
+ this.isConnected = false;
|
|
|
+ console.log("🔌 MQTT连接已关闭");
|
|
|
+ this.$emit("mqtt-close");
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 订阅单个 topic
|
|
|
+ subscribeTopic(topic) {
|
|
|
+ if (!this.client || !this.isConnected) {
|
|
|
+ console.warn("MQTT 未连接,无法订阅:", topic);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!topic || this.subscribedTopics.includes(topic)) return;
|
|
|
+
|
|
|
+ this.client.subscribe(topic, (err) => {
|
|
|
+ if (!err) {
|
|
|
+ console.log("订阅成功:", topic);
|
|
|
+ this.subscribedTopics.push(topic);
|
|
|
+ this.$emit("topic-subscribed", topic);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 取消订阅单个 topic
|
|
|
+ unsubscribeTopic(topic) {
|
|
|
+ if (!this.client || !this.isConnected) return;
|
|
|
+ if (!topic || !this.subscribedTopics.includes(topic)) return;
|
|
|
+
|
|
|
+ this.client.unsubscribe(topic, (err) => {
|
|
|
+ if (!err) {
|
|
|
+ console.log("取消订阅:", topic);
|
|
|
+ this.subscribedTopics = this.subscribedTopics.filter((t) => t !== topic);
|
|
|
+ this.$emit("topic-unsubscribed", topic);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 发布消息
|
|
|
+ publish(topic, message) {
|
|
|
+ if (!this.client || !this.isConnected) {
|
|
|
+ console.warn("MQTT 未连接,消息未发送:", topic);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ console.log("sdfdsf",typeof message === "object");
|
|
|
+
|
|
|
+ const payload = typeof message === "object" ? JSON.stringify(message) : String(message);
|
|
|
+ this.client.publish(topic, payload);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 断开连接,取消所有订阅
|
|
|
+ disconnect() {
|
|
|
+ if (this.client) {
|
|
|
+ // 先取消所有订阅
|
|
|
+ this.subscribedTopics.forEach((t) => this.unsubscribeTopic(t));
|
|
|
+ this.client.end(true, () => {
|
|
|
+ console.log("🔌 MQTT手动断开成功");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.initMqtt();
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ this.disconnect();
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.mqtt-comp {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+</style>
|