فهرست منبع

master: Fixed 左右两次实现

gitboyzcf 5 ماه پیش
والد
کامیت
905ed9cf2e

+ 2 - 0
package.json

@@ -35,6 +35,8 @@
     "vue-echarts": "^7.0.3",
     "vue-i18n": "^10.0.4",
     "vue-router": "^4.4.5",
+    "vue3-count-to": "^1.1.2",
+    "vue3-seamless-scroll": "^2.0.1",
     "vuedraggable": "^2.24.3",
     "xgplayer": "^3.0.20"
   },

+ 31 - 0
pnpm-lock.yaml

@@ -74,6 +74,12 @@ dependencies:
   vue-router:
     specifier: ^4.4.5
     version: 4.4.5(vue@3.5.12)
+  vue3-count-to:
+    specifier: ^1.1.2
+    version: 1.1.2(vue@3.5.12)
+  vue3-seamless-scroll:
+    specifier: ^2.0.1
+    version: 2.0.1
   vuedraggable:
     specifier: ^2.24.3
     version: 2.24.3
@@ -4617,6 +4623,11 @@ packages:
   /text-table@0.2.0:
     resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
 
+  /throttle-debounce@5.0.0:
+    resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
+    engines: {node: '>=12.22'}
+    dev: false
+
   /through@2.3.8:
     resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
     dev: true
@@ -5002,6 +5013,10 @@ packages:
       vue: 3.5.12(typescript@5.6.3)
     dev: false
 
+  /vue-count-to@1.0.13:
+    resolution: {integrity: sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ==}
+    dev: false
+
   /vue-demi@0.13.11(vue@3.5.12):
     resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
     engines: {node: '>=12'}
@@ -5095,6 +5110,22 @@ packages:
       vue: 3.5.12(typescript@5.6.3)
     dev: false
 
+  /vue3-count-to@1.1.2(vue@3.5.12):
+    resolution: {integrity: sha512-C5AvlcGfyM4XvFqPDkni94rqGd5K/+RB+B4xv/1NQx3RrdC+GvXPFzeXW5hWL/jh8ehWLm4LITyK0eMKf4iJbg==}
+    peerDependencies:
+      vue: '>= 3 < 4'
+    dependencies:
+      core-js: 3.39.0
+      vue: 3.5.12(typescript@5.6.3)
+      vue-count-to: 1.0.13
+    dev: false
+
+  /vue3-seamless-scroll@2.0.1:
+    resolution: {integrity: sha512-mI3BaDU3pjcPUhVSw3/xNKdfPBDABTi/OdZaZqKysx4cSdNfGRbVvGNDzzptBbJ5S7imv5T55l6x/SqgnxKreg==}
+    dependencies:
+      throttle-debounce: 5.0.0
+    dev: false
+
   /vue@3.5.12(typescript@5.6.3):
     resolution: {integrity: sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==}
     peerDependencies:

BIN
src/assets/images/box-bg.png


+ 5 - 2
src/components/Box.vue

@@ -1,7 +1,9 @@
 <template>
   <div class="flex flex-col">
     <div class="box-title w-full h-28px"
-      ><span class="color-#f0f0f0 font-bold block w-90px text-center">{{ title }}</span></div
+      ><span class="color-#f0f0f0 font-bold block w-90px text-center" :style="{ width: wHeader }">{{
+        title
+      }}</span></div
     >
     <div class="box-content p-15px bg-#031e559c" :style="styleContent">
       <slot></slot>
@@ -15,6 +17,7 @@
       type: String,
       default: '标题'
     },
+    wHeader: String,
     styleContent: String
   })
 </script>
@@ -22,6 +25,6 @@
 <style lang="scss" scoped>
   .box-title {
     background: url('@/assets/images/box-h-bg.png') no-repeat center;
-    background-size: 100%;
+    background-size: 100% 100%;
   }
 </style>

+ 7 - 0
src/components/Countto.vue

@@ -0,0 +1,7 @@
+<template>
+  <count-to v-bind="$attrs" :duration="2000"></count-to>
+</template>
+
+<script setup>
+  import { CountTo } from 'vue3-count-to'
+</script>

+ 3 - 6
src/components/ECharts/ECharts.vue

@@ -5,7 +5,7 @@
   import * as echarts from 'echarts'
   import 'echarts-liquidfill'
 
-  let myChart = ref(null)
+  let myChart = shallowRef(null)
 
   const props = defineProps({
     // 区分chart
@@ -67,14 +67,11 @@
       text: '',
       color: '#409eff',
       textColor: '#000',
-      maskColor: 'rgba(255, 255, 255, .95)',
+      maskColor: 'rgba(56, 155, 255, .45)',
       zlevel: 0,
       lineWidth: 2
     })
