<template>
  <div v-loading="loading">
    <!-- ECharts 图表容器 -->
    <div class="pannel" v-if="isshow">
      光标数据
      <div class="pannel-row" v-show="showReadoutSingle">
        <span class="pannel-key">单指针</span>
        <span class="pannel-val">{{ cursorReadoutSingle }}</span>
      </div>
      <div class="pannel-row" v-show="showReadoutSideband">
        <span class="pannel-key">边带</span>
        <span class="pannel-val">{{ cursorReadoutSideband }}</span>
      </div>
      <div class="pannel-row" v-show="showReadoutPeak">
        <span class="pannel-key">峰值</span>
        <span class="pannel-val">{{ cursorReadoutPeak }}</span>
      </div>
      <div class="pannel-row" v-show="showReadoutHarmonic">
        <span class="pannel-key">谐波</span>
        <span class="pannel-val">{{ cursorReadoutHarmonic }}</span>
      </div>
    </div>
    <div class="line-chart" ref="chart"></div>

    <div class="control-panel">
      <!-- 频率范围 -->
      <div class="box full-row">
        <div class="panel-block">
          <span class="label1">频率</span>
          <el-input v-model="freqMin" size="mini" placeholder="下限" />
          <span>~</span>
          <el-input v-model="freqMax" size="mini" placeholder="上限" />
          <el-button size="mini" type="primary" @click="handleFreqRange">
            应用
          </el-button>
        </div>
      </div>
      <!-- 手动标注 -->
      <div class="panel-block">
        <span class="label1">标注</span>
        <el-input v-model="manualFreq" size="mini" placeholder="频率" />
        <el-input v-model="multiple" size="mini" placeholder="倍频" />
        <el-button size="mini" type="success" @click="handleMark"
          >标注</el-button
        >
      </div>
      <!-- 特征值（多选） -->
      <div class="panel-block">
        <span class="label">特征 </span>
        <el-cascader
          v-model="selectedFeatures"
          :options="cascaderOptions"
          :props="cascaderProps"
          collapse-tags
          clearable
          placeholder="请选择特征"
          size="small"
          @change="handleCascaderChange"
        />
      </div>
      <!-- 光标（单选） -->
      <div class="panel-block">
        <span class="label">光标</span>
        <div class="btn-group">
          <span
            v-for="item in GBcheckList"
            :key="item.val"
            :class="['btn', checkedGB.includes(item.val) ? 'active' : '']"
            @click="selectCursor(item.val)"
          >
            {{ item.val }}
          </span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import * as echarts from "echarts";
import cursorReferenceMixin from "./spectrogramcharts/cursorReferenceMixin";
import Bdgb from "./spectrogramcharts/Bdgb";
import Xdgb from "./spectrogramcharts/Xdgb";
import Tjgb from "./spectrogramcharts/Tjgb";
import failureFrequency from "./data/failureFrequency.json";

