Forráskód Böngészése

Merge branch 'master' of http://192.168.50.233:3000/rui.jiang/performance-test

liujiejie 3 hónapja
szülő
commit
6109475834

+ 322 - 0
src/views/health/components/cursorReferenceMixin copy.js

@@ -0,0 +1,322 @@
+// cursorReferenceMixin.js
+// import * as echarts from "echarts";
+
+export default {
+  data() {
+    return {
+      // 参考线相关数据
+      cursorHightPoints: [], // 存储所有参考线
+      currentCursorIndex: -1, // 当前参考线索引
+      peakPoints: [], // 存储所有峰值点
+      isHandlingCursor: false, // 防止重复处理
+      chartInstance: null, // ECharts实例
+    };
+  },
+
+  mounted() {
+    // 监听键盘事件
+    window.addEventListener("keydown", this.handleKeyDown);
+  },
+
+  beforeDestroy() {
+    // 移除事件监听
+    window.removeEventListener("keydown", this.handleKeyDown);
+  },
+
+  methods: {
+    /**
+     * 处理按钮点击生成参考线
+     */
+    handleMoveCursor() {
+      console.log("handleMoveCursor", "222");
+      if (this.isHandlingCursor || !this.spectrumList) return;
+      this.isHandlingCursor = true;
+
+      // 1. 找到所有峰值点
+      this.findPeakPoints();
+
+      // 2. 如果没有峰值点则返回
+      if (this.peakPoints.length === 0) {
+        this.isHandlingCursor = false;
+        return;
+      }
+
+      // 3. 找到Y轴最大值点
+      const maxPeak = this.peakPoints.reduce((prev, current) =>
+        prev.y > current.y ? prev : current
+      );
+
+      // 4. 创建参考线数据
+      const referenceLine = {
+        xAxis: maxPeak.x,
+        val: maxPeak.y.toFixed(2),
+        index: maxPeak.index,
+      };
+
+      // 5. 更新参考线
+      this.cursorHightPoints = [referenceLine];
+      this.currentCursorIndex = this.peakPoints.findIndex(
+        (p) => p.index === maxPeak.index
+      );
+
+      // 6. 更新图表
+      this.updateCursorElements2();
+
+      this.isHandlingCursor = false;
+    },
+
+    /**
+     * 查找所有峰值点
+     */
+    findPeakPoints() {
+      this.peakPoints = [];
+      const yValues = this.spectrumList.y;
+
+      // 简单峰值检测算法 - 比相邻点都高的点
+      for (let i = 1; i < yValues.length - 1; i++) {
+        if (yValues[i] > yValues[i - 1] && yValues[i] > yValues[i + 1]) {
+          this.peakPoints.push({
+            x: this.spectrumList.x[i],
+            y: yValues[i],
+            index: i,
+          });
+        }
+      }
+
+      // 按X轴排序
+      this.peakPoints.sort((a, b) => a.x - b.x);
+    },
+
+    /**
+     * 处理键盘事件
+     */
+    handleKeyDown(event) {
+      if (this.cursorHightPoints.length === 0) return;
+
+      switch (event.keyCode) {
+        case 37: // 左箭头
+          this.moveCursorToLeft();
+          break;
+        case 39: // 右箭头
+          this.moveCursorToRight();
+          break;
+        default:
+          return;
+      }
+
+      // 阻止默认行为
+      event.preventDefault();
+    },
+
+    /**
+     * 向左移动参考线
+     */
+    moveCursorToLeft() {
+      if (this.currentCursorIndex <= 0) return;
+
+      const newIndex = this.currentCursorIndex - 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+    },
+
+    /**
+     * 向右移动参考线
+     */
+    moveCursorToRight() {
+      if (this.currentCursorIndex >= this.peakPoints.length - 1) return;
+
+      const newIndex = this.currentCursorIndex + 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+    },
+
+    /**
+     * 更新参考线位置
+     */
+    updateCursorPosition(peak, index) {
+      this.cursorHightPoints = [
+        {
+          xAxis: peak.x,
+          val: peak.y.toFixed(2),
+          index: peak.index,
+        },
+      ];
+      console.log(this.cursorHightPoints,'updateCursorPosition');
+      
+      this.currentCursorIndex = index;
+      this.$nextTick(()=>{
+        this.updateCursorElements2();
+      })
+    },
+    /**
+     * 获取已有参考线配置
+     */
+    getExistingMarkLines() {
+      if (!this.chartInstance) return;
+
+      const option = this.chartInstance.getOption();
+      this.existingMarkLines = [];
+
+      // 遍历所有series查找markLine配置
+      option.series.forEach((series) => {
+        if (series.markLine && series.markLine.data) {
+          // 过滤掉峰值参考线(避免重复)
+          const nonPeakLines = series.markLine.data.filter(
+            (line) => !line.id || line.id !== "PEAK_REFERENCE_LINE"
+          );
+          this.existingMarkLines.push(...nonPeakLines);
+        }
+      });
+    },
+
+    /**
+     * 更新参考线元素(不覆盖已有参考线)
+     */
+    updateCursorElements2() {
+      if (!this.chartInstance) return;
+
+      // 1. 获取当前图表配置中的已有series
+      const currentOption = this.chartInstance.getOption();
+      const existingSeries = currentOption.series || [];
+
+      // 2. 过滤掉旧的峰值参考线(通过id或特定标记识别)
+      const filteredSeries = existingSeries.filter(
+        (series) => !series.id || !series.id.includes("PEAK_REFERENCE")
+      );
+      console.log(filteredSeries);
+
+      // 3. 准备新的峰值参考线配置
+      const cursorHighLineSeries = {
+        id: "PEAK_REFERENCE_LINE",
+        type: "line",
+        markLine: {
+          data: this.cursorHightPoints.map((point) => ({
+            xAxis: point.xAxis,
+            label: {
+              formatter: "峰值: " + point.val,
+            },
+            lineStyle: {
+              color: "#FF0000",
+            },
+          })),
+        },
+      };
+
+      const cursorPointSeries = {
+        id: "PEAK_REFERENCE_POINT",
+        type: "scatter",
+        symbol: "circle",
+        symbolSize: 8,
+        itemStyle: { color: "#FF0000" },
+        data: this.cursorPoints.map((point) => ({
+          value: [point.xAxis, point.yAxis],
+          name: point.val,
+        })),
+        label: {
+          show: true,
+          formatter: "{@[1]}",
+          position: "top",
+          color: "#FF0000",
+          fontSize: 12,
+          backgroundColor: "rgba(255,255,255,0.7)",
+          padding: [2, 4],
+          borderRadius: 3,
+        },
+      };
+
+      // 4. 合并所有series配置
+      const allSeries = [
+        ...filteredSeries, // 保留已有series
+        cursorHighLineSeries, // 添加新的峰值参考线
+        cursorPointSeries, // 添加新的峰值参考点
+      ];
+
+      // 5. 更新图表配置
+      this.chartInstance.setOption(
+        {
+          series: allSeries,
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+    },
+    // /**
+    //  * 仅更新参考线元素
+    //  */
+    // updateCursorElements2() {
+    //   if (!this.chartInstance) return;
+    //   const cursorLineSeries = {
+    //     type: "line",
+    //     markLine: {
+    //       data: this.cursorHightPoints.map((point) => ({
+    //         xAxis: point.xAxis,
+    //         label: {
+    //           formatter: "峰值: " + point.val,
+    //         },
+    //         lineStyle: {
+    //           color: "#FF0000",
+    //         },
+    //       })),
+    //     },
+    //   };
+
+    //   if (this.chartInstance) {
+    //     this.chartInstance.setOption(
+    //       {
+    //         series: [
+    //           {
+    //             name: "数据系列",
+    //             type: "line",
+    //             data: this.spectrumList.x.map((x, i) => [
+    //               x,
+    //               this.spectrumList.y[i],
+    //             ]),
+    //             symbol: "none",
+    //             lineStyle: { color: "#162961", width: 1 },
+    //             itemStyle: {
+    //               color: "#162961",
+    //               borderColor: "#fff",
+    //               borderWidth: 1,
+    //             },
+    //             large: true,
+    //           },
+    //           ...this.generateSeries({
+    //             Fr: this.Fr,
+    //             BPFI: this.BPFI,
+    //             BPFO: this.BPFO,
+    //             BSF: this.BSF,
+    //             FTF: this.FTF,
+    //             B3P: this.B3P,
+    //           }),
+    //           cursorLineSeries,
+    //         ],
+    //       },
+    //       { replaceMerge: ["series"] }
+    //     );
+    //   }
+    // },
+
+    /**
+     * 获取参考线markLine配置
+     */
+    getCursorMarkLineConfig() {
+      return {
+        data: this.cursorHightPoints.map((point) => ({
+          xAxis: point.xAxis,
+          label: {
+            formatter: "峰值: " + point.val,
+          },
+          lineStyle: {
+            color: "#FF0000",
+          },
+        })),
+        symbol: ["none", "none"],
+        silent: true,
+      };
+    },
+  },
+};

+ 107 - 6
src/views/health/components/envelopecharts.vue

@@ -16,7 +16,7 @@
         @input="handleInput"
       ></el-input>
       <el-button size="small" @click="chaxun">确定</el-button>
-      <div v-if="TZshow" class="eigenvalue">
+      <div v-if="PXshow" class="eigenvalue">
         <el-checkbox-group v-model="checkedValues" @change="handleCheckChange">
           <el-checkbox
             v-for="(item, index) in PXcheckList"
@@ -27,6 +27,16 @@
           </el-checkbox>
         </el-checkbox-group>
       </div>
+      <!-- 光标 -->
+      <div v-if="BGshow" class="eigenvalue">
+        <el-checkbox-group v-model="checkedGB" @change="handlecursor">
+          <el-checkbox v-for="(item, index) in GBcheckList" :key="index" :label="item.val" :disabled="item.disabled">
+            {{ item.val }}
+          </el-checkbox>
+        </el-checkbox-group>
+      </div>
+
+      
     </div>
 
     <div class="line-chart" ref="chart"></div>
@@ -36,9 +46,14 @@
 <script>
 import * as echarts from "echarts"; // 导入 echarts 库
 import axios from "axios";
-import { log } from "plotly.js-dist";
+import Bdgb from "./envelopecharts/Bdgb";
+import Xdgb from "./envelopecharts/Xdgb";
+import Tjgb from "./envelopecharts/Tjgb";
+import cursorReferenceMixin from "./envelopecharts/cursorReferenceMixin";
+
 export default {
   name: "TimedomainCharts", // 组件名称
+  mixins: [ cursorReferenceMixin,Bdgb, Xdgb, Tjgb],
   props: {
     // 可以通过 props 接收外部传入的数据
     currentIndex: {
@@ -74,7 +89,14 @@ export default {
       daval: "",
       envelopeList: {},
       TZshow: false,
-
+      BGshow: false,
+      PXshow: false,
+      GBcheckList: [
+        { val: "添加光标", checked: false, disabled: false },
+        { val: "谐波光标", checked: false, disabled: false },
+        { val: "边带光标", checked: false, disabled: false },
+        { val: "移动峰值", checked: false, disabled: false },
+      ],
       PXcheckList: [
         { val: "Fr", checked: false },
         { val: "BPFI", checked: false },
@@ -92,6 +114,9 @@ export default {
 
       checkedGB: [],
       checkedValues: [],
+
+          // 添加光标
+    cursorPoints: [], // 存储参考点数据
     };
   },
   watch: {
@@ -105,8 +130,68 @@ export default {
   },
   mounted() {
     this.initializeChart();
+    this.$nextTick(() => {
+    if (this.chartInstance) {
+      this.chartInstance.getZr().on('dblclick', this.handleDoubleClick);
+    }
+  });
   },
+  beforeDestroy() {
+    if (this.chartInstance) {
+      this.chartInstance.getZr().off("dblclick", this.handleDoubleClick);
+      this.chartInstance
+        .getZr()
+        .off("mousemove", this.handleSidebandCursorMove);
+      this.chartInstance.dispose();
+    }
+  },
+  
   methods: {
+
+    
+
+
+    handlecursor() {
+      // 特殊光标类型数组
+      const specialCursors = ["添加光标","移动峰值", "边带光标", "谐波光标"];
+
+      // 检查是否有多个特殊光标被选中
+      const selectedSpecials = specialCursors.filter((type) =>
+        this.checkedGB.includes(type)
+      );
+
+      // 如果多于1个,则只保留第一个
+      if (selectedSpecials.length > 1) {
+        this.checkedGB = [
+          ...this.checkedGB.filter((val) => !specialCursors.includes(val)),
+          selectedSpecials[0], // 保留第一个选中的
+        ];
+      }
+
+      // 其余逻辑保持不变...
+      const isMoveChecked = this.checkedGB.includes("移动峰值");
+      const isSidebandChecked = this.checkedGB.includes("边带光标");
+      const isHarmonicChecked = this.checkedGB.includes("谐波光标");
+
+      isMoveChecked ? this.handleMoveCursor() : this.removeCursor();
+      isSidebandChecked
+        ? this.enableSidebandCursor()
+        : this.disableSidebandCursor();
+      isHarmonicChecked
+        ? this.enableHarmonicCursor()
+        : this.disableHarmonicCursor();
+
+      // 设置互斥disabled状态
+      this.GBcheckList = this.GBcheckList.map((item) => ({
+        ...item,
+        disabled:
+          specialCursors.includes(item.val) &&
+          this.checkedGB.some(
+            (val) => val !== item.val && specialCursors.includes(val)
+          ),
+      }));
+    },
+    // 。。。。。。。。。。。。。。。
     handleInput() {
       this.$emit("update:modelValue", {
         xiaoval: this.xiaoval,
@@ -305,11 +390,17 @@ export default {
               icon: `image://${require("@/assets/analyse/09.png")}`,
               onclick: () => this.nextRow(),
             },
+            myCustomTool4: {
+              show: true,
+              title: "光标",
+              icon: `image://${require("@/assets/analyse/12.png")}`,
+              onclick: () => this.Show("2"),
+            },
             myCustomTool3: {
               show: true,
               title: "特征频率",
               icon: `image://${require("@/assets/analyse/13.png")}`,
-              onclick: () => this.Show(),
+              onclick: () => this.Show('3'),
             },
           },
         },
@@ -397,8 +488,18 @@ export default {
       this.$emit("update-next-row", 3, this.activeIndex);
     },
 
-    Show() {
-      this.TZshow = !this.TZshow;
+    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;
+      }
+      // this.TZshow = !this.TZshow;
     },
   },
 };

+ 145 - 0
src/views/health/components/envelopecharts/Bdgb.js

@@ -0,0 +1,145 @@
+export default {
+  data() {
+    return {
+      // 边带光标
+      sidebandCursorVisible: false,
+      sidebandCursorPoints: [],
+      sidebandCursorSeries: null,
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    // 边带光标
+    enableSidebandCursor() {
+      this.sidebandCursorVisible = true;
+      // 添加鼠标移动事件监听
+      this.chartInstance.getZr().on("mousemove", this.handleSidebandCursorMove);
+    },
+
+    disableSidebandCursor() {
+      this.sidebandCursorVisible = false;
+      // 移除鼠标移动事件监听
+      this.chartInstance
+        .getZr()
+        .off("mousemove", this.handleSidebandCursorMove);
+      // 移除边带光标
+      this.removeSidebandCursor();
+    },
+
+    handleSidebandCursorMove(event) {
+      if (!this.sidebandCursorVisible) return;
+
+      // 获取鼠标位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const xValue = pointInGrid[0];
+
+      // 生成3个光标点(中心、左、右)
+      this.sidebandCursorPoints = [
+        { xAxis: xValue - 5, val: (xValue - 5).toFixed(2) }, // 左边带
+        { xAxis: xValue, val: xValue.toFixed(2) }, // 中心
+        { xAxis: xValue + 5, val: (xValue + 5).toFixed(2) }, // 右边带
+      ];
+
+      this.updateSidebandCursor();
+    },
+    updateSidebandCursor() {
+      if (this.sidebandCursorPoints.length < 3) return;
+
+      // 获取当前图表选项
+      const option = this.chartInstance.getOption();
+
+      // 创建新的系列配置
+      this.sidebandCursorSeries = {
+        type: "line",
+        id: "SIDEBAND_CURSOR",
+        silent: true, // 禁止系列响应事件
+        markLine: {
+          silent: true,
+          lineStyle: {
+            color: "red",
+            type: "dashed",
+            width: 1,
+          },
+          symbol: ["none", "none"],
+          label: {
+            show: true,
+            position: "start",
+            formatter: (params) => params.data.val,
+            color: "red",
+          },
+          data: this.sidebandCursorPoints.map((point) => ({
+            xAxis: point.xAxis,
+            val: point.val,
+          })),
+        },
+        markArea: {
+          silent: true,
+          itemStyle: {
+            color: "rgba(255, 0, 0, 0.2)", // 红色半透明背景
+          },
+          data: [
+            // 左侧区域(左线到中线)
+            [
+              {
+                xAxis: this.sidebandCursorPoints[0].xAxis,
+                yAxis: "min", // 从Y轴最小值开始
+              },
+              {
+                xAxis: this.sidebandCursorPoints[1].xAxis,
+                yAxis: "max", // 到Y轴最大值结束
+              },
+            ],
+            // 右侧区域(中线到右线)
+            [
+              {
+                xAxis: this.sidebandCursorPoints[1].xAxis,
+                yAxis: "min",
+              },
+              {
+                xAxis: this.sidebandCursorPoints[2].xAxis,
+                yAxis: "max",
+              },
+            ],
+          ],
+        },
+      };
+
+      // 更新图表(保留原有系列)
+      const otherSeries = option.series.filter(
+        (s) => s.id !== "SIDEBAND_CURSOR"
+      );
+      this.chartInstance.setOption(
+        {
+          series: [...otherSeries, this.sidebandCursorSeries],
+        },
+        {
+          replaceMerge: ["series"], // 关键配置:只替换series
+          notMerge: false,
+        }
+      );
+    },
+
+    removeSidebandCursor() {
+      // 获取当前选项
+      const option = this.chartInstance.getOption();
+
+      // 过滤掉边带光标系列
+      const series = option.series.filter((s) => s.id !== "SIDEBAND_CURSOR");
+
+      // 更新图表
+      this.chartInstance.setOption(
+        {
+          series: series,
+        },
+        { replaceMerge: "series" }
+      );
+
+      this.sidebandCursorPoints = [];
+    },
+  },
+};

+ 128 - 0
src/views/health/components/envelopecharts/Tjgb.js

@@ -0,0 +1,128 @@
+export default {
+  data() {
+    return {
+    // 添加光标
+    cursorPoints: [], // 存储参考点数据
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    handleDoubleClick(event) {
+      if (!this.checkedGB.includes("添加光标")) return;
+      
+      // 获取鼠标位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const xValue = pointInGrid[0];
+    
+      // 找到最接近的X轴数据点
+      const closestIndex = this.findClosestIndex(xValue);
+      const yValue = this.envelopeList.y[closestIndex];
+    
+      // 存储参考点
+      this.cursorPoints.push({
+        xAxis: this.envelopeList.x[closestIndex], // 使用实际数据点的X坐标
+        yAxis: yValue.toFixed(2), // 使用实际数据点的Y坐标
+        val: yValue.toFixed(2), // 显示实际Y值
+      });
+    
+      console.log("cursorPoints:", this.cursorPoints);
+    
+      // 强制更新图表
+      this.updateCursorElements();
+    },
+        // 找到最接近的X轴索引
+        findClosestIndex(xValue) {
+      if (!this.envelopeList.x) return 0;
+      
+      let minDiff = Infinity;
+      let closestIndex = 0;
+      
+      this.envelopeList.x.forEach((x, index) => {
+        const diff = Math.abs(x - xValue);
+        if (diff < minDiff) {
+          minDiff = diff;
+          closestIndex = index;
+        }
+      });
+      
+      return closestIndex;
+    },
+    
+        updateCursorElements() {
+      if (!this.chartInstance) return;
+      
+      // 获取当前图表选项
+      const currentOption = this.chartInstance.getOption();
+      
+      // 主数据系列
+      const mainSeries = currentOption.series[0];
+      
+      // 特征值系列(过滤掉已有的光标系列)
+      const featureSeries = currentOption.series.filter(
+        s => s.markLine && !s.id?.startsWith('CURSOR_')
+      );
+    
+      // 参考线配置(垂直线)
+      const cursorLineSeries = {
+        id: 'CURSOR_LINE_SERIES',
+        type: "line",
+        markLine: {
+          silent: true,
+          lineStyle: {
+            color: "#FF0000",
+            type: "dashed",
+            width: 1,
+          },
+          symbol: ["none", "none"],
+          label: { 
+            show: true,
+            formatter: (params) => params.data.val || ''
+          },
+          data: this.cursorPoints.map((point) => ({
+            xAxis: point.xAxis,
+            val: point.val
+          })),
+        },
+      };
+    
+      // 参考点配置(实际数据点位置)
+      const cursorPointSeries = {
+        id: 'CURSOR_POINT_SERIES',
+        type: "scatter",
+        symbol: "circle",
+        symbolSize: 8,
+        itemStyle: { color: "#FF0000" },
+        data: this.cursorPoints.map((point) => ({
+          value: [point.xAxis, point.yAxis],
+          name: point.val,
+        })),
+        label: {
+          show: true,
+          formatter: "{@[1]}",
+          position: "top",
+          color: "#FF0000",
+          fontSize: 12,
+          backgroundColor: "rgba(255,255,255,0.7)",
+          padding: [2, 4],
+          borderRadius: 3,
+        },
+      };
+    
+      // 设置新选项
+      this.chartInstance.setOption({
+        series: [
+          mainSeries,
+          ...featureSeries,
+          cursorLineSeries,
+          cursorPointSeries
+        ]
+      }, { replaceMerge: ['series'] });
+    },
+
+  },
+};

+ 109 - 0
src/views/health/components/envelopecharts/Xdgb.js

@@ -0,0 +1,109 @@
+export default {
+  data() {
+    return {
+    // 谐波光标
+    harmonicCursorVisible: false,
+    harmonicCursorPoints: [],
+    harmonicCursorSeries: null,
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    enableHarmonicCursor() {
+      this.harmonicCursorVisible = true;
+      this.chartInstance.getZr().on("click", this.handleHarmonicCursorClick);
+    },
+
+    // 禁用谐波光标
+    disableHarmonicCursor() {
+      this.harmonicCursorVisible = false;
+      this.chartInstance.getZr().off("click", this.handleHarmonicCursorClick);
+      this.removeHarmonicCursor();
+    },
+
+    handleHarmonicCursorClick(event) {
+      if (!this.harmonicCursorVisible) return;
+
+      // 获取点击位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const baseX = pointInGrid[0];
+
+      // 生成1-6倍频的X坐标
+      this.harmonicCursorPoints = [];
+      for (let i = 1; i <= 6; i++) {
+        const xValue = baseX * i;
+        const closestIndex = this.findClosestIndex(xValue);
+        this.harmonicCursorPoints.push({
+          xAxis: xValue,
+          multiple: i,
+          yValue: this.envelopeList.y[closestIndex]?.toFixed(2) || "0",
+        });
+      }
+
+      this.updateHarmonicCursor();
+    },
+
+    // 更新谐波光标显示
+    updateHarmonicCursor() {
+      // 创建谐波光标系列
+      this.harmonicCursorSeries = {
+        type: "line",
+        id: "HARMONIC_CURSOR",
+        silent: true,
+        markLine: {
+          silent: true,
+          lineStyle: {
+            color: "#FFA500", // 橙色表示谐波光标
+            type: "dashed",
+            width: 1,
+          },
+          symbol: ["none", "none"],
+          label: {
+            show: true,
+            position: "start",
+            formatter: (params) =>
+              `${params.data.multiple}X\n${params.data.yValue}`,
+            color: "#FFA500",
+            backgroundColor: "rgba(255,255,255,0.8)",
+            padding: [2, 4],
+            borderRadius: 3,
+          },
+          data: this.harmonicCursorPoints.map((point) => ({
+            xAxis: point.xAxis,
+            multiple: point.multiple,
+            yValue: point.yValue,
+          })),
+        },
+      };
+
+      // 更新图表
+      const option = this.chartInstance.getOption();
+      const otherSeries = option.series.filter(
+        (s) => s.id !== "HARMONIC_CURSOR"
+      );
+
+      this.chartInstance.setOption(
+        {
+          series: [...otherSeries, this.harmonicCursorSeries],
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+    },
+
+    // 移除谐波光标
+    removeHarmonicCursor() {
+      const option = this.chartInstance.getOption();
+      const series = option.series.filter((s) => s.id !== "HARMONIC_CURSOR");
+      this.chartInstance.setOption({ series }, { replaceMerge: ["series"] });
+      this.harmonicCursorPoints = [];
+    },
+  },
+};

+ 295 - 0
src/views/health/components/envelopecharts/cursorReferenceMixin.js

@@ -0,0 +1,295 @@
+// cursorReferenceMixin.js
+// import * as echarts from "echarts";
+
+export default {
+  data() {
+    return {
+      // 参考线相关数据
+      cursorHightPoints: [], // 存储所有参考线
+      currentCursorIndex: -1, // 当前参考线索引
+      peakPoints: [], // 存储所有峰值点
+      isHandlingCursor: false, // 防止重复处理
+      chartInstance: null, // ECharts实例
+    };
+  },
+
+  mounted() {
+    // 监听键盘事件
+    window.addEventListener("keydown", this.handleKeyDown);
+  },
+
+  beforeDestroy() {
+    // 移除事件监听
+    window.removeEventListener("keydown", this.handleKeyDown);
+  },
+
+  methods: {
+    /**
+     * 处理按钮点击生成参考线
+     */
+    handleMoveCursor() {
+      console.log("handleMoveCursor", "222");
+      if (this.isHandlingCursor || !this.envelopeList) return;
+      this.isHandlingCursor = true;
+
+      // 1. 找到所有峰值点
+      this.findPeakPoints();
+
+      // 2. 如果没有峰值点则返回
+      if (this.peakPoints.length === 0) {
+        this.isHandlingCursor = false;
+        return;
+      }
+      console.log(this.peakPoints);
+
+      // 3. 找到Y轴最大值点
+      const maxPeak = this.peakPoints.reduce((prev, current) =>
+        prev.y > current.y ? prev : current
+      );
+
+      // 4. 创建参考线数据
+      const referenceLine = {
+        xAxis: maxPeak.x,
+        val: maxPeak.y.toFixed(9),
+        index: maxPeak.index,
+      };
+
+      // 5. 更新参考线
+      this.cursorHightPoints = [referenceLine];
+      this.currentCursorIndex = this.peakPoints.findIndex(
+        (p) => p.index === maxPeak.index
+      );
+
+      // 6. 更新图表
+      this.updateCursorElements2();
+
+      this.isHandlingCursor = false;
+    },
+
+    /**
+     * 查找所有峰值点
+     */
+    findPeakPoints() {
+      this.peakPoints = [];
+      const yValues = this.envelopeList.y;
+      const xValues = this.envelopeList.x;
+
+      // 1. 找到所有局部峰值点(比相邻点都高的点)
+      const allPeaks = [];
+      for (let i = 1; i < yValues.length - 1; i++) {
+        if (yValues[i] > yValues[i - 1] && yValues[i] > yValues[i + 1]) {
+          allPeaks.push({
+            x: xValues[i],
+            y: yValues[i],
+            index: i,
+          });
+        }
+      }
+
+      // 2. 按y值从大到小排序
+      allPeaks.sort((a, b) => b.y - a.y);
+
+      this.peakPoints = allPeaks;
+    },
+
+    /**
+     * 处理键盘事件
+     */
+    handleKeyDown(event) {
+      if (this.cursorHightPoints.length === 0) return;
+
+      switch (event.keyCode) {
+        case 37: // 左箭头
+          this.moveCursorToLeft();
+          break;
+        case 39: // 右箭头
+          this.moveCursorToRight();
+          break;
+        default:
+          return;
+      }
+
+      // 阻止默认行为
+      event.preventDefault();
+    },
+
+    /**
+     * 向左移动参考线并保持居中
+     */
+    moveCursorToLeft() {
+      this.findPeakPoints();
+      if (this.currentCursorIndex <= 0) return;
+
+      const newIndex = this.currentCursorIndex - 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+      this.centerViewOnPeak(newPeak);
+    },
+
+    /**
+     * 向右移动参考线并保持居中
+     */
+    moveCursorToRight() {
+      this.findPeakPoints();
+      if (this.currentCursorIndex >= this.peakPoints.length - 1) return;
+
+      const newIndex = this.currentCursorIndex + 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+      // this.centerViewOnPeak(newPeak);
+    },
+
+    /**
+     * 将视图中心对准峰值点
+     */
+    centerViewOnPeak(peak) {
+      if (!this.chartInstance || !peak) return;
+
+      // 获取当前x轴配置和数据范围
+      const option = this.chartInstance.getOption();
+      const xAxis = option.xAxis[0];
+
+      // 计算当前可视范围
+      const axisModel = this.chartInstance.getModel().getComponent("xAxis");
+      const currentRange = axisModel.axis.scale.getExtent();
+      const viewWidth = currentRange[1] - currentRange[0];
+
+      // 计算新的居中范围(确保不超出数据边界)
+      const newMin = Math.max(xAxis.min, peak.x - viewWidth / 2);
+      const newMax = Math.min(xAxis.max, peak.x + viewWidth / 2);
+
+      // 应用新的视图范围
+      this.chartInstance.dispatchAction({
+        type: "dataZoom",
+        xAxisIndex: 0,
+        start: ((newMin - xAxis.min) / (xAxis.max - xAxis.min)) * 100,
+        end: ((newMax - xAxis.min) / (xAxis.max - xAxis.min)) * 100,
+        animation: {
+          duration: 300, // 添加平滑过渡效果
+        },
+      });
+    },
+
+    /**
+     * 更新参考线位置
+     */
+    updateCursorPosition(peak, index) {
+      this.cursorHightPoints = [
+        {
+          xAxis: peak.x,
+          val: peak.y.toFixed(9),
+          index: peak.index,
+        },
+      ];
+      console.log(this.cursorHightPoints, "updateCursorPosition");
+
+      this.currentCursorIndex = index;
+      this.$nextTick(() => {
+        this.updateCursorElements2();
+      });
+    },
+
+    /**
+     * 更新参考线元素(不覆盖已有参考线)
+     */
+    updateCursorElements2() {
+      if (!this.chartInstance) return;
+
+      // 1. 获取当前图表配置中的已有series
+      const currentOption = this.chartInstance.getOption();
+      const existingSeries = currentOption.series || [];
+
+      // 2. 过滤掉旧的峰值参考线(通过id或特定标记识别)
+      const filteredSeries = existingSeries.filter(
+        (series) => !series.id || !series.id.includes("PEAK_REFERENCE_LINE")
+      );
+      console.log(filteredSeries);
+
+      // 3. 准备新的峰值参考线配置
+      const cursorHighLineSeries = {
+        id: "PEAK_REFERENCE_LINE",
+        type: "line",
+        markLine: {
+          data: this.cursorHightPoints.map((point) => ({
+            xAxis: point.xAxis,
+            label: {
+              formatter: "峰值: " + point.val,
+            },
+            lineStyle: {
+              color: "#FF0000",
+            },
+          })),
+        },
+      };
+
+      // 4. 合并所有series配置
+      const allSeries = [
+        ...filteredSeries, // 保留已有series
+        cursorHighLineSeries, // 添加新的峰值参考线
+      ];
+      console.log(allSeries);
+
+      // 5. 更新图表配置
+      this.chartInstance.setOption(
+        {
+          series: allSeries,
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+    },
+    /**
+     * 获取参考线markLine配置
+     */
+    getCursorMarkLineConfig() {
+      return {
+        data: this.cursorHightPoints.map((point) => ({
+          xAxis: point.xAxis,
+          label: {
+            formatter: "峰值: " + point.val,
+          },
+          lineStyle: {
+            color: "#FF0000",
+          },
+        })),
+        symbol: ["none", "none"],
+        silent: true,
+      };
+    },
+
+
+
+
+    removeCursor() {
+      if (!this.chartInstance) return;
+  
+      // 获取当前图表配置中的所有series
+      const currentOption = this.chartInstance.getOption();
+      const existingSeries = currentOption.series || [];
+  
+      // 过滤掉峰值参考线(通过id或特定标记识别)
+      const filteredSeries = existingSeries.filter(
+        (series) => !series.id || !series.id.includes("PEAK_REFERENCE_LINE")
+      );
+  
+      // 更新图表配置,移除所有峰值参考线
+      this.chartInstance.setOption(
+        {
+          series: filteredSeries,
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+  
+      // 清空当前光标数据
+      this.cursorHightPoints = [];
+      this.currentCursorIndex = -1;
+    },
+  },
+};

+ 556 - 0
src/views/health/components/spectrogramcharts copy.vue

@@ -0,0 +1,556 @@
+<template>
+  <div>
+    <div class="FD">
+      <!-- 光标 -->
+      <div v-if="BGshow" class="eigenvalue">
+        <el-checkbox-group v-model="checkedGB" @change="handlecursor">
+          <el-checkbox v-for="(item, index) in GBcheckList" :key="index" :label="item.val">
+            {{ item.val }}
+          </el-checkbox>
+        </el-checkbox-group>
+      </div>
+      <!-- 特征值 -->
+      <div v-if="PXshow" class="eigenvalue">
+        <el-checkbox-group v-model="checkedValues" @change="handleCheckChange">
+          <el-checkbox v-for="(item, index) in PXcheckList" :key="index" :label="item.val">
+            {{ item.val }}
+          </el-checkbox>
+        </el-checkbox-group>
+      </div>
+    </div>
+    <!-- ECharts 图表容器 -->
+
+    <div class="line-chart" ref="chart"></div>
+  </div>
+</template>
+
+<script>
+import axios from "axios";
+import * as echarts from "echarts"; // 导入 echarts 库
+
+export default {
+  name: "TimedomainCharts", // 组件名称
+  props: {
+    currentIndex: {
+      type: Number,
+      default: 0,
+    },
+    activeIndex: {
+      type: Number,
+      default: 0,
+    },
+    ids: {
+      type: Array,
+      default: () => [],
+    },
+    spectrumListTwo: {
+      type: Object,
+      default: () => ({}),
+    },
+    currentRow: {
+      type: Object,
+      default: () => ({}),
+    },
+    windCode: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {
+      chartInstance: null,
+      option: null,
+      TZshow: false,
+      BGshow: false,
+      PXshow: false,
+      spectrumList: {},
+
+      GBcheckList: [
+        { val: "添加光标" , checked: false},
+        { val: "谐波光标" , checked: false},
+        { val: "边带光标" , checked: false},
+        { val: "移动峰值" , checked: false},
+      ],
+      PXcheckList: [
+        { val: "Fr", checked: false },
+        { val: "BPFI", checked: false },
+        { val: "BPFO", checked: false },
+        { val: "BSF", checked: false },
+        { val: "FTF", checked: false },
+        { val: "3P", checked: false },
+      ],
+      Fr: [],
+      BPFI: [],
+      BPFO: [],
+      BSF: [],
+      FTF: [],
+      B3P: [],
+
+      checkedGB: [],
+      checkedValues: [],
+
+
+      cursorLines: [], // 存储添加的光标线
+      cursorPoints: [], // 用于存储参考点(浮动点)数据
+
+    };
+  },
+  watch: {
+    // 监听 chartData 和 chartLabels 的变化,重新绘制图表
+    chartData(newData) {
+      this.updateChart(newData, this.chartLabels);
+    },
+    chartLabels(newLabels) {
+      this.updateChart(this.chartData, newLabels);
+    },
+    spectrumListTwo(newValue) {
+      this.spectrumList = newValue; // 将 spectrumListTwo 的新值赋给 spectrumList
+      if (this.chartInstance) {
+        this.updateChart(this.spectrumList.y, this.spectrumList.x); // 更新图表
+      }
+    },
+    spectrumList: {
+      handler(newValue) {
+        if (!newValue) return;
+        console.log(newValue, "newValue");
+        if (this.chartInstance) {
+          this.updateChart(newValue.y, newValue.x); // 只在 chartInstance 初始化后更新图表
+        }
+      },
+      deep: true, // 深度监听
+    },
+  },
+  destroyed() {
+  if (this.chartInstance) {
+    this.chartInstance.getZr().off('dblclick', this.handleDoubleClick)
+  }
+},
+
+  mounted() {
+    
+    this.$nextTick(() => {
+      setTimeout(() => {
+        this.initializeChart(); // 延迟2秒后调用
+        this.getTime();
+      }, 500); // 500毫秒,即0.5秒
+    });
+  },
+
+  methods: {
+    initializeChart() {
+      const chartDom = this.$refs.chart;
+      if (chartDom && !this.chartInstance) {
+        this.chartInstance = echarts.init(chartDom); // 仅初始化一次
+      }
+
+      // 使用 $nextTick 确保数据更新后再渲染图表
+      this.$nextTick(() => {
+        if (this.chartInstance && this.spectrumList.y && this.spectrumList.x) {
+          this.updateChart(this.spectrumList.y, this.spectrumList.x); // 更新图表
+        }
+      });
+
+       // 绑定双击事件
+    this.chartInstance.getZr().on('dblclick', this.handleDoubleClick)
+    },
+
+    handleDoubleClick(event) {
+    // 只有勾选了“添加光标”时才响应
+    if (!this.checkedGB.includes('添加光标')) return
+    // 转换鼠标位置为图表的 x 轴数值
+    const pointInGrid = this.chartInstance.convertFromPixel({ seriesIndex: 0 }, [event.offsetX, event.offsetY])
+    const xValue = pointInGrid[0]
+    // 添加参考线(使用“光标”命名)
+    this.cursorLines.push({ xAxis: xValue, val: '光标' })
+    // 更新图表:添加参考线
+    this.updateCursorLines()
+    // 自动取消勾选
+    this.checkedGB = this.checkedGB.filter(val => val !== '添加光标')
+    this.handlecursor() // 同步 checked 状态
+  },
+
+
+
+  updateCursorLines() {
+    const cursorLine = {
+      type: 'line',
+      markLine: {
+        silent: true,
+        lineStyle: { color: '#FF0000', type: 'dotted', width: 2 },
+        symbol: ['none', 'none'],
+        label: {
+          show: true,
+          formatter: ({ data }) => `光标`,
+          position: 'end',
+        },
+        data: this.cursorLines.map(({ xAxis, val }) => ({ xAxis, val })),
+      },
+    }
+
+    // 更新图表,仅更新 series
+    if (this.chartInstance) {
+      this.chartInstance.setOption(
+        {
+          series: [
+            {
+              name: '数据系列',
+              type: 'line',
+              data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
+              symbol: 'none',
+              lineStyle: { color: '#162961', width: 1 },
+              itemStyle: { color: '#162961', borderColor: '#fff', borderWidth: 1 },
+              large: true,
+            },
+            ...this.generateSeries({
+              Fr: this.Fr,
+              BPFI: this.BPFI,
+              BPFO: this.BPFO,
+              BSF: this.BSF,
+              FTF: this.FTF,
+              B3P: this.B3P,
+            }),
+            cursorLine,
+          ],
+        },
+        { replaceMerge: ['series'] }
+      )
+    }
+  },
+
+
+
+    // 更新图表数据
+    updateChart(data, labels) {
+      if (
+        !this.chartInstance ||
+        !Array.isArray(labels) ||
+        !Array.isArray(data) ||
+        labels.length !== data.length
+      ) {
+        console.error("Invalid data or labels");
+        return;
+      }
+
+      const createMarkLine = (dataSource, color) => ({
+        type: "line",
+        markLine: {
+          silent: false,
+          lineStyle: { color, type: "solid", width: 2 },
+          symbol: ["arrow", "none"],
+          label: {
+            show: true,
+            position: "end",
+            formatter: ({ data }) => data.val,
+          },
+          emphasis: {
+            lineStyle: { color: "#FF6A00", width: 4 },
+            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 = {
+        title: { text: this.spectrumList.title, left: "center" },
+        toolbox: {
+          feature: {
+            dataZoom: { yAxisIndex: "none" },
+            restore: {},
+            saveAsImage: {},
+            myCustomTool: {
+              show: true,
+              title: "上一条",
+              icon: `image://${require("@/assets/analyse/08.png")}`,
+              onclick: () => this.previousRow(),
+            },
+            myCustomTool2: {
+              show: true,
+              title: "下一条",
+              icon: `image://${require("@/assets/analyse/09.png")}`,
+              onclick: () => this.nextRow(),
+            },
+            myCustomTool4: {
+              show: true,
+              title: "光标",
+              icon: `image://${require("@/assets/analyse/12.png")}`,
+              onclick: () => this.Show("2"),
+            },
+            myCustomTool5: {
+              show: true,
+              title: "特征频率",
+              icon: `image://${require("@/assets/analyse/13.png")}`,
+              onclick: () => this.Show("3"),
+            },
+          },
+        },
+        xAxis: {
+          type: "value",
+          name: this.spectrumList.xaxis,
+          nameLocation: "center",
+          nameTextStyle: {
+            fontSize: 14,
+            color: "#333",
+            padding: [10, 0, 0, 0],
+          },
+        },
+        yAxis: {
+          type: "value",
+          name: this.spectrumList.yaxis,
+          nameTextStyle: {
+            fontSize: 14,
+            color: "#333",
+            padding: [10, 0, 0, 0],
+          },
+        },
+        tooltip: {
+          trigger: "axis",
+          formatter: ([
+            {
+              value: [x, y],
+            },
+          ]) => `X: ${x}<br/>Y: ${y}`,
+          axisPointer: { type: "line" },
+        },
+        dataZoom: [
+          { type: "inside", start: 0, end: 10 },
+          {
+            type: "slider",
+            start: 0,
+            end: 10,
+            handleSize: "80%",
+            showDataShadow: false,
+          },
+        ],
+        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);
+    },
+
+    // 处理复选框变化 特征值
+    handleCheckChange() {
+      this.PXcheckList.forEach((item) => {
+        item.checked = this.checkedValues.includes(item.val);
+      });
+
+      // 构建新的特征频率数据
+      const newFeatureLines = {
+        Fr: this.checkedValues.includes("Fr") ? this.spectrumList.fn_Gen : [],
+        BPFI: this.checkedValues.includes("BPFI") ? this.spectrumList.BPFI : [],
+        BPFO: this.checkedValues.includes("BPFO") ? this.spectrumList.BPFO : [],
+        BSF: this.checkedValues.includes("BSF") ? this.spectrumList.BSF : [],
+        FTF: this.checkedValues.includes("FTF") ? this.spectrumList.FTF : [],
+        B3P: this.checkedValues.includes("3P")
+          ? Array.isArray(this.spectrumList.B3P)
+            ? this.spectrumList.B3P
+            : [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
+          : [],
+      };
+
+      // 仅更新 `series`,避免重新渲染整个 ECharts 组件
+      if (this.chartInstance) {
+        this.chartInstance.setOption(
+          {
+            series: this.generateSeries(newFeatureLines),
+          },
+          { replaceMerge: ["series"] }
+        );
+      }
+    },
+
+    generateSeries(featureLines) {
+      const createMarkLine = (dataSource, color) => ({
+        type: "line",
+        markLine: {
+          silent: false,
+          lineStyle: { color, type: "dashed", width:1 },
+          symbol: ["arrow", "none"],
+          label: {
+            show: true,
+            position: "end",
+            formatter: ({ data }) => data.val,
+          },
+          emphasis: {
+            lineStyle: { color: "#FF6A00", width: 2 },
+            label: {
+              show: true,
+              formatter: ({ value }) => `特征值: ${value}`,
+              color: "#000",
+            },
+          },
+          data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
+        },
+      });
+
+      const markLines = [
+        { data: featureLines.Fr, color: "#A633FF" },
+        { data: featureLines.BPFI, color: "#23357e" },
+        { data: featureLines.BPFO, color: "#42a0ae" },
+        { data: featureLines.BSF, color: "#008080" },
+        { data: featureLines.FTF, color: "#af254f" },
+        { data: featureLines.B3P, color: "#FFD700" },
+      ].map(({ data, color }) => createMarkLine(data, color));
+
+      return [
+        {
+          name: "数据系列",
+          type: "line",
+          data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
+          symbol: "none",
+          lineStyle: { color: "#162961", width: 1 },
+          itemStyle: { color: "#162961", borderColor: "#fff", borderWidth: 1 },
+          large: true,
+        },
+        ...markLines,
+      ];
+    },
+
+    // 处理复选框变化 光标
+    handlecursor(){
+      this.GBcheckList.forEach((item) => {
+        item.checked = this.checkedGB.includes(item.val);
+        console.log(  item.checked ,"item.checked");
+      });
+
+    },
+
+    getTime() {
+      this.$emit("handleLoading", null, true, this.activeIndex);
+      const params = {
+        ids: this.ids,
+        windCode: this.windCode,
+        analysisType: "frequency",
+      };
+      axios
+        .post("/WJapi/analysis/frequency", params)
+        .then((res) => {
+          console.log(res, "频谱图数据");
+          this.spectrumList = { ...JSON.parse(res.data) };
+          console.log(this.spectrumList, "频谱图数据1");
+          const XrmsValue = this.spectrumList?.Xrms;
+          // 通过 $emit 传递 XrmsValue 给父组件
+          this.$emit("updateXrms", XrmsValue);
+          this.PXcheckList.forEach((item) => {
+            if (item.checked) {
+              switch (item.val) {
+                case "Fr":
+                  this.Fr = this.spectrumList.fn_Gen;
+                  break;
+                case "BPFI":
+                  this.BPFI = this.spectrumList.BPFI;
+                  break;
+                case "BPFO":
+                  this.BPFO = this.spectrumList.BPFO;
+                  break;
+                case "BSF":
+                  this.BSF = this.spectrumList.BSF;
+                  break;
+                case "FTF":
+                  this.FTF = this.spectrumList.FTF;
+                  break;
+                case "3P":
+                  this.B3P = Array.isArray(this.spectrumList.B3P)
+                    ? this.spectrumList.B3P
+                    : [{ Xaxis: this.spectrumList.B3P, val: "3P" }];
+                  break;
+                default:
+                  break;
+              }
+            }
+          });
+        })
+        .catch((error) => {
+          console.error(error);
+        })
+        .finally(() => {
+          this.$emit("handleLoading", this.currentRow, false, this.activeIndex);
+        });
+    },
+
+    previousRow() {
+      this.$emit("update-previous-row", 2, this.activeIndex);
+    },
+
+    nextRow() {
+      this.$emit("update-next-row", 2, this.activeIndex);
+    },
+
+    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]) {
+        // Toggle the state for the given value
+        this.TZshow = value === "1" ? !this.TZshow : false;
+        this.BGshow = value === "2" ? !this.BGshow : false;
+        this.PXshow = value === "3" ? !this.PXshow : false;
+      }
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.line-chart {
+  width: 100%;
+  height: 280px;
+}
+
+.FD {
+  width: 100%;
+  height: 1px;
+  position: relative;
+}
+
+.eigenvalue {
+  position: absolute;
+  top: 30px;
+  right: 0;
+  font-size: 10px;
+  width: 100px;
+  border: 1px solid black;
+  padding: 5px;
+  background: #fff;
+  z-index: 99;
+
+  h5 {
+    line-height: 16px;
+    height: 16px;
+  }
+}
+</style>

+ 180 - 166
src/views/health/components/spectrogramcharts.vue

@@ -3,8 +3,8 @@
     <div class="FD">
       <!-- 光标 -->
       <div v-if="BGshow" class="eigenvalue">
-        <el-checkbox-group v-model="checkedGB">
-          <el-checkbox v-for="(item, index) in GBcheckList" :key="index" :label="item.val">
+        <el-checkbox-group v-model="checkedGB" @change="handlecursor">
+          <el-checkbox v-for="(item, index) in GBcheckList" :key="index" :label="item.val" :disabled="item.disabled">
             {{ item.val }}
           </el-checkbox>
         </el-checkbox-group>
@@ -19,17 +19,22 @@
       </div>
     </div>
     <!-- ECharts 图表容器 -->
-
     <div class="line-chart" ref="chart"></div>
   </div>
 </template>
 
 <script>
 import axios from "axios";
-import * as echarts from "echarts"; // 导入 echarts 库
+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";
 
 export default {
-  name: "TimedomainCharts", // 组件名称
+  name: "TimedomainCharts",
+  mixins: [cursorReferenceMixin, Bdgb, Xdgb, Tjgb],
+
   props: {
     currentIndex: {
       type: Number,
@@ -60,16 +65,16 @@ export default {
     return {
       chartInstance: null,
       option: null,
-      TZshow: false,
+      // TZshow: false,
       BGshow: false,
       PXshow: false,
       spectrumList: {},
 
       GBcheckList: [
-        { val: "添加光标" },
-        { val: "谐波光标" },
-        { val: "边带光标" },
-        { val: "移动峰值" },
+        { val: "添加光标", checked: false, disabled: false },
+        { val: "谐波光标", checked: false, disabled: false },
+        { val: "边带光标", checked: false, disabled: false },
+        { val: "移动峰值", checked: false, disabled: false },
       ],
       PXcheckList: [
         { val: "Fr", checked: false },
@@ -85,62 +90,201 @@ export default {
       BSF: [],
       FTF: [],
       B3P: [],
-
       checkedGB: [],
       checkedValues: [],
     };
   },
   watch: {
-    // 监听 chartData 和 chartLabels 的变化,重新绘制图表
-    chartData(newData) {
-      this.updateChart(newData, this.chartLabels);
-    },
-    chartLabels(newLabels) {
-      this.updateChart(this.chartData, newLabels);
-    },
     spectrumListTwo(newValue) {
-      this.spectrumList = newValue; // 将 spectrumListTwo 的新值赋给 spectrumList
+      this.spectrumList = newValue;
       if (this.chartInstance) {
-        this.updateChart(this.spectrumList.y, this.spectrumList.x); // 更新图表
+        this.updateChart(this.spectrumList.y, this.spectrumList.x);
       }
     },
     spectrumList: {
       handler(newValue) {
         if (!newValue) return;
-        console.log(newValue, "newValue");
         if (this.chartInstance) {
-          this.updateChart(newValue.y, newValue.x); // 只在 chartInstance 初始化后更新图表
+          this.updateChart(newValue.y, newValue.x);
         }
       },
-      deep: true, // 深度监听
+      deep: true,
     },
   },
+  beforeDestroy() {
+    if (this.chartInstance) {
+      this.chartInstance.getZr().off("dblclick", this.handleDoubleClick);
+      this.chartInstance
+        .getZr()
+        .off("mousemove", this.handleSidebandCursorMove);
+      this.chartInstance.dispose();
+    }
+  },
   mounted() {
-    
     this.$nextTick(() => {
       setTimeout(() => {
-        this.initializeChart(); // 延迟2秒后调用
+        this.initializeChart();
         this.getTime();
-      }, 500); // 500毫秒,即0.5秒
+      }, 500);
     });
   },
-
   methods: {
     initializeChart() {
       const chartDom = this.$refs.chart;
       if (chartDom && !this.chartInstance) {
-        this.chartInstance = echarts.init(chartDom); // 仅初始化一次
+        this.chartInstance = echarts.init(chartDom);
+        this.chartInstance.getZr().on("dblclick", this.handleDoubleClick);
       }
 
-      // 使用 $nextTick 确保数据更新后再渲染图表
       this.$nextTick(() => {
         if (this.chartInstance && this.spectrumList.y && this.spectrumList.x) {
-          this.updateChart(this.spectrumList.y, this.spectrumList.x); // 更新图表
+          this.updateChart(this.spectrumList.y, this.spectrumList.x);
         }
       });
     },
+    // 光标
+    handlecursor() {
+      // 特殊光标类型数组
+      const specialCursors = ["添加光标","移动峰值", "边带光标", "谐波光标"];
+
+      // 检查是否有多个特殊光标被选中
+      const selectedSpecials = specialCursors.filter((type) =>
+        this.checkedGB.includes(type)
+      );
+
+      // 如果多于1个,则只保留第一个
+      if (selectedSpecials.length > 1) {
+        this.checkedGB = [
+          ...this.checkedGB.filter((val) => !specialCursors.includes(val)),
+          selectedSpecials[0], // 保留第一个选中的
+        ];
+      }
+
+      // 其余逻辑保持不变...
+      const isMoveChecked = this.checkedGB.includes("移动峰值");
+      const isSidebandChecked = this.checkedGB.includes("边带光标");
+      const isHarmonicChecked = this.checkedGB.includes("谐波光标");
+
+      isMoveChecked ? this.handleMoveCursor() : this.removeCursor();
+      isSidebandChecked
+        ? this.enableSidebandCursor()
+        : this.disableSidebandCursor();
+      isHarmonicChecked
+        ? this.enableHarmonicCursor()
+        : this.disableHarmonicCursor();
+
+      // 设置互斥disabled状态
+      this.GBcheckList = this.GBcheckList.map((item) => ({
+        ...item,
+        disabled:
+          specialCursors.includes(item.val) &&
+          this.checkedGB.some(
+            (val) => val !== item.val && specialCursors.includes(val)
+          ),
+      }));
+    },
+
+    // 特征值
+    handleCheckChange() {
+      this.PXcheckList.forEach((item) => {
+        item.checked = this.checkedValues.includes(item.val);
+      });
+
+      this.updateFeatureLines();
+    },
+
+    updateFeatureLines() {
+      const newFeatureLines = {
+        Fr: this.checkedValues.includes("Fr") ? this.spectrumList.fn_Gen : [],
+        BPFI: this.checkedValues.includes("BPFI") ? this.spectrumList.BPFI : [],
+        BPFO: this.checkedValues.includes("BPFO") ? this.spectrumList.BPFO : [],
+        BSF: this.checkedValues.includes("BSF") ? this.spectrumList.BSF : [],
+        FTF: this.checkedValues.includes("FTF") ? this.spectrumList.FTF : [],
+        B3P: this.checkedValues.includes("3P")
+          ? Array.isArray(this.spectrumList.B3P)
+            ? this.spectrumList.B3P
+            : [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
+          : [],
+      };
+
+      if (this.chartInstance) {
+        const currentOption = this.chartInstance.getOption();
+
+        // 获取现有的光标系列
+        const cursorLineSeries =
+          currentOption.series.find((s) => s.id === "CURSOR_LINE_SERIES") || {};
+        const cursorPointSeries =
+          currentOption.series.find((s) => s.id === "CURSOR_POINT_SERIES") ||
+          {};
+        const cursorHighLineSeries =
+          currentOption.series.find((s) => s.id === "PEAK_REFERENCE_LINE") ||
+          {};
+
+        // 生成新的特征值系列
+        const featureSeries = this.generateSeries(newFeatureLines);
+
+        this.chartInstance.setOption(
+          {
+            series: [
+              currentOption.series[0], // 主数据系列
+              ...featureSeries.slice(1), // 新的特征值系列
+              cursorLineSeries, // 保留光标线系列
+              cursorPointSeries, // 保留光标点系列
+              cursorHighLineSeries, // 保留峰值参考线
+            ],
+          },
+          { replaceMerge: ["series"] }
+        );
+      }
+    },
+
+    generateSeries(featureLines) {
+      const createMarkLine = (dataSource, color) => ({
+        type: "line",
+        markLine: {
+          silent: false,
+          lineStyle: { color, type: "dashed", width: 1 },
+          symbol: ["arrow", "none"],
+          label: {
+            show: true,
+            position: "end",
+            formatter: ({ data }) => data.val,
+          },
+          emphasis: {
+            lineStyle: { color: "#FF6A00", width: 2 },
+            label: {
+              show: true,
+              formatter: ({ value }) => `特征值: ${value}`,
+              color: "#000",
+            },
+          },
+          data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
+        },
+      });
+
+      const markLines = [
+        { data: featureLines.Fr, color: "#A633FF" },
+        { data: featureLines.BPFI, color: "#23357e" },
+        { data: featureLines.BPFO, color: "#42a0ae" },
+        { data: featureLines.BSF, color: "#008080" },
+        { data: featureLines.FTF, color: "#af254f" },
+        { data: featureLines.B3P, color: "#FFD700" },
+      ].map(({ data, color }) => createMarkLine(data, color));
+
+      return [
+        {
+          name: "数据系列",
+          type: "line",
+          data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
+          symbol: "none",
+          lineStyle: { color: "#162961", width: 1 },
+          itemStyle: { color: "#162961", borderColor: "#fff", borderWidth: 1 },
+          large: true,
+        },
+        ...markLines,
+      ];
+    },
 
-    // 更新图表数据
     updateChart(data, labels) {
       if (
         !this.chartInstance ||
@@ -281,86 +425,7 @@ export default {
       this.chartInstance.setOption(option);
     },
 
-    handleCheckChange() {
-      this.PXcheckList.forEach((item) => {
-        item.checked = this.checkedValues.includes(item.val);
-      });
-
-      // 构建新的特征频率数据
-      const newFeatureLines = {
-        Fr: this.checkedValues.includes("Fr") ? this.spectrumList.fn_Gen : [],
-        BPFI: this.checkedValues.includes("BPFI") ? this.spectrumList.BPFI : [],
-        BPFO: this.checkedValues.includes("BPFO") ? this.spectrumList.BPFO : [],
-        BSF: this.checkedValues.includes("BSF") ? this.spectrumList.BSF : [],
-        FTF: this.checkedValues.includes("FTF") ? this.spectrumList.FTF : [],
-        B3P: this.checkedValues.includes("3P")
-          ? Array.isArray(this.spectrumList.B3P)
-            ? this.spectrumList.B3P
-            : [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
-          : [],
-      };
-
-      // 仅更新 `series`,避免重新渲染整个 ECharts 组件
-      if (this.chartInstance) {
-        this.chartInstance.setOption(
-          {
-            series: this.generateSeries(newFeatureLines),
-          },
-          { replaceMerge: ["series"] }
-        );
-      }
-    },
-
-    generateSeries(featureLines) {
-      const createMarkLine = (dataSource, color) => ({
-        type: "line",
-        markLine: {
-          silent: false,
-          lineStyle: { color, type: "dashed", width:1 },
-          symbol: ["arrow", "none"],
-          label: {
-            show: true,
-            position: "end",
-            formatter: ({ data }) => data.val,
-          },
-          emphasis: {
-            lineStyle: { color: "#FF6A00", width: 2 },
-            label: {
-              show: true,
-              formatter: ({ value }) => `特征值: ${value}`,
-              color: "#000",
-            },
-          },
-          data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
-        },
-      });
-
-      const markLines = [
-        { data: featureLines.Fr, color: "#A633FF" },
-        { data: featureLines.BPFI, color: "#23357e" },
-        { data: featureLines.BPFO, color: "#42a0ae" },
-        { data: featureLines.BSF, color: "#008080" },
-        { data: featureLines.FTF, color: "#af254f" },
-        { data: featureLines.B3P, color: "#FFD700" },
-      ].map(({ data, color }) => createMarkLine(data, color));
-
-      return [
-        {
-          name: "数据系列",
-          type: "line",
-          data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
-          symbol: "none",
-          lineStyle: { color: "#162961", width: 1 },
-          itemStyle: { color: "#162961", borderColor: "#fff", borderWidth: 1 },
-          large: true,
-        },
-        ...markLines,
-      ];
-    },
-
-    
-
-
+    // 获取数据
     getTime() {
       this.$emit("handleLoading", null, true, this.activeIndex);
       const params = {
@@ -371,11 +436,11 @@ export default {
       axios
         .post("/WJapi/analysis/frequency", params)
         .then((res) => {
-          console.log(res, "频谱图数据");
           this.spectrumList = { ...JSON.parse(res.data) };
+
           console.log(this.spectrumList, "频谱图数据1");
+
           const XrmsValue = this.spectrumList?.Xrms;
-          // 通过 $emit 传递 XrmsValue 给父组件
           this.$emit("updateXrms", XrmsValue);
           this.PXcheckList.forEach((item) => {
             if (item.checked) {
@@ -430,66 +495,15 @@ export default {
       };
 
       if (stateMap[value]) {
-        // Toggle the state for the given value
         this.TZshow = value === "1" ? !this.TZshow : false;
         this.BGshow = value === "2" ? !this.BGshow : false;
         this.PXshow = value === "3" ? !this.PXshow : false;
       }
     },
-
-    // handleCheckChange() {
-    //   this.PXcheckList.forEach((item) => {
-    //     // 如果 `checkedValues` 里有这个项,则 checked=true,否则 checked=false
-    //     item.checked = this.checkedValues.includes(item.val);
-    //   });
-
-    //   // 重置数据数组
-    //   this.Fr = [];
-    //   this.BPFI = [];
-    //   this.BPFO = [];
-    //   this.BSF = [];
-    //   this.FTF = [];
-    //   this.B3P = [];
-
-    //   // 找到刚刚被点击的项
-    //   const changedItem = this.PXcheckList.find(
-    //     (item) => !this.checkedValues.includes(item.val) !== item.checked
-    //   );
-
-    //   if (changedItem) {
-    //     console.log("当前点击项:", changedItem);
-    //     // 根据选中状态赋值
-    //     if (this.checkedValues.includes("Fr")) {
-    //       this.Fr = this.spectrumList.fn_Gen;
-    //     }
-    //     if (this.checkedValues.includes("BPFI")) {
-    //       this.BPFI = this.spectrumList.BPFI;
-    //     }
-    //     if (this.checkedValues.includes("BPFO")) {
-    //       this.BPFO = this.spectrumList.BPFO;
-    //     }
-    //     if (this.checkedValues.includes("BSF")) {
-    //       this.BSF = this.spectrumList.BSF;
-    //     }
-    //     if (this.checkedValues.includes("FTF")) {
-    //       this.FTF = this.spectrumList.FTF;
-    //     }
-    //     if (this.checkedValues.includes("3P")) {
-    //       this.B3P = Array.isArray(this.spectrumList.B3P)
-    //         ? this.spectrumList.B3P
-    //         : [{ Xaxis: this.spectrumList.B3P, val: "3P" }];
-    //     }
-    //     // 更新 ECharts 图表数据
-    //     if (this.chartInstance) {
-    //       this.updateChart(this.spectrumList.y, this.spectrumList.x);
-    //     }
-    //   }
-    // },
-
-   
   },
 };
 </script>
+
 <style lang="scss" scoped>
 .line-chart {
   width: 100%;
@@ -518,4 +532,4 @@ export default {
     height: 16px;
   }
 }
-</style>
+</style>

+ 145 - 0
src/views/health/components/spectrogramcharts/Bdgb.js

@@ -0,0 +1,145 @@
+export default {
+  data() {
+    return {
+      // 边带光标
+      sidebandCursorVisible: false,
+      sidebandCursorPoints: [],
+      sidebandCursorSeries: null,
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    // 边带光标
+    enableSidebandCursor() {
+      this.sidebandCursorVisible = true;
+      // 添加鼠标移动事件监听
+      this.chartInstance.getZr().on("mousemove", this.handleSidebandCursorMove);
+    },
+
+    disableSidebandCursor() {
+      this.sidebandCursorVisible = false;
+      // 移除鼠标移动事件监听
+      this.chartInstance
+        .getZr()
+        .off("mousemove", this.handleSidebandCursorMove);
+      // 移除边带光标
+      this.removeSidebandCursor();
+    },
+
+    handleSidebandCursorMove(event) {
+      if (!this.sidebandCursorVisible) return;
+
+      // 获取鼠标位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const xValue = pointInGrid[0];
+
+      // 生成3个光标点(中心、左、右)
+      this.sidebandCursorPoints = [
+        { xAxis: xValue - 5, val: (xValue - 5).toFixed(2) }, // 左边带
+        { xAxis: xValue, val: xValue.toFixed(2) }, // 中心
+        { xAxis: xValue + 5, val: (xValue + 5).toFixed(2) }, // 右边带
+      ];
+
+      this.updateSidebandCursor();
+    },
+    updateSidebandCursor() {
+      if (this.sidebandCursorPoints.length < 3) return;
+
+      // 获取当前图表选项
+      const option = this.chartInstance.getOption();
+
+      // 创建新的系列配置
+      this.sidebandCursorSeries = {
+        type: "line",
+        id: "SIDEBAND_CURSOR",
+        silent: true, // 禁止系列响应事件
+        markLine: {
+          silent: true,
+          lineStyle: {
+            color: "red",
+            type: "dashed",
+            width: 1,
+          },
+          symbol: ["none", "none"],
+          label: {
+            show: true,
+            position: "start",
+            formatter: (params) => params.data.val,
+            color: "red",
+          },
+          data: this.sidebandCursorPoints.map((point) => ({
+            xAxis: point.xAxis,
+            val: point.val,
+          })),
+        },
+        markArea: {
+          silent: true,
+          itemStyle: {
+            color: "rgba(255, 0, 0, 0.2)", // 红色半透明背景
+          },
+          data: [
+            // 左侧区域(左线到中线)
+            [
+              {
+                xAxis: this.sidebandCursorPoints[0].xAxis,
+                yAxis: "min", // 从Y轴最小值开始
+              },
+              {
+                xAxis: this.sidebandCursorPoints[1].xAxis,
+                yAxis: "max", // 到Y轴最大值结束
+              },
+            ],
+            // 右侧区域(中线到右线)
+            [
+              {
+                xAxis: this.sidebandCursorPoints[1].xAxis,
+                yAxis: "min",
+              },
+              {
+                xAxis: this.sidebandCursorPoints[2].xAxis,
+                yAxis: "max",
+              },
+            ],
+          ],
+        },
+      };
+
+      // 更新图表(保留原有系列)
+      const otherSeries = option.series.filter(
+        (s) => s.id !== "SIDEBAND_CURSOR"
+      );
+      this.chartInstance.setOption(
+        {
+          series: [...otherSeries, this.sidebandCursorSeries],
+        },
+        {
+          replaceMerge: ["series"], // 关键配置:只替换series
+          notMerge: false,
+        }
+      );
+    },
+
+    removeSidebandCursor() {
+      // 获取当前选项
+      const option = this.chartInstance.getOption();
+
+      // 过滤掉边带光标系列
+      const series = option.series.filter((s) => s.id !== "SIDEBAND_CURSOR");
+
+      // 更新图表
+      this.chartInstance.setOption(
+        {
+          series: series,
+        },
+        { replaceMerge: "series" }
+      );
+
+      this.sidebandCursorPoints = [];
+    },
+  },
+};

+ 123 - 0
src/views/health/components/spectrogramcharts/Tjgb.js

@@ -0,0 +1,123 @@
+export default {
+  data() {
+    return {
+    // 添加光标
+    cursorPoints: [], // 存储参考点数据
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    handleDoubleClick(event) {
+      if (!this.checkedGB.includes("添加光标")) return;
+      // 获取鼠标位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const xValue = pointInGrid[0];
+
+      // 找到最接近的X轴数据点
+      const closestIndex = this.findClosestIndex(xValue);
+      const yValue = this.spectrumList.y[closestIndex];
+
+      // 存储参考点
+      this.cursorPoints.push({
+        xAxis: this.spectrumList.x[closestIndex], // 使用实际数据点的X坐标
+        yAxis: yValue.toFixed(2), // 使用实际数据点的Y坐标
+        val: yValue.toFixed(2), // 显示实际Y值
+      });
+
+      console.log("cursorPoints:", this.cursorPoints);
+
+      this.updateCursorElements();
+
+      // this.checkedGB = this.checkedGB.filter((val) => val !== "添加光标");
+      // this.handlecursor();
+      this.GBcheckList.forEach((item) => {
+        item.checked = this.checkedGB.includes(item.val);
+      });
+    },
+    // 找到最接近的X轴索引
+    findClosestIndex(xValue) {
+      let minDiff = Infinity;
+      let closestIndex = 0;
+      this.spectrumList.x.forEach((x, index) => {
+        const diff = Math.abs(x - xValue);
+        if (diff < minDiff) {
+          minDiff = diff;
+          closestIndex = index;
+        }
+      });
+      return closestIndex;
+    },
+
+    updateCursorElements() {
+  // 获取当前图表选项
+  const currentOption = this.chartInstance.getOption();
+  
+  // 找到现有的特征值系列(它们有 markLine 但没有特定标识)
+  const featureSeries = currentOption.series.filter(
+    s => s.markLine && !s.id?.startsWith('CURSOR_')
+  );
+  
+  // 参考线配置(垂直线)
+  const cursorLineSeries = {
+    id: 'CURSOR_LINE_SERIES',
+    type: "line",
+    markLine: {
+      silent: true,
+      lineStyle: {
+        color: "#FF0000",
+        type: "dashed",
+        width: 1,
+      },
+      symbol: ["none", "none"],
+      label: { show: false },
+      data: this.cursorPoints.map((point) => ({
+        xAxis: point.xAxis,
+      })),
+    },
+  };
+
+  // 参考点配置(实际数据点位置)
+  const cursorPointSeries = {
+    id: 'CURSOR_POINT_SERIES',
+    type: "scatter",
+    symbol: "circle",
+    symbolSize: 8,
+    itemStyle: { color: "#FF0000" },
+    data: this.cursorPoints.map((point) => ({
+      value: [point.xAxis, point.yAxis],
+      name: point.val,
+    })),
+    label: {
+      show: true,
+      formatter: "{@[1]}",
+      position: "top",
+      color: "#FF0000",
+      fontSize: 12,
+      backgroundColor: "rgba(255,255,255,0.7)",
+      padding: [2, 4],
+      borderRadius: 3,
+    },
+  };
+
+  if (this.chartInstance) {
+    this.chartInstance.setOption(
+      {
+        series: [
+          currentOption.series[0], // 主数据系列
+          ...featureSeries,      // 保留所有特征值系列
+          cursorLineSeries,       // 光标线系列
+          cursorPointSeries       // 光标点系列
+        ],
+      },
+      { replaceMerge: ["series"] }
+    );
+  }
+},
+
+  },
+};

+ 109 - 0
src/views/health/components/spectrogramcharts/Xdgb.js

@@ -0,0 +1,109 @@
+export default {
+  data() {
+    return {
+    // 谐波光标
+    harmonicCursorVisible: false,
+    harmonicCursorPoints: [],
+    harmonicCursorSeries: null,
+    };
+  },
+  mounted() {},
+
+  beforeDestroy() {},
+  methods: {
+    enableHarmonicCursor() {
+      this.harmonicCursorVisible = true;
+      this.chartInstance.getZr().on("click", this.handleHarmonicCursorClick);
+    },
+
+    // 禁用谐波光标
+    disableHarmonicCursor() {
+      this.harmonicCursorVisible = false;
+      this.chartInstance.getZr().off("click", this.handleHarmonicCursorClick);
+      this.removeHarmonicCursor();
+    },
+
+    handleHarmonicCursorClick(event) {
+      if (!this.harmonicCursorVisible) return;
+
+      // 获取点击位置对应的X值
+      const pointInGrid = this.chartInstance.convertFromPixel(
+        { seriesIndex: 0 },
+        [event.offsetX, event.offsetY]
+      );
+      const baseX = pointInGrid[0];
+
+      // 生成1-6倍频的X坐标
+      this.harmonicCursorPoints = [];
+      for (let i = 1; i <= 6; i++) {
+        const xValue = baseX * i;
+        const closestIndex = this.findClosestIndex(xValue);
+        this.harmonicCursorPoints.push({
+          xAxis: xValue,
+          multiple: i,
+          yValue: this.spectrumList.y[closestIndex]?.toFixed(2) || "0",
+        });
+      }
+
+      this.updateHarmonicCursor();
+    },
+
+    // 更新谐波光标显示
+    updateHarmonicCursor() {
+      // 创建谐波光标系列
+      this.harmonicCursorSeries = {
+        type: "line",
+        id: "HARMONIC_CURSOR",
+        silent: true,
+        markLine: {
+          silent: true,
+          lineStyle: {
+            color: "#FFA500", // 橙色表示谐波光标
+            type: "dashed",
+            width: 1,
+          },
+          symbol: ["none", "none"],
+          label: {
+            show: true,
+            position: "start",
+            formatter: (params) =>
+              `${params.data.multiple}X\n${params.data.yValue}`,
+            color: "#FFA500",
+            backgroundColor: "rgba(255,255,255,0.8)",
+            padding: [2, 4],
+            borderRadius: 3,
+          },
+          data: this.harmonicCursorPoints.map((point) => ({
+            xAxis: point.xAxis,
+            multiple: point.multiple,
+            yValue: point.yValue,
+          })),
+        },
+      };
+
+      // 更新图表
+      const option = this.chartInstance.getOption();
+      const otherSeries = option.series.filter(
+        (s) => s.id !== "HARMONIC_CURSOR"
+      );
+
+      this.chartInstance.setOption(
+        {
+          series: [...otherSeries, this.harmonicCursorSeries],
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+    },
+
+    // 移除谐波光标
+    removeHarmonicCursor() {
+      const option = this.chartInstance.getOption();
+      const series = option.series.filter((s) => s.id !== "HARMONIC_CURSOR");
+      this.chartInstance.setOption({ series }, { replaceMerge: ["series"] });
+      this.harmonicCursorPoints = [];
+    },
+  },
+};

+ 295 - 0
src/views/health/components/spectrogramcharts/cursorReferenceMixin.js

@@ -0,0 +1,295 @@
+// cursorReferenceMixin.js
+// import * as echarts from "echarts";
+
+export default {
+  data() {
+    return {
+      // 参考线相关数据
+      cursorHightPoints: [], // 存储所有参考线
+      currentCursorIndex: -1, // 当前参考线索引
+      peakPoints: [], // 存储所有峰值点
+      isHandlingCursor: false, // 防止重复处理
+      chartInstance: null, // ECharts实例
+    };
+  },
+
+  mounted() {
+    // 监听键盘事件
+    window.addEventListener("keydown", this.handleKeyDown);
+  },
+
+  beforeDestroy() {
+    // 移除事件监听
+    window.removeEventListener("keydown", this.handleKeyDown);
+  },
+
+  methods: {
+    /**
+     * 处理按钮点击生成参考线
+     */
+    handleMoveCursor() {
+      console.log("handleMoveCursor", "222");
+      if (this.isHandlingCursor || !this.spectrumList) return;
+      this.isHandlingCursor = true;
+
+      // 1. 找到所有峰值点
+      this.findPeakPoints();
+
+      // 2. 如果没有峰值点则返回
+      if (this.peakPoints.length === 0) {
+        this.isHandlingCursor = false;
+        return;
+      }
+      console.log(this.peakPoints);
+
+      // 3. 找到Y轴最大值点
+      const maxPeak = this.peakPoints.reduce((prev, current) =>
+        prev.y > current.y ? prev : current
+      );
+
+      // 4. 创建参考线数据
+      const referenceLine = {
+        xAxis: maxPeak.x,
+        val: maxPeak.y.toFixed(9),
+        index: maxPeak.index,
+      };
+
+      // 5. 更新参考线
+      this.cursorHightPoints = [referenceLine];
+      this.currentCursorIndex = this.peakPoints.findIndex(
+        (p) => p.index === maxPeak.index
+      );
+
+      // 6. 更新图表
+      this.updateCursorElements2();
+
+      this.isHandlingCursor = false;
+    },
+
+    /**
+     * 查找所有峰值点
+     */
+    findPeakPoints() {
+      this.peakPoints = [];
+      const yValues = this.spectrumList.y;
+      const xValues = this.spectrumList.x;
+
+      // 1. 找到所有局部峰值点(比相邻点都高的点)
+      const allPeaks = [];
+      for (let i = 1; i < yValues.length - 1; i++) {
+        if (yValues[i] > yValues[i - 1] && yValues[i] > yValues[i + 1]) {
+          allPeaks.push({
+            x: xValues[i],
+            y: yValues[i],
+            index: i,
+          });
+        }
+      }
+
+      // 2. 按y值从大到小排序
+      allPeaks.sort((a, b) => b.y - a.y);
+
+      this.peakPoints = allPeaks;
+    },
+
+    /**
+     * 处理键盘事件
+     */
+    handleKeyDown(event) {
+      if (this.cursorHightPoints.length === 0) return;
+
+      switch (event.keyCode) {
+        case 37: // 左箭头
+          this.moveCursorToLeft();
+          break;
+        case 39: // 右箭头
+          this.moveCursorToRight();
+          break;
+        default:
+          return;
+      }
+
+      // 阻止默认行为
+      event.preventDefault();
+    },
+
+    /**
+     * 向左移动参考线并保持居中
+     */
+    moveCursorToLeft() {
+      this.findPeakPoints();
+      if (this.currentCursorIndex <= 0) return;
+
+      const newIndex = this.currentCursorIndex - 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+      this.centerViewOnPeak(newPeak);
+    },
+
+    /**
+     * 向右移动参考线并保持居中
+     */
+    moveCursorToRight() {
+      this.findPeakPoints();
+      if (this.currentCursorIndex >= this.peakPoints.length - 1) return;
+
+      const newIndex = this.currentCursorIndex + 1;
+      const newPeak = this.peakPoints[newIndex];
+
+      this.updateCursorPosition(newPeak, newIndex);
+      // this.centerViewOnPeak(newPeak);
+    },
+
+    /**
+     * 将视图中心对准峰值点
+     */
+    centerViewOnPeak(peak) {
+      if (!this.chartInstance || !peak) return;
+
+      // 获取当前x轴配置和数据范围
+      const option = this.chartInstance.getOption();
+      const xAxis = option.xAxis[0];
+
+      // 计算当前可视范围
+      const axisModel = this.chartInstance.getModel().getComponent("xAxis");
+      const currentRange = axisModel.axis.scale.getExtent();
+      const viewWidth = currentRange[1] - currentRange[0];
+
+      // 计算新的居中范围(确保不超出数据边界)
+      const newMin = Math.max(xAxis.min, peak.x - viewWidth / 2);
+      const newMax = Math.min(xAxis.max, peak.x + viewWidth / 2);
+
+      // 应用新的视图范围
+      this.chartInstance.dispatchAction({
+        type: "dataZoom",
+        xAxisIndex: 0,
+        start: ((newMin - xAxis.min) / (xAxis.max - xAxis.min)) * 100,
+        end: ((newMax - xAxis.min) / (xAxis.max - xAxis.min)) * 100,
+        animation: {
+          duration: 300, // 添加平滑过渡效果
+        },
+      });
+    },
+
+    /**
+     * 更新参考线位置
+     */
+    updateCursorPosition(peak, index) {
+      this.cursorHightPoints = [
+        {
+          xAxis: peak.x,
+          val: peak.y.toFixed(9),
+          index: peak.index,
+        },
+      ];
+      console.log(this.cursorHightPoints, "updateCursorPosition");
+
+      this.currentCursorIndex = index;
+      this.$nextTick(() => {
+        this.updateCursorElements2();
+      });
+    },
+
+    /**
+     * 更新参考线元素(不覆盖已有参考线)
+     */
+    updateCursorElements2() {
+      if (!this.chartInstance) return;
+
+      // 1. 获取当前图表配置中的已有series
+      const currentOption = this.chartInstance.getOption();
+      const existingSeries = currentOption.series || [];
+
+      // 2. 过滤掉旧的峰值参考线(通过id或特定标记识别)
+      const filteredSeries = existingSeries.filter(
+        (series) => !series.id || !series.id.includes("PEAK_REFERENCE_LINE")
+      );
+      console.log(filteredSeries);
+
+      // 3. 准备新的峰值参考线配置
+      const cursorHighLineSeries = {
+        id: "PEAK_REFERENCE_LINE",
+        type: "line",
+        markLine: {
+          data: this.cursorHightPoints.map((point) => ({
+            xAxis: point.xAxis,
+            label: {
+              formatter: "峰值: " + point.val,
+            },
+            lineStyle: {
+              color: "#FF0000",
+            },
+          })),
+        },
+      };
+
+      // 4. 合并所有series配置
+      const allSeries = [
+        ...filteredSeries, // 保留已有series
+        cursorHighLineSeries, // 添加新的峰值参考线
+      ];
+      console.log(allSeries);
+
+      // 5. 更新图表配置
+      this.chartInstance.setOption(
+        {
+          series: allSeries,
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+    },
+    /**
+     * 获取参考线markLine配置
+     */
+    getCursorMarkLineConfig() {
+      return {
+        data: this.cursorHightPoints.map((point) => ({
+          xAxis: point.xAxis,
+          label: {
+            formatter: "峰值: " + point.val,
+          },
+          lineStyle: {
+            color: "#FF0000",
+          },
+        })),
+        symbol: ["none", "none"],
+        silent: true,
+      };
+    },
+
+
+
+
+    removeCursor() {
+      if (!this.chartInstance) return;
+  
+      // 获取当前图表配置中的所有series
+      const currentOption = this.chartInstance.getOption();
+      const existingSeries = currentOption.series || [];
+  
+      // 过滤掉峰值参考线(通过id或特定标记识别)
+      const filteredSeries = existingSeries.filter(
+        (series) => !series.id || !series.id.includes("PEAK_REFERENCE_LINE")
+      );
+  
+      // 更新图表配置,移除所有峰值参考线
+      this.chartInstance.setOption(
+        {
+          series: filteredSeries,
+        },
+        {
+          replaceMerge: ["series"],
+          notMerge: false,
+        }
+      );
+  
+      // 清空当前光标数据
+      this.cursorHightPoints = [];
+      this.currentCursorIndex = -1;
+    },
+  },
+};

+ 1 - 1
src/views/health/vibration.vue

@@ -317,7 +317,7 @@ export default {
     // 监听 timeList 的变化
     currentRow(newVal, oldVal) {
       if (newVal) {
-        console.log(newVal, oldVal);
+        // console.log(newVal, oldVal);
         this.oldCurrentRow = oldVal;
       } else {
         console.error("currentRow is undefined or null");

+ 4 - 0
src/views/home/Index.vue

@@ -51,7 +51,11 @@ export default {
   data() {
     return {
       loading: false,
+<<<<<<< HEAD
+      isShowHd: false,//切换华电
+=======
       isShowHd: false, //true 则展示华电的菜单样式,false 则展示默认的左侧边栏菜单
+>>>>>>> 055ee205f9e0fd151c91a7107661ff86dcdd6a2c
     };
   },
   methods: {

+ 2 - 2
vue.config.js

@@ -89,8 +89,8 @@ module.exports = {
         // target: "http://192.168.5.11:8001", // WZLapi 目标地址
         // target: "http://106.120.102.238:18080/ImportDataDev", //导数工具
         // target: "http://106.120.102.238:18080/WindTransDev", //WTL外网目标地址
-        // target: "http://106.120.102.238:28999/transDataWeb", //WTL演示环境
-        target: "http://192.168.50.235:8999/transDataWeb", //WTL演示环境
+        target: "http://106.120.102.238:28999/transDataWeb", //WTL演示环境
+        // target: "http://192.168.50.235:8999/transDataWeb", //WTL演示环境
         changeOrigin: true,
         pathRewrite: {
           "^/ETLapi": "", // 去掉 /WZLapi 前缀