Browse Source

隧道模型

2545307760@qq.com 1 day ago
parent
commit
3ebd79a4df

+ 1 - 1
web/.env.development

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

+ 4 - 0
web/package.json

@@ -24,6 +24,8 @@
         "highlight.js": "^11.8.0",
         "js-cookie": "^3.0.5",
         "jsencrypt": "^3.3.2",
+        "less": "^4.2.2",
+        "less-loader": "^12.2.0",
         "marked": "4.3.0",
         "mitt": "^3.0.1",
         "nprogress": "^0.2.0",
@@ -34,6 +36,8 @@
         "sortablejs": "^1.15.2",
         "spark-md5": "^3.0.2",
         "tailwindcss": "^3.3.3",
+        "three": "^0.175.0",
+        "three.js": "^0.77.1",
         "vue": "^3.4.21",
         "vue-router": "^4.3.2",
         "vuedraggable": "^4.1.0"

BIN
web/public/智慧隧道.glb


BIN
web/src/assets/line.png


BIN
web/src/assets/title_bg.png


+ 8 - 1
web/src/router/index.js

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

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

@@ -0,0 +1,359 @@
+<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">
+            <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 titleUrl from '@/assets/title_bg.png'
+
+// 获取容器引用
+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(20, 20, 20);
+
+  // 创建渲染器
+  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 material = reactive({})
+
+// 加载 GLB 模型
+const loadModel = () => {
+  const loader = new GLTFLoader();
+  loader.load('../../public/智慧隧道.glb', function (gltf){
+      let object = gltf.scene
+      object.children[0].children[1].material.opacity = 0.2
+      material = object.children[0].children[1].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);
+};
+
+// 组件挂载时初始化
+onMounted(() => {
+  initThree();
+  loadModel();
+  animate();
+});
+
+// 组件卸载时清理资源
+onUnmounted(() => {
+  if (renderer) {
+    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">
+.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;
+    }
+    .formBox_two{
+      position: absolute;
+      right: 20px;
+      top: 150px;
+      z-index:2;
+    }
+    .vehicleBox{
+      position: absolute;
+      right: 20px;
+      top: 280px;
+      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: 120px;
+      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;
+      }
+      .brightness{
+        margin: 90px 0 0 25px;
+        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>
+

+ 23 - 7
web/src/view/admin/tunnel/tunnel.vue

@@ -72,13 +72,9 @@
           align="center"
         />
         <el-table-column
-          prop="switchType"
-          label="开关类型"
-          align="center"
-        />
-        <el-table-column
-          label="策略"
-          align="center"
+            prop="switchType"
+            label="开关类型"
+            align="center"
         >
           <template #default="scope">
             <el-select
@@ -101,26 +97,37 @@
           width="500"
         >
           <template #default="scope">
+            <el-button
+                type="primary"
+                size="small"
+                @click="jumpScreen"
+            >
+              大屏
+            </el-button>
             <el-button
               type="primary"
+              size="small"
               @click="tunnelData = scope.row ; tunnelEditDialog = true"
             >
               修改
             </el-button>
             <el-button
               type="danger"
+              size="small"
               @click="tunnelDelete(scope.row)"
             >
               删除
             </el-button>
             <el-button
               type="primary"
+              size="small"
               @click="tunnelControlPanel(scope.row)"
             >
               控制面板
             </el-button>
             <el-button
               type="primary"
+              size="small"
               @click="getDeviceFile(scope.row.ID)"
             >
               生成设备文件
@@ -422,6 +429,8 @@ import { deviceSwitch, generateDeviceFile } from '@/api/device'
 import { useUserStore } from '@/pinia/modules/user'
 const userData = useUserStore()
 const userInfo = userData.userInfo
+import { useRouter } from 'vue-router'
+const router = useRouter()
 
 const searchData = ref({
   pageInfo: {
@@ -711,6 +720,13 @@ const switchButton = async(device, relay) => {
   })
 }
 
+// 大屏
+const jumpScreen = () => {
+  router.push('/dataDashboard')
+  // const routeData = router.resolve({ name: 'dataDashboard' })
+  // window.open(routeData.href, '_blank')
+}
+
 onMounted(() => {
   getData()
 })