-    if (!props.loading) {
-      myChart.value.hideLoading()
-      myChart.value.setOption(props.fullOptions.options, true)
-    }
+
     //自适应不同屏幕时改变图表尺寸
     window.addEventListener('resize', cancalDebounce)
   })

+ 791 - 79
src/components/ECharts/optionsConfig.js

@@ -1,84 +1,6 @@
 import * as echarts from 'echarts'
 export const chartOptions = {
-  setOption1(data) {
-    const option = {
-      legend: {
-        data: ['Allocated Budget', 'Actual Spending'],
-        textStyle: {
-          color: '#fff',
-          fontSize: 14
-        }
-      },
-
-      radar: {
-        shape: 'circle', // 外环的形状(圆形/多边形)
-        splitNumber: 5, // 外环圈数
-        indicator: [
-          // 每项指标的最大值设置
-          // { name: 'Sales', max: 6500 },
-          // { name: 'Administration', max: 16000 },
-          // { name: 'Information Technology', max: 30000 },
-          // { name: 'Customer Support', max: 38000 },
-          // { name: 'Development', max: 52000 },
-          // { name: 'Marketing', max: 25000 }
-          { name: 'Sales' },
-          { name: 'Administration' },
-          { name: 'Information Technology' },
-          { name: 'Customer Support' },
-          { name: 'Development' },
-          { name: 'Marketing' }
-        ],
-        splitLine: {
-          // 外环分割线样式
-          lineStyle: {
-            color: '#45BCE4',
-            type: 'dashed'
-          }
-        },
-        splitArea: {
-          show: false
-        },
-        axisLine: {
-          // 坐标轴线样式设置
-          lineStyle: {
-            color: '#45BCE4'
-          }
-        }
-      },
-      series: [
-        {
-          name: 'Budget vs spending',
-          type: 'radar',
-          data: [
-            {
-              value: [4200, 3000, 20000, 35000, 50000, 18000],
-              name: 'Allocated Budget',
-              itemStyle: {
-                // 多边形线颜色
-                color: '#47EB99'
-              },
-              areaStyle: {
-                opacity: 0.5
-              }
-            },
-            {
-              value: [5000, 14000, 28000, 26000, 42000, 21000],
-              name: 'Actual Spending',
-              itemStyle: {
-                color: '#47EAEB'
-              },
-              areaStyle: {
-                opacity: 0.5
-              }
-            }
-          ]
-        }
-      ]
-    }
-    return option
-  },
-
-  setOption2(data) {
+  setOption2() {
     function Pie() {
       let dataArr = []
       for (var i = 0; i < 150; i++) {
@@ -263,5 +185,795 @@ export const chartOptions = {
       ]
     }
     return option
+  },
+  setSbxxOption(data) {
+    const option = {
+      grid: {
+        top: '0%',
+        left: '0',
+        right: '0',
+        bottom: '-5%'
+      },
+      tooltip: {
+        trigger: 'item',
+        backgroundColor: '#031e559c',
+        formatter: '{b}: {c}',
+        textStyle: {
+          color: '#fff'
+        }
+      },
+      legend: {
+        data: ['在线', '离线', '故障', '身份认证失败', '证书过期', '视频源头断开'],
+        bottom: '0%',
+        x: 'center',
+        icon: 'rect',
+        itemWidth: 10,
+        itemHeight: 10,
+        textStyle: {
+          color: '#fff'
+        }
+      },
+      series: [
+        {
+          type: 'pie',
+          selectedMode: 'single',
+          center: ['50%', '46%'],
+          radius: [0, '40%'],
+          label: {
+            position: 'inner',
+            fontSize: 14,
+            color: '#fff'
+          },
+          labelLine: {
+            show: false
+          },
+          data: [
+            { value: 1, name: '身份认证失败' },
+            { value: 1, name: '证书过期' },
+            { value: 2, name: '视频源头断开' }
+          ]
+        },
+        {
+          type: 'pie',
+          radius: ['60%', '80%'],
+          center: ['50%', '46%'],
+          labelLine: {
+            show: false,
+            length: 20
+          },
+          label: {
+            color: '#fff',
+            position: 'inner',
+            rich: {
+              a: {
+                color: '#6E7079',
+                lineHeight: 22,
+                align: 'center'
+              },
+              hr: {
+                borderColor: '#8C8D8E',
+                width: '100%',
+                borderWidth: 1,
+                height: 0
+              },
+              b: {
+                color: '#4C5058',
+                fontSize: 14,
+                fontWeight: 'bold',
+                lineHeight: 33
+              },
+              per: {
+                color: '#fff',
+                backgroundColor: '#4C5058',
+                padding: [3, 4],
+                borderRadius: 4
+              }
+            }
+          },
+          data: [
+            { value: 70, name: '在线' },
+            { value: 10, name: '离线' },
+            { value: 2, name: '故障' }
+          ]
+        }
+      ]
+    }
+    return option
+  },
+  setYhqkOption(data, type = 0) {
+    const color = ['#33B5FF ', '#22E59C']
+    const legendData = ['登录次数', '登录人数']
+    const series = []
+    const xPoint = []
+    switch (type) {
+      case 0:
+        for (let i = 0; i < 10; i++) {
+          let currentTime = new Date().getTime() - 3600 * 1000 * i
+          let time = new Date(currentTime).toLocaleTimeString()
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 10; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+      case 1:
+        for (let i = 0; i < 7; i++) {
+          // 修改循环次数为7
+          let currentTime = new Date().getTime() - 24 * 3600 * 1000 * i // 修改为每天减少一天的时间
+          let time = new Date(currentTime).toLocaleDateString() // 使用 toLocaleDateString 获取日期部分
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 7; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+      case 2:
+        for (let i = 0; i < 30; i++) {
+          // 修改循环次数为30
+          let currentTime = new Date().getTime() - 24 * 3600 * 1000 * i // 修改为每天减少一天的时间
+          let time = new Date(currentTime).toLocaleDateString() // 使用 toLocaleDateString 获取日期部分
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 30; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+    }
+
+    const option = {
+      grid: {
+        top: '15%',
+        bottom: '15%',
+        left: '10%',
+        right: '5%'
+      },
+      xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        axisLabel: {
+          // X轴刻度标签
+          color: 'rgba(255, 255, 255, 0.6)',
+          fontSize: 12
+        },
+        axisLine: {
+          // X轴线
+          show: true,
+          lineStyle: {
+            color: 'rgba(255, 255, 255, .4)'
+          }
+        },
+        splitLine: {
+          // 网格线
+          show: true,
+          lineStyle: {
+            type: 'dashed',
+            width: 1,
+            color: 'rgba(255, 255, 255, .2)'
+          }
+        },
+        axisTick: {
+          show: false
+        },
+        data: xPoint
+      },
+      yAxis: {
+        type: 'value',
+        axisLabel: {
+          color: 'rgba(255, 255, 255, .6)',
+          fontSize: 12
+        },
+        splitLine: {
+          // 网格线
+          show: true,
+          lineStyle: {
+            type: 'dashed',
+            width: 1,
+            color: 'rgba(255, 255, 255, .2)'
+          }
+        },
+        axisLine: {
+          show: false
+        },
+        axisTick: {
+          show: false
+        }
+      },
+      legend: {
+        show: false,
+        data: legendData,
+        left: 'center',
+        top: 0,
+        itemHeight: 8,
+        textStyle: {
+          fontSize: 14,
+          color: '#fff'
+        },
+        itemStyle: {
+          borderWidth: 6,
+          borderColor: 'rgba(51, 181, 255, .2)'
+        }
+      },
+      tooltip: {
+        trigger: 'axis',
+        backgroundColor: 'rgba(33, 85, 154, .6)',
+        borderWidth: 1,
+        borderColor: {
+          type: 'linear',
+          x: 0,
+          y: 0,
+          x2: 0,
+          y2: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgba(85, 149, 233, .6)' // 0% 处的颜色
+            },
+            {
+              offset: 1,
+              color: 'rgba(85, 149, 233, 0)' // 100% 处的颜色
+            }
+          ],
+          global: false // 缺省为 false
+        },
+        padding: 8,
+        textStyle: {
+          color: '#fff'
+        },
+        axisPointer: {
+          lineStyle: {
+            type: 'dashed',
+            color: 'rgba(255, 255, 255, .6)'
+          }
+        },
+        extraCssText: 'box-shadow: 2px 2px 16px 1px rgba(0, 39, 102, 0.16)',
+        formatter: function (params) {
+          let content = `<div style='font-size: 14px; color: #fff;'>${params[0].name}</div>`
+          if (Array.isArray(params)) {
+            for (let i = 0; i < params.length; i++) {
+              content += `
+                     <div style='display: flex; align-items: center; padding: 4px; background: #21559A; margin-top: 4px; color: #fff;'>
+                       <div style='width: 10px; height: 10px; background: ${params[i].color}; margin-right: 8px;'></div>
+                       <div style='font-size: 12px; margin-right: 32px;'>${params[i].seriesName}</div>
+                       <div style='font-size: 14px;'>${params[i].value}</div>
+                     </div>
+                   `
+            }
+          }
+          return content
+        }
+      },
+      series
+    }
+    return option
+  },
+  setBjzxOption(data, type = 0) {
+    const color = ['#379ED7', '#F0BC1E']
+    const legendData = ['已处理', '未处理']
+    const series = []
+    const xPoint = []
+    switch (type) {
+      case 0:
+        for (let i = 0; i < 10; i++) {
+          let currentTime = new Date().getTime() - 3600 * 1000 * i
+          let time = new Date(currentTime).toLocaleTimeString()
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 10; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+      case 1:
+        for (let i = 0; i < 7; i++) {
+          // 修改循环次数为7
+          let currentTime = new Date().getTime() - 24 * 3600 * 1000 * i // 修改为每天减少一天的时间
+          let time = new Date(currentTime).toLocaleDateString() // 使用 toLocaleDateString 获取日期部分
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 7; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+      case 2:
+        for (let i = 0; i < 30; i++) {
+          // 修改循环次数为30
+          let currentTime = new Date().getTime() - 24 * 3600 * 1000 * i // 修改为每天减少一天的时间
+          let time = new Date(currentTime).toLocaleDateString() // 使用 toLocaleDateString 获取日期部分
+          xPoint.push(time)
+        }
+        for (let i = 0; i < legendData.length; i++) {
+          const curData = []
+          for (let j = 0; j < 30; j++) {
+            curData.push(Math.floor(Math.random() * 100))
+          }
+
+          let obj = {
+            name: legendData[i],
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 6,
+            itemStyle: {
+              color: color[i % color.length],
+              borderWidth: 6,
+              borderColor: 'rgba(51, 181, 255, .2)'
+            },
+            lineStyle: {
+              normal: {
+                width: 2,
+                color: color[i % color.length] // 线条颜色
+              }
+            },
+            label: {
+              show: false,
+              color: 'rgba(255,255,255, 0.6)'
+            },
+            data: curData
+          }
+          series.push(obj)
+        }
+        break
+    }
+
+    const option = {
+      grid: {
+        top: '15%',
+        bottom: '15%',
+        left: '10%',
+        right: '5%'
+      },
+      xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        axisLabel: {
+          // X轴刻度标签
+          color: 'rgba(255, 255, 255, 0.6)',
+          fontSize: 12
+        },
+        axisLine: {
+          // X轴线
+          show: true,
+          lineStyle: {
+            color: 'rgba(255, 255, 255, .4)'
+          }
+        },
+        splitLine: {
+          // 网格线
+          show: true,
+          lineStyle: {
+            type: 'dashed',
+            width: 1,
+            color: 'rgba(255, 255, 255, .2)'
+          }
+        },
+        axisTick: {
+          show: false
+        },
+        data: xPoint
+      },
+      yAxis: {
+        type: 'value',
+        axisLabel: {
+          color: 'rgba(255, 255, 255, .6)',
+          fontSize: 12
+        },
+        splitLine: {
+          // 网格线
+          show: true,
+          lineStyle: {
+            type: 'dashed',
+            width: 1,
+            color: 'rgba(255, 255, 255, .2)'
+          }
+        },
+        axisLine: {
+          show: false
+        },
+        axisTick: {
+          show: false
+        }
+      },
+      legend: {
+        show: false,
+        data: legendData,
+        left: 'center',
+        top: 0,
+        itemHeight: 8,
+        textStyle: {
+          fontSize: 14,
+          color: '#fff'
+        },
+        itemStyle: {
+          borderWidth: 6,
+          borderColor: 'rgba(51, 181, 255, .2)'
+        }
+      },
+      tooltip: {
+        trigger: 'axis',
+        backgroundColor: 'rgba(33, 85, 154, .6)',
+        borderWidth: 1,
+        borderColor: {
+          type: 'linear',
+          x: 0,
+          y: 0,
+          x2: 0,
+          y2: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgba(85, 149, 233, .6)' // 0% 处的颜色
+            },
+            {
+              offset: 1,
+              color: 'rgba(85, 149, 233, 0)' // 100% 处的颜色
+            }
+          ],
+          global: false // 缺省为 false
+        },
+        padding: 8,
+        textStyle: {
+          color: '#fff'
+        },
+        axisPointer: {
+          lineStyle: {
+            type: 'dashed',
+            color: 'rgba(255, 255, 255, .6)'
+          }
+        },
+        extraCssText: 'box-shadow: 2px 2px 16px 1px rgba(0, 39, 102, 0.16)',
+        formatter: function (params) {
+          let content = `<div style='font-size: 14px; color: #fff;'>${params[0].name}</div>`
+          if (Array.isArray(params)) {
+            for (let i = 0; i < params.length; i++) {
+              content += `
+                     <div style='display: flex; align-items: center; padding: 4px; background: #21559A; margin-top: 4px; color: #fff;'>
+                       <div style='width: 10px; height: 10px; background: ${params[i].color}; margin-right: 8px;'></div>
+                       <div style='font-size: 12px; margin-right: 32px;'>${params[i].seriesName}</div>
+                       <div style='font-size: 14px;'>${params[i].value}</div>
+                     </div>
+                   `
+            }
+          }
+          return content
+        }
+      },
+      series
+    }
+    return option
+  },
+  setBjlxOption(data) {
+    var bgImg =
+      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbYAAAARCAYAAACxZ4mSAAAAAXNSR0IArs4c6QAABANJREFUeF7t3O9rG3UcB/D35y5dmjjbLq5JLJsynOgqA2c721lW7HCgCCLI9gf4QHFbQrOBj/dYWFOaqugD/wCHIIIoFKWsiza46kCWFeZQ6ixJusW0m+mP3N1HkiWhe3aPZN69A3lw3/t87+79+jz4EDgi8MFn/w0N7irhgOHA9EFcRqQABSjgawHxQ/rBy/qM7aD8y6is+CEvM1KAAhTws4DnB9vQvMYAdOWG5YafG83sFKAABfwi4OnBduRzDTlP4Om7S1jMn5QtvzSVOSlAAQr4WcC7g01Vhi/h2UoNpcVX5I6fm8zsFKAABfwk4NnBduiy9hmC0MKI3PRTQ5mVAhSggN8FPDnYBq5oWKvY32UjPzsmlt+bzPwUoAAF/CTgvcGmKoez6K/V8NfVMan4qZnMSgEKUIACgOcG29C87hFFYP6I/MEGU4ACFKCA/wQ8Ndj6r+nO0Cr2LdxCHifF9l87mZgCFKAABR4YbHsmNGQZSEIRqtOoYsNcw9RyBHbcRgLAzub6ll1D5vZNbEQPIGEAXY11gbWpmK6kpIITasZGcFoUkfo5R+AELHy0fA534mm8B0G0ya92DZ+svC+FaFrfMYC+xroB3bLwWfmc/OmqTarG4A/or5hY+m1Y1lztYREFKEABCnhO4IHB1juhr5qC4VZKB5gppSQbS+sxAUa3pZ8tpGS2d1JHTcWxdr0gWxqXmfpxbFKHRPHatj0/FVLy9e60vhAA3th2j6ullHwZy+hBsfBWu15wrTAuF92KH8rqk4YDXTgqS273sI4CFKAABbwn0B5sXRMa6RScNnD//xQVqBRXMR2JINxhIyFAR/OX191SBZnYI+hAAEkBgk2WamEVUzgvGzivnfFuJAGEm9fahIWp4j+oxXuQgOLR5nqtZiJTLqMa68YZAXoa9wDszSCmV0/J327IB2a0W8LYe+Ul5CHiuNnDGgpQgAIU8KZAe7DFJ/UEFM+1YmoAXxQT8ms0rW8awPOtdQv46nZKfo6n9XUAh9v1gm+K45KrH0cn9bihGGmds018t5KUuXhaXwZQ/zY+ClwqpuT7aFpHDOB4u14xv3JWvnVFrmoO/Ij+9U38nh+Te672sIgCFKAABTwr0BhskQu6d0cAb8O5/5akAyyXUvJp7wcaNzvwLlpvTypKhRQ+7ruAx6wAThkKozGgBOViFh/iotg9ae0JCs7U30xsXmutdB2Z3U+h0wwiIYodTc17BROZvjJMuwtJEXQ21gXrBQdTOCvrbtRfzOk+qaKWG5NbbupZQwEKUIAC3hb4X78VeXBOd4UVj+eO4jpE1NutYjoKUIACFHAjIENzOuCm8GGssRSKMBYXBqX6MD4fn4kCFKAABf57gX8BSq0+Tbg1W4gAAAAASUVORK5CYII='
+
+    var datalist = [
+      {
+        name: '物品出界报警',
+        value: 189
+      },
+      {
+        name: '围界入侵报警',
+        value: 168
+      },
+      {
+        name: '检测未穿戴工服',
+        value: 45
+      },
+      {
+        name: '烟雾报警',
+        value: 9
+      },
+      {
+        name: '火焰报警',
+        value: 2
+      }
+    ]
+
+    const option = {
+      //你的代码
+      grid: {
+        left: '15%',
+        right: '5%',
+        bottom: '10%',
+        top: '5%'
+      },
+      xAxis: {
+        show: false,
+        type: 'value'
+      },
+      yAxis: [
+        {
+          type: 'category',
+          inverse: true,
+          axisLabel: {
+            color: '#fff',
+            fontSize: 14,
+            margin: 10,
+            formatter: (name, index) => {
+              const id = index + 1
+              return `{count|TOP}{num${index}|0${id}}`
+            },
+            rich: {
+              count: {
+                width: 32,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#ffffff',
+                fontSize: 16
+              },
+              num0: {
+                width: 22,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#f43339',
+                fontSize: 16
+              },
+              num1: {
+                width: 22,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#ffff64',
+                fontSize: 16
+              },
+              num2: {
+                width: 22,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#3b9bf8',
+                fontSize: 16
+              },
+              num3: {
+                width: 22,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#0ec289',
+                fontSize: 16
+              },
+              num4: {
+                width: 22,
+                height: 22,
+                fontStyle: 'italic',
+                fontWeight: 'bold',
+                align: 'center',
+                color: '#0ec289',
+                fontSize: 16
+              }
+            }
+          },
+          splitLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisLine: {
+            show: false
+          },
+          data: datalist.map((el) => {
+            return el.name
+          })
+        },
+        {
+          type: 'category',
+          inverse: true,
+          axisTick: 'none',
+          axisLine: 'none',
+          show: true,
+          axisLabel: {
+            verticalAlign: 'top',
+            textStyle: {
+              color: '#ffffff',
+              fontSize: '14',
+              padding: [-5, 0, 0, -20]
+            }
+          },
+          data: datalist.map((el) => {
+            return el.value
+          })
+        }
+      ],
+      series: [
+        {
+          name: '值',
+          type: 'bar',
+          itemStyle: {
+            normal: {
+              // barBorderRadius: 30,
+              color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
+                {
+                  offset: 0,
+                  color: 'rgba(24, 144, 254, 1)'
+                },
+                {
+                  offset: 0.5,
+                  color: '#16599b'
+                },
+                {
+                  offset: 1,
+                  color: '#0f4581'
+                }
+              ]),
+              barBorderRadius: 2
+            }
+          },
+          barWidth: 8,
+          data: datalist,
+          label: {
+            show: true,
+            // offset: [30, -16],
+            padding: [10, 0, 10, 10],
+            verticalAlign: 'top',
+            color: '#75d8ff',
+            fontWeight: 500,
+            position: 'left',
+            fontSize: 16,
+            align: 'left',
+            formatter: function (params) {
+              return params.data.name
+            }
+          }
+        },
+        {
+          type: 'pictorialBar',
+          barWidth: '18',
+          z: 99,
+          silent: true,
+          barCategoryGap: 20,
+          symbol: 'image://' + bgImg,
+          symbolOffset: [-45, 8, 50, 0],
+          symbolClip: false,
+          symbolBoundingData: 310,
+          symbolPosition: 'center',
+          symbolSize: ['100%', '100%'],
+          label: {
+            show: false
+          },
+          data: [300, 300, 300, 300, 300]
+        }
+      ]
+    }
+    return option
   }
 }

