1
wangjuncheng
2025-06-06 fd855df19dfadabf14c34ba91e8dfc2421227bf1
1
已添加4个文件
已修改4个文件
433 ■■■■ 文件已修改
src/assets/img/tools/tools_second/大气散射.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Dam.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Ditching.vue 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/SunAnalysis.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Tools.vue 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/tools.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/GisView.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/left/KGSim.vue 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/tools/tools_second/´óÆøÉ¢Éä.png
src/components/tools/Dam.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
<template>
  <div class="custom-panel">
    <div class="panel-content">
      <el-switch
        v-model="isDamEnabled"
        active-text="开挖开启"
        inactive-text="开挖关闭"
        @change="handleSwitchChange"
      />
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { ElSwitch } from 'element-plus';
const isDamEnabled = ref(false);
function handleDamOn() {
  console.log('开挖功能已开启');
  earthCtrl.factory.createModelLibrary()
}
// å¼€å…³å…³é—­æ—¶æ‰§è¡Œçš„函数
function handleDamOff() {
  console.log('开挖功能已关闭');
}
// ç›‘听 switch å˜åŒ–
function handleSwitchChange(value) {
  if (value) {
    handleDamOn();
  } else {
    handleDamOff();
  }
}
</script>
<style scoped>
.custom-panel {
  padding: 20px;
  width: 290px;
  background: url("@/assets/img/tools/plotting_new.png") no-repeat;
  filter: opacity(83%);
  background-size: 100% 100%;
  box-sizing: border-box;
}
.panel-content {
  display: flex;
  flex-direction: column;
}
</style>
src/components/tools/Ditching.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,137 @@
<template>
  <div class="custom-panel">
    <div class="panel-content">
      <!-- å¼€æŒ–深度设置 -->
      <el-form :model="form" label-width="80px">
        <el-form-item label="开挖深度">
          <el-input v-model="form.digDepth" placeholder="请输入开挖深度(m)" />
        </el-form-item>
      </el-form>
      <!-- æŒ‰é’®åŒºåŸŸ -->
      <div class="button-group">
        <el-button type="primary" @click="handleDraw">绘制</el-button>
        <el-button type="success" @click="handleConfirm">确认</el-button>
        <el-button type="danger" @click="handleClear">清除</el-button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, reactive, watch, defineEmits } from 'vue';
