Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	web/src/view/admin/tunnel/tunnel.vue
xu 6 days ago
parent
commit
845dfaf7d6

+ 15 - 0
web/src/pinia/modules/screen.js

@@ -0,0 +1,15 @@
+import { defineStore } from 'pinia'
+import { reactive } from 'vue'
+
+export const useScreenStore = defineStore('screen',() => {
+    const controllerData = reactive({})
+
+    const setController = (val) => {
+        Object.assign(controllerData, val)
+    }
+
+    return {
+        controllerData,
+        setController
+    }
+})

+ 7 - 0
web/src/router/index.js

@@ -22,6 +22,13 @@ const routes = [{
       closeTab: true,
     },
     component: () => import('@/view/admin/dataDashboard/dataDashboard.vue')
+  },
+  {
+    path: '/dataScreen',
+    meta: {
+      closeTab: true
+    },
+    component:() => import('@/view/screen/dataScreen.vue')
   }
 ]
 

+ 170 - 27
web/src/view/admin/dataDashboard/dataDashboard.vue

@@ -18,7 +18,20 @@
               class="panel-slider"
               @change="changeTransparency"
           />
-          <div class="brightness">
+          <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>
@@ -81,9 +94,16 @@ 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);
 
@@ -110,7 +130,7 @@ const initThree = () => {
       0.1,
       1000
   );
-  camera.position.set(20, 20, 20);
+  camera.position.set(30, 20, 30);
 
   // 创建渲染器
   renderer = new THREE.WebGLRenderer({ antialias: true });
@@ -133,15 +153,17 @@ const initThree = () => {
 };
 
 // 存储模型数据
