Sfoglia il codice sorgente

整体功能完成90%

zhangsijie 1 anno fa
parent
commit
ec0ef2d03e

+ 1 - 1
minggao/index.html

@@ -3,7 +3,7 @@
  * @Autor: lin
  * @Date: 2023-06-05 08:51:07
  * @LastEditors: lin
- * @LastEditTime: 2024-04-11 15:22:19
+ * @LastEditTime: 2024-04-18 16:01:57
 -->
 <!DOCTYPE html>
 <html>

+ 21 - 1
minggao/package-lock.json

@@ -12,7 +12,9 @@
         "axios": "^0.24.0",
         "dayjs": "^1.11.7",
         "echarts": "^4.9.0",
+        "echarts-gl": "^1.1.0",
         "element-ui": "^2.15.6",
+        "ezuikit-js": "^7.6.6",
         "less": "^4.1.2",
         "lodash-es": "^4.17.21",
         "qrcodejs2": "^0.0.2",
@@ -2765,6 +2767,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/claygl": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
+      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
+    },
     "node_modules/clean-css": {
       "version": "4.2.4",
       "resolved": "https://registry.npmmirror.com/clean-css/-/clean-css-4.2.4.tgz",
@@ -4895,6 +4902,15 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/echarts-gl": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-1.1.0.tgz",
+      "integrity": "sha512-zbGq09XbOfqLsrMKmXhQnUn2Wvmd9eOiA0K/eyQqIqyu3GzKpmdVLZydUgIr+CHi1PEJ0Lwh3cRHA18MSbI7IQ==",
+      "dependencies": {
+        "claygl": "^1.1.0",
+        "zrender": "^4.0.2"
+      }
+    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
@@ -6286,6 +6302,11 @@
         "webpack": "^3.1.0"
       }
     },
+    "node_modules/ezuikit-js": {
+      "version": "7.6.6",
+      "resolved": "https://registry.npmjs.org/ezuikit-js/-/ezuikit-js-7.6.6.tgz",
+      "integrity": "sha512-D8wCmbf8zvSncy3dvuLvgEpUT428bq6m/I26H6ULsmyBRkmVnea5KlhdvQLvhzmjOV0PurRn31Bgzob4VnQUhA=="
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -17668,7 +17689,6 @@
       "version": "4.3.2",
       "resolved": "https://registry.npmmirror.com/zrender/-/zrender-4.3.2.tgz",
       "integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g==",
-      "dev": true,
       "license": "BSD-3-Clause"
     }
   }

+ 2 - 0
minggao/package.json

@@ -14,7 +14,9 @@
     "axios": "^0.24.0",
     "dayjs": "^1.11.7",
     "echarts": "^4.9.0",
+    "echarts-gl": "^1.1.0",
     "element-ui": "^2.15.6",
+    "ezuikit-js": "^7.6.6",
     "less": "^4.1.2",
     "lodash-es": "^4.17.21",
     "qrcodejs2": "^0.0.2",

BIN
minggao/src/assets/images/newHome/all.png


minggao/src/assets/images/newHome/Frame 802@2x.png → minggao/src/assets/images/newHome/bigBtn.png


minggao/src/assets/images/newHome/Frame 803@2x.png → minggao/src/assets/images/newHome/bigBtnHover.png


minggao/src/assets/images/newHome/Frame 331@2x.png → minggao/src/assets/images/newHome/btn.png


minggao/src/assets/images/newHome/Frame 799@2x.png → minggao/src/assets/images/newHome/btnHover.png


+ 9 - 0
minggao/src/assets/images/newHome/rectangle.svg

