import { shallowRef } from "vue";
import { setPx, addParam } from "./util";
import config from "./config";
import mqtt from "mqtt";
import commonOption from "./option";
import crypto from "@/utils/crypto";
import { getGlobValue, getFunction, uuid } from "@/utils/utils";
import COMMON from "@/config";
export default (() => {
  return {
    inject: ["subgroup"],
    props: {
      filterList: Object,
      dataFormatterId: String,
      dataFormatterStr: [String, Function],
      clickFormatterStr: [String, Function],
      dblClickFormatterStr: [String, Function],
      mouseEnterFormatterStr: [String, Function],
      mouseLeaveFormatterStr: [String, Function],
      dataBeforeFormatterStr: [String, Function],
      dataAfterFormatterStr: [String, Function],
      echartFormatterStr: [String, Function],
      labelFormatterStr: [String, Function],
      stylesFormatterStr: [String, Function],
      formatterStr: [String, Function],
      titleFormatter: Function,
      sqlFormatter: Function,
      fillFormatter: Function,
      fill: String,
      recordFormatter: Function,
      transfer: Function,
      data: [Array, Object],
      dataQueryType: String,
      dataQuery: String,
      dataHeader: String,
      fontFamily: String,
      usernamme: String,
      password: String,
      topicName: String,
      fillParams: {
        type: String,
        default: "{}",
      },
      dataList: Array,
      object: {
        type: Object,
        default: () => {
          return {};
        },
      },
      initialize: {
        type: Boolean,
        default: true,
      },
      width: {
        type: [Number, String],
        default: 600,
      },
      height: {
        type: [Number, String],
        default: 600,
      },
      theme: {
        type: String,
      },
      child: {
        type: Object,
        default: () => {
          return {};
        },
      },
      record: {
        type: String,
      },
      public: {
        type: String,
      },
      sql: {
        type: String,
      },
      time: {
        type: [Number, String],
        default: 0,
      },
      proxy: {
        type: Boolean,
      },
      url: {
        type: String,
      },
      wsUrl: {
        type: String,
      },
      mqttUrl: {
        type: String,
      },
      mqttConfig: {
        type: String,
      },
      dataType: {
        type: Number,
        default: 0,
      },
      dataMethod: {
        type: String,
        default: "get",
      },
      id: {
        type: String,
        default: "main_" + uuid(),
      },
      index: String,
      data: {
        type: [Object, String, Array],
      },
      display: Boolean,
      component: {
        type: Object,
        default: () => {
          return {};
        },
      },
      option: {
        type: Object,
        default: () => {
          return {};
        },
      },
    },
    mixins: [commonOption],
    data() {
      return {
        timeFn: null,
        headerHeight: "",
        checkPublic: [],
        checkChart: "",
        myChart: "",
        dataOldChart: [],
        dataResChart: [],
        dataResultChart: [],
        dataChart: [],
        dataAxios: {},
        dataParams: {},
        refList: [],
        wsClient: [],
        mqClient: [],
        styles: {},
        className: "",
        wsReconnectTimers: [],
        mqttReconnectTimers: [],
        wsReconnectCount: [],
        mqttReconnectCount: [],
        maxReconnectAttempts: 10,
        reconnectInterval: 3000,
      };
    },
    watch: {
      dataList: {
        handler(val) {
          if (val && val[0]) {
            this.object.data = val[0].data;
          }
        },
        deep: true,
      },
      data: {
        handler(val) {
          if (this.dataList && this.dataList[0]) {
            this.dataList[0].data = val;
            this.updateData();
          }
        },
        deep: true,
        immediate: true,
      },
      dataChart: {
        handler(val) {
          this.updateChart();
          this.bindEvent();
        },
        deep: true,
      },
      echartFormatter() {
        this.updateChart();
        this.bindEvent();
      },
      width() {
        this.$nextTick(() => {
          this.updateChart();
        });
      },
      height() {
        this.$nextTick(() => {
          this.updateChart();
        });
      },
      theme() {
        this.myChart.dispose();
        this.init();
      },
      option: {
        handler() {
          this.updateChart();
          this.bindEvent();
        },
        deep: true,
      },
      display: {
        handler(val) {
          if (val) {
            this.hideAnimation();
          } else {
            this.initAnima();
          }
        },
        immediate: true,
      },
      "component.animatedInfinite"() {
        this.initAnima();
      },
      "component.animated"() {
        this.initAnima();
      },
      "component.animatedSwitch"() {
        this.initAnima();
      },
    },
    computed: {
      mappingValue() {
        return this.dataChart[this.option.mapping || "value"];
      },
      dataFormatter() {
        let fun = this.dataFormatterStr;
        if (this.dataFormatterId) {
          fun = this.filterList[this.dataFormatterId].dataFormatter;
        }
        return typeof fun == "function" ? fun : getFunction(fun);
      },
      clickFormatter() {
        return this.getFormatter(this.clickFormatterStr, true);
      },
      dblClickFormatter() {
        return this.getFormatter(this.dblClickFormatterStr, true);
      },
      mouseEnterFormatter() {
        return this.getFormatter(this.mouseEnterFormatterStr, true);
      },
      mouseLeaveFormatter() {
        return this.getFormatter(this.mouseLeaveFormatterStr, true);
      },
      dataBeforeFormatter() {
        return this.getFormatter(this.dataBeforeFormatterStr, true);
      },
      dataAfterFormatter() {
        return this.getFormatter(this.dataAfterFormatterStr, true);
      },
      echartFormatter() {
        return this.getFormatter(this.echartFormatterStr);
      },
      labelFormatter() {
        return this.getFormatter(this.labelFormatterStr);
      },
      stylesFormatter() {
        return this.getFormatter(this.stylesFormatterStr);
      },
      formatter() {
        return this.getFormatter(this.formatterStr);
      },
      count() {
        return this.option.count;
      },
      switchTheme() {
        return this.validData(this.option.switchTheme, false);
      },
      name() {
        let className = this.$el.className.split(" ")[0];
        const result = className.replace(config.name, "");
        return result;
      },
      minWidth() {
        const val = this.option.minWidth;
        if (val > this.width) return val;
      },
      styleChartName() {
        const obj = {
          fontFamily: this.component.fontFamily,
          width: setPx(this.minWidth || this.width),
          height: setPx(this.height),
          opacity: this.component.opacity * 0.01 || 1,
          filter: `contrast(${this.component.contrast || 100}%) saturate(${
            this.component.saturate || 100
          }%) brightness(${this.component.brightness || 100}%) opacity(${
            this.component.opacity || 100
          }%) grayscale(${this.component.grayscale || 0}%) hue-rotate(${
            this.component.hueRotate || 0
          }deg) invert(${this.component.invert || 0}%) blur(${
            this.component.blur
          }px)`,
          transform: `scale(${this.component.scale || 1}) perspective(${
            this.component.perspective || 500
          }px) rotateX(${this.component.rotateX || 0}deg) rotateY(${
            this.component.rotateY || 0
          }deg) rotateZ(${this.component.rotateZ || 0}deg)`,
        };
        return obj;
      },
      styleSizeName() {
        return Object.assign(
          {
            width: setPx(this.width),
            height: setPx(this.height),
          },
          (() => {
            if (this.minWidth) {
              return {
                overflowX: "auto",
                overflowY: "hidden",
              };
            }
            return {};
          })(),
          this.styles,
          {
            animationDuration: this.component.animateDuration + "s",
            animationDelay: this.component.animateDelay + "s",
            animationTimingFunction: this.component.animateSpeed,
            animationDirection: this.component.animateDirection,
          }
        );
      },
    },
    created() {
      this.init();
    },
    mounted() {
      this.initChart();
    },
    methods: {
      init() {
        this.initDataList();
      },
      initDataList() {
        if (!Array.isArray(this.dataList)) {
          let obj = {
            id: uuid(),
            name: "数据源",
            switch: true,
          };
          [
            "dataType",
            "dataMethod",
            "dataHeader",
            "url",
            "record",
            "public",
            "data",
            "dataQuery",
            "dataQueryType",
            "wsUrl",
            "sql",
            "mqttUrl",
            "mqttConfig",
          ].forEach((ele) => {
            obj[ele] = this.object[ele];
          });
          this.object.dataList = [obj];
        }
      },

      initChart() {
        this.refList = this.getItemRefs();
        const main = this.$refs[this.id];
        if (main) {
          // 判断是否图表去初始化
          const isChart = config.echart.includes(this.name);
          if (isChart) {
            this.myChart = shallowRef(
              window.echarts.init(main, this.theme, {
                renderer: this.option.renderer ? "svg" : "canvas",
              })
            );
          }
        }
        this.updateChart();
        this.updateData();
      },
      initAnima() {
        this.object.hidden = false;
        this.setAnimation();
      },
      hideAnimation() {
        this.setAnimation(true);
        if (this.component.animatedHide) {
          setTimeout(() => {
            this.object.hidden = true;
          }, this.animateDuration * 1000 || 1000);
        } else {
          this.object.hidden = true;
        }
      },
      setAnimation(isHide = false) {
        if (this.component.animatedSwitch) {
          const animationType = isHide
            ? this.component.animatedHide
            : this.component.animated;
          this.className = `animated ${animationType}${
            this.component.animatedInfinite ? " infinite" : ""
          }`;
        } else {
          this.className = "";
        }
      },
      getFormatter(formatterStr, isEchart = false) {
        return typeof formatterStr === "function"
          ? formatterStr
          : getFunction(formatterStr, isEchart, this.index);
      },
      getItemRefs() {
        let refList = (this.subgroup || {}).$refs || [];
        let result = {};
        Object.keys(refList).forEach((ele) => {
          if (ele.indexOf(COMMON.NAME) !== -1) {
            let obj = refList[ele][0];
            if (obj) result[ele.replace(COMMON.NAME, "")] = obj.$refs.temp;
          } else if ((refList[ele][0] || {}).type === "folder") {
            let obj = refList[ele][0];
            if (obj) result[ele.replace(COMMON.DEAFNAME, "")] = obj;
          }
        });
        return result;
      },
      updateChart() {},
      bindEvent() {
        if (this.myChart) {
          [
            {
              name: "click",
              event: "handleClick",
              event1: "handleEventClick",
            },
            {
              name: "dblclick",
              event: "handleDblClick",
              event1: "handleEventDblClick",
            },
            {
              name: "mouseover",
              event: "handleMouseEnter",
            },
            {
              name: "mouseout",
              event: "handleMouseLeave",
            },
          ].forEach((ele) => {
            this.myChart.off(ele.name);
            this.myChart.on(ele.name, (e) => {
              const callback = () => {
                this[ele.event](e, e.dataIndex);
                if (this[ele.event1]) this[ele.event1] && this[ele.event1](e);
              };
              if (ele.name == "click") {
                clearTimeout(this.timeFn);
                this.timeFn = setTimeout(() => {
                  callback();
                }, 250);
              } else if (ele.name == "dblclick") {
                clearTimeout(this.timeFn);
                callback();
              } else {
                callback();
              }
            });
          });
        }
        if (typeof this.stylesFormatter === "function") {
          this.styles =
            this.stylesFormatter(
              this.dataChart,
              this.dataParams,
              this.getItemRefs()
            ) || {};
        }
      },
      // 更新数据核心方法
      updateData(p = {}) {
        let allPromise = [];
        this.closeClient();
        const callback = (res, index) => {
          if (!this.validatenull(index)) this.dataResChart[index] = res;
          else this.dataResChart = res;
          this.dataOldChart =
            this.dataResChart.length > 1
              ? this.dataResChart
              : this.deepClone(this.dataResChart[0]) || {};
          if (typeof this.dataFormatter === "function") {
            try {
              this.dataChart = this.dataFormatter(
                this.dataOldChart,
                this.dataParams,
                this.getItemRefs()
              );
            } catch (err) {
              console.log(new Error(err));
              this.dataChart = err + "";
            }
          } else {
            this.dataChart = this.dataOldChart;
          }
          if (typeof this.stylesFormatter === "function") {
            this.styles =
              this.stylesFormatter(
                this.dataChart,
                this.dataParams,
                this.getItemRefs()
              ) || {};
          }
          this.$refs.main &&
            this.$refs.main.updateData &&
            this.$refs.main.updateData(p);
          this.handleDataAfterFormatter(this.dataChart, -1);
        };
        const getDataList = () => {
          (this.dataList || []).forEach((dataObj, index) => {
            if (dataObj.switch == false) return;
            let record;
            let isRecord = dataObj.dataType === 4;
            let isPublic = dataObj.dataType === 5;
            this.dataParams = Object.assign(this.dataParams, p);
            let childPromise = new Promise((resolve, reject) => {
              let safe = dataObj;
              const formatter = (data) => {
                if (isRecord) {
                  const dataFormatter = getFunction(record.dataFormatter);
                  if (typeof dataFormatter == "function") {
                    data = dataFormatter(data);
                  }
                }
                return data;
              };
              const getData = () => {
                safe = record || dataObj;
                let isApi = safe.dataType === 1;
                let isSql = safe.dataType === 2;
                let isWs = safe.dataType === 3;
                let isMqtt = safe.dataType == 6;
                let isNode = safe.dataType === 7;
                let isFill = safe.dataType === 8;
                if (isApi || isNode) {
                  let url = getGlobValue(safe.url);
                  if (this.validatenull(url)) return;
                  let dataQuery = getFunction(safe.dataQuery);
                  dataQuery =
                    (typeof dataQuery === "function" && dataQuery(url)) || {};
                  let dataHeader = getFunction(safe.dataHeader);
                  dataHeader =
                    (typeof dataHeader === "function" && dataHeader(url)) || {};
                  let params = Object.assign(dataQuery, this.dataParams);
                  let axiosParams = {};
                  if (safe.proxy || isNode) dataHeader.proxy = true;
                  if (["post", "put"].includes(safe.dataMethod)) {
                    axiosParams.data = params;
                    if (safe.dataQueryType == "form") {
                      if (safe.proxy) dataHeader.form = true;
                      let formData = [];
                      Object.keys(params).forEach((ele) => {
                        formData.push(`${ele}=${params[ele]}`);
                      });
                      axiosParams.data = formData.join("&");
                    }
                  } else if (["get", "delete"].includes(safe.dataMethod)) {
                    axiosParams.params = params;
                  }
                  this.$axios({
                    ...{
                      method: safe.dataMethod,
                      url: url,
                      headers: dataHeader,
                    },
                    ...axiosParams,
                  })
                    .then((res) => {
                      this.dataAxios = res;
                      let result = res.data;
                      result = formatter(result, params);
                      callback(result, index);
                      resolve(result);
                    })
                    .catch((err) => {
                      resolve(err);
                    });
                } else if (isWs) {
                  let url = getGlobValue(safe.wsUrl);
                  if (this.validatenull(url)) return;
                  let dataQuery = getFunction(safe.dataQuery);
                  dataQuery =
                    (typeof dataQuery === "function" && dataQuery(url)) || {};
                  let params = Object.assign(dataQuery, this.dataParams);
                  url = url + addParam(url, params);

                  // 创建WebSocket配置对象
                  const wsConfig = {
                    url,
                    index,
                    safe,
                    formatter,
                    resolve,
                    callback,
                  };
                  this.createWebSocketConnection(wsConfig);
                } else if (isSql) {
                  let data, result, sql;
                  try {
                    // sql = JSON.parse(crypto.decrypt(safe.sql));
                    sql = JSON.parse(safe.sql);
                    sql.sql = getFunction(sql.sql)(this.dataParams);
                    // data = crypto.encrypt(JSON.stringify(sql));
                    data = sql;
                  } catch (error) {
                    data = safe.sql;
                  }
                  if (data) {
                    this.sqlFormatter(data)
                      .then((res) => {
                        result = res.data.data;
                        result = formatter(result, this.dataParams);
                        callback(result, index);
                        resolve(result);
                      })
                      .catch((err) => {
                        resolve(err);
                      });
                  }
                } else if (isMqtt) {
                  let url = getGlobValue(safe.mqttUrl);
                  let dataMqttConfig = JSON.parse(safe.mqttConfig || "{}");
                  dataMqttConfig = {
                    ...dataMqttConfig,
                    ...{
                      clientId: "mqttjs_" + uuid(),
                      topic: dataMqttConfig.topic || {},
                      username:
                        dataMqttConfig.username || getGlobValue(safe.username),
                      password:
                        dataMqttConfig.password || getGlobValue(safe.password),
                    },
                  };
                  const topicName = dataMqttConfig.topic.name;
                  const topicQos = dataMqttConfig.topic.qos || 0;

                  // 创建MQTT配置对象
                  const mqttConfig = {
                    url,
                    dataMqttConfig,
                    topicName,
                    topicQos,
                    index,
                    safe,
                    formatter,
                    resolve,
                    callback,
                  };
                  this.createMqttConnection(mqttConfig);
                } else if (isFill) {
                  this.fillFormatter(
                    Object.assign(
                      { templateId: safe.fill },
                      JSON.parse(safe.fillParams)
                    )
                  )
                    .then((res) => {
                      let result = res.data.data.records;
                      result = result.map((ele) => {
                        try {
                          return JSON.parse(ele.data);
                        } catch {
                          return ele;
                        }
                      });
                      result = formatter(result, this.dataParams);
                      callback(result, index);
                      resolve(result);
                    })
                    .catch((err) => {
                      resolve(err);
                    });
                } else if (isPublic) {
                  let refList = this.getItemRefs();
                  let result = refList[dataObj.public].dataChart;
                  result = formatter(this.deepClone(result), this.dataParams);
                  callback(result, index);
                  result && resolve(result);
                } else {
                  let result = this.deepClone(safe.data);
                  if (isRecord) {
                    result = getFunction(result);
                  }
                  result = formatter(result, this.dataParams);
                  callback(result, index);
                  resolve(result);
                }
              };
              const sendData = () => {
                this.$nextTick(() => {
                  getData();
                  clearInterval(this.checkPublic[index]);
                  if (isPublic) {
                    this.checkPublic[index] = setInterval(() => {
                      let refList = this.getItemRefs();
                      let result = refList[dataObj.public].dataChart;
                      if (
                        JSON.stringify(result) ==
                        JSON.stringify(this.dataResultChart[index])
                      ) {
                        return;
                      }
                      this.dataResultChart[index] = result;
                      getData();
                    }, 100);
                  }
                });
              };
              if (isRecord) {
                this.recordFormatter(dataObj.record)
                  .then((res) => {
                    const data = res.data.data;
                    record = {
                      ...data,
                      sql: data.data,
                    };
                    sendData();
                  })
                  .catch((err) => {
                    resolve(err);
                  });
              } else {
                sendData();
              }
            });
            allPromise.push(childPromise);
          });
        };
        getDataList();
        this.checkChart && clearInterval(this.checkChart);
        if (
          this.time != 0 &&
          !this.validatenull(this.time) &&
          !this.initialize
        ) {
          this.checkChart = setInterval(() => {
            this.handleDataBeforeFormatter({}, -1);
            getDataList();
          }, this.time);
        }
        return new Promise((resolve) => {
          Promise.all(allPromise).then((res) => {
            resolve({
              news: this.dataChart,
              old: this.dataOldChart,
            });
          });
        });
      },
      updateClick(params, type) {
        let refList = this.getItemRefs();
        let paramList = this.child.paramList || [];
        paramList = paramList.filter(
          (ele) => (ele.event || "clickFormatter") == type
        );
        paramList = paramList.filter((ele) => {
          try {
            return getFunction(ele.condition)(params, refList, this);
          } catch {}
        });
        if (paramList.length != 0)
          this.transfer && this.transfer(paramList, refList, params, this);
      },
      handleCommonBind(item, index, type) {
        this.updateClick(item || this.dataChart, type);
        let params = {};
        if (!this.validatenull(index)) {
          params = {
            item,
            index,
            data: this.dataChart,
          };
          if (item && item.value) params.value = item.value;
        } else {
          params = item || this.dataChart;
        }
        this[type] && this[type](params, this.getItemRefs(), this);
      },
      handleDataAfterFormatter(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "dataAfterFormatter");
      },
      handleDataBeforeFormatter(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "dataAfterFormatter");
      },
      handleClick(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "clickFormatter");
      },
      handleChange(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "changeFormatter");
      },
      handleDblClick(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "dblClickFormatter");
      },
      handleMouseEnter(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "mouseEnterFormatter");
      },
      handleMouseLeave(item = {}, index) {
        if (item.pointerType == "mouse") item = this.dataChart;
        this.handleCommonBind(item, index, "mouseLeaveFormatter");
      },
      // 下面俩都是chart的公共的方法,就放这里面共用
      getColor(index, first) {
        const category = this.option.category;
        if ((this.option.barColor || []).length > 0) {
          const barColor = this.option.barColor || [];
          if (barColor[index]) {
            const color1 = barColor[index].color1;
            const color2 = barColor[index].color2;
            const postion = (barColor[index].postion || 0.9) * 0.01;
            if (first) return color1;
            if (color2) {
              return {
                type: "linear",
                x: 0,
                y: 0,
                x2: category ? 1 : 0,
                y2: category ? 0 : 1,
                colorStops: [
                  {
                    offset: 0,
                    color: color1, // 0% 处的颜色
                  },
                  {
                    offset: postion,
                    color: color2, // 100% 处的颜色
                  },
                ],
                global: false, // 缺省为 false
              };
            }
            return color1;
          } else {
            return [];
          }
        } else if (!this.validatenull(window.$glob.theme)) {
          let colors = window.$glob.theme.color;
          if (colors[index]) {
            return colors[index];
          }
        }
      },
      getHasProp(isHas, propObj, staticObj = {}) {
        return Object.assign(
          (() => {
            return isHas ? propObj : {};
          })(),
          staticObj
        );
      },
      closeClient() {
        this.wsReconnectTimers.forEach((timer) => clearTimeout(timer));
        this.mqttReconnectTimers.forEach((timer) => clearTimeout(timer));

        this.wsClient.forEach((ele) => ele && ele.close && ele.close());

        this.mqClient.forEach((ele) => {
          ele && ele.end && ele.end();
          ele && ele.close && ele.close();
        });
      },

      createWebSocketConnection(wsConfig) {
        const { url, index, safe, formatter, resolve, callback } = wsConfig;

        if (this.wsReconnectCount[index] === undefined) {
          this.wsReconnectCount[index] = 0;
        }

        this.wsClient[index] = new WebSocket(url);

        this.wsClient[index].onopen = () => {
          console.log(`WebSocket连接成功: ${url}`);
          this.wsReconnectCount[index] = 0;
        };

        this.wsClient[index].onmessage = (message = {}) => {
          try {
            let result = JSON.parse(message.data);
            result = formatter(result, this.dataParams);
            callback(result, index);
            resolve && resolve(result);
          } catch (error) {
            console.error("WebSocket消息处理错误:", error);
          }
        };

        this.wsClient[index].onclose = (event) => {
          console.log(
            `WebSocket连接关闭, 代码: ${event.code}, 原因: ${event.reason}`
          );
          this.handleWebSocketReconnect(wsConfig);
        };

        this.wsClient[index].onerror = (error) => {
          console.error("WebSocket连接错误:", error);
        };
      },

      handleWebSocketReconnect(wsConfig) {
        const { index } = wsConfig;

        if (this.wsReconnectTimers[index]) {
          clearTimeout(this.wsReconnectTimers[index]);
        }

        if (this.wsReconnectCount[index] < this.maxReconnectAttempts) {
          console.log(
            `WebSocket尝试重连(${this.wsReconnectCount[index] + 1}/${
              this.maxReconnectAttempts
            })...`
          );

          this.wsReconnectTimers[index] = setTimeout(() => {
            this.wsReconnectCount[index]++;
            this.createWebSocketConnection(wsConfig);
          }, this.reconnectInterval);
        } else {
          console.error(
            `WebSocket已达到最大重连次数(${this.maxReconnectAttempts})`
          );
        }
      },

      createMqttConnection(mqttConfig) {
        const {
          url,
          dataMqttConfig,
          topicName,
          topicQos,
          index,
          safe,
          formatter,
          resolve,
          callback,
        } = mqttConfig;

        if (this.mqttReconnectCount[index] === undefined) {
          this.mqttReconnectCount[index] = 0;
        }

        let mqttClient = mqtt.connect(url, dataMqttConfig);

        mqttClient.on("connect", () => {
          console.log(`MQTT连接成功: ${url}`);
          this.mqClient[index] = mqttClient;
          this.mqttReconnectCount[index] = 0;

          const onSubscribe = (item) => {
            this.mqClient[index].subscribe(
              item || topicName,
              {
                qos: topicQos,
              },
              (error, res) => {
                if (error) {
                  console.error("MQTT主题订阅错误:", error);
                } else {
                  console.log("MQTT主题订阅成功:", res);
                }
                resolve && resolve();
              }
            );
          };

          if (safe.topicName) {
            let topicNameList = safe.topicName.split(",");
            topicNameList.forEach((ele) => onSubscribe(ele));
          } else {
            onSubscribe();
          }

          this.mqClient[index].on("message", (topic, message) => {
            try {
              let result = JSON.parse(message);
              result = formatter(result, this.dataParams);
              callback(result, index);
              resolve && resolve(result);
            } catch (error) {
              console.error("MQTT消息处理错误:", error);
            }
          });
        });

        mqttClient.on("reconnect", () => {
          console.log(`MQTT正在重连...`);
        });

        mqttClient.on("error", (error) => {
          console.error("MQTT连接错误:", error);
          this.handleMqttReconnect(mqttConfig);
        });

        mqttClient.on("close", () => {
          console.log(`MQTT连接关闭`);
          this.handleMqttReconnect(mqttConfig);
        });

        mqttClient.on("offline", () => {
          console.log(`MQTT连接离线`);
        });
      },

      handleMqttReconnect(mqttConfig) {
        const { index } = mqttConfig;

        if (this.mqttReconnectTimers[index]) {
          clearTimeout(this.mqttReconnectTimers[index]);
        }

        if (this.mqttReconnectCount[index] < this.maxReconnectAttempts) {
          console.log(
            `MQTT尝试重连(${this.mqttReconnectCount[index] + 1}/${
              this.maxReconnectAttempts
            })...`
          );

          if (this.mqClient[index]) {
            this.mqClient[index].end(true);
          }

          this.mqttReconnectTimers[index] = setTimeout(() => {
            this.mqttReconnectCount[index]++;
            this.createMqttConnection(mqttConfig);
          }, this.reconnectInterval);
        } else {
          console.error(`MQTT已达到最大重连次数(${this.maxReconnectAttempts})`);
        }
      },
    },
    beforeUnmount() {
      clearInterval(this.checkChart);
      this.checkPublic.forEach((ele) => clearInterval(ele));
      this.closeClient();
    },
  };
})();