-let material = reactive({})
+let materialOne = reactive({})
+let materialTwo = reactive({})
+
 
 // 加载 GLB 模型
 const loadModel = () => {
   const loader = new GLTFLoader();
-  loader.load('../../public/智慧隧道.glb', function (gltf){
+  loader.load('../../public/隧道1.glb', function (gltf){
       let object = gltf.scene
-      object.children[0].children[1].material.opacity = 0.2
-      material = object.children[0].children[1].material
+      materialOne = object.children[0].children[3].material
+      materialTwo = object.children[19].children[3].material
       //gltf.scene获取gltf文件包含的模型数据
       scene.add(gltf.scene)
     }, function (xhr) {
@@ -149,7 +171,7 @@ const loadModel = () => {
         console.log((xhr.loaded / xhr.total * 100) + '% loaded');
       }, function (error) {
         // 加载错误回调
-        console.error('An error happened', error);
+        // console.error('An error happened', error);
       }
   )
 };
@@ -161,11 +183,143 @@ const animate = () => {
   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 = lampData.devices[0].deviceRelays
+    for (let i = 0; i < relay.length; i++) {
+      if (i < option[e][2]) {
+        relay[i].state = true
+      } else {
+        relay[i].state = false
+      }
+    }
+    for (let j = 0; j < relay.length; j++) {
+      deviceSwitch({
+        tunnelSn: lampData.tunnelSn,
+        radarId: lampData.devices[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 = lampData.devices[1].deviceRelays
+    for (let i = 0; i < relay.length; i++) {
+      if (i < option[e][2]) {
+        relay[i].state = true
+      } else {
+        relay[i].state = false
+      }
+    }
+    for (let j = 0; j < relay.length; j++) {
+      deviceSwitch({
+        tunnelSn: lampData.tunnelSn,
+        radarId: lampData.devices[1].radarId,
+        relayId: relay[j].relayId,
+        state: relay[j].state
+      }).then(res => {
+        if (res.code === 0) {
+          console.log('发送成功');
+        }
+      })
+    }
+  }
+}
+
+// 灯光数据
+const lampData = reactive({})
+
+const judgeLamp = () => {
+  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 === '四路控制器') {
+      let deviceLamp1 = lampData.devices[0].deviceRelays
+      let deviceLamp2 = lampData.devices[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)
 });
 
 // 组件卸载时清理资源
@@ -174,22 +328,6 @@ onUnmounted(() => {
     renderer.dispose();
   }
 });
-
-// 亮度调整
-
-const transparency = ref(0)
-
-
-const changeTransparency = (e) => {
-  let option = {
-    0: 0.8,
-    50: 0.5,
-    100: 0.2
-  }
-  material.opacity = option[e]
-}
-
-
 </script>
 
 <style scoped lang="less">
@@ -242,13 +380,13 @@ const changeTransparency = (e) => {
     .formBox_two{
       position: absolute;
       right: 20px;
-      top: 150px;
+      top: 250px;
       z-index:2;
     }
     .vehicleBox{
       position: absolute;
       right: 20px;
-      top: 280px;
+      top: 380px;
       z-index:2;
       .vehicleData{
         display: flex;
@@ -272,7 +410,7 @@ const changeTransparency = (e) => {
     .panel{
       position: relative;
       width: 300px;
-      height: 120px;
+      height: 200px;
       border: 1px solid rgba(25,186,139,0.17);
       padding: 0 0.1875rem 0.5rem;
       margin-bottom: 0.1875rem;
@@ -334,8 +472,13 @@ const changeTransparency = (e) => {
         top: 60px;
         left: 25px;
       }
+      .panel-slider2{
+        width: 250px;
+        position: absolute;
+        top: 120px;
+        left: 25px;
+      }
       .brightness{
-        margin: 90px 0 0 25px;
         width: 250px;
         display: flex;
         justify-content: space-between;

+ 40 - 22
web/src/view/admin/tunnel/tunnel.vue

@@ -82,15 +82,15 @@
         >
           <template #default="scope">
             <el-select
-              v-model="scope.row.tactics"
-              style="width: 100px"
-              @change="changeTactics(scope.row)"
+                v-model="scope.row.tactics"
+                style="width: 100px"
+                @change="changeTactics(scope.row)"
             >
               <el-option
-                v-for="item in tacticsOptions"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
+                  v-for="item in tacticsOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
               />
             </el-select>
           </template>
@@ -102,9 +102,9 @@
         >
           <template #default="scope">
             <el-button
-              type="primary"
-              size="small"
-              @click="jumpScreen"
+                type="primary"
+                size="small"
+                @click="jumpScreen(scope.row)"
             >
               大屏
             </el-button>
@@ -346,8 +346,9 @@
                 key="k"
                 v-model="v.state"
                 class="ml-2"
+                :disabled="k === 0"
                 style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
-                @click="switchButton(item, v)"
+                @click="switchButton(item, v, k)"
               />
             </div>
           </div>
@@ -355,7 +356,7 @@
             <div style="margin: 0 0 0 20px">
               <el-slider
                 v-model="tunnelTimeData.lampValue1"
-                :step="10"
+                :step="50"
                 style="width: 50%;"
                 show-stops
               />
@@ -363,7 +364,7 @@
             <div style="margin: 0 0 0 20px">
               <el-slider
                 v-model="tunnelTimeData.lampValue2"
-                :step="10"
+                :step="50"
                 style="width: 50%;"
                 show-stops
               />
@@ -460,6 +461,7 @@
 
 <script setup>
 import { ref, onMounted } from 'vue'
+import { useScreenStore } from '@/pinia/modules/screen'
 import { queryAllRegions } from '@/api/region'
 import {
   createTunnel,
@@ -479,6 +481,7 @@ const userInfo = userData.userInfo
 import { useRouter } from 'vue-router'
 const router = useRouter()
 
+const lampList = [33,66,100]
 const searchData = ref({
   pageInfo: {
     page: 1,
@@ -509,6 +512,7 @@ const getData = async() => {
     region.value = res.data
   })
   await queryTunnelList(searchData.value).then(res => {
+    console.log(res.data.list)
     tunnel.value = res.data.list
     total.value = res.data.total
     searchData.value.pageInfo.page = res.data.page
@@ -527,7 +531,6 @@ const isTunnelAdd = () => {
 
 function getFormattedDateTime() {
   const now = new Date()
-
   const year = now.getFullYear()
   const month = String(now.getMonth() + 1).padStart(2, '0') // 月份从0开始,所以需要加1
   const day = String(now.getDate()).padStart(2, '0')
@@ -713,9 +716,17 @@ const tunnelTimeData = ref()
 const isControlPanel = ref(false)
 const tunnelControlPanel = (val) => {
   isControlPanel.value = true
+  let lampObj = {
+    0:0,
+    33: 0,
+    50:50,
+    66: 50,
+    100: 100,
+  }
+  val.lampValue1 = lampObj[val.lampValue1]
+  val.lampValue2 = lampObj[val.lampValue2]
   tunnelTimeData.value = val
   tunnelTiming.value = val.tunnelTime
-  console.log(val)
 }
 
 const activeNames = ref(['1', '2'])
@@ -738,11 +749,16 @@ const editTunnelTiming = async() => {
 }
 
 const lampSet = async(val) => {
+  let judge = {
+    0: 33,
+    50: 66,
+    100: 100
+  }
   await updateTunnelLamp({
     id: val.ID,
     tunnelSn: val.tunnelSn,
-    lampValue1: val.lampValue1,
-    lampValue2: val.lampValue2
+    lampValue1: judge[val.lampValue1],
+    lampValue2: judge[val.lampValue2]
   }).then(res => {
     if (res.code === 0) {
       ElMessage.success('已发送')
@@ -900,8 +916,10 @@ function initLightBySnChart(index, data) {
   myChart.setOption(option)
 }
 // 开关
-const switchButton = async(device, relay) => {
-  console.log(device, relay)
+const switchButton = async(device, relay, index) => {
+  if (index === 0) {
+    return
+  }
   await deviceSwitch({
     tunnelSn: device.tunnel.tunnelSn,
     radarId: device.radarId,
@@ -916,10 +934,10 @@ const switchButton = async(device, relay) => {
 }
 
 // 大屏
-const jumpScreen = () => {
+const useScreen =  useScreenStore()
+const jumpScreen = (row) => {
+  useScreen.setController(row)
   router.push('/dataDashboard')
-  // const routeData = router.resolve({ name: 'dataDashboard' })
-  // window.open(routeData.href, '_blank')
 }
 
 onMounted(() => {

+ 6 - 1
web/src/view/layout/index.vue

@@ -82,6 +82,7 @@
                           :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-col>
                     <el-col
                       :xs="12"
@@ -183,7 +184,6 @@
         <CommandMenu ref="command" />
       </el-main>
     </el-container>
-
   </el-container>
 </template>
 
@@ -201,6 +201,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";
 
 defineOptions({
   name: 'Layout',
@@ -255,6 +256,10 @@ const handleCommand = () => {
   command.value.open()
 }
 
+const jumpScreen = () => {
+  router.push('/dataScreen')
+}
+
 onMounted(() => {
   // 挂载一些通用的事件
   emitter.emit('collapse', isCollapse.value)

+ 296 - 0
web/src/view/screen/dataScreen.vue

@@ -0,0 +1,296 @@
+<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>
+  </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({})
+
+
+// 加载 GLB 模型
+const loadModel = () => {
+  const loader = new GLTFLoader();
+  loader.load('../../public/隧道1.glb', function (gltf){
+        let object = gltf.scene
+        materialOne = object.children[0].children[3].material
+        materialTwo = object.children[19].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) => {
+  console.log(e)
+}
+
+const transparencyTwo = ref(0)
+const changeTransparencyTwo = (e) => {
+  console.log(e)
+}
+
+// 灯光数据
+const lampData = reactive({})
+
+// 组件挂载时初始化
+onMounted(() => {
+  Object.assign(lampData, useScreen.controllerData)
+  initThree();
+  loadModel();
+  animate();
+});
+
+// 组件卸载时清理资源
+onUnmounted(() => {
+  if (renderer) {
+    renderer.dispose();
+  }
+});
+</script>
+
+<style scoped lang="less">
+.horn {
+  position: absolute;
+  content: "";
+  width: 10px;
+  height: 10px;
+}
+.screen{
+  width: 100%;
+  height: 900px;
+  //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: 800px;
+    margin-top: 20px;
+    position: relative;
+    .three-container {
+      z-index: 1;
+      position: absolute;
+      height: 800px;
+      width: 100%;
+    }
+    .formBox{
+      position: absolute;
+      right: 20px;
+      z-index:2;
+    }
+    .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;
+      }
+      .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>
+