소스 검색

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

liujiejie 7 달 전
부모
커밋
2c80f1c48d

BIN
dist.zip


BIN
src/assets/img/DC.png


BIN
src/assets/img/DZ.png


BIN
src/assets/img/SD.png


BIN
src/assets/img/SZ.png


BIN
src/assets/img/WD.png


BIN
src/assets/img/ZC.png


+ 82 - 27
src/components/map/index.vue

@@ -2,7 +2,13 @@
   <div class="map-container">
     <div id="map" class="map"></div>
     <!-- 以下为悬浮信息等 -->
-    <div v-if="hoverInfo" :style="hoverStyle" class="hover-info">
+    <div
+      v-if="hoverInfo"
+      :style="hoverStyle"
+      class="hover-info"
+      @mouseenter="hovering = true"
+      @mouseleave="onHoverLeave"
+    >
       <h3>{{ hoverInfo.fieldName }}</h3>
       <div>
         <p>
@@ -74,7 +80,13 @@
       </div>
     </div>
 
-    <div v-if="hoverfengji" :style="hoverfengjiStyle" class="hover-fengji">
+    <div
+      v-if="hoverfengji"
+      :style="hoverfengjiStyle"
+      class="hover-fengji"
+      @mouseenter="hoveringFengji = true"
+      @mouseleave="onFengjiLeave"
+    >
       <h3>{{ hoverfengji.engineName }}</h3>
       <div>
         <p>
@@ -119,7 +131,13 @@
       </div>
     </div>
 
-    <div v-if="hoverta" :style="hovertaStyle" class="hover-ta">
+    <div
+      v-if="hoverta"
+      :style="hovertaStyle"
+      class="hover-ta"
+      @mouseenter="hoveringTa = true"
+      @mouseleave="onTaLeave"
+    >
       <h3>{{ hoverta.anemometerName }}</h3>
       <div>
         <p>
@@ -189,6 +207,8 @@ export default {
       dialogVisible: false,
       tableData: [],
       hoverInfo: null,
+      hovering: false,
+      hideTimer: null,
       hoverStyle: {
         position: "absolute",
         left: "0px",
@@ -206,6 +226,11 @@ export default {
         left: "0px",
         top: "0px",
       },
+
+      hoveringFengji: false,
+      hoveringTa: false,
+      fengjiTimer: null,
+      taTimer: null,
       newWind: {},
     };
   },