export default {
  name: "TimedomainCharts",
  mixins: [cursorReferenceMixin, Bdgb, Xdgb, Tjgb],

  props: {
    isshow: {
      type: Boolean,
      default: false,
    },
    currentIndex: {
      type: Number,
      default: 0,
    },
    activeIndex: {
      type: Number,
      default: 0,
    },
    ids: {
      type: Array,
      default: () => [],
    },
    spectrumListTwo: {
      type: Object,
      default: () => ({}),
    },
    currentRow: {
      type: Object,
      default: () => ({}),
    },
    /** 振动页合并 sessionStorage+路由 后的深链快照（可含 rotationalSpeed、otherData.RPM） */
    deepLinkSpectrumContext: {
      type: Object,
      default: null,
    },
    /** 已打开图表列表（含 rowData），与深链 id 严格一致时取 RPM；不再使用 measurementPointData */
    chartRowSnapshots: {
      type: Array,
      default: () => [],
    },
    routeAnalysisId: {
      type: String,
      default: "",
    },
    routeAnalysisTime: {
      type: String,
      default: "",
    },
    windCode: {
      type: String,
      default: "",
    },
    loading: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      freqMin: "",
      freqMax: "",
      manualFreq: "",
      multiple: 1,
      manualMarks: [],
      chartInstance: null,
      option: null,
      // TZshow: false,
      BGshow: false,
      PXshow: false,
      spectrumList: {},
      GBcheckList: [
        { val: "单指针", checked: false, disabled: false },
        { val: "谐波光标", checked: false, disabled: false },
        { val: "边带光标", checked: false, disabled: false },
        { val: "移动峰值", checked: false, disabled: false },
      ],
      featureGroups: [
        {
          label: "轴承故障",
          type: "bearing",
          children: [
            {
              // GEN
              label: "发电机轴承",
              type: "bearing",
              children: [
                "GEN NDE BPFO",
                "GEN NDE BPFI",
                "GEN NDE BSF",
                "GEN NDE FTF",
                "GEN-DE BPFO",
                "GEN-DE BPFI",
                "GEN-DE BSF",
                "GEN-DE FTF",
              ],
            },
            {
              label: "主轴轴承",
              type: "bearing",
              children: [
                // 主轴轴承
                "MB01 BPFO",
                "MB01 BPFI",
                "MB01 BSF",
                "MB01 FTF",
                "MB02 BPFO",
                "MB02 BPFI",
                "MB02 BSF",
                "MB02 FTF",
              ],
            },
            {
              label: "LSS",
              type: "bearing",
              children: [
                "lSS NNCF5048 BPFO",
                "lSS NNCF5048 BPFI",
                "lSS NNCF5048 BSF",
                "lSS NNCF5048 FTF",
              ],
            },
            {
              label: "HSS",
              type: "bearing",
              children: [
                // HSS
                "HSS-NU2228 BPFO",
                "HSS-NU2228 BPFI",
                "HSS-NU2228 BSF",
                "HSS-NU2228 FTF",
                "HSS-QJ328 BPFO",
                "HSS-QJ328 BPFI",
                "HSS-QJ328 BSF",
                "HSS-QJ328 FTF",
              ],
            },
            {
              label: "IMS",
              type: "bearing",
              children: [
                // IMS
                "IMS-32956 BPFO",
                "IMS-32956 BPFI",
                "IMS-32956 BSF",
                "IMS-32956 FTF",
                "IMS-NU1052 BPFO",
                "IMS-NU1052 BPFI",
                "IMS-NU1052 BSF",
                "IMS-NU1052 FTF",
                "IMS-NU2324 BPFO",
                "IMS-NU2324 BPFI",
                "IMS-NU2324 BSF",
                "IMS-NU2324 FTF",
              ],
            },
            {
              label: "行星轴承（LSS/IMS）",
              type: "bearing",
              children: [
                // 行星轴承（LSS/IMS）
                "LSS BPFO",
                "LSS BPFI",
                "LSS BSF",
                "LSS FTF",
                "IMS BPFO", //中间轴
                "IMS BPFI",
                "IMS BSF",
                "IMS FTF",
              ],
            },
          ],
        },
        {
          label: "转动基频",
          type: "rotation",
          children: [
            "Speed",
            "Blade",
            "MainShaft",
            "LSS Planet shaft",
            "IMS Planet shaft",
            "Rotor, Rotor bars", //转子
            "固定联轴节HHS",
          ],
        },
        {
          label: "结构频率",
          type: "structure",
          children: [
            "Stator, Pole pass freq.", //定子
            "Stator, Grid freq.",
            "Rotor, Grid freq.",
          ],
        },
        {
          label: "齿轮特征",
          type: "gear",
          children: [
            "GearIMS",
            "GearHHS",
            "LSS", //小齿轮// 行星啮合频率（本质GMF）
            "IMS", //中间轴
          ],
        },
      ],
      // 每个分类单独存
      selectedMap: {
        bearing: [],
        rotation: [],
        structure: [],
        gear: [],
      },
      // 最终统一给图表用
      checkedFeatures: [],
      selectedFeatures: [],
      cascaderProps: {
        multiple: true,
        checkStrictly: false,
        emitPath: true, // 保留（你需要路径）
        value: "value",
        label: "label",
      },
      Fr: [],
      BPFI: [],
      BPFO: [],
      BSF: [],
      FTF: [],
      B3P: [],
      checkedGB: [],
      checkedValues: [],
      featureMultipleMap: {},
      /** 与 failureFrequency.json 中各部件的 ratio（传动比）对应到每条故障特征名 */
      featureRatioMap: {},
      rpmMissingWarned: false,
    };
  },
  computed: {
    cascaderOptions() {
      return this.featureGroups.map((group) => ({
        label: group.label,
        value: group.label,
        children: group.children.map((item) => {
          // 其它分组：子项为字符串；「轴承故障」为 { label, children: string[] } 多一级
          if (typeof item === "string") {
            return { label: item, value: item };
          }
          if (item && Array.isArray(item.children)) {
            return {
              label: item.label,
              value: item.label,
              children: item.children.map((leaf) => ({
                label: leaf,
                value: leaf,
              })),
            };
          }
          return {
            label: item.label,
            value: item.label,
          };
        }),
      }));
    },
    spectrumXLabel() {
      const t = this.spectrumList?.xaxis;
      return t && String(t).trim() ? String(t).trim() : "Hz";
    },
    spectrumYLabel() {
      const t = this.spectrumList?.yaxis;
      return t && String(t).trim() ? String(t).trim() : "m/s²";
    },
    /** 单指针：点击后的频率与幅值（来自 mixin singlePointerPoint） */
    cursorReadoutSingle() {
      const p = this.singlePointerPoint;
      if (!p || p.xAxis == null) return this.formatCursorPair(null, null);
      return this.formatCursorPair(p.xAxis, p.val);
    },
    /** 边带：展示 +1 边带线处的频率与谱幅（与图上「+1」标注一致） */
    cursorReadoutSideband() {
      if (!this.sidebandCursorPoints?.length || !this.singlePointerPoint) {
        return this.formatCursorPair(null, null);
      }
      const plusOne = this.sidebandCursorPoints.find((p) => p.val === "+1");
      if (!plusOne || plusOne.xAxis == null) {
        return this.formatCursorPair(null, null);
      }
      const xData = this.spectrumList?.x;
      const yData = this.spectrumList?.y;
      if (!xData?.length || !yData?.length) {
        return this.formatCursorPair(plusOne.xAxis, null);
      }
      const idx = this.findClosestIndex(Number(plusOne.xAxis), xData);
      const yVal = yData[idx];
      const amp =
        yVal != null && !Number.isNaN(Number(yVal))
          ? Number(yVal).toFixed(6)
          : null;
      return this.formatCursorPair(plusOne.xAxis, amp);
    },
    /** 移动峰值：当前峰值光标（cursorHightPoints） */
    cursorReadoutPeak() {
      const pts = this.cursorHightPoints;
      if (!pts?.length) return this.formatCursorPair(null, null);
      const p = pts[0];
      return this.formatCursorPair(p.xAxis, p.val);
    },
    /** 谐波：基频（1×）处频率与插值幅值（harmonicCursorPoints[0]） */
    cursorReadoutHarmonic() {
      const pts = this.harmonicCursorPoints;
      if (!pts?.length) return this.formatCursorPair(null, null);
      const p = pts[0];
      return this.formatCursorPair(p.xAxis, p.yValue);
    },
    /** v-show 用：字符串恒为真，不能写 v-show="cursorReadoutPeak"，需按数据源判断 */
    showReadoutSingle() {
      return (
        this.singlePointerPoint != null && this.singlePointerPoint.xAxis != null
      );
    },
    showReadoutSideband() {
      return (
        !!this.sidebandCursorPoints?.length &&
        this.singlePointerPoint != null &&
        this.singlePointerPoint.xAxis != null
      );
    },
    showReadoutPeak() {
      return !!(this.cursorHightPoints && this.cursorHightPoints.length);
    },
    showReadoutHarmonic() {
      return !!(this.harmonicCursorPoints && this.harmonicCursorPoints.length);
    },
  },
  watch: {
    // immediate：开发热更新重挂载时 props 引用未变，普通 watch 不触发，会导致 spectrumList 仍是 {}、图表空白
    spectrumListTwo: {
      handler(newValue) {
        this.spectrumList =
          newValue && typeof newValue === "object" ? newValue : {};
        if (
          this.chartInstance &&
          Array.isArray(this.spectrumList?.y) &&
          Array.isArray(this.spectrumList?.x) &&
          this.spectrumList.y.length === this.spectrumList.x.length
        ) {
          this.updateChart(this.spectrumList.y, this.spectrumList.x);
          this.updateFeatureLinesByGroup();
        }
      },
      immediate: true,
      deep: true,
    },
    spectrumList(newVal) {
      if (!newVal) return;

      this.$nextTick(() => {
        this.updateFeatureLinesByGroup();
      });
    },
    currentRow: {
      deep: true,
      handler() {
        this.$nextTick(() => {
          this.updateFeatureLinesByGroup();
        });
      },
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.initializeChart();

      window.addEventListener("resize", this.handleResize);
      // 数据由父组件统一刷新（props: spectrumListTwo），同步依赖 watch immediate
    });
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.handleResize);
    if (this.chartInstance) {
      this.disableSinglePointer?.();
      this.chartInstance.getZr().off("dblclick", this.handleDoubleClick);
      this.chartInstance.dispose();
      this.chartInstance = null;
    }
  },
  methods: {
    /** 频率类数值展示：统一保留 6 位小数（特征竖线标签、光标读数等） */
    formatNumericFreq(v) {
      const n = Number(v);
      if (Number.isNaN(n)) return null;
      return Math.abs(n) >= 1000 ? n.toFixed(2) : n.toFixed(6);
    },
    toFinitePositiveNumber(raw) {
      if (raw === null || raw === undefined || raw === "") return null;
      if (typeof raw === "number") {
        return Number.isFinite(raw) && raw > 0 ? raw : null;
      }
      if (typeof raw === "string") {
        const s = raw.trim();
        if (!s) return null;
        const direct = Number(s);
        if (Number.isFinite(direct) && direct > 0) return direct;
        const m = s.match(/-?\d+(?:\.\d+)?/);
        if (!m) return null;
        const n = Number(m[0]);
        return Number.isFinite(n) && n > 0 ? n : null;
      }
      return null;
    },
    normalizeIdToken(v) {
      if (v === undefined || v === null) return "";
      return String(v).trim();
    },
    normalizeTimeToken(v) {
      if (v === undefined || v === null) return "";
      return String(v).trim().replace(/\s+/g, " ");
    },
    timeTokensEffectivelyEqual(a, b) {
      const na = this.normalizeTimeToken(a);
      const nb = this.normalizeTimeToken(b);
      if (na === nb) return true;
      const da = Date.parse(String(a).replace(/-/g, "/"));
      const db = Date.parse(String(b).replace(/-/g, "/"));
      if (!Number.isFinite(da) || !Number.isFinite(db)) return false;
      return da === db;
    },
    extractRpmFromRow(row) {
      if (!row) return null;
      const od = row.otherData || {};
      const candidates = [
        row.rotationalSpeed,
        row.rotationSpeed,
        od.RPM,
        od.rpm,
        od.rotationalSpeed,
        od.rotationSpeed,
      ];
      for (const raw of candidates) {
        const n = this.toFinitePositiveNumber(raw);
        if (n != null) return n;
      }
      return null;
    },
    getStrictAnchor() {
      const routeId = this.normalizeIdToken(this.routeAnalysisId);
      const routeTime = this.normalizeTimeToken(this.routeAnalysisTime);
      if (routeId) {
        return { id: routeId, time: routeTime };
      }
      const cur = this.currentRow || {};
      const curId = this.normalizeIdToken(cur.id ?? cur.itemKey);
      const curTime = this.normalizeTimeToken(
        cur.timeStamp ?? cur.itemValue ?? "",
      );
      return { id: curId, time: curTime };
    },
    recordMatchesAnchor(row) {
      const { id: anchorId, time: anchorTime } = this.getStrictAnchor();
      if (!anchorId || !row) return false;
      if (this.normalizeIdToken(row.id ?? row.itemKey) !== anchorId) {
        return false;
      }
      if (anchorTime) {
        return this.timeTokensEffectivelyEqual(
          row.timeStamp ?? row.itemValue ?? "",
          anchorTime,
        );
      }
      return true;
    },
    /** sessionStorage+路由 合并对象：id（及可选 time）与当前分析一致时才用其中的 RPM */
    findRpmFromDeepLinkSpectrumContext() {
      const ctx = this.deepLinkSpectrumContext;
      if (!ctx || typeof ctx !== "object") return null;
      const anchorId = this.normalizeIdToken(
        this.routeAnalysisId || this.currentRow?.id || this.currentRow?.itemKey,
      );
      if (!anchorId) return null;
      const cid = this.normalizeIdToken(ctx.id ?? ctx.itemKey);
      if (cid !== anchorId) return null;
      const wantTime = this.normalizeTimeToken(this.routeAnalysisTime);
      if (wantTime) {
        if (
          !this.timeTokensEffectivelyEqual(
            ctx.timeStamp ?? ctx.itemValue ?? "",
            wantTime,
          )
        ) {
          return null;
        }
      }
      return this.extractRpmFromRow(ctx);
    },
    /** 仅扫历史图表 rowData，不用 measurementPointData（避免默认列表错行） */
    findRpmFromStrictChartSnapshots() {
      const { id: anchorId } = this.getStrictAnchor();
      if (!anchorId) return null;
      const snapshots = Array.isArray(this.chartRowSnapshots)
        ? this.chartRowSnapshots
        : [];
      for (const item of snapshots) {
        const rd = item?.rowData;
        if (rd && this.recordMatchesAnchor(rd)) {
          const r = this.extractRpmFromRow(rd);
          if (r != null) return r;
        }
      }
      return null;
    },
    formatCursorPair(freqNum, ampVal) {
      const xl = this.spectrumXLabel;
      const yl = this.spectrumYLabel;
      const numStr = this.formatNumericFreq(freqNum);
      const left = numStr == null ? "—" : `${numStr} ${xl}`;
      const amp =
        ampVal === null || ampVal === undefined || ampVal === ""
          ? null
          : String(ampVal);
      const right = amp == null ? "—" : `${amp} ${yl}`;
      return `${left}；${right}`;
    },
    normalizeFeatureName(name) {
      if (!name) return "";
      return String(name)
        .replace(/GEN-NDE/g, "GEN NDE")
        .trim();
    },
    buildFeatureMultipleMap() {
      const map = {};
      const ratioMap = {};
      (failureFrequency || []).forEach((part) => {
        const partRatioRaw = part?.ratio;
        const partRatio =
          partRatioRaw != null && partRatioRaw !== ""
            ? Number(partRatioRaw)
            : 1;
        const r = Number.isFinite(partRatio) ? partRatio : 1;
        (part.faultFrequencies || []).forEach((item) => {
          if (!item?.name) return;
          const key = this.normalizeFeatureName(item.name);
          map[key] = Number(item.multiple);
          ratioMap[key] = r;
        });
      });
      // 兼容页面中的中文别名
      if (map.Blade != null) {
        map.叶片频率 = map.Blade;
        ratioMap.叶片频率 = ratioMap.Blade != null ? ratioMap.Blade : 1;
      }
      map.转速频率 = 1;
      ratioMap.转速频率 = ratioMap.Speed != null ? ratioMap.Speed : 1;
      this.featureMultipleMap = map;
      this.featureRatioMap = ratioMap;
    },
    getFeatureMultipleByName(name) {
      const normalized = this.normalizeFeatureName(name);
      if (this.featureMultipleMap[normalized] != null) {
        return this.featureMultipleMap[normalized];
      }
      // 兼容 GEN-NDE / GEN NDE 两种写法
      const swapped = normalized.includes("GEN NDE")
        ? normalized.replace("GEN NDE", "GEN-NDE")
        : normalized.replace("GEN-NDE", "GEN NDE");
      if (this.featureMultipleMap[swapped] != null) {
        return this.featureMultipleMap[swapped];
      }
      return null;
    },
    /** 传动比：来自 failureFrequency.json 中该特征所属部件的 ratio，缺省为 1 */
    getFeatureRatioByName(name) {
      const normalized = this.normalizeFeatureName(name);
      const m = this.featureRatioMap || {};
      if (m[normalized] != null && Number.isFinite(Number(m[normalized]))) {
        return Number(m[normalized]);
      }
      const swapped = normalized.includes("GEN NDE")
        ? normalized.replace("GEN NDE", "GEN-NDE")
        : normalized.replace("GEN-NDE", "GEN NDE");
      if (m[swapped] != null && Number.isFinite(Number(m[swapped]))) {
        return Number(m[swapped]);
      }
      return 1;
    },
    /** 「齿轮特征」分组下的叶子项：不乘传动比，轴转频 = RPM/60（与轴承/转动等其它分组区分） */
    isGearGroupFeatureName(name) {
      const n = this.normalizeFeatureName(name);
      const gear = this.featureGroups.find((g) => g.type === "gear");
      const leaves = (gear?.children || []).filter(
        (c) => typeof c === "string",
      );
      return leaves.some((leaf) => this.normalizeFeatureName(leaf) === n);
    },
    /**
     * 特征竖线：非齿轮特征 X = (RPM×传动比/60)×倍频；齿轮特征 X = (RPM/60)×倍频
     * 转速来源：树节点 otherData.RPM 优先，其次行上 rotationalSpeed（与波形接口一致）
     */
    getRotationalSpeedRpm() {
      const cur = this.currentRow || {};
      const od = cur.otherData || {};
      const sp = this.spectrumList || {};
      const spOd =
        sp.otherData && typeof sp.otherData === "object" ? sp.otherData : {};
      const candidates = [
        od.RPM,
        od.rpm,
        od.rotationalSpeed,
        od.rotationSpeed,
        cur.rotationalSpeed,
        cur.rotationSpeed,
        sp.RPM,
        sp.rpm,
        sp.rotationalSpeed,
        sp.rotationSpeed,
        spOd.RPM,
        spOd.rpm,
        spOd.rotationalSpeed,
        spOd.rotationSpeed,
      ];
      for (const raw of candidates) {
        const n = this.toFinitePositiveNumber(raw);
        if (n != null) return n;
      }
      const fromDeepLink = this.findRpmFromDeepLinkSpectrumContext();
      if (fromDeepLink != null) return fromDeepLink;
      const fromCharts = this.findRpmFromStrictChartSnapshots();
      if (fromCharts != null) return fromCharts;
      return null;
    },
    handleResize() {
      this.chartInstance?.resize();
    },
    handleFeatureChange() {
      // 1️⃣ 汇总所有选中的特征
      const allSelected = Object.values(this.selectedMap).flat();

      this.checkedFeatures = allSelected;

      // 2️⃣ 更新图表
      this.updateFeatureLinesByGroup();
    },
    handleCascaderChange(val) {
      // console.log(
      //   this.spectrumListTwo,
      //   val,
      //   "spectrumListTwo",
      //   this.spectrumList,
      // );
      this.manualFreq = "";
      this.multiple = 1;

      if (!val || val.length === 0) {
        this.checkedFeatures = [];
        this.renderFeatureSeries([]);
        return;
      }
      // 👉 1. 提取最后一层（真正特征）
      this.checkedFeatures = val
        .map((item) => item[item.length - 1])
        .filter(Boolean);
      console.log(this.checkedFeatures, "checkedFeatures");
      // 👉 3. 更新图表
      this.updateFeatureLinesByGroup();
    },
    selectCursor(val) {
      // 光标选择逻辑：
      // - 「单指针」与「边带光标」允许同时选中（边带依赖单指针中心）
      // - 其它光标（谐波光标 / 移动峰值）保持单选互斥
      const isAlreadyChecked = this.checkedGB.includes(val);

      const isSinglePointerVal = val === "单指针";
      const isSidebandVal = val === "边带光标";
      const isHarmonicVal = val === "谐波光标";
      const isMovePeakVal = val === "移动峰值";

      if (isAlreadyChecked) {
        // 取消选中
        if (isSinglePointerVal) {
          // 单指针被取消时：边带依赖单指针中心，直接级联取消边带并清除边带设置
          this.checkedGB = this.checkedGB.filter(
            (v) => v !== "单指针" && v !== "边带光标",
          );
        } else {
          // 其它：仅移除当前项
          this.checkedGB = this.checkedGB.filter((v) => v !== val);
        }
      } else if (isSinglePointerVal || isSidebandVal) {
        // 单指针/边带：在现有基础上追加（保留对方）
        const next = new Set(this.checkedGB);
        next.add(val);
        // 但如果此时已经选了「谐波光标」或「移动峰值」，需要清掉（它们保持单选）
        next.delete("谐波光标");
        next.delete("移动峰值");
        this.checkedGB = Array.from(next);
      } else if (isHarmonicVal || isMovePeakVal) {
        // 其它：单选互斥（会清掉单指针/边带）
        this.checkedGB = [val];
      } else {
        this.checkedGB = [val];
      }
      console.log(this.checkedGB, "this.checkedGB");
      const isMoveChecked = this.checkedGB.includes("移动峰值");
      const isSidebandChecked = this.checkedGB.includes("边带光标");
      const isHarmonicChecked = this.checkedGB.includes("谐波光标");
      const isSinglePointer = this.checkedGB.includes("单指针");

      // 峰值 / 谐波 与 单指针+边带 互斥：先清边带与单指针线，再画峰值或谐波（避免只清状态、线残留）
      if (isMoveChecked || isHarmonicChecked) {
        this.disableSidebandCursor();
        this.disableSinglePointer();
      }

      isMoveChecked ? this.handleMoveCursor() : this.removeCursor();
      isSidebandChecked
        ? this.enableSidebandCursor()
        : this.disableSidebandCursor();
      isHarmonicChecked
        ? this.enableHarmonicCursor()
        : this.disableHarmonicCursor();
      // 单指针：
      // - 只要没选中「单指针」→ 移除单指针线+解绑事件
      // - 选中「单指针」且未启用「边带光标」→ 允许点击移动单指针
      // - 选中「单指针」且启用「边带光标」→ 冻结单指针（保留线，不允许点击移动）
      if (!isSinglePointer) {
        this.disableSinglePointer();
      } else if (isSidebandChecked) {
        // 冻结：仅解绑 click，不删除单指针线
        this.unbindSinglePointerClick?.();
      } else {
        this.enableSinglePointer();
      }
    },
    initializeChart() {
      const chartDom = this.$refs.chart;
      if (chartDom && !this.chartInstance) {
        this.chartInstance = echarts.init(chartDom);
        this.chartInstance.getZr().on("dblclick", this.handleDoubleClick);
      }

      this.$nextTick(() => {
        if (this.chartInstance && this.spectrumList.y && this.spectrumList.x) {
          this.updateChart(this.spectrumList.y, this.spectrumList.x);
        }
      });
    },
    handleFreqRange() {
      const min = Number(this.freqMin);
      const max = Number(this.freqMax);

      if (isNaN(min) || isNaN(max)) return;

      this.chartInstance.setOption({
        xAxis: { min, max },
      });
    },
    handleMark() {
      const freq = Number(this.manualFreq);
      const multiple = Number(this.multiple) || 1;

      if (isNaN(freq)) return;

      const marks = [];

      for (let i = 1; i <= multiple; i++) {
        marks.push({
          xAxis: freq * i,
          val: `${i}x`,
        });
      }

      this.manualMarks = marks;
      this.renderManualMarks();
    },
    renderManualMarks() {
      const option = this.chartInstance.getOption();

      const manualSeries = {
        id: "MANUAL_MARK",
        type: "line",
        markLine: {
          symbol: ["none", "none"],
          lineStyle: {
            color: "#ff0000",
            width: 2,
            type: "dashed",
          },
          label: {
            formatter: ({ data }) => data.val,
          },
          data: this.manualMarks,
        },
      };

      this.chartInstance.setOption({
        series: [
          ...(option.series || []).filter((s) => s && s.id !== "MANUAL_MARK"),
          manualSeries,
        ],
      });
    },
    updateFeatureLinesByGroup() {
      console.log(this.spectrumList, "updateFeatureLinesByGroup");
      if (!this.spectrumList) return;
      const rpm = this.getRotationalSpeedRpm();
      console.log(rpm, "rpm");
      if (rpm == null) {
        this.renderFeatureSeries([]);
        if (this.checkedFeatures.length && !this.rpmMissingWarned) {
          this.rpmMissingWarned = true;
          this.$message.warning(
            "当前数据缺少有效转速(RPM)，无法计算特征频率标注",
          );
        }
        return;
      }
      this.rpmMissingWarned = false;
      const featureLines = this.checkedFeatures
        .map((name) => {
          const multiple = this.getFeatureMultipleByName(name);
          if (multiple == null || Number.isNaN(multiple)) return null;
          const ratio = this.getFeatureRatioByName(name);
          console.log(multiple, "multiple");
          console.log(rpm, ratio, "rpm, ratio");
          const shaftHz = this.isGearGroupFeatureName(name)
            ? rpm / 60
            : (rpm * ratio) / 60;
          const x = shaftHz * Number(multiple);
          if (!Number.isFinite(x)) return null;
          const freqStr = this.formatNumericFreq(x);
          const xl = this.spectrumXLabel;
          const labelText =
            freqStr != null ? `${name}: ${freqStr} ${xl}` : `${name}`;
          return {
            Xaxis: x,
            val: labelText,
          };
        })
        .filter(Boolean);
      console.log(featureLines, "featureLines");
      this.renderFeatureSeries(featureLines);
    },

    updateChart(data, labels) {
      if (
        !this.chartInstance ||
        !Array.isArray(labels) ||
        !Array.isArray(data) ||
        labels.length !== data.length
      ) {
        console.error("Invalid data or labels");
        return;
      }
      console.log(this.spectrumList, "updataChart  频谱图");
      const createMarkLine = (dataSource, color) => ({
        type: "line",
        markLine: {
          silent: false,
          lineStyle: { color, type: "dashed", width: 2 },
          symbol: ["none", "none"],
          label: {
            show: true,
            position: "end",
            formatter: ({ data }) => data.val,
          },
          emphasis: {
            lineStyle: { color: "#FF6A00", width: 4, type: "dashed" },
            label: {
              show: true,
              formatter: ({ value }) => `特征值: ${value}`,
              color: "#000",
              backgroundColor: "#FFF",
              padding: [2, 4],
              borderRadius: 3,
              fontSize: 12,
            },
          },
          data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
        },
      });

      const markLines = [
        { data: this.Fr, color: "#A633FF" },
        { data: this.BPFI, color: "#23357e" },
        { data: this.BPFO, color: "#42a0ae" },
        { data: this.BSF, color: "#008080" },
        { data: this.FTF, color: "#af254f" },
        { data: this.B3P, color: "#FFD700" },
      ].map(({ data, color }) => createMarkLine(data, color));

      const option = {
        grid: {
          left: 60, // 原来是100，适当缩小左右边距
          right: 20,
          // top: 90, // 给推拽条和坐标轴腾出空间
          top: 30,
          bottom: 50,
        },
        // title: {
        //   text: this.spectrumList.title || "",
        //   left: "center",
        //   top: 0,
        //   textStyle: {
        //     fontSize: 15,
        //     fontWeight: 600,
        //     color: "#303133",
        //   },
        //   padding: [0, 12, 6, 12],
        // },
        toolbox: {
          right: 10,
          // top: 55, // 👈 工具栏在最上面
          feature: {
            dataZoom: { yAxisIndex: "none" },
            restore: {},
            saveAsImage: {},
          },
        },
        xAxis: {
          type: "value",
          name: this.spectrumList.xaxis,
          nameLocation: "center",
          nameTextStyle: {
            fontSize: 12,
            color: "#333",
            padding: [10, 0, 0, 0], // 增加X轴标题和轴线的距离
          },
          axisLabel: {
            margin: 1, // 增加数值标签和轴线的间距
            formatter: (value) => value,
          },
        },
        yAxis: {
          type: "value",
          name: this.spectrumList.yaxis,
          nameTextStyle: {
            fontSize: 12,
            color: "#333",
            padding: [10, 0, 0, 0],
          },
        },
        tooltip: {
          trigger: "axis",
          formatter: ([
            {
              value: [x, y],
            },
          ]) => `X: ${x}<br/>Y: ${y}`,
          axisPointer: { type: "line" },
        },
        // 无滑块；工具栏「区域缩放」需 dataZoom 组件：用不可见 inside，关闭滚轮
        dataZoom: [
          {
            type: "inside",
            xAxisIndex: 0,
            filterMode: "none",
            zoomOnMouseWheel: false,
            moveOnMouseMove: false,
            moveOnMouseWheel: false,
          },
        ],
        series: [
          {
            id: "MAIN_SPECTRUM_SERIES",
            name: "数据系列",
            type: "line",
            data: labels.map((x, i) => [x, data[i]]),
            symbol: "none",
            lineStyle: { color: "#162961", width: 1 },
            itemStyle: {
              color: "#162961",
              borderColor: "#fff",
              borderWidth: 1,
            },
            large: true,
            progressive: 2000,
          },
          ...markLines,
        ],
      };

      this.chartInstance.setOption(option, true);
      this.$nextTick(() => {
        if (this.singlePointerPoint) {
          this.applySinglePointerSeries();
        }
      });
    },
    /**
     * 特征竖线必须挂在「数据系列」上（与频谱折线同一 series）。
     * 若用独立的无 data 的 line + markLine，ECharts 无法对齐 x 轴，竖线会全部画在 x=0。
     */
    renderFeatureSeries(featureLines) {
      if (!this.chartInstance) return;

      const colors = [
        "#A633FF",
        "#23357e",
        "#42a0ae",
        "#008080",
        "#af254f",
        "#FFD700",
        "#ff7f50",
        "#00bcd4",
      ];

      const markLineData = (featureLines || [])
        .map((line, i) => {
          const x = Number(line.Xaxis);
          if (!Number.isFinite(x)) return null;
          const text = line.val != null ? String(line.val) : "";
          return {
            xAxis: x,
            lineStyle: {
              color: colors[i % colors.length],
              type: "dashed",
              width: 2,
            },
            label: {
              show: true,
              position: "end",
              formatter: text,
            },
          };
        })
        .filter(Boolean);

      this.chartInstance.setOption(
        {
          series: [
            {
              id: "MAIN_SPECTRUM_SERIES",
              // 特征值仅作为展示，不参与点击交互，避免触发额外事件链
              markLine: {
                silent: true,
                symbol: ["none", "none"],
                data: markLineData,
              },
            },
          ],
        },
        false,
        true,
      );
    },
    // 获取数据
    getTime() {
      this.$emit("handleLoading", {
        id: this.chartId,
        currentRow: this.currentRow,
        loading: true,
      });
      const params = {
        ids: this.ids,
        windCode: this.windCode,
        analysisType: "frequency",
      };
      axios
        .post("/AnalysisMulti/analysis/frequency", params)
        .then((res) => {
          this.spectrumList = { ...JSON.parse(res.data) };

          console.log(this.spectrumList, "频谱图数据1");

          const XrmsValue = this.spectrumList?.Xrms;
          this.$emit("updateXrms", XrmsValue);
          // 拉完数据后，如果已有选中项，自动渲染
          this.$nextTick(() => {
            this.updateFeatureLinesByGroup();
          });
        })
        .catch((error) => {
          console.error(error);
        })
        .finally(() => {
          this.$emit("handleLoading", {
            id: this.chartId,
            currentRow: this.currentRow,
            loading: false,
          });
        });
    },

    Show(value) {
      const stateMap = {
        1: { TZshow: true, BGshow: false, PXshow: false },
        2: { TZshow: false, BGshow: true, PXshow: false },
        3: { TZshow: false, BGshow: false, PXshow: true },
      };

      if (stateMap[value]) {
        this.TZshow = value === "1" ? !this.TZshow : false;
        this.BGshow = value === "2" ? !this.BGshow : false;
        this.PXshow = value === "3" ? !this.PXshow : false;
      }
    },
  },
  created() {
    this.buildFeatureMultipleMap();
  },
};
</script>

