Browse Source

军信前端1

xu 4 months ago
parent
commit
dfa35967c2
8 changed files with 253 additions and 103 deletions
  1. 1 1
      index.html
  2. 1 0
      package.json
  3. 8 0
      pnpm-lock.yaml
  4. 236 102
      src/App.vue
  5. 7 0
      src/api/device.js
  6. BIN
      src/static/jx.glb
  7. BIN
      src/static/jx.png
  8. BIN
      src/static/地图标点.png

+ 1 - 1
index.html

@@ -6,7 +6,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>军信路灯控制</title>
   </head>
-  <body>
+  <body style="margin: 0;">
     <div id="app"></div>
     <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=YwKx9ej9X37pvSHGl0Y9S1G2tvtKzP0v"></script>
     <script type="module" src="/src/main.js"></script>

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "jsencrypt": "^3.3.2",
     "path": "^0.12.7",
     "process": "^0.11.10",
+    "three": "^0.170.0",
     "vue": "^3.5.10"
   },
   "devDependencies": {

+ 8 - 0
pnpm-lock.yaml

@@ -32,6 +32,9 @@ importers:
       process:
         specifier: ^0.11.10
         version: 0.11.10
+      three:
+        specifier: ^0.170.0
+        version: 0.170.0
       vue:
         specifier: ^3.5.10
         version: 3.5.12
@@ -529,6 +532,9 @@ packages:
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
     engines: {node: '>=0.10.0'}
 
+  three@0.170.0:
+    resolution: {integrity: sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==}
+
   tslib@2.3.0:
     resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
 
@@ -1018,6 +1024,8 @@ snapshots:
 
   source-map-js@1.2.1: {}
 
+  three@0.170.0: {}
+
   tslib@2.3.0: {}
 
   util@0.10.4:

+ 236 - 102
src/App.vue

@@ -1,16 +1,44 @@
 <template>
   <div class="app">
-    <el-container class="container" @mousedown="startDrag" @mousemove="drag" @mouseup="endDrag" @mouseleave="endDrag" @contextmenu.prevent>
+    <el-container>
       <BorderBox1 class="cs">
         <div style="margin: 20px 0 10px 0;">在线设备:{{onlineData.online}}</div>
         <div style="margin: 0 0 20px 0;">总设备:{{onlineData.total}}</div>
         <el-progress type="dashboard" :percentage="percentage" :color="colors" />
       </BorderBox1>
-      <div/>
-      <img ref="map" :src="imageSrc" alt="Map" @dragstart.prevent />
-      <el-button v-for="(button, index) in buttons" :key="index" class="button" :style="button.style" @click="openRegionDrawer(button)">
-        {{ button.text }}
-      </el-button>
+      <div class="top-label">
+        <div style="height: 50px;line-height: 50px">
+          <img src="/src/static/jx.png" alt="Map" style="top: 0;left: -100px;width: 80px;height: 80px"/>
+          军信路灯控制
+        </div>
+        <Decoration5 style="width:500px; height:120px;" />
+      </div>
+      <div class="fixed-sidebar">
+        <BorderBox8 :reverse="true" class="upper-part">
+          <el-button  v-for="(button, index) in buttons" :key="index" style="margin: 20px 0 30px 20px;display: block" @click="openRegionDrawer(button)">
+            {{ button.text }}
+          </el-button>
+          <!-- 上部分内容 -->
+        </BorderBox8>
+        <BorderBox8 class="lower-part">
+          <!-- 下部分内容 -->
+          <div v-for="device in sunDevices" class="sun_info">
+            <div>
+              名称:{{device.name}}
+            </div>
+            <div>
+              电池电流:{{device.sun.batteryCurrent}}mA
+            </div>
+            <div>
+              电池电压:{{device.sun.batteryVoltage}}V
+            </div>
+            <div>
+              电池板电压:{{device.sun.batteryPlateVoltage}}V
+            </div>
+            <el-divider />
+          </div>
+        </BorderBox8>
+      </div>
     </el-container>
     <el-drawer
         v-model="table"
@@ -165,21 +193,20 @@
 
 <script setup>
 import {ref, onMounted, reactive, computed} from 'vue';
-import {BorderBox1,BorderBox3 } from '@dataview/datav-vue3';
+import {BorderBox1,BorderBox2,BorderBox8,Decoration5 } from '@dataview/datav-vue3';
 import {ElContainer, ElButton, ElMessage, ElMessageBox} from 'element-plus';
-import {deviceBatchSwitch, deviceLoopSwitch, deviceSwitch, getOnlineDevice, queryData, saveData} from "@/api/device.js";
+import {
+  deviceBatchSwitch,
+  deviceLoopSwitch,
+  deviceSwitch,
+  getOnlineDevice,
+  getSunDevices,
+  queryData,
+  saveData
+} from "@/api/device.js";
 import DeviceReplayTimeSet from "@/comm/deviceReplayTimeSet.vue";
 import DeviceLoopReplayTimeSet from "@/comm/deviceLoopReplayTimeSet.vue";
 
-const imageSrc = '/src/static/jx4.png'; // 替换为你的图片路径
-const map = ref(null);
-let isDragging = false;
-let dragStartX = 0;
-let dragStartY = 0;
-let currentMapLeft = 0;
-let currentMapTop = 0;
-const dragSpeed = 0.1; // 控制拖动速度,值越小速度越慢
-
 const buttons = ref([
   { text: '生活区', initialLeft: 500, initialTop: 1800 },
   { text: '股份公司进场上坡', initialLeft: 500, initialTop: 1550 },
@@ -191,71 +218,23 @@ const buttons = ref([
   { text: '污水进场道路', initialLeft: 2200, initialTop: 300 }
 ]);
 
-function startDrag(event) {
-  isDragging = true;
-  dragStartX = event.clientX;
-  dragStartY = event.clientY;
-}
-
-function drag(event) {
-  if (!isDragging) return;
-
-  const containerRect = map.value.parentElement.getBoundingClientRect();
-  const mapRect = map.value.getBoundingClientRect();
-
-  const deltaX = (event.clientX - dragStartX) * dragSpeed;
-  const deltaY = (event.clientY - dragStartY) * dragSpeed;
-
-  const newX = currentMapLeft + deltaX;
-  const newY = currentMapTop + deltaY;
-
-  // 计算边界限制
-  const minX = -(mapRect.width - containerRect.width); // 左侧边缘不能完全移出容器
-  const maxX = 0; // 右侧边缘可以超过容器
-  const minY = -(mapRect.height - containerRect.height); // 顶部边缘不能完全移出容器
-  const maxY = 0; // 底部边缘可以超过容器
-
-  // 应用边界限制
-  const finalX = Math.max(minX, Math.min(maxX, newX));
-  const finalY = Math.max(minY, Math.min(maxY, newY));
-
-  currentMapLeft = finalX;
-  currentMapTop = finalY;
-
-  map.value.style.left = `${finalX}px`;
-  map.value.style.top = `${finalY}px`;
-
-  // 更新按钮位置
-  updateButtonPositions();
-}
-
-function endDrag() {
-  isDragging = false;
-}
-
-function updateButtonPositions() {
-  buttons.value.forEach((button) => {
-    button.style = {
-      left: `${button.initialLeft + currentMapLeft}px`,
-      top: `${button.initialTop + currentMapTop}px`
-    };
-  });
-}
-
 const regionData = ref()
 const onlineData = ref({
   online: 0,
   total:0
 })
+const sunDevices =ref()
 const getData = async() => {
   await queryData().then(res => {
-    console.log(res)
     regionData.value = res.data
   })
   await getOnlineDevice().then(res => {
-    console.log(res.data)
     onlineData.value = res.data
   })
+  await getSunDevices().then(res => {
+    console.log(res.data)
+    sunDevices.value = res.data
+  })
 }
 
 const percentage = computed(() => {
@@ -281,6 +260,9 @@ const deviceData = ref()
 const openRegionDrawer = (val) => {
   table.value = true;
   regionName.value = val.text;
+  if (!regionName.value) {
+    regionName.value = val
+  }
 
   for (let i = 0; i < regionData.value.length; i++) {
     if (regionData.value[i].name === regionName.value) {
@@ -298,10 +280,10 @@ const addDeviceData = ref({
   sn: '',
   name: '',
   regionId: null,
-  genre: "回路控制",
+  genre: "回路控制",
   state: 1,
   isSun: false,
-  loopNumber : 8,
+  loopNumber : 4,
   deviceLoops: []
 })
 
@@ -492,33 +474,104 @@ setInterval(() => {
 }, 300000);
 
 onMounted(() => {
-  // 初始化地图位置
-  map.value.style.left = `${currentMapLeft}px`;
-  map.value.style.top = `${currentMapTop}px`;
-
-  // 初始化按钮位置
-  updateButtonPositions();
   getData()
 });
+
+// 3d图
+
+import * as THREE from 'three';
+import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import {GLTFLoader} from "three/addons/loaders/GLTFLoader.js";
+// 创建场景
+const scene = new THREE.Scene();
+
+// 创建相机
+const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
+camera.position.set(0, 2000, 0);
+camera.lookAt(0,0,0)
+
+// 创建渲染器
+const renderer = new THREE.WebGLRenderer({
+  antialias: true,
+});
+renderer.setClearColor(0x060c18,1.0);
+renderer.setPixelRatio(window.devicePixelRatio)
+renderer.setSize(window.innerWidth, window.innerHeight);
+document.body.appendChild(renderer.domElement);
+
+const point = ['生活区','股份公司进场上坡','地磅房至污泥厂门口','三角花园至油库','地磅房至搅拌站','搅拌站至三岔路口','垃圾堆体道路','污水进场道路']
+
+//环境光
+const ambientLight = new THREE.AmbientLight(0xffffff, 2);
+scene.add(ambientLight);
+
+const loader = new GLTFLoader();
+
+loader.load( '/src/static/jx.glb', function ( gltf ) {
+  scene.add( gltf.scene );
+})
+
+window.onresize = function () {
+  renderer.setSize(window.innerWidth, window.innerHeight);
+  camera.aspect = window.innerWidth / window.innerHeight
+  camera.updateProjectionMatrix();
+}
+
+// 设置相机控件轨道控制器OrbitControls
+const controls = new OrbitControls(camera, renderer.domElement);
+// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
+controls.addEventListener('change', function () {
+  renderer.render(scene, camera); //执行渲染操作
+});//监听鼠标、键盘事件
+
+// 创建光线投射器
+const raycaster = new THREE.Raycaster();
+const mouse = new THREE.Vector2();
+
+// 渲染函数
+function animate() {
+  requestAnimationFrame(animate);
+  renderer.render(scene, camera);
+}
+
+// 鼠标点击事件处理
+function onDocumentMouseDown(event) {
+  event.preventDefault();
+
+  // 将鼠标位置归一化到 -1 到 1 的范围内
+  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
+  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
+
+  // 更新光线投射器
+  raycaster.setFromCamera(mouse, camera);
+
+  // 计算所有与光线相交的对象
+  const intersects = raycaster.intersectObjects(scene.children);
+
+  if (intersects.length > 0) {
+    const intersectedObject = intersects[0].object;
+
+    // 根据点击的对象执行不同的操作
+    if (point.includes(intersectedObject.name)) {
+      openRegionDrawer(intersectedObject.name)
+    }
+  }
+}
+
+// 监听鼠标点击事件
+document.addEventListener('mousedown', onDocumentMouseDown, false);
+
+// 开始渲染
+animate();
 </script>
 
 <style scoped>
 .app {
   position: relative;
   width: 100vw;
-  height: 100vh;
   overflow: hidden;
 }
 
-.container {
-  position: relative;
-  width: 100%;
-  height: 100%;
-  background-color: #f4f4f4;
-  border: 1px solid #ccc;
-  cursor: move;
-}
-
 img {
   position: absolute;
   top: 0;
@@ -529,27 +582,108 @@ img {
   -webkit-user-drag: none; /* 禁止图片拖动 */
 }
 
-.button {
-  position: absolute;
-  padding: 5px 10px;
-  background-color: rgba(0, 0, 0, 0.5);
-  color: white;
-  border-radius: 5px;
-  cursor: pointer;
-  user-select: none;
-}
 .cs {
-  z-index: 10;
+  position: fixed;
+  top: 0;
+  left: 5%;
+  font-size: 20px;
+  font-weight: 600;
   width: 200px;
-  height: 230px;
+  height: 250px;
   color: white;
   text-align: center;
+  transform: translateX(-50%);
+  background-color: rgba(0, 0, 0, 0);
+  z-index: 10; /* 确保它在最上层 */
 }
-.cs1 {
+
+.fixed-sidebar {
   z-index: 10;
-  width: 200px;
-  height: 100px;
+  position: fixed;
+  top: 0;
+  right: 0;
+  width: 16.67%; /* 100% / 6 = 16.67% */
+  height: 100%;
+  //background-color: #f0f0f0;
+  display: flex;
+  flex-direction: column;
+}
+
+.upper-part {
+  flex: 6; /* 60% */
+  background-color: rgba(0, 0, 0, 0.1);
+  padding: 10px;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column; /* 使按钮竖直排列 */
+  align-items: flex-start; /* 使按钮左对齐 */
+}
+
+.lower-part {
+  flex: 4; /* 40% */
+  background-color: rgba(0, 0, 0, 0.1);
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+/* 可选:添加一些样式来美化盒子 */
+.upper-part h2, .lower-part h2 {
+  margin: 0;
+  font-size: 18px;
+}
+
+.upper-part p, .lower-part p {
+  margin: 10px 0;
+  font-size: 14px;
+}
+
+.top-label {
+  position: fixed;
+  top: 20px;
+  left: 50%;
+  font-size: 50px;
+  font-weight: 600;
   color: white;
   text-align: center;
+  transform: translateX(-50%);
+  background-color: rgba(0, 0, 0, 0);
+  padding: 10px 20px;
+  z-index: 10; /* 确保它在最上层 */
+}
+.sun_info div{
+  color: white;
+  margin: 15px 0;
+}
+.upper-part button {
+  border: 2px solid white;
+  background: transparent;
+  text-transform: uppercase;
+  color: white;
+  outline: none;
+  overflow: hidden;
+  position: relative;
+}
+
+span {
+  z-index: 20;
+}
+
+.upper-part button:after {
+  content: '';
+  display: block;
+  position: absolute;
+  top: -36px;
+  left: -100px;
+  background: white;
+  width: 50px;
+  height: 125px;
+  opacity: 20%;
+  transform: rotate(-45deg);
+}
+
+.upper-part button:hover:after {
+  left: 120%;
+  transition: all 600ms cubic-bezier(0.3, 1, 0.2, 1);
+  -webkit-transition: all 600ms cubic-bezier(0.3, 1, 0.2, 1);
 }
 </style>

+ 7 - 0
src/api/device.js

@@ -44,4 +44,11 @@ export const getOnlineDevice = () => {
         url: '/api/getOnlineDevice',
         method: 'get'
     })
+}
+
+export const getSunDevices = () => {
+    return service({
+        url: '/api/getSunDevices',
+        method: 'get'
+    })
 }

BIN
src/static/jx.glb


BIN
src/static/jx.png


BIN
src/static/地图标点.png