Browse Source

页面搭建

gr 1 month ago
parent
commit
0c60c4b517

+ 15 - 0
src/assets/styles/animation.scss

@@ -40,3 +40,18 @@
 .emerge-left-enter-active, .emerge-left-leave-active {
   transition: opacity 0.3s ease, transform 0.3s ease-out;
 }
+
+// merge from bottom
+.emerge-bottom-enter-from, .emerge-bottom-leave-to {
+  opacity: 0;
+  transform: translateY(30px);
+}
+
+.emerge-bottom-enter-to, .emerge-bottom-leave-from {
+  opacity: 1;
+  transform: translateY(0);
+}
+
+.emerge-bottom-enter-active, .emerge-bottom-leave-active {
+  transition: opacity 0.3s ease, transform 0.3s ease-out;
+}

+ 58 - 9
src/assets/styles/element.scss

@@ -70,6 +70,12 @@
 }
 
 .el-form {
+  &.el-form--default {
+    .el-form-item__label {
+      font-size: 16px;
+    }
+  }
+
   &.el-form--large {
     .el-form-item__label {
       font-size: 20px;
@@ -158,6 +164,30 @@
   }
 
   .el-radio {
+    margin-right: 15px;
+
+    .el-radio__label {
+      font-size: 16px;
+    }
+
+    .el-radio__input {
+      .el-radio__inner {
+        width: 20px;
+        height: 20px;
+        background: rgba(139, 160, 201, 0.2);
+        box-shadow: 0px 4px 0px 0px rgba(101, 122, 165, 0.5);
+        border-radius: 10px;
+        border: 1px solid #B2CCFF;
+
+        &::after {
+          width: 8px;
+          height: 8px;
+          background: #8BA0C9;
+          border-radius: 4px;
+        }
+      }
+    }
+
     &.is-checked {
       .el-radio__label {
         color: inherit;
@@ -167,6 +197,8 @@
 
 
   .el-radio--large {
+    margin-right: 25px;
+
     .el-radio__label {
       font-size: 17px;
     }
@@ -175,15 +207,11 @@
       .el-radio__inner {
         width: 22px;
         height: 22px;
-        background: rgba(139, 160, 201, 0.2);
-        box-shadow: 0px 4px 0px 0px rgba(101, 122, 165, 0.5);
         border-radius: 11px;
-        border: 1px solid #B2CCFF;
 
         &::after {
           width: 10px;
           height: 10px;
-          background: #8BA0C9;
           border-radius: 5px;
         }
       }
@@ -192,21 +220,42 @@
 }
 
 .el-checkbox {
+  .el-checkbox__input .el-checkbox__inner {
+    width: 20px;
+    height: 20px;
+    background: rgba(139, 160, 201, 0.2);
+    box-shadow: 0px 4px 0px 0px rgba(101, 122, 165, 0.5);
+    border-radius: 4px;
+    border: 1px solid #B2CCFF;
+
+    &::after {
+      border-width: 2px;
+      height: 11px;
+      left: 6px;
+      width: 5px;
+    }
+  }
+
+  .el-checkbox__label {
+    font-size: 16px;
+  }
+
+  &.is-checked .el-checkbox__label {
+    color: inherit;
+  }
+
   &.el-checkbox--large {
     .el-checkbox__input .el-checkbox__inner {
       width: 24px;
       height: 24px;
-      background: rgba(139, 160, 201, 0.2);
-      box-shadow: 0px 4px 0px 0px rgba(101, 122, 165, 0.5);
-      border-radius: 4px;
-      border: 1px solid #B2CCFF;
+
       &::after {
-        border-width: 2px;
         height: 13px;
         left: 8px;
         width: 6px;
       }
     }
+
     .el-checkbox__label {
       font-size: 20px;
     }

+ 7 - 0
src/store/layout.js

@@ -10,6 +10,10 @@ const useLayoutStore = defineStore(
       sceneType: 'gis', // 场景类型 'ue' | 'gis'
       mapScene: 'dark', // 底图类型 'light' | 'dark' | 'rs'
       leftPanelType: 'default', // 左侧面板显示的内容
+      floatPanels: {
+        uav: false, // 无人机信息
+        mesh: false // 分层空域
+      }
     }),
     actions: {
       toggleGlobalLoading(status) {
@@ -34,6 +38,9 @@ const useLayoutStore = defineStore(
       setLeftPanel(value) {
         this.leftPanelType = value
       },
+      toggleFloatPanel(target, value) {
+        this.floatPanels[target] = value || !this.floatPanels[target]
+      }
     }
   })
 

+ 10 - 14
src/views/home/Home.vue

@@ -108,15 +108,20 @@
     <ToolList />
 
     <!-- 无人机详情 -->
-    <FloatPanelUav v-model="dialogShow.uavInfo" />
+    <Transition name="emerge-left">
+      <FloatPanelUav v-if="layoutStore.floatPanels.uav" />
+    </Transition>
 
     <!-- 网格编辑 -->
-    <MeshEditor v-if="dialogShow.MeshEditor" />
+    <Transition name="emerge-bottom">
+      <MeshEditor v-if="layoutStore.floatPanels.mesh" />
+    </Transition>
+
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, getCurrentInstance, onMounted, computed } from 'vue'
+import { reactive, onMounted } from 'vue'
 import { getAssetsFile } from '@/utils/require'
 import ToolList from './cpns/ToolList.vue'
 // import { setSdtj } from '@/echarts/options.js'
@@ -130,12 +135,10 @@ import FloatPanelUav from './cpns/FloatPanelUav.vue'
 import PanelSgzy from './cpns/PanelSgzy.vue'
 import PanelKypm from './cpns/PanelKypm.vue'
 import PanelSjwg from './cpns/PanelSjwg.vue'
-import MeshEditor from './cpns/MeshEditor.vue'
+import MeshEditor from './cpns/FloatPanelMesh.vue'
 
 const layoutStore = useLayoutStore()
 
-const { proxy } = getCurrentInstance()
-
 const staticPanelData = reactive({
   flightSummary: [
     { label: '飞行计划总数', count: 1024, unit: '次', icon: getAssetsFile('page/bg-fxjhzs.png') },
@@ -162,16 +165,9 @@ const staticPanelData = reactive({
 })
 
 function CheckUav(item) {
-  console.log(item)
-  dialogShow.uavInfo = true
+  layoutStore.toggleFloatPanel('uav', true)
 }
 
-
-const dialogShow = reactive({
-  uavInfo: false,
-  MeshEditor: true
-})
-
 onMounted(() => {
 
 })

+ 120 - 83
src/views/home/cpns/MeshEditor.vue

@@ -1,12 +1,33 @@
 <template>
-  <div class="slider-container">
+  <div class="slider-container" v-if="!layoutStore.asideCollapse">
+
+    <el-form v-model="form" inline class="ml-5 mt-3">
+      <el-form-item label="网格类型" prop="meshType">
+        <el-radio-group v-model="form.meshType">
+          <el-radio label="二维" value="二维" />
+          <el-radio label="三维" value="三维" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item>
+        <el-checkbox v-model="form.grade">三维评分</el-checkbox>
+      </el-form-item>
+      <el-form-item label="网格范围" prop="meshRange">
+        <el-radio-group v-model="form.meshRange">
+          <el-radio label="全市范围" value="全市范围" />
+          <el-radio label="自定义范围" value="自定义范围" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item>
+        <el-button class="btn-secondary">绘制</el-button>
+      </el-form-item>
+    </el-form>
 
     <!-- 单点选择滑动条 -->
     <div class="slider-bg single-slider">
       <div class="slider">
         <div v-for="(point, index) in DenseData" :key="index" class="marker"
-             :class="{ 'key-point': selectedPoint === index }" :style="{ left: point.position + '%' }"
-             @click="selectPoint(index)">
+          :class="{ 'key-point': selectedPoint === index }" :style="{ left: index * (100 / (DenseData.length - 1)) + '%' }"
+          @click="selectPoint(index)">
           <span class="label">{{ point.label }}</span>
           <span class="des">{{ point.des }}</span>
         </div>
@@ -18,16 +39,16 @@
       <div class="slider">
         <!-- 高亮背景 -->
         <div class="range-highlight" v-if="rangeStart !== null && rangeEnd !== null" :style="{
-          left: heightData[rangeStart].position + 1.5 + '%',
-          width: (heightData[rangeEnd].position - heightData[rangeStart].position) + '%',
+          left: rangeStart * (100 / (heightData.length - 1)) + 1.5 + '%',
+          width: (rangeEnd - rangeStart) * (100 / (heightData.length - 1)) + '%',
         }"></div>
         <!-- 数据点 -->
         <div v-for="(point, index) in heightData" :key="index" class="marker" :class="{
           'active': (rangeStart !== null && rangeEnd === null && index === rangeStart) || (rangeStart !== null && rangeEnd !== null && index >= rangeStart && index <= rangeEnd),
           'hover': shouldHighlightOnHover(index),
           'key-point': index === rangeStart || index === rangeEnd
-        }" :style="{ left: point.position + '%' }" @click="selectRange(index)" @mouseover="handleMouseOver(index)"
-             @mouseleave="handleMouseLeave">
+        }" :style="{ left: index * (100 / (heightData.length - 1)) + '%' }" @click="selectRange(index)" @mouseover="handleMouseOver(index)"
+          @mouseleave="handleMouseLeave">
           <span class="label">{{ point.label }}</span>
         </div>
       </div>
@@ -39,103 +60,110 @@
 import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
 // import { useMapStore } from "@/store/map.js";
 // import { GetRealPower2 } from "@/utils/map/addLayer.js";
+import useLayoutStore from '@/store/layout';
 
 export default {
   setup(props, { emit }) {
+    const layoutStore = useLayoutStore()
+    const form = ref({
+      meshType: '二维',
+      grade: true,
+      meshRange: '全市范围'
+    })
     // const mapStore = useMapStore();
     let chosenType = ref([]);
     let typeData = ref([
       {
-        id:"1",
+        id: "1",
         label: '综合指数',
-        value:"all",
-        chosen:true,
+        value: "all",
+        chosen: true,
       },
       {
-        id:"2",
+        id: "2",
         label: '人口',
-        value:"demographics",
-        chosen:false,
+        value: "demographics",
+        chosen: false,
       },
       {
-        id:"3",
+        id: "3",
         label: '绿地',
-        value:"green",
-        chosen:false,
+        value: "green",
+        chosen: false,
       },
       {
-        id:"4",
+        id: "4",
         label: '河流',
-        value:"river",
-        chosen:false,
+        value: "river",
+        chosen: false,
       },
       {
-        id:"5",
+        id: "5",
         label: '道路',
-        value:"road",
-        chosen:false,
+        value: "road",
+        chosen: false,
       },
       {
-        id:"6",
+        id: "6",
         label: '建筑物',
-        value:"collision_buffer",
-        chosen:false,
+        value: "collision_buffer",
+        chosen: false,
       },
       {
-        id:"7",
+        id: "7",
         label: '禁飞区',
-        value:"no_fly_zone_buffer",
-        chosen:false,
+        value: "no_fly_zone_buffer",
+        chosen: false,
       },
       {
-        id:"8",
+        id: "8",
         label: '净空区',
-        value:"clear_zone_buffer",
-        chosen:false,
+        value: "clear_zone_buffer",
+        chosen: false,
       }
     ])
 
     const DenseData = reactive([
-      // { label: '1/8″网格', level: 24, size: { x: 3.3055614085396883, y: 3.8513467134689563, z: 3.3678982462941303 }, des: '(3.9m)', position: 0 },
-      { label: '1/4″网格', level: 23, size: { x: 6.7358, y: 7.7024, z: 6.6111 }, des: '(7m)', position: 10 },
-      { label: '1/2″网格', level: 22, size: { x: 13.222978864358083, y: 15.406742669116284, z: 13.471596544164798 }, des: '(15m)', position: 20 },
-      { label: '1′网格', level: 21, size: { x: 26.44107169853396, y: 30.815525255577086, z: 26.943221541824816 }, des: '(30.9m)', position: 30 },
-      { label: '2′网格', level: 20, size: { x: 52.887881893650956, y: 61.627412608112536, z: 53.887012166300096 }, des: '(61m)', position: 40 },
-      { label: '4′网格', level: 19, size: { x: 105.79869494173579, y: 123.43930203184209, z: 107.77356906534683  }, des: '(123.7m)', position: 50 },
-      { label: '8′网格', level: 18, size: { x: 211.66439868324142, y: 246.49964316944533, z: 215.5489592181181 }, des: '(247.4m)', position: 60 },
-      { label: '16′网格', level: 17, size: { x: 424.0518521273334, y: 492.09123171765896, z: 431.1052029077298 }, des: '(376.7m)', position: 70 },
-      { label: '32′网格', level: 16, size: { x: 844.8477050379952, y: 990.1345935064928, z: 862.239544684298 }, des: '(746.4m)', position: 80 },
-      { label: '1′网格', level: 15, size: { x: 1582.2726823222256, y: 1856.6079667204758, z: 1724.5956527210265 }, des: '(1850m)', position: 90 },
-      // { label: '2′网格', level: 14, size: { x: 2984.4, y: 2984.4, z: 2984.4 }, des: '(2984.4m)', position: 100 },
+      // { label: '1/8″网格', level: 24, size: { x: 3.3055614085396883, y: 3.8513467134689563, z: 3.3678982462941303 }, des: '(3.9m)'},
+      { label: '1/4″网格', level: 23, size: { x: 6.7358, y: 7.7024, z: 6.6111 }, des: '(7m)'},
+      { label: '1/2″网格', level: 22, size: { x: 13.222978864358083, y: 15.406742669116284, z: 13.471596544164798 }, des: '(15m)'},
+      { label: '1′网格', level: 21, size: { x: 26.44107169853396, y: 30.815525255577086, z: 26.943221541824816 }, des: '(30.9m)'},
+      { label: '2′网格', level: 20, size: { x: 52.887881893650956, y: 61.627412608112536, z: 53.887012166300096 }, des: '(61m)'},
+      { label: '4′网格', level: 19, size: { x: 105.79869494173579, y: 123.43930203184209, z: 107.77356906534683 }, des: '(123.7m)'},
+      { label: '8′网格', level: 18, size: { x: 211.66439868324142, y: 246.49964316944533, z: 215.5489592181181 }, des: '(247.4m)'},
+      { label: '16′网格', level: 17, size: { x: 424.0518521273334, y: 492.09123171765896, z: 431.1052029077298 }, des: '(376.7m)'},
+      { label: '32′网格', level: 16, size: { x: 844.8477050379952, y: 990.1345935064928, z: 862.239544684298 }, des: '(746.4m)'},
+      { label: '1′网格', level: 15, size: { x: 1582.2726823222256, y: 1856.6079667204758, z: 1724.5956527210265 }, des: '(1850m)'},
+      // { label: '2′网格', level: 14, size: { x: 2984.4, y: 2984.4, z: 2984.4 }, des: '(2984.4m)'},
     ]);
 
     const heightData = reactive([
-      { label: "0m", value: 0, position: 0 },
-      { label: "20m", value: 20, position: 10 },
-      { label: "40m", value: 40, position: 20 },
-      { label: "60m", value: 60, position: 30 },
-      { label: "80m", value: 80, position: 40 },
-      { label: "100m", value: 100, position: 50 },
-      { label: "120m", value: 120, position: 60 },
-      { label: "200m", value: 200, position: 70 },
-      { label: "300m", value: 300, position: 80 },
-      { label: "600m", value: 600, position: 90 },
-      { label: "1000m", value: 1000, position: 100 },
+      { label: "0m", value: 0 },
+      { label: "20m", value: 20 },
+      { label: "40m", value: 40 },
+      { label: "60m", value: 60 },
+      { label: "80m", value: 80 },
+      { label: "100m", value: 100 },
+      { label: "120m", value: 120 },
+      { label: "200m", value: 200 },
+      { label: "300m", value: 300 },
+      { label: "600m", value: 600 },
+      { label: "1000m", value: 1000 },
     ]);
 
     const changeType = (item) => {
       item.chosen = !item.chosen;
-      if(item.id == "1"){
-        if(item.chosen){
-          chosenType.value = ["demographics","green","river","road","collision_buffer","no_fly_zone_buffer","clear_zone_buffer"];
+      if (item.id == "1") {
+        if (item.chosen) {
+          chosenType.value = ["demographics", "green", "river", "road", "collision_buffer", "no_fly_zone_buffer", "clear_zone_buffer"];
         }
-      }else{
+      } else {
         chosenType.value = [];
         typeData.value.forEach((item) => {
-          if(item.id == "1"){
+          if (item.id == "1") {
             item.chosen = false;
           }
-          if(item.chosen && item.id != "1"){
+          if (item.chosen && item.id != "1") {
             chosenType.value.push(item.value);
           }
         })
@@ -187,8 +215,8 @@ export default {
       } else if (hoverIndex.value !== null && rangeStart.value !== null && rangeEnd.value === null) {
         // 如果已选择起点,且未选择终点,高亮起点到悬浮点之间的范围
         return (
-            (index >= rangeStart.value && index <= hoverIndex.value) ||
-            (index <= rangeStart.value && index >= hoverIndex.value)
+          (index >= rangeStart.value && index <= hoverIndex.value) ||
+          (index <= rangeStart.value && index >= hoverIndex.value)
         );
       }
       return false; // 不满足条件时,不高亮
@@ -219,7 +247,7 @@ export default {
 
     onMounted(() => {
       // 组件挂载后处理的逻辑
-      chosenType.value = ["demographics","green","river","road","collision_buffer","no_fly_zone_buffer","clear_zone_buffer"];
+      chosenType.value = ["demographics", "green", "river", "road", "collision_buffer", "no_fly_zone_buffer", "clear_zone_buffer"];
     });
     onBeforeUnmount(() => {
       // GetRealPower2({
@@ -230,6 +258,8 @@ export default {
 
 
     return {
+      layoutStore,
+      form,
       typeData,
       DenseData,
       heightData,
@@ -251,17 +281,16 @@ export default {
 <style lang="scss" scoped>
 .slider-container {
   position: absolute;
-  top: calc(var(--aside-height) - 260px - var(--footer-height));
-  left: 50%;
-  transform: translateX(-50%);
-  width: calc(100% - 2 * var(--aside-width) - 2 * var(--panel-gap));;
-  height: 276px;
-  background: rgba(0,10,30,0.6);
-  box-shadow: 0px 1px 6px 0px rgba(37,37,37,0.45);
+  top: calc(var(--aside-height) - 246px - var(--footer-height));
+  left: calc(var(--aside-width) + var(--panel-gap));
+  width: calc(100% - 2 * var(--aside-width) - 2 * var(--panel-gap));
+  height: 260px;
+  background: rgba(0, 10, 30, 0.6);
+  box-shadow: 0px 1px 6px 0px rgba(37, 37, 37, 0.6);
   border: 1px solid #98baffb6;
 }
 
-.type-list{
+.type-list {
   width: 100%;
   height: 60px;
   display: flex;
@@ -296,10 +325,10 @@ export default {
     content: '';
     position: absolute;
     display: block;
-    top: 8.5px;
+    top: 9px;
     left: 8px;
-    width: 5px;
-    height: 5px;
+    width: 8px;
+    height: 8px;
     transform: rotateZ(45deg);
     border: 2px solid #6495ed;
   }
@@ -314,12 +343,14 @@ export default {
 
   &.key-point {
     span {
-      transform: translateX(-50%) scale(1.2);
-      color: #9daac7;
+      font-weight: bold;
+      font-size: 18px;
+      color: #FFFFFF;
     }
+
     &::before {
       border-color: #FFFCF5;
-      box-shadow: 0 0 2px 5px #ffd90044;
+      box-shadow: 0 0 4px 5px #ffd90062;
       background-color: #ffd700;
     }
   }
@@ -332,9 +363,8 @@ export default {
   left: 50%;
   transform: translateX(-50%);
   white-space: nowrap;
-  font-family: BarlowBold;
-  font-size: 15px;
-  color: #9daac7ae;
+  font-size: 16px;
+  color: #9DAAC7;
 }
 
 .des {
@@ -343,9 +373,8 @@ export default {
   left: 50%;
   transform: translateX(-50%);
   white-space: nowrap;
-  font-family: BarlowBold;
-  font-size: 12px;
-  color: #9daac7ae;
+  font-size: 14px;
+  color: #9DAAC7;
 }
 
 .range-highlight {
@@ -358,10 +387,18 @@ export default {
 
 .single-slider {
   margin-top: 50px;
+
+  .label {
+    font-size: 14px;
+  }
+
+  .key-point span {
+    font-size: 16px;
+  }
 }
 
 .range-slider {
-  margin-top: 50px;
+  margin-top: 53px;
 
   .slider .marker {
     z-index: 2;

+ 2 - 8
src/views/home/cpns/FloatPanelUav.vue

@@ -1,6 +1,6 @@
 <template>
   <Transition name="fade">
-    <div class="panel-uav" v-if="modelValue && !layoutStore.asideCollapse">
+    <div class="panel-uav" v-if="!layoutStore.asideCollapse">
       <i @click="handleClose" class=" absolute right-4 top-4 text-white size-6 cursor-pointer hover:scale-110">
         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
           <path fill="currentColor"
@@ -58,10 +58,6 @@ import useLayoutStore from '@/store/layout';
 const layoutStore = useLayoutStore()
 
 const props = defineProps({
-  modelValue: {
-    type: Boolean,
-    required: true
-  },
   data: {
     type: Object,
     default: {
@@ -87,10 +83,8 @@ const props = defineProps({
   }
 })
 
-const emit = defineEmits(['update:modelValue'])
-
 function handleClose() {
-  emit('update:modelValue', false)
+  layoutStore.toggleFloatPanel('uav', false)
 }
 
 </script>

+ 1 - 1
src/views/home/cpns/PanelQjchs.vue

@@ -62,7 +62,7 @@
               <div class="upload-trigger">点击上传文件</div>
             </el-upload>
           </el-form-item>
-          <el-form-item label="高度" prop="height">
+          <el-form-item label="高度" prop="height" v-if="form.shape!=='漏斗'">
             <el-input v-model="form.height" type="number" clearable>
               <template #suffix>
                 <span>米</span>

+ 2 - 1
src/views/home/cpns/ToolList.vue

@@ -121,7 +121,8 @@ function handleToolClick(tool, childIndex) {
         case 'kytc':
           setLeftPanelByToolId(tool.active ? tool.id : 'default')
           break;
-
+        case 'fcky':
+          layoutStore.toggleFloatPanel('mesh', tool.active)
       }
     }
   }