<style lang="scss" scoped>
.line-chart {
  width: 100%;
  height: 400px;
}

.FD {
  width: 100%;
  height: 1px;
  position: relative;
}

.eigenvalue {
  position: absolute;
  top: 60px;
  right: 0;
  font-size: 10px;
  width: 146px;
  border: 1px solid rgb(182, 182, 182);
  padding: 5px;
  background: #fff;
  z-index: 99;
  border-radius: 5px;
  h5 {
    line-height: 16px;
    height: 16px;
  }
}
.eigenvalue--first {
  width: 100px;
}
.control-panel {
  /* 按控件区域实际宽度断点（嵌入侧栏时比视口媒体查询可靠） */
  container-name: control-panel;
  container-type: inline-size;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 6px;
  padding: 8px 12px;
  background: #f5f7fa;
  border: 1px solid #ddd;
  border-radius: 6px;
  margin-bottom: 10px;
}
/* 🌟 独占一行；容器宽度 ≤600 时频率块全宽，>600 时约半宽 */
.full-row {
  width: 100%;
  display: flex;
  justify-content: space-between;
  .panel-block {
    width: 92%;
  }
}

@container control-panel (min-width: 701px) {
  .full-row .panel-block {
    width: 45%;
  }
}
.panel-block {
  display: flex;
  align-items: center;
  gap: 6px;
}