+ 15 - 0
src/components/ScrollBox.vue

@@ -0,0 +1,15 @@
+<template>
+  <vue3-seamless-scroll
+    :hover="true"
+    :wheel="true"
+    :step="0.3"
+    v-bind="$attrs"
+    class="scroll overflow-hidden h-200px"
+  >
+    <slot></slot>
+  </vue3-seamless-scroll>
+</template>
+
+<script setup>
+  import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
+</script>

+ 1 - 1
src/layout/LayoutMain.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="layout-main flex-1 h-0 relative">
+  <div class="layout-main flex-1 h-0 relative color-#f0f0f0">
     <div class="layout-main-left absolute left-15px top-70px">
       <slot name="left"></slot>
     </div>

+ 22 - 9
src/views/home/home.vue

@@ -1,23 +1,36 @@
 <template>
   <Layout class="home">
     <template #left>
-      <div class="w-359px h-80% flex flex-col gap-15px">
-        <Box title="概况">
-          <LeftTopBox />
+      <div class="w-453px flex flex-col gap-15px">
+        <Box title="概况" wHeader="60px">
+          <TopBox />
+        </Box>
+        <Box title="设备信息">
+          <MiddleBox />
+        </Box>
+        <Box title="用户情况">
+          <BottomBox />
         </Box>