import { ElForm, ElFormItem, ElInput, ElButton, ElMessage } from 'element-plus';
const emit = defineEmits(['update-excavation-data']);
const form = reactive({
  digDepth: '100'
});
let excavationInstance = null;
const currentPoints = reactive([]);
const isDrawing = ref(false);
let clickHandler = null;
const handleDraw = () => {
  if (!window.viewer) {
    console.error('Cesium Viewer å°šæœªåˆå§‹åŒ–');
    return;
  }
  const viewer = window.viewer;
  // æ¸…空之前的数据
  currentPoints.splice(0, currentPoints.length);
  isDrawing.value = true;
  // é”€æ¯æ—§çš„监听器
  if (clickHandler) {
    clickHandler.destroy();
  }
  // ç«‹å³åˆ›å»ºå¼€æŒ–对象(不依赖初始点)
  createExcavation();
  // å¼€å§‹ç›‘听点击事件
  clickHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  clickHandler.setInputAction((movement) => {
    const cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
    if (cartesian) {
      currentPoints.push(cartesian.clone());
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};
const createExcavation = () => {
  const depth = parseFloat(form.digDepth);
  if (!isNaN(depth)) {
    excavationInstance = window.earthCtrl.analysis.createTerrainExcavation({
      height: depth,
      callback: function (a) {
      },
    });
  }else{
    ElMessage.warning('请输入有效的开挖深度!');
  }
};
watch(
  () => form.digDepth,
  (newVal) => {
    const num = parseFloat(newVal);
    if (!isNaN(num) && excavationInstance) {
      excavationInstance.setDeepth?.(num);
    }
  }
);
// ç‚¹å‡»ç¡®è®¤æŒ‰é’®ï¼ˆæ‰“印当前坐标点集合和深度)
const handleConfirm = () => {
  if (currentPoints.length === 0) {
    ElMessage.warning('请选取开沟有效的坐标点!');
    return;
  }
  const depth = parseFloat(form.digDepth);
  // è½¬æ¢ä¸ºæ™®é€šå¯¹è±¡æ•°ç»„
  const plainPoints = currentPoints.map(point => ({
    x: point.x,
    y: point.y,
    z: point.z
  }));
  const result = {
    points: plainPoints,
    depth: depth
  };
  emit('update-excavation-data', result);
};
const handleClear = () => {
  isDrawing.value = false;
  // é”€æ¯ç‚¹å‡»äº‹ä»¶ç›‘听器
  if (clickHandler) {
    clickHandler.destroy();
    clickHandler = null;
  }
  // æ¸…空临时点
  currentPoints.splice(0, currentPoints.length);
  // ç§»é™¤å¼€æŒ–对象
  if (excavationInstance) {
    excavationInstance.removeFromMap?.();
    excavationInstance = null;
  }
};
</script>
<style scoped>
.custom-panel {
  padding: 20px;
  width: 290px;
  background: url("@/assets/img/tools/plotting_new.png") no-repeat;
  filter: opacity(83%);
  background-size: 100% 100%;
  box-sizing: border-box;
}
.panel-content {
  display: flex;
  flex-direction: column;
}
.button-group {
  display: flex;
  justify-content: space-around;
}
</style>
src/components/tools/SunAnalysis.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
<template>
  <div class="settings-panel">
    <el-form :model="form" label-width="80px" class="terrain-settings">
      <el-form-item label="渲染大小">
        <el-select v-model="form.renderSize" placeholder="请选择">
          <el-option v-for="item in sizeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="配置选项">
        <el-switch v-model="form.lightShadow" active-text="光源阴影"></el-switch>
        <el-switch v-model="form.softShadow" active-text="软阴影"></el-switch>
      </el-form-item>
      <el-button type="primary" @click="analyzeShadows">阴影分析</el-button>
    </el-form>
  </div>
</template>
<script setup>
import { reactive, watch } from "vue";
import mapUtils from "@/utils/tools.js";
// å®šä¹‰è¡¨å•数据
const form = reactive({
  renderSize: '1024px X 1024px', // é»˜è®¤æ¸²æŸ“大小
  lightShadow: true, // é»˜è®¤å¼€å¯å…‰æºé˜´å½±
  softShadow: true, // é»˜è®¤å…³é—­è½¯é˜´å½±
});
// æ¸²æŸ“大小选项
const sizeOptions = [
  { value: '2048px X 2048px', label: '2048px X 2048px' },
  { value: '1024px X 1024px', label: '1024px X 1024px' },
  { value: '512px X 512px', label: '512px X 512px' },
  { value: '256px X 256px', label: '256px X 256px' },
];
// é˜´å½±åˆ†æžæŒ‰é’®ç‚¹å‡»äº‹ä»¶
const analyzeShadows = () => {
  let currentTime = earthCtrl.viewer.clock.currentTime.clone();
  let startTime = earthCtrl.viewer.clock.startTime.clone();
  let stopTime = earthCtrl.viewer.clock.stopTime.clone();
  let multiplier = earthCtrl.viewer.clock.multiplier;
  console.log('阴影分析');
  mapUtils.AnalysisSunshine()
};
</script>
<style lang="less" scoped>
.settings-panel {
  padding: 20px;
  width: 350px;
  background: url("@/assets/img/tools/plotting_new.png") no-repeat;
  filter: opacity(83%);
  background-size: 100% 100%;
  box-sizing: border-box;
}
.terrain-settings {
  .el-form-item {
    margin-bottom: 10px;
  }
  .el-select,
  .el-switch {
    margin-right: 10px;
  }
  .el-button {
    width: 100%;
    margin-top: 10px;
  }
}
</style>
src/components/tools/Tools.vue
@@ -4,16 +4,17 @@
    <div class="tools-title" @click="toggleCollapse">
      å·¥å…·æ 
      <div class="popup-menu" v-if="isPopupVisible">
        <div class="popup-item" v-for="(option, idx) in currentToolOptions" :key="idx" @click="handleOptionClick(option)">
          <img class="popup-icon" :src="
              require(`../../assets/img/tools/tools_second/${option.icon}.png`)
        <div class="popup-item" v-for="(option, idx) in currentToolOptions" :key="idx"
          @click="handleOptionClick(option)">
          <img class="popup-icon" :src="require(`../../assets/img/tools/tools_second/${option.icon}.png`)
            " :alt="option.name" />
          {{ option.name }}
        </div>
      </div>
      <LayerTree class="popup-menu" v-show="showLayerTree" />
      <!-- å¯è§†åŸŸåˆ†æž -->
      <seeAnalyze :option="option" v-show="seeAnalyzeShow" @update:showConeLine="handleUpdateShowConeLine" @update-option="onUpdateOption" @draw="onDraw" @clear="onClear" class="popup-menu-see" />
      <seeAnalyze :option="option" v-show="seeAnalyzeShow" @update:showConeLine="handleUpdateShowConeLine"
        @update-option="onUpdateOption" @draw="onDraw" @clear="onClear" class="popup-menu-see" />
      <!-- å‰–面提取 -->
      <TopographyDia @draw="handleDraw" @clear="handleClear" class="popup-menu-see" v-show="topographyShow" />
      <!-- å‰–面提取的echarts -->
@@ -21,11 +22,14 @@
        <div id="echartsView1" style="width: 100%; height: 100%"></div>
      </div>
      <!-- å¡åº¦å¡å‘分析 -->
      <Aspect v-show="showAspect" @draw="SlopeArrow" @clear="SlopeArrowClose" @handleaspect="handleaspect" @handleSlope="handleSlope" class="popup-menu-see" />
      <SlopeAnalysis @draw="SlopeAnalysiss" v-show="isContourLabel" class="popup-menu-see" @update-slope="onUpdateSlope" />
      <Aspect v-show="showAspect" @draw="SlopeArrow" @clear="SlopeArrowClose" @handleaspect="handleaspect"
        @handleSlope="handleSlope" class="popup-menu-see" />
      <SlopeAnalysis @draw="SlopeAnalysiss" v-show="isContourLabel" class="popup-menu-see"
        @update-slope="onUpdateSlope" />
      <!-- é›¨ -->
      <Rain v-show="showRain" class="popup-menu-see" @update-rain="onUpdateRain" />
      <Snow v-show="showSnow" class="popup-menu-see" @update-snow="onUpdateSnow" />
      <SunAnalysis v-show="showSunAnalysis" class="popup-menu-see"></SunAnalysis>
    </div>
    <!-- å·¥å…·æ å†…容 -->
@@ -49,9 +53,10 @@
import mapUtils from "@/utils/tools.js";
import Rain from "@/components/tools/Rain.vue";
import Snow from "@/components/tools/Snow.vue";
import SunAnalysis from "@/components/tools/SunAnalysis.vue";
// åˆ‡æ¢å±•å¼€/收缩状态
function toggleCollapse () {
function toggleCollapse() {
  // isCollapsed.value = !isCollapsed.value;
}
@@ -66,6 +71,8 @@
const isContourLabel = ref(false);
const showRain = ref(false);
const showSnow = ref(false);
const showAtmosphere = ref(false);
const showSunAnalysis = ref(false);
// å‰–面分析弹窗
const topographyShow = ref(false);
@@ -141,12 +148,14 @@
      { name: "雨天模式", icon: "雨天模式" },
      { name: "雪天模式", icon: "雪天模式" },
      { name: "清除天气", icon: "清除分析" },
      { name: "大气散射", icon: "大气散射" },
      { name: "日照分析", icon: "大气散射" },
    ],
  },
]);
// å¤„理工具点击事件
function handleClick (tool, event) {
function handleClick(tool, event) {
  // éåŽ†å·¥å…·åˆ—è¡¨ï¼Œæ›´æ–°æ¿€æ´»çŠ¶æ€
  toolList.value.forEach((item) => {
    item.active = item.name === tool.name && currentToolOptions.value !== tool.options;
@@ -188,7 +197,7 @@
const currentOption = ref(null);
// å¤„理弹窗选项点击事件
function handleOptionClick (option) {
function handleOptionClick(option) {
  isPopupVisible.value = false;
  currentOption.value = option.name;
  console.log("Selected option:", currentOption.value);
@@ -212,6 +221,22 @@
        console.log("天气效果已清除");
      } else {
        console.log("没有打开的天气效果");
      }
    },
    å¤§æ°”散射: () => {
      showAtmosphere.value = !showAtmosphere.value
      if (showAtmosphere.value) {
        mapUtils.enableAtmosphere()
      } else {
        mapUtils.disableAtmosphere()
      }
    },
    æ—¥ç…§åˆ†æž: () => {
      showSunAnalysis.value = !showSunAnalysis.value
      if (showSunAnalysis.value) {
        // mapUtils.AnalysisSunshine()
      } else {
        // mapUtils.disableAtmosphere()
      }
    },
@@ -292,13 +317,13 @@
};
// å¤„理子组件传来的可视域显示锥线的值
function handleUpdateShowConeLine (value) {
function handleUpdateShowConeLine(value) {
  showConeLine.value = value;
  mapUtils.showSyfxViewCone(showConeLine.value);
}
// é¼ æ ‡ç»˜åˆ¶å¯è§†åŸŸ
function onDraw () {
function onDraw() {
  // å®šä¹‰å›žè°ƒå‡½æ•°ï¼Œç”¨äºŽæŽ¥æ”¶ res å¹¶æ›´æ–° option
  const callback = (res) => {
    option.heading = res.heading;
@@ -309,7 +334,7 @@
}
// æ¸…除可视域
function onClear () {
function onClear() {
  mapUtils.syfxqc(option);
}
src/utils/tools.js
@@ -299,7 +299,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => { }
      (e) => {}
    );
  },
  qxcl() {
@@ -309,7 +309,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => { }
      (e) => {}
    );
  },
  fwjcl() {
@@ -319,7 +319,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => { }
      (e) => {}
    );
  },
  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>场景截图<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@@ -929,7 +929,7 @@
    };
    this.analysisFlood = earthCtrl.analysis.createSubmergence(
      method,
      (value) => { }
      (value) => {}
    );
  },
  clearFlood() {
@@ -962,6 +962,12 @@
      this.contourLabel.showContourLabel(false);
    }
  },
  enableAtmosphere() {
    earthCtrl.atmosphere.enable();
  },
  disableAtmosphere() {
    earthCtrl.atmosphere.disable();
  },
};
export default mapUtils;
src/views/GisView.vue
@@ -27,15 +27,17 @@
  // 1. è®¾ç½®åˆå§‹æ—¶é—´
  const date = new Date(2025, 3, 11, 12, 0, 0, 0);
  // const date = new Date(2024, 6, 13, 5, 5, 50);
  const julianDate = SmartEarth.Cesium.JulianDate.fromDate(date);
  // earthCtrl.viewer.clock.currentTime = julianDate;
  // 2. é…ç½®æ—¶é’Ÿé€‰é¡¹ï¼Œç¦æ­¢è‡ªåŠ¨æŽ¨è¿›æ—¶é—´
  // // 2. é…ç½®æ—¶é’Ÿé€‰é¡¹ï¼Œç¦æ­¢è‡ªåŠ¨æŽ¨è¿›æ—¶é—´
  earthCtrl.viewer.clockViewModel.shouldAnimate = false; // ç¦ç”¨åŠ¨ç”»
  earthCtrl.viewer.clockViewModel.clockRange =
    SmartEarth.Cesium.ClockRange.CLAMPED; // é™åˆ¶æ—¶é—´èŒƒå›´
  earthCtrl.viewer.clockViewModel.multiplier = 0; // è®¾ç½®æ—¶é—´æŽ¨è¿›é€Ÿåº¦ä¸º0
  // å¼€å¯å¤§æ°”散射效果
  // earthCtrl.atmosphere.enable();
  // 3. è®¾ç½®å½“前时间并锁定
  earthCtrl.viewer.clock.currentTime = julianDate;