.label {
  font-size: 12px;
  color: #666;
}
.label1 {
  font-size: 12px;
  color: #666;
  display: inline-block;
  width: 75px;
}

.btn-group {
  display: flex;
  gap: 6px;
}

.btn {
  padding: 2px 8px;
  font-size: 12px;
  border: 1px solid #ccc;
  border-radius: 3px;
  cursor: pointer;
}

.btn.active {
  background: #409eff;
  color: #fff;
}
.full-width {
  width: 100%;
}

.el-cascader {
  font-size: 12px;
}

.el-cascader__tags {
  max-width: 240px;
  overflow: hidden;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr); // 两列布局
  gap: 10px;
  width: 100%;
}

.feature-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.el-select {
  flex: 1;
}

.pannel {
  margin: 5px;
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.5;
  // color: #303133;
  background: #f5f7fa;
  border: 1px solid #ddd;
  border-radius: 4px;
  display: flex;
}
.pannel-row {
  display: flex;
  align-items: flex-start;
  margin: 0px 10px;
  // margin-right: 5px;
  // gap: 5px;
  // margin-bottom: 4px;
  &:last-child {
    margin-bottom: 0;
  }
}
.pannel-key {
  // flex: 0 0 37px;
  // flex: 0 0 45px;
  color: #666;
}
.pannel-val {
  flex: 1;
  word-break: break-all;
}
</style>