-        <Box title="设备信息"> 设备信息 </Box>
-        <Box title="用户情况"> 测试 </Box>
       </div>
     </template>
     <template #right>
-      <div class="w-359px h-80%">123</div>
+      <div class="w-453px flex flex-col gap-15px">
+        <Box title="报警中心">
+          <RightTopBox />
+        </Box>
+        <Box title="报警类型TOP5" wHeader="124px">
+          <RightBottomBox />
+        </Box>
+      </div>
     </template>
   </Layout>
 </template>
 
 <script setup>
   import Layout from '@/layout/index.vue'
-  import LeftTopBox from './leftbox/leftTopBox.vue'
+  import TopBox from './leftBox/topBox.vue'
+  import MiddleBox from './leftBox/middleBox.vue'
+  import BottomBox from './leftbox/bottomBox.vue'
+  import RightTopBox from './rightBox/topBox.vue'
+  import RightBottomBox from './rightBox/bottomBox.vue'
 </script>
-
-<style lang="scss" scoped></style>

+ 64 - 0
src/views/home/leftbox/bottomBox.vue

@@ -0,0 +1,64 @@
+<template>
+  <div class="bottom-box">
+    <div class="flex justify-between relative">
+      <div>
+        <span>用户总数 </span>
+        <Countto class="text-18px color-#389bff font-bold" :endVal="data.yhzs" />
+      </div>
+
+      <ul class="flex gap-15px">
+        <li
+          :class="[
+            'w-50px cursor-pointer text-center b-solid b-1px b-color-#389bff hover:b-color-#FAC858',
+            i === selectedI ? 'b-color-#FAC858' : ''
+          ]"
+          v-for="(item, i) in options"
+          :key="item.code"
+          @click="dayClick(i)"
+        >
+          <span class="text-12px">{{ item.name }}</span>
+        </li>
+      </ul>
+    </div>
+    <ECharts
+      id="yhqk-echarts"
+      width="100%"
+      height="120px"
+      :loading="loading"
+      :fullOptions="fullOptions"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { chartOptions } from '@/components/ECharts/optionsConfig'
+  const loading = ref(true)
+  const data = reactive({
+    yhzs: 30
+  })
+
+  const fullOptions = ref({ options: {} })
+  const selectedI = ref(0)
+  const options = ref([
+    { name: '当日', code: 0 },
+    { name: '近一周', code: 1 },
+    { name: '近一月', code: 2 }
+  ])
+  const dayClick = (v) => {
+    selectedI.value = v
+    fullOptions.value.options = chartOptions.setYhqkOption([], selectedI.value)
+  }
+  onMounted(() => {
+    setTimeout(() => {
+      loading.value = false
+      fullOptions.value.options = chartOptions.setYhqkOption([], selectedI.value)
+    }, 1000)
+  })
+</script>
+
+<style scoped lang="scss">
+  .box-style {
+    background: url('@/assets/images/box-bg.png') no-repeat center;
+    background-size: 100%;
+  }
+</style>