src/views/left/KGSim.vue
@@ -3,29 +3,21 @@
    <!-- æ¨¡æ‹ŸåŒºåŸŸ -->
    <div class="simulation-area">
      <p>模拟区域</p>
      <el-select
        v-model="selectedArea"
        placeholder="请选择"
        style="max-width: 600px"
        popper-class="mySelectStyle"
        filterable
        :filter-method="filterOptions"
        @change="handleSelectChange"
      >
        <el-option
          v-for="item in filteredOptions"
          :key="item.value"
          :label="item.label"
          :value="item"
        />
      <el-select v-model="selectedArea" placeholder="请选择" style="max-width: 600px" popper-class="mySelectStyle"
        filterable :filter-method="filterOptions" @change="handleSelectChange">
        <el-option v-for="item in filteredOptions" :key="item.value" :label="item.label" :value="item" />
      </el-select>
    </div>
    <!-- æ²»ç†å·¥ç¨‹æ ‡ç»˜ -->
    <div class="engineering-buttons">
      <p>治理工程标绘</p>
      <el-button type="primary" @click="handleStart">开沟</el-button>
      <el-button type="success" @click="handleAdd">加坝</el-button>
      <el-button type="primary" @click="toggleDitch">
        {{ ditchingActive ? "关闭开沟" : "开启开沟" }}
      </el-button>
      <el-button type="primary" @click="toggleDam">
        {{ damActive ? "关闭加坝" : "开启加坝" }}
        </el-button>
    </div>
    <!-- åŽ†å²æ¨¡æ‹Ÿ -->
