瀏覽代碼

楼宇自控、出入口、电子巡查、访客系统、客流统计、门禁系统

AaronBruin 2 月之前
父節點
當前提交
e3dd155701
共有 74 個文件被更改,包括 3459 次插入973 次删除
  1. 1 0
      package.json
  2. 8 0
      pnpm-lock.yaml
  3. 12 0
      src/api/system/access.js
  4. 12 0
      src/api/system/building.js
  5. 12 0
      src/api/system/endpoint.js
  6. 12 0
      src/api/system/energy.js
  7. 12 0
      src/api/system/illuminating.js
  8. 12 0
      src/api/system/information.js
  9. 12 0
      src/api/system/invade.js
  10. 12 0
      src/api/system/monitor.js
  11. 12 0
      src/api/system/passageway.js
  12. 12 0
      src/api/system/passenger.js
  13. 3 3
      src/api/system/tenement.js
  14. 12 0
      src/api/system/visitor.js
  15. 二進制
      src/assets/logo/ball.png
  16. 7 1
      src/components/waterdrop/index.vue
  17. 11 6
      src/layout/components/Sidebar/Logo.vue
  18. 167 0
      src/views/index/particle.vue
  19. 64 38
      src/views/login.vue
  20. 1 1
      src/views/system/broadcast/index.vue
  21. 190 0
      src/views/system/building/equipment.vue
  22. 87 12
      src/views/system/building/index.vue
  23. 25 8
      src/views/system/energy/index.vue
  24. 30 12
      src/views/system/energy/modules/carbonEmission.vue
  25. 30 13
      src/views/system/energy/modules/consume.vue
  26. 51 34
      src/views/system/energy/modules/consumptionPower.vue
  27. 31 12
      src/views/system/energy/modules/consumptionWater.vue
  28. 21 7
      src/views/system/energy/modules/running.vue
  29. 21 7
      src/views/system/energy/modules/sameDay.vue
  30. 24 10
      src/views/system/entranceguard/alleyway.vue
  31. 34 4
      src/views/system/entranceguard/equipment.vue
  32. 27 14
      src/views/system/entranceguard/inbreak.vue
  33. 25 6
      src/views/system/entranceguard/index.vue
  34. 32 1
      src/views/system/entranceguard/inform.vue
  35. 24 14
      src/views/system/entranceguard/passable.vue
  36. 58 41
      src/views/system/inspection/index.vue
  37. 171 0
      src/views/system/intruderalarm/alarm.vue
  38. 77 24
      src/views/system/intruderalarm/index.vue
  39. 23 6
      src/views/system/lighting/index.vue
  40. 67 46
      src/views/system/lighting/modules/deviceList.vue
  41. 68 51
      src/views/system/lighting/modules/eventList.vue
  42. 169 24
      src/views/system/lighting/modules/running.vue
  43. 67 26
      src/views/system/lighting/modules/switchAll.vue
  44. 24 8
      src/views/system/message/index.vue
  45. 39 9
      src/views/system/message/modules/carbonEmission.vue
  46. 9 3
      src/views/system/message/modules/consume.vue
  47. 66 32
      src/views/system/message/modules/running.vue
  48. 59 47
      src/views/system/message/modules/sameDay.vue
  49. 27 8
      src/views/system/message/modules/tiring.vue
  50. 44 13
      src/views/system/passageway/Personnel.vue
  51. 38 6
      src/views/system/passageway/index.vue
  52. 27 15
      src/views/system/passengerFlow/district.vue
  53. 25 11
      src/views/system/passengerFlow/earlyWarning.vue
  54. 52 14
      src/views/system/passengerFlow/index.vue
  55. 26 15
      src/views/system/passengerFlow/monitoring.vue
  56. 26 12
      src/views/system/passengerFlow/security.vue
  57. 11 11
      src/views/system/tenement/index.vue
  58. 43 9
      src/views/system/tenement/modules/carbonEmission.vue
  59. 18 3
      src/views/system/tenement/modules/consume.vue
  60. 61 49
      src/views/system/tenement/modules/eventList.vue
  61. 25 7
      src/views/system/tenement/modules/running.vue
  62. 36 7
      src/views/system/tenement/modules/sameDay.vue
  63. 76 57
      src/views/system/tenement/modules/tiring.vue
  64. 50 36
      src/views/system/video/index.vue
  65. 29 9
      src/views/system/video/modules/carbonEmission.vue
  66. 10 3
      src/views/system/video/modules/consume.vue
  67. 57 44
      src/views/system/video/modules/eventList.vue
  68. 23 6
      src/views/system/video/modules/running.vue
  69. 12 2
      src/views/system/video/modules/sameDay.vue
  70. 147 0
      src/views/system/visitor/caller.vue
  71. 109 116
      src/views/system/visitor/index.vue
  72. 171 0
      src/views/system/visitor/register.vue
  73. 171 0
      src/views/system/visitor/swiping.vue
  74. 202 0
      src/views/system/visitor/transit.vue

+ 1 - 0
package.json

@@ -35,6 +35,7 @@
     "nprogress": "0.2.0",
     "pinia": "2.1.7",
     "splitpanes": "3.1.5",
+    "three": "^0.176.0",
     "vue": "3.4.31",
     "vue-cropper": "1.1.1",
     "vue-router": "4.4.0",

+ 8 - 0
pnpm-lock.yaml

@@ -65,6 +65,9 @@ importers:
       splitpanes:
         specifier: 3.1.5
         version: 3.1.5
+      three:
+        specifier: ^0.176.0
+        version: 0.176.0
       vue:
         specifier: 3.4.31
         version: 3.4.31
@@ -1940,6 +1943,9 @@ packages:
     engines: {node: '>=10.13.0'}
     hasBin: true
 
+  three@0.176.0:
+    resolution: {integrity: sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==}
+
   tiny-emitter@2.1.0:
     resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
 
@@ -4179,6 +4185,8 @@ snapshots:
       picocolors: 1.1.1
       stable: 0.1.8
 
+  three@0.176.0: {}
+
   tiny-emitter@2.1.0: {}
 
   to-object-path@0.3.0:

+ 12 - 0
src/api/system/access.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询门禁系统统计数据
+export function getAccess(query) {
+    return request({
+        url: '/Hikvision/access',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/building.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询楼宇自控统计数据
+export function getIntell(query) {
+    return request({
+        url: '/intell/count',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/endpoint.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询电子巡查统计数据
+export function getEndpoint(query) {
+    return request({
+        url: '/Hikvision/endpoint',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/energy.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询能源系统统计数据
+export function getEnergy(query) {
+    return request({
+        url: '/energy/count',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/illuminating.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询照明系统统计数据
+export function getIlluminating(query) {
+    return request({
+        url: '/illuminating/count',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/information.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询信息发布统计数据
+export function getInformation(query) {
+    return request({
+        url: '/information/count',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/invade.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询入侵报警统计数据
+export function getInvade(query) {
+    return request({
+        url: '/Hikvision/invade',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/monitor.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询视频系统统计数据
+export function getHikvision(query) {
+    return request({
+        url: '/Hikvision/monitor',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/passageway.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询出入口统计数据
+export function getAccess(query) {
+    return request({
+        url: '/Access/count',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 12 - 0
src/api/system/passenger.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询客流统计数据
+export function getPassenger(query) {
+    return request({
+        url: '/Hikvision/passenger',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

+ 3 - 3
src/api/system/tenement.js

@@ -1,10 +1,10 @@
 import request from '@/utils/request'
 const Url = "http://182.43.247.65:8000"
 
-// 查询会议统计数据
-export function getBroadcast(query) {
+// 查询物业统计数据
+export function getProperty(query) {
     return request({
-        url: '/elevator/count',
+        url: '/property/count',
         method: 'get',
         params: query,
         baseURL: import.meta.env.DEV ? '/APP' : 'Url',

+ 12 - 0
src/api/system/visitor.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+const Url = "http://182.43.247.65:8000"
+
+// 查询访客统计数据
+export function getVisitor(query) {
+    return request({
+        url: '/Hikvision/visitor',
+        method: 'get',
+        params: query,
+        baseURL: import.meta.env.DEV ? '/APP' : 'Url',
+    })
+}

二進制
src/assets/logo/ball.png


+ 7 - 1
src/components/waterdrop/index.vue

@@ -44,7 +44,13 @@ const props = defineProps({
     }
 })
 const heightDrop = ref(0)
-const heightTop = props.heightTop
+const heightTop = ref(0)
+watch(() => props.heightTop, (newVal) => {
+    if (newVal) {
+        heightTop.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
     var element = document.getElementById("myElement");

+ 11 - 6
src/layout/components/Sidebar/Logo.vue

@@ -21,10 +21,10 @@
       </div>
     </router-link>
     <div class="avatar-container">
-      <Dropdown :name="name" :options="['退出登录']" @changeData="logout"></Dropdown>
       <div class="shiny-button" @click="expandFold">
-        {{ appStore.expandFoldType ?'收起':'展开'}}
+        {{ appStore.expandFoldType ? '收起' : '展开' }}
       </div>
+      <Dropdown :name="name" :options="['退出登录']" @changeData="logout"></Dropdown>
     </div>
   </div>
 </template>
@@ -166,11 +166,11 @@ const getWeather = async (params) => {
   }
 }
 // 展开收起
-const expandFold = () =>{
+const expandFold = () => {
   let foldType = true
-  if(appStore.expandFoldType){
+  if (appStore.expandFoldType) {
     foldType = false
-  }else{
+  } else {
     foldType = true
   }
   appStore.getExpandFold(foldType);
@@ -294,7 +294,7 @@ onMounted(() => {
 
 .shiny-button {
   user-select: none;
-  margin-left: 20px;
+  margin-right: 20px;
   width: fit-content;
   position: relative;
   padding: 2px 20px;
@@ -338,9 +338,11 @@ onMounted(() => {
   0% {
     left: -120%;
   }
+
   8% {
     left: 50%;
   }
+
   100% {
     left: 50%;
   }
@@ -350,12 +352,15 @@ onMounted(() => {
   0% {
     background-position: 0px, -250px;
   }
+
   25% {
     background-position: 0px, -200px;
   }
+
   75% {
     background-position: 0px, 50px;
   }
+
   100% {
     background-position: 0px, 50px;
   }

+ 167 - 0
src/views/index/particle.vue

@@ -0,0 +1,167 @@
+<template>
+    <div id="waves" />
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+import * as THREE from "three";
+
+const amountX = ref(50);
+const amountY = ref(50);
+const color = ref("#91a3c2");
+const topOffset = ref(650);
+
+let count = 0;
+let mouseX = 0;
+let windowHalfX = null;
+let camera = null;
+let scene = null;
+let particles = null;
+let renderer = null;
+
+const init = () => {
+    const SEPARATION = 100;
+    const SCREEN_WIDTH = window.innerWidth;
+    const SCREEN_HEIGHT = window.innerHeight;
+    const container = document.createElement("div");
+    windowHalfX = window.innerWidth / 2;
+    container.style.position = "relative";
+    container.style.top = `${topOffset.value}px`;
+    container.style.height = `${SCREEN_HEIGHT - topOffset.value}px`;
+
+    const waves = document.getElementById("waves");
+    waves.appendChild(container);
+
+    camera = new THREE.PerspectiveCamera(
+        75,
+        SCREEN_WIDTH / SCREEN_HEIGHT,
+        1,
+        10000,
+    );
+    camera.position.z = 1000;
+    scene = new THREE.Scene();
+    const numParticles = amountX.value * amountY.value;
+    const positions = new Float32Array(numParticles * 3);
+    const scales = new Float32Array(numParticles);
+    let i = 0;
+    let j = 0;
+    for (let ix = 0; ix < amountX.value; ix++) {
+        for (let iy = 0; iy < amountY.value; iy++) {
+            positions[i] = ix * SEPARATION - (amountX.value * SEPARATION) / 2;
+            positions[i + 1] = 0;
+            positions[i + 2] = iy * SEPARATION - (amountY.value * SEPARATION) / 2;
+            scales[j] = 1;
+            i += 3;
+            j++;
+        }
+    }
+    const geometry = new THREE.BufferGeometry();
+    geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
+    geometry.setAttribute("scale", new THREE.BufferAttribute(scales, 1));
+    const material = new THREE.ShaderMaterial({
+        uniforms: {
+            color: { value: new THREE.Color(color.value) },
+        },
+        vertexShader: `
+        attribute float scale;
+        void main() {
+          vec4 mvPosition = modelViewMatrix * vec4( position, 2.0 );
+          gl_PointSize = scale * ( 300.0 / - mvPosition.z );
+          gl_Position = projectionMatrix * mvPosition;
+        }
+      `,
+        fragmentShader: `
+        uniform vec3 color;
+        void main() {
+          if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
+          gl_FragColor = vec4( color, 1.0 );
+        }
+      `,
+    });
+    particles = new THREE.Points(geometry, material);
+    scene.add(particles);
+    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
+    renderer.setSize(container.clientWidth, container.clientHeight);
+    renderer.setPixelRatio(window.devicePixelRatio);
+    renderer.setClearAlpha(0);
+    container.appendChild(renderer.domElement);
+    window.addEventListener("resize", onWindowResize, { passive: false });
+    // document.addEventListener("mousemove", onDocumentMouseMove, {
+    //     passive: false,
+    // });
+    // document.addEventListener("touchstart", onDocumentTouchStart, {
+    //     passive: false,
+    // });
+    // document.addEventListener("touchmove", onDocumentTouchMove, {
+    //     passive: false,
+    // });
+};
+
+const render = () => {
+    camera.position.x += (mouseX - camera.position.x) * 0.05;
+    camera.position.y = 400;
+    camera.lookAt(scene.position);
+    const positions = particles.geometry.attributes.position.array;
+    const scales = particles.geometry.attributes.scale.array;
+
+    let i = 0;
+    let j = 0;
+    for (let ix = 0; ix < amountX.value; ix++) {
+        for (let iy = 0; iy < amountY.value; iy++) {
+            positions[i + 1] =
+                Math.sin((ix + count) * 0.3) * 100 + Math.sin((iy + count) * 0.5) * 100;
+            scales[j] =
+                (Math.sin((ix + count) * 0.3) + 1) * 8 +
+                (Math.sin((iy + count) * 0.5) + 1) * 8;
+            i += 3;
+            j++;
+        }
+    }
+
+    particles.geometry.attributes.position.needsUpdate = true;
+    particles.geometry.attributes.scale.needsUpdate = true;
+    renderer.render(scene, camera);
+    count += 0.1;
+};
+
+const animate = () => {
+    requestAnimationFrame(animate);
+    render();
+};
+
+const onDocumentMouseMove = (event) => {
+    mouseX = event.clientX - windowHalfX;
+};
+
+const onDocumentTouchStart = (event) => {
+    if (event.touches.length === 1) {
+        mouseX = event.touches[0].pageX - windowHalfX;
+    }
+};
+
+const onDocumentTouchMove = (event) => {
+    if (event.touches.length === 1) {
+        event.preventDefault();
+        mouseX = event.touches[0].pageX - windowHalfX;
+    }
+};
+
+const onWindowResize = () => {
+    windowHalfX = window.innerWidth / 2;
+    camera.aspect = window.innerWidth / window.innerHeight;
+    camera.updateProjectionMatrix();
+    renderer.setSize(window.innerWidth, window.innerHeight);
+};
+
+onMounted(() => {
+    init();
+    animate();
+});
+
+onUnmounted(() => {
+    window.removeEventListener("resize", onWindowResize);
+    document.removeEventListener("mousemove", onDocumentMouseMove);
+    document.removeEventListener("touchstart", onDocumentTouchStart);
+    document.removeEventListener("touchmove", onDocumentTouchMove);
+});
+</script>

+ 64 - 38
src/views/login.vue

@@ -1,43 +1,47 @@
 <template>
   <dv-full-screen-container>
     <div class="login">
-      <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
-        <h3 class="title">{{ title }}</h3>
-        <el-form-item prop="username">
-          <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
-            <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
-          </el-input>
-        </el-form-item>
-        <el-form-item prop="password">
-          <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码"
-            @keyup.enter="handleLogin">
-            <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
-          </el-input>
-        </el-form-item>
-        <el-form-item prop="code" v-if="captchaEnabled">
-          <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%"
-            @keyup.enter="handleLogin">
-            <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
-          </el-input>
-          <div class="login-code">
-            <img :src="codeUrl" @click="getCode" class="login-code-img" />
-          </div>
-        </el-form-item>
-        <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
-        <el-form-item style="width:100%;">
-          <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
-            <span v-if="!loading">登 录</span>
-            <span v-else>登 录 中...</span>
-          </el-button>
-          <div style="float: right;" v-if="register">
-            <router-link class="link-type" :to="'/register'">立即注册</router-link>
-          </div>
-        </el-form-item>
-      </el-form>
+      <div class="login_box">
+        <div class="ball_login"></div>
+        <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
+          <h3 class="title">{{ title }}</h3>
+          <el-form-item prop="username">
+            <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
+              <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
+            </el-input>
+          </el-form-item>
+          <el-form-item prop="password">
+            <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码"
+              @keyup.enter="handleLogin">
+              <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
+            </el-input>
+          </el-form-item>
+          <el-form-item prop="code" v-if="captchaEnabled">
+            <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%"
+              @keyup.enter="handleLogin">
+              <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
+            </el-input>
+            <div class="login-code">
+              <img :src="codeUrl" @click="getCode" class="login-code-img" />
+            </div>
+          </el-form-item>
+          <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
+          <el-form-item style="width:100%;">
+            <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
+              <span v-if="!loading">登 录</span>
+              <span v-else>登 录 中...</span>
+            </el-button>
+            <div style="float: right;" v-if="register">
+              <router-link class="link-type" :to="'/register'">立即注册</router-link>
+            </div>
+          </el-form-item>
+        </el-form>
+      </div>
       <!--  底部  -->
       <div class="el-login-footer">
         <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
       </div>
+      <particle style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;"></particle>
     </div>
   </dv-full-screen-container>
 </template>
@@ -47,6 +51,7 @@ import { getCodeImg } from "@/api/login";
 import Cookies from "js-cookie";
 import { encrypt, decrypt } from "@/utils/jsencrypt";
 import useUserStore from '@/store/modules/user'
+import particle from './index/particle.vue'
 
 const title = import.meta.env.VITE_APP_TITLE;
 const userStore = useUserStore();
@@ -145,24 +150,45 @@ getCookie();
 .login {
   display: flex;
   justify-content: center;
-  align-items: center;
+  // align-items: center;
   height: 100%;
-  background: url("@/assets/images/login-bg.svg");
-  background-size: cover;
+  background: radial-gradient(at 50% 50%, rgb(29, 52, 94) 1%, rgb(3, 22, 46) 60%);
+}
+
+.login_box {
+  position: absolute;
+  top: 5%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 .title {
+  font-size: 24px;
   margin: 0px auto 30px auto;
   text-align: center;
-  color: #707070;
+  background-image: -webkit-linear-gradient(bottom, rgb(120, 173, 221), rgb(229, 232, 236));
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+}
+
+.ball_login {
+  flex: none;
+  width: 700px;
+  height: 700px;
+  background: url("@/assets/logo/ball.png");
+  background-size: cover;
 }
 
 .login-form {
+  margin-left: 10%;
+  flex: none;
   border-radius: 6px;
-  background: #ffffff;
+  // background: #ffffff;
   width: 400px;
   padding: 25px 25px 5px 25px;
   box-shadow: var(--el-box-shadow-light);
+  z-index: 1;
 
   .el-input {
     height: 40px;

+ 1 - 1
src/views/system/broadcast/index.vue

@@ -8,7 +8,7 @@
                 </div>
             </template>
             <template #content>
-                <p>广播</p>
+                <!-- <p>广播</p> -->
             </template>
             <template #right>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">

+ 190 - 0
src/views/system/building/equipment.vue

@@ -0,0 +1,190 @@
+<template>
+    <div class="_eventList">
+        <div class="_eventList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
+                    <div class="_eventList_mains_item_text">
+                        <div :class="item.State === 'on' ? '_warning' : '_success'"
+                            class="_eventList_mains_item_text_flag"></div>
+                        <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
+                            {{ item.Name }}
+                        </el-text>
+                    </div>
+                    <div class="_eventList_mains_item_btn">
+                        {{ item.State == 0 ? '离线' : '在线' }}
+                    </div>
+                    <div class="_eventList_mains_item_btn">
+                        {{ item.Date }}
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+const eventList = ref([])
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '终端设备播放',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '终端设备播放',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '终端设备停止',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '终端设备播放',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '终端设备停止',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '终端设备停止',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '终端设备播放',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '终端设备停止',
+//     time: '2025-04-15 10:20:00'
+// }])
+
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value?.querySelector('._eventList_mains_item')?.offsetHeight;
+        if (!itemHeight) return;
+
+        scrollY.value -= scrollSpeed;
+
+        // 检查第一个元素是否完全离开视口
+        if (Math.abs(scrollY.value) >= itemHeight) {
+            // 将第一个元素移到列表末尾
+            const firstItem = eventList.value.shift();
+            if (firstItem) {
+                eventList.value.push(firstItem);
+            }
+            // 调整滚动位置
+            scrollY.value += itemHeight;
+        }
+    }, 50);
+};
+
+const pauseCarousel = () => {
+    clearInterval(intervalId);
+};
+
+const resumeCarousel = () => {
+    startCarousel();
+};
+
+onMounted(() => {
+    startCarousel();
+});
+
+onUnmounted(() => {
+    clearInterval(intervalId);
+});
+</script>
+
+<style lang="scss" scoped>
+._success {
+    background: #15acaa;
+}
+
+._warning {
+    background: #FFC107;
+}
+
+._eventList {
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+
+    &_mains {
+        margin: 10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        // 鼠标移入时改变手势
+        cursor: pointer;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px 0;
+
+            &_text {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+
+                &_flag {
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    margin-left: 10px;
+                }
+
+                &_p {
+                    margin-left: 10px;
+                }
+            }
+
+            &_btn {
+                color: #fff;
+                display: flex;
+                font-size: 14px;
+                gap: 20px;
+
+                &_item {
+                    border-radius: 5px;
+                    cursor: pointer;
+                }
+            }
+        }
+
+        &_item:nth-child(even) {
+            background: rgba($color: #168cdb, $alpha: .05);
+        }
+
+        &_item:hover {
+            background-image: linear-gradient(to right, #168cdb, transparent);
+        }
+    }
+}
+</style>

+ 87 - 12
src/views/system/building/index.vue

@@ -3,28 +3,29 @@
         <layout>
             <template #left>
                 <div class="left_spection">
-                    <div style="height: 30%;">
+                    <!-- <div style="height: 30%;">
                         <HeadlineTag value="水滴图"></HeadlineTag>
                         <div class="box_arch center_in">
                             <div style="width: 50%;height: 100%;">
                                 <waterdrop width="100%" color="rgb(42, 139, 247)"></waterdrop>
                             </div>
                         </div>
-                    </div>
+                    </div> -->
                     <div class="flex_spection">
                         <HeadlineTag value="设备列表"></HeadlineTag>
                         <div class="box_arch_point">
                             <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
                                 <el-input v-model="input" placeholder="按设备名称搜索" />
                             </div>
-                            <div style="height: calc(100% - 160px);">
+                            <equipment :resultData="leftData.DeviceList"></equipment>
+                            <!-- <div style="height: calc(100% - 160px);">
                                 <Empty></Empty>
                             </div>
                             <div class="center_in">
                                 <pagination :total="total" v-model:page="queryParams.pageNum"
                                     v-model:limit="queryParams.pageSize" layout="total, prev, pager, next"
                                     @pagination="getList" />
-                            </div>
+                            </div> -->
                         </div>
                     </div>
                 </div>
@@ -35,21 +36,21 @@
                         <HeadlineTag type="right" value="运行统计"></HeadlineTag>
                         <div class="box_arch">
                             <div class="image_tubbiness">
-                                <div class="work_num">3235</div>
+                                <div class="work_num">{{ leftData.DeviceCount || 0 }}</div>
                                 <div class="work_title">设备总数</div>
                             </div>
                             <div class="right_content">
                                 <div class="work_week">
                                     <div class="color_line_xj" style="background-color: rgb(21, 213, 21);"></div>
-                                    <span>运行状态:</span>0
+                                    <span>运行状态:</span>{{ leftData.RunState || 0 }}
                                 </div>
                                 <div class="work_week">
                                     <div class="color_line_xj" style="background-color: rgb(196, 127, 19);"></div>
-                                    <span>停止状态:</span>0
+                                    <span>停止状态:</span>{{ leftData.StopState || 0 }}
                                 </div>
                                 <div class="work_week">
                                     <div class="color_line_xj" style="background-color: rgb(195, 56, 56);"></div>
-                                    <span>故障状态:</span>0
+                                    <span>故障状态:</span>{{ leftData.FaultState || 0 }}
                                 </div>
                             </div>
                         </div>
@@ -57,7 +58,9 @@
                     <div class="flex_spection">
                         <HeadlineTag type="right" value="设备群控"></HeadlineTag>
                         <div class="box_arch">
-                            <div ref="chartRouting" style="width: 100%;height: 100%;"></div>
+                            <!-- <div ref="chartRouting" style="width: 100%;height: 100%;"></div> -->
+                            <dv-scroll-board :config="groupControl"
+                                style="width:100%;height:calc(100% - 10px);margin-top: 10px;" />
                         </div>
                     </div>
                     <div class="flex_spection">
@@ -74,10 +77,12 @@
 </template>
 
 <script setup>
+import { getIntell } from "@/api/system/building"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import Empty from '@/components/Empty'
 import waterdrop from '@/components/waterdrop'
+import equipment from './equipment.vue'
 import * as echarts from 'echarts'
 const total = ref(0);
 const queryParams = ref({
@@ -85,11 +90,29 @@ const queryParams = ref({
     pageSize: 10,
 });
 const input = ref('')
+const groupControl = ref({
+    headerBGC: '#10285c',
+    oddRowBGC: '#10285c7f',
+    evenRowBGC: '#10285c00',
+    header: ['名称', '位置', '时间'],
+    data: [
+        ['行1列1', '行1列2', '行1列3'],
+        ['行2列1', '行2列2', '行2列3'],
+        ['行3列1', '行3列2', '行3列3'],
+        ['行4列1', '行4列2', '行4列3'],
+        ['行5列1', '行5列2', '行5列3'],
+        ['行6列1', '行6列2', '行6列3'],
+        ['行7列1', '行7列2', '行7列3'],
+        ['行8列1', '行8列2', '行8列3'],
+        ['行9列1', '行9列2', '行9列3'],
+        ['行10列1', '行10列2', '行10列3']
+    ]
+})
 const config = ref({
     headerBGC: '#10285c',
     oddRowBGC: '#10285c7f',
     evenRowBGC: '#10285c00',
-    header: ['名称', '位置', '列3'],
+    header: ['名称', '事件', '时间'],
     data: [
         ['行1列1', '行1列2', '行1列3'],
         ['行2列1', '行2列2', '行2列3'],
@@ -111,7 +134,9 @@ const chartRouting = ref(null);
 let chartInstance = null;
 // 初始化图表
 const initChart = () => {
-    chartInstance = echarts.init(chartRouting.value);
+    if (!chartInstance) {
+        chartInstance = echarts.init(chartRouting.value);
+    }
     chartInstance.setOption({
         tooltip: {
             trigger: 'axis',
@@ -211,7 +236,57 @@ const initChart = () => {
     });
 };
 // 生命周期
-onMounted(initChart);
+onMounted(() => {
+    intervalId.value = setInterval(getIntellData, 10000);
+    getIntellData()
+    // initChart()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getIntellData() {
+    getIntell().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
+
+watch(() => leftData.value, (newVal) => {
+    let arrData = []
+    let arrDatail = newVal.DeviceList
+    if (arrDatail && arrDatail.length > 0) {
+        arrDatail.forEach((item) => {
+            let arrData2 = []
+            arrData2.push(item.Name)
+            arrData2.push(item.AlarmContent)
+            arrData2.push(item.Date)
+            arrData.push(arrData2)
+        })
+    }
+    config.value.data = arrData
+    let arrData1 = []
+    let arrDatail1 = newVal.DeviceList
+    if (arrDatail1 && arrDatail1.length > 0) {
+        arrDatail1.forEach((item) => {
+            let arrData2 = []
+            arrData2.push(item.Name)
+            let title = ''
+            if (item.State == 0) {
+                title = '在线'
+            } else {
+                title = '离线'
+            }
+            arrData2.push(title)
+            arrData2.push(item.Date)
+            arrData1.push(arrData2)
+        })
+    }
+    groupControl.value.data = arrData1
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
     chartInstance?.resize();

+ 25 - 8
src/views/system/energy/index.vue

@@ -3,19 +3,19 @@
         <layout>
             <template #left>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <sameDay style="flex: 1;" />
-                    <consumptionPower style="flex: 1;" />
-                    <consumptionWater style="flex: 1;" />
+                    <sameDay :resultData="leftData" style="flex: 1;" />
+                    <consumptionPower :resultData="leftData.OnedayPowerConsumption" style="flex: 1;" />
+                    <consumptionWater :resultData="leftData.OnedayWaterConsumption" style="flex: 1;" />
                 </div>
             </template>
             <template #content>
-                <p>能源</p>
+                <!-- <p>能源</p> -->
             </template>
             <template #right>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <running style="flex: 1;" />
-                    <consume style="flex: 1;" />
-                    <carbonEmission style="flex: 1;" />
+                    <running :resultData="leftData" style="flex: 1;" />
+                    <consume :resultData="leftData" style="flex: 1;" />
+                    <carbonEmission :resultData="leftData" style="flex: 1;" />
                 </div>
             </template>
         </layout>
@@ -23,6 +23,7 @@
 </template>
 
 <script setup name="Role">
+import { getEnergy } from "@/api/system/energy"
 import layout from "@/components/layout_/index.vue";
 import sameDay from './modules/sameDay.vue'
 import consumptionPower from './modules/consumptionPower.vue'
@@ -31,7 +32,23 @@ import running from './modules/running.vue'
 import carbonEmission from './modules/carbonEmission.vue'
 import consume from './modules/consume.vue'
 
-
+const intervalId = ref(null)
+const leftData = ref({})
+// 生命周期
+onMounted(() => {
+    intervalId.value = setInterval(getEnergyData, 10000);
+    getEnergyData()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+function getEnergyData() {
+    getEnergy().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
 </script>
 <style lang="scss">
 ._energy {

+ 30 - 12
src/views/system/energy/modules/carbonEmission.vue

@@ -11,10 +11,14 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
-
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,19 +26,16 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
-        const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
-
+        // const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
+        const months = []
         const option = {
             xAxis: {
                 type: 'category',
@@ -80,7 +81,8 @@ onMounted(() => {
                 {
                     name: '当年',
                     type: 'bar',
-                    data: generateRandomData(12, 50),
+                    // data: generateRandomData(12, 50),
+                    data: [],
                     barWidth: '30%',
                     itemStyle: {
                         color: {
@@ -96,7 +98,7 @@ onMounted(() => {
                             }],
                             global: false // 缺省为 false
                         },
-                        barBorderRadius: [10, 10, 10,10]
+                        barBorderRadius: [10, 10, 10, 10]
 
                     },
                 },
@@ -105,11 +107,11 @@ onMounted(() => {
                     name: '去年',
                     type: 'line',
                     // smooth: true,
-                    data: generateRandomData(12, 50),
+                    // data: generateRandomData(12, 50),
+                    data: [],
                     lineStyle: {
                         color: '#216b87',
                         // 设置柱状图圆角
-                       
                     },
                     showSymbol: false,
                     smooth: true,
@@ -136,11 +138,27 @@ onMounted(() => {
                 }
             ]
         };
-
         chart.setOption(option);
     }
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal.LastYearCarbonEmissions),
+            },
+            series: [{
+                name: '当年',
+                data: Object.entries(newVal.YearCarbonEmissions),
+            }, {
+                name: '去年',
+                data: Object.entries(newVal.LastYearCarbonEmissions),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 30 - 13
src/views/system/energy/modules/consume.vue

@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,19 +27,16 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
-        const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
-
+        // const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
+        const months = []
         const option = {
             xAxis: {
                 type: 'category',
@@ -80,9 +82,9 @@ onMounted(() => {
                 {
                     name: '当年',
                     type: 'bar',
-                    data: generateRandomData(12, 50),
+                    // data: generateRandomData(12, 50),
+                    data: [],
                     barWidth: '30%',
-                    
                     itemStyle: {
                         color: {
                             type: 'linear',
@@ -97,8 +99,7 @@ onMounted(() => {
                             }],
                             global: false // 缺省为 false
                         },
-                        barBorderRadius: [10, 10, 10,10]
-
+                        barBorderRadius: [10, 10, 10, 10]
                     },
                 },
                 // 曲线
@@ -106,11 +107,11 @@ onMounted(() => {
                     name: '去年',
                     type: 'line',
                     // smooth: true,
-                    data: generateRandomData(12, 50),
+                    // data: generateRandomData(12, 50),
+                    data: [],
                     lineStyle: {
                         color: '#cda23d',
                         // 设置柱状图圆角
-                       
                     },
                     showSymbol: false,
                     smooth: true,
@@ -137,11 +138,27 @@ onMounted(() => {
                 }
             ]
         };
-
         chart.setOption(option);
     }
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal.YearEnergyConsumption),
+            },
+            series: [{
+                name: '当年',
+                data: Object.entries(newVal.YearEnergyConsumption),
+            }, {
+                name: '去年',
+                data: Object.entries(newVal.LastYearEnergyConsumption),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 51 - 34
src/views/system/energy/modules/consumptionPower.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="_consume">
-        <HeadlineTag value="24小时能耗-电/kwh"></HeadlineTag> 
+        <HeadlineTag value="24小时能耗-电/kwh"></HeadlineTag>
         <div class="_consume_mains">
             <div ref="chartRef" style="width: 100%; height: 100%;"></div>
         </div>
@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,25 +27,22 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 修改为 24 小时
-        const hours = Array.from({ length: 24 }, (_, i) => `${i}时`);
-
+        // const hours = Array.from({ length: 24 }, (_, i) => `${i}时`);
+        const hours = []
         const option = {
             xAxis: {
                 type: 'category',
                 // 使用 24 小时数据
-                data: hours, 
+                data: hours,
                 axisLabel: {
                     color: '#fff'
                 },
@@ -55,56 +57,57 @@ onMounted(() => {
                 }
             },
             grid: {
-                top: '10%', 
+                top: '10%',
                 bottom: '10%',
-                right: '0%', 
+                right: '0%',
             },
             yAxis: {
                 type: 'value',
                 axisLabel: {
-                    show: true, 
+                    show: true,
                     color: '#fff'
                 },
                 splitLine: {
-                    show: false, 
+                    show: false,
                     lineStyle: {
-                        color: '#44585e' 
+                        color: '#44585e'
                     }
                 },
                 axisTick: {
-                    show: false 
+                    show: false
                 },
             },
             series: [
                 {
                     name: '24小时能耗',
-                    data: generateRandomData(24, 100),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     type: 'line',
                     showSymbol: false,
                     smooth: true,
                     color: '#00F7FF',
                     lineStyle: {
-                    width: 2,
+                        width: 2,
                     },
                     areaStyle: {
-                    color: new echarts.graphic.LinearGradient(
-                        0,
-                        0,
-                        0,
-                        1,
-                        [{
-                        offset: 0,
-                        color: 'rgba(0, 247, 255, .6)',
-                        },
-                        {
-                        offset: 0.8,
-                        color: 'rgba(0, 247, 255, .2)',
-                        },
-                        ],
-                        false
-                    ),
-                    shadowColor: 'rgba(0, 0, 0, 0.1)',
-                    shadowBlur: 10,
+                        color: new echarts.graphic.LinearGradient(
+                            0,
+                            0,
+                            0,
+                            1,
+                            [{
+                                offset: 0,
+                                color: 'rgba(0, 247, 255, .6)',
+                            },
+                            {
+                                offset: 0.8,
+                                color: 'rgba(0, 247, 255, .2)',
+                            },
+                            ],
+                            false
+                        ),
+                        shadowColor: 'rgba(0, 0, 0, 0.1)',
+                        shadowBlur: 10,
                     },
                     symbol: 'circle',
                     symbolSize: 6,
@@ -116,6 +119,20 @@ onMounted(() => {
     }
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal),
+            },
+            series: [{
+                type: 'line',
+                data: Object.entries(newVal),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 31 - 12
src/views/system/energy/modules/consumptionWater.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="_consume">
-        <HeadlineTag value="24小时能耗-水/T"></HeadlineTag> 
+        <HeadlineTag value="24小时能耗-水/T"></HeadlineTag>
         <div class="_consume_mains">
             <div ref="chartRef" style="width: 100%; height: 100%;"></div>
         </div>
@@ -11,7 +11,12 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
-
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 const chartRef = ref(null);
 let chart = null;
 
@@ -32,15 +37,14 @@ const handleResize = () => {
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 生成 24 小时的时间数据
-        const hours = Array.from({ length: 24 }, (_, i) => `${i}时`);
-
+        // const hours = Array.from({ length: 24 }, (_, i) => `${i}时`);
+        const hours = []
         const option = {
             xAxis: {
                 type: 'category',
                 // 使用 24 小时数据
-                data: hours, 
+                data: hours,
                 axisLabel: {
                     color: '#fff'
                 },
@@ -55,24 +59,24 @@ onMounted(() => {
                 }
             },
             grid: {
-                top: '10%', 
+                top: '10%',
                 bottom: '10%',
                 right: '0%',
             },
             yAxis: {
                 type: 'value',
                 axisLabel: {
-                    show: true, 
+                    show: true,
                     color: '#fff'
                 },
                 splitLine: {
-                    show: false, 
+                    show: false,
                     lineStyle: {
-                        color: '#44585e' 
+                        color: '#44585e'
                     }
                 },
                 axisTick: {
-                    show: false 
+                    show: false
                 },
             },
             series: [
@@ -80,7 +84,8 @@ onMounted(() => {
                     name: '24小时水能耗',
                     type: 'line',
                     // 生成 24 个随机数据
-                    data: generateRandomData(24, 50), 
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     lineStyle: {
                         color: 'rgb(49, 143, 247)',
                     },
@@ -114,6 +119,20 @@ onMounted(() => {
     }
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal),
+            },
+            series: [{
+                type: 'line',
+                data: Object.entries(newVal),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 21 - 7
src/views/system/energy/modules/running.vue

@@ -5,7 +5,7 @@
             <div class="_running_mains_left" id="runWidth" :style="{ '--heightRunning': heightRun + 'px' }">
                 <div class="_running_mains_left_tuan"></div>
                 <div class="_running_mains_left_conter">
-                    <div class="_running_mains_left_conter_num">62</div>
+                    <div class="_running_mains_left_conter_num">{{resultData.EnergyCount}}</div>
                     <div class="_running_mains_left_conter_text">能源总量</div>
                 </div>
             </div>
@@ -30,13 +30,27 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
-const runningList = ref([
-    { name: '能耗强度', state: '3541', color: '#15acaa' },
-    { name: '碳排总量', state: '134', color: '#FFC107' },
-    { name: '碳排强度', state: '16964', color: '#F44336' },
-    { name: '碳排总量', state: '645521', color: '#F44336' }
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
+const runningList = ref([
+    { name: '能耗强度', state: 0, color: '#15acaa' },
+    { name: '碳排总量', state: 0, color: '#FFC107' },
+    { name: '碳排强度', state: 0, color: '#F44336' },
 ])
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.EnergyIntensity
+        runningList.value[1].state = newVal.CarbonEmissions
+        runningList.value[2].state = newVal.CarbonIsntensity
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const heightRun = ref(0)
 // 生命周期
 onMounted(() => {
@@ -58,7 +72,7 @@ onMounted(() => {
         align-items: center;
 
         &_left {
-            width: 40%;
+            width: 50%;
             height: var(--heightRunning);
             position: relative;
             flex-shrink: 0;

+ 21 - 7
src/views/system/energy/modules/sameDay.vue

@@ -6,7 +6,7 @@
                 <div class="_sameDay_mains_left_tuan"></div>
                 <div class="_sameDay_mains_left_conter">
                     <div class="_sameDay_mains_left_conter_num">
-                        62<span style="font-size: 12px;">kwh</span>/5<span style="font-size: 12px;">T</span></div>
+                        {{resultData.PowerConsumption}}<span style="font-size: 12px;">kwh</span>/{{resultData.WaterConsumption}}<span style="font-size: 12px;">T</span></div>
                     <div class="_sameDay_mains_left_conter_text">今日实时电/水</div>
                 </div>
             </div>
@@ -31,15 +31,29 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const sameDayList = ref([
-    { name: '昨日用电', state: 152, color: '#15acaa' },
-    { name: '本月用电', state: 1933, color: '#15acaa' },
-    { name: '昨日用水', state: 2000, color: '#FFC107' },
-    { name: '本月用水', state: 7562, color: '#FFC107' },
-
+    { name: '昨日用电', state: 0, color: '#15acaa' },
+    { name: '本月用电', state: 0, color: '#15acaa' },
+    { name: '昨日用水', state: 0, color: '#FFC107' },
+    { name: '本月用水', state: 0, color: '#FFC107' },
 ])
 
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        sameDayList.value[0].state = newVal.YesterdayConsumption
+        sameDayList.value[1].state = newVal.MonthElectricityConsumption
+        sameDayList.value[2].state = newVal.YesterdayWaterConsumption
+        sameDayList.value[3].state = newVal.MonthWaterConsumption
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const heightDay = ref(0)
 // 生命周期
 onMounted(() => {
@@ -62,7 +76,7 @@ onMounted(() => {
         align-items: center;
 
         &_left {
-            width: 40%;
+            width: 50%;
             height: var(--heightSameDay);
             position: relative;
             flex-shrink: 0;

+ 24 - 10
src/views/system/entranceguard/alleyway.vue

@@ -6,15 +6,15 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartAccess = ref(null);
 let chartDom = null;
-const initAccess = () => {
+const initAccess = (val1, val2, val3) => {
     const hexToRgb = hex => {
         const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
         hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b)
@@ -27,15 +27,15 @@ const initAccess = () => {
             }
             : null
     }
-    let xData = ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00', '00:00']
+    let xData = val1
     const yData = [
         {
             name: '每日总量',
-            data: [100, 120, 200, 210, 130, 160, 280, 240, 260, 200, 270, 280, 120],
+            data: val2,
         },
         {
             name: '累计总量',
-            data: [60, 80, 100, 110, 80, 100, 90, 180, 160, 140, 200, 220, 275, 100],
+            data: val3,
         },
     ]
     const xAxisFn = xData => {
@@ -53,7 +53,9 @@ const initAccess = () => {
         ]
     }
     const colorList = ['#107FFF', '#55D1FD',]
-    chartDom = echarts.init(chartAccess.value);
+    if (!chartDom) {
+        chartDom = echarts.init(chartAccess.value);
+    }
     let option = {
         series: yData.map((item, index) => {
             const rgb = hexToRgb(colorList[index])
@@ -140,9 +142,21 @@ const initAccess = () => {
     };
     chartDom.setOption(option)
 };
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        let xData = Object.keys(newVal.DailyTotal)
+        let y1Data = Object.entries(newVal.DailyTotal)
+        let y2Data = Object.entries(newVal.Cumulative)
+        initAccess(xData, y1Data, y2Data)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    let xData = ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00', '00:00']
+    let y1Data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    let y2Data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    initAccess(xData, y1Data, y2Data)
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 34 - 4
src/views/system/entranceguard/equipment.vue

@@ -7,7 +7,7 @@
                 </div>
                 <div class="equip_ment">
                     <div class="equip_ment_title">设备总数</div>
-                    <span class="num_ment blue_title">999</span>
+                    <span class="num_ment blue_title">{{ resultData.DeviceCount }}</span>
                 </div>
             </div>
             <div class="card_ment_equip">
@@ -16,7 +16,7 @@
                 </div>
                 <div class="equip_ment">
                     <div class="equip_ment_title">在线</div>
-                    <span class="num_ment yellow_title">999</span>
+                    <span class="num_ment yellow_title">{{ resultData.Online }}</span>
                 </div>
             </div>
             <div class="card_ment_equip">
@@ -25,7 +25,7 @@
                 </div>
                 <div class="equip_ment">
                     <div class="equip_ment_title">异常</div>
-                    <span class="num_ment green_title">999</span>
+                    <span class="num_ment green_title">{{ resultData.Abnormal }}</span>
                 </div>
             </div>
         </div>
@@ -36,11 +36,17 @@
 </template>
 
 <script setup>
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 const config = ref({
     headerBGC: '#10285c',
     oddRowBGC: '#10285c7f',
     evenRowBGC: '#10285c00',
-    header: ['设备名称', '位置', '列3'],
+    header: ['设备名称', '位置', '状态'],
     data: [
         ['行1列1', '行1列2', '行1列3'],
         ['行2列1', '行2列2', '行2列3'],
@@ -54,6 +60,30 @@ const config = ref({
         ['行10列1', '行10列2', '行10列3']
     ]
 })
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        let arrData = []
+        let arrData1 = newVal.AlarmList
+        if (arrData1 && arrData1.length > 0) {
+            arrData1.forEach(item => {
+                let arrData2 = []
+                arrData2.push(item.AlarmContent)
+                arrData2.push(item.Location)
+                let title = ''
+                if (item.State == 0) {
+                    title = '正常'
+                } else {
+                    title = '异常'
+                }
+                arrData2.push(title)
+                arrData2.push(item.Date)
+                arrData.push(arrData2)
+            })
+        }
+        // config.value.data = arrData
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 </script>
 
 <style scoped lang="scss">

+ 27 - 14
src/views/system/entranceguard/inbreak.vue

@@ -6,15 +6,15 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartDistrict = ref(null);
 let chartDom = null;
-const initAccess = () => {
+const initAccess = (val1, val2, val3) => {
     function xWrapText(params, num = 2) {
         let newParamsName = ''
         const paramsNameNumber = params.length
@@ -37,10 +37,12 @@ const initAccess = () => {
         }
         return newParamsName
     }
-    let xData = ['12.20', '12.30', '12.40', '12.50', '13.00']
-    let y1Data = [110, 90, 120, 70, 60]
-    let y2Data = [15, 22, 13, 22, 13]
-    chartDom = echarts.init(chartDistrict.value);
+    let xData = val1
+    let y1Data = val2
+    let y2Data = val3
+    if (!chartDom) {
+        chartDom = echarts.init(chartDistrict.value);
+    }
     let option = {
         grid: {
             left: '10%',
@@ -63,7 +65,7 @@ const initAccess = () => {
             },
         },
         legend: {
-            data: ['非法入侵', '非法入侵1'],
+            data: ['非法入侵', '强行闯入'],
             right: 'center',
             top: '6%',
             itemWidth: 11,
@@ -159,7 +161,7 @@ const initAccess = () => {
             data: y1Data,
         },
         {
-            name: '非法入侵1',
+            name: '强行闯入',
             type: 'bar',
             label: {
                 normal: {
@@ -189,16 +191,27 @@ const initAccess = () => {
             barWidth: '20%',
             yAxisIndex: 1,
             data: y2Data,
-
         },
-
         ],
     };
     chartDom.setOption(option)
 };
+
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        let xData = Object.keys(newVal.Invasio1)
+        let y1Data = Object.entries(newVal.Invasio1)
+        let y2Data = Object.entries(newVal.Invasio2)
+        initAccess(xData, y1Data, y2Data)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    let xData = ['12.20', '12.30', '12.40', '12.50', '13.00', '13.20', '13.40']
+    let y1Data = [0, 0, 0, 0, 0, 0, 0]
+    let y2Data = [0, 0, 0, 0, 0, 0, 0]
+    initAccess(xData, y1Data, y2Data)
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 25 - 6
src/views/system/entranceguard/index.vue

@@ -6,13 +6,13 @@
                     <div style="height: 500px;">
                         <HeadlineTag value="门禁设备"></HeadlineTag>
                         <div class="box_arch">
-                            <equipment></equipment>
+                            <equipment :resultData="leftData"></equipment>
                         </div>
                     </div>
                     <div class="flex_spection">
                         <HeadlineTag value="非法侵入统计"></HeadlineTag>
                         <div class="box_arch">
-                            <inbreak></inbreak>
+                            <inbreak :resultData="leftData"></inbreak>
                         </div>
                     </div>
                 </div>
@@ -20,21 +20,21 @@
             <template #right>
                 <div class="right_guard_flow">
                     <div class="flex_spection">
-                        <HeadlineTag type="right" value="今日通行数据概览"></HeadlineTag>
+                        <HeadlineTag type="right" value="今日出勤统计"></HeadlineTag>
                         <div class="box_arch">
-                            <passable></passable>
+                            <passable :resultData="leftData"></passable>
                         </div>
                     </div>
                     <div class="flex_spection">
                         <HeadlineTag type="right" value="出入记录统计"></HeadlineTag>
                         <div class="box_arch">
-                            <alleyway></alleyway>
+                            <alleyway :resultData="leftData"></alleyway>
                         </div>
                     </div>
                     <div class="flex_spection">
                         <HeadlineTag type="right" value="实时告警与通知"></HeadlineTag>
                         <div class="box_arch">
-                            <inform></inform>
+                            <inform :resultData="leftData"></inform>
                         </div>
                     </div>
                 </div>
@@ -44,6 +44,7 @@
 </template>
 
 <script setup>
+import { getAccess } from "@/api/system/access"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import alleyway from './alleyway'
@@ -51,6 +52,24 @@ import equipment from './equipment'
 import inbreak from './inbreak'
 import passable from './passable'
 import inform from './inform'
+
+// 生命周期
+onMounted(() => {
+    intervalId.value = setInterval(getAccessData, 10000);
+    getAccessData()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getAccessData() {
+    getAccess().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
 </script>
 
 <style scoped lang="scss">

+ 32 - 1
src/views/system/entranceguard/inform.vue

@@ -5,11 +5,17 @@
 </template>
 
 <script setup>
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 const config = ref({
     headerBGC: '#10285c',
     oddRowBGC: '#10285c7f',
     evenRowBGC: '#10285c00',
-    header: ['告警内容', '地点', '时间', '状态'],
+    header: ['告警内容', '地点', '状态', '时间'],
     data: [
         ['行1列1', '行1列2', '行1列3', '行1列3'],
         ['行1列1', '行1列2', '行1列3', '行1列3'],
@@ -23,6 +29,31 @@ const config = ref({
         ['行1列1', '行1列2', '行1列3', '行1列3'],
     ]
 })
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        let arrData = []
+        let arrData1 = newVal.AlarmList
+        if (arrData1 && arrData1.length > 0) {
+            arrData1.forEach(item => {
+                let arrData2 = []
+                arrData2.push(item.AlarmContent)
+                arrData2.push(item.Location)
+                let title = ''
+                if (item.State == 0) {
+                    title = '正常'
+                } else {
+                    title = '异常'
+                }
+                arrData2.push(title)
+                arrData2.push(item.Date)
+                arrData.push(arrData2)
+            })
+        }
+        config.value.data = arrData
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 </script>
 
 <style scoped lang="scss">

+ 24 - 14
src/views/system/entranceguard/passable.vue

@@ -6,8 +6,8 @@
                     <div class="line_blue">
                         <div class="blue_dot"></div>
                     </div>
-                    <div class="monit_title">在线</div>
-                    <span class="monit_num">83</span>
+                    <div class="monit_title">应到岗</div>
+                    <span class="monit_num">{{ resultData.Fault }}人</span>
                 </div>
                 <div class="camera">
                     <div class="entry-box">
@@ -24,8 +24,8 @@
                     <div class="line_green">
                         <div class="green_dot"></div>
                     </div>
-                    <div class="monit_title">离线</div>
-                    <span class="monit_num">23</span>
+                    <div class="monit_title">实际到岗</div>
+                    <span class="monit_num">{{ resultData.Offline }}人</span>
                 </div>
             </div>
         </dv-border-box-1>
@@ -34,16 +34,19 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartDistrict = ref(null);
 let chartDom = null;
-const initAccess = () => {
-    chartDom = echarts.init(chartDistrict.value);
+const initAccess = (valueNum) => {
+    if (!chartDom) {
+        chartDom = echarts.init(chartDistrict.value);
+    }
+    let attendanceRate = valueNum
     let option = {
         graphic: {
             elements: [
@@ -69,7 +72,7 @@ const initAccess = () => {
                     left: 'center',
                     top: 110,
                     style: {
-                        text: '完成率',
+                        text: '出勤率',
                         textAlign: 'center',
                         fill: '#75AFFC',
                         fontSize: 12,
@@ -179,7 +182,7 @@ const initAccess = () => {
                 data: [
                     {
                         name: '完成率',
-                        value: 82,
+                        value: attendanceRate,
                     },
                 ],
             },
@@ -232,7 +235,7 @@ const initAccess = () => {
                 data: [
                     {
                         name: '',
-                        value: 82,
+                        value: attendanceRate,
                     },
                 ],
             },
@@ -315,9 +318,16 @@ const initAccess = () => {
     };
     chartDom.setOption(option)
 };
+
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        initAccess(newVal.Abnormal)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    initAccess(0)
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 58 - 41
src/views/system/inspection/index.vue

@@ -24,21 +24,21 @@
             <HeadlineTag type="right" value="运行统计"></HeadlineTag>
             <div class="box_arch">
               <div class="image_tubbiness">
-                <div class="work_num">3714<span>个</span></div>
+                <div class="work_num">{{ leftData.TodayTotal }}<span>个</span></div>
                 <div class="work_title">今日总数</div>
               </div>
               <div class="right_content">
                 <div class="work_week">
                   <div class="color_line_xj" style="background-color: rgb(21, 213, 21);"></div>
-                  <span>巡检点数:</span>20
+                  <span>巡检点数:</span>{{ leftData.InspectionPoints }}
                 </div>
                 <div class="work_week">
                   <div class="color_line_xj" style="background-color: rgb(196, 127, 19);"></div>
-                  <span>巡检计划:</span>10
+                  <span>巡检计划:</span>{{ leftData.InspectionPlan }}
                 </div>
                 <div class="work_week">
                   <div class="color_line_xj" style="background-color: rgb(195, 56, 56);"></div>
-                  <span>巡检线路:</span>15
+                  <span>巡检线路:</span>{{ leftData.InspectTheLine }}
                 </div>
               </div>
             </div>
@@ -62,6 +62,7 @@
 </template>
 
 <script setup>
+import { getEndpoint } from "@/api/system/endpoint"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import Empty from '@/components/Empty'
@@ -76,7 +77,7 @@ const config = ref({
   headerBGC: '#10285c',
   oddRowBGC: '#10285c7f',
   evenRowBGC: '#10285c00',
-  header: ['名称', '位置', '列3'],
+  header: ['名称', '位置', '时间'],
   data: [
     ['行1列1', '行1列2', '行1列3'],
     ['行2列1', '行2列2', '行2列3'],
@@ -109,45 +110,17 @@ const initChart = () => {
       backgroundColor: 'rgba(0, 0, 0, 0.5)',
       extraCssText: 'backdrop-filter: blur(6px);',
     },
-    legend: {
-      data: ['产值', '增加值'],
-      icon: 'rich',
-      show: true,
-      itemWidth: 18,
-      itemHeight: 2,
-      textStyle: {
-        color: '#AFBDD1',
-        fontSize: '12px',
-      },
-      top: 8,
-      right: 10,
-      itemGap: 34,
-    },
     grid: {
-      left: '4%',
       right: '4%',
       bottom: '10%',
       top: '16%',
-      containLabel: true,
     },
     xAxis: {
-      data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
       type: 'category',
-      boundaryGap: false,
-      axisLine: {
-        symbol: 'none',
-        lineStyle: {
-          color: '#50637A',
-        },
-      },
-      axisTick: {
-        show: false,
-      },
+      // 使用 24 小时数据
+      data: [],
       axisLabel: {
-        interval: 0,
-        color: '#ffffff',
-        fontSize: 12,
-        padding: [10, 0, 0, 0],
+        color: '#fff'
       },
     },
     yAxis: {
@@ -198,7 +171,51 @@ const initChart = () => {
   });
 };
 // 生命周期
-onMounted(initChart);
+onMounted(() => {
+  intervalId.value = setInterval(getAccessData, 10000);
+  getAccessData()
+  initChart()
+});
+
+onUnmounted(() => {
+  clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getAccessData() {
+  getEndpoint().then((res) => {
+    if (res.code == 200) {
+      leftData.value = res.data
+    }
+  })
+}
+
+watch(() => leftData.value, (newVal) => {
+  if (chartInstance) {
+    chartInstance.setOption({
+      xAxis: {
+        data: Object.keys(newVal.Inspect),
+      },
+      series: [{
+        type: 'line',
+        data: Object.entries(newVal.Inspect),
+      }],
+    })
+  }
+  let arrData = []
+  let arrData1 = newVal.realTime
+  if (arrData1 && arrData1.length > 0) {
+    arrData1.forEach(item => {
+      let arrData2 = []
+      arrData2.push(item.Name)
+      arrData2.push(item.Location)
+      arrData2.push(item.Event)
+      arrData.push(arrData2)
+    })
+  }
+  config.value.data = arrData
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
   chartInstance?.resize();
@@ -236,7 +253,7 @@ window.addEventListener('resize', () => {
 }
 
 .operation_spection {
-  height: 250px;
+  height: 30%;
   color: #fff;
 }
 
@@ -255,7 +272,7 @@ window.addEventListener('resize', () => {
   position: relative;
   flex: none;
   width: 200px;
-  height: 100%;
+  height: 220px;
   background: url("@/assets/images/tubbiness.png");
   background-size: 80% 80%;
   background-position: center center;
@@ -263,7 +280,7 @@ window.addEventListener('resize', () => {
 
   .work_num {
     position: absolute;
-    top: 60px;
+    top: 70px;
     left: 0;
     right: 0;
     text-align: center;
@@ -278,7 +295,7 @@ window.addEventListener('resize', () => {
 
   .work_title {
     position: absolute;
-    bottom: 36px;
+    bottom: 43px;
     left: 0px;
     right: 0px;
     text-align: center;

+ 171 - 0
src/views/system/intruderalarm/alarm.vue

@@ -0,0 +1,171 @@
+<template>
+    <div class="_eventList">
+        <!-- 绑定鼠标移入移出事件 -->
+        <div class="_eventList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <!-- 复制一份数据用于无缝滚动 -->
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_eventList_mains_item" v-for="(item, index) in eventList" :key="index">
+                    <div class="_eventList_mains_item_text">
+                        <div :class="item.Name === 0 ? '_warning' : '_success'" class="_eventList_mains_item_text_flag">
+                        </div>
+                        <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
+                            {{ item.Name }}
+                        </el-text>
+                    </div>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Phone }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Location }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Date }}
+                    </el-text>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+// const eventList = ref([{
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }])
+
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal.realTime
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value.querySelector('._eventList_mains_item').offsetHeight
+        scrollY.value -= scrollSpeed
+        if (Math.abs(scrollY.value) >= itemHeight * eventList.value.length) {
+            scrollY.value = 0
+        }
+    }, 20)
+}
+
+const pauseCarousel = () => {
+    clearInterval(intervalId)
+}
+
+const resumeCarousel = () => {
+    startCarousel()
+}
+
+onMounted(async () => {
+    await nextTick();
+    startCarousel()
+})
+
+onUnmounted(() => {
+    clearInterval(intervalId)
+})
+</script>
+
+<style lang="scss" scoped>
+._success {
+    background: #15acaa;
+}
+
+._warning {
+    background: #FFC107;
+}
+
+._eventList {
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    height: calc(100% - 40px);
+
+    &_mains {
+        margin: 10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        // 鼠标移入时改变手势
+        cursor: pointer;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px 0;
+
+            &_text {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+
+                &_flag {
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    margin-left: 10px;
+                }
+
+                &_p {
+                    margin-left: 10px;
+                }
+            }
+        }
+
+        &_item:hover {
+            background-image: linear-gradient(to right, #168cdb, transparent);
+        }
+    }
+}
+</style>

+ 77 - 24
src/views/system/intruderalarm/index.vue

@@ -15,14 +15,15 @@
                             <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
                                 <el-input v-model="input" placeholder="按报警名称搜索" />
                             </div>
-                            <div style="height: calc(100% - 160px);">
+                            <alarm :resultData="leftData"></alarm>
+                            <!-- <div style="height: calc(100% - 160px);">
                                 <Empty></Empty>
                             </div>
                             <div class="center_in">
                                 <pagination :total="total" v-model:page="queryParams.pageNum"
                                     v-model:limit="queryParams.pageSize" layout="total, prev, pager, next"
                                     @pagination="getList" />
-                            </div>
+                            </div> -->
                         </div>
                     </div>
                 </div>
@@ -39,18 +40,18 @@
                                 </div>
                             </div>
                             <div class="left_water">
-                                <span class="water_span_title">75</span>
+                                <span class="water_span_title">{{ leftData.EventRisk }}</span>
                                 <div class="tile_fx">事件风险</div>
                             </div>
                             <div class="right_water">
-                                <span class="water_span_title">83</span>
+                                <span class="water_span_title">{{ leftData.AlarmRisk }}</span>
                                 <div class="tile_fx">告警风险</div>
                             </div>
                             <div class="box_water_drop">
                                 <div style="width: 140px;height: 140px;">
                                     <waterdrop width="100%" fontSize="32px" circleBackGround="rgb(8, 36, 62)"
-                                        birderColor="transparent" color="rgb(42, 139, 247)" heightTop="-50%"
-                                        dropTitle="50%"></waterdrop>
+                                        birderColor="transparent" color="rgb(42, 139, 247)"
+                                        :heightTop="'-' + leftData.trend + '%'" :dropTitle="leftData.trend + '%'"></waterdrop>
                                 </div>
                                 <!-- <div ref="chartWater" style="width: 140px;height: 140px;"></div> -->
                             </div>
@@ -76,10 +77,12 @@
 </template>
 
 <script setup>
+import { getInvade } from "@/api/system/invade"
 import waterdrop from '@/components/waterdrop'
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import Empty from '@/components/Empty'
+import alarm from './alarm.vue'
 import * as echarts from 'echarts'
 import 'echarts-liquidfill';
 const total = ref(0);
@@ -94,16 +97,16 @@ const config = ref({
     evenRowBGC: '#10285c00',
     header: ['名称', '位置', '列3'],
     data: [
-        ['行1列1', '行1列2', '行1列3'],
-        ['行2列1', '行2列2', '行2列3'],
-        ['行3列1', '行3列2', '行3列3'],
-        ['行4列1', '行4列2', '行4列3'],
-        ['行5列1', '行5列2', '行5列3'],
-        ['行6列1', '行6列2', '行6列3'],
-        ['行7列1', '行7列2', '行7列3'],
-        ['行8列1', '行8列2', '行8列3'],
-        ['行9列1', '行9列2', '行9列3'],
-        ['行10列1', '行10列2', '行10列3']
+        // ['行1列1', '行1列2', '行1列3'],
+        // ['行2列1', '行2列2', '行2列3'],
+        // ['行3列1', '行3列2', '行3列3'],
+        // ['行4列1', '行4列2', '行4列3'],
+        // ['行5列1', '行5列2', '行5列3'],
+        // ['行6列1', '行6列2', '行6列3'],
+        // ['行7列1', '行7列2', '行7列3'],
+        // ['行8列1', '行8列2', '行8列3'],
+        // ['行9列1', '行9列2', '行9列3'],
+        // ['行10列1', '行10列2', '行10列3']
     ]
 })
 
@@ -307,7 +310,7 @@ const initChart = () => {
 };
 const chartFacility = ref(null);
 let chartInstanceFacility = null;
-const initFacility = () => {
+const initFacility = (data, total) => {
     let nameList = [
         '超危报警',
         '高危报警',
@@ -315,9 +318,15 @@ const initFacility = () => {
         '低危报警',
         '设备预警',
     ];
-    let valueList = [612.5, 548.7, 300.2, 300, 400];
+    let valueList = [612.5, 548.7, 300.2, 300, 900];
+    if (data) {
+        valueList = data
+    }
     let colorList = ['#FB6A66', '#FFC949', '#867DFF', '#06CA70', '#008AFF'];
     let totalNum = 1000; // 数据总数
+    if (total) {
+        totalNum = total
+    }
     let emue = ['red', 'yellow', 'purple', 'green', 'blue'];
     var category = nameList.map((item, index) => {
         return {
@@ -348,7 +357,9 @@ const initFacility = () => {
     category.forEach((value) => {
         datas.push(value.value);
     });
-    chartInstanceFacility = echarts.init(chartFacility.value);
+    if (chartInstanceFacility == null) {
+        chartInstanceFacility = echarts.init(chartFacility.value);
+    }
     chartInstanceFacility.setOption({
         xAxis: {
             max: totalNum,
@@ -427,7 +438,6 @@ const initFacility = () => {
                 z: 1,
                 animationEasing: 'elasticOut',
             },
-
             {
                 // 分隔
                 type: 'pictorialBar',
@@ -490,7 +500,6 @@ const initFacility = () => {
                 data: datas,
                 z: 0,
             },
-
             {
                 name: '外框',
                 type: 'bar',
@@ -517,12 +526,56 @@ const initFacility = () => {
         ],
     });
 }
-
 // 生命周期
 onMounted(() => {
+    intervalId.value = setInterval(getInvadeData, 10000);
+    getInvadeData()
     initChart()
     initFacility()
 });
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getInvadeData() {
+    getInvade().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
+
+watch(() => leftData.value, (newVal) => {
+    if (chartInstance && chartInstanceFacility) {
+        let alarmArr = [newVal.OverHazardWarning, newVal.HighRiskWarning, newVal.MediumRiskWarning, newVal.LowRiskWarning, newVal.DeviceAlerts]
+        let sum = 0;
+        alarmArr.forEach(number => {
+            sum += number;
+        });
+        initFacility(alarmArr, sum)
+        chartInstance.setOption({
+            xAxis: {
+                data: Object.keys(newVal.AlarmTrend24Hour),
+            },
+            series: [{
+                type: 'line',
+                data: Object.entries(newVal.AlarmTrend24Hour),
+            }],
+        })
+        let arrData = []
+        let arrData1 = newVal.realTime
+        arrData1.forEach(item=>{
+            let arrData2 = []
+            arrData2.push(item.Name)
+            arrData2.push(item.Location)
+            arrData2.push(item.Event)
+            arrData.push(arrData2)
+        })
+        config.value.data = arrData
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
     chartInstance?.resize();
@@ -562,7 +615,7 @@ window.addEventListener('resize', () => {
 
 .operation_spection {
     position: relative;
-    height: 250px;
+    height: 30%;
     color: #fff;
 }
 
@@ -665,7 +718,7 @@ window.addEventListener('resize', () => {
 
     .entry-box-item {
         width: 100%;
-        height: 180px;
+        height: 100%;
         color: #fff;
         display: flex;
         justify-content: center;

+ 23 - 6
src/views/system/lighting/index.vue

@@ -3,17 +3,17 @@
         <layout>
             <template #left>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <deviceList />
+                    <deviceList :resultData="leftData.IlluminatingDevice" />
                 </div>
             </template>
             <template #content>
-                <p>照明</p>
+                <!-- <p>照明</p> -->
             </template>
             <template #right>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <running style="flex: 1;" />
-                    <switchAll style="flex: 1;" />
-                    <eventList style="flex: 1;" />
+                    <running :resultData="leftData" style="flex: 1;" />
+                    <switchAll :resultData="leftData.RunAnalyse" style="flex: 1;" />
+                    <eventList :resultData="leftData.EventList" style="flex: 1;" />
                 </div>
             </template>
         </layout>
@@ -21,13 +21,30 @@
 </template>
 
 <script setup name="Role">
+import { getIlluminating } from "@/api/system/illuminating"
 import layout from "@/components/layout_/index.vue";
 import deviceList from './modules/deviceList.vue'
 import running from './modules/running.vue'
 import eventList from './modules/eventList.vue'
 import switchAll from './modules/switchAll.vue'
 
-
+const intervalId = ref(null)
+const leftData = ref({})
+// 生命周期
+onMounted(() => {
+    intervalId.value = setInterval(getIlluminatingData, 10000);
+    getIlluminatingData()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+function getIlluminatingData() {
+    getIlluminating().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
 </script>
 <style lang="scss">
 ._energy {

+ 67 - 46
src/views/system/lighting/modules/deviceList.vue

@@ -2,25 +2,29 @@
     <div class="_deviceList">
         <HeadlineTag value="设备列表" style="flex-shrink: 0;"></HeadlineTag>
         <div class="point_box" style="margin-top: 10px;">
-          <el-input v-model="value" placeholder="按巡查点名称搜索" />
+            <el-input v-model="value" placeholder="按巡查点名称搜索" />
         </div>
         <div class="_deviceList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
             <div :style="{ transform: `translateY(${scrollY}px)` }">
                 <div class="_deviceList_mains_item" v-for="(item, index) in eventList" :key="index">
                     <el-text class="w-150px mb-2 _table_row1" truncated style="color: white;flex: .4;">
                         <el-icon color="#168cdb">
-                            <el-icon><Opportunity /></el-icon>
+                            <el-icon>
+                                <Opportunity />
+                            </el-icon>
                         </el-icon>
-                        {{ item.name }}
+                        {{ item.DeviceName }}
                     </el-text>
                     <el-text class="w-150px mb-2" truncated style="color: white;flex: .2;">
-                        {{ item.state }}
+                        {{ item.state == 0 ? '开启' : '关闭' }}
                     </el-text>
                     <el-text class="w-150px mb-2" truncated style="color: white;flex: .2">
-                        {{ item.flag }}
+                        {{ item.OnlinePresence == 0 ? '在线' : '离线' }}
                     </el-text>
                     <el-icon color="#168cdb" style="flex: .2;">
-                        <el-icon><Aim /></el-icon>
+                        <el-icon>
+                            <Aim />
+                        </el-icon>
                     </el-icon>
                 </div>
             </div>
@@ -32,34 +36,49 @@
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import { Opportunity, Aim } from '@element-plus/icons-vue'
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+
 const value = ref('')
-const eventList = ref([
-    { name: '回路1', state: '开启', flag: '在线' },
-    { name: '回路2', state: '关闭', flag: '离线' },
-    { name: '回路3', state: '开启', flag: '在线' },
-    { name: '回路4', state: '关闭', flag: '离线' },
-    { name: '回路5', state: '开启', flag: '在线' },
-    { name: '回路6', state: '关闭', flag: '离线' },
-    { name: '回路7', state: '开启', flag: '在线' },
-    { name: '回路8', state: '关闭', flag: '离线' },
-    { name: '回路9', state: '开启', flag: '在线' },
-    { name: '回路10', state: '关闭', flag: '离线' },
-    { name: '回路11', state: '开启', flag: '在线' },
-    { name: '回路12', state: '关闭', flag: '离线' },
-    { name: '回路13', state: '开启', flag: '在线' },
-    { name: '回路14', state: '关闭', flag: '离线' },
-    { name: '回路15', state: '开启', flag: '在线' },
-    { name: '回路16', state: '关闭', flag: '离线' },
-    { name: '回路17', state: '开启', flag: '在线' },
-    { name: '回路18', state: '关闭', flag: '离线' },
-    { name: '回路19', state: '开启', flag: '在线' },
-    { name: '回路20', state: '关闭', flag: '离线' },
-    { name: '回路21', state: '开启', flag: '在线' },
-    { name: '回路22', state: '关闭', flag: '离线' },
-    { name: '回路23', state: '开启', flag: '在线' },
-    { name: '回路24', state: '关闭', flag: '离线' }
-])
+// const eventList = ref([
+//     { name: '回路1', state: '开启', flag: '在线' },
+//     { name: '回路2', state: '关闭', flag: '离线' },
+//     { name: '回路3', state: '开启', flag: '在线' },
+//     { name: '回路4', state: '关闭', flag: '离线' },
+//     { name: '回路5', state: '开启', flag: '在线' },
+//     { name: '回路6', state: '关闭', flag: '离线' },
+//     { name: '回路7', state: '开启', flag: '在线' },
+//     { name: '回路8', state: '关闭', flag: '离线' },
+//     { name: '回路9', state: '开启', flag: '在线' },
+//     { name: '回路10', state: '关闭', flag: '离线' },
+//     { name: '回路11', state: '开启', flag: '在线' },
+//     { name: '回路12', state: '关闭', flag: '离线' },
+//     { name: '回路13', state: '开启', flag: '在线' },
+//     { name: '回路14', state: '关闭', flag: '离线' },
+//     { name: '回路15', state: '开启', flag: '在线' },
+//     { name: '回路16', state: '关闭', flag: '离线' },
+//     { name: '回路17', state: '开启', flag: '在线' },
+//     { name: '回路18', state: '关闭', flag: '离线' },
+//     { name: '回路19', state: '开启', flag: '在线' },
+//     { name: '回路20', state: '关闭', flag: '离线' },
+//     { name: '回路21', state: '开启', flag: '在线' },
+//     { name: '回路22', state: '关闭', flag: '离线' },
+//     { name: '回路23', state: '开启', flag: '在线' },
+//     { name: '回路24', state: '关闭', flag: '离线' }
+// ])
 
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null
@@ -69,9 +88,7 @@ const startCarousel = () => {
     intervalId = setInterval(() => {
         const itemHeight = mainsRef.value?.querySelector('._deviceList_mains_item')?.offsetHeight;
         if (!itemHeight) return;
-
         scrollY.value -= scrollSpeed;
-
         // 检查第一个元素是否完全离开视口
         if (Math.abs(scrollY.value) >= itemHeight) {
             // 将第一个元素移到列表末尾
@@ -103,41 +120,45 @@ onUnmounted(() => {
 </script>
 
 <style lang="scss">
-._deviceList{
+._deviceList {
     overflow: hidden;
     display: flex;
     flex-direction: column;
-    &_mains{
-        margin:10px 30px;
+
+    &_mains {
+        margin: 10px 30px;
         overflow: hidden; // 隐藏溢出内容
         cursor: pointer;
-        &_item{
+
+        &_item {
             display: flex;
             justify-content: space-between;
             padding: 10px;
         }
-        &_item:hover{
+
+        &_item:hover {
             cursor: pointer;
-            background-image: linear-gradient(to right, #168cdb, transparent); 
+            background-image: linear-gradient(to right, #168cdb, transparent);
         }
     }
 }
 </style>
 
 <style lang="scss" scoped>
-.point_box{
-    margin:10px 30px;
+.point_box {
+    margin: 10px 30px;
 }
+
 .point_box :deep(.el-input__wrapper) {
-  background-color: transparent !important;
-  box-shadow: 0 0 0 1px rgb(58, 86, 117) inset !important;
+    background-color: transparent !important;
+    box-shadow: 0 0 0 1px rgb(58, 86, 117) inset !important;
 }
 
 .point_box :deep(.el-input__wrapper.is-focus) {
-  box-shadow: 0 0 0 1px #409EFF inset !important;
+    box-shadow: 0 0 0 1px #409EFF inset !important;
 }
 
 .point_box :deep(.el-input__inner) {
-  color: #ffffff !important;
+    color: #ffffff !important;
 }
 </style>

+ 68 - 51
src/views/system/lighting/modules/eventList.vue

@@ -7,15 +7,14 @@
             <div :style="{ transform: `translateY(${scrollY}px)` }">
                 <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
                     <div class="_eventList_mains_item_text">
-                        <div
-                        :class="item.store === 'on' ? '_success' : '_warning'"
-                        class="_eventList_mains_item_text_flag"></div>
+                        <div :class="item.DeviceStatus === 0 ? '_success' : '_warning'"
+                            class="_eventList_mains_item_text_flag"></div>
                         <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
-                            {{ item.name }}
+                            {{ item.DeviceName }}
                         </el-text>
                     </div>
                     <el-text class="w-150px mb-2" truncated style="color: white;">
-                        {{ item.time }}
+                        {{ item.EventDate }}
                     </el-text>
                 </div>
             </div>
@@ -26,49 +25,62 @@
 <script setup>
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '设备启动1',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '设备启动2',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '设备停止3',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '设备启动4',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '设备停止5',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '设备停止6',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '设备启动7',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '设备停止8',
+//     time: '2025-04-15 10:20:00'
+// }])
 
-const eventList = ref([{
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '设备启动1',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '设备启动2',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '设备停止3',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '设备启动4',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '设备停止5',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '设备停止6',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '设备启动7',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '设备停止8',
-    time: '2025-04-15 10:20:00'
-}])
-
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null
@@ -103,11 +115,13 @@ onUnmounted(() => {
 
 <style lang="scss" scoped>
 ._success {
-    background: #15acaa;	
+    background: #15acaa;
 }
+
 ._warning {
-    background: #FFC107;	
+    background: #FFC107;
 }
+
 ._eventList {
     overflow: hidden;
     display: flex;
@@ -129,19 +143,22 @@ onUnmounted(() => {
                 display: flex;
                 justify-content: space-between;
                 align-items: center;
+
                 &_flag {
                     width: 10px;
                     height: 10px;
                     border-radius: 50%;
-                    margin-left: 10px; 
+                    margin-left: 10px;
                 }
+
                 &_p {
                     margin-left: 10px;
                 }
             }
         }
+
         &_item:hover {
-            background-image: linear-gradient(to right, #168cdb, transparent); 
+            background-image: linear-gradient(to right, #168cdb, transparent);
         }
     }
 }

+ 169 - 24
src/views/system/lighting/modules/running.vue

@@ -13,42 +13,33 @@
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import * as echarts from 'echarts'
-const runningList = ref([
-    { name: '开启数量', state: '61', color: '#15acaa' },
-    // { name:'关闭数量', state:'14', color:'#FFC107'},
-    { name: '故障数量', state: '34', color: '#F44336' }
-])
-
-// 计算比例的函数
-const calculateRatios = () => {
-    const total = runningList.value.reduce((sum, item) => sum + parseInt(item.state, 10), 0);
-    return runningList.value.map(item => ({
-        ...item,
-        ratio: total > 0 ? (parseInt(item.state, 10) / total) * 100 : 0
-    }));
-};
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartAccessLeft = ref(null);
-
 let chartLeft = null;
 let chartRight = null;
 const initAccess = () => {
     let data = [
         {
             name: '设备总数',
-            value: 13211,
+            value: 0,
         },
         {
             name: '开启数量',
-            value: 4211,
+            value: 0,
         },
         {
             name: '关闭数量',
-            value: 8171,
+            value: 0,
         },
         {
             name: '故障数量',
-            value: 1211,
+            value: 0,
         },
     ];
     let arrName = getArrayValue(data, 'name');
@@ -243,15 +234,169 @@ const initAccess = () => {
         ],
         series: optionData.series,
     };
-
-
     chartLeft.setOption(option)
+};
 
+watch(() => props.resultData, (newVal) => {
+    if (chartLeft) {
+        let data = [
+            {
+                name: '设备总数',
+                value: newVal.DeviceCount,
+            },
+            {
+                name: '开启数量',
+                value: newVal.OpenCount,
+            },
+            {
+                name: '关闭数量',
+                value: newVal.OffCount,
+            },
+            {
+                name: '故障数量',
+                value: newVal.FaultCount,
+            },
+        ];
+        let arrName = getArrayValue(data, 'name');
+        let arrValue = getArrayValue(data, 'value');
+        let sumValue = eval(arrValue.join('+'));
+        let objData = array2obj(data, 'name');
+        let optionData = getData(data);
+        function getArrayValue(array, key) {
+            var key = key || 'value';
+            var res = [];
+            if (array) {
+                array.forEach(function (t) {
+                    res.push(t[key]);
+                });
+            }
+            return res;
+        }
 
+        function array2obj(array, key) {
+            var resObj = {};
+            for (var i = 0; i < array.length; i++) {
+                resObj[array[i][key]] = array[i];
+            }
+            return resObj;
+        }
 
-
-
-};
+        function getData(data) {
+            var res = {
+                series: [],
+                yAxis: [],
+            };
+            for (let i = 0; i < data.length; i++) {
+                res.series.push({
+                    // name: '职员1',
+                    type: 'pie',
+                    clockWise: false, //顺时加载
+                    hoverAnimation: false, //鼠标移入变大
+                    radius: [65 - i * 15 + '%', 57 - i * 15 + '%'],
+                    center: ['30%', '55%'],
+                    label: {
+                        show: false,
+                    },
+                    itemStyle: {
+                        label: {
+                            show: false,
+                        },
+                        labelLine: {
+                            show: false,
+                        },
+                        borderWidth: 5,
+                    },
+                    data: [
+                        {
+                            value: data[i].value,
+                            name: data[i].name,
+                        },
+                        {
+                            value: sumValue - data[i].value,
+                            name: '',
+                            itemStyle: {
+                                color: 'rgba(0,0,0,0)',
+                                borderWidth: 0,
+                            },
+                            tooltip: {
+                                show: false,
+                            },
+                            hoverAnimation: false,
+                        },
+                    ],
+                });
+                res.series.push({
+                    name: '',
+                    type: 'pie',
+                    silent: true,
+                    z: 1,
+                    clockWise: false, //顺时加载
+                    hoverAnimation: false, //鼠标移入变大
+                    radius: [65 - i * 15 + '%', 57 - i * 15 + '%'],
+                    center: ['30%', '55%'],
+                    label: {
+                        show: false,
+                    },
+                    itemStyle: {
+                        label: {
+                            show: false,
+                        },
+                        labelLine: {
+                            show: false,
+                        },
+                        borderWidth: 5,
+                    },
+                    data: [
+                        {
+                            value: 7.5,
+                            itemStyle: {
+                                color: '#E3F0FF',
+                                borderWidth: 0,
+                            },
+                            tooltip: {
+                                show: false,
+                            },
+                            hoverAnimation: false,
+                        },
+                        {
+                            value: 2.5,
+                            name: '',
+                            itemStyle: {
+                                color: 'rgba(0,0,0,0)',
+                                borderWidth: 0,
+                            },
+                            tooltip: {
+                                show: false,
+                            },
+                            hoverAnimation: false,
+                        },
+                    ],
+                });
+                res.yAxis.push(((data[i].value / sumValue) * 100).toFixed(2) + '%');
+            }
+            return res;
+        }
+        chartLeft.setOption({
+            legend: {
+                data: arrName,
+                formatter: function (name) {
+                    return '{title|' + name + '}-{value|' + objData[name].value + '}';
+                },
+            },
+            xAxis: [
+                {
+                    show: true,
+                },
+            ],
+            yAxis: [{
+                type: 'category',
+                data: optionData.yAxis,
+            }],
+            series: optionData.series,
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
     initAccess()

+ 67 - 26
src/views/system/lighting/modules/switchAll.vue

@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,23 +27,20 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
-const handleResize = () => {
+ const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         const option = {
-            title: null, 
+            title: null,
             tooltip: {
                 trigger: 'axis'
             },
-            legend: false, 
+            legend: false,
             // 调整 grid 配置以在 Y 轴方向拉伸图表
             grid: {
                 top: '10%', // 减小顶部边距,让图表向上扩展
@@ -47,16 +49,16 @@ onMounted(() => {
             },
             xAxis: {
                 type: 'category',
-                data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+                data: [],
                 axisLabel: {
-                    color: '#fff' 
+                    color: '#fff'
                 },
             },
             yAxis: {
                 type: 'value',
                 axisLabel: {
                     show: true, // 不显示刻度标签
-                    color: '#fff' 
+                    color: '#fff'
                 },
                 // 配置 Y 轴网格刻线
                 splitLine: {
@@ -74,7 +76,8 @@ onMounted(() => {
                     name: '开启数量',
                     type: 'line',
                     smooth: true,
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     showSymbol: false,
                     lineStyle: {
                         color: 'rgb(49, 143, 247)',
@@ -104,7 +107,8 @@ onMounted(() => {
                     name: '关闭数量',
                     type: 'line',
                     smooth: true,
-                    data: generateRandomData(9, 60), 
+                    // data: generateRandomData(9, 60),
+                    data: [],
                     showSymbol: false,
                     lineStyle: {
                         color: 'rgb(255,193,7)',
@@ -134,7 +138,8 @@ onMounted(() => {
                     name: '故障数量',
                     type: 'line',
                     smooth: true,
-                    data: generateRandomData(5, 30), 
+                    // data: generateRandomData(9, 60),
+                    data: [],
                     showSymbol: false,
                     lineStyle: {
                         color: 'rgb(244,67,54)'
@@ -168,6 +173,36 @@ onMounted(() => {
     window.addEventListener('resize', handleResize);
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        let arrData = Object.keys(newVal)
+        let arr1 = []
+        let arr2 = []
+        let arr3 = []
+        arrData.forEach((item) => {
+            let data = Object.entries(newVal[item])
+            arr1.push(data[0][1])
+            arr2.push(data[1][1])
+            arr3.push(data[2][1])
+        })
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal),
+            },
+            series: [{
+                name: '开启数量',
+                data: arr1,
+            }, {
+                name: '关闭数量',
+                data: arr2,
+            }, {
+                name: '故障数量',
+                data: arr3,
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {
@@ -177,25 +212,29 @@ onUnmounted(() => {
 </script>
 
 <style lang="scss">
-._divider{
+._divider {
     height: 1px;
     border: 1px dashed #168cdb;
     flex: 1;
     margin: 0 10px;
 }
-._switchAll{
+
+._switchAll {
     display: flex;
     flex-direction: column;
-    &_mains{
-        margin:10px 30px;
+
+    &_mains {
+        margin: 10px 30px;
         flex: 1;
         display: flex;
-        &_item{
+
+        &_item {
             display: flex;
             justify-content: space-between;
             align-items: center;
             padding: 10px;
-            &_name{
+
+            &_name {
                 width: 30px;
                 height: 30px;
                 background: url("@/assets/images/content_circle_num.png");
@@ -203,18 +242,20 @@ onUnmounted(() => {
                 background-position: center;
                 background-repeat: no-repeat;
                 // animation: scanning 4s linear infinite;
-                border: 1px solid red; 
+                border: 1px solid red;
             }
-            &_flag{
+
+            &_flag {
                 display: flex;
                 align-items: center;
                 gap: 3px;
-                &_item{
+
+                &_item {
                     width: 30px;
                     height: 30px;
                     border: 3px dashed #168cdb;
                     box-sizing: border-box;
-                    background:#0e6ead;
+                    background: #0e6ead;
                     color: #fff;
                     border-radius: 50%;
                     display: flex;
@@ -224,11 +265,11 @@ onUnmounted(() => {
                 }
             }
         }
-        &_item:hover{
+
+        &_item:hover {
             cursor: pointer;
-            background-image: linear-gradient(to right, #168cdb, transparent); 
+            background-image: linear-gradient(to right, #168cdb, transparent);
         }
     }
 }
-
 </style>

+ 24 - 8
src/views/system/message/index.vue

@@ -3,18 +3,18 @@
      <layout>
          <template #left>
             <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                <running style="flex: 1;"/>
-                <carbonEmission style="flex:1;"/>
+                <running :resultData="leftData" style="flex: 1;"/>
+                <carbonEmission :resultData="leftData.Information" style="flex:1;"/>
              </div>
          </template>
          <template #content>
-             <p>信息</p>
+             <!-- <p>信息</p> -->
          </template>
          <template #right>
             <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                <consume  style="flex:1;"/>
-                <tiring style="flex: 1;"/>
-                <sameDay style="flex: 1;"/>
+                <consume  :resultData="leftData" style="flex:1;"/>
+                <tiring :resultData="leftData.Readings" style="flex: 1;"/>
+                <sameDay :resultData="leftData.Large" style="flex: 1;"/>
              </div>
          </template>
      </layout>
@@ -22,15 +22,31 @@
  </template>
  
  <script setup name="Role">
+import { getInformation } from "@/api/system/information"
  import layout from "@/components/layout_/index.vue";
-
  import running from './modules/running.vue'
  import consume from './modules/consume.vue'
  import carbonEmission from "./modules/carbonEmission.vue";
  import sameDay from './modules/sameDay.vue'
  import tiring from './modules/tiring.vue'
 
- 
+const intervalId = ref(null)
+const leftData = ref({})
+// 生命周期
+onMounted(() => {
+    intervalId.value = setInterval(getInformationData, 10000);
+    getInformationData()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+function getInformationData() {
+    getInformation().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
  </script> 
  <style lang="scss">
  ._energy{

+ 39 - 9
src/views/system/message/modules/carbonEmission.vue

@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,17 +27,14 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 信息类型
         const infoTypes = ['紧急通知', '政策法规', '活动预告', '其他'];
         // 生成随机占比数据
@@ -41,7 +43,6 @@ onMounted(() => {
             name: type,
             value: randomData[index]
         }));
-
         const option = {
             // 添加动画效果
             animation: true,
@@ -60,7 +61,8 @@ onMounted(() => {
                 orient: 'horizontal', // 图例水平排列
                 bottom: '0%', // 增大距离底部的距离,可根据需求调整
                 left: 'center', // 水平居中
-                data: infoTypes,
+                // data: infoTypes,
+                data: [],
                 textStyle: {
                     color: '#fff'
                 }
@@ -69,7 +71,8 @@ onMounted(() => {
                 {
                     name: '信息类型',
                     type: 'pie',
-                    data: data,
+                    // data: data,
+                    data: [],
                     radius: ['40%', '70%'],
                     roseType: 'radius',
                     stillShowZeroSum: false,
@@ -84,7 +87,7 @@ onMounted(() => {
                     emphasis: {
                         itemStyle: {
                             // 鼠标悬停时加大圆角
-                            borderRadius: 12 
+                            borderRadius: 12
                         }
                     },
                     label: {
@@ -112,7 +115,34 @@ onMounted(() => {
     }
     window.addEventListener('resize', handleResize);
 });
-
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        let data = [{
+            name: newVal[0].InformationType,
+            value: newVal[0].UseState
+        }, {
+            name: newVal[1].InformationType,
+            value: newVal[1].UseState
+        }, {
+            name: newVal[2].InformationType,
+            value: newVal[2].UseState
+        }, {
+            name: newVal[3].InformationType,
+            value: newVal[3].UseState
+        }]
+        let legendData = [newVal[0].InformationType, newVal[1].InformationType, newVal[2].InformationType, newVal[3].InformationType]
+        chart.setOption({
+            legend: {
+                data: legendData,
+            },
+            series: [{
+                name: '信息类型',
+                data: data,
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 9 - 3
src/views/system/message/modules/consume.vue

@@ -5,21 +5,21 @@
             <div class="_runnings_mains_left" id="sumeWidth">
                 <div class="_runnings_mains_left_tuan tuan1"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">75</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.UrgentNotice}}</div>
                     <div class="_runnings_mains_left_conter_text">紧急通知</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan2"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">54</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.Policy}}</div>
                     <div class="_runnings_mains_left_conter_text">政策法规</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan3"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">18</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.Activity}}</div>
                     <div class="_runnings_mains_left_conter_text">活动预告</div>
                 </div>
             </div>
@@ -30,6 +30,12 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 const runningList = ref([
     { name: '入侵检测', state: '154', color: '#409eff', tip: '划定区域人员闯入' },
     { name: '异常行为', state: '15', color: '#15acaa', tip: '徘徊、倒地、聚集' },

+ 66 - 32
src/views/system/message/modules/running.vue

@@ -1,26 +1,25 @@
 <template>
     <div class="_running">
         <HeadlineTag value="实时设备统计"></HeadlineTag>
-
         <div class="_running_mains">
-            <div class="_running_mains_left">
+            <div class="_running_mains_left" id="videoWidth" :style="{ '--heightRun': heightVideo + 'px' }">
                 <div class="_running_mains_left_tuan"></div>
                 <div class="_running_mains_left_conter">
-                    <div class="_running_mains_left_conter_num">38</div>
+                    <div class="_running_mains_left_conter_num">{{getTotal()}}</div>
                     <div class="_running_mains_left_conter_text">大屏总量</div>
                 </div>
             </div>
             <div class="_running_mains_right">
-                <div class="_running_mains_right_item" v-for="item,index in runningList" :key="index">
+                <div class="_running_mains_right_item" v-for="item, index in runningList" :key="index">
                     <div class="_running_mains_right_item_tuan">
-                        <span class="_running_mains_right_item_tuan_flag" :style="{backgroundColor: item.color}"></span>
+                        <span class="_running_mains_right_item_tuan_flag" :style="{ backgroundColor: item.color }"></span>
                         <el-text class="w-150px mb-2" truncated style="color: #ccc;">
-                            {{item.name}}
+                            {{ item.name }}
                         </el-text>
                     </div>
                     <div class="_running_mains_right_item__txt">
-                        <span>{{item.state}}</span> 
-                        <span :style="{color:item.color,'font-size':'12px','margin-left':'5px'}">{{item.unit}}</span>
+                        <span>{{ item.state }}</span>
+                        <span :style="{ color: item.color, 'font-size': '12px', 'margin-left': '5px' }">{{ item.unit }}</span>
                     </div>
                 </div>
             </div>
@@ -31,28 +30,54 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
-import { color } from "echarts";
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
 const runningList = ref([
-    { name:'正常', state:'20', color:'#409eff', unit:'台'},
-    { name:'故障', state:'18', color:'rgb(244, 67, 54)', unit:'台'},
-    { name:'空闲', state:'15', color:'#15acaa', unit:'台'},
+    { name: '正常', state: 0, color: '#409eff', unit: '台' },
+    { name: '故障', state: 0, color: 'rgb(244, 67, 54)', unit: '台' },
+    { name: '空闲', state: 0, color: '#15acaa', unit: '台' },
 ])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.Normal
+        runningList.value[1].state = newVal.Fault
+        runningList.value[2].state = newVal.Idle
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+function getTotal (){
+    let num = runningList.value[0].state + runningList.value[1].state + runningList.value[2].state
+    return num
+}
+const heightVideo = ref(0)
+// 生命周期
+onMounted(() => {
+    var element = document.getElementById("videoWidth");
+    var width = element.offsetWidth;
+    heightVideo.value = width
+});
 </script>
 <style lang="scss">
 ._running {
     display: flex;
     flex-direction: column;
+
     &_mains {
         flex: 1;
         margin: 30px;
         display: flex;
         align-items: center;
+
         &_left {
-            width: 180px;
-            height: 180px;
+            width: 50%;
+            height: var(--heightRun);
             position: relative;
-            flex-shrink: 0;
-            &_tuan{
+
+            &_tuan {
                 width: 100%;
                 height: 100%;
                 background: url("@/assets/images/content_circle.png");
@@ -61,11 +86,12 @@ const runningList = ref([
                 background-repeat: no-repeat;
                 animation: scanning 4s linear infinite;
             }
+
             &_conter {
                 position: absolute;
                 left: 0;
                 top: 0;
-            	flex-shrink: 0;
+                flex-shrink: 0;
                 width: 100%;
                 height: 100%;
                 display: flex;
@@ -73,27 +99,33 @@ const runningList = ref([
                 align-items: center;
                 justify-content: center;
                 color: #fff;
+
                 &_num {
                     font-size: 18px;
                 }
+
                 &_text {
                     font-size: 12px;
-                }	
+                }
             }
         }
+
         &_right {
-            margin-left:10px;
-           flex: 1;
-           color: #fff;
-           &_item{
+            margin-left: 10px;
+            flex: 1;
+            color: #fff;
+
+            &_item {
                 display: flex;
-                align-items: center; 
+                align-items: center;
                 gap: 40px;
                 padding: 5px 0;
+
                 &_tuan {
                     display: flex;
-                    align-items: center; 
-                    &_flag{
+                    align-items: center;
+
+                    &_flag {
                         display: block;
                         width: 7px;
                         height: 7px;
@@ -101,18 +133,20 @@ const runningList = ref([
                         margin-right: 10px;
                     }
                 }
-                &__txt{
-                    font-size:24px;
+
+                &__txt {
+                    font-size: 24px;
                 }
             }
         }
 
-        
+
     }
 }
+
 @keyframes scanning {
-		to {
-			transform: rotate(1turn);
-		}
-	}
+    to {
+        transform: rotate(1turn);
+    }
+}
 </style>

+ 59 - 47
src/views/system/message/modules/sameDay.vue

@@ -11,10 +11,11 @@
                             </el-icon> -->
                         </div>
                         <el-text class="w-150px mb-2" truncated style="color: #fff;">
-                            {{ index + 1 }}F#{{ item.name }}
+                            {{ index + 1 }}F#{{ item.DeviceName }}
                         </el-text>
                     </div>
-                    <div class="_xian" :class="item.store == 'on' ? '_success' : '_warning'">{{ item.store == 'on' ? '播放' : '空闲' }}</div>
+                    <div class="_xian" :class="item.UseState == 0 ? '_success' : '_warning'">{{ item.UseState == 0 ?
+                        '播放' : '空闲' }}</div>
                     <div class="_eventList_mains_item_btn">
                         <div class="_eventList_mains_item_btn_plays">播放</div>
                         <div class="_eventList_mains_item_btn_plays">暂停</div>
@@ -28,49 +29,62 @@
 <script setup>
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
-
-const eventList = ref([{
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '栋显示大屏',
-    time: '2025-04-15 10:20:00'
-}])
-
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '栋显示大屏',
+//     time: '2025-04-15 10:20:00'
+// }])
+
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null
@@ -80,9 +94,7 @@ const startCarousel = () => {
     intervalId = setInterval(() => {
         const itemHeight = mainsRef.value?.querySelector('._eventList_mains_item')?.offsetHeight;
         if (!itemHeight) return;
-
         scrollY.value -= scrollSpeed;
-
         // 检查第一个元素是否完全离开视口
         if (Math.abs(scrollY.value) >= itemHeight) {
             // 将第一个元素移到列表末尾

+ 27 - 8
src/views/system/message/modules/tiring.vue

@@ -11,24 +11,26 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 // 模拟不同年龄段的阅读量数据
-const ageGroupReadData = [30, 50, 70, 40, 20]; 
+const ageGroupReadData = [30, 50, 70, 40, 20];
 const ageGroups = ['30岁以下', '30 - 40岁', '40 - 50岁', '50 - 60岁', '60岁以上'];
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         const option = {
             xAxis: {
                 type: 'category',
@@ -71,12 +73,13 @@ onMounted(() => {
                 {
                     name: '阅读量',
                     type: 'bar',
-                    data: ageGroupReadData,
+                    // data: ageGroupReadData,
+                    data: [],
                     // 设置柱子宽度
-                    barWidth: '40%', 
+                    barWidth: '40%',
                     itemStyle: {
                         // 设置柱子圆角,仅上下圆角
-                        borderRadius: [10, 10, 10, 10], 
+                        borderRadius: [10, 10, 10, 10],
                         // 设置渐变颜色
                         color: {
                             type: 'linear',
@@ -111,6 +114,22 @@ onMounted(() => {
     window.addEventListener('resize', handleResize);
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        let dataArr = []
+        let arr = Object.entries(newVal)
+        arr.forEach(item=>{
+            dataArr.push(item[1])
+        })
+        chart.setOption({
+            series: [{
+                name: '阅读量',
+                data: dataArr,
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 44 - 13
src/views/system/passageway/Personnel.vue

@@ -11,23 +11,28 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartAccessLeft = ref(null);
 const chartAccessRight = ref(null);
 let chartLeft = null;
 let chartRight = null;
-const initAccess = () => {
-    const datas = {
-        value: 63.5,
-        text: "在线率"
+const initAccess = (value, type) => {
+    // const datas = {
+    //     value: 63.5,
+    //     text: "出人员"
+    // }
+    const datas = value
+    if (!chartLeft) {
+        chartLeft = echarts.init(chartAccessLeft.value);
+    }
+    if (!chartRight) {
+        chartRight = echarts.init(chartAccessRight.value);
     }
-    chartLeft = echarts.init(chartAccessLeft.value);
-    chartRight = echarts.init(chartAccessRight.value);
     let option = {
         series: [
             /*仪表盘图,做中间刻度线*/
@@ -155,12 +160,38 @@ const initAccess = () => {
             }
         ]
     };
-    chartLeft.setOption(option)
-    chartRight.setOption(option)
+    if (type == 'out' && chartLeft) {
+        chartLeft.setOption(option)
+    }
+    if (type == 'into' && chartRight) {
+        chartRight.setOption(option)
+    }
 };
+watch(() => props.resultData, (newVal) => {
+    if (newVal.Out) {
+        let valueOut = {
+            value: newVal.Out,
+            text: "人员(出)"
+        }
+        initAccess(valueOut, 'out')
+    }
+    if (newVal.Into) {
+        let valueInto = {
+            value: newVal.Into,
+            text: "人员(入)"
+        }
+        initAccess(valueInto, 'into')
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    let value = {
+        value: [],
+        text: ""
+    }
+    initAccess(value,'out')
+    initAccess(value,'into')
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 38 - 6
src/views/system/passageway/index.vue

@@ -30,7 +30,7 @@
                       <div class="blue_dot"></div>
                     </div>
                     <div class="monit_title">在线</div>
-                    <span class="monit_num">83</span>
+                    <span class="monit_num">{{ leftData.Online }}</span>
                   </div>
                   <div class="camera">
                     <div class="entry-box">
@@ -56,7 +56,7 @@
                       <div class="green_dot"></div>
                     </div>
                     <div class="monit_title">离线</div>
-                    <span class="monit_num">23</span>
+                    <span class="monit_num">{{ leftData.Offline }}</span>
                   </div>
                 </div>
               </dv-border-box-1>
@@ -77,7 +77,7 @@
           <div class="flex_spection">
             <HeadlineTag type="right" value="出入人员统计"></HeadlineTag>
             <div class="box_arch">
-              <Personnel></Personnel>
+              <Personnel :resultData="leftData"></Personnel>
             </div>
           </div>
         </div>
@@ -87,6 +87,7 @@
 </template>
 
 <script setup>
+import { getAccess } from "@/api/system/passageway"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import Personnel from './Personnel.vue'
@@ -124,8 +125,10 @@ const chartRouting = ref(null);
 let chartInstance = null;
 // 初始化图表
 const initChart = () => {
-  var data = [91, 82, 73, 61, 54, 46];
-  var yAxis = ['北京市', '天津市', '河北省', '吉林省', '辽宁省', '内蒙古']
+  // var data = [91, 82, 73, 61, 54, 46];
+  var data = [];
+  // var yAxis = ['北京市', '天津市', '河北省', '吉林省', '辽宁省', '内蒙古']
+  var yAxis = []
   chartInstance = echarts.init(chartRouting.value);
   chartInstance.setOption({
     tooltip: {
@@ -248,8 +251,37 @@ const initChart = () => {
 
 // 生命周期
 onMounted(() => {
+  intervalId.value = setInterval(getAccessData, 10000);
+  getAccessData()
   initChart()
 });
+onUnmounted(() => {
+  clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getAccessData() {
+  getAccess().then((res) => {
+    if (res.code == 200) {
+      leftData.value = res.data
+    }
+  })
+}
+
+watch(() => leftData.value, (newVal) => {
+  if (chartInstance) {
+    chartInstance.setOption({
+      yAxis: [{
+        data: newVal.DeviceRanking.map(person => person.DeviceName),
+      }],
+      series: [{
+        name: '标准化',
+        data: newVal.DeviceRanking.map(person => person.Value),
+      }],
+    })
+  }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
   chartInstance?.resize();
@@ -287,7 +319,7 @@ window.addEventListener('resize', () => {
 }
 
 .operation_spection {
-  height: 250px;
+  height: 30%;
   color: #fff;
 }
 

+ 27 - 15
src/views/system/passengerFlow/district.vue

@@ -6,15 +6,15 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartDistrict = ref(null);
 let chartDom = null;
-const initAccess = () => {
+const initAccess = (arrData) => {
     let colorList = [
         "rgba(255, 38, 38, 1)",
         "rgba(255, 96, 0, 1)",
@@ -45,14 +45,10 @@ const initAccess = () => {
         "rgba(142, 255, 206, 0.1)",
         "rgba(165, 232, 255, 0.1)",
     ];
-    let result = [
-        { name: "天水祥丰农资农贸有限公司", value: 86 },
-        { name: "天水花牛苹果", value: 83 },
-        { name: "天水红富士", value: 73 },
-        { name: "天水金帅苹果", value: 61 },
-        { name: "天水黄面皮", value: 61 },
-    ];
-    chartDom = echarts.init(chartDistrict.value);
+    let result = arrData
+    if (!chartDom) {
+        chartDom = echarts.init(chartDistrict.value);
+    }
     let option = {
         color: colorList,
         tooltip: {
@@ -207,7 +203,6 @@ const initAccess = () => {
                     fontSize: 14,
                     fontFamily: "Source Han Sans CN",
                     formatter: function (params) {
-                        console.log(params);
                         return params.data.name;
                     },
                 },
@@ -294,9 +289,26 @@ const initAccess = () => {
     };
     chartDom.setOption(option)
 };
+
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        let arr = newVal.Rankings
+        let result = Object.entries(arr).map(([name, value]) => ({ name, value }));
+        var firstFive = result.slice(0, 5)
+        initAccess(firstFive)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    let result = [
+        { name: "公司1", value: 0 },
+        { name: "公司2", value: 0 },
+        { name: "公司3", value: 0 },
+        { name: "公司4", value: 0 },
+        { name: "公司5", value: 0 },
+    ];
+    initAccess(result)
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 25 - 11
src/views/system/passengerFlow/earlyWarning.vue

@@ -16,40 +16,54 @@
         <div class="right_warning">
             <div class="box_equipment">
                 <span class="equi_title">网络设备</span>
-                <span class="equi_num">389</span>
+                <span class="equi_num">{{ networkDevices }}</span>
             </div>
             <div class="box_early_warn">
                 <div class="space_between_in card_eary">
                     <div class="type_title_early">正常</div>
-                    <div class="type_num_early">343个</div>
+                    <div class="type_num_early">{{ resultData.Normal }}个</div>
                 </div>
-                <el-progress :percentage="50" :text-inside="true" color="rgb(100, 178, 161)" />
+                <el-progress :percentage="getPercentage(resultData.Normal)" :text-inside="true"
+                    color="rgb(100, 178, 161)" />
             </div>
             <div class="box_early_warn">
                 <div class="space_between_in card_eary">
                     <div class="type_title_early">故障</div>
-                    <div class="type_num_early">33个</div>
+                    <div class="type_num_early">{{ resultData.Fault }}个</div>
                 </div>
-                <el-progress :percentage="50" :text-inside="true" color="rgb(230, 162, 60)" />
+                <el-progress :percentage="getPercentage(resultData.Fault)" :text-inside="true"
+                    color="rgb(230, 162, 60)" />
             </div>
             <div class="box_early_warn">
                 <div class="space_between_in card_eary">
                     <div class="type_title_early">离线</div>
-                    <div class="type_num_early">0个</div>
+                    <div class="type_num_early">{{ resultData.Offline }}个</div>
                 </div>
-                <el-progress :percentage="50" :text-inside="true" color="rgb(245, 108, 108)" />
+                <el-progress :percentage="getPercentage(resultData.Offline)" :text-inside="true"
+                    color="rgb(245, 108, 108)" />
             </div>
         </div>
     </div>
 </template>
 
 <script setup>
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
+const networkDevices = ref(0)
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        networkDevices.value = newVal.Normal + newVal.Fault + newVal.Offline
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+function getPercentage(params) {
+    let num = params / networkDevices.value * 100
+    return Math.floor(num)
+}
 // 生命周期
 onMounted(() => {
 });

+ 52 - 14
src/views/system/passengerFlow/index.vue

@@ -6,19 +6,19 @@
           <div class="flex_spection">
             <HeadlineTag value="客流监控"></HeadlineTag>
             <div class="box_arch">
-              <monitoring></monitoring>
+              <monitoring :resultData="leftData"></monitoring>
             </div>
           </div>
           <div class="flex_spection">
-            <HeadlineTag value="安全监控"></HeadlineTag>
+            <HeadlineTag value="安全监控等级"></HeadlineTag>
             <div class="box_arch">
-              <security></security>
+              <security :resultData="leftData"></security>
             </div>
           </div>
           <div class="flex_spection">
             <HeadlineTag value="实时预警信息"></HeadlineTag>
             <div class="box_arch">
-              <earlyWarning></earlyWarning>
+              <earlyWarning :resultData="leftData"></earlyWarning>
             </div>
           </div>
         </div>
@@ -28,7 +28,7 @@
           <div class="flex_spection">
             <HeadlineTag type="right" value="指标区客流排行榜"></HeadlineTag>
             <div class="box_arch">
-              <district></district>
+              <district :resultData="leftData"></district>
             </div>
           </div>
           <div class="flex_spection">
@@ -50,6 +50,7 @@
 </template>
 
 <script setup>
+import { getPassenger } from "@/api/system/passenger"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import monitoring from './monitoring'
@@ -63,7 +64,7 @@ const config = ref({
   headerBGC: '#10285c',
   oddRowBGC: '#10285c7f',
   evenRowBGC: '#10285c00',
-  header: ['名称', '位置', '列3'],
+  header: ['名称', '位置', '时间'],
   data: [
     ['行1列1', '行1列2', '行1列3'],
     ['行2列1', '行2列2', '行2列3'],
@@ -77,13 +78,11 @@ const config = ref({
     ['行10列1', '行10列2', '行10列3']
   ]
 })
-const initChart = () => {
-  let list = [
-    { name: "男性", value: 88 },
-    { name: "女性", value: 75 },
-    { name: "新老客", value: 66 }
-  ]
-  chartInstanceWater = echarts.init(chartFlow.value);
+const initChart = (arrData) => {
+  let list = arrData
+  if (!chartInstanceWater) {
+    chartInstanceWater = echarts.init(chartFlow.value);
+  }
   chartInstanceWater.setOption({
     grid: {
       left: '10%',
@@ -217,8 +216,47 @@ const initChart = () => {
 }
 // 生命周期
 onMounted(() => {
-  initChart()
+  intervalId.value = setInterval(getPassengerData, 10000);
+  getPassengerData()
+  let list = [
+    { name: "男性", value: 0 },
+    { name: "女性", value: 0 },
+    { name: "新老客", value: 0 }
+  ]
+  initChart(list)
 });
+onUnmounted(() => {
+  clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getPassengerData() {
+  getPassenger().then((res) => {
+    if (res.code == 200) {
+      leftData.value = res.data
+    }
+  })
+}
+watch(() => leftData.value, (newVal) => {
+  if (chartInstanceWater) {
+    let arr = newVal.Customers
+    let result = Object.entries(arr).map(([name, value]) => ({ name, value }));
+    initChart(result)
+    let arrData = []
+    let arrData1 = newVal.Event
+    if (arrData1 && arrData1.length > 0) {
+      arrData1.forEach(item => {
+        let arrData2 = []
+        arrData2.push(item.Name)
+        arrData2.push(item.Location)
+        arrData2.push(item.Event)
+        arrData.push(arrData2)
+      })
+    }
+    config.value.data = arrData
+  }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
   chartInstanceWater?.resize();

+ 26 - 15
src/views/system/passengerFlow/monitoring.vue

@@ -6,15 +6,15 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartAccess = ref(null);
 let chartDom = null;
-const initAccess = () => {
+const initAccess = (arrData, timeData) => {
     const color = ['#EAEA26', '#906BF9', '#FE5656', '#01E17E', '#3DD1F9', '#FFAD05']; //2个以上的series就需要用到color数组
     const legend = {
         //data,就是取得每个series里面的name属性。
@@ -44,12 +44,7 @@ const initAccess = () => {
         backgroundColor: 'rgba(0, 0, 0, 0.5)',
         extraCssText: 'backdrop-filter: blur(6px);',
     };
-    let seriesData = [
-        { name: '电子邮箱', data: [120, 132, 101, 134, 90, 230, 210] },
-        { name: '联盟广告', data: [220, 182, 191, 234, 290, 330, 310] },
-        { name: '视频广告', data: [150, 232, 201, 154, 190, 330, 410] },
-        { name: '直播', data: [320, 332, 301, 334, 390, 330, 320] },
-    ];
+    let seriesData = arrData
     const commonConfigFn = (index) => {
         return {
             type: 'line',
@@ -89,9 +84,10 @@ const initAccess = () => {
             },
         };
     };
-
     seriesData = seriesData.map((item, index) => ({ ...item, ...commonConfigFn(index) }));
-    chartDom = echarts.init(chartAccess.value);
+    if (!chartDom) {
+        chartDom = echarts.init(chartAccess.value);
+    }
     let option = {
         color,
         tooltip,
@@ -122,7 +118,7 @@ const initAccess = () => {
             splitLine: {
                 show: false, //不显示grid竖向分割线
             },
-            data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+            data: timeData,
         },
         yAxis: {
             type: 'value',
@@ -145,8 +141,23 @@ const initAccess = () => {
 };
 // 生命周期
 onMounted(() => {
-    initAccess()
+    let seriesData = [];
+    let time = []
+    initAccess(seriesData, time)
 });
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        let time = Object.keys(newVal.Type1)
+        let seriesData = [
+            { name: '客流1', data: Object.entries(newVal.Type1) },
+            { name: '客流2', data: Object.entries(newVal.Type2) },
+            { name: '客流3', data: Object.entries(newVal.Type3) },
+            { name: '客流4', data: Object.entries(newVal.Type4) },
+        ];
+        initAccess(seriesData, time)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
     chartDom?.resize();

+ 26 - 12
src/views/system/passengerFlow/security.vue

@@ -6,21 +6,19 @@
 
 <script setup>
 import * as echarts from 'echarts'
-defineProps({
-    title: {
-        type: String,
-        default: '暂无数据'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
     }
 })
 const chartAccess = ref(null);
 let chartDom = null;
-const initAccess = () => {
-    const demoData = [{
-        name: '安全等级',
-        value: 204,
-        unit: '分'
-    }];
-    chartDom = echarts.init(chartAccess.value);
+const initAccess = (dataVal) => {
+    const demoData = dataVal
+    if (!chartDom) {
+        chartDom = echarts.init(chartAccess.value);
+    }
     let option = {
         series: (function () {
             var result = [];
@@ -151,9 +149,25 @@ const initAccess = () => {
     };
     chartDom.setOption(option)
 };
+watch(() => props.resultData, (newVal) => {
+    if (chartDom) {
+        const demoData = [{
+            name: '安全等级',
+            value: newVal.SecurityLevel,
+            unit: '分'
+        }];
+        initAccess(demoData)
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
-    initAccess()
+    const demoData = [{
+        name: '安全等级',
+        value: 0,
+        unit: '分'
+    }];
+    initAccess(demoData)
 });
 // 窗口自适应
 window.addEventListener('resize', () => {

+ 11 - 11
src/views/system/tenement/index.vue

@@ -3,9 +3,9 @@
         <layout>
             <template #left>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <consume style="flex:1;" />
-                    <running style="flex: 1;" />
-                    <carbonEmission style="flex:1;" />
+                    <consume :resultData="leftData" style="flex:1;" />
+                    <running :resultData="leftData" style="flex: 1;" />
+                    <carbonEmission :resultData="leftData.Access" style="flex:1;" />
                 </div>
             </template>
             <template #content>
@@ -13,9 +13,9 @@
             </template>
             <template #right>
                 <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                    <eventList style="flex: 1;" />
-                    <sameDay style="flex: 1;" />
-                    <tiring style="flex: 1;" />
+                    <eventList :resultData="leftData.AccessRecords" style="flex: 1;" />
+                    <sameDay :resultData="leftData.GarageCount" style="flex: 1;" />
+                    <tiring :resultData="leftData.GarRecords" style="flex: 1;" />
                 </div>
             </template>
         </layout>
@@ -23,7 +23,7 @@
 </template>
 
 <script setup name="Role">
-import { getBroadcast } from "@/api/system/tenement"
+import { getProperty } from "@/api/system/tenement"
 import layout from "@/components/layout_/index.vue";
 import running from './modules/running.vue'
 import consume from './modules/consume.vue'
@@ -36,14 +36,14 @@ const intervalId = ref(null)
 const leftData = ref({})
 // 生命周期
 onMounted(() => {
-    intervalId.value = setInterval(getBroadcastData, 10000);
-    getBroadcastData()
+    intervalId.value = setInterval(getPropertyData, 10000);
+    getPropertyData()
 });
 onUnmounted(() => {
     clearInterval(intervalId.value);
 })
-function getBroadcastData() {
-    getBroadcast().then((res) => {
+function getPropertyData() {
+    getProperty().then((res) => {
         if (res.code == 200) {
             leftData.value = res.data
         }

+ 43 - 9
src/views/system/tenement/modules/carbonEmission.vue

@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,20 +27,16 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 生成一周的日期数据
-        const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
-
+        const weekDays = [];
         const option = {
             xAxis: {
                 type: 'category',
@@ -79,7 +80,8 @@ onMounted(() => {
                 {
                     name: '刷脸进入',
                     type: 'bar',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     barWidth: '30%',
                     itemStyle: {
                         color: {
@@ -102,7 +104,8 @@ onMounted(() => {
                 {
                     name: '刷卡进入',
                     type: 'line',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     lineStyle: {
                         color: '#3b90d7',
                     },
@@ -132,7 +135,8 @@ onMounted(() => {
                 {
                     name: '远程开门',
                     type: 'line',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     lineStyle: {
                         color: '#ffc107',
                     },
@@ -167,6 +171,36 @@ onMounted(() => {
     window.addEventListener('resize', handleResize);
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        let arrData = Object.keys(newVal)
+        let arr1 = []
+        let arr2 = []
+        let arr3 = []
+        arrData.forEach((item)=>{
+            let data = Object.entries(newVal[item])
+            arr1.push(data[0][1])
+            arr2.push(data[1][1])
+            arr3.push(data[2][1])
+        })
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal),
+            },
+            series: [{
+                name: '刷脸进入',
+                data: arr1,
+            },{
+                name: '刷卡进入',
+                data: arr2,
+            },{
+                name: '远程开门',
+                data: arr3,
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 18 - 3
src/views/system/tenement/modules/consume.vue

@@ -5,21 +5,21 @@
             <div class="_runnings_mains_left" id="sumeWidth">
                 <div class="_runnings_mains_left_tuan tuan1"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">785</div>
+                    <div class="_runnings_mains_left_conter_num">{{ resultData.HousesCount }}</div>
                     <div class="_runnings_mains_left_conter_text">房屋数</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan2"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">54</div>
+                    <div class="_runnings_mains_left_conter_num">{{ resultData.HouseholdCount }}</div>
                     <div class="_runnings_mains_left_conter_text">住户数</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan3"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">18</div>
+                    <div class="_runnings_mains_left_conter_num">{{ resultData.DrivewayCount }}</div>
                     <div class="_runnings_mains_left_conter_text">车位数</div>
                 </div>
             </div>
@@ -30,12 +30,27 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
 const runningList = ref([
     { name: '入侵检测', state: '154', color: '#409eff', tip: '划定区域人员闯入' },
     { name: '异常行为', state: '15', color: '#15acaa', tip: '徘徊、倒地、聚集' },
     { name: '丢失告警', state: '134', color: '#FFC107', tip: '物品遗留/丢失告警' },
 ])
 const heightcon = ref(0)
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.HousesCount
+        runningList.value[1].state = newVal.HouseholdCount
+        runningList.value[2].state = newVal.DrivewayCount
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 生命周期
 onMounted(() => {
     var element = document.getElementById("sumeWidth");

+ 61 - 49
src/views/system/tenement/modules/eventList.vue

@@ -6,19 +6,19 @@
                 <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
                     <div class="_eventList_mains_item_text">
                         <div
-                            :class="item.store === 'on' ? '_success' : '_warning'"
+                            :class="item.State === 0 ? '_success' : '_warning'"
                             class="_eventList_mains_item_text_flag">
-                            {{ item.store === 'on'?'进':'出' }}
+                            {{ item.State === 0?'进':'出' }}
                         </div>
                         <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
-                            {{ item.name }}
+                            {{ item.Name }}
                         </el-text>
                     </div>
-                    <div :style="{color:item.store === 'on'?'#15acaa':'#FFC107','font-size':'12px'}">
-                        {{ item.store === 'on'?'进入':'出入' }}
+                    <div :style="{color:item.State === 0?'#15acaa':'#FFC107','font-size':'12px'}">
+                        {{ item.State === 0?'进入':'出入' }}
                     </div>
                     <div class="_eventList_mains_item_btn">
-                        2025-04-15 10:20:00
+                        {{item.Date}}
                     </div>
                 </div>
             </div>
@@ -29,49 +29,61 @@
 <script setup>
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
-
-const eventList = ref([{
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '赵**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '陈**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '王**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '陈**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '李**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '陈**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '张**',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '杨**',
-    time: '2025-04-15 10:20:00'
-}])
-
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '赵**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '陈**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '王**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '陈**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '李**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '陈**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '张**',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '杨**',
+//     time: '2025-04-15 10:20:00'
+// }])
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null

+ 25 - 7
src/views/system/tenement/modules/running.vue

@@ -5,7 +5,7 @@
             <div class="_running_mains_left" id="videoWidth" :style="{ '--heightRun': heightVideo + 'px' }">
                 <div class="_running_mains_left_tuan"></div>
                 <div class="_running_mains_left_conter">
-                    <div class="_running_mains_left_conter_num">12212</div>
+                    <div class="_running_mains_left_conter_num">{{getTotal()}}</div>
                     <div class="_running_mains_left_conter_text">人口总数</div>
                 </div>
             </div>
@@ -32,13 +32,31 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
-import { color } from "echarts";
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
 const runningList = ref([
-    { name: '30岁以下', state: '154', color: '#409eff', unit: '人' },
-    { name: '40岁以下', state: '15', color: '#15acaa', unit: '人' },
-    { name: '50岁以下', state: '15', color: '#FFC107', unit: '人' },
-    { name: '60岁以上', state: '15', color: 'rgb(244, 67, 54)', unit: '人' },
+    { name: '30岁以下', state: 0, color: '#409eff', unit: '人' },
+    { name: '40岁以下', state: 0, color: '#15acaa', unit: '人' },
+    { name: '50岁以下', state: 0, color: '#FFC107', unit: '人' },
+    { name: '60岁以上', state: 0, color: 'rgb(244, 67, 54)', unit: '人' },
 ])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.Under30
+        runningList.value[1].state = newVal.Under40
+        runningList.value[2].state = newVal.Under50
+        runningList.value[3].state = newVal.More60
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+function getTotal (){
+    let num = runningList.value[0].state + runningList.value[1].state + runningList.value[2].state + runningList.value[3].state
+    return num
+}
 const heightVideo = ref(0)
 // 生命周期
 onMounted(() => {
@@ -59,7 +77,7 @@ onMounted(() => {
         align-items: center;
 
         &_left {
-            width: 40%;
+            width: 50%;
             height: var(--heightRun);
             position: relative;
 

+ 36 - 7
src/views/system/tenement/modules/sameDay.vue

@@ -11,6 +11,12 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
@@ -22,20 +28,16 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 生成一周的日期数据
-        const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
-
+        const weekDays = [];
         const option = {
             xAxis: {
                 type: 'category',
@@ -78,7 +80,8 @@ onMounted(() => {
             {
                     name: '车辆入库(辆)',
                     type: 'line',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data:[],
                     lineStyle: {
                         color: '#3b90d7',
                     },
@@ -108,7 +111,8 @@ onMounted(() => {
                 {
                     name: '车辆出库(辆)',
                     type: 'line',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data:[],
                     lineStyle: {
                         color: '#de4337',
                     },
@@ -143,6 +147,31 @@ onMounted(() => {
     window.addEventListener('resize', handleResize);
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        let arrData = Object.keys(newVal)
+        let arr1 = []
+        let arr2 = []
+        arrData.forEach((item)=>{
+            let data = Object.entries(newVal[item])
+            arr1.push(data[0][1])
+            arr2.push(data[1][1])
+        })
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal),
+            },
+            series: [{
+                name: '车辆入库(辆)',
+                data: arr1,
+            },{
+                name: '车辆出库(辆)',
+                data: arr2,
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 76 - 57
src/views/system/tenement/modules/tiring.vue

@@ -5,23 +5,21 @@
             <div :style="{ transform: `translateY(${scrollY}px)` }">
                 <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
                     <div class="_eventList_mains_item_text">
-                        <div
-                            :class="item.store === 'on' ? '_success' : '_warning'"
-                            class="_eventList_mains_item_text_flag">
-                            {{ item.store === 'on'?'进':'出' }}
+                        <div :class="item.State === 0 ? '_success' : '_warning'" class="_eventList_mains_item_text_flag">
+                            {{ item.State === 0 ? '进' : '出' }}
                         </div>
                         <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
-                            {{ item.name }}
+                            {{ item.GarName }}
                         </el-text>
                     </div>
-                    <div :style="{color:item.store === 'on'?'#15acaa':'#FFC107','font-size':'12px'}">
-                        {{ item.store === 'on'?'进入':'离开' }}
+                    <div :style="{ color: item.State === 0 ? '#15acaa' : '#FFC107', 'font-size': '12px' }">
+                        {{ item.State === 0 ? '进入' : '离开' }}
                     </div>
                     <div>
-                        <img src="@/assets/images/car.jpg" style="width: 30px;height: 30px;border-radius: 5px;" srcset="">
+                        <img :src="item.GarImag" style="width: 30px;height: 30px;border-radius: 5px;" srcset="">
                     </div>
                     <div class="_eventList_mains_item_btn">
-                        2025-04-15 10:20:00
+                        {{ item.Date }}
                     </div>
                 </div>
             </div>
@@ -32,49 +30,62 @@
 <script setup>
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//    name: '贵A.CL888',
+//     time: '2025-04-15 10:20:00'
+// }])
 
-const eventList = ref([{
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-   name: '贵A.CL888',
-    time: '2025-04-15 10:20:00'
-}])
-
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null
@@ -119,11 +130,13 @@ onUnmounted(() => {
 
 <style lang="scss" scoped>
 ._success {
-    background: #15acaa;	
+    background: #15acaa;
 }
+
 ._warning {
-    background: #FFC107;	
+    background: #FFC107;
 }
+
 ._eventList {
     overflow: hidden;
     display: flex;
@@ -146,37 +159,43 @@ onUnmounted(() => {
                 display: flex;
                 justify-content: space-between;
                 align-items: center;
+
                 &_flag {
                     width: 30px;
                     height: 30px;
                     border-radius: 50%;
-                    margin-left: 10px; 
+                    margin-left: 10px;
                     display: flex;
                     align-items: center;
                     justify-content: center;
                     color: #fff;
                     font-size: 14px;
                 }
+
                 &_p {
                     margin-left: 10px;
                 }
             }
-            &_btn{
+
+            &_btn {
                 color: #fff;
                 display: flex;
                 font-size: 14px;
                 gap: 20px;
+
                 &_item {
                     border-radius: 5px;
                     cursor: pointer;
                 }
             }
         }
-        &_item:nth-child(even){
+
+        &_item:nth-child(even) {
             background: rgba($color: #168cdb, $alpha: .05);
         }
+
         &_item:hover {
-            background-image: linear-gradient(to right, #168cdb, transparent); 
+            background-image: linear-gradient(to right, #168cdb, transparent);
         }
     }
 }

+ 50 - 36
src/views/system/video/index.vue

@@ -1,41 +1,55 @@
 <template>
     <div class="_energy">
-     <layout>
-         <template #left>
-            <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                <running style="flex: 1;"/>
-                <consume  style="flex: 1;"/>
-                <carbonEmission style="flex: 1;"/>
-             </div>
-         </template>
-         <template #content>
-             <p>视频</p>
-         </template>
-         <template #right>
-            <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
-                <sameDay style="flex: 1;"/>
-                <eventList style="flex: 2;"/>
-             </div>
-         </template>
-     </layout>
+        <layout>
+            <template #left>
+                <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
+                    <running :resultData="leftData" style="flex: 1;" />
+                    <consume :resultData="leftData" style="flex: 1;" />
+                    <carbonEmission :resultData="leftData" style="flex: 1;" />
+                </div>
+            </template>
+            <template #content>
+                <p>视频</p>
+            </template>
+            <template #right>
+                <div style="height: 100%;display: flex;flex-direction: column;overflow: hidden;">
+                    <sameDay :resultData="leftData" style="flex: 1;" />
+                    <eventList :resultData="leftData.MonitorList" style="flex: 2;" />
+                </div>
+            </template>
+        </layout>
     </div>
- </template>
- 
- <script setup name="Role">
- import layout from "@/components/layout_/index.vue";
+</template>
 
- import running from './modules/running.vue'
- import carbonEmission from './modules/carbonEmission.vue'
- import consume from './modules/consume.vue'
- 
- import sameDay from './modules/sameDay.vue'
- import eventList from './modules/eventList.vue'
+<script setup name="Role">
+import { getHikvision } from "@/api/system/monitor"
+import layout from "@/components/layout_/index.vue";
+import running from './modules/running.vue'
+import carbonEmission from './modules/carbonEmission.vue'
+import consume from './modules/consume.vue'
+import sameDay from './modules/sameDay.vue'
+import eventList from './modules/eventList.vue'
 
- 
- </script> 
- <style lang="scss">
- ._energy{
-     height: 100%;
- }
- </style>
- 
+const intervalId = ref(null)
+const leftData = ref({})
+// 生命周期
+onMounted(() => {
+    intervalId.value = setInterval(getHikvisionData, 10000);
+    getHikvisionData()
+});
+onUnmounted(() => {
+    clearInterval(intervalId.value);
+})
+function getHikvisionData() {
+    getHikvision().then((res) => {
+        if (res.code == 200) {
+            leftData.value = res.data
+        }
+    })
+}
+</script>
+<style lang="scss">
+._energy {
+    height: 100%;
+}
+</style>

+ 29 - 9
src/views/system/video/modules/carbonEmission.vue

@@ -11,10 +11,15 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import * as echarts from 'echarts';
 import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
 
 const chartRef = ref(null);
 let chart = null;
-
 const generateRandomData = (length, max) => {
     const randomData = [];
     for (let i = 0; i < length; i++) {
@@ -22,20 +27,17 @@ const generateRandomData = (length, max) => {
     }
     return randomData;
 };
-
 const handleResize = () => {
     if (chart) {
         chart.resize();
     }
 };
-
 onMounted(() => {
     if (chartRef.value) {
         chart = echarts.init(chartRef.value);
-
         // 生成一周的日期数据
-        const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
-
+        // const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
+        const weekDays = []
         const option = {
             xAxis: {
                 type: 'category',
@@ -79,7 +81,8 @@ onMounted(() => {
                 {
                     name: '车牌识别',
                     type: 'bar',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     barWidth: '30%',
                     itemStyle: {
                         color: {
@@ -102,7 +105,8 @@ onMounted(() => {
                 {
                     name: '黑名单',
                     type: 'line',
-                    data: generateRandomData(7, 50),
+                    // data: generateRandomData(7, 50),
+                    data: [],
                     lineStyle: {
                         color: '#216b87',
                     },
@@ -131,12 +135,28 @@ onMounted(() => {
                 }
             ]
         };
-
         chart.setOption(option);
     }
     window.addEventListener('resize', handleResize);
 });
 
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal.LicensePlateRecognition),
+            },
+            series: [{
+                name: '车牌识别',
+                data: Object.entries(newVal.LicensePlateRecognition),
+            }, {
+                name: '黑名单',
+                data: Object.entries(newVal.Blacklist),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 onUnmounted(() => {
     window.removeEventListener('resize', handleResize);
     if (chart) {

+ 10 - 3
src/views/system/video/modules/consume.vue

@@ -5,21 +5,21 @@
             <div class="_runnings_mains_left" id="sumeWidth">
                 <div class="_runnings_mains_left_tuan tuan1"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">785</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.IntrusionDetection}}</div>
                     <div class="_runnings_mains_left_conter_text">入侵检测</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan2"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">14</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.AbnormalBehavior}}</div>
                     <div class="_runnings_mains_left_conter_text">异常行为</div>
                 </div>
             </div>
             <div class="_runnings_mains_left">
                 <div class="_runnings_mains_left_tuan tuan3"></div>
                 <div class="_runnings_mains_left_conter">
-                    <div class="_runnings_mains_left_conter_num">54</div>
+                    <div class="_runnings_mains_left_conter_num">{{resultData.LostAlarms}}</div>
                     <div class="_runnings_mains_left_conter_text">丢失告警</div>
                 </div>
             </div>
@@ -30,6 +30,13 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+
 const runningList = ref([
     { name: '入侵检测', state: '154', color: '#409eff', tip: '划定区域人员闯入' },
     { name: '异常行为', state: '15', color: '#15acaa', tip: '徘徊、倒地、聚集' },

+ 57 - 44
src/views/system/video/modules/eventList.vue

@@ -6,10 +6,10 @@
                 <div class="_eventList_mains_item" v-for="(item, index) in eventList.concat(eventList)" :key="index">
                     <div class="_eventList_mains_item_text">
                         <div
-                        :class="item.store === 'on' ? '_success' : '_warning'"
+                        :class="item.Id === 'on' ? '_success' : '_warning'"
                         class="_eventList_mains_item_text_flag"></div>
                         <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
-                            {{ item.name }}
+                            {{ item.Name }}
                         </el-text>
                     </div>
                     <div class="_eventList_mains_item_btn">
@@ -29,49 +29,62 @@
 <script setup>
 import { ref, onMounted, onUnmounted } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '监控设备1',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '监控设备2',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '监控设备3',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '监控设备4',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '监控设备5',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '监控设备6',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'on',
+//     color: 'rgb(82.4, 155.2, 46.4)',
+//     name: '监控设备7',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     store: 'off',
+//     color: 'red',
+//     name: '监控设备8',
+//     time: '2025-04-15 10:20:00'
+// }])
 
-const eventList = ref([{
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '监控设备1',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '监控设备2',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '监控设备3',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '监控设备4',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '监控设备5',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '监控设备6',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'on',
-    color: 'rgb(82.4, 155.2, 46.4)',
-    name: '监控设备7',
-    time: '2025-04-15 10:20:00'
-}, {
-    store: 'off',
-    color: 'red',
-    name: '监控设备8',
-    time: '2025-04-15 10:20:00'
-}])
-
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const mainsRef = ref(null)
 const scrollY = ref(0)
 let intervalId = null

+ 23 - 6
src/views/system/video/modules/running.vue

@@ -5,7 +5,7 @@
             <div class="_running_mains_left" id="videoWidth" :style="{ '--heightRun': heightVideo + 'px' }">
                 <div class="_running_mains_left_tuan"></div>
                 <div class="_running_mains_left_conter">
-                    <div class="_running_mains_left_conter_num">785</div>
+                    <div class="_running_mains_left_conter_num">{{ resultData.MonitorCount }}</div>
                     <div class="_running_mains_left_conter_text">摄像头总量</div>
                 </div>
             </div>
@@ -33,12 +33,29 @@
 <script setup>
 import { ref } from "vue";
 import HeadlineTag from '@/components/HeadlineTag'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+
 const runningList = ref([
-    { name: '设备在线', state: '154', color: '#409eff', unit: '台' },
-    { name: '设备离线', state: '15', color: '#15acaa', unit: '台' },
-    { name: '存储容量', state: '134', color: '#FFC107', unit: 'TB' },
-    { name: '存储剩余', state: '30', color: '#F44336', unit: 'TB' },
+    { name: '设备在线', state: 0, color: '#409eff', unit: '台' },
+    { name: '设备离线', state: 0, color: '#15acaa', unit: '台' },
+    { name: '存储容量', state: 0, color: '#FFC107', unit: 'TB' },
+    { name: '存储剩余', state: 0, color: '#F44336', unit: 'TB' },
 ])
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.DeviceOnline
+        runningList.value[1].state = newVal.DeviceOffline
+        runningList.value[2].state = newVal.StorageCapacity
+        runningList.value[3].state = newVal.StoreSurplus
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 const heightVideo = ref(0)
 // 生命周期
 onMounted(() => {
@@ -59,7 +76,7 @@ onMounted(() => {
         align-items: center;
 
         &_left {
-            width: 40%;
+            width: 50%;
             height: var(--heightRun);
             position: relative;
 

+ 12 - 2
src/views/system/video/modules/sameDay.vue

@@ -6,14 +6,17 @@
             <div class="_runnin_mains_item" style="width: 33%;height: 100%;">
                 <div style="width: 100%;">
                     <waterdrop width="100%" fontSize="32px" circleBackGround="rgb(8, 36, 62)" birderColor="transparent"
-                        color="rgb(42, 139, 247)" heightTop="-50%" dropTitle="50%"></waterdrop>
+                        color="rgb(42, 139, 247)" :heightTop="'-' + resultData.CPU + '%'"
+                        :dropTitle="resultData.CPU + '%'">
+                    </waterdrop>
                 </div>
                 <span style="margin-top: 10px;font-weight: bold;">CPU</span>
             </div>
             <div class="_runnin_mains_item" style="width: 33%;height: 100%;">
                 <div style="width: 100%;">
                     <waterdrop width="100%" fontSize="32px" circleBackGround="rgb(8, 36, 62)"
-                        birderColor="rgb(8, 36, 62)" color="rgb(251, 97, 38)" heightTop="-65%" dropTitle="65%">
+                        birderColor="rgb(8, 36, 62)" color="rgb(251, 97, 38)" :heightTop="'-' + resultData.RAM + '%'"
+                        :dropTitle="resultData.RAM + '%'">
                     </waterdrop>
                 </div>
                 <span style="margin-top: 10px;font-weight: bold;">RAM</span>
@@ -26,6 +29,13 @@
 import 'echarts-liquidfill';
 import HeadlineTag from '@/components/HeadlineTag'
 import waterdrop from '@/components/waterdrop'
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+
 </script>
 
 <style lang="scss" scoped>

+ 147 - 0
src/views/system/visitor/caller.vue

@@ -0,0 +1,147 @@
+<template>
+    <div class="_running_mains">
+        <div class="_running_mains_left" id="runWidth" :style="{ '--heightRunning': heightRun + 'px' }">
+            <div class="_running_mains_left_tuan"></div>
+            <div class="_running_mains_left_conter">
+                <div class="_running_mains_left_conter_num">{{ resultData.VisitorCount || 0 }}</div>
+                <div class="_running_mains_left_conter_text">访客总量</div>
+            </div>
+        </div>
+        <div class="_running_mains_right">
+            <div class="_running_mains_right_item" v-for="item, index in runningList" :key="index">
+                <div class="_running_mains_right_item_tuan">
+                    <span class="_running_mains_right_item_tuan_flag" :style="{ backgroundColor: item.color }"></span>
+                    <el-text class="w-150px mb-2" truncated style="color: #ccc;">
+                        {{ item.name }}
+                    </el-text>
+                </div>
+                <div class="_running_mains_right_item__txt">
+                    {{ item.state || 0 }}
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref } from "vue";
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+
+const runningList = ref([
+    { name: '签到数量', state: 0, color: '#15acaa' },
+    { name: '通行数量', state: 0, color: '#FFC107' },
+    { name: '离场数量', state: 0, color: '#F44336' },
+])
+
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        runningList.value[0].state = newVal.SignInCount
+        runningList.value[1].state = newVal.TransitCount
+        runningList.value[2].state = newVal.Exit
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+const heightRun = ref(0)
+// 生命周期
+onMounted(() => {
+    var element = document.getElementById("runWidth");
+    var width = element.offsetWidth;
+    heightRun.value = width
+});
+</script>
+<style lang="scss" scoped>
+._running {
+    display: flex;
+    flex-direction: column;
+
+    &_mains {
+        flex: 1;
+        width: calc(100% - 30px);
+        padding-left: 30px;
+        display: flex;
+        align-items: center;
+
+        &_left {
+            width: 50%;
+            height: var(--heightRunning);
+            position: relative;
+            flex-shrink: 0;
+
+            &_tuan {
+                width: 100%;
+                height: 100%;
+                background: url("@/assets/images/content_circle.png");
+                background-size: 100% 100%;
+                background-position: center;
+                background-repeat: no-repeat;
+                animation: scanning 4s linear infinite;
+            }
+
+            &_conter {
+                position: absolute;
+                left: 0;
+                top: 0;
+                flex-shrink: 0;
+                width: 100%;
+                height: 100%;
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+                justify-content: center;
+                color: #fff;
+
+                &_num {
+                    font-size: 18px;
+                }
+
+                &_text {
+                    font-size: 12px;
+                }
+            }
+        }
+
+        &_right {
+            margin-left: 10px;
+            flex: 1;
+            color: #fff;
+
+            &_item {
+                display: flex;
+                align-items: center;
+                gap: 40px;
+                padding: 5px 0;
+
+                &_tuan {
+                    display: flex;
+                    align-items: center;
+
+                    &_flag {
+                        display: block;
+                        width: 7px;
+                        height: 7px;
+                        border-radius: 50%;
+                        margin-right: 10px;
+                    }
+                }
+
+                &__txt {
+                    font-size: 24px;
+                }
+            }
+        }
+
+
+    }
+}
+
+@keyframes scanning {
+    to {
+        transform: rotate(1turn);
+    }
+}
+</style>

+ 109 - 116
src/views/system/visitor/index.vue

@@ -3,104 +3,57 @@
     <layout>
       <template #left>
         <div class="left_visitor">
-          <HeadlineTag value="访客列表"></HeadlineTag>
-          <div class="box_arch_point">
-            <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
-              <el-input v-model="input" placeholder="按访客名称搜索" />
-            </div>
-            <div style="height: calc(100% - 160px);">
-              <Empty></Empty>
+          <div class="flex_spection" style="height:50%;">
+            <HeadlineTag value="访客登记信息列表"></HeadlineTag>
+            <div class="box_arch_point">
+              <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
+                <el-input v-model="input" placeholder="按访客名称搜索" />
+              </div>
+              <register :resultData="leftData"></register>
+              <!-- <div style="height: calc(100%);">
+                <Empty></Empty>
+              </div> -->
+              <!-- <div class="center_in">
+                <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
+                  layout="total, prev, pager, next" @pagination="getList" />
+              </div> -->
             </div>
-            <div class="center_in">
-              <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
-                layout="total, prev, pager, next" @pagination="getList" />
+          </div>
+          <div class="flex_spection" style="height:50%;">
+            <HeadlineTag value="访客刷卡记录列表"></HeadlineTag>
+            <div class="box_arch_point">
+              <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
+                <el-input v-model="input" placeholder="按访客名称搜索" />
+              </div>
+              <swiping :resultData="leftData"></swiping>
+              <!-- <div style="height: calc(100%);">
+                <Empty></Empty>
+              </div> -->
+              <!-- <div class="center_in">
+                <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
+                  layout="total, prev, pager, next" @pagination="getList" />
+              </div> -->
             </div>
           </div>
         </div>
       </template>
       <template #right>
         <div class="right_visitor">
-          <div class="garden_box">
-            <HeadlineTag type="right" value="园区基本信息"></HeadlineTag>
-            <div class="card_visitor_star">
-              <div class="item_visitor_top">
-                <div class="circle_itor center_in">
-                  <svg class="visitor_star" aria-hidden="true">
-                    <defs>
-                      <linearGradient id="myGradient" x1="0%" y1="100%" x2="0%" y2="0%">
-                        <stop offset="0%" stop-color="rgb(20, 188, 244)" />
-                        <stop offset="100%" stop-color="#ffffff" />
-                      </linearGradient>
-                    </defs>
-                    <use xlink:href="#icon-user" fill="url('#myGradient')" />
-                  </svg>
-                </div>
-                <div class="title_box_itor">
-                  <div class="title_itor_13">总规划建筑面积</div>
-                  <div class="title_itor_18">142万</div>
-                </div>
-              </div>
-              <div class="item_visitor_top">
-                <div class="circle_itor center_in">
-                  <svg class="visitor_star" aria-hidden="true">
-                    <defs>
-                      <linearGradient id="myGradient" x1="0%" y1="100%" x2="0%" y2="0%">
-                        <stop offset="0%" stop-color="rgb(20, 188, 244)" />
-                        <stop offset="100%" stop-color="#ffffff" />
-                      </linearGradient>
-                    </defs>
-                    <use xlink:href="#icon-user" fill="url('#myGradient')" />
-                  </svg>
-                </div>
-                <div class="title_box_itor">
-                  <div class="title_itor_13">总规划建筑面积</div>
-                  <div class="title_itor_18">142万</div>
-                </div>
-              </div>
-              <div class="item_visitor_top">
-                <div class="circle_itor center_in">
-                  <svg class="visitor_star" aria-hidden="true">
-                    <defs>
-                      <linearGradient id="myGradient" x1="0%" y1="100%" x2="0%" y2="0%">
-                        <stop offset="0%" stop-color="rgb(20, 188, 244)" />
-                        <stop offset="100%" stop-color="#ffffff" />
-                      </linearGradient>
-                    </defs>
-                    <use xlink:href="#icon-user" fill="url('#myGradient')" />
-                  </svg>
-                </div>
-                <div class="title_box_itor">
-                  <div class="title_itor_13">总规划建筑面积</div>
-                  <div class="title_itor_18">142万</div>
-                </div>
-              </div>
-              <div class="item_visitor_top">
-                <div class="circle_itor center_in">
-                  <svg class="visitor_star" aria-hidden="true">
-                    <defs>
-                      <linearGradient id="myGradient" x1="0%" y1="100%" x2="0%" y2="0%">
-                        <stop offset="0%" stop-color="rgb(20, 188, 244)" />
-                        <stop offset="100%" stop-color="#ffffff" />
-                      </linearGradient>
-                    </defs>
-                    <use xlink:href="#icon-user" fill="url('#myGradient')" />
-                  </svg>
-                </div>
-                <div class="title_box_itor">
-                  <div class="title_itor_13">总规划建筑面积</div>
-                  <div class="title_itor_18">142万</div>
-                </div>
-              </div>
+          <div class="flex_spection">
+            <HeadlineTag type="right" value="今日访客统计"></HeadlineTag>
+            <div class="box_arch">
+              <!-- <starView></starView> -->
+              <caller :resultData="leftData"></caller>
             </div>
           </div>
-          <div style="height: 300px;">
-            <HeadlineTag type="right" value="访客统计"></HeadlineTag>
-            <div class="box_arch">
-              <starView></starView>
+          <div class="flex_spection">
+            <HeadlineTag type="right" value="通行趋势"></HeadlineTag>
+            <div class="card_visitor_star">
+              <transit :resultData="leftData"></transit>
             </div>
           </div>
           <div class="flex_spection">
-            <HeadlineTag type="right" value="外地人员分配"></HeadlineTag>
+            <HeadlineTag type="right" value="访客身份类型占比"></HeadlineTag>
             <div class="box_arch">
               <div ref="chartDom" style="width: 100%;height: 100%;" />
             </div>
@@ -112,10 +65,15 @@
 </template>
 
 <script setup>
+import { getVisitor } from "@/api/system/visitor"
 import layout from "@/components/layout_/index.vue";
 import HeadlineTag from '@/components/HeadlineTag'
 import Empty from '@/components/Empty'
 import starView from './starView'
+import transit from './transit.vue'
+import caller from './caller.vue'
+import register from './register.vue'
+import swiping from './swiping.vue'
 import * as echarts from 'echarts'
 const total = ref(0);
 const queryParams = ref({
@@ -130,7 +88,7 @@ function getList() {
 const chartDom = ref(null);
 let chartInstance = null;
 // 初始化图表
-const initChart = () => {
+const initChart = (valueData) => {
   var colorList = [{
     type: 'linear',
     x: 0,
@@ -235,7 +193,6 @@ const initChart = () => {
   }
   ]
   var colorLine = ['#33C0CD', '#73ACFF', '#9E87FF', '#FE6969', '#FDB36A', '#FECE43']
-
   function getRich() {
     let result = {}
     colorLine.forEach((v, i) => {
@@ -255,27 +212,7 @@ const initChart = () => {
     })
     return result
   }
-  let data = [{
-    'name': '北京',
-    'value': 25
-  }, {
-    'name': '上海',
-    'value': 20
-  }, {
-    'name': '广州',
-    'value': 18
-  }, {
-    'name': '深圳',
-    'value': 15
-  }, {
-    'name': '未知',
-    'value': 13
-  }, {
-    'name': '海外',
-    'value': 9
-  }].sort((a, b) => {
-    return b.value - a.value
-  })
+  let data = valueData
   data.forEach((v, i) => {
     v.labelLine = {
       lineStyle: {
@@ -284,7 +221,9 @@ const initChart = () => {
       }
     }
   })
-  chartInstance = echarts.init(chartDom.value);
+  if (!chartInstance) {
+    chartInstance = echarts.init(chartDom.value);
+  }
   chartInstance.setOption({
     series: [{
       type: 'pie',
@@ -316,7 +255,65 @@ const initChart = () => {
   });
 };
 // 生命周期
-onMounted(initChart);
+onMounted(() => {
+  intervalId.value = setInterval(getVisitorData, 10000);
+  getVisitorData()
+  let data = [{
+    'name': '客户',
+    'value': 0
+  }, {
+    'name': '供应商',
+    'value': 0
+  }, {
+    'name': '面试者',
+    'value': 0
+  }, {
+    'name': '政府人员',
+    'value': 0
+  }, {
+    'name': '其他',
+    'value': 0
+  }].sort((a, b) => {
+    return b.value - a.value
+  })
+  initChart(data)
+});
+onUnmounted(() => {
+  clearInterval(intervalId.value);
+})
+const intervalId = ref(null)
+const leftData = ref({})
+function getVisitorData() {
+  getVisitor().then((res) => {
+    if (res.code == 200) {
+      leftData.value = res.data
+    }
+  })
+}
+watch(() => leftData.value, (newVal) => {
+  if (chartInstance) {
+    let data = [{
+      'name': '客户',
+      'value': newVal.Client
+    }, {
+      'name': '供应商',
+      'value': newVal.Vendor
+    }, {
+      'name': '面试者',
+      'value': newVal.Interviewees
+    }, {
+      'name': '政府人员',
+      'value': newVal.GovernmentPersonnel
+    }, {
+      'name': '其他',
+      'value': newVal.Other
+    }].sort((a, b) => {
+      return b.value - a.value
+    })
+    initChart(data)
+  }
+}, { deep: true, immediate: true } // 开启深度监听
+)
 // 窗口自适应
 window.addEventListener('resize', () => {
   chartInstance?.resize();
@@ -353,13 +350,9 @@ window.addEventListener('resize', () => {
   height: calc(100% - 40px);
 }
 
-.operation_spection {
-  height: 250px;
-  color: #fff;
-}
 
 .garden_box {
-  height: 300px;
+  height: 30%;
 }
 
 .flex_spection {

+ 171 - 0
src/views/system/visitor/register.vue

@@ -0,0 +1,171 @@
+<template>
+    <div class="_eventList">
+        <!-- 绑定鼠标移入移出事件 -->
+        <div class="_eventList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <!-- 复制一份数据用于无缝滚动 -->
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_eventList_mains_item" v-for="(item, index) in eventList" :key="index">
+                    <div class="_eventList_mains_item_text">
+                        <div :class="item.Name === 0 ? '_warning' : '_success'" class="_eventList_mains_item_text_flag">
+                        </div>
+                        <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
+                            {{ item.Name }}
+                        </el-text>
+                    </div>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Phone }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Location }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Date }}
+                    </el-text>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+// const eventList = ref([{
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     phone: '17231123222',
+//     address: '1号门',
+//     time: '2025-04-15 10:20:00'
+// }])
+
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal.VisitorRegistration
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value.querySelector('._eventList_mains_item').offsetHeight
+        scrollY.value -= scrollSpeed
+        if (Math.abs(scrollY.value) >= itemHeight * eventList.value.length) {
+            scrollY.value = 0
+        }
+    }, 20)
+}
+
+const pauseCarousel = () => {
+    clearInterval(intervalId)
+}
+
+const resumeCarousel = () => {
+    startCarousel()
+}
+
+onMounted(async () => {
+    await nextTick();
+    startCarousel()
+})
+
+onUnmounted(() => {
+    clearInterval(intervalId)
+})
+</script>
+
+<style lang="scss" scoped>
+._success {
+    background: #15acaa;
+}
+
+._warning {
+    background: #FFC107;
+}
+
+._eventList {
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    height: calc(100% - 40px);
+
+    &_mains {
+        margin: 10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        // 鼠标移入时改变手势
+        cursor: pointer;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px 0;
+
+            &_text {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+
+                &_flag {
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    margin-left: 10px;
+                }
+
+                &_p {
+                    margin-left: 10px;
+                }
+            }
+        }
+
+        &_item:hover {
+            background-image: linear-gradient(to right, #168cdb, transparent);
+        }
+    }
+}
+</style>

+ 171 - 0
src/views/system/visitor/swiping.vue

@@ -0,0 +1,171 @@
+<template>
+    <div class="_eventList">
+        <!-- 绑定鼠标移入移出事件 -->
+        <div class="_eventList_mains" ref="mainsRef" @mouseenter="pauseCarousel" @mouseleave="resumeCarousel">
+            <!-- 复制一份数据用于无缝滚动 -->
+            <div :style="{ transform: `translateY(${scrollY}px)` }">
+                <div class="_eventList_mains_item" v-for="(item, index) in eventList" :key="index">
+                    <div class="_eventList_mains_item_text">
+                        <div :class="item.Name === 0 ? '_success' : '_warning'" class="_eventList_mains_item_text_flag">
+                        </div>
+                        <el-text class="w-150px mb-2" truncated style="color: white;margin-left: 10px;">
+                            {{ item.Name }}
+                        </el-text>
+                    </div>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Location }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.State == 0 ? '进入' : '离开' }}
+                    </el-text>
+                    <el-text class="w-150px mb-2" truncated style="color: white;">
+                        {{ item.Date }}
+                    </el-text>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue";
+const props = defineProps({
+    resultData: {
+        type: Array,
+        default: []
+    }
+})
+// const eventList = ref([{
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 0,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 1,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 1,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 0,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 0,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 1,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 1,
+//     time: '2025-04-15 10:20:00'
+// }, {
+//     name: '张史蒂',
+//     address: 'A栋1层东门',
+//     direction: 0,
+//     time: '2025-04-15 10:20:00'
+// }])
+
+const eventList = ref([])
+watch(() => props.resultData, (newVal) => {
+    if (newVal) {
+        eventList.value = []
+        eventList.value = newVal.VisitorsSwipeCards
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+const mainsRef = ref(null)
+const scrollY = ref(0)
+let intervalId = null
+const scrollSpeed = 1 // 滚动速度
+
+const startCarousel = () => {
+    intervalId = setInterval(() => {
+        const itemHeight = mainsRef.value.querySelector('._eventList_mains_item').offsetHeight
+        scrollY.value -= scrollSpeed
+        if (Math.abs(scrollY.value) >= itemHeight * eventList.value.length) {
+            scrollY.value = 0
+        }
+    }, 50)
+}
+
+const pauseCarousel = () => {
+    clearInterval(intervalId)
+}
+
+const resumeCarousel = () => {
+    startCarousel()
+}
+
+onMounted(async () => {
+    await nextTick();
+    startCarousel()
+})
+
+onUnmounted(() => {
+    clearInterval(intervalId)
+})
+</script>
+
+<style lang="scss" scoped>
+._success {
+    background: #15acaa;
+}
+
+._warning {
+    background: #FFC107;
+}
+
+._eventList {
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    height: calc(100% - 40px);
+
+    &_mains {
+        margin: 10px 30px;
+        overflow: hidden; // 隐藏溢出内容
+        // 鼠标移入时改变手势
+        cursor: pointer;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px 0;
+
+            &_text {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+
+                &_flag {
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    margin-left: 10px;
+                }
+
+                &_p {
+                    margin-left: 10px;
+                }
+            }
+        }
+
+        &_item:hover {
+            background-image: linear-gradient(to right, #168cdb, transparent);
+        }
+    }
+}
+</style>

+ 202 - 0
src/views/system/visitor/transit.vue

@@ -0,0 +1,202 @@
+<template>
+    <div class="_consume_mains">
+        <div ref="chartRef" style="width: 100%; height: 100%;"></div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from 'vue';
+import * as echarts from 'echarts';
+import HeadlineTag from '@/components/HeadlineTag';
+const props = defineProps({
+    resultData: {
+        type: Object,
+        default: {}
+    }
+})
+
+const chartRef = ref(null);
+let chart = null;
+const generateRandomData = (length, max) => {
+    const randomData = [];
+    for (let i = 0; i < length; i++) {
+        randomData.push(Math.floor(Math.random() * max));
+    }
+    return randomData;
+};
+const handleResize = () => {
+    if (chart) {
+        chart.resize();
+    }
+};
+onMounted(() => {
+    if (chartRef.value) {
+        chart = echarts.init(chartRef.value);
+        // 修改为 24 小时
+        // const hours = Array.from({ length: 24 }, (_, i) => `${i}时`);
+        const hours = []
+        const option = {
+            xAxis: {
+                type: 'category',
+                // 使用 24 小时数据
+                data: hours,
+                axisLabel: {
+                    color: '#fff'
+                },
+            },
+            tooltip: {
+                trigger: 'axis',
+                axisPointer: {
+                    type: 'cross',
+                    crossStyle: {
+                        color: '#999'
+                    }
+                }
+            },
+            grid: {
+                top: '10%',
+                bottom: '10%',
+                right: '0%',
+            },
+            yAxis: {
+                type: 'value',
+                axisLabel: {
+                    show: true,
+                    color: '#fff'
+                },
+                splitLine: {
+                    show: false,
+                    lineStyle: {
+                        color: '#44585e'
+                    }
+                },
+                axisTick: {
+                    show: false
+                },
+            },
+            series: [
+                {
+                    name: '24小时能耗',
+                    // data: generateRandomData(7, 50),
+                    data: [],
+                    type: 'line',
+                    showSymbol: false,
+                    smooth: true,
+                    color: '#00F7FF',
+                    lineStyle: {
+                        width: 2,
+                    },
+                    areaStyle: {
+                        color: new echarts.graphic.LinearGradient(
+                            0,
+                            0,
+                            0,
+                            1,
+                            [{
+                                offset: 0,
+                                color: 'rgba(0, 247, 255, .6)',
+                            },
+                            {
+                                offset: 0.8,
+                                color: 'rgba(0, 247, 255, .2)',
+                            },
+                            ],
+                            false
+                        ),
+                        shadowColor: 'rgba(0, 0, 0, 0.1)',
+                        shadowBlur: 10,
+                    },
+                    symbol: 'circle',
+                    symbolSize: 6,
+                }
+            ]
+        };
+
+        chart.setOption(option);
+    }
+});
+
+watch(() => props.resultData, (newVal) => {
+    if (chart) {
+        chart.setOption({
+            xAxis: {
+                data: Object.keys(newVal.PrevailingTrends),
+            },
+            series: [{
+                type: 'line',
+                data: Object.entries(newVal.PrevailingTrends),
+            }],
+        })
+    }
+}, { deep: true, immediate: true } // 开启深度监听
+)
+onUnmounted(() => {
+    window.removeEventListener('resize', handleResize);
+    if (chart) {
+        chart.dispose();
+    }
+});
+</script>
+
+<style lang="scss">
+._divider {
+    height: 1px;
+    border: 1px dashed #168cdb;
+    flex: 1;
+    margin: 0 10px;
+}
+
+._consume {
+    display: flex;
+    flex-direction: column;
+
+    &_mains {
+        margin: 10px 30px;
+        flex: 1;
+        display: flex;
+
+        &_item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 10px;
+
+            &_name {
+                width: 30px;
+                height: 30px;
+                background: url("@/assets/images/content_circle_num.png");
+                background-size: 100% 100%;
+                background-position: center;
+                background-repeat: no-repeat;
+                // animation: scanning 4s linear infinite;
+                border: 1px solid red;
+            }
+
+            &_flag {
+                display: flex;
+                align-items: center;
+                gap: 3px;
+
+                &_item {
+                    width: 30px;
+                    height: 30px;
+                    border: 3px dashed #168cdb;
+                    box-sizing: border-box;
+                    background: #0e6ead;
+                    color: #fff;
+                    border-radius: 50%;
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                    font-size: 14px;
+                }
+            }
+        }
+
+        &_item:hover {
+            cursor: pointer;
+            background-image: linear-gradient(to right, #168cdb, transparent);
+        }
+    }
+}
+</style>