+ 41 - 0
src/views/home/leftbox/middleBox.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="left-top-box">
+    <div class="flex gap-15px h-90px">
+      <div
+        class="box-style color- flex-1 flex flex-col flex-justify-center flex-items-center gap-2px"
+      >
+        <span>监控点位</span>
+        <Countto class="text-20px color-#389bff font-bold" :endVal="80" />
+      </div>
+      <div class="box-style flex-1 flex flex-col flex-justify-center flex-items-center gap-2px">
+        <span>智能分析</span>
+        <Countto class="text-20px color-#389bff font-bold" :endVal="60" />
+      </div>
+    </div>
+    <ECharts
+      id="sbxx-echarts"
+      width="100%"
+      height="300px"
+      :loading="loading"
+      :fullOptions="{ options: chartOptions.setSbxxOption() }"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { chartOptions } from '@/components/ECharts/optionsConfig'
+  const loading = ref(true)
+
+  onMounted(() => {
+    setTimeout(() => {
+      loading.value = false
+    }, 1000)
+  })
+</script>
+
+<style scoped lang="scss">
+  .box-style {
+    background: url('@/assets/images/box-bg.png') no-repeat center;
+    background-size: 100% 100%;
+  }
+</style>

+ 3 - 5
src/views/home/leftbox/leftTopBox.vue → src/views/home/leftbox/topBox.vue