@@ -36,7 +28,6 @@
        <el-radio label="预测模拟">预测模拟</el-radio>
      </el-radio-group>
      <div v-if="selectedSimulation === '历史模拟'">
        <!-- <HistorySimulation :selectedArea="selectedArea" /> -->
        <CitySim :selectedArea="selectedArea" />
      </div>
      <div v-if="selectedSimulation === '实时模拟'">
@@ -46,6 +37,8 @@
        <PredictiveSimulation :selectedArea="selectedArea" />
      </div>
    </div>
    <Ditching v-show="ditchingShow" class="ditchingPosition" @update-excavation-data="handleUpdateExcavationData"></Ditching>
    <Dam v-show="damShow" class="ditchingPosition"></Dam>
  </div>
</template>
@@ -53,6 +46,8 @@
import { ref, computed, onMounted, reactive } from "vue";
import HistorySimulation from "./KGSimOption/HistorySimulation.vue";
import CitySim from './CitySim.vue'
import Ditching from "@/components/tools/Ditching.vue";
import Dam from "@/components/tools/Dam.vue";
import PredictiveSimulation from "./KGSimOption/PredictiveSimulation.vue";
import RealTimeSimulation from "./KGSimOption/RealTimeSimulation.vue";
import { getRegionData } from "@/api/trApi";
@@ -62,6 +57,10 @@
const selectedArea = ref(); // é€‰ä¸­çš„区域
// é‡ç‚¹æ²Ÿæ•°æ®
const importGOptions = reactive([]);
let ditchingShow = ref(false);
let damShow = ref(false);
let ditchingActive = ref(false);
let damActive = ref(false);
onMounted(() => {
  // èŽ·å–é‡ç‚¹æ²Ÿæ•°æ®
@@ -86,6 +85,10 @@
  );
});
const handleUpdateExcavationData = (data) => {
  console.log('接收到子组件的数据:', data);
  // æ­¤å¤„可进行后续操作,如保存、绘图等
};
// è‡ªå®šä¹‰è¿‡æ»¤æ–¹æ³•
const filterOptions = (query) => {
  searchQuery.value = query;
@@ -101,8 +104,35 @@
  ); // æ‰“印完整的选中数据
};
const handleStart = () => {
  console.log("开始按钮被点击");
// åˆ‡æ¢å¼€æ²ŸçŠ¶æ€
const toggleDitch = () => {
  ditchingActive.value = !ditchingActive.value;
  ditchingShow.value = ditchingActive.value;
  if (ditchingActive.value) {
    console.log("开启按钮被点击");
  } else {
    console.log("关闭按钮被点击");
    cloesDitch();
  }
};
// åˆ‡æ¢åŠ åçŠ¶æ€
const toggleDam = () => {
  damActive.value = !damActive.value;
  damShow.value = damActive.value;
  if (damActive.value) {
    console.log("开启按钮被点击");
  } else {
    console.log("关闭按钮被点击");
    cloesDam();
  }
};
const cloesDitch = () => {
  ditchingShow.value = false;
};
const cloesDam = () => {
  damShow.value = false;
};
const handleAdd = () => {
@@ -111,6 +141,12 @@
</script>
<style scoped>
.ditchingPosition {
  position: fixed;
  left: 18%;
  top: 20%;
}
.simulation-module {
  color: #61f7d4;
  font-size: 14px;
@@ -130,25 +166,36 @@
.history-simulation-wrapper {
  margin-bottom: 20px;
  height: 100%; /* å›ºå®šé«˜åº¦ */
  height: 100%;
  /* å›ºå®šé«˜åº¦ */
  overflow: auto;
}
/* è‡ªå®šä¹‰å•选框样式 */
:deep(.el-radio__input.is-checked .el-radio__inner) {
  background-color: #009688; /* é€‰ä¸­æ—¶çš„背景颜色 */
  border-color: #009688; /* é€‰ä¸­æ—¶çš„边框颜色 */
  background-color: #009688;
  /* é€‰ä¸­æ—¶çš„背景颜色 */
  border-color: #009688;
  /* é€‰ä¸­æ—¶çš„边框颜色 */
}
:deep(.el-radio__input.is-checked + .el-radio__label) {
  color: inherit; /* è®©æ–‡å­—颜色跟随父级 */
  color: inherit;
  /* è®©æ–‡å­—颜色跟随父级 */
}
:deep(.el-select__placeholder) {
  color: #fff; /* è®©æ–‡å­—颜色跟随父级 */
  color: #fff;
  /* è®©æ–‡å­—颜色跟随父级 */
}
:deep(.el-radio) {
  color: #fff; /* è®©æ–‡å­—颜色跟随父级 */
  color: #fff;
  /* è®©æ–‡å­—颜色跟随父级 */
}
:deep(.el-input__inner) {
  color: #fff; /* è®©æ–‡å­—颜色跟随父级 */
  color: #fff;
  /* è®©æ–‡å­—颜色跟随父级 */
}
</style>
</style>