@@ -223,12 +248,12 @@ export default {
       layers: [
         new TileLayer({
           source: new XYZ({
-            // url: "http://106.120.102.238:18000/tiles/{z}/{x}/{y}.png", //外网
+            url: "http://106.120.102.238:18000/tiles/{z}/{x}/{y}.png", //外网
             // url: "http://127.0.0.1:8010/tiles/{z}/{x}/{y}.png", //本地
             // url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //内网
             // url: "http://10.96.137.5:9080/tiles/{z}/{x}/{y}.png", //大~#@唐
             // url: "http://192.168.0.1/tiles/{z}/{x}/{y}.png", //华电
-            url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //中广核
+            // url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //中广核
           }),
         }),
         new VectorLayer({
@@ -282,6 +307,35 @@ export default {
     this.initEvent();
   },
   methods: {
+    onHoverLeave() {
+      this.hovering = false;
+      clearTimeout(this.hideTimer);
+      this.hideTimer = setTimeout(() => {
+        if (!this.hovering) {
+          this.hoverInfo = null;
+        }
+      }, 100); // 这里延迟100ms防止意外移出
+    },
+    onFengjiLeave() {
+      this.hoveringFengji = false;
+      clearTimeout(this.fengjiTimer);
+      this.fengjiTimer = setTimeout(() => {
+        if (!this.hoveringFengji) {
+          this.hoverfengji = null;
+        }
+      }, 100); // 你可以根据实际需要调大一点时间
+    },
+
+    onTaLeave() {
+      this.hoveringTa = false;
+      clearTimeout(this.taTimer);
+      this.taTimer = setTimeout(() => {
+        if (!this.hoveringTa) {
+          this.hoverta = null;
+        }
+      }, 100);
+    },
+
     addMarker(data = { point: [120.2, 30.35], val: "1" }) {
       const layer = this.map
         .getLayers()
@@ -414,18 +468,19 @@ export default {
             } else if (val == "6") {
               this.currentFeatureData = data;
             } else {
-              this.hoverInfo = null;
-              this.hoverfengji = null;
-              this.hoverta = null;
-              this.currentFeatureData = null;
+              this.hoverInfo = false;
+              this.hoverfengji = false;
+              this.hoverta = false;
+              this.currentFeatureData = false;
             }
             lastHoveredFeature = feature;
           }
         } else {
           // 没有特征时,清空所有悬浮信息
-          this.hoverInfo = null;
-          this.hoverfengji = null;
-          this.hoverta = null;
+          if (!this.hoveringInfo) this.hoverInfo = null;
+          if (!this.hoveringFengji) this.hoverfengji = null;
+          if (!this.hoveringTa) this.hoverta = null;
+
           this.currentFeatureData = null;
           lastHoveredFeature = null;
         }
@@ -468,21 +523,21 @@ export default {
       });
     },
     getwind() {
-      if (this.hoverInfo && this.hoverInfo.batchCode) {
-        const param = {
-          batchcode: this.hoverInfo.batchCode,
-          fieldCode: this.hoverInfo.codeNumber,
-        };
-        queryFloatingWindowInfo(param)
-          .then((res) => {
-            this.newWind = res.data;
-          })
-          .catch((err) => {
-            console.error("获取风信息失败", err);
-          });
-      } else {
-        console.warn("hoverInfo 或 batchCode 未定义");
-      }
+      // if (this.hoverInfo && this.hoverInfo.batchCode) {
+      const param = {
+        batchcode: this.hoverInfo.batchCode,
+        fieldCode: this.hoverInfo.codeNumber,
+      };
+      queryFloatingWindowInfo(param)
+        .then((res) => {
+          this.newWind = res.data;
+        })
+        .catch((err) => {
+          console.error("获取风信息失败", err);
+        });
+      // } else {
+      //   console.warn("hoverInfo 或 batchCode 未定义");
+      // }
     },
     moveAndZoom(data = { point: [120.2, 30.35], zoom: 15 }) {
       this.map.getView().animate({

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
src/icons/svg/fj.svg


+ 25 - 0
src/main.js

@@ -82,6 +82,31 @@ Vue.prototype.$formatDateTWO = function (timestamp) {
   return `${year}-${month}-${day} ${hours}:${minutes}`;
 };
 
+Vue.directive('number-only', {
+  bind(el) {
+    el.addEventListener('input', (e) => {
+      // 正则表达式:允许数字和最多一个小数点
+      let inputVal = e.target.value;
+      const regex = /^\d*\.?\d*$/;
+
+      // 如果不符合格式,移除不合法字符
+      if (!regex.test(inputVal)) {
+        inputVal = inputVal.replace(/[^\d.]/g, '');  // 移除非数字和小数点的字符
+      }
+
+      // 防止多个小数点
+      const parts = inputVal.split('.');
+      if (parts.length > 2) {
+        inputVal = parts[0] + '.' + parts[1];  // 只保留第一个小数点及其后面的部分
+      }
+
+      // 更新输入框的值
+      e.target.value = inputVal;
+    });
+  },
+});
+
+
 // man.js
 
 // 注册 convertDMSToDecimal 方法

+ 1 - 1
src/views/admin/cockpitManage/component/leftdata.vue

@@ -164,7 +164,7 @@
             >
               <h3>{{ item.windFarmName }}</h3>
               <p>数据类型: {{ item.typeName }}</p>
-              <p>采集次数: {{ item.count }} 次</p>
+              <p>采集条数: {{ item.count }} 条</p>
               <p>采集时间: {{ item.latestDataTime }}</p>
             </div>
           </div>

+ 8 - 8
src/views/health/components/envelopecharts.vue

@@ -28,13 +28,13 @@
         </el-checkbox-group>
       </div>
       <!-- 光标 -->
-      <!-- <div v-if="BGshow" class="eigenvalue">
+      <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>
 
     <div class="line-chart" ref="chart"></div>
@@ -383,12 +383,12 @@ 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"),
-            // },
+            myCustomTool4: {
+              show: true,
+              title: "光标",
+              icon: `image://${require("@/assets/analyse/12.png")}`,
+              onclick: () => this.Show("2"),
+            },
             myCustomTool3: {
               show: true,
               title: "特征频率",

+ 103 - 0
src/views/health/components/malfunction/Eecharts.vue

@@ -0,0 +1,103 @@
+<template>
+  <div ref="chartDom" style="width: 100%; height: 400px"></div>
+</template>
+  
+  <script>
+import * as echarts from "echarts";
+
+export default {
+  name: "LineChart",
+  props: {
+    xData: {
+      type: Array,
+      required: true,
+    },
+    yData: {
+      type: Array,
+      required: true,
+    },
+    yNames: {
+      type: Array,
+      required: true,
+    },
+    yAxisName: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {
+      myChart: null,
+    };
+  },
+  mounted() {
+    this.initChart();
+  },
+  watch: {
+    xData: "initChart",
+    yData: "initChart",
+    yNames: "initChart",
+    yAxisName: "initChart",
+  },
+  methods: {
+    initChart() {
+      if (!this.$refs.chartDom) return;
+
+      if (!this.myChart) {
+        this.myChart = echarts.init(this.$refs.chartDom);
+      }
+      const colors = ["#81C9EC", "#9CEED5", "#98A0BC", "#C9CDFF"];
+      const series = this.yData.map((dataArr, idx) => ({
+        name: this.yNames[idx] || `系列${idx + 1}`,
+        type: "line",
+        data: dataArr,
+        lineStyle: {
+          color: colors[idx % colors.length],
+        },
+        itemStyle: {
+          color: colors[idx % colors.length],
+        },
+        // areaStyle: {
+        //   color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+        //     { offset: 0, color: colors[idx % colors.length] },
+        //     { offset: 1, color: colors[idx % colors.length] + "00" }, // 底部透明
+        //   ]),
+        // },
+      }));
+
+      const option = {
+        tooltip: {
+          trigger: "axis",
+        },
+        legend: {
+          data: this.yNames,
+          top: 10,
+        },
+        grid: {
+          top: 40,
+          bottom: 0,
+          left: 40,
+          right: 20,
+          containLabel: true,
+        },
+        xAxis: {
+          type: "category",
+          data: this.xData,
+        },
+        yAxis: {
+          type: "value",
+          name: this.yAxisName,
+        },
+        series,
+        color: colors, // 统一设定图表配色
+      };
+
+      this.myChart.setOption(option);
+    },
+  },
+};
+</script>
+  
+  <style scoped>
+</style>
+  

+ 502 - 0
src/views/health/components/malfunction/bearing copy.vue

@@ -0,0 +1,502 @@
+<template>
+  <div>
+    <div class="TopBox">
+      <div class="leftdiv">
+        <h4>轴承状态</h4>
+        <div class="state">
+          <p :style="{ backgroundColor: bearingStateColors.innerRing }">
+            轴承内圈状态
+          </p>
+          <p :style="{ backgroundColor: bearingStateColors.outerRing }">
+            轴承外圈状态
+          </p>
+          <p :style="{ backgroundColor: bearingStateColors.rollingElement }">
+            轴承滚动体状态
+          </p>
+          <p :style="{ backgroundColor: bearingStateColors.cage }">
+            轴承保持架状态
+          </p>
+        </div>
+
+        <p class="PText">
+          <span><i class="color1"></i>正常</span
+          ><span><i class="color2"></i>报警</span
+          ><span><i class="color3"></i>危险</span>
+        </p>
+        <div class="Btn">
+          <el-button type="primary" size="small" @click="automaticDiagnosis"
+            >自动诊断</el-button
+          >
+        </div>
+
+        <h4>诊断步骤:</h4>
+        <p class="minp">1、选择振动测点与起止时间,点击“查询”;</p>
+        <p class="minp">2、对轴承“参数设置”输入相关信息;</p>
+        <p class="minp">3、点击“自动诊断”输出最终轴承状态结果。</p>
+      </div>
+
+      <div class="rightdiv">
+        <el-table
+          ref="multipleTable"
+          :data="tableData"
+          tooltip-effect="dark"
+          style="width: 100%"
+          height="250"
+        >
+          <!-- <el-table-column fixed type="selection" width="55"> </el-table-column> -->
+          <el-table-column prop="timeStamp" label="时间" align="center">
+          </el-table-column>
+          <el-table-column
+            prop="samplingFrequency"
+            label="采样频率(Hz)"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="rotationalSpeed"
+            label="转速(rpm)"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="innerRingFault"
+            label="轴承内圈故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="outerRingFault"
+            label="轴承外圈故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="rollingElementFault"
+            label="轴承滚动体故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="cageFault"
+            label="轴承保持架故障"
+            align="center"
+          >
+          </el-table-column>
+        </el-table>
+        <div class="fenye">
+          <p><span>故障状态代码说明:</span>0代表正常,1代表报警,2代表危险</p>
+
+          <el-pagination
+      @current-change="handleCurrentChange"
+      :current-page="currentPage"
+      layout="total, prev, pager, next, jumper"
+      :total="totalCount"
+      :page-size="10"
+    ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <div class="bottomBox">
+      <div class="BtLeft">
+        <h4>轴承状态趋势图</h4>
+        <el-empty
+          v-if="this.xData.length === 0 || this.yData.length === 0"
+          description="暂无数据"
+          style="padding: 17px 0"
+        ></el-empty>
+        <Eecharts
+          v-else
+          style="height: 250px"
+          :xData="xData"
+          :yData="yData"
+          :yNames="[
+            '轴承内圈状态',
+            '轴承外圈状态',
+            '轴承滚动体状态',
+            '轴承保持架状态',
+          ]"
+          yAxisName="轴承故障状态"
+        ></Eecharts>
+      </div>
+      <div class="BtRight">
+        <h4>参数设置</h4>
+        <div class="BtRightDiv">
+          <p class="BtRightP">
+            发动机到轴承测点转速传动比<span
+              ><el-input v-model="transmissionRatio" size="small"     v-number-only></el-input
+            ></span>
+          </p>
+          <h4>滚动轴承参数输入</h4>
+          <div class="canshu">
+            <p class="BtRightP">
+              <span class="label-text">轴承节圆直径D(mm)</span>
+              <span
+                ><el-input
+                  v-model="bearingPitchDiameter"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">滚动体直径d(mm)</span>
+              <span
+                ><el-input
+                  v-model="rollingElementDiameter"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">滚动体个数Z(个)</span>
+              <span
+                ><el-input v-model="rollingElementCount" size="small"     v-number-only></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">接触角α(°)</span>
+              <span
+                ><el-input v-model="contactAngle" size="small"     v-number-only></el-input
+              ></span>
+            </p>
+          </div>
+          <h4>报警阈值输入</h4>
+          <div class="canshu">
+            <p class="BtRightP">
+              <span class="label-text">振动速度报警阈值(mm/s)</span>
+              <span
+                ><el-input
+                  v-model="vibrationSpeedAlarmThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">振动速度危险阈值(mm/s)</span>
+              <span
+                ><el-input
+                  v-model="vibrationSpeedDangerThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">包络总值报警阈值(gE)</span>
+              <span
+                ><el-input
+                  v-model="envelopeTotalAlarmThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">包络总值危险阈值(gE)</span>
+              <span
+                ><el-input
+                  v-model="envelopeTotalDangerThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Eecharts from "./Eecharts.vue";
+export default {
+  components: { Eecharts },
+  props: {
+    codedata: {
+      type: Array,
+      default: () => [],
+    },
+    totalCount: {
+      type: Number,
+      default: 0,
+    },
+    totalPage: {
+      type: Number,
+      default: 0,
+    },
+  },
+  data() {
+    return {
+      tableData: [],
+      // 添加新的数据属性用于绑定输入框的值
+      transmissionRatio: "",
+      bearingPitchDiameter: "",
+      rollingElementDiameter: "",
+      rollingElementCount: "",
+      contactAngle: "",
+      vibrationSpeedAlarmThreshold: "",
+      vibrationSpeedDangerThreshold: "",
+      envelopeTotalAlarmThreshold: "",
+      envelopeTotalDangerThreshold: "",
+      // 分页
+
+      currentPage: 1,
+      total: 1,
+
+      xData: [],
+      yData: [],
+      // 颜色判断
+      bearingStateColors: {
+        innerRing: "#80808057",
+        outerRing: "#80808057",
+        rollingElement: "#80808057",
+        cage: "#80808057",
+      },
+      hasError: false, // 标志是否已经显示过错误提示
+    };
+  },
+  created() {
+    console.log(this.codedata, "11111111111111111111111111");
+
+    // this.tableData = this.codedata;
+  },
+  watch: {
+    codedata: {
+      handler(newVal) {
+        this.tableData = newVal;
+      },
+      immediate: true, // 组件创建时立刻执行一次
+      deep: true, // 如果 codedata 是复杂对象,建议加上
+    },
+  },
+
+  methods: {
+    
+    toggleSelection(rows) {
+      if (rows) {
+        rows.forEach((row) => {
+          this.$refs.multipleTable.toggleRowSelection(row);
+        });
+      } else {
+        this.$refs.multipleTable.clearSelection();
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+      
+      this.currentPage = val // 子组件内部更新当前页
+      this.$emit('updatePage', this.currentPage) // 通知父组件,把当前页传出去
+    },
+    automaticDiagnosis() {
+      // 验证必填项
+      const requiredFields = [
+        { field: this.transmissionRatio, name: "发动机到轴承测点转速传动比" },
+        { field: this.bearingPitchDiameter, name: "轴承节圆直径D(mm)" },
+        { field: this.rollingElementDiameter, name: "滚动体直径d(mm)" },
+        { field: this.rollingElementCount, name: "滚动体个数Z(个)" },
+        { field: this.contactAngle, name: "接触角α(°)" },
+        {
+          field: this.vibrationSpeedAlarmThreshold,
+          name: "振动速度报警阈值(mm/s)",
+        },
+        {
+          field: this.vibrationSpeedDangerThreshold,
+          name: "振动速度危险阈值(mm/s)",
+        },
+        {
+          field: this.envelopeTotalAlarmThreshold,
+          name: "包络总值报警阈值(gE)",
+        },
+        {
+          field: this.envelopeTotalDangerThreshold,
+          name: "包络总值危险阈值(gE)",
+        },
+      ];
+
+      // 记录是否已弹出过错误提示
+      let hasError = false;
+
+      // 只检查必填项的字段是否为空
+      // for (const { field, name } of requiredFields) {
+      //   if (!field && !hasError) {
+      //     // 弹出提示并标记已经出现错误提示
+      //     this.$message.error(`${name} 是必填项`);
+      //     hasError = true;  // 标记已经弹出过错误提示
+      //     return;  // 停止执行后续逻辑
+      //   }
+      // }
+
+      // 如果验证通过,继续执行后续逻辑
+      const newProps = this.tableData.map(() => ({
+        innerRingFault: Math.floor(Math.random() * 3).toString(),
+        outerRingFault: Math.floor(Math.random() * 3).toString(),
+        rollingElementFault: Math.floor(Math.random() * 3).toString(),
+        cageFault: Math.floor(Math.random() * 3).toString(),
+      }));
+
+      this.tableData.forEach((row, index) => {
+        this.$set(this.tableData, index, {
+          ...row,
+          ...newProps[index], // 用每一行自己生成的随机数
+        });
+      });
+
+      // 更新颜色状态
+      const fields = [
+        { key: "innerRingFault", colorKey: "innerRing" },
+        { key: "outerRingFault", colorKey: "outerRing" },
+        { key: "rollingElementFault", colorKey: "rollingElement" },
+        { key: "cageFault", colorKey: "cage" },
+      ];
+
+      fields.forEach(({ key, colorKey }) => {
+        const values = newProps.map((item) => Number(item[key]));
+        const maxVal = Math.max(...values);
+        let color = "#80808057"; // 默认灰色
+        if (maxVal === 0) color = "green"; // 无故障
+        else if (maxVal === 1) color = "yellow"; // 警告
+        else if (maxVal === 2) color = "red"; // 危险
+
+        this.bearingStateColors[colorKey] = color; // 更新颜色
+      });
+
+      // 更新趋势图数据
+      // 更新趋势图数据(用tableData,不是newProps)
+      this.xData = this.tableData.map((item) => item.timeStamp);
+      this.yData = fields.map(({ key }) =>
+        this.tableData.map((item) => Number(item[key]))
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+h4 {
+  margin-bottom: 5px;
+  font-weight: 600;
+}
+.TopBox {
+  height: 280px;
+  display: flex;
+  justify-content: space-around;
+  .leftdiv {
+    width: 29%;
+
+    .state {
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-around;
+      align-content: center;
+      height: 100px;
+      p {
+        width: 150px;
+        height: 40px;
+        background: rgb(227, 227, 227);
+        color: rgb(50, 50, 50);
+        margin-bottom: 10px;
+        text-align: center;
+        align-content: center;
+        font-weight: 600;
+      }
+    }
+    .PText {
+      display: flex;
+      justify-content: space-around;
+      span {
+        display: flex;
+        align-items: center;
+        i {
+          width: 30px;
+          height: 15px;
+          margin-right: 5px;
+        }
+        .color1 {
+          background-color: green;
+        }
+        .color2 {
+          background-color: yellow;
+        }
+        .color3 {
+          background-color: red;
+        }
+      }
+    }
+
+    .Btn {
+      display: flex;
+      justify-content: space-around;
+      margin: 10px 0;
+    }
+    .minp {
+      font-size: 12px;
+    }
+  }
+  .rightdiv {
+    width: 69%;
+    .fenye {
+      display: flex;
+      justify-content: space-between;
+      margin: 5px 0;
+      font-size: 12px;
+      line-height: 30px;
+      span {
+        font-weight: 600;
+      }
+    }
+  }
+}
+
+.bottomBox {
+  display: flex;
+  justify-content: space-around;
+  margin-top: 10px;
+  .BtLeft {
+    border: 1px solid rgb(231, 231, 231);
+    width: 49%;
+    padding: 10px;
+  }
+  .BtRight {
+    width: 49%;
+    border: 1px solid rgb(231, 231, 231);
+    padding: 10px;
+    .BtRightDiv {
+      padding: 0 10px;
+      h4 {
+        font-size: 14px;
+      }
+      .BtRightP {
+        line-height: 30px;
+        font-size: 12px;
+        display: flex;
+        margin-bottom: 5px;
+        width: 50%;
+        span {
+          margin-left: 10px;
+          .el-input {
+            width: 100px;
+          }
+        }
+        .label-text {
+          width: 140px;
+        }
+      }
+      .canshu {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+      }
+    }
+  }
+}
+::v-deep .el-table__cell {
+  padding: 2px 0;
+  font-size: 12px;
+}
+</style>

+ 555 - 0
src/views/health/components/malfunction/bearing.vue

@@ -0,0 +1,555 @@
+<template>
+  <div>
+    <div class="TopBox">
+      <div class="leftdiv">
+        <div class="stateBox">
+          <h4>轴承状态</h4>
+          <div class="state">
+            <p :style="{ backgroundColor: bearingStateColors.innerRing }">
+              轴承内圈状态
+            </p>
+            <p :style="{ backgroundColor: bearingStateColors.outerRing }">
+              轴承外圈状态
+            </p>
+            <p :style="{ backgroundColor: bearingStateColors.rollingElement }">
+              轴承滚动体状态
+            </p>
+            <p :style="{ backgroundColor: bearingStateColors.cage }">
+              轴承保持架状态
+            </p>
+          </div>
+          <el-button
+            type="primary"
+            size="small"
+            @click="automaticDiagnosis"
+            class="btn-auto"
+            >自动诊断</el-button
+          >
+        </div>
+
+        <div class="Btn">
+          <div style="height: 200px">
+            <bing :result="result"> </bing>
+          </div>
+
+          <div class="minp">
+            <p class="PText">
+              <span><i class="color1"></i>正常</span
+              ><span><i class="color2"></i>报警</span
+              ><span><i class="color3"></i>危险</span>
+            </p>
+
+            <h4>诊断步骤:</h4>
+            <p>1、选择振动测点与起止时间,点击“查询”;</p>
+            <p>2、对轴承“参数设置”输入相关信息;</p>
+            <p>3、点击“自动诊断”输出最终轴承状态结果。</p>
+          </div>
+        </div>
+      </div>
+
+      <div class="rightdiv">
+        <el-table
+          ref="multipleTable"
+          :data="tableData"
+          tooltip-effect="dark"
+          style="width: 100%"
+          height="250"
+        >
+          <!-- <el-table-column fixed type="selection" width="55"> </el-table-column> -->
+          <el-table-column prop="timeStamp" label="时间" align="center">
+          </el-table-column>
+          <el-table-column
+            prop="samplingFrequency"
+            label="采样频率(Hz)"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="rotationalSpeed"
+            label="转速(rpm)"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="innerRingFault"
+            label="轴承内圈故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="outerRingFault"
+            label="轴承外圈故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="rollingElementFault"
+            label="轴承滚动体故障"
+            align="center"
+          >
+          </el-table-column>
+          <el-table-column
+            prop="cageFault"
+            label="轴承保持架故障"
+            align="center"
+          >
+          </el-table-column>
+        </el-table>
+        <div class="fenye">
+          <p><span>故障状态代码说明:</span>0代表正常,1代表报警,2代表危险</p>
+
+          <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page="currentPage"
+            layout="total, prev, pager, next, jumper"
+            :total="totalCount"
+            :page-size="10"
+          ></el-pagination>
+        </div>
+      </div>
+    </div>
+    <div class="bottomBox">
+      <div class="BtLeft">
+        <h4>轴承状态趋势图</h4>
+        <el-empty
+          v-if="this.xData.length === 0 || this.yData.length === 0"
+          description="暂无数据"
+          style="padding: 17px 0"
+        ></el-empty>
+        <Eecharts
+          v-else
+          style="height: 250px"
+          :xData="xData"
+          :yData="yData"
+          :yNames="[
+            '轴承内圈状态',
+            '轴承外圈状态',
+            '轴承滚动体状态',
+            '轴承保持架状态',
+          ]"
+          yAxisName="轴承故障状态"
+        ></Eecharts>
+      </div>
+      <div class="BtRight">
+        <h4>参数设置</h4>
+        <div class="BtRightDiv">
+          <p class="BtRightP">
+            发动机到轴承测点转速传动比<span
+              ><el-input
+                v-model="transmissionRatio"
+                size="small"
+                v-number-only
+              ></el-input
+            ></span>
+          </p>
+          <h4>滚动轴承参数输入</h4>
+          <div class="canshu">
+            <p class="BtRightP">
+              <span class="label-text">轴承节圆直径D(mm)</span>
+              <span
+                ><el-input
+                  v-model="bearingPitchDiameter"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">滚动体直径d(mm)</span>
+              <span
+                ><el-input
+                  v-model="rollingElementDiameter"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">滚动体个数Z(个)</span>
+              <span
+                ><el-input
+                  v-model="rollingElementCount"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">接触角α(°)</span>
+              <span
+                ><el-input
+                  v-model="contactAngle"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+          </div>
+          <h4>报警阈值输入</h4>
+          <div class="canshu">
+            <p class="BtRightP">
+              <span class="label-text">振动速度报警阈值(mm/s)</span>
+              <span
+                ><el-input
+                  v-model="vibrationSpeedAlarmThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">振动速度危险阈值(mm/s)</span>
+              <span
+                ><el-input
+                  v-model="vibrationSpeedDangerThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">包络总值报警阈值(gE)</span>
+              <span
+                ><el-input
+                  v-model="envelopeTotalAlarmThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+            <p class="BtRightP">
+              <span class="label-text">包络总值危险阈值(gE)</span>
+              <span
+                ><el-input
+                  v-model="envelopeTotalDangerThreshold"
+                  size="small"
+                  v-number-only
+                ></el-input
+              ></span>
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Eecharts from "./Eecharts.vue";
+import bing from "./bing.vue";
+import { cacheEntryPossiblyAdded } from "plotly.js-dist";
+export default {
+  components: { Eecharts, bing },
+  props: {
+    codedata: {
+      type: Array,
+      default: () => [],
+    },
+    totalCount: {
+      type: Number,
+      default: 0,
+    },
+    totalPage: {
+      type: Number,
+      default: 0,
+    },
+  },
+  data() {
+    return {
+      tableData: [],
+      // 添加新的数据属性用于绑定输入框的值
+      transmissionRatio: "",
+      bearingPitchDiameter: "",
+      rollingElementDiameter: "",
+      rollingElementCount: "",
+      contactAngle: "",
+      vibrationSpeedAlarmThreshold: "",
+      vibrationSpeedDangerThreshold: "",
+      envelopeTotalAlarmThreshold: "",
+      envelopeTotalDangerThreshold: "",
+      // 分页
+
+      currentPage: 1,
+      total: 1,
+
+      xData: [],
+      yData: [],
+      // 颜色判断
+      bearingStateColors: {
+        innerRing: "#80808057",
+        outerRing: "#80808057",
+        rollingElement: "#80808057",
+        cage: "#80808057",
+      },
+      hasError: false, // 标志是否已经显示过错误提示
+      result: {},
+    };
+  },
+  created() {},
+  watch: {
+    codedata: {
+      handler(newVal) {
+        this.tableData = newVal;
+      },
+      immediate: true, // 组件创建时立刻执行一次
+      deep: true, // 如果 codedata 是复杂对象,建议加上
+    },
+  },
+
+  methods: {
+    toggleSelection(rows) {
+      if (rows) {
+        rows.forEach((row) => {
+          this.$refs.multipleTable.toggleRowSelection(row);
+        });
+      } else {
+        this.$refs.multipleTable.clearSelection();
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+
+      this.currentPage = val; // 子组件内部更新当前页
+      this.$emit("updatePage", this.currentPage); // 通知父组件,把当前页传出去
+    },
+    automaticDiagnosis() {
+      // 验证必填项
+      const requiredFields = [
+        { field: this.transmissionRatio, name: "发动机到轴承测点转速传动比" },
+        { field: this.bearingPitchDiameter, name: "轴承节圆直径D(mm)" },
+        { field: this.rollingElementDiameter, name: "滚动体直径d(mm)" },
+        { field: this.rollingElementCount, name: "滚动体个数Z(个)" },
+        { field: this.contactAngle, name: "接触角α(°)" },
+        {
+          field: this.vibrationSpeedAlarmThreshold,
+          name: "振动速度报警阈值(mm/s)",
+        },
+        {
+          field: this.vibrationSpeedDangerThreshold,
+          name: "振动速度危险阈值(mm/s)",
+        },
+        {
+          field: this.envelopeTotalAlarmThreshold,
+          name: "包络总值报警阈值(gE)",
+        },
+        {
+          field: this.envelopeTotalDangerThreshold,
+          name: "包络总值危险阈值(gE)",
+        },
+      ];
+
+      // 记录是否已弹出过错误提示
+      let hasError = false;
+
+      // 只检查必填项的字段是否为空
+      // for (const { field, name } of requiredFields) {
+      //   if (!field && !hasError) {
+      //     // 弹出提示并标记已经出现错误提示
+      //     this.$message.error(`${name} 是必填项`);
+      //     hasError = true;  // 标记已经弹出过错误提示
+      //     return;  // 停止执行后续逻辑
+      //   }
+      // }
+
+      // 如果验证通过,继续执行后续逻辑
+      const newProps = this.tableData.map(() => ({
+        innerRingFault: Math.floor(Math.random() * 3).toString(),
+        outerRingFault: Math.floor(Math.random() * 3).toString(),
+        rollingElementFault: Math.floor(Math.random() * 3).toString(),
+        cageFault: Math.floor(Math.random() * 3).toString(),
+      }));
+
+      this.tableData.forEach((row, index) => {
+        this.$set(this.tableData, index, {
+          ...row,
+          ...newProps[index], // 用每一行自己生成的随机数
+        });
+      });
+
+      const faultValues = [
+        ...this.tableData.map((record) => record.innerRingFault),
+        ...this.tableData.map((record) => record.outerRingFault),
+        ...this.tableData.map((record) => record.rollingElementFault),
+        ...this.tableData.map((record) => record.cageFault),
+      ];
+
+      // 统计各个值出现的次数
+      const counter = faultValues.reduce((acc, value) => {
+        acc[value] = (acc[value] || 0) + 1;
+        return acc;
+      }, {});
+
+      // 构造统计结果对象
+      this.result = {
+        1: counter["0"] || 0,
+        2: counter["1"] || 0,
+        3: counter["2"] || 0,
+      };
+
+      // 更新颜色状态
+      const fields = [
+        { key: "innerRingFault", colorKey: "innerRing" },
+        { key: "outerRingFault", colorKey: "outerRing" },
+        { key: "rollingElementFault", colorKey: "rollingElement" },
+        { key: "cageFault", colorKey: "cage" },
+      ];
+
+      fields.forEach(({ key, colorKey }) => {
+        const values = newProps.map((item) => Number(item[key]));
+        const maxVal = Math.max(...values);
+        let color = "#80808057"; // 默认灰色
+        if (maxVal === 0) color = "green"; // 无故障
+        else if (maxVal === 1) color = "yellow"; // 警告
+        else if (maxVal === 2) color = "red"; // 危险
+
+        this.bearingStateColors[colorKey] = color; // 更新颜色
+      });
+
+      // 更新趋势图数据
+      // 更新趋势图数据(用tableData,不是newProps)
+      this.xData = this.tableData.map((item) => item.timeStamp);
+      this.yData = fields.map(({ key }) =>
+        this.tableData.map((item) => Number(item[key]))
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+h4 {
+  margin-bottom: 5px;
+  font-weight: 600;
+}
+.TopBox {
+  height: 280px;
+  display: flex;
+  justify-content: space-around;
+  .leftdiv {
+    width: 29%;
+    display: flex;
+    justify-content: space-around;
+    .stateBox {
+      .state {
+        display: flex;
+        flex-direction: column;
+        justify-content: center; /* 整体居中 */
+        align-items: center;
+        height: 200px;
+        gap: 20px; /* 控制间距 */
+        p {
+          width: 150px;
+          height: 40px;
+          background: rgb(227, 227, 227);
+          color: rgb(50, 50, 50);
+          text-align: center;
+          align-content: center;
+          font-weight: 600;
+        }
+      }
+      .btn-auto {
+        margin-top: 10px;
+        width: 100%;
+      }
+    }
+    .Btn {
+      display: flex;
+      flex-direction: column; /* 垂直排列 */
+      justify-content: space-between; /* 顶部和底部对齐 */
+      min-height: 100px; /* 确保容器有足够高度 */
+      margin: 10px 0;
+      .PText {
+        display: flex;
+        justify-content: space-around;
+
+        span {
+          display: flex;
+          align-items: center;
+          i {
+            width: 30px;
+            height: 15px;
+            margin-right: 5px;
+          }
+          .color1 {
+            background-color: #8AE359;
+          }
+          .color2 {
+            background-color: #EECB5F  ;
+          }
+          .color3 {
+            background-color: #F7715F;
+          }
+        }
+      }
+      margin: 10px 0;
+      .minp {
+        font-size: 12px;
+        margin-top: auto; /* 自动推到最底部 */
+      }
+    }
+  }
+  .rightdiv {
+    width: 69%;
+    .fenye {
+      display: flex;
+      justify-content: space-between;
+      margin: 5px 0;
+      font-size: 12px;
+      line-height: 30px;
+      span {
+        font-weight: 600;
+      }
+    }
+  }
+}
+
+.bottomBox {
+  display: flex;
+  justify-content: space-around;
+  margin-top: 10px;
+  .BtLeft {
+    border: 1px solid rgb(231, 231, 231);
+    width: 49%;
+    padding: 10px;
+  }
+  .BtRight {
+    width: 49%;
+    border: 1px solid rgb(231, 231, 231);
+    padding: 10px;
+    .BtRightDiv {
+      padding: 0 10px;
+      h4 {
+        font-size: 14px;
+      }
+      .BtRightP {
+        line-height: 30px;
+        font-size: 12px;
+        display: flex;
+        margin-bottom: 5px;
+        width: 50%;
+        span {
+          margin-left: 10px;
+          .el-input {
+            width: 100px;
+          }
+        }
+        .label-text {
+          width: 140px;
+        }
+      }
+      .canshu {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+      }
+    }
+  }
+}
+::v-deep .el-table__cell {
+  padding: 2px 0;
+  font-size: 12px;
+}
+</style>

+ 149 - 0
src/views/health/components/malfunction/bing.vue

@@ -0,0 +1,149 @@
+<template>
+  <div ref="chartDom" style="width: 100%; height: 100%"></div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+
+export default {
+  name: "EChartsComponent",
+
+  props: {
+    result: {
+      type: Object, // 使用 Object 作为类型
+      default: () => ({}),
+    },
+  },
+
+  data() {
+    return {
+      myChart: null,
+    };
+  },
+
+  mounted() {
+    console.log(this.result, "this.result");
+
+    this.initChart(); // 初始化图表
+  },
+
+  watch: {
+    // 监听 result 的变化
+    result(newValue) {
+      console.log("result changed", newValue);
+      this.updateChart(newValue); // 更新图表
+    },
+  },
+
+  methods: {
+    initChart() {
+      const chartDom = this.$refs.chartDom;
+      this.myChart = echarts.init(chartDom);
+
+      const option = {
+        title: {
+          text: "状态统计图",
+          left: "center",
+          textStyle: {
+            fontSize: 14, // 设置字体大小
+            fontWeight: "600", // 可选,设置字体粗细
+            color: "#333", // 可选,设置字体颜色
+          },
+        },
+        tooltip: {
+          trigger: "item",
+          formatter: "{b}: {c} 次 ({d}%)", // 显示次数和百分比
+        },
+
+        series: [
+          {
+            name: "状态次数",
+            type: "pie",
+            radius: ["40%", "60%"], // 设置内外半径来形成圆环
+            data: [
+              { value: 0, name: "正常", itemStyle: { color: "#8AE359" } },
+              { value: 0, name: "一般", itemStyle: { color: "#EECB5F" } },
+              { value: 0, name: "危险", itemStyle: { color: "#F7715F" } },
+            ],
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: "rgba(0, 0, 0, 0.5)",
+              },
+            },
+            label: {
+              // formatter: "{b}: {c} 次", // 在图表中显示次数
+            },
+          },
+        ],
+      };
+
+      this.myChart.setOption(option);
+    },
+
+    // 更新图表方法
+    updateChart(newResult) {
+      console.log(newResult, "111111111111111111");
+
+      const option = {
+        title: {
+          text: "状态统计图",
+          left: "center",
+          textStyle: {
+            fontSize: 14, // 设置字体大小
+            fontWeight: "600", // 可选,设置字体粗细
+            color: "#333", // 可选,设置字体颜色
+          },
+        },
+        tooltip: {
+          trigger: "item",
+          // formatter: "{b}: {c} 次 ({d}%)", // 显示次数和百分比
+        },
+
+        series: [
+          {
+            name: "状态次数",
+            type: "pie",
+            radius: ["40%", "60%"], // 设置内外半径来形成圆环
+            data: [
+              {
+                value: newResult[1] || 0,
+                name: "正常",
+                itemStyle: { color: "#8AE359" },
+              },
+              {
+                value: newResult[2] || 0,
+                name: "一般",
+                itemStyle: { color: "#EECB5F" },
+              },
+              {
+                value: newResult[3] || 0,
+                name: "危险",
+                itemStyle: { color: "#F7715F" },
+              },
+            ],
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: "rgba(0, 0, 0, 0.5)",
+              },
+            },
+            label: {
+              // formatter: "{b}: {c} 次", // 在图表中显示次数
+            },
+          },
+        ],
+      };
+
+      // 更新图表
+      this.myChart.setOption(option);
+    },
+  },
+};
+</script>
+
+<style scoped>
+/* 可根据需求添加样式 */
+</style>

+ 16 - 0
src/views/health/components/malfunction/dissymmetry.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>不对称诊断</div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  height: 300px;
+  background: #677445;;
+}
+</style>

+ 16 - 0
src/views/health/components/malfunction/gear.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>齿轮诊断</div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  height: 300px;
+  background: #fd5d18;;
+}
+</style>

+ 16 - 0
src/views/health/components/malfunction/loose.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>松动诊断</div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  height: 300px;
+  background: #7e0505;;
+}
+</style>

+ 16 - 0
src/views/health/components/malfunction/misalignment.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>不平衡诊断</div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  height: 300px;
+  background: #16a37e;;
+}
+</style>

+ 18 - 0
src/views/health/components/malfunction/temperature.vue

@@ -0,0 +1,18 @@
+<template>
+  <div>
+    温度诊断
+  </div>
+</template>
+
+<script>
+export default {
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  height: 300px;
+  background: #33a21d9f;;
+}
+</style>

+ 8 - 8
src/views/health/components/spectrogramcharts.vue

@@ -2,13 +2,13 @@
   <div>
     <div class="FD">
       <!-- 光标 -->
-      <!-- <div v-if="BGshow" class="eigenvalue">
+      <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 v-if="PXshow" class="eigenvalue">
         <el-checkbox-group v-model="checkedValues" @change="handleCheckChange">
@@ -351,12 +351,12 @@ 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"),
-            // },
+            myCustomTool4: {
+              show: true,
+              title: "光标",
+              icon: `image://${require("@/assets/analyse/12.png")}`,
+              onclick: () => this.Show("2"),
+            },
             myCustomTool5: {
               show: true,
               title: "特征频率",

+ 360 - 0
src/views/health/index.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="global-variable">
+    <div class="searchbox">
+      <p>
+        单位:
+        <selecttree
+          style="width: 180px"
+          placeholder="请选择所属公司"
+          :list="parentOpt"
+          type="1"
+          v-model="companyCode"
+          :defaultParentProps="{
+            children: 'children',
+            label: 'companyName',
+            value: 'codeNumber',
+          }"
+        >
+        </selecttree>
+      </p>
+
+      <p>
+        时间:
+        <el-date-picker
+          v-model="timevalue"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        >
+        </el-date-picker>
+      </p>
+      <el-button type="primary" size="small" @click="conditions"
+        >查询</el-button
+      >
+    </div>
+    <div class="main-body">
+      <div class="basics" v-for="(item, index) in ListData" :key="item + index">
+        <div class="title">
+          <span>
+            <SvgIcons
+              name="WindPower3"
+              class="WindPower3"
+              width="30"
+              height="30"
+            ></SvgIcons>
+          </span>
+          <h4>
+            {{ item.fanName }}
+          </h4>
+        </div>
+        <div class="content">
+          <div class="summary" v-if="item.status == '1'" style="color: #28a745">
+            健康
+          </div>
+          <div
+            class="summary"
+            v-else-if="item.status == '2'"
+            style="color: #ffc107"
+          >
+            亚健康
+          </div>
+          <div
+            class="summary"
+            v-else-if="item.status == '3'"
+            style="color: #fd7e14"
+          >
+            一般
+          </div>
+          <div
+            class="summary"
+            v-else-if="item.status == '4'"
+            style="color: #dc3545"
+          >
+            故障
+          </div>
+          <div class="summary" v-else>未知状态</div>
+
+          <ul class="health">
+            <li v-for="item in item.systems" :key="item.name">
+              <span>{{ item.name }}</span>
+              <span :class="'health-' + item.val">
+                {{ getStatusText(item.val) }}
+              </span>
+            </li>
+          </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as FileSaver from "file-saver";
+import * as XLSX from "xlsx";
+import { getSysOrganizationAuthTreeByRoleId } from "@/api/ledger.js";
+import selecttree from "../../components/selecttree.vue";
+import axios from "axios";
+export default {
+  components: {
+    selecttree,
+  },
+  data() {
+    return {
+      parentOpt: [],
+      companyCode: "",
+      timevalue: [], // 绑定 el-date-picker 的值
+      startTime: "", // 开始时间
+      endTime: "", // 结束时间
+      ListData: [
+        {
+          fanName: "FXX风机-1号", // 风机名称
+          status: "1",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "1" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "3" },
+            { name: "电网环境", val: "4" },
+            { name: "辅助系统", val: "1" },
+          ],
+        },
+        {
+          fanName: "FXX风机-2号", // 风机名称
+          status: "2",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "2" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "2" },
+            { name: "电网环境", val: "2" },
+            { name: "辅助系统", val: "2" },
+          ],
+        },
+        {
+          fanName: "FXX风机-1号", // 风机名称
+          status: "1",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "1" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "3" },
+            { name: "电网环境", val: "4" },
+            { name: "辅助系统", val: "1" },
+          ],
+        },
+        {
+          fanName: "FXX风机-1号", // 风机名称
+          status: "1",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "1" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "3" },
+            { name: "电网环境", val: "4" },
+            { name: "辅助系统", val: "1" },
+          ],
+        },
+        {
+          fanName: "FXX风机-1号", // 风机名称
+          status: "1",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "1" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "3" },
+            { name: "电网环境", val: "4" },
+            { name: "辅助系统", val: "1" },
+          ],
+        },
+        {
+          fanName: "FXX风机-1号", // 风机名称
+          status: "1",
+          systems: [
+            // 子系统列表
+            { name: "发电机组", val: "1" },
+            { name: "传动系统", val: "2" },
+            { name: "机舱系统", val: "3" },
+            { name: "电网环境", val: "4" },
+            { name: "辅助系统", val: "1" },
+          ],
+        },
+      ],
+    };
+  },
+
+  created() {
+    this.GETtree();
+  },
+  watch: {},
+  methods: {
+    getStatusText(val) {
+      const statusMap = {
+        1: "健康",
+        2: "亚健康",
+        3: "一般",
+        4: "故障",
+      };
+      return statusMap[val] || val;
+    },
+    // 获取风场
+    async GETtree() {
+      const res = await getSysOrganizationAuthTreeByRoleId();
+      const treedata = res.data;
+      const processedData = this.processTreeData(treedata);
+      this.parentOpt = processedData;
+      this.defaultdata = res.data[0];
+    },
+
+    processTreeData(treeData) {
+      const processedData = [];
+      function processNode(node) {
+        if (node.codeType === "field") {
+          node.companyName = node.fieldName;
+        }
+        if (node.children && node.children.length > 0) {
+          node.children.forEach((child) => {
+            processNode(child);
+          });
+        }
+      }
+      treeData.forEach((root) => {
+        processNode(root);
+        processedData.push(root);
+      });
+      return processedData;
+    },
+
+    conditions() {},
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.searchbox {
+  display: flex;
+  margin: 0 0 20px 0;
+  p {
+    margin-right: 20px;
+  }
+  .el-select {
+    width: 180px;
+  }
+}
+
+.el-input__inner {
+  width: 340px;
+}
+
+.main-body {
+  margin: 0 auto;
+  display: grid;
+  grid-template-columns: repeat(auto-fill, 300px); /* 严格保持300px宽度 */
+  justify-content: space-evenly; /* 均匀分布 */
+  gap: 10px;
+
+  height: min-content;
+  max-height: 700px;
+  overflow: hidden;
+  overflow-y: auto;
+  .basics {
+    width: 300px; /* 固定宽度 */
+    display: flex;
+    flex-direction: column;
+    margin-bottom: 20px;
+    border: 1px solid var(--header-bg);
+
+    .title {
+      padding: 5px 0;
+      width: 100%;
+      border-bottom: 1px solid var(--header-bg);
+      text-align: center;
+
+      display: flex;
+      align-items: center; // 垂直居中
+    //   justify-content: center; // 水平居中
+
+      span {
+        display: inline-block;
+        margin-right: 6px;
+
+        svg {
+          display: block;
+        }
+      }
+
+      h4 {
+        color: var(--header-bg);
+        font-size: 1.1em;
+        font-weight: 600;
+        margin: 0;
+      }
+    }
+
+    .content {
+      display: flex;
+      width: 100%;
+      gap: 8px;
+      .summary {
+        width: 90px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-weight: bold;
+        font-size: 1.3em;
+      }
+      .health {
+        flex: 1;
+        display: flex;
+        flex-wrap: wrap;
+        gap: 6px;
+        list-style: none;
+        padding: 0;
+        margin: 0;
+
+        li {
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          padding: 6px 6px;
+          border-radius: 4px;
+          min-width: 60px;
+          font-size: 0.8em;
+
+          span {
+            display: block;
+            text-align: center;
+            line-height: 1.3;
+            &:first-child {
+              font-size: 0.9em;
+              font-weight: 600;
+              margin-bottom: 2px;
+            }
+          }
+        }
+        li span {
+          &:last-child {
+            // Status color classes
+            &.health-1 {
+              color: #28a745;
+            } // 健康 - 绿色
+            &.health-2 {
+              color: #ffc107;
+            } // 亚健康 - 黄色
+            &.health-3 {
+              color: #fd7e14;
+            } // 一般 - 橙色
+            &.health-4 {
+              color: #dc3545;
+            } // 故障 - 红色
+          }
+        }
+      }
+    }
+  }
+}
+.jia {
+  color: var(--header-bg);
+}
+</style>

+ 404 - 0
src/views/health/malfunction.vue

@@ -0,0 +1,404 @@
+<template>
+  <div class="global-variable">
+    <div class="head">
+      <ul>
+        <li
+          v-for="(item, index) in menuItems"
+          :key="index"
+          @click="activeTab = item.component"
+          :class="{ active: activeTab === item.component }"
+        >
+          <span class="Simg"><img :src="item.icon" :alt="item.name" /></span>
+          <span>{{ item.name }}</span>
+        </li>
+      </ul>
+    </div>
+
+    <div class="searchbox">
+      <p>
+        单位:
+        <selecttree
+          style="width: 180px"
+          placeholder="请选择所属公司"
+          :list="parentOpt"
+          type="1"
+          v-model="companyCode"
+          @change="parentChange"
+          :defaultParentProps="{
+            children: 'children',
+            label: 'companyName',
+            value: 'codeNumber',
+          }"
+        >
+        </selecttree>
+      </p>
+      <p>
+        风机:
+        <el-select
+          style="width: 150px"
+          v-model="unitvalue"
+          @change="getchedian"
+          placeholder="请选择"
+        >
+          <el-option
+            v-for="item in unitoptions"
+            :key="item.engineCode"
+            :label="item.engineName"
+            :value="item.engineCode"
+          >
+          </el-option>
+        </el-select>
+      </p>
+      <p>
+        测点:
+        <el-select v-model="monitoringvalue" clearable placeholder="请选择">
+          <el-option
+            v-for="item in monitoringoptions"
+            :key="item.detectionPointEn"
+            :label="item.detectionPointCn"
+            :value="item.detectionPointEn"
+          >
+          </el-option>
+        </el-select>
+      </p>
+      <p>
+        频率:
+        <el-select v-model="frequencyvalue" clearable placeholder="请选择">
+          <el-option
+            v-for="item in frequencyoptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          >
+          </el-option>
+        </el-select>
+      </p>
+      <p>
+        时间:
+        <el-date-picker
+          v-model="timevalue"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        >
+        </el-date-picker>
+      </p>
+      <el-button type="primary" size="small" @click="conditions(1)"
+        >查询</el-button
+      >
+      <!-- <el-button type="primary" size="small">自动诊断</el-button> -->
+    </div>
+
+    <div class="main-body">
+      <keep-alive>
+        <component :is="activeTab" :codedata="codedata" :totalCount="totalCount"  :totalPage="totalPage" @updatePage="handlePageChange" />
+      </keep-alive>
+    </div>
+  </div>
+</template>
+  
+  <script>
+import * as FileSaver from "file-saver";
+import * as XLSX from "xlsx";
+import {
+  getSysOrganizationAuthTreeByRoleId,
+  windEngineGrouPage,
+  queryDetectionDic,
+} from "@/api/ledger.js";
+import selecttree from "../../components/selecttree.vue";
+import Bearing from "./components/malfunction/bearing.vue";
+import Dissymmetry from "./components/malfunction/dissymmetry.vue";
+import Gear from "./components/malfunction/gear.vue";
+import Loose from "./components/malfunction/loose.vue";
+import Misalignment from "./components/malfunction/misalignment.vue";
+import Temperature from "./components/malfunction/temperature.vue";
+import axios from "axios";
+export default {
+  components: {
+    selecttree,
+    Bearing,
+    Dissymmetry,
+    Gear,
+    Loose,
+    Misalignment,
+    Temperature,
+  },
+  data() {
+    return {
+      activeTab: "Bearing", // 默认显示轴承诊断
+      menuItems: [
+        {
+          name: "轴承诊断",
+          icon: require("@/assets/img/ZC.png"),
+          component: "Bearing",
+        },
+        {
+          name: "齿轮诊断",
+          icon: require("@/assets/img/SZ.png"),
+          component: "Gear",
+        },
+        {
+          name: "不对中诊断",
+          icon: require("@/assets/img/DZ.png"),
+          component: "Dissymmetry",
+        },
+        {
+          name: "不平衡诊断",
+          icon: require("@/assets/img/DC.png"),
+          component: "Misalignment",
+        },
+        {
+          name: "松动诊断",
+          icon: require("@/assets/img/SD.png"),
+          component: "Loose",
+        },
+        {
+          name: "温度诊断",
+          icon: require("@/assets/img/WD.png"),
+          component: "Temperature",
+        },
+      ],
+      unitvalue: "",
+      unitoptions: [],
+      companyCode: "",
+      parentOpt: [],
+      timevalue: [],
+      startTime: "",
+      endTime: "",
+      monitoringvalue: "",
+      monitoringoptions: [],
+
+      frequencyvalue: "",
+      frequencyoptions: [],
+
+      codedata: [],
+      totalCount: 0,
+      totalPage:0,
+      page: "",
+    };
+  },
+  created() {
+    this.GETtree();
+  },
+  methods: {
+    async GETtree() {
+      const res = await getSysOrganizationAuthTreeByRoleId();
+      const treedata = res.data;
+      const processedData = this.processTreeData(treedata);
+      this.parentOpt = processedData;
+      this.defaultdata = res.data[0];
+    },
+    // 获取所属单位
+    parentChange(data) {
+      this.maplist = data;
+      this.maplistArr = data;
+
+      // 1. 检查关键数据
+      if (!this.maplist?.codeNumber) {
+        console.error("codeNumber 不存在!");
+        return;
+      }
+
+      // 2. 发起第一个请求
+      let paramsData = {
+        fieldCode: this.maplist.codeNumber,
+        pageNum: 1,
+        pageSize: 99,
+      };
+      this.unitvalue = "";
+
+      windEngineGrouPage(paramsData)
+        .then((res) => {
+          this.unitoptions = res.data.list;
+          this.windCode = this.companyCode;
+        })
+        .catch((err) => {
+          console.error("windEngineGrouPage 失败:", err);
+        });
+
+      // 3. 解析坐标逻辑(避免 return 终止函数)
+      let shouldSkip = false;
+      try {
+        if (data.codeType === "field") {
+          if (
+            this.parseCoordinates(data.longitudeAndLatitudeString).length > 0
+          ) {
+            shouldSkip = true;
+          }
+        } else {
+          data.children?.forEach((element) => {
+            if (
+              element.codeType === "field" &&
+              this.parseCoordinates(element.longitudeAndLatitudeString).length >
+                0
+            ) {
+              shouldSkip = true;
+            }
+          });
+        }
+      } catch (err) {
+        console.error("解析坐标出错:", err);
+      }
+
+      if (shouldSkip) {
+        console.log("坐标已存在,跳过部分逻辑");
+      }
+
+      // 4. 确保第二个请求执行
+      axios
+        .get(
+          `/ETLapi/waveData/getAllSamplingFrequency/${this.maplist.codeNumber}`
+        )
+
+        .then((res) => {
+          this.frequencyoptions = res.data.datas;
+        })
+        .catch((err) => {
+          console.error("第二个请求失败:", err);
+        });
+    },
+    processTreeData(treeData) {
+      const processedData = [];
+      function processNode(node) {
+        if (node.codeType === "field") {
+          node.companyName = node.fieldName;
+        }
+        if (node.children && node.children.length > 0) {
+          node.children.forEach((child) => {
+            processNode(child);
+          });
+        }
+      }
+      treeData.forEach((root) => {
+        processNode(root);
+        processedData.push(root);
+      });
+      return processedData;
+    },
+    parseCoordinates(input) {
+      if (input && typeof input === "string") {
+        return input.split(",").map(Number);
+      }
+      return [];
+    },
+    // 风机
+    getchedian(value) {
+      queryDetectionDic({ engineCodes: value }).then((res) => {
+        this.monitoringoptions = res.data;
+      });
+    },
+    handlePageChange(page) {
+      console.log(`接收到的当前页: ${page}`);
+      // 更新当前页
+      this.conditions(page);  // 调用条件方法时传递页码
+    },
+    conditions(page) {
+      const params = {
+        samplingFrequency: this.frequencyvalue,
+        windCode: this.maplist.codeNumber,
+        windTurbineNumberList: [this.unitvalue],
+        mesureNameList: [this.monitoringvalue],
+        startTime: this.$formatDateTWO(this.timevalue[0]),
+        endTime: this.$formatDateTWO(this.timevalue[1]),
+        pageNo:page,
+        pageSize: 10,
+      };
+
+      axios.post(`/ETLapi/waveData/getMesureDataWithSF`, params).then((res) => {
+        this.codedata = res.data.datas;
+        this.totalCount = res.data.totalCount;
+        this.totalPage=res.data.totalPage
+      });
+    },
+  },
+};
+</script>
+  
+  <style lang="scss" scoped>
+.global-variable {
+  padding: 20px;
+}
+.head {
+  padding: 5px 0;
+  display: flex;
+  justify-content: space-between;
+
+  ul {
+    display: flex;
+    width: 500px;
+    height: 65px;
+    justify-content: space-between;
+    li {
+      cursor: pointer;
+      padding: 8px 12px 0 12px;
+      border-radius: 4px;
+      transition: all 0.3s;
+
+      &:hover {
+        background-color: #f0f0f0;
+      }
+
+      &.active {
+        background-color: #e6f7ff;
+        border-bottom: 2px solid var(--header-bg);
+
+        span {
+          color: var(--header-bg);
+          font-weight: bold;
+        }
+      }
+
+      .Simg {
+        width: 30px;
+        height: 30px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 auto;
+
+        img {
+          max-width: 100%;
+          max-height: 100%;
+        }
+      }
+
+      span {
+        display: block;
+        font-size: 12px;
+        font-weight: 600;
+        text-align: center;
+        margin-top: 5px;
+      }
+    }
+  }
+}
+.searchbox {
+  display: flex;
+  margin: 10px 0;
+  align-items: center;
+
+  p {
+    margin-right: 20px;
+    margin-bottom: 0;
+    display: flex;
+    align-items: center;
+
+    .el-select,
+    .el-date-picker {
+      margin-left: 10px;
+    }
+  }
+
+  .el-select {
+    width: 180px;
+  }
+}
+.main-body {
+  margin-top: 10px;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  padding: 10px;
+  background: #fff;
+}
+</style>

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

@@ -26,6 +26,7 @@
         <img src="@/assets/analyse/06.png" alt="全部关闭" @click="guanbi" />
       </div>
     </div>
+    
     <div class="searchbox">
       <p>
         单位:

+ 2 - 2
vue.config.js

@@ -66,8 +66,8 @@ module.exports = {
         // target: "http://192.168.5.4:16200", // 石月
         // target: "http://192.168.50.235:16200", // 内网
         // target: "http://192.168.5.15:16200",
-        target: "http://192.168.50.235:16500", //演示环境
-        // target: "http://106.120.102.238:26500", //外网演示环境
+        // target: "http://192.168.50.235:16500", //演示环境
+        target: "http://106.120.102.238:26500", //外网演示环境
         // target: "http://106.120.102.238:16700", // 外网16700  生产16600
         // target: "http://10.96.137.5",
         changeOrigin: true,

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.