@@ -23,11 +23,9 @@
       </swiper-slide>
     </swiper>
     <ScrollPanel
-      style="width: 100%; height: 200px"
-      :dt="{
-        bar: {
-          background: '{primary.color}'
-        }
+      style="width: 100%; height: 150px"
+      :pt="{
+        barY: '!bg-#6286b6c2'
       }"
     >
       <div v-for="(item, i) in dataList" :key="i" class="text-18px color-#f0f0f0">

+ 31 - 0
src/views/home/rightbox/bottomBox.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="right-bottom-box">
+    <ECharts
+      id="bjlx-echarts"
+      width="100%"
+      height="290px"
+      :loading="loading"
+      :fullOptions="fullOptions"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { chartOptions } from '@/components/ECharts/optionsConfig'
+  const loading = ref(true)
+
+  const fullOptions = ref({ options: {} })
+  onMounted(() => {
+    setTimeout(() => {
+      loading.value = false
+      fullOptions.value.options = chartOptions.setBjlxOption([])
+    }, 1000)
+  })
+</script>
+
+<style scoped lang="scss">
+  .box-style {
+    background: url('@/assets/images/box-bg.png') no-repeat center;
+    background-size: 100% 100%;
+  }
+</style>

+ 164 - 0
src/views/home/rightbox/topBox.vue

