Browse Source

Merge remote-tracking branch 'origin/master'

xu 7 tháng trước cách đây
mục cha
commit
a312889f86

+ 2 - 2
web/.env.development

@@ -3,9 +3,9 @@ VITE_CLI_PORT = 8080
 VITE_SERVER_PORT = 8888
 VITE_BASE_API = /api
 VITE_FILE_API = /api
-VITE_BASE_PATH = http://192.168.110.218
+//VITE_BASE_PATH = http://192.168.110.218
 //VITE_BASE_PATH = http://192.168.110.214
-//VITE_BASE_PATH = http://127.0.0.1
+VITE_BASE_PATH = http://127.0.0.1
 VITE_POSITION = close
 VITE_EDITOR = vscode
 // VITE_EDITOR = webstorm 如果使用webstorm开发且要使用dom定位到代码行功能 请先自定添加 webstorm到环境变量 再将VITE_EDITOR值修改为webstorm

+ 1 - 2
web/index.html

@@ -7,8 +7,7 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <meta content="Gin,Vue,Admin.Gin-Vue-Admin,GVA,gin-vue-admin,后台管理框架,vue后台管理框架,gin-vue-admin文档,gin-vue-admin首页,gin-vue-admin" name="keywords" />
     <link rel="icon" href="favicon.ico">
-    <title></title>
-<!--    <script src="https://map.qq.com/api/gljs?v=1.exp&key=3SVBZ-6MYYZ-Q75X5-7YN43-BMIBZ-YABND"></script>-->
+    <title>龙弛智慧隧道</title>
 </head>
 
 <body>

+ 2 - 2
web/jsconfig.json

@@ -2,9 +2,9 @@
     "compilerOptions": {
       "baseUrl": "./",
       "paths": {
-        "@/*": ["src/*"],
+        "@/*": ["src/*"]
       }
     },
     "exclude": ["node_modules", "dist"],
     "include": ["src/**/*"]
-  }
+  }

BIN
web/src/assets/icons/device.png


BIN
web/src/assets/icons/environment.png


BIN
web/src/assets/icons/fourWays.png


BIN
web/src/assets/icons/inductance.png


BIN
web/src/assets/icons/logo.png


BIN
web/src/assets/icons/power.png


BIN
web/src/assets/icons/setting.png


BIN
web/src/assets/icons/singleLamp.png


BIN
web/src/assets/icons/sunlight.png


BIN
web/src/assets/icons/title.png


BIN
web/src/assets/icons/topbg.png


BIN
web/src/assets/icons/warn.png


+ 8 - 1
web/src/pinia/modules/screen.js