@@ -0,0 +1,9 @@
+<svg width="142" height="168" viewBox="0 0 142 168" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 0H142V142.15C142 173.739 0 179.38 0 142.15V0Z" fill="url(#paint0_linear_173_4948)"/>
+<defs>
+<linearGradient id="paint0_linear_173_4948" x1="71" y1="39.8252" x2="71" y2="168" gradientUnits="userSpaceOnUse">
+<stop stop-color="#00388D" stop-opacity="0"/>
+<stop offset="1" stop-color="#A7CAFF"/>
+</linearGradient>
+</defs>
+</svg>

BIN
minggao/src/assets/images/newHome/video.png


minggao/src/assets/images/newHome/Frame 805@2x.png → minggao/src/assets/images/newHome/warningDefault.png


minggao/src/assets/images/newHome/Frame 806@2x.png → minggao/src/assets/images/newHome/warningHover.png


minggao/src/assets/images/newHome/单数据3@2x.png → minggao/src/assets/images/newHome/warningTips.png


+ 3 - 3
minggao/src/page/home/newHome/components/Title.vue

@@ -3,10 +3,10 @@
  * @Autor: lin
  * @Date: 2024-04-12 13:48:21
  * @LastEditors: lin
- * @LastEditTime: 2024-04-12 14:43:07
+ * @LastEditTime: 2024-04-16 13:47:27
 -->
 <template>
-    <div class="box">
+    <div class="titlebox">
       <span class="dot"></span>
       <span class="text">{{ text }}</span>
     </div>
@@ -44,7 +44,7 @@ export default {
 </script>
 
 <style scoped lang="less">
-.box{
+.titlebox{
   display: flex;
   align-items: center;
   height: 2.6vh;

+ 470 - 0
minggao/src/page/home/newHome/components/pie3D.vue

@@ -0,0 +1,470 @@
+<template>
+  <!-- 饼图 -->
+  <div class="container">
+    <!-- 字儿上面的底座 -->
+    <div class="topText"></div>
+    <div class="title" v-if="optionData.length > 0">
+      <span>{{ optionData[currentIndex].name }}({{ optionData[currentIndex].value }}头)</span>
+      <span>{{ Number((optionData[currentIndex].value/total) * 100).toFixed(2)}}%</span>
+    </div>
+    <div class="chartsGl" :id="chartId"></div>
+    <!-- 饼图下面的底座 -->
+    <div class="buttomCharts"></div>
+  </div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+import "echarts-gl";
+
+export default {
+  props:['dataList', 'chartId'],
+  data() {
+    return {
+      timmer: null,
+      currentIndex: 0,// 当前选中的圆环索引
+      // dataList: [{
+      //   name: '444',
+      //   value: 8
+      // },
+      // {
+      //   name: '111',
+      //   value: 8
+      //   },
+      //   {
+      //   name: '333',
+      //   value: 8
+      // }],
+      //饼图数据+颜色
+      optionData: [
+      ],
+      total: 0
+    }
+  },
+  beforeDestroy() {
+    clearInterval(this.timmer);
+    this.timmer = null;
+  },
+  mounted() {
+    this.optionData = this.dataList;
+    this.total = 0;
+    this.optionData.forEach(item => {
+      this.total = this.total + item.value;
+    })
+    this.$nextTick(() => {
+      this.init();
+    });
+  },
+  methods: {
+    //初始化构建
+    init() {
+      let that = this;
+      //构建3d饼状图
+      let myChart = echarts.init(document.getElementById(this.chartId));
+      // 传入数据生成 option ; getPie3D(数据,透明的空心占比(调节中间空心范围的0就是普通饼1就很镂空))
+      this.option = this.getPie3D(this.optionData, 0.95);
+      //将配置项设置进去
+      myChart.setOption(this.option);
+      //鼠标移动上去特效效果
+      // this.bindListen(myChart);
+      if(this.optionData.length == 1) return
+      this.timmer = setInterval(() => {
+        this.currentIndex = (this.currentIndex + 1 ) == this.option.series.length ? 0 : this.currentIndex + 1;  // 循环选择下一个圆环
+        // 取消所有高亮
+        that.option.series.forEach((item) => {
+          item.parametricEquation = that.getParametricEquation(item.pieData.startRatio, item.pieData.endRatio,
+            false, false, 0.05, item.pieData.value);
+          item.pieStatus.hovered = false;
+        });
+        let startRatio = that.option.series[this.currentIndex].pieData.startRatio;
+        let endRatio = that.option.series[this.currentIndex].pieData.endRatio;
+        let k = that.option.series[this.currentIndex].pieStatus.k;
+        // 对当前点击的扇形,执行高亮操作(对 option 更新)
+        that.option.series[this.currentIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
+          false, true, k, that.option.series[this.currentIndex].pieData.value + 5);
+        that.option.series[this.currentIndex].pieStatus.hovered = true;
+        myChart.setOption(this.option);  // 更新图表配置
+      }, 2000);  // 每隔两秒切换一次选中状态
+    },
+
+    //配置构建 pieData 饼图数据 internalDiameterRatio:透明的空心占比
+    getPie3D(pieData, internalDiameterRatio) {
+      let that = this;
+      let series = [];
+      let sumValue = 0;
+      let startValue = 0;
+      let endValue = 0;
+      let legendData = [];
+      let legendBfb = [];
+      let k = 1 - internalDiameterRatio;
+      pieData.sort((a, b) => {
+        return (b.value - a.value);
+      });
+      // 为每一个饼图数据,生成一个 series-surface(参数曲面) 配置
+      for (let i = 0; i < pieData.length; i++) {
+        sumValue += pieData[i].value;
+        let seriesItem = {
+          //系统名称
+          name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
+          type: 'surface',
+          //是否为参数曲面(是)
+          parametric: true,
+          //曲面图网格线(否)上面一根一根的
+          wireframe: {
+            show: false
+          },
+          pieData: pieData[i],
+          pieStatus: {
+            selected: false,
+            hovered: false,
+            k: k
+          }
+          //设置饼图在容器中的位置(目前没发现啥用)
+          //   center: ['50%', '100%']
+        };
+
+        //曲面的颜色、不透明度等样式。
+        if (typeof pieData[i].itemStyle != 'undefined') {
+          let itemStyle = {};
+          typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
+          typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
+          seriesItem.itemStyle = itemStyle;
+        }
+        series.push(seriesItem);
+      }
+
+      // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
+      // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
+      legendData = [];
+      legendBfb = [];
+      for (let i = 0; i < series.length; i++) {
+        endValue = startValue + series[i].pieData.value;
+        series[i].pieData.startRatio = startValue / sumValue;
+        series[i].pieData.endRatio = endValue / sumValue;
+        series[i].parametricEquation = this.getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
+          false, false, k, series[i].pieData.value);
+        startValue = endValue;
+        let bfb = that.fomatFloat(series[i].pieData.value / sumValue, 4);
+        legendData.push({
+          name: series[i].name,
+          value: bfb
+        });
+        legendBfb.push({
+          name: series[i].name,
+          value: bfb
+        });
+      }
+      //(第二个参数可以设置你这个环形的高低程度)
+      let boxHeight = this.getHeight3D(series, 13);//通过传参设定3d饼/环的高度
+      // 准备待返回的配置项,把准备好的 legendData、series 传入。
+      let option = {
+        //图例组件
+        legend: {
+          show: false
+        },
+        color:['#fc8251','#5470c6','#9A60B4','#ef6567', '#f9c956','#3BA272'],
+        //移动上去提示的文本内容(我没来得及改 你们可以根据需求改)
+        tooltip: {
+          formatter: params => {
+            if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
+              let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
+                100).toFixed(2);
+              return `${params.seriesName}<br/>` +
+                `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
+                `${bfb}`;
+            }
+          }
+        },
+        //这个可以变形
+        xAxis3D: {
+          min: -1,
+          max: 1
+        },
+        yAxis3D: {
+          min: -1,
+          max: 1
+        },
+        zAxis3D: {
+          min: -1,
+          max: 1
+        },
+        //此处是修改样式的重点
+        grid3D: {
+          show: false,
+          boxHeight: boxHeight, //圆环的高度
+          //这是饼图的位置
+          top: '0%',
+          right:'0%',
+          left: '0%',
+          viewControl: { //3d效果可以放大、旋转等,请自己去查看官方配置
+            alpha: 20, //角度(这个很重要 调节角度的)
+            distance: 200,//调整视角到主体的距离,类似调整zoom(这是整体大小)
+            rotateSensitivity: 0, //设置为0无法旋转
+            zoomSensitivity: 0, //设置为0无法缩放
+            panSensitivity: 0, //设置为0无法平移
+            autoRotate: false //自动旋转
+          }
+        },
+        series: series
+      };
+      return option;
+    },
+
+    //获取3d丙图的最高扇区的高度
+    getHeight3D(series, height) {
+      series.sort((a, b) => {
+        return (b.pieData.value - a.pieData.value);
+      })
+      return height * 5 / series[0].pieData.value;
+    },
+
+    // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
+    getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
+      // 计算
+      let midRatio = (startRatio + endRatio) / 2;
+      let startRadian = startRatio * Math.PI * 2;
+      let endRadian = endRatio * Math.PI * 2;
+      let midRadian = midRatio * Math.PI * 2;
+      // 如果只有一个扇形,则不实现选中效果。
+      if (startRatio === 0 && endRatio === 1) {
+        isSelected = false;
+      }
+      // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
+      k = typeof k !== 'undefined' ? k : 1 / 3;
+      // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
+      let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
+      let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
+      // 计算高亮效果的放大比例(未高亮,则比例为 1)
+      let hoverRate = isHovered ? 1.05 : 1;
+      // 返回曲面参数方程
+      return {
+        u: {
+          min: -Math.PI,
+          max: Math.PI * 3,
+          step: Math.PI / 32
+        },
+        v: {
+          min: 0,
+          max: Math.PI * 2,
+          step: Math.PI / 20
+        },
+        x: function (u, v) {
+          if (u < startRadian) {
+            return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
+          }
+          if (u > endRadian) {
+            return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
+          }
+          return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
+        },
+        y: function (u, v) {
+          if (u < startRadian) {
+            return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
+          }
+          if (u > endRadian) {
+            return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
+          }
+          return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
+        },
+        z: function (u, v) {
+          if (u < -Math.PI * 0.5) {
+            return Math.sin(u);
+          }
+          if (u > Math.PI * 2.5) {
+            return Math.sin(u) * h * .1;
+          }
+          return Math.sin(v) > 0 ? 1 * h * .1 : -1;
+        }
+      };
+    },
+
+    //这是一个自定义计算的方法
+    fomatFloat(num, n) {
+      var f = parseFloat(num);
+      if (isNaN(f)) {
+        return false;
+      }
+      f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂
+      var s = f.toString();
+      var rs = s.indexOf('.');
+      //判定如果是整数,增加小数点再补0
+      if (rs < 0) {
+        rs = s.length;
+        s += '.';
+      }
+      while (s.length <= rs + n) {
+        s += '0';
+      }
+      return s;
+    },
+    // 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
+    bindListen(myChart) {
+      let that = this;
+      let selectedIndex = '';
+      let hoveredIndex = '';
+      // 监听点击事件,实现选中效果(单选)
+      myChart.on('click', function (params) {
+        // 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
+        let isSelected = !that.option.series[params.seriesIndex].pieStatus.selected;
+        let isHovered = that.option.series[params.seriesIndex].pieStatus.hovered;
+        let k = that.option.series[params.seriesIndex].pieStatus.k;
+        let startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
+        let endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
+        // 如果之前选中过其他扇形,将其取消选中(对 option 更新)
+        if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
+          that.option.series[selectedIndex].parametricEquation = that.getParametricEquation(that.option.series[
+            selectedIndex].pieData
+            .startRatio, that.option.series[selectedIndex].pieData.endRatio, false, false, k, that.option.series[
+              selectedIndex].pieData
+            .value);
+          that.option.series[selectedIndex].pieStatus.selected = false;
+        }
+        // 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
+        that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
+          isSelected,
+          isHovered, k, that.option.series[params.seriesIndex].pieData.value);
+        that.option.series[params.seriesIndex].pieStatus.selected = isSelected;
+        // 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
+        isSelected ? selectedIndex = params.seriesIndex : null;
+        // 使用更新后的 option,渲染图表
+        myChart.setOption(that.option);
+      });
+      // 监听 mouseover,近似实现高亮(放大)效果
+      myChart.on('mouseover', function (params) {
+        // 准备重新渲染扇形所需的参数
+        let isSelected;
+        let isHovered;
+        let startRatio;
+        let endRatio;
+        let k;
+        // 如果触发 mouseover 的扇形当前已高亮,则不做操作
+        if (hoveredIndex === params.seriesIndex) {
+          return;
+          // 否则进行高亮及必要的取消高亮操作
+        } else {
+          // 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
+          if (hoveredIndex !== '') {
+            // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
+            isSelected = that.option.series[hoveredIndex].pieStatus.selected;
+            isHovered = false;
+            startRatio = that.option.series[hoveredIndex].pieData.startRatio;
+            endRatio = that.option.series[hoveredIndex].pieData.endRatio;
+            k = that.option.series[hoveredIndex].pieStatus.k;
+            // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
+            that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
+              isSelected,
+              isHovered, k, that.option.series[hoveredIndex].pieData.value);
+            that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
+            // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
+            hoveredIndex = '';
+          }
+          // 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
+          if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
+            // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
+            isSelected = that.option.series[params.seriesIndex].pieStatus.selected;
+            isHovered = true;
+            startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
+            endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
+            k = that.option.series[params.seriesIndex].pieStatus.k;
+            // 对当前点击的扇形,执行高亮操作(对 option 更新)
+            that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
+              isSelected, isHovered, k, that.option.series[params.seriesIndex].pieData.value + 5);
+            that.option.series[params.seriesIndex].pieStatus.hovered = isHovered;
+            // 记录上次高亮的扇形对应的系列号 seriesIndex
+            hoveredIndex = params.seriesIndex;
+          }
+          // 使用更新后的 option,渲染图表
+          myChart.setOption(that.option);
+        }
+      });
+      // 修正取消高亮失败的 bug
+      myChart.on('globalout', function () {
+        // 准备重新渲染扇形所需的参数
+        let isSelected;
+        let isHovered;
+        let startRatio;
+        let endRatio;
+        let k;
+        if (hoveredIndex !== '') {
+          // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
+          isSelected = that.option.series[hoveredIndex].pieStatus.selected;
+          isHovered = false;
+          k = that.option.series[hoveredIndex].pieStatus.k;
+          startRatio = that.option.series[hoveredIndex].pieData.startRatio;
+          endRatio = that.option.series[hoveredIndex].pieData.endRatio;
+          // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
+          that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
+            isSelected,
+            isHovered, k, that.option.series[hoveredIndex].pieData.value);
+          that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
+          // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
+          hoveredIndex = '';
+        }
+        // 使用更新后的 option,渲染图表
+        myChart.setOption(that.option);
+      });
+    }
+
+  }
+};
+</script>
+
+<style lang="less" scoped>
+//饼图(外面的容器)
+.container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  .title {
+    position: absolute;
+    top: 3vh;
+    left: 0;
+    width: 100%;
+    font-size: 1.4rem;
+    text-align: center;
+    color: #fff;
+    z-index: 3;
+    span{
+      display: block;
+      color: #ffffff;
+      text-shadow: 0 0 3.59px #FFF;
+      font-size: 1.4rem;
+    }
+    span:nth-child(2) {
+      font-size: 2.5rem;
+    }
+  }
+}
+
+//饼图的大小
+.chartsGl {
+  height: 100%;
+  width: 100%;
+  z-index: 1;
+}
+// 数字底座
+.topText {
+  position: absolute;
+  top: 0;
+  left: 10%;
+  mix-blend-mode: screen;
+  background: center center url(../../../../assets/images/newHome/rectangle.svg) no-repeat;
+  background-size: auto 100%;
+  width: 80%;
+  height: 10vh;
+  z-index: 2;
+}
+//饼图底座(我也想给你们底座图片 可是我不知道咋给)
+.buttomCharts {
+  position: absolute;
+  bottom: 1.5vh;
+  left: 10%;
+  mix-blend-mode: screen;
+  background: center center url(../../../../assets/images/newHome/video.png) no-repeat;
+  background-size: cover;
+  width: 80%;
+  height: 10vh;
+  z-index: 0;
+}
+</style>

+ 82 - 0
minggao/src/page/home/newHome/components/scrollInfo.vue

@@ -0,0 +1,82 @@
+<!--
+ * @Description:
+ * @Autor: lin
+ * @Date: 2024-04-18 11:18:19
+ * @LastEditors: lin
+ * @LastEditTime: 2024-04-18 16:28:38
+-->
+<template>
+  <div class="scrollInfoContent">
+    <div :class="`scrollItem ${index == 0 ? 'animate__animated animate__slideOutUp heightOut' : ''}`" v-for="(info, index) in newData" :key="`time${info.addtime_format}`">
+      <template>
+        <div>{{ info.pest_name }}</div>
+        <div class="timeBox">{{ info.addtime_format }}</div>
+        <div>{{ info.count }}</div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ['data'],
+  data() {
+    return {
+      newData: [],
+      timmer: null
+    };
+  },
+  computed: {
+
+  },
+  created() {
+
+  },
+  beforeDestroy() {
+    clearInterval(this.timmer)
+  },
+  mounted() {
+    this.newData = JSON.parse(JSON.stringify(this.data))
+    this.startScroll();
+  },
+  methods: {
+    startScroll() {
+      this.timmer = setInterval(() => {
+        this.newData.push(this.newData.shift()); // 将第一个元素移动到列表末尾
+      }, 2000); // 设置滚动间隔
+    }
+  },
+  components: {
+
+  },
+};
+</script>
+
+<style scoped lang="less">
+.scrollInfoContent {
+  height: calc(100% - 3.3vh);
+  overflow: hidden;
+}
+.scrollItem {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  color: #ffffffcc;
+  font-size: 1.2rem;
+  height: 3.3vh;
+  border-bottom: 1px solid #ffffff4d;
+  overflow: hidden;
+
+  div {
+    width: 25%;
+    text-align: center;
+  }
+  .timeBox{
+    width: 40%;
+  }
+}
+.heightOut{
+  height: 0;
+  transition: height 1s ease; /* 定义高度过渡动画,持续时间 1 秒 */
+}
+</style>

+ 658 - 19
minggao/src/page/home/newHome/deviceHome.vue

@@ -3,45 +3,684 @@
  * @Autor: lin
  * @Date: 2024-04-09 14:26:43
  * @LastEditors: lin
- * @LastEditTime: 2024-04-09 14:26:58
+ * @LastEditTime: 2024-04-18 16:55:05
 -->
 <template>
-    <div>
-        测报灯首页
-    </div>
+  <div class="bigBg">
+    <el-carousel indicator-position="outside" class="deviceBox" :autoplay="false" :interval="10000">
+      <el-carousel-item v-for="(item, index) in deviceList" :key="item.id">
+        <div class="flexBox topBox">
+          <div class="rowFlex">
+            <div class="card">
+              <Title text="设备信息"></Title>
+              <div class="deviceInfo">
+                <div class="leftInfo">
+                  <img src="../../../assets/images/newHome/id.png" />
+                  <div>设备ID</div>
+                </div>
+                <div class="rightInfo">{{ item.device_id }}</div>
+              </div>
+              <div class="deviceInfo">
+                <div class="leftInfo">
+                  <img src="../../../assets/images/newHome/name.png" />
+                  <div>设备名称</div>
+                </div>
+                <div class="rightInfo">{{ item.device_name }}</div>
+              </div>
+              <div class="deviceInfo">
+                <div class="leftInfo">
+                  <img src="../../../assets/images/newHome/point.png" />
+                  <div>设备定位</div>
+                </div>
+                <div class="rightInfo">{{ item.address }}</div>
+              </div>
+              <div class="deviceInfo">
+                <div class="leftInfo">
+                  <img src="../../../assets/images/newHome/time.png" />
+                  <div>最新上报时间</div>
+                </div>
+                <div class="rightInfo">{{ item.uptime_format }}</div>
+              </div>
+            </div>
+            <div class="card">
+              <Title text="设备参数"></Title>
+              <div class="flexBox">
+                <div class="itemInfo">
+                  <span class="status">{{ item.device_status ? '在线' : '离线' }}</span>
+                  <span>在线状态</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">≤5w</span>
+                  <span>待机功率</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">雨控</span>
+                  <span>自动触发</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">1200w</span>
+                  <span>超清像素</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">开启</span>
+                  <span>光诱状态</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">3</span>
+                  <span>灯管数量</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">365nm</span>
+                  <span>主波长</span>
+                </div>
+                <div class="itemInfo">
+                  <span class="status">开启</span>
+                  <span>性诱状态</span>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="bigCard">
+            <div class="titleBox">
+              <Title text="实时监控"></Title>
+              <div class="nameContent">{{ item.jk_device_name }}</div>
+            </div>
+            <div class="charBox" :id="`playBox${item.id}`">
+            </div>
+            <!-- <video class="charBox" :id="`play${item.id}`" :src="item.jk_addr.hlsHd" muted autoplay  poster='' controls playsInline  webkit-playsinline></video> -->
+          </div>
+          <div class="rowFlex">
+            <div class="card">
+              <Title text="设备图片"></Title>
+              <el-carousel indicator-position="none" class="charBox" :autoplay="false" :interval="1000">
+                <el-carousel-item v-for="(img) in pestImgList[index]" :key="img">
+                  <el-image :src="`https://www.yhswjc.com${img}`" fit="contain" :preview-src-list="pestImgList[index]">
+                  </el-image>
+                </el-carousel-item>
+              </el-carousel>
+            </div>
+            <div class="card">
+              <Title text="实时数据"></Title>
+              <div class="charBox">
+                <div class="scrollItem scrollHeader">
+                  <div>害虫名称</div>
+                  <div class="timeBox">上报时间</div>
+                  <div>数量</div>
+                </div>
+                <PestInfo v-if="pestNowList[index] && pestNowList[index].length > 0" :data="pestNowList[index]">
+                </PestInfo>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="flexBox bottomBox">
+          <div class="card">
+            <Title text="环境温湿度"></Title>
+            <div class="charBox" :id="`temChar${item.id}`"></div>
+          </div>
+          <div class="card">
+            <Title text="虫情类别"></Title>
+            <PestType class="charBox" v-if="pestTypeList[index] && pestTypeList[index].length > 0"
+              :dataList="pestTypeList[index]" :chartId="`type${item.id}`"></PestType>
+          </div>
+          <div class="card">
+            <Title text="害虫总数量">
+            </Title>
+            <div class="charBox" :id="`countChar${item.id}`"></div>
+          </div>
+          <div class="card">
+            <div class="titleBox">
+              <Title text="虫害折线图"></Title>
+              <div class="rightBox">
+                <el-select size="mini">
+                </el-select>
+                <div class="rightType">
+                  <div class="active" @click="changePestType(index, 'date', `pestDateChar${item.id}`)">日</div>
+                  <div @click="changePestType(index, 'month', `pestDateChar${item.id}`)">月</div>
+                  <div @click="changePestType(index, 'year', `pestDateChar${item.id}`)">年</div>
+                </div>
+              </div>
+            </div>
+            <div class="charBox" :id="`pestDateChar${item.id}`"></div>
+          </div>
+        </div>
+      </el-carousel-item>
+    </el-carousel>
+  </div>
 </template>
 
 <script>
+import * as echarts from 'echarts';
+import Title from './components/Title.vue';
+import PestType from "./components/pie3D.vue"; // 害虫种类3d环状图
+import PestInfo from './components/scrollInfo.vue';
 export default {
-    props: {
+  props: {
 
-    },
-    data() {
-        return {
+  },
+  data() {
+    return {
+      deviceList: [],
+      pestTypeList: [], // 害虫类别数组
+      pestLineDate: [], // 害虫周 月 年 折线图
+      pestNowList: [], // 实时数据
+      pestImgList: [], //设备图片
+      videoList: [], //监控列表 跳出页面要停止
+    };
+  },
+  computed: {
 
-        };
-    },
-    computed: {
+  },
+  created() {
 
+  },
+  mounted() {
+    this.getDeviceList();
+  },
+  beforeDestroy() {
+    this.videoList.forEach(item => {
+      item.stop()
+    })
+  },
+  methods: {
+    // 获取有测报灯列表
+    getDeviceList(date) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.cbd_screen.device_screen_info',
+        data: this.qs.stringify({
+          date
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        // console.log(res.data.data);
+        this.deviceList = res.data.data;
+        this.deviceList.length = 1;
+        this.pestTypeList = [];
+        this.$nextTick(() => {
+          this.deviceList.forEach((item, index) => {
+            this.getTypeList(item.id);
+            this.getPhotoList(item.id);
+            this.getNowList(item.id);
+            this.getLineDate(item.id);
+            item.jk_addr = eval('(' + item.jk_addr + ')');
+            // let playHtml = `<video id="play${item.id}" autoplay  muted poster='' controls playsInline  webkit-playsinline src="${item.jk_addr.hlsHd}"  style="width:100%; height:100%;"></video>`;
+            // document.getElementById(
+            //   'playBox' + item.id
+            // ).innerHTML = playHtml;
+            // // // 视频
+            // this.$nextTick(() => {
+            //   let playerObj = new EZUIKit.EZUIPlayer({
+            //     id: `play${item.id}`
+            //   });
+            //   console.log(playerObj, 'playerObj')
+            //   this.videoList.push(playerObj)
+            // })
+            let char = echarts.init(document.getElementById(`temChar${item.id}`));
+            this.setLineOption(char, ['温度(℃)', '湿度(%)'], item.ath.addtime, [item.ath.tem, item.ath.hum], [['#90ff0366', '#8fff0010'], ['#0066ff59', '#0066ff00']], ['#19E4A6', '#1588F2'])
+          })
+          // console.log(this.pestTypeList, 'pestTypeList');
+        })
+      })
     },
-    created() {
+    // 折线图带渐变配置
+    setLineOption(char, name, xData, yData, color, lineColor) {
+      let series = [];
+      yData.forEach((item, index) => {
+        let pre = {
+          data: item,
+          type: 'line',
+          smooth: true,
+          name: name[index],
+          areaStyle: {
+            normal: {
+              color: {
+                type: 'linear',
+                x: 0,
+                y: 0,
+                x2: 0,
+                y2: 1,
+                colorStops: [{
+                  offset: 0,
+                  color: color[index][0] // 0% 处的颜色
+                }, {
+                  offset: 0.8,
+                  color: color[index][1] // 100% 处的颜色
+                }],
+                global: false // 缺省为 false
+              },
+              shadowColor: "rgba(0, 0, 0, 0.1)"
+            }
+          }
+        };
+        series.push(pre)
+      })
+      let optionsPestLine = {
+        // 设置全局文本样式
+        textStyle: {
+          fontSize: 14, // 设置字体大小为14px
+        },
+        grid: {
+          top: '5%',
+          left: '0',
+          bottom: '5%',
+          right: '0%',
+          containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis'
+        },
+        color: lineColor,
+        xAxis: {
+          type: 'category',
+          axisLine: {
+            lineStyle: {
+              color: '#ffffff'  // 设置 x 轴轴线颜色为白色
+            }
+          },
+          axisLabel: {
+            show: false
+          },
+          splitLine: {
+            show: false  // 不显示 x 轴分隔线
+          },
+          data: xData
+        },
+        yAxis: {
+          type: 'value',
+          nameTextStyle: {
+            color: '#fff'
+          },
+          axisLine: {
+            show: false  // 不显示 y 轴轴线
+          },
+          axisLabel: {
+            color: '#ffffff'  // 设置 y 轴标签字体颜色为白色
+          },
+          splitLine: {
+            lineStyle: {
+              type: 'dotted',  // 设置分隔线为点线
+              color: '#ffffff88'
+            }
+          }
+        },
+        series: series
+      }; // 有害生物发生趋势 折线图
 
+      char.setOption(optionsPestLine)
     },
-    mounted() {
+    // 柱状图配置
+    setBarOption(char, xData, yData) {
+      let optionsPestLine = {
+        // 设置全局文本样式
+        textStyle: {
+          fontSize: 14, // 设置字体大小为14px
+        },
+        grid: {
+          top: '5%',
+          left: '0',
+          bottom: '5%',
+          right: '0%',
+          containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis'
+        },
+        color: ['#24D3BE'],
+        xAxis: {
+          type: 'category',
+          axisLine: {
+            lineStyle: {
+              color: '#ffffff'  // 设置 x 轴轴线颜色为白色
+            }
+          },
+          axisLabel: {
+            show: true
+          },
+          splitLine: {
+            show: false  // 不显示 x 轴分隔线
+          },
+          data: xData
+        },
+        yAxis: {
+          type: 'value',
+          nameTextStyle: {
+            color: '#fff'
+          },
+          axisLine: {
+            show: false  // 不显示 y 轴轴线
+          },
+          axisLabel: {
+            color: '#ffffff'  // 设置 y 轴标签字体颜色为白色
+          },
+          splitLine: {
+            lineStyle: {
+              type: 'dotted',  // 设置分隔线为点线
+              color: '#ffffff88'
+            }
+          }
+        },
+        series: [
+          {
+            data: yData,
+            type: 'bar'
+          },
+        ]
+      }; // 有害生物发生趋势 折线图
 
+      char.setOption(optionsPestLine)
     },
-    watch: {
-
+    // 获取虫害分类数据
+    getTypeList(id) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.cbd_screen.cbd_pest_info',
+        data: this.qs.stringify({
+          id
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        let newArray = []
+        res.data.data.name.forEach((item, index) => {
+          let preObj = {
+            name: item,
+            num: res.data.data.count[index],
+            value: res.data.data.count[index]
+          }
+          newArray.push(preObj)
+        });
+        console.log(id)
+        let char = echarts.init(document.getElementById(`countChar${id}`));
+        this.setBarOption(char, res.data.data.name, res.data.data.count);
+        this.pestTypeList.push(newArray)
+      })
     },
-    methods: {
-
+    // 获取虫害图片数据
+    getPhotoList(id) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.cbd_screen.recent_photo_count',
+        data: this.qs.stringify({
+          id
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        this.pestImgList.push(res.data.data)
+      })
     },
-    components: {
-
+    // 获取虫害实时数据
+    getNowList(id) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.cbd_screen.recent_pest_count',
+        data: this.qs.stringify({
+          id
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        this.pestNowList.push(res.data.data)
+      })
+    },
+    getLineDate(id) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.cbd_screen.cbd_pest_count',
+        data: this.qs.stringify({
+          id
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        this.pestLineDate.push(res.data.data)
+      })
     },
+  },
+  components: {
+    Title,
+    PestType,
+    PestInfo
+  },
 };
 </script>
 
 <style scoped lang="less">
+.bigBg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  background: #02112F;
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  padding: 11.7vh 5.52vw;
+  /deep/ .el-select,
+  /deep/ .el-date-editor {
+    width: 8.8vw;
+    font-size: 14px;
+
+    .el-input {
+      width: 100%;
+      font-size: 16px;
+    }
+
+    .el-input__inner {
+      background: #ffffff1a;
+      color: #ffffffcc;
+      border: none;
+    }
+  }
+}
+
+.titleBox {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+
+  .nameContent {
+    color: #ffffffcc;
+    font-size: 2rem;
+  }
+  .rightBox{
+    display: flex;
+    align-items: center;
+    max-width: 60%;
+    .rightType{
+      display: flex;
+      color: #ffffff80;
+      font-size: 1.6rem;
+      margin-left: .5rem;
+      div{
+        width: 2.4rem;
+        text-align: center;
+        cursor: pointer;
+      }
+      .active{
+        color: #ffffff;
+        text-shadow: 0 0 2.5px #FFF;
+      }
+    }
+  }
+}
+
+.card {
+  padding: 1.5vh 1.2vw;
+  box-sizing: border-box;
+  width: 21.2vw;
+  height: 23vh;
+  background: url('../../../assets/images/newHome/smallChar.png') center center no-repeat;
+  background-size: 100% 100%;
+
+  .charBox {
+    width: 100%;
+    height: 17.3vh;
+    overflow: hidden;
+
+    /deep/ .el-carousel__container {
+      width: 100% !important;
+      height: 100% !important;
+    }
+
+    /deep/ .el-carousel__arrow--left {
+      left: 16px !important;
+    }
+
+    /deep/ .el-carousel__arrow--right {
+      right: 16px !important;
+    }
+
+    .el-image {
+      width: 100%;
+      height: 100%;
+
+      /deep/ img {
+        height: 100%;
+      }
+    }
+
+    .scrollInfoContent {
+      height: calc(100% - 3.3vh);
+      overflow: hidden;
+    }
+
+    .scrollItem {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      color: #ffffffcc;
+      font-size: 1.2rem;
+      height: 3.3vh;
+      border-bottom: 1px solid #ffffff4d;
+
+      div {
+        width: 25%;
+        text-align: center;
+      }
+      .timeBox{
+        width: 40%;
+      }
+    }
+
+    .scrollHeader {
+      color: #fff;
+    }
+  }
+}
+
+.bigCard {
+  padding: 1.5vh 1.2vw;
+  box-sizing: border-box;
+  width: 44vw;
+  height: 48vh;
+  background: url('../../../assets/images/newHome/smallChar.png') center center no-repeat;
+  background-size: 100% 100%;
+
+  .charBox {
+    width: 100%;
+    height: 38.7vh;
+    overflow: hidden;
+  }
+}
+
+.deviceBox {
+  position: absolute;
+  width: 100vw;
+  top: 11.7vh;
+  left: 0;
+  z-index: 200;
+  height: 76.6vh;
+
+  /deep/ .el-carousel__container {
+    margin: 0 auto;
+    width: 88.96vw;
+    height: calc(100% - 26px);
+
+    .el-carousel__arrow {
+      border: 1px solid #fff;
+    }
+
+    .el-carousel__arrow--left {
+      left: -36px;
+    }
+
+    .el-carousel__arrow--right {
+      right: -36px;
+    }
+  }
+
+  .flexBox {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+  }
+
+  .rowFlex {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+  }
+
+  .topBox {
+    height: 48vh;
+
+    .itemInfo {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      margin-top: 1vh;
+      width: 24%;
+      height: 7vh;
+      font-size: 1.4rem;
+      color: #ffffff99;
+      background: linear-gradient(180deg, #163e8c1f 0%, #9daaccba 100%);
+
+      .status {
+        color: #ffffffe6;
+        font-size: 2rem;
+        font-weight: 600;
+        margin-bottom: .4rem;
+      }
+    }
+  }
+
+  .bottomBox {
+    margin-top: 1.5vh;
+  }
+
+  .deviceInfo {
+    display: flex;
+    align-items: center;
+    height: 3.7vh;
+    color: #ffffffcc;
+    font-size: 1.4rem;
+    border-bottom: 1px solid #ffffff4d;
+
+    .leftInfo {
+      display: flex;
+      width: 50%;
+      height: 100%;
+      align-items: center;
 
+      img {
+        width: 2rem;
+        height: 2rem;
+        margin-right: 1rem;
+      }
+    }
+  }
+}
 </style>

+ 67 - 5
minggao/src/page/home/newHome/index.vue

@@ -3,11 +3,20 @@
  * @Autor: lin
  * @Date: 2024-04-09 14:29:42
  * @LastEditors: lin
- * @LastEditTime: 2024-04-12 13:56:38
+ * @LastEditTime: 2024-04-17 08:48:38
 -->
 <template>
   <div class="bigBox">
     <div class="top">智网监测中心</div>
+    <!-- 左边按钮组 -->
+    <div class="topLeftBtn">
+      <router-link to="/newHome/home">
+        <div :class="`newHomeBtn ${$route.path == '/newHome/home' ? 'newHomeBtnClick' : '' }`">首页</div>
+      </router-link>
+      <router-link to="/newHome/device">
+        <div :class="`newHomeBtn newHomeBigBtn ${$route.path == '/newHome/device' ? 'newHomeBigBtnClick' : '' }`">智能测报系统</div>
+      </router-link>
+    </div>
     <div class="left"></div>
     <div class="right"></div>
     <div class="content">
@@ -22,8 +31,6 @@ const setBaseFontSize = () => {
   const baseFontSize = (window.innerWidth / 1920) * 10; // 根据屏幕宽度计算基准字体大小
   document.documentElement.style.fontSize = `${baseFontSize}px`; // 设置根元素字体大小
 };
-setBaseFontSize(); // 初始化基准字体大小
-window.addEventListener("resize", setBaseFontSize); // 监听窗口大小变化,重新设置基准字体大小
 export default {
   props: {
 
@@ -40,7 +47,9 @@ export default {
 
   },
   mounted() {
-
+    setBaseFontSize(); // 初始化基准字体大小
+    window.addEventListener("resize", setBaseFontSize); // 监听窗口大小变化,重新设置基准字体大小
+    console.log(this.$route)
   },
   beforeDestroy() {
     document.documentElement.removeAttribute("style");
@@ -57,20 +66,72 @@ export default {
   },
 };
 </script>
+<style lang="less">
+.newHomeBtn {
+  display: inline-block;
+  cursor: pointer;
+  width: 6.4vw;
+  height: 3.52vh;
+  color: #ffffff80;
+  font-size: 1.6rem;
+  line-height: 2.8vh;
+  text-align: center;
+  background: url(../../../assets/images/newHome/btn.png) center center no-repeat;
+  background-size: 100% 100%;
+
+  &:hover {
+    color: #FFF;
+    background: url(../../../assets/images/newHome/btnHover.png) center center no-repeat;
+    background-size: 100% 100%;
+  }
+}
 
+.newHomeBtnClick {
+  color: #FFF;
+  background: url(../../../assets/images/newHome/btnHover.png) center center no-repeat;
+  background-size: 100% 100%;
+}
+
+.newHomeBigBtn {
+  width: 8.125vw;
+  background: url(../../../assets/images/newHome/bigBtn.png) center center no-repeat;
+  background-size: 100% 100%;
+
+  &:hover {
+    color: #FFF;
+    background: url(../../../assets/images/newHome/bigBtnHover.png) center center no-repeat;
+    background-size: 100% 100%;
+  }
+}
+
+.newHomeBigBtnClick {
+  color: #FFF;
+  background: url(../../../assets/images/newHome/bigBtnHover.png) center center no-repeat;
+  background-size: 100% 100%;
+}
+</style>
 <style scoped lang="less">
 .bigBox {
   position: relative;
   overflow: hidden;
   width: 100vw;
   height: 100vh;
-  .content{
+
+  .topLeftBtn {
+    position: absolute;
+    top: 2.5vh;
+    left: 2.2vw;
+    z-index: 190;
+  }
+
+  .content {
     position: absolute;
     top: 0;
     left: 0;
     width: 100vw;
     height: 100vh;
   }
+
   .top {
     position: absolute;
     color: #ffffff;
@@ -102,6 +163,7 @@ export default {
     background-size: 100% 100%;
     z-index: 3;
   }
+
   .right {
     position: absolute;
     top: 0;

+ 335 - 44
minggao/src/page/home/newHome/newHome.vue

@@ -3,40 +3,81 @@
  * @Autor: lin
  * @Date: 2024-04-09 14:26:07
  * @LastEditors: lin
- * @LastEditTime: 2024-04-15 18:43:55
+ * @LastEditTime: 2024-04-17 15:36:56
 -->
 <template>
   <div class="box">
     <div class="mapBox" id="newHome"></div>
     <!-- 左侧统计图 -->
-    <transition leave-active-class='animate__animated animate__bounceOutLeft'
-      enter-active-class="animate__animated animate__bounceInLeft">
-      <div class="smallChar deviceInfo" v-if="defaultInfo">
-        <div class="charBox">
-          <div class="charTitle">
-            <Title text="设备信息"></Title>
-          </div>
-          <div class="charContent">
-            <div class="charList" v-for="item in deviceInfo" :key="item.device_type_id">
-              <div class="leftInfo">
-                <img :src="`${item.icon}`" alt="">
-                <div>{{ item.type_name }}</div>
-              </div>
-              <div class="leftInfo">
-                <span>{{ item.device_count }}台</span>
-                <img class="markerIcon" :src="`${markerObj[item.device_type_id].length == 0 ? eyeClose : eyeOpen}`"
-                  alt="" @click="setMarker(item.devices_info, item.device_type_id)" />
+    <transition leave-active-class='animate__animated animate__fast animate__fadeOutLeft'
+      enter-active-class="animate__animated animate__fast animate__fadeInLeft">
+      <div v-show="!showBanner">
+        <div class="smallChar deviceInfo">
+          <div class="charBox">
+            <div class="charTitle">
+              <Title text="设备信息"></Title>
+            </div>
+            <div class="charContent">
+              <div class="charList" v-for="item in deviceInfo" :key="item.device_type_id">
+                <div class="leftInfo">
+                  <img :src="`${item.icon}`" alt="">
+                  <div>{{ item.type_name }}</div>
+                </div>
+                <div class="leftInfo">
+                  <span>{{ item.device_count }}台</span>
+                  <img class="markerIcon" :src="`${markerObj[item.device_type_id].length == 0 ? eyeClose : eyeOpen}`"
+                    alt="" @click="setMarker(item.devices_info, item.device_type_id)" />
+                </div>
               </div>
             </div>
           </div>
         </div>
+        <div class="smallChar deviceInfo bottomBox">
+          <div class="charBox">
+            <div class="charTitle">
+              <Title text="有害生物监测"></Title>
+              <el-date-picker :pickerOptions="pickerOptions" :clearable="false" size="mini" v-model="watchYear"
+                type="month" placeholder="选择年月" format="yyyy-MM" value-format="yyyy-MM"
+                @change="getWatchInfo(watchYear)">
+              </el-date-picker>
+            </div>
+            <div class="charContent">
+              <el-carousel>
+                <el-carousel-item v-for="item in watchInfo" :key="item.category" indicator-position="outside">
+                  <div class="small">{{ item.warning }}</div>
+                  <div class="charInfo">
+                    <div class="infoTitle">{{ item.category }}</div>
+                    <div class="detailInfo">
+                      <div>害虫总数</div>
+                      <div>{{ item.sum }}</div>
+                    </div>
+                    <div class="detailInfo" v-if="item.category != '外来有害杂草'">
+                      <div>害虫种类</div>
+                      <div>{{ item.count }}</div>
+                    </div>
+                  </div>
+                </el-carousel-item>
+              </el-carousel>
+            </div>
+          </div>
+        </div>
+        <div class="tipsBox">
+          <div>
+            <span>77</span>
+            <span>本月预警数量</span>
+          </div>
+          <div>
+            <span>48664</span>
+            <span>全年预警数量</span>
+          </div>
+        </div>
       </div>
     </transition>
     <!-- 右侧统计图 -->
-    <transition leave-active-class='animate__animated animate__bounceOutRight'
-      enter-active-class="animate__animated animate__bounceInRight">
-      <div>
-        <div class="smallChar lineBox" v-if="defaultInfo">
+    <transition leave-active-class='animate__animated animate__fast animate__fadeOutRight'
+      enter-active-class="animate__animated animate__fast animate__fadeInRight">
+      <div v-show="!showBanner">
+        <div class="smallChar lineBox">
           <div class="charBox">
             <div class="charTitle">
               <Title class="smallTitle" text="有害生物发生趋势"></Title>
@@ -52,13 +93,12 @@
             </div>
           </div>
         </div>
-        <div class="smallChar lineBox bottomBox" v-if="defaultInfo">
+        <div class="smallChar lineBox bottomBox">
           <div class="charBox">
             <div class="charTitle">
               <Title class="smallTitle" text="任务统计"></Title>
               <el-date-picker :pickerOptions="pickerOptions" :clearable="false" size="mini" v-model="taskYear"
-                type="year" placeholder="选择年" format="yyyy" value-format="yyyy"
-                @change="getTaskInfo(taskYear)">
+                type="year" placeholder="选择年" format="yyyy" value-format="yyyy" @change="getTaskInfo(taskYear)">
               </el-date-picker>
             </div>
             <div class="charContent">
@@ -66,11 +106,21 @@
             </div>
           </div>
         </div>
+        <div class="tipsBox rightTips">
+          <div>
+            <span>77</span>
+            <span>今日监督任务</span>
+          </div>
+          <div>
+            <span>48664</span>
+            <span>今日监测任务</span>
+          </div>
+        </div>
       </div>
     </transition>
     <!-- 点击地图圆圈的详情 -->
-    <transition leave-active-class='animate__animated animate__bounceOutUp'
-      enter-active-class="animate__animated animate__bounceInDown">
+    <transition leave-active-class='animate__animated animate__fast animate__fadeOutUp'
+      enter-active-class="animate__fast animate__animated animate__fadeInDown">
       <div v-if="groupDialog" class="dialog">
         <div class="dialog_content">
           <!-- 关闭按钮 -->
@@ -135,12 +185,37 @@
               <div class="rightInfo">{{ deviceDialogInfo.uptime_format }}</div>
             </div>
           </div>
+          <div class="contentInfo" v-else-if="checkType == 'warning'">
+            <div class="title">告警详情</div>
+            <div class="warningInfo">
+              <div class="infoContent">
+                {{ warningList.latest_content }}
+                <div class="marginBtn">
+                  <router-link to="/index/alermRecord" target="_blank">
+                    <div class="newHomeBtn newHomeBigBtn">
+                      查看历史记录
+                    </div>
+                  </router-link>
+                </div>
+              </div>
+              <div class="infoDesc">
+                <div>
+                  <span class="num">{{ warningList.month_count }}</span>
+                  <span class="name">本月预警</span>
+                </div>
+                <div>
+                  <span class="num">{{ warningList.year_count }}</span>
+                  <span class="name">本年预警</span>
+                </div>
+              </div>
+            </div>
+          </div>
         </div>
       </div>
     </transition>
     <!-- 点击林木虫害信息右侧放大图标 -->
-    <transition leave-active-class='animate__animated animate__bounceOutDown'
-      enter-active-class="animate__animated animate__bounceInUp">
+    <transition leave-active-class='animate__animated animate__fast animate__fadeOutDown'
+      enter-active-class="animate__animated animate__fast animate__fadeInUp">
       <div v-if="showBanner" class="dialog bigBanner">
         <div class="dialog_content">
           <!-- 关闭按钮 -->
@@ -150,7 +225,8 @@
             <div class="barContent">
               <div class="searchBox">
                 <el-date-picker :pickerOptions="pickerOptions" :clearable="false" size="mini" v-model="bannerYear"
-                  type="year" placeholder="选择年" format="yyyy" value-format="yyyy" @change="getBannerInfo(bannerYear, bannerBarCategory)">
+                  type="year" placeholder="选择年" format="yyyy" value-format="yyyy"
+                  @change="getBannerInfo(bannerYear, bannerBarCategory)">
                 </el-date-picker>
                 <el-select class="selectThem" v-model="bannerBarCategory" size="mini" placeholder="请选择分类"
                   @change="getBannerInfo(bannerYear, bannerBarCategory)">
@@ -187,6 +263,12 @@
         </div>
       </div>
     </transition>
+    <!-- 头部告警 -->
+    <div class="warningBox" v-if="warningList.latest_content" @click="groupDialog = true; checkType = 'warning'">
+      <div class="content">
+        <div class="item">{{ warningList.latest_content }}</div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -215,7 +297,6 @@ export default {
       marker8: require('../../../assets/images/newHome/8.png'),
       marker9: require('../../../assets/images/newHome/9.png'),
       marker10: require('../../../assets/images/newHome/10.png'),
-      defaultInfo: true,
       colorObject: {
         0: '#3ACD9C',
         1: '#FF5951',
@@ -268,6 +349,8 @@ export default {
       deviceDialogInfo: {}, //设备弹框内容
       groupInfo: {},  // 圈圈弹框内容
       typeList: [],
+      watchYear: '', //有害生物监测统计年份
+      watchInfo: [], // 有害生物监测信息详情
       rightLineCategory: '',// 有害生物发生趋势 下拉框
       pestLineObj: {}, // 有害生物发生趋势 类型-》数据
       pestChart: null, // 有害生物发生趋势 折线图
@@ -284,6 +367,11 @@ export default {
       bannerLoading: true,
       bannerData: [],
       taskYear: new Date().getFullYear() + '', // 任务统计年份
+      warningList: {
+        latest_content: "",
+        month_count: 0,
+        year_count: 0
+      }, // 告警详情
     };
   },
   computed: {
@@ -303,7 +391,9 @@ export default {
     this.initMap();
     this.getDeviceInfo();
     this.getPestLineInfo();
-    this.getTaskInfo(this.taskYear)
+    this.getTaskInfo(this.taskYear);
+    this.getWatchInfo();
+    this.getWarningList();
   },
   watch: {
 
@@ -328,6 +418,21 @@ export default {
         })
       }
     },
+    // 获取告警列表
+    getWarningList() {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.screen.alarm_detail',
+        data: this.qs.stringify({})
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        this.warningList = res.data.data;
+        console.log(this.warningList)
+      })
+    },
     // 获取设备信息
     getDeviceInfo() {
       this.$axios({
@@ -339,7 +444,6 @@ export default {
           this.$message.error('网络连接出错或服务报错,请刷新页面重试');
           return
         }
-        this.defaultInfo = true;
         this.deviceInfo = res.data.data;
         this.deviceInfo.forEach(item => {
           if (item.device_type_id == '2') {
@@ -353,6 +457,23 @@ export default {
         console.log(this.markerObj);
       })
     },
+    // 获取有害生物监测数据
+    getWatchInfo(date) {
+      this.$axios({
+        method: 'POST',
+        url: '/api/api_gateway?method=data_report.screen.pest_check',
+        data: this.qs.stringify({
+          date
+        })
+      }).then(res => {
+        if (!res.data.data) {
+          this.$message.error('网络连接出错或服务报错,请刷新页面重试');
+          return
+        }
+        console.log(res.data.data);
+        this.watchInfo = res.data.data;
+      })
+    },
     // 获取任务统计图
     getTaskInfo(year) {
       this.$axios({
@@ -366,7 +487,7 @@ export default {
           this.$message.error('网络连接出错或服务报错,请刷新页面重试');
           return
         }
-        console.log(res.data.data);
+        // console.log(res.data.data);
         let charData = res.data.data;
         // let pestLineObj = {};
         // 害虫个数
@@ -397,7 +518,7 @@ export default {
           this.$message.error('网络连接出错或服务报错,请刷新页面重试');
           return
         }
-        console.log(res.data.data);
+        // console.log(res.data.data);
         this.bannerData = res.data.data.table;
         let charData = res.data.data.lines[0];
         // let pestLineObj = {};
@@ -415,6 +536,10 @@ export default {
         xDataNew.push(item + '月')
       })
       let optionsPestLine = {
+        // 设置全局文本样式
+        textStyle: {
+          fontSize: 14, // 设置字体大小为14px
+        },
         grid: {
           top: '50',
           left: '2%',
@@ -498,6 +623,10 @@ export default {
         xDataNew.push(item + '月')
       })
       let optionsPestLine = {
+        // 设置全局文本样式
+        textStyle: {
+          fontSize: 14, // 设置字体大小为14px
+        },
         grid: {
           left: '0%',
           bottom: '0%',
@@ -590,13 +719,12 @@ export default {
           this.$message.error('网络连接出错或服务报错,请刷新页面重试');
           return
         }
-        this.defaultInfo = true;
         let pestLineObj = {};
         res.data.data.forEach(pest => {
           pestLineObj[pest.category] = pest.data
         })
         this.$set(this, 'pestLineObj', pestLineObj)
-        console.log(this.pestLineObj);
+        // console.log(this.pestLineObj);
         this.pestChart = echarts.init(document.getElementById('chartDetailId'));
         this.setLineOption(this.pestChart, pestLineObj[this.rightLineCategory].month, pestLineObj[this.rightLineCategory].count)
       })
@@ -699,7 +827,7 @@ export default {
       circle.on('click', (e) => {
         let data = e.target._opts.extData;
         this.getInfoByGroupId(data);
-        console.log(data, '当前点击的圆圈是');
+        // console.log(data, '当前点击的圆圈是');
       })
       this.overlayList.push(circle);
       // 添加水波纹效果的圆点
@@ -731,7 +859,7 @@ export default {
       // 水波纹点击查看组织详情
       rippleCircle.on('click', (e) => {
         let data = e.target._opts.extData;
-        console.log(data, '当前点击的水波纹是');
+        // console.log(data, '当前点击的水波纹是');
         this.getInfoByGroupId(data);
       })
       this.map.add(rippleCircle);
@@ -859,10 +987,12 @@ export default {
 
   /deep/ .el-select,
   /deep/ .el-date-editor {
-    width: 16rem;
+    width: 8.8vw;
+    font-size: 14px;
 
     .el-input {
       width: 100%;
+      font-size: 16px;
     }
 
     .el-input__inner {
@@ -963,14 +1093,61 @@ export default {
           }
 
         }
+
+        .el-carousel {
+          height: 19.8vh;
+          color: #ffffffcc;
+          font-size: 1.4rem;
+
+          /deep/ .el-carousel__container {
+            height: 100%;
+            padding: 0 36px;
+            box-sizing: border-box;
+          }
+
+          .small {
+            line-height: 2rem;
+          }
+
+          .charInfo {
+            width: 90%;
+            margin: 0 auto;
+            display: flex;
+            justify-content: space-around;
+            align-items: center;
+            height: calc(100% - 2rem);
+
+            .infoTitle {
+              font-size: 1.6rem;
+              writing-mode: vertical-rl;
+              color: #aaf0d2;
+            }
+
+            .detailInfo {
+              width: 40%;
+              height: 16vh;
+              box-sizing: border-box;
+              text-align: center;
+              background: url(../../../assets/images/newHome/all.png) top center no-repeat;
+              background-size: cover;
+
+              :first-child {
+                margin-top: 3rem;
+              }
+
+              :last-child {
+                color: #fff;
+                font-size: 4rem;
+                font-weight: 400;
+                text-shadow: 0px 0px .4rem #FFF;
+              }
+            }
+          }
+        }
       }
     }
   }
 
-  .lineBox {
-    right: 6.2vw;
-    left: auto;
-  }
 
   .bottomBox {
     top: 46.5vh;
@@ -1072,6 +1249,31 @@ export default {
             }
           }
         }
+
+        .warningInfo {
+          display: flex;
+          justify-content: space-between;
+          color: #ffffff;
+          margin-top: 1.85vh;
+          height: 11.39vh;
+          font-size: 1.4rem;
+
+          .infoContent {
+            width: 18.38vw;
+
+            .marginBtn {
+              margin-top: 2.3vh;
+            }
+          }
+
+          .infoDesc {
+            width: 13.5vw;
+
+            div {
+              width: 49%;
+            }
+          }
+        }
       }
     }
 
@@ -1197,5 +1399,94 @@ export default {
       }
     }
   }
+
+  .tipsBox {
+    position: absolute;
+    left: 6.2vw;
+    bottom: 8.9vh;
+    z-index: 201;
+    display: flex;
+
+    div {
+      width: 9vw;
+      height: 12vh;
+      background: url('../../../assets/images/newHome/warningTips.png') bottom center no-repeat;
+      background-size: 100% 100%;
+      text-align: center;
+      box-sizing: border-box;
+      padding-top: 3vh;
+
+      span {
+        display: inline-block;
+        width: 100%;
+        color: #ffffffbf;
+        font-size: 1.4rem;
+      }
+
+      :first-child {
+        color: #ffffffbf;
+        font-size: 4rem;
+        text-shadow: 0 0 .4rem #FFF;
+      }
+    }
+  }
+
+  .lineBox,
+  .rightTips {
+    right: 6.2vw;
+    left: auto;
+  }
+
+  .warningBox {
+    position: absolute;
+    top: 8.4vh;
+    left: 50%;
+    z-index: 190;
+    transform: translateX(-50%);
+    width: 18.8vw;
+    height: 3.7vh;
+    cursor: pointer;
+    color: #ffffff;
+    font-size: 1.4rem;
+    white-space: nowrap;
+    /* 禁止文本换行 */
+    overflow: hidden;
+    /* 隐藏溢出部分 */
+    background: url('../../../assets/images/newHome/warningDefault.png') bottom center no-repeat;
+    background-size: 100% 100%;
+
+    &:hover {
+      background: url('../../../assets/images/newHome/warningHover.png') bottom center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .content {
+      position: relative;
+      width: 80%;
+      margin: 0 auto;
+      overflow: hidden;
+    }
+
+    .item {
+      display: inline-block;
+      /* 内联显示项目 */
+      white-space: nowrap;
+      /* 禁止项目换行 */
+      animation: scroll 20s linear infinite;
+      /* 使用名为 "scroll" 的动画,持续 10 秒,线性运动,无限循环 */
+    }
+
+    @keyframes scroll {
+      0% {
+        transform: translateX(0);
+        /* 从初始位置开始 */
+      }
+
+      100% {
+        transform: translateX(-100%);
+        /* 向左平移整个容器宽度 */
+      }
+    }
+  }
 }
 </style>

+ 19 - 1
minggao/yarn.lock

@@ -1711,6 +1711,11 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
+claygl@^1.1.0:
+  version "1.3.0"
+  resolved "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz"
+  integrity sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==
+
 clean-css@4.2.x:
   version "4.2.4"
   resolved "https://registry.npmmirror.com/clean-css/-/clean-css-4.2.4.tgz"
@@ -2688,6 +2693,14 @@ echarts-extension-amap@^1.9.2:
   resolved "https://registry.npmmirror.com/echarts-extension-amap/-/echarts-extension-amap-1.11.0.tgz"
   integrity sha512-H93Nx8DGbhczkz+whD+5jcrzcEzyEvkaabdeSzzaG9xy9e756sRU7lwLT4JWNdklRWqG+QuQnnxhDRdipeKy/A==
 
+echarts-gl@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/echarts-gl/-/echarts-gl-1.1.0.tgz"
+  integrity sha512-zbGq09XbOfqLsrMKmXhQnUn2Wvmd9eOiA0K/eyQqIqyu3GzKpmdVLZydUgIr+CHi1PEJ0Lwh3cRHA18MSbI7IQ==
+  dependencies:
+    claygl "^1.1.0"
+    zrender "^4.0.2"
+
 echarts@^4.7.0:
   version "4.9.0"
   resolved "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz"
@@ -3255,6 +3268,11 @@ extract-text-webpack-plugin@^3.0.0:
     schema-utils "^0.3.0"
     webpack-sources "^1.0.1"
 
+ezuikit-js@^7.6.6:
+  version "7.6.6"
+  resolved "https://registry.npmjs.org/ezuikit-js/-/ezuikit-js-7.6.6.tgz"
+  integrity sha512-D8wCmbf8zvSncy3dvuLvgEpUT428bq6m/I26H6ULsmyBRkmVnea5KlhdvQLvhzmjOV0PurRn31Bgzob4VnQUhA==
+
 fast-deep-equal@^1.0.0:
   version "1.1.0"
   resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz"
@@ -8512,7 +8530,7 @@ zego-express-logger@1.2.3:
   resolved "https://registry.npmmirror.com/zego-express-logger/-/zego-express-logger-1.2.3.tgz"
   integrity sha512-6ZLi51nqYS17jLM0tmE5UYVmuRVyGTi/ibz4ViuInAsDY0DpQtW5YhRg5MwVueuy86q+Jako+B/uyAen9vDAWg==
 
-zrender@4.3.2:
+zrender@^4.0.2, zrender@4.3.2:
   version "4.3.2"
   resolved "https://registry.npmmirror.com/zrender/-/zrender-4.3.2.tgz"
   integrity sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g==