import { useState, useEffect } from 'react'; import mqtt from 'mqtt'; import { MQTT_URL, MQTT_TOPIC_COMMAND, MQTT_TOPIC_TICK, MQTT_USERNAME, MQTT_PASSWORD } from '../config'; /* ========================================================= MQTT 客户端(mqtt.js)—— 后端控制通道 订阅 opc/display/command(页面/媒体/卡片控制)与 opc/dashboard/tick(数据快照) 断线自动重连;未连接时静默降级(页面仍可本地操作) ========================================================= */ let client = null; let status = 'connecting'; // connecting | connected | offline const listeners = new Set(); function notifyStatus() { window.dispatchEvent(new CustomEvent('dpm:mqtt-status', { detail: { status } })); } export function connectMqtt() { if (client) return; try { client = mqtt.connect(MQTT_URL, { reconnectPeriod: 3000, connectTimeout: 8000, clientId: `dpm-screen-${Math.random().toString(16).slice(2, 8)}`, clean: true, username: MQTT_USERNAME || undefined, password: MQTT_PASSWORD || undefined, }); client.on('connect', () => { status = 'connected'; notifyStatus(); client.subscribe([MQTT_TOPIC_COMMAND, MQTT_TOPIC_TICK], { qos: 1 }); }); client.on('reconnect', () => { status = 'connecting'; notifyStatus(); }); client.on('close', () => { status = 'offline'; notifyStatus(); }); client.on('error', () => { status = 'offline'; notifyStatus(); }); client.on('message', (topic, payload) => { let data = null; try { data = JSON.parse(payload.toString()); } catch { return; } listeners.forEach((fn) => fn(topic, data)); }); } catch (e) { status = 'offline'; notifyStatus(); } } export function getMqttStatus() { return status; } /** 订阅 MQTT 消息,返回取消订阅函数 */ export function onMqttMessage(fn) { listeners.add(fn); return () => listeners.delete(fn); } /** React Hook:MQTT 连接状态 */ export function useMqttStatus() { const [s, setS] = useState(status); useEffect(() => { connectMqtt(); const on = (e) => setS(e.detail.status); window.addEventListener('dpm:mqtt-status', on); return () => window.removeEventListener('dpm:mqtt-status', on); }, []); return s; }