@@ -6,6 +6,7 @@ export const useScreenStore = defineStore('screen',() => {
     let placeList = []
     const tunnelList = reactive([])
     const currentTunnel = ref({})
+    const screenType = ref('map')
 
     const setController = (val) => {
         Object.assign(controllerData, val)
@@ -26,6 +27,10 @@ export const useScreenStore = defineStore('screen',() => {
     const setCurrentTunnel = (val) => {
         currentTunnel.value = val
     }
+
+    const setScreenType = (val) => {
+        screenType.value = val
+    }
     return {
         controllerData,
         setController,
@@ -33,6 +38,8 @@ export const useScreenStore = defineStore('screen',() => {
         setTunnelList,
         placeList,
         currentTunnel,
-        setCurrentTunnel
+        setCurrentTunnel,
+        screenType,
+        setScreenType
     }
 })

+ 13 - 13
web/src/router/index.js

@@ -16,20 +16,20 @@ const routes = [{
   },
   component: () => import('@/view/error/index.vue')
 },
-  {
-    path: '/dataDashboard',
-    meta: {
-      closeTab: true,
-    },
-    component: () => import('@/view/admin/dataDashboard/dataDashboard.vue')
+{
+  path: '/dataDashboard',
+  meta: {
+    closeTab: true,
+  },
+  component: () => import('@/view/screen/dataDashboard.vue')
+},
+{
+  path: '/dataScreen',
+  meta: {
+    closeTab: true
   },
-  {
-    path: '/dataScreen',
-    meta: {
-      closeTab: true
-    },
-    component:() => import('@/view/screen/dataScreen.vue')
-  }
+  component: () => import('@/view/screen/dataScreen.vue')
+}
 ]
 
 const router = createRouter({

+ 0 - 506
web/src/view/admin/dataDashboard/dataDashboard.vue

@@ -1,506 +0,0 @@
-<template>
-  <div class="screen">
-    <div style="height: 10px"></div>
-    <div class="titleImage">
-      <el-image :src="titleUrl" />
-      <span class="Heading">龙弛智慧隧道系统</span>
-    </div>
-    <div class="coreBox">
-      <div ref="container" class="three-container"></div>
-      <div class="formBox">
-        <div class="panel">
-          <span class="panel-title">亮度调整</span>
-          <el-slider
-              v-model="transparency"
-              :step="50"
-              show-stops
-              :show-tooltip="false"
-              class="panel-slider"
-              @change="changeTransparency"
-          />
-          <div class="brightness" style="margin: 90px 0 0 25px;">
-            <span>低</span>
-            <span>中</span>
-            <span>高</span>
-          </div>
-          <el-slider
-              v-model="transparencyTwo"
-              :step="50"
-              show-stops
-              :show-tooltip="false"
-              class="panel-slider2"
-              @change="changeTransparencyTwo"
-          />
-          <div class="brightness" style="margin: 50px 0 0 25px;">
-            <span>低</span>
-            <span>中</span>
-            <span>高</span>
-          </div>
-          <div class="panel-bottom"></div>
-        </div>
-      </div>
-      <div class="formBox_two">
-        <div class="panel" style="height: 100px">
-          <span class="panel-title">轴流式风机</span>
-          <span class="panelSwitchTitle">风机开关</span>
-          <el-switch class="panelSwitch" size="large"></el-switch>
-          <div class="panel-bottom"></div>
-        </div>
-      </div>
-      <div class="vehicleBox">
-        <div class="panel" style="height: 190px">
-          <span class="panel-title">车辆检测器</span>
-          <el-form style="position: absolute;left: 40px;top: 50px">
-            <el-form-item label="交通量" label-width="110" label-position="left">
-              <el-row style="width: 120px">
-                <el-col :span="15" class="vehicleData">
-                  <span>123</span>
-                </el-col>
-                <el-col :span="9" class="vehicleUnit">
-                  <span>辆</span>
-                </el-col>
-              </el-row>
-            </el-form-item>
-            <el-form-item label="平均车速" label-width="110" label-position="left">
-              <el-row style="width: 120px">
-                <el-col :span="15" class="vehicleData">
-                  <span>66</span>
-                </el-col>
-                <el-col :span="9" class="vehicleUnit">
-                  <span>km/h</span>
-                </el-col>
-              </el-row>
-            </el-form-item>
-            <el-form-item label="车道占有量" label-width="110" label-position="left">
-              <el-row style="width: 120px">
-                <el-col :span="15" class="vehicleData">
-                  <span>12</span>
-                </el-col>
-                <el-col :span="9" class="vehicleUnit">
-                  <span>%</span>
-                </el-col>
-              </el-row>
-            </el-form-item>
-          </el-form>
-          <div class="panel-bottom"></div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import * as THREE from 'three';
-import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
-import { onMounted, onUnmounted, reactive, ref } from 'vue';
-import { useScreenStore } from '@/pinia/modules/screen'
-// 单灯控制
-import { updateTunnelLamp } from "@/api/tunnel";
-// 四路控制
-import { deviceSwitch } from "@/api/device";
-// 标题图片
-import titleUrl from '@/assets/title_bg.png'
-import {ElMessage} from "element-plus";
-
-const useScreen = useScreenStore()
-// 获取容器引用
-const container = ref(null);
-
-// 定义 Three.js 相关变量
-let scene, camera, renderer, controls;
-
-// 创建场景
-scene = new THREE.Scene();
-
-// 添加环境光
-const ambientLight = new THREE.AmbientLight(0xffffff, 1);
-
-// 初始化 Three.js 场景
-const initThree = () => {
-  scene.background = null;
-  // textureLoader.load('@/assets/OIP-C.jpg', (texture) => {
-  //   // 将图片设置为场景的背景
-  //   scene.background = texture;
-  // });
-  // 创建相机
-  camera = new THREE.PerspectiveCamera(
-      75,
-      container.value.clientWidth / container.value.clientHeight,
-      0.1,
-      1000
-  );
-  camera.position.set(30, 20, 30);
-
-  // 创建渲染器
-  renderer = new THREE.WebGLRenderer({ antialias: true });
-  renderer.setSize(container.value.clientWidth, container.value.clientHeight);
-  renderer.setClearAlpha(0);
-  // renderer.setClearColor(222842);
-  container.value.appendChild(renderer.domElement);
-
-  // 添加轨道控制器
-  controls = new OrbitControls(camera, renderer.domElement);
-  controls.enableDamping = true; // 启用阻尼效果
-  controls.dampingFactor = 0.05;
-
-  scene.add(ambientLight);
-
-  // 添加平行光
-  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
-  directionalLight.position.set(5, 5, 5).normalize();
-  scene.add(directionalLight);
-};
-
-// 存储模型数据
-let materialOne = reactive({})
-let materialTwo = reactive({})
-
-const relayList = reactive([])
-
-
-// 加载 GLB 模型
-const loadModel = () => {
-  const loader = new GLTFLoader();
-  loader.load('../../public/隧道1.glb', function (gltf){
-      let object = gltf.scene
-      console.log(object.children)
-      object.children.forEach(item => {
-        if (item.name === '柱体') {
-          materialOne = item.children[3].material
-        } else if(item.name === '柱体001') {
-          materialTwo = item.children[3].material
-        }
-      })
-      //gltf.scene获取gltf文件包含的模型数据
-      scene.add(gltf.scene)
-    }, function (xhr) {
-        // 加载进度回调
-        // console.log((xhr.loaded / xhr.total * 100) + '% loaded');
-      }, function (error) {
-        // 加载错误回调
-        // console.error('An error happened', error);
-      }
-  )
-};
-
-// 动画循环
-const animate = () => {
-  requestAnimationFrame(animate);
-  controls.update(); // 更新控制器
-  renderer.render(scene, camera);
-};
-
-// 亮度调整
-const transparency = ref(0)
-const changeTransparency = (e) => {
-  let option = {
-    0: [0.8, 33, 1],
-    50: [0.5, 66, 2],
-    100: [0.2, 100, 3]
-  }
-  materialOne.opacity = option[e][0]
-  if (lampData.switchType === '单灯控制器') {
-    updateTunnelLamp({
-      id: lampData.ID,
-      tunnelSn: lampData.tunnelSn,
-      lampValue1: option[e][1]
-    }).then(res => {
-      if (res.code === 0) {
-        ElMessage.success('已发送')
-      }
-    })
-  } else {
-    let relay = relayList[0].deviceRelays
-    for (let i = 0; i < relay.length; i++) {
-      relay[i].state = i < option[e][2];
-    }
-    for (let j = 0; j < relay.length; j++) {
-      deviceSwitch({
-        tunnelSn: lampData.tunnelSn,
-        radarId: relayList[0].radarId,
-        relayId: relay[j].relayId,
-        state: relay[j].state
-      }).then(res => {
-        if (res.code === 0) {
-          console.log('发送成功')
-        }
-      })
-    }
-  }
-}
-
-const transparencyTwo = ref(0)
-const changeTransparencyTwo = (e) => {
-  let option = {
-    0: [0.8, 33, 1],
-    50: [0.5, 66, 2],
-    100: [0.2, 100, 3]
-  }
-  materialTwo.opacity = option[e][0]
-  if (lampData.switchType === '单灯控制器') {
-    updateTunnelLamp({
-      id: lampData.ID,
-      tunnelSn: lampData.tunnelSn,
-      lampValue2: option[e][1]
-    }).then(res => {
-      if (res.code === 0) {
-        ElMessage.success('已发送')
-      }
-    })
-  } else {
-    let relay = relayList[1].deviceRelays
-    for (let i = 0; i < relay.length; i++) {
-      relay[i].state = i < option[e][2];
-    }
-    for (let j = 0; j < relay.length; j++) {
-      deviceSwitch({
-        tunnelSn: lampData.tunnelSn,
-        radarId: relayList[1].radarId,
-        relayId: relay[j].relayId,
-        state: relay[j].state
-      }).then(res => {
-        if (res.code === 0) {
-          console.log('发送成功');
-        }
-      })
-    }
-  }
-}
-
-// 灯光数据
-const lampData = reactive({})
-
-const judgeLamp = () => {
-  relayList.length = 0
-  if (lampData.switchType === '单灯控制器') {
-    let val1 = lampData.lampValue1
-    let val2 = lampData.lampValue2
-    let judge = {
-      33: [0.8,0],
-      66: [0.5,50],
-      100: [0.2,100],
-    }
-    transparency.value = judge[val1][1]
-    materialOne.opacity = judge[val1][0]
-    transparencyTwo.value = judge[val1][1]
-    materialTwo.opacity = judge[val2][0]
-  } else if(lampData.switchType === '四路控制器') {
-    lampData.devices.forEach(item => {
-      if (item.genre === 6) {
-        relayList.push(item)
-      }
-    })
-    let deviceLamp1 = relayList[0].deviceRelays
-    let deviceLamp2 = relayList[1].deviceRelays
-      let count1 = 0
-      let count2 = 0
-      deviceLamp1.forEach(item => {
-        item.state ? count1++ : count1
-      })
-      deviceLamp2.forEach(item => {
-        item.state ? count2++ : count2
-      })
-      let judgeWay = {
-        1: [0.8,0],
-        2: [0.5,50],
-        3: [0.2,100],
-        4: [0.2,100]
-      }
-    transparency.value = judgeWay[count1][1]
-    materialOne.opacity = judgeWay[count1][0]
-    transparencyTwo.value = judgeWay[count2][1]
-    materialTwo.opacity = judgeWay[count2][0]
-  }
-
-}
-
-// 组件挂载时初始化
-onMounted(() => {
-  Object.assign(lampData, useScreen.controllerData)
-  initThree();
-  loadModel();
-  animate();
-  setTimeout(function () {
-    judgeLamp()
-  },500)
-});
-
-// 组件卸载时清理资源
-onUnmounted(() => {
-  if (renderer) {
-    renderer.dispose();
-  }
-});
-</script>
-
-<style scoped lang="less">
-.horn {
-  position: absolute;
-  content: "";
-  width: 10px;
-  height: 10px;
-}
-.screen{
-  width: 100%;
-  height: 970px;
-  //background-image: url("@/assets/back.jpeg");
-  background-size:100% 100%;
-  background: #1d2b56 url("@/assets/line.png");
-
-  .titleImage {
-    width: 100%;
-    height: 70px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    position: relative;
-    .Heading{
-      position: absolute;
-      left: 42%;
-      top: 25%;
-      text-align: center;
-      font-size: 1.7vw;
-      font-weight: bold;
-      color: #0EFCFF;
-    }
-  }
-  .coreBox{
-    width: 100%;
-    height: 900px;
-    margin-top: 20px;
-    position: relative;
-    .three-container {
-      z-index: 1;
-      position: absolute;
-      height: 800px;
-      width: 100%;
-    }
-    .formBox{
-      position: absolute;
-      right: 20px;
-      z-index:2;
-    }
-    .formBox_two{
-      position: absolute;
-      right: 20px;
-      top: 250px;
-      z-index:2;
-    }
-    .vehicleBox{
-      position: absolute;
-      right: 20px;
-      top: 380px;
-      z-index:2;
-      .vehicleData{
-        display: flex;
-        justify-content: end;
-        align-items: center;
-        span {
-          font-size: 18px;
-          font-weight: bold;
-          color: #0EFCFF;
-        }
-      }
-      .vehicleUnit{
-        display: flex;
-        justify-content: end;
-        align-items: center;
-        span {
-          color: #909399;
-        }
-      }
-    }
-    .panel{
-      position: relative;
-      width: 300px;
-      height: 200px;
-      border: 1px solid rgba(25,186,139,0.17);
-      padding: 0 0.1875rem 0.5rem;
-      margin-bottom: 0.1875rem;
-      background: url(@/assets/line.png) rgba(255,255,255,0.04);
-      &::before{
-        .horn;
-        top: 0;
-        left: 0;
-        border-left: 2px solid #02a6b5;
-        border-top: 2px solid #02a6b5;
-      }
-      &::after{
-        .horn;
-        top: 0;
-        right: 0;
-        border-right: 2px solid #02a6b5;
-        border-top: 2px solid #02a6b5;
-      }
-      .panel-bottom{
-        &::before{
-          .horn;
-          bottom: 0;
-          left: 0;
-          border-left: 2px solid #02a6b5;
-          border-bottom: 2px solid #02a6b5;
-        }
-        &::after{
-          .horn;
-          bottom: 0;
-          right: 0;
-          border-right: 2px solid #02a6b5;
-          border-bottom: 2px solid #02a6b5;
-        }
-      }
-      .panel-title{
-        position: absolute;
-        left: 110px;
-        top: 10px;
-        font-size: 20px;
-        font-weight: bold;
-        color: #0EFCFF;
-      }
-      .panelSwitchTitle{
-        color: #ffffff;
-        font-size: 16px;
-        position: absolute;
-        bottom: 30px;
-        font-weight: bold;
-        left:25px;
-      }
-      .panelSwitch{
-        position: absolute;
-        right: 25px;
-        bottom: 20px;
-      }
-      .panel-slider{
-        width: 250px;
-        position: absolute;
-        top: 60px;
-        left: 25px;
-      }
-      .panel-slider2{
-        width: 250px;
-        position: absolute;
-        top: 120px;
-        left: 25px;
-      }
-      .brightness{
-        width: 250px;
-        display: flex;
-        justify-content: space-between;
-        color: #909399;
-        font-size: 14px;
-      }
-    }
-  }
-}
-
-/* ::v-deep是vue3提供的深度选择器,.el-form-item__label是element-plus官方定义的类 */
-/deep/ .el-form-item__label{
-  color: white;
-  font-size: 16px;
-}
-
-.el-slider__runway{ // 滑块的进度条颜色
-  background-color: #000000;
-}
-</style>
-

+ 8 - 3
web/src/view/layout/index.vue

@@ -82,7 +82,12 @@
                           :key="item.path"
                         >{{ fmtTitle(item.meta.title,route) }}</el-breadcrumb-item>
                       </el-breadcrumb>
-                      <el-button :icon="Menu" text style="margin-left: 20px" @click="jumpScreen">数据大屏</el-button>
+                      <el-button
+                        :icon="Menu"
+                        text
+                        style="margin-left: 20px"
+                        @click="jumpScreen"
+                      >数据大屏</el-button>
                     </el-col>
                     <el-col
                       :xs="12"
@@ -201,7 +206,7 @@ import { useRouter, useRoute } from 'vue-router'
 import { useRouterStore } from '@/pinia/modules/router'
 import { fmtTitle } from '@/utils/fmtRouterTitle'
 import { useUserStore } from '@/pinia/modules/user'
-import { Menu } from "@element-plus/icons-vue";
+import { Menu } from '@element-plus/icons-vue'
 
 defineOptions({
   name: 'Layout',
@@ -257,7 +262,7 @@ const handleCommand = () => {
 }
 
 const jumpScreen = () => {
-  router.push('/dataScreen')
+  router.push('/dataDashboard')
 }
 
 onMounted(() => {

+ 28 - 22
web/src/view/screen/components/chart.vue

@@ -1,25 +1,32 @@
 <template>
-  <img src="@/assets/main_top_left.png" alt="" class="imgStyle"/>
-  <div class="titleIcon"></div>
+  <img
+    src="@/assets/main_top_left.png"
+    alt=""
+    class="imgStyle"
+  >
+  <div class="titleIcon" />
   <div class="chartBox_title">温度/湿度</div>
-  <div id="environment" class="environment"></div>
+  <div
+    id="environment"
+    class="environment"
+  />
 </template>
 
 <script setup>
-import * as echarts from 'echarts';
+import * as echarts from 'echarts'
 import { onMounted, watch } from 'vue'
-import { useScreenStore } from "@/pinia/modules/screen";
+import { useScreenStore } from '@/pinia/modules/screen'
 const useScreen = useScreenStore()
 
 onMounted(() => {
-  setTimeout(function (){
-    const list  = useScreen.tunnelList[0].envData
+  setTimeout(function() {
+    const list = useScreen.tunnelList[0].envData
     chartLoading(list)
   }, 1000)
 })
 
 const chartLoading = (list) => {
-  let myChart = echarts.init(document.getElementById('environment'));
+  const myChart = echarts.init(document.getElementById('environment'))
   myChart.setOption({
     tooltip: {
       trigger: 'axis',
@@ -36,13 +43,13 @@ const chartLoading = (list) => {
         {
           name: '温度',
           textStyle: {
-            color: '#0EFCFF'          // 图例文字颜色
+            color: '#0EFCFF' // 图例文字颜色
           }
         },
         {
           name: '湿度',
           textStyle: {
-            color: '#0EFCFF'          // 图例文字颜色
+            color: '#0EFCFF' // 图例文字颜色
           }
         }
       ],
@@ -51,21 +58,21 @@ const chartLoading = (list) => {
       type: 'time', // 使用时间类型的x轴
       boundaryGap: false,
       axisLine: {
-        show:true,
-        lineStyle:{
-          color:'#0EFCFF',
-          width:1,
-          type:'solid'
+        show: true,
+        lineStyle: {
+          color: '#0EFCFF',
+          width: 1,
+          type: 'solid'
         }
       }
     },
     yAxis: {
       axisLine: {
-        show:true,
-        lineStyle:{
-          color:'#0EFCFF',
-          width:1,
-          type:'solid'
+        show: true,
+        lineStyle: {
+          color: '#0EFCFF',
+          width: 1,
+          type: 'solid'
         }
       },
       splitLine: {
@@ -90,7 +97,7 @@ const chartLoading = (list) => {
 }
 
 // 监听 ref 数据变化
-watch(() => useScreen.currentTunnel, (newValue, oldValue) => {
+watch(() => useScreen.currentTunnel, (newValue) => {
   yourMethod(newValue) // 调用你的方法
 })
 
@@ -129,5 +136,4 @@ const yourMethod = (value) => {
     top: 20px;
   }
 
-
 </style>

+ 28 - 22
web/src/view/screen/components/lightChart.vue

@@ -1,26 +1,33 @@
 <template>
-  <img src="@/assets/main_top_left.png" alt="" class="imgStyle"/>
-  <div class="titleIcon"></div>
+  <img
+    src="@/assets/main_top_left.png"
+    alt=""
+    class="imgStyle"
+  >
+  <div class="titleIcon" />
   <div class="chartBox_title">光照度</div>
-  <div id="light" class="environment"></div>
+  <div
+    id="light"
+    class="environment"
+  />
 </template>
 
 <script setup>
-import * as echarts from 'echarts';
+import * as echarts from 'echarts'
 import { onMounted, watch } from 'vue'
-import { useScreenStore } from "@/pinia/modules/screen";
+import { useScreenStore } from '@/pinia/modules/screen'
 const useScreen = useScreenStore()
 
 onMounted(() => {
-  setTimeout(function (){
-    const list  = useScreen.tunnelList[0].envData
+  setTimeout(function() {
+    const list = useScreen.tunnelList[0].envData
     chartLoading(list)
-  },1000)
+  }, 1000)
 })
 
 const chartLoading = (val) => {
-  //time: moment(item.CreatedAt).format('HH:mm')
-  let myChart = echarts.init(document.getElementById('light'));
+  // time: moment(item.CreatedAt).format('HH:mm')
+  const myChart = echarts.init(document.getElementById('light'))
   myChart.setOption({
     tooltip: {
       trigger: 'axis',
@@ -36,7 +43,7 @@ const chartLoading = (val) => {
         {
           name: '光照度',
           textStyle: {
-            color: '#0EFCFF'          // 图例文字颜色
+            color: '#0EFCFF' // 图例文字颜色
           }
         },
       ]
@@ -45,21 +52,21 @@ const chartLoading = (val) => {
       type: 'time', // 使用时间类型的x轴
       boundaryGap: false,
       axisLine: {
-        show:true,
-        lineStyle:{
-          color:'#0EFCFF',
-          width:1,
-          type:'solid'
+        show: true,
+        lineStyle: {
+          color: '#0EFCFF',
+          width: 1,
+          type: 'solid'
         }
       }
     },
     yAxis: {
       axisLine: {
-        show:true,
-        lineStyle:{
-          color:'#0EFCFF',
-          width:1,
-          type:'solid'
+        show: true,
+        lineStyle: {
+          color: '#0EFCFF',
+          width: 1,
+          type: 'solid'
         }
       },
       splitLine: {
@@ -117,5 +124,4 @@ const yourMethod = (value) => {
   top: 20px;
 }
 
-
 </style>

+ 220 - 38
web/src/view/screen/components/map.vue

@@ -1,75 +1,156 @@
 <template>
   <tlbs-map
-      ref="mapRef"
-      api-key="3SVBZ-6MYYZ-Q75X5-7YN43-BMIBZ-YABND"
-      :center="center"
-      :zoom="zoom"
-      :control="control"
-      class="mapBox"
-      @click="onClick"
-      @map_inited="onMapInited"
+    ref="mapRef"
+    api-key="3SVBZ-6MYYZ-Q75X5-7YN43-BMIBZ-YABND"
+    :center="center"
+    :zoom="zoom"
+    :control="control"
+    class="mapBox"
+    :options="mapOption"
+    @click="onClick"
+    @map_inited="onMapInited"
   >
     <tlbs-multi-marker
-        ref="markerRef"
-        :geometries="geometries"
-        :styles="styles"
-        :options="options"
-        @click="openInfo"
+      ref="markerRef"
+      :geometries="geometries"
+      :styles="styles"
+      :options="options"
+      @click="openInfo"
     />
   </tlbs-map>
-  <el-dialog v-model="dialogVisible" width="250px" title="隧道信息" align-center>
-    <el-form>
+  <el-dialog
+    v-model="dialogVisible"
+    width="350px"
+    title="隧道信息"
+    align-center
+  >
+    <el-form
+      size="large"
+      label-width="70px"
+      label-position="left"
+      label-suffix=""
+    >
       <el-form-item label="名称:">
-        <el-text size="large">{{dialogData.name}}</el-text>
+        <el-text size="large">{{ dialogData.name }}</el-text>
       </el-form-item>
       <el-form-item label="类型:">
-        <el-text size="large">{{dialogData.switchType}}</el-text>
+        <el-text size="large">{{ dialogData.switchType }}</el-text>
+      </el-form-item>
+      <el-form-item label="灯控1:">
+        <el-slider
+          v-if="dialogData.switchType === '单灯控制器'"
+          v-model="transparency"
+          :step="50"
+          show-stops
+          :show-tooltip="false"
+          @change="changeTransparency($event,'单灯','')"
+        />
+        <div
+          v-if="dialogData.switchType === '四路控制器'"
+          style="width: 100%;display: flex; justify-content: space-between"
+        >
+          <el-switch
+            v-for="(item,index) in relayList[0].relay"
+            :key="item.id"
+            v-model="item.state"
+            :disabled="index === 0"
+            @change="changeTransparency($event,'四路',item)"
+          />
+        </div>
+      </el-form-item>
+      <el-form-item label="灯控2:">
+        <el-slider
+          v-if="dialogData.switchType === '单灯控制器'"
+          v-model="transparencyTwo"
+          :step="50"
+          show-stops
+          :show-tooltip="false"
+          @change="changeTransparencyTwo($event,'单灯','')"
+        />
+        <div
+          v-if="dialogData.switchType === '四路控制器'"
+          style="width: 100%;display: flex; justify-content: space-between"
+        >
+          <el-switch
+            v-for="(item,index) in relayList[1].relay"
+            :key="item.id"
+            v-model="item.state"
+            :disabled="index === 0"
+            @change="changeTransparencyTwo($event,'四路',item)"
+          />
+        </div>
+      </el-form-item>
+      <el-form-item
+        v-if="dialogData.switchType === '单灯控制器'"
+        label-width="0"
+      >
+        <el-button
+          type="primary"
+          style="width: 100%"
+          @click="singleLamp"
+        >
+          设定
+        </el-button>
       </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="callParentMethod">查看数据</el-button>
+      <el-form-item label-width="0">
+        <div style="width: 100%; display: flex; justify-content: space-between">
+          <el-button
+            type="primary"
+            @click="callParentMethod"
+          >查看数据</el-button>
+          <el-button
+            type="primary"
+          >查看模型</el-button>
+        </div>
       </el-form-item>
     </el-form>
   </el-dialog>
 </template>
 
 <script>
-import { defineComponent, ref } from 'vue-demi';
-import {useScreenStore} from "@/pinia/modules/screen";
+import { defineComponent, ref, reactive } from 'vue-demi'
+import { useScreenStore } from '@/pinia/modules/screen'
+import { updateTunnelLamp } from '@/api/tunnel'
+import { ElMessage } from 'element-plus'
+import { deviceSwitch } from '@/api/device'
 const useScreen = useScreenStore()
 export default defineComponent({
   name: 'MarkerDemo',
   setup() {
-    const mapRef = ref(null);
-    const markerRef = ref(null);
-    const center = ref({ lat: 28.7052848, lng: 113.5759597 });
-    const zoom = ref(10);
+    const mapRef = ref(null)
+    const markerRef = ref(null)
+    const center = ref({ lat: 28.7052848, lng: 113.5759597 })
+    const zoom = ref(10)
     const geometries = ref(useScreen.placeList)
     const dialogVisible = ref(false)
     const dialogData = ref({})
+    const mapOption = ref({
+      mapStyleId: 'style1'
+    })
     const onClick = (e) => {
-      console.log(e.latLng);
+      console.log(e.latLng)
       // geometries.value = [
       //   {
       //     styleId: 'marker',
-      //     position: { lat: 28.7052848, lng: 113.5759597 } ,
+      //     position: { lat: 28.7052848, lng: 113.5759597 },
       //   },
       //   {
       //     styleId: 'marker',
-      //     position: { lat: e.latLng.lat, lng: e.latLng.lng } ,
+      //     position: { lat: e.latLng.lat, lng: e.latLng.lng },
       //   },
       // ]
-    };
+    }
 
     const onMapInited = () => {
       // 地图加载完成后,可以获取地图实例、点标记实例,调用地图实例、点标记实例方法
-      console.log(mapRef.value.map);
-      console.log(markerRef.value.marker);
-    };
+      // console.log(mapRef.value.map)
+      // console.log(markerRef.value.marker)
+    }
 
     const getLayerInstance = () => {
       // 可以获取点标记实例,调用点标记实例方法
-      console.log(markerRef.value.marker);
-    };
+      console.log(markerRef.value.marker)
+    }
     const openInfo = (e) => {
       dialogVisible.value = true
       const id = e.geometry.styleId
@@ -77,6 +158,7 @@ export default defineComponent({
       list.forEach(item => {
         if (item.ID === id) {
           dialogData.value = item
+          brightness(item)
         }
       })
     }
@@ -84,6 +166,95 @@ export default defineComponent({
       useScreen.setCurrentTunnel(dialogData.value)
       dialogVisible.value = false
     }
+    // const viewModel = () => {
+    //   useScreen.setScreenType('pattern')
+    //   dialogVisible.value = false
+    // }
+    // 亮度调节
+    const transparency = ref(0)
+    const transparencyTwo = ref(0)
+    const materialOne = reactive({})
+    const materialTwo = reactive({})
+    const relayList = reactive([])
+    const lampData = reactive({})
+    const brightness = (item) => {
+      Object.assign(lampData, item)
+      if (item.switchType === '单灯控制器') {
+        const val1 = item.lampValue1
+        const val2 = item.lampValue2
+        const judge = {
+          0: [0.8, 0],
+          33: [0.8, 0],
+          66: [0.5, 50],
+          100: [0.2, 100],
+        }
+        transparency.value = judge[val1][1]
+        transparencyTwo.value = judge[val2][1]
+        materialOne.opacity = judge[val1][0]
+        materialTwo.opacity = judge[val2][0]
+      } else if (item.switchType === '四路控制器') {
+        relayList.length = 0
+        item.devices.forEach(option => {
+          if (option.genre === 6) {
+            relayList.push({ radarId: option.radarId, relay: option.deviceRelays })
+          }
+        })
+      }
+    }
+    const changeTransparency = (e, type, data) => {
+      // materialOne.opacity = option[e][0]
+      if (type === '单灯') {
+        transparency.value = e
+      } else {
+        deviceSwitch({
+          tunnelSn: lampData.tunnelSn,
+          radarId: relayList[0].radarId,
+          relayId: data.relayId,
+          state: e
+        }).then(res => {
+          if (res.code === 0) {
+            console.log('发送成功')
+          }
+        })
+      }
+    }
+    const changeTransparencyTwo = (e, type, data) => {
+      // materialOne.opacity = option[e][0]
+      if (type === '单灯') {
+        transparencyTwo.value = e
+      } else {
+        deviceSwitch({
+          tunnelSn: lampData.tunnelSn,
+          radarId: relayList[1].radarId,
+          relayId: data.relayId,
+          state: e
+        }).then(res => {
+          if (res.code === 0) {
+            console.log('发送成功')
+          }
+        })
+      }
+    }
+    const singleLamp = () => {
+      const option = {
+        0: [0.8, 33, 1],
+        50: [0.5, 66, 2],
+        100: [0.2, 100, 3]
+      }
+      const lamp1 = option[transparency.value][1]
+      const lamp2 = option[transparencyTwo.value][1]
+      console.log(lamp1, lamp2)
+      updateTunnelLamp({
+        id: lampData.ID,
+        tunnelSn: lampData.tunnelSn,
+        lampValue1: lamp1,
+        lampValue2: lamp2
+      }).then(res => {
+        if (res.code === 0) {
+          ElMessage.success('已发送')
+        }
+      })
+    }
     return {
       center,
       zoom,
@@ -114,15 +285,26 @@ export default defineComponent({
       dialogVisible,
       dialogData,
       callParentMethod,
-    };
+      mapOption,
+      // 亮度调节
+      transparency,
+      transparencyTwo,
+      materialOne,
+      materialTwo,
+      brightness,
+      changeTransparency,
+      changeTransparencyTwo,
+      relayList,
+      singleLamp
+    }
   },
-});
+})
 </script>
 
 <style scoped lang="less">
 .mapBox{
-  width: 1150px;
-  height: 800px;
+  width: 1200px;
+  height: 600px;
 }
 
 .infoDialog{

+ 130 - 75
web/src/view/screen/components/pattern.vue

@@ -1,119 +1,174 @@
 <template>
-  <div ref="container" class="model-container"></div>
+  <div
+    ref="container"
+    class="three-container"
+  />
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount } from 'vue'
 import * as THREE from 'three'
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
-import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
+import { onMounted, onUnmounted, reactive, ref } from 'vue'
+import { useScreenStore } from '@/pinia/modules/screen'
 
+const useScreen = useScreenStore()
+// 获取容器引用
 const container = ref(null)
 
-// 初始化场景
-const scene = new THREE.Scene()
-// 相机
-const camera = new THREE.PerspectiveCamera(
+// 定义 Three.js 相关变量
+let scene, camera, renderer, controls
+
+// 创建场景
+// eslint-disable-next-line prefer-const
+scene = new THREE.Scene()
+
+// 添加环境光
+const ambientLight = new THREE.AmbientLight(0xffffff, 1)
+
+// 初始化 Three.js 场景
+const initThree = () => {
+  scene.background = null
+  // textureLoader.load('@/assets/OIP-C.jpg', (texture) => {
+  //   // 将图片设置为场景的背景
+  //   scene.background = texture;
+  // });
+  // 创建相机
+  camera = new THREE.PerspectiveCamera(
     75,
-    window.innerWidth / window.innerHeight,
+    container.value.clientWidth / container.value.clientHeight,
     0.1,
     1000
-)
-// 渲染器
-const renderer = new THREE.WebGLRenderer({
-  antialias: true,
-  alpha: true
-})
-
-// 添加光源
-const ambientLight = new THREE.AmbientLight(0xffffff, 2)
-
-let controls = null
-let model = null
-
-// 初始化场景
-const initScene = () => {
-  if (!container.value) return
-  camera.position.set(30, 30, 30);
-  scene.add(ambientLight)
+  )
+  camera.position.set(30, 20, 30)
 
-  // 设置渲染器
+  // 创建渲染器
+  renderer = new THREE.WebGLRenderer({ antialias: true })
   renderer.setSize(container.value.clientWidth, container.value.clientHeight)
-  renderer.setPixelRatio(window.devicePixelRatio)
-  renderer.outputEncoding = THREE.sRGBEncoding
+  renderer.setClearAlpha(0)
+  // renderer.setClearColor(222842);
   container.value.appendChild(renderer.domElement)
 
+  // 添加轨道控制器
+  controls = new OrbitControls(camera, renderer.domElement)
+  controls.enableDamping = true // 启用阻尼效果
+  controls.dampingFactor = 0.05
+
+  scene.add(ambientLight)
 
-  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
-  directionalLight.position.set(5, 5, 5)
+  // 添加平行光
+  const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
+  directionalLight.position.set(5, 5, 5).normalize()
   scene.add(directionalLight)
+}
 
-  // 添加轨道控制器
-  controls = new OrbitControls(camera, renderer.domElement);
-  controls.enableDamping = true; // 启用阻尼效果
-  controls.dampingFactor = 0.05;
-  scene.add(ambientLight);
+// 存储模型数据
+let materialOne = reactive({})
+let materialTwo = reactive({})
 
-}
+const relayList = reactive([])
 
-// 加载模型
+// 加载 GLB 模型
 const loadModel = () => {
   const loader = new GLTFLoader()
-
-  loader.load(
-      '../public/隧道1.glb', // 模型路径
-      (gltf) => {
-        model = gltf.scene
-        scene.add(model)
-      },
-      undefined, // 进度回调(可选)
-      (error) => {
-        console.error('Error loading model:', error)
+  loader.load('../../public/隧道1.glb', function(gltf) {
+    const object = gltf.scene
+    object.children.forEach(item => {
+      if (item.name === '柱体') {
+        materialOne = item.children[3].material
+      } else if (item.name === '柱体001') {
+        materialTwo = item.children[3].material
       }
+    })
+    // gltf.scene获取gltf文件包含的模型数据
+    scene.add(gltf.scene)
+  }, function(xhr) {
+    // 加载进度回调
+    // console.log((xhr.loaded / xhr.total * 100) + '% loaded');
+  }, function(error) {
+    // 加载错误回调
+    // console.error('An error happened', error);
+  }
   )
 }
 
 // 动画循环
 const animate = () => {
   requestAnimationFrame(animate)
-  if (controls) controls.update()
+  controls.update() // 更新控制器
   renderer.render(scene, camera)
 }
 
+// 亮度调整
+const transparency = ref(0)
+
+const transparencyTwo = ref(0)
+
+// 灯光数据
+const lampData = reactive({})
+
+const judgeLamp = () => {
+  relayList.length = 0
+  if (lampData.switchType === '单灯控制器') {
+    const val1 = lampData.lampValue1
+    const val2 = lampData.lampValue2
+    const judge = {
+      33: [0.8, 0],
+      66: [0.5, 50],
+      100: [0.2, 100],
+    }
+    transparency.value = judge[val1][1]
+    materialOne.opacity = judge[val1][0]
+    transparencyTwo.value = judge[val1][1]
+    materialTwo.opacity = judge[val2][0]
+  } else if (lampData.switchType === '四路控制器') {
+    lampData.devices.forEach(item => {
+      if (item.genre === 6) {
+        relayList.push(item)
+      }
+    })
+    const deviceLamp1 = relayList[0].deviceRelays
+    const deviceLamp2 = relayList[1].deviceRelays
+    let count1 = 0
+    let count2 = 0
+    deviceLamp1.forEach(item => {
+      item.state ? count1++ : count1
+    })
+    deviceLamp2.forEach(item => {
+      item.state ? count2++ : count2
+    })
+    const judgeWay = {
+      1: [0.8, 0],
+      2: [0.5, 50],
+      3: [0.2, 100],
+      4: [0.2, 100]
+    }
+    transparency.value = judgeWay[count1][1]
+    materialOne.opacity = judgeWay[count1][0]
+    transparencyTwo.value = judgeWay[count2][1]
+    materialTwo.opacity = judgeWay[count2][0]
+  }
+}
 
+// 组件挂载时初始化
 onMounted(() => {
-  initScene()
+  Object.assign(lampData, useScreen.controllerData)
+  initThree()
   loadModel()
   animate()
+  setTimeout(function() {
+    judgeLamp()
+  }, 500)
 })
 
-onBeforeUnmount(() => {
-  window.removeEventListener('resize', handleResize)
-  if (container.value && container.value.contains(renderer.domElement)) {
-    container.value.removeChild(renderer.domElement)
-  }
-
-  // 清理模型资源
-  if (model) {
-    scene.remove(model)
-    model.traverse((child) => {
-      if (child.isMesh) {
-        child.geometry.dispose()
-        if (Array.isArray(child.material)) {
-          child.material.forEach(m => m.dispose())
-        } else {
-          child.material.dispose()
-        }
-      }
-    })
+// 组件卸载时清理资源
+onUnmounted(() => {
+  if (renderer) {
+    renderer.dispose()
   }
 })
 </script>
 
 <style scoped>
-.model-container {
-  width: 100%;
-  height: 100vh;
-  position: relative;
-}
+
 </style>

+ 458 - 0
web/src/view/screen/dataDashboard.vue

@@ -0,0 +1,458 @@
+<template>
+  <div style="background-color: #0e122d">
+    <div class="screenTitle">
+      <img
+        :src="topBg"
+        alt=""
+      >
+      <span>龙弛智慧隧道系统</span>
+    </div>
+    <div class="screen">
+      <div class="leftBox">
+        <div class="deviceSummary">
+          <div class="deviceSummary_title">
+            <img
+              alt=""
+              :src="Device"
+              style="padding-left: 15px"
+            >
+            <span style="padding-left: 10px;">设备汇总</span>
+          </div>
+          <div class="deviceOptionBox">
+            <div
+              v-for="item in deviceTypeList"
+              :key="item.id"
+              class="deviceOption"
+            >
+              <div class="deviceOption">
+                <div style="width: 35px;height: 35px">
+                  <img
+                      :src="item.url"
+                      style="width: 35px;height: 35px"
+                      alt=""
+                  >
+                </div>
+                <el-text
+                    style="padding-top: 8px;color: #ffffff"
+                    size="small"
+                >{{ item.label + item.value }}</el-text>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="inductance">
+          <div class="inductanceTitle">
+            <img
+              alt=""
+              :src="Power"
+              style="padding-left: 15px"
+            >
+            <span style="padding-left: 10px;">电感检测</span>
+          </div>
+        </div>
+        <div class="warn">
+          <div class="warnTitle">
+            <img
+              alt=""
+              :src="Warn"
+              style="padding-left: 15px"
+            >
+            <span style="padding-left: 10px;">警告列表</span>
+          </div>
+        </div>
+      </div>
+      <div class="centerBox">
+        <div style="width: 1200px;height: 600px;border: 3px solid #1b92fd; padding: 2px">
+          <Map />
+        </div>
+        <div class="centerBox_chart">
+          <div class="centerBox_environment">
+            <div class="centerBox_environment_title">
+              <img
+                :src="Setting"
+                alt=""
+                style="padding-left: 10px"
+              >
+              <span style="padding-left: 15px;">环境</span>
+            </div>
+            <div
+              id="environment"
+              class="centerBox_environment_chart"
+              style="width: 500px"
+            />
+          </div>
+          <div class="centerBox_environment">
+            <div class="centerBox_environment_title">
+              <img
+                :src="Sunlight"
+                alt=""
+                style="padding-left: 10px"
+              >
+              <span style="padding-left: 15px;">光照度</span>
+            </div>
+            <div
+              id="lamp"
+              class="centerBox_environment_chart"
+              style="width: 500px"
+            />
+          </div>
+        </div>
+      </div>
+      <div class="rightBox" />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import Device from '@/assets/icons/device.png'
+import { reactive, onMounted, watch } from 'vue'
+// import environments from '@/assets/icons/environment.png'
+// import fourWays from '@/assets/icons/fourWays.png'
+// import inductance from '@/assets/icons/inductance.png'
+// import singleLamp from '@/assets/icons/singleLamp.png'
+import Setting from '@/assets/icons/setting.png'
+import Sunlight from '@/assets/icons/sunlight.png'
+import topBg from '@/assets/icons/topbg.png'
+import Power from '@/assets/icons/power.png'
+import Warn from '@/assets/icons/warn.png'
+import Map from '@/view/screen/components/map.vue'
+import * as echarts from 'echarts'
+import { useScreenStore } from '@/pinia/modules/screen'
+import { queryTunnelList } from '@/api/tunnel'
+import { queryAllDevices, queryAllDeviceGenres } from '@/api/device'
+
+const useScreen = useScreenStore()
+
+// const deviceList = reactive([
+//   { url: environments, label: '环境:', value: '1/0' },
+//   { url: fourWays, label: '四路:', value: '1/0' },
+//   { url: inductance, label: '电感:', value: '1/0' },
+//   { url: singleLamp, label: '单灯:', value: '1/0' },
+// ])
+
+const deviceTypeList = reactive([])
+
+const condition = {
+  pageInfo: {
+    page: 1,
+    pageSize: 1000
+  },
+  name: '',
+  regionId: 0,
+  userId: 1
+}
+
+const lampData = reactive({})
+onMounted(() => {
+  queryTunnelList(condition).then(res => {
+    if (res.code === 0) {
+      useScreen.setTunnelList(res.data)
+      Object.assign(lampData, res.data.list[0])
+      loading(lampData.envData)
+      loadingLamp(lampData.envData)
+    }
+  })
+  queryAllDevices().then(res => {
+    console.log('res', res)
+  })
+  queryAllDeviceGenres().then(res => {
+    if (res.code === 0) {
+      const result = []
+      for (let i = 0; i < res.data.length; i += 4) {
+        result.push(res.data.slice(i, i + 4))
+      }
+      deviceTypeList.push(...result)
+      console.log('设备类型', deviceTypeList)
+    }
+  })
+})
+
+const loading = (list) => {
+  const chartDom = document.getElementById('environment')
+  const myChart = echarts.init(chartDom)
+  const option = {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross',
+        crossStyle: {
+          color: '#ffffff'
+        }
+      },
+    },
+    legend: {
+      data: [
+        // '待下发','处置中','已完成'
+        {
+          name: '温度',
+          textStyle: {
+            color: '#0EFCFF' // 图例文字颜色
+          }
+        },
+        {
+          name: '湿度',
+          textStyle: {
+            color: '#1b92fd' // 图例文字颜色
+          }
+        }
+      ],
+    },
+    xAxis: {
+      type: 'time', // 使用时间类型的x轴
+      boundaryGap: false,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#ffffff',
+          width: 1,
+          type: 'solid'
+        }
+      }
+    },
+    yAxis: {
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#ffffff',
+          width: 1,
+          type: 'solid'
+        }
+      },
+      splitLine: {
+        lineStyle: {
+          color: ['#ffffff']
+        }
+      }
+    },
+    series: [
+      {
+        name: '温度',
+        type: 'line',
+        data: list.map(item => [new Date(item.CreatedAt).getTime(), item.temperature])
+      },
+      {
+        name: '湿度',
+        type: 'line',
+        data: list.map(item => [new Date(item.CreatedAt).getTime(), item.humidity])
+      }
+    ],
+  }
+
+  option && myChart.setOption(option)
+}
+
+const loadingLamp = (list) => {
+  const chartDom = document.getElementById('lamp')
+  const myChart = echarts.init(chartDom)
+  const option = {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross',
+        crossStyle: {
+          color: '#ffffff'
+        }
+      },
+    },
+    legend: {
+      data: [
+        {
+          name: '光照度',
+          textStyle: {
+            color: '#ffffff' // 图例文字颜色
+          }
+        },
+      ]
+    },
+    xAxis: {
+      type: 'time', // 使用时间类型的x轴
+      boundaryGap: false,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#ffffff',
+          width: 1,
+          type: 'solid'
+        }
+      }
+    },
+    yAxis: {
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#ffffff',
+          width: 1,
+          type: 'solid'
+        }
+      },
+      splitLine: {
+        lineStyle: {
+          color: ['#ffffff']
+        }
+      }
+    },
+    series: [
+      {
+        name: '光照度',
+        type: 'bar',
+        data: list.map(item => [new Date(item.CreatedAt).getTime(), item.illuminance])
+      },
+    ]
+  }
+
+  option && myChart.setOption(option)
+}
+
+watch(() => useScreen.currentTunnel, (newValue) => {
+  loading(newValue.envData)
+  loadingLamp(newValue.envData)
+})
+
+</script>
+
+<style scoped lang="less">
+// 公共样式
+.title {
+  display: flex;
+  align-items: center;
+  font-size: 20px;
+  font-family: PingFang-SC-Medium,serif;
+  color: rgba(27, 146, 253, 1);
+}
+.boxShape {
+  width: 370px;
+  border: 1px solid rgba(27,146,253,0.5);
+  background: rgba(50, 72, 106, 0.2);
+  margin-left: 20px;
+}
+//.....................
+.screenTitle{
+  width: 100%;
+  height: 100px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  //background: linear-gradient(to bottom, #2583e0, #80aad8); /*设置渐变的方向从左到右 颜色从ff0000到ffff00*/
+  //-webkit-background-clip: text;/*将设置的背景颜色限制在文字中*/
+  //-webkit-text-fill-color: transparent;/*给文字设置成透明*/
+  position: relative;
+  span{
+    position: absolute;
+    top: 30px;
+    left: 890px;
+    font-size: 30px;
+    color: #ffffff;
+    padding-left: 20px;
+    letter-spacing: 10px;
+  }
+  img{
+    height: 80px;
+  }
+}
+.screen{
+  width: 100%;
+  height: 1200px;
+  background-color: #0e122d;
+  display: flex;
+  margin-top: 20px;
+  .leftBox {
+    width: 20%;
+    height: 1200px;
+    .deviceSummary {
+      height: 150px;
+      .boxShape;
+      .deviceSummary_title {
+        width: 370px;
+        height: 50px;
+        .title;
+        img{
+          width: 30px;
+          height: 30px;
+        }
+      }
+      .deviceOptionBox {
+        width: 370px;
+        height: 120px;
+        display: flex;
+        margin-top: 20px;
+        .deviceOption {
+          width: 90px;
+          height: 60px;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          color: #ffffff;
+        }
+      }
+    }
+    .inductance {
+      height: 200px;
+      margin-top: 20px;
+      .boxShape;
+      .inductanceTitle {
+        width: 370px;
+        height: 50px;
+        .title;
+        img{
+          width: 30px;
+          height: 30px;
+        }
+      }
+    }
+    .warn {
+      height: 470px;
+      margin-top: 20px;
+      .boxShape;
+      .warnTitle {
+        width: 370px;
+        height: 50px;
+        .title;
+        img{
+          width: 30px;
+          height: 30px;
+        }
+      }
+    }
+  }
+  .centerBox {
+    width: 60%;
+    height: 1200px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .centerBox_chart {
+      width: 1200px;
+      height: 220px;
+      margin-top: 40px;
+      display: flex;
+      justify-content: space-between;
+      border: 1px solid rgba(27,146,253,0.5);
+      background: rgba(50, 72, 106, 0.2);
+    }
+    .centerBox_environment{
+      width: 500px;
+      height: 220px;
+      position: relative;
+      .centerBox_environment_title {
+        width: 500px;
+        height: 50px;
+        .title;
+        img {
+          width: 30px;
+          height: 30px;
+        }
+      }
+      .centerBox_environment_chart {
+        height: 250px;
+        position: absolute;
+        top: 5px;
+      }
+    }
+  }
+  .rightBox {
+    width: 20%;
+    height: 1200px;
+  }
+}
+</style>
+

+ 178 - 115
web/src/view/screen/dataScreen.vue

@@ -1,115 +1,172 @@
 <template>
   <div class="screen">
-    <div style="height: 10px"></div>
+    <div style="height: 10px" />
     <div class="titleImage">
       <el-image :src="titleUrl" />
       <span class="Heading">龙弛智慧隧道系统</span>
-      <div class="titleOption" style="left: 19%" @click="jumpScreen('map')">
+      <div
+        class="titleOption"
+        style="left: 19%"
+      >
         <span>地图</span>
       </div>
-      <div class="titleOption" style="left: 76%" @click="jumpScreen('model')">
+      <div
+        class="titleOption"
+        style="left: 76%"
+      >
         <span>模型</span>
       </div>
     </div>
-    <div style="height: 10px"></div>
+    <div style="height: 10px" />
     <el-row>
-      <el-col :span="5" style="height: 900px;">
+      <el-col
+        :span="5"
+        style="height: 900px;"
+      >
         <div class="deviceBox">
-          <img src="@/assets/main_top_left.png" alt=""/>
-          <div class="titleIcon"></div>
+          <img
+            src="@/assets/main_top_left.png"
+            alt=""
+          >
+          <div class="titleIcon" />
           <div class="deviceBox_title">设备汇总</div>
           <div class="deviceOptionBox">
-            <div class="deviceOption" v-for="item in deviceList">
-              <img :src="item.url" style="width: 35px;height: 35px"  alt=""/>
-              <el-text style="padding-top: 8px;color: #ffffff" size="small">{{item.label + item.value}}</el-text>
+            <div
+              v-for="item in deviceList"
+              class="deviceOption"
+            >
+              <img
+                :src="item.url"
+                style="width: 35px;height: 35px"
+                alt=""
+              >
+              <el-text
+                style="padding-top: 8px;color: #ffffff"
+                size="small"
+              >{{ item.label + item.value }}</el-text>
             </div>
           </div>
         </div>
         <div class="chartBox">
-          <Chart/>
+          <Chart />
         </div>
         <div class="chartBox">
-          <lightChart/>
+          <lightChart />
         </div>
       </el-col>
-      <el-col :span="14" style="display: flex;justify-content: center">
+      <el-col
+        :span="14"
+        style="display: flex;justify-content: center"
+      >
         <div class="centerBox">
-          <Map @call-parent="parentMethod"/>
+          <Map v-if="useScreen.screenType === 'map'" />
+          <div
+            v-if="useScreen.screenType === 'pattern'"
+            style="position: relative"
+          >
+            <el-button
+              style="position: absolute;z-index: 1;"
+              type="info"
+              text
+              icon="ArrowLeft"
+              @click="returnMap"
+            >
+              返回地图
+            </el-button>
+            <Pattern style="position: absolute;z-index: 2;pointer-events: none;" />
+          </div>
         </div>
       </el-col>
-      <el-col :span="5" class="rightBox">
-        <div style="height: 20px"></div>
+      <el-col
+        :span="5"
+        class="rightBox"
+      >
+        <div style="height: 20px" />
         <div class="panel">
           <span class="panel-title">亮度调整</span>
           <el-slider
-              v-model="transparency"
-              :step="50"
-              show-stops
-              :show-tooltip="false"
-              class="panel-slider"
-              @change="changeTransparency"
+            v-model="transparency"
+            :step="50"
+            show-stops
+            :show-tooltip="false"
+            class="panel-slider"
+            @change="changeTransparency"
           />
-          <div class="brightness" style="margin: 90px 0 0 50px;">
+          <div
+            class="brightness"
+            style="margin: 90px 0 0 50px;"
+          >
             <span>低</span>
             <span>中</span>
             <span>高</span>
           </div>
           <el-slider
-              v-model="transparencyTwo"
-              :step="50"
-              show-stops
-              :show-tooltip="false"
-              class="panel-slider2"
-              @change="changeTransparencyTwo"
+            v-model="transparencyTwo"
+            :step="50"
+            show-stops
+            :show-tooltip="false"
+            class="panel-slider2"
+            @change="changeTransparencyTwo"
           />
-          <div class="brightness" style="margin: 50px 0 0 50px;">
+          <div
+            class="brightness"
+            style="margin: 50px 0 0 50px;"
+          >
             <span>低</span>
             <span>中</span>
             <span>高</span>
           </div>
-          <div class="panel-bottom"></div>
+          <div class="panel-bottom" />
         </div>
-<!--        <div class="vehicleBox">-->
-<!--          <div class="panel" style="height: 190px">-->
-<!--            <span class="panel-title">车辆检测器</span>-->
-<!--            <el-form style="position: absolute;left: 40px;top: 50px">-->
-<!--              <el-form-item label="交通量" label-width="110" label-position="left">-->
-<!--                <el-row style="width: 200px">-->
-<!--                  <el-col :span="15" class="vehicleData">-->
-<!--                    <span>123</span>-->
-<!--                  </el-col>-->
-<!--                  <el-col :span="9" class="vehicleUnit">-->
-<!--                    <span>辆</span>-->
-<!--                  </el-col>-->
-<!--                </el-row>-->
-<!--              </el-form-item>-->
-<!--              <el-form-item label="平均车速" label-width="110" label-position="left">-->
-<!--                <el-row style="width: 200px">-->
-<!--                  <el-col :span="15" class="vehicleData">-->
-<!--                    <span>66</span>-->
-<!--                  </el-col>-->
-<!--                  <el-col :span="9" class="vehicleUnit">-->
-<!--                    <span>km/h</span>-->
-<!--                  </el-col>-->
-<!--                </el-row>-->
-<!--              </el-form-item>-->
-<!--              <el-form-item label="车道占有量" label-width="110" label-position="left">-->
-<!--                <el-row style="width: 200px">-->
-<!--                  <el-col :span="15" class="vehicleData">-->
-<!--                    <span>12</span>-->
-<!--                  </el-col>-->
-<!--                  <el-col :span="9" class="vehicleUnit">-->
-<!--                    <span>%</span>-->
-<!--                  </el-col>-->
-<!--                </el-row>-->
-<!--              </el-form-item>-->
-<!--            </el-form>-->
-<!--            <div class="panel-bottom"></div>-->
-<!--          </div>-->
-<!--        </div>-->
+        <!--        <div class="vehicleBox">-->
+        <!--          <div class="panel" style="height: 190px">-->
+        <!--            <span class="panel-title">车辆检测器</span>-->
+        <!--            <el-form style="position: absolute;left: 40px;top: 50px">-->
+        <!--              <el-form-item label="交通量" label-width="110" label-position="left">-->
+        <!--                <el-row style="width: 200px">-->
+        <!--                  <el-col :span="15" class="vehicleData">-->
+        <!--                    <span>123</span>-->
+        <!--                  </el-col>-->
+        <!--                  <el-col :span="9" class="vehicleUnit">-->
+        <!--                    <span>辆</span>-->
+        <!--                  </el-col>-->
+        <!--                </el-row>-->
+        <!--              </el-form-item>-->
+        <!--              <el-form-item label="平均车速" label-width="110" label-position="left">-->
+        <!--                <el-row style="width: 200px">-->
+        <!--                  <el-col :span="15" class="vehicleData">-->
+        <!--                    <span>66</span>-->
+        <!--                  </el-col>-->
+        <!--                  <el-col :span="9" class="vehicleUnit">-->
+        <!--                    <span>km/h</span>-->
+        <!--                  </el-col>-->
+        <!--                </el-row>-->
+        <!--              </el-form-item>-->
+        <!--              <el-form-item label="车道占有量" label-width="110" label-position="left">-->
+        <!--                <el-row style="width: 200px">-->
+        <!--                  <el-col :span="15" class="vehicleData">-->
+        <!--                    <span>12</span>-->
+        <!--                  </el-col>-->
+        <!--                  <el-col :span="9" class="vehicleUnit">-->
+        <!--                    <span>%</span>-->
+        <!--                  </el-col>-->
+        <!--                </el-row>-->
+        <!--              </el-form-item>-->
+        <!--            </el-form>-->
+        <!--            <div class="panel-bottom"></div>-->
+        <!--          </div>-->
+        <!--        </div>-->
         <div class="warnBox">
-          <img :src="warn" alt="" class="warnBoxExternal" />
-          <img :src="warnTitle" alt="" class="warnBoxTitle"/>
+          <img
+            :src="warn"
+            alt=""
+            class="warnBoxExternal"
+          >
+          <img
+            :src="warnTitle"
+            alt=""
+            class="warnBoxTitle"
+          >
           <span>警告列表</span>
         </div>
       </el-col>
@@ -120,32 +177,34 @@
 <script setup>
 // 标题图片
 import titleUrl from '@/assets/title_bg.png'
-import environments from "@/assets/icons/environment.png";
-import fourWays from "@/assets/icons/fourWays.png"
-import inductance from "@/assets/icons/inductance.png"
-import singleLamp from "@/assets/icons/singleLamp.png"
-import Chart from "./components/chart.vue";
+import environments from '@/assets/icons/environment.png'
+import fourWays from '@/assets/icons/fourWays.png'
+import inductance from '@/assets/icons/inductance.png'
+import singleLamp from '@/assets/icons/singleLamp.png'
+import Chart from './components/chart.vue'
 import warn from '@/assets/main_bottopm_top2.png'
 import Map from './components/map.vue'
+import Pattern from './components/pattern.vue'
 import warnTitle from '@/assets/warnTitle.png'
 import lightChart from './components/lightChart.vue'
 import { queryTunnelList } from '@/api/tunnel'
-import {reactive, onMounted, ref, watch} from 'vue'
+import { reactive, onMounted, ref, watch } from 'vue'
 // 单灯控制
-import { updateTunnelLamp } from "@/api/tunnel";
+import { updateTunnelLamp } from '@/api/tunnel'
 // 四路控制
-import { deviceSwitch } from "@/api/device";
-import {useScreenStore} from "@/pinia/modules/screen";
-import {ElMessage} from "element-plus";
+import { deviceSwitch } from '@/api/device'
+import { useScreenStore } from '@/pinia/modules/screen'
+import { ElMessage } from 'element-plus'
+
 // 灯光数据
 const lampData = reactive({})
 const useScreen = useScreenStore()
 
 const deviceList = reactive([
-  {url: environments, label: '环境:', value: '1/0'},
-  {url: fourWays, label: '四路:', value: '1/0'},
-  {url: inductance, label: '电感:', value: '1/0'},
-  {url: singleLamp, label: '单灯:', value: '1/0'},
+  { url: environments, label: '环境:', value: '1/0' },
+  { url: fourWays, label: '四路:', value: '1/0' },
+  { url: inductance, label: '电感:', value: '1/0' },
+  { url: singleLamp, label: '单灯:', value: '1/0' },
 ])
 
 const condition = {
@@ -159,14 +218,14 @@ const condition = {
 }
 
 // 存储模型数据
-let materialOne = reactive({})
-let materialTwo = reactive({})
+const materialOne = reactive({})
+const materialTwo = reactive({})
 
 // 亮度调整
 const transparency = ref(0)
 const relayList = reactive([])
 const changeTransparency = (e) => {
-  let option = {
+  const option = {
     0: [0.8, 33, 1],
     50: [0.5, 66, 2],
     100: [0.2, 100, 3]
@@ -183,9 +242,9 @@ const changeTransparency = (e) => {
       }
     })
   } else {
-    let relay = relayList[0].deviceRelays
+    const relay = relayList[0].deviceRelays
     for (let i = 0; i < relay.length; i++) {
-      relay[i].state = i < option[e][2];
+      relay[i].state = i < option[e][2]
     }
     for (let j = 0; j < relay.length; j++) {
       deviceSwitch({
@@ -204,7 +263,7 @@ const changeTransparency = (e) => {
 
 const transparencyTwo = ref(0)
 const changeTransparencyTwo = (e) => {
-  let option = {
+  const option = {
     0: [0.8, 33, 1],
     50: [0.5, 66, 2],
     100: [0.2, 100, 3]
@@ -221,9 +280,9 @@ const changeTransparencyTwo = (e) => {
       }
     })
   } else {
-    let relay = relayList[1].deviceRelays
+    const relay = relayList[1].deviceRelays
     for (let i = 0; i < relay.length; i++) {
-      relay[i].state = i < option[e][2];
+      relay[i].state = i < option[e][2]
     }
     for (let j = 0; j < relay.length; j++) {
       deviceSwitch({
@@ -233,41 +292,36 @@ const changeTransparencyTwo = (e) => {
         state: relay[j].state
       }).then(res => {
         if (res.code === 0) {
-          console.log('发送成功');
+          console.log('发送成功')
         }
       })
     }
   }
 }
 
-const parentMethod = (e) => {
-  console.log('子组件调用了')
-  console.log(e)
-}
-
 const brightness = () => {
   if (lampData.switchType === '单灯控制器') {
-    let val1 = lampData.lampValue1
-    let val2 = lampData.lampValue2
-    let judge = {
-      0:[0.8,0],
-      33: [0.8,0],
-      66: [0.5,50],
-      100: [0.2,100],
+    const val1 = lampData.lampValue1
+    const val2 = lampData.lampValue2
+    const judge = {
+      0: [0.8, 0],
+      33: [0.8, 0],
+      66: [0.5, 50],
+      100: [0.2, 100],
     }
     transparency.value = judge[val1][1]
     transparencyTwo.value = judge[val1][1]
     materialOne.opacity = judge[val1][0]
     materialTwo.opacity = judge[val2][0]
-  } else if(lampData.switchType === '四路控制器') {
+  } else if (lampData.switchType === '四路控制器') {
     relayList.length = 0
     lampData.devices.forEach(item => {
       if (item.genre === 6) {
         relayList.push(item)
       }
     })
-    let deviceLamp1 = relayList[0].deviceRelays
-    let deviceLamp2 = relayList[1].deviceRelays
+    const deviceLamp1 = relayList[0].deviceRelays
+    const deviceLamp2 = relayList[1].deviceRelays
     let count1 = 0
     let count2 = 0
     deviceLamp1.forEach(item => {
@@ -276,12 +330,12 @@ const brightness = () => {
     deviceLamp2.forEach(item => {
       item.state ? count2++ : count2
     })
-    let judgeWay = {
-      0: [0.8,0],
-      1: [0.8,0],
-      2: [0.5,50],
-      3: [0.2,100],
-      4: [0.2,100]
+    const judgeWay = {
+      0: [0.8, 0],
+      1: [0.8, 0],
+      2: [0.5, 50],
+      3: [0.2, 100],
+      4: [0.2, 100]
     }
     transparency.value = judgeWay[count1][1]
     transparencyTwo.value = judgeWay[count2][1]
@@ -307,6 +361,11 @@ const yourMethod = (value) => {
   Object.assign(lampData, value)
   brightness()
 }
+
+const returnMap = () => {
+  console.log('返回地图')
+  useScreen.setScreenType('map')
+}
 </script>
 
 <style scoped lang="less">
@@ -546,5 +605,9 @@ const yourMethod = (value) => {
   margin-top: 20px;
 }
 
+.three-container {
+  height: 800px;
+  width: 100%;
+}
 </style>
 

+ 1 - 0
web/vite.config.js

@@ -73,6 +73,7 @@ export default ({
       },
     },
     build: {
+      charset:'utf8',
       minify: 'terser', // 是否进行压缩,boolean | 'terser' | 'esbuild',默认使用terser
       manifest: false, // 是否产出manifest.json
       sourcemap: false, // 是否产出sourcemap.json