@@ -0,0 +1,164 @@
+<template>
+  <div class="right-top-box">
+    <div class="flex gap-15px h-90px mb-15px">
+      <div
+        class="box-style color- flex-1 flex flex-col flex-justify-center flex-items-center gap-2px"
+      >
+        <span>已处理</span>
+        <Countto class="text-20px color-#379ED7 font-bold" :endVal="data.ycl" />
+      </div>
+      <div class="box-style flex-1 flex flex-col flex-justify-center flex-items-center gap-2px">
+        <span>未处理</span>
+        <Countto class="text-20px color-#F0BC1E font-bold" :endVal="data.wcl" />
+      </div>
+    </div>
+    <div class="flex justify-between relative">
+      <ul class="flex gap-15px justify-start">
+        <li
+          :class="[
+            'w-50px h-30px line-height-25px cursor-pointer text-center b-solid b-1px b-color-#389bff hover:b-color-#FAC858',
+            i === typeSelectedI ? 'color-#FAC858 b-color-#FAC858' : ''
+          ]"
+          v-for="(item, i) in typeOptions"
+          :key="item.code"
+          @click="typeClick(i)"
+        >
+          <span class="text-12px">{{ item.name }}</span>
+        </li>
+      </ul>
+      <ul class="flex gap-15px">
+        <li
+          :class="[
+            'w-50px cursor-pointer text-center b-solid b-1px b-color-#389bff hover:b-color-#FAC858',
+            i === selectedI ? 'color-#FAC858 b-color-#FAC858' : ''
+          ]"
+          v-for="(item, i) in options"
+          :key="item.code"
+          @click="dayClick(i)"
+        >
+          <span class="text-12px">{{ item.name }}</span>
+        </li>
+      </ul>
+    </div>
+    <ECharts
+      id="bjzx-echarts"
+      width="100%"
+      height="200px"
+      :loading="loading"
+      :fullOptions="fullOptions"
+    />
+    <div class="table-box w-full">
+      <div class="text-left bg-#389bff94 flex">
+        <span class="p-2 w-60px">报警</span>
+        <span class="p-2 w-80px">报警类型</span>
+        <span class="p-2 flex-1">报警时间</span>
+        <span class="p-2 w-80px">报警级别</span>
+        <span class="p-2 w-60px">处理</span>
+      </div>
+      <ScrollBox :list="data.list">
+        <div
+          :class="[
+            'text-left  text-14px hover:bg-#389bff24 flex',
+            (i + 1) % 2 == 0 ? 'bg-#ffffff24' : ''
+          ]"
+          v-for="(item, i, index) in data.list"
+          :key="index"
+        >
+          <span class="p-2 w-60px">{{ item.name }}</span>
+          <span class="p-2 w-80px">{{ item.type }}</span>
+          <span class="p-2 flex-1">{{ item.time }}</span>
+          <span class="p-2 w-80px">{{ item.level ? '告警' : '故障' }}</span>
+          <span :class="['p-2 w-60px', item.cl ? 'color-#389bff' : 'color-red']">{{
+            item.cl ? '已处理' : '未处理'
+          }}</span>
+        </div>
+      </ScrollBox>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  import { chartOptions } from '@/components/ECharts/optionsConfig'
+  const loading = ref(true)
+  const data = reactive({
+    ycl: 105,
+    wcl: 2,
+    list: [
+      {
+        name: 'XY7809',
+        type: '工服',
+        time: '2022-03-01 12:00:00',
+        level: 0,
+        cl: 0
+      },
+      {
+        name: 'XY7809',
+        type: '烟雾',
+        time: '2024-03-01 12:00:00',
+        level: 1,
+        cl: 1
+      },
+      {
+        name: 'XY7809',
+        type: '工服',
+        time: '2022-03-01 12:00:00',
+        level: 0,
+        cl: 0
+      },
+      {
+        name: 'XY7809',
+        type: '烟雾',
+        time: '2024-03-01 12:00:00',
+        level: 1,
+        cl: 1
+      },
+      {
+        name: 'XY7809',
+        type: '工服',
+        time: '2022-03-01 12:00:00',
+        level: 0,
+        cl: 0
+      },
+      {
+        name: 'XY7809',
+        type: '烟雾',
+        time: '2024-03-01 12:00:00',
+        level: 1,
+        cl: 1
+      }
+    ]
+  })
+  const selectedI = ref(0)
+  const fullOptions = ref({ options: {} })
+
+  const options = ref([
+    { name: '当日', code: 0 },
+    { name: '近一周', code: 1 },
+    { name: '近一月', code: 2 }
+  ])
+  const dayClick = (v) => {
+    selectedI.value = v
+    fullOptions.value.options = chartOptions.setBjzxOption([], selectedI.value)
+  }
+  const typeSelectedI = ref(0)
+  const typeOptions = ref([
+    { name: '趋势', code: 0 },
+    { name: '类型', code: 1 }
+  ])
+  const typeClick = (v) => {
+    typeSelectedI.value = v
+  }
+  onMounted(() => {
+    setTimeout(() => {
+      loading.value = false
+      fullOptions.value.options = chartOptions.setBjzxOption([], selectedI.value)
+    }, 1000)
+  })
+</script>
+
+<style scoped lang="scss">
+  .box-style {
+    background: url('@/assets/images/box-bg.png') no-repeat center;
+    background-size: 100% 100%;
+  }
+</style>