wangjuncheng
2025-05-08 db07d86f01f19683d7adb263139159ffe1e0c9bf
change
已添加6个文件
已修改9个文件
413 ■■■■ 文件已修改
public/images/poi/含水率.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/poi/摄像头.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/poi/泥位计.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/poi/流速仪.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/TimeLine.vue 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monifangzhen/schemeInfo.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/DebuffDetail.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/LayerTree.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Legend_yhgl.vue 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Legend_zhjc.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Message.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/GisView.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Home.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/yhgl.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/zhjc.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/images/poi/º¬Ë®ÂÊ.png
public/images/poi/ÉãÏñÍ·.png
public/images/poi/Äàλ¼Æ.png
public/images/poi/Á÷ËÙÒÇ.png
src/components/menu/TimeLine.vue
@@ -2,30 +2,20 @@
  <div class="timeline-container">
    <div class="controls">
      <div class="control-btn" @click="skipBackward">
        <img
          src="@/assets/img/timeline/left.png"
          class="fas fa-step-backward"
        />
        <img src="@/assets/img/timeline/left.png" class="fas fa-step-backward" />
      </div>
      <div class="control-btn play-btn" @click="togglePlay">
        <img v-show="isPlaying" src="@/assets/img/timeline/stop.png" />
        <img v-show="!isPlaying" src="@/assets/img/timeline/start.png" />
      </div>
      <div class="control-btn" @click="skipForward">
        <img
          src="@/assets/img/timeline/right.png"
          class="fas fa-step-forward"
        />
        <img src="@/assets/img/timeline/right.png" class="fas fa-step-forward" />
      </div>
      <div class="speed-control">
        <div @click="toggleSpeedMenu">{{ playbackRate }}X</div>
        <div class="speed-menu" v-show="showSpeedMenu">
          <div
            v-for="rate in playbackRates"
            :key="rate"
            @click.capture="setPlaybackRate(rate)"
            :class="{ active: playbackRate === rate }"
          >
          <div v-for="rate in playbackRates" :key="rate" @click.capture="setPlaybackRate(rate)"
            :class="{ active: playbackRate === rate }">
            {{ rate }}X
          </div>
        </div>
@@ -35,39 +25,21 @@
    <div class="timeline">
      <div class="dates">
        <div class="current-date">当前播放时间:{{ currentPlayingTime }}</div>
        <div
          v-for="(date, index) in visibleDates"
          :key="index"
          class="date-label"
        >
        <div v-for="(date, index) in visibleDates" :key="index" class="date-label">
          <!-- {{ formatDate(date) }} -->
        </div>
      </div>
      <div class="timeline-track" ref="timelineTrack" @click="seekToPosition">
        <div
          class="timeline-progress"
          :style="{ width: progressPercentage + '%' }"
        ></div>
        <div
          class="timeline-cursor"
          :style="{ left: progressPercentage + '%' }"
        ></div>
        <div class="timeline-progress" :style="{ width: progressPercentage + '%' }"></div>
        <div class="timeline-cursor" :style="{ left: progressPercentage + '%' }"></div>
        <div class="time-markers">
          <div
            v-for="(time, index) in timeMarkers"
            :key="index"
            class="time-marker"
          >
          <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker">
            {{ time }}
          </div>
        </div>
      </div>
    </div>
    <el-button
      @click="handleBack"
      style="margin-top: 26px; margin-left: 30px; margin-right: 10px"
      >结束模拟</el-button
    >
    <el-button @click="handleBack" style="margin-top: 26px; margin-left: 30px; margin-right: 10px">结束模拟</el-button>
  </div>
</template>
@@ -215,54 +187,127 @@
    emit("timeUpdate", progress * 100); // ç™¾åˆ†æ¯”上报
  }, 1000); // æ³¨æ„ä½¿ç”¨interval而非固定1000ms
};
let rainFallValues = ref([]); // ç”¨äºŽå­˜å‚¨æå–çš„value数组
// é™é›¨å˜åŒ–部分
// é™é›¨æ•°æ®ç›¸å…³å˜é‡
// é™é›¨æ•°æ®ç›¸å…³å˜é‡
let rainFallValues = ref([]); // å­˜å‚¨åŽŸå§‹é™é›¨é‡æ•°æ®
let minRainValue = ref(Infinity);
let maxRainValue = ref(-Infinity);
// èŽ·å–é™é›¨æ•°æ®
function getRainfallData() {
  getRainfall().then((res) => {
    rainFallValues.value = res;
    // æå–value值
    rainFallValues.value = rainFallValues.value.data.map(item => item.value);
    // è®¡ç®—min和max雨量值
    rainFallValues.value = res.data.map(item => item.value); // æå–降雨量值
    minRainValue.value = Math.min(...rainFallValues.value);
    maxRainValue.value = Math.max(...rainFallValues.value);
    console.log(minRainValue.value, maxRainValue.value, 'min and max rain values');
  });
}
// çº¿æ€§æ˜ å°„函数
function mapValue(value, fromLow, fromHigh, toLow, toHigh) {
  return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
}
// æ ¹æ®å½“前播放进度更新天气
// æˆ‘这里要是接入真实数据后,每个数据
function updateWeatherByProgress() {
  const progress = currentTime.value / duration.value;
  // è®¡ç®—当前进度对应于 rainFallValues æ•°ç»„中的位置
  const index = Math.floor(progress * (rainFallValues.value.length - 1));
  const rainValue = rainFallValues.value[index]; // èŽ·å–å¯¹åº”çš„é™é›¨é‡ value
  // æ ¹æ®å½“前雨量动态调整雨的参数
  // const rainParams = {
  //   rainSize: mapValue(rainValue, minRainValue.value, maxRainValue.value, 0.5, 1.5),     // é›¨æ»´å¤§å°ï¼šä»Žå°åˆ°å¤§
  //   rainSpeed: mapValue(rainValue, minRainValue.value, maxRainValue.value, 30, 120),      // é›¨é€Ÿï¼šä»Žæ…¢åˆ°å¿«
  //   rainDensity: mapValue(rainValue, minRainValue.value, maxRainValue.value, 20, 120),    // å¯†åº¦ï¼šä»Žç¨€ç–åˆ°å¯†é›†
  //   rainColor: "#99B3CC"  // å¯ä»¥åœ¨æ­¤åŸºç¡€ä¸Šå¢žåŠ é¢œè‰²å˜åŒ–é€»è¾‘ï¼Œä¾‹å¦‚æš´é›¨ä¸ºæ·±è“ç­‰
  // };
  // è°ƒç”¨å·¥å…·æ–¹æ³•更新下雨效果
  mapUtils.toggleRain(rainParams, true);
// // çº¿æ€§æ˜ å°„函数
// function mapValue(value, fromLow, fromHigh, toLow, toHigh) {
//   return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
// }
// å®šä¹‰é™é›¨ç­‰çº§åŠå…¶å¯¹åº”的视觉参数
const rainLevels = [
  {
    name: '小雨',
    min: 0.1,
    max: 9.9,
    size: 0.5,     // é›¨æ»´å¤§å°ï¼šæ›´å°
    speed: 20,     // ä¸‹è½é€Ÿåº¦ï¼šæ›´æ…¢
    density: 15,   // é›¨æ»´å¯†åº¦ï¼šæ›´ç¨€ç–
    color: '#ADD8E6' // æµ…蓝色,象征轻柔的小雨
  },
  {
    name: '中雨',
    min: 10,
    max: 24.9,
    size: 0.7,
    speed: 40,
    density: 35,
    color: '#ADD8E6' // å¤©è“è‰²ï¼Œè±¡å¾æŒç»­çš„中雨
  },
  {
    name: '大雨',
    min: 25,
    max: 49.9,
    size: 1.0,
    speed: 70,
    density: 60,
    color: '#ADD8E6' // æ·±è“è‰²ï¼Œè±¡å¾å¯†é›†çš„大雨
  },
  {
    name: '暴雨',
    min: 50,
    max: 99.9,
    size: 1.3,
    speed: 90,
    density: 80,
    color: '#ADD8E6' // æ·±è“é»‘色,象征强降雨
  },
  {
    name: '大暴雨',
    min: 100,
    size: 1.6,
    speed: 110,
    density: 100,
    color: '#ADD8E6' // é»‘色,象征极端暴雨
  }
];
// æ ¹æ®é™é›¨é‡è¿”回对应的雨形配置
function getRainLevel(rainValue) {
  for (let level of rainLevels) {
    if (level.min <= rainValue && (level.max === undefined || rainValue <= level.max)) {
      return level;
    }
  }
  // é»˜è®¤æ— é›¨çŠ¶æ€
  return { name: '无雨', size: 0.5, speed: 30, density: 20, color: '#F0F8FF' };
}
// æ ¹æ®æ’­æ”¾è¿›åº¦æ›´æ–°å¤©æ°”效果
function updateWeatherByProgress() {
  const progress = currentTime.value / duration.value;
  const floatIndex = progress * (rainFallValues.value.length - 1);
  const index = Math.floor(floatIndex);
  const nextIndex = Math.min(index + 1, rainFallValues.value.length - 1);
  const currentRain = rainFallValues.value[index];
  const nextRain = rainFallValues.value[nextIndex];
  // æ’值因子 [0, 1]
  // const alpha = floatIndex - index;
  // æ’值得到当前降雨量
  // const rainValue = currentRain + (nextRain - currentRain) * alpha;
  const rainValue = currentRain + (nextRain - currentRain);
  // èŽ·å–å¯¹åº”çš„é›¨å½¢é…ç½®
  const rainLevel = getRainLevel(rainValue);
  if (rainLevel.name === '无雨') {
    mapUtils.delRain();
    return;
  }
  // éžæ— é›¨çŠ¶æ€ï¼šæž„å»ºé›¨æ»´å‚æ•°å¹¶æ›´æ–°é›¨æ•ˆ
  const rainParams = {
    rainSize: rainLevel.size,
    rainSpeed: rainLevel.speed,
    rainDensity: rainLevel.density,
    rainColor: rainLevel.color
  };
  console.log('当前雨量数据:', rainValue);
  console.log('当前雨形:', rainLevel);
  // è°ƒç”¨å·¥å…·æ–¹æ³•更新雨效
  mapUtils.toggleRain(rainParams, true);
}
const stopPlayback = () => {
  clearInterval(playInterval);
};
const skipForward = () =>
  (currentTime.value = Math.min(currentTime.value + 1, duration.value)); // å‘前跳转1秒
const skipBackward = () =>
  (currentTime.value = Math.max(currentTime.value - 1, 0)); // å‘后跳转1秒
const toggleSpeedMenu = () => (showSpeedMenu.value = !showSpeedMenu.value);
// è®¾ç½®æ’­æ”¾é€Ÿçއ
const setPlaybackRate = (rate) => {
  playbackRate.value = rate;
@@ -270,14 +315,13 @@
  // åœæ­¢å½“前播放
  stopPlayback();
  setTimeout(() => {
        mapUtils.delRain();
      }, 3000);
    mapUtils.delRain();
  }, 3000);
  // é‡ç½®æ—¶é—´è½´åˆ°åˆå§‹çŠ¶æ€
  currentTime.value = 0; // æ—¶é—´å½’é›¶
  emit("timeUpdate", progressPercentage.value);
  isPlaying.value = false;
  emit("isPlaying", false);
  // é”€æ¯çŽ°æœ‰çš„æ°´ä½“æ¨¡æ‹Ÿå±‚
  if (isWaterPrimitiveCreated.value) {
    destoryWaterPrimitive();
@@ -298,7 +342,7 @@
      message: "请先启动水体模拟后再进行时间轴跳转。",
      type: "warning",
    });
    return; // é˜»æ­¢åŽç»­é€»è¾‘执行
    return;
  }
  const rect = timelineTrack.value.getBoundingClientRect();
  const percentage = (event.clientX - rect.left) / rect.width;
@@ -314,10 +358,7 @@
      "Time:",
      dayjs(waterTimestamps.value[closestIndex]).format("YYYY-MM-DD HH:mm:ss")
    );
    // è°ƒç”¨è·³è½¬æŽ¥å£ï¼Œä¼ é€’索引值
    setTimeForWaterSimulation(closestIndex);
    // å¦‚果当前是暂停状态,调用 pauseWaterSimulation
    if (!isPlaying.value) {
      pauseWaterSimulation();
    }
@@ -331,7 +372,7 @@
  waterTimestamps.value.forEach((timestamp, index) => {
    const diff = Math.abs(
      dayjs(timestamp).diff(dayjs(waterTimestamps.value[0]), "second") -
        currentTimeValue
      currentTimeValue
    );
    if (diff < minDiff) {
      minDiff = diff;
@@ -446,7 +487,7 @@
  left: 50%;
  transform: translateX(-50%);
  z-index: 99;
  width: 878px;
  width: 678px;
  height: 108px;
  /* background-color: #1a2634; */
  background: url("@/assets/img/menubar/bar.png");
src/components/monifangzhen/schemeInfo.vue
@@ -133,6 +133,15 @@
        }
        continue;
      }
      // å¤„理 areaName å­—段
      if (key === "areaName") {
        data.push({
          name: "区域名称:",
          value: value || "无",
        });
        continue;
      }
      // å¤„理 result å­—段
      if (key === "result") {
src/components/tools/DebuffDetail.vue
@@ -1,7 +1,7 @@
<template>
    <div class="detail">
        <div class="detail-top">统计分析结果</div>
        <div class="detail-btn" @click="showMsg">查看详情</div>
        <!-- <div class="detail-btn" @click="showMsg">查看详情</div> -->
        <div class="detail-close" @click="closeMsg"></div>
        <div class="detail-context">
            <div v-for="(item, key) in detailList" :key="key" class="detail-item">
src/components/tools/LayerTree.vue
@@ -263,7 +263,7 @@
  districtList.value.forEach((item) => {
    item.showBillboard = true;
    item.className = "district";
    item.type = "泥石流";
    // item.type = "泥石流";        //数据icon设置
    const entity = createPoint(item);
    entity.show = false;
    list.push(entity);
src/components/tools/Legend_yhgl.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
<template>
  <div class="legend-container">
    <div class="legend-title">图例说明</div>
    <ul class="legend-list">
      <li v-for="(item, index) in legendItems" :key="index" class="legend-item">
        <img :src="getImageUrl(item.icon)" :alt="item.label" class="legend-icon" />
        <span class="legend-label">{{ item.label }}</span>
      </li>
    </ul>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
// å®šä¹‰å›¾ä¾‹æ•°æ®
const legendItems = ref([
  { icon: "崩塌.png", label: "崩塌" },
  { icon: "泥石流.png", label: "泥石流" },
  { icon: "滑坡.png", label: "滑坡" },
]);
// èŽ·å– public ä¸‹çš„图片路径
const getImageUrl = (iconName) => {
  return `/images/poi/${iconName}`;
};
onMounted(() => {
  console.log("这里是图例集合!");
});
</script>
<style lang="less" scoped>
.legend-container {
  padding: 0.5rem; // å‡å°‘内边距
  // background-color: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 8px;
  max-width: 100%;
  width: auto;
  font-size: clamp(10px, 1vw, 14px); // æ›´å°çš„基础字号
}
.legend-title {
  width: 100%;
  // border: 1px solid #ddd;
  margin-bottom: 10%;
  text-align: center;
  letter-spacing: 2px;
  font-weight: 600;
  font-size: clamp(16px, 1vw, 20px); // æ›´å°çš„基础字号
}
.legend-list {
  list-style: none;
  padding: 0;
  // margin: 0;
  display: flex;
  flex-direction: column; // æ”¹ä¸ºåž‚直方向布局
  gap: 0.5rem; // å‡å°‘间距
}
.legend-item {
  display: flex;
  align-items: center;
}
.legend-icon {
  width: 23px; // å‡å°‘图标大小
  height: 25px; // å‡å°‘图标大小
  margin-right: 0.5rem; // å‡å°‘右边距
}
.legend-label {
  font-size: inherit; // ç»§æ‰¿çˆ¶çº§å­—体大小
}
</style>
src/components/tools/Legend_zhjc.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
<template>
  <div class="legend-container">
    <div class="legend-title">图例说明</div>
    <ul class="legend-list">
      <li v-for="(item, index) in legendItems" :key="index" class="legend-item">
        <img :src="getImageUrl(item.icon)" :alt="item.label" class="legend-icon" />
        <span class="legend-label">{{ item.label }}</span>
      </li>
    </ul>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
// å®šä¹‰å›¾ä¾‹æ•°æ®
const legendItems = ref([
  { icon: "编码器.png", label: "编码器" },
  { icon: "摄像头.png", label: "摄像头" },
  { icon: "泥位计.png", label: "泥位计" },
  { icon: "流速仪.png", label: "流速仪" },
  { icon: "含水率.png", label: "含水率" },
  { icon: "次生仪.png", label: "次生仪" },
  { icon: "雨量计.png", label: "雨量计" },
  { icon: "墒情.png", label: "墒情" },
]);
// èŽ·å– public ä¸‹çš„图片路径
const getImageUrl = (iconName) => {
  return `/images/poi/${iconName}`;
};
onMounted(() => {
  console.log("这里是图例集合!");
});
</script>
<style lang="less" scoped>
.legend-container {
  padding: 0.5rem; // å‡å°‘内边距
  // background-color: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 8px;
  max-width: 100%;
  width: auto;
  font-size: clamp(10px, 1vw, 14px); // æ›´å°çš„基础字号
}
.legend-title {
  width: 100%;
  // border: 1px solid #ddd;
  margin-bottom: 10%;
  text-align: center;
  letter-spacing: 2px;
  font-weight: 600;
  font-size: clamp(16px, 1vw, 20px); // æ›´å°çš„基础字号
}
.legend-list {
  list-style: none;
  padding: 0;
  // margin: 0;
  display: flex;
  flex-direction: column; // æ”¹ä¸ºåž‚直方向布局
  gap: 0.5rem; // å‡å°‘间距
}
.legend-item {
  display: flex;
  align-items: center;
}
.legend-icon {
  width: 23px; // å‡å°‘图标大小
  height: 25px; // å‡å°‘图标大小
  margin-right: 0.5rem; // å‡å°‘右边距
}
.legend-label {
  font-size: inherit; // ç»§æ‰¿çˆ¶çº§å­—体大小
}
</style>
src/components/tools/Message.vue
@@ -118,6 +118,11 @@
        continue;
      }
      if (key === "areaName") {
        formattedData.push({ name: "区域名称:", value: value || "无" });
        continue;
      }
      if (key === "name") {
        formattedData.push({ name: "仿真方案:", value: value || "无" });
        continue;
src/views/GisView.vue
@@ -468,8 +468,8 @@
  position: absolute;
}
// // ä¿®æ”¹æŒ‡å—针位置
// /deep/ .compass {
//     right: 128px !important;
//     top: 112px;
// }
/deep/ .compass {
    right: 128px !important;
    top: 112px;
}
</style>
src/views/Home.vue
@@ -22,7 +22,6 @@
  <ImagePreview v-if="showPreview" />
  <!-- <Weather v-if="weatherShow" @close="weatherShow = false" /> -->
  <Bar v-if="barShow" @close="barShow = false" />
  <Detail v-if="showDetail" />
</template>
src/views/yhgl.vue
@@ -1,10 +1,23 @@
<template>
    <Location />
    <Legend class="legend" />
</template>
<script setup>
    import Location from "@/components/menu/Location.vue"
import Location from "@/components/menu/Location.vue"
import Legend from "@/components/tools/Legend_yhgl.vue";
</script>
<style lang="less" scoped>
    @import url("../assets/css/home.css");
.legend {
    // background: url("@/assets/img/right/rightbg.png");
    color: white;
    position: fixed;
    bottom: 6%;
    right: 1%;
    z-index: 3333;
}
@import url("../assets/css/home.css");
</style>
src/views/zhjc.vue
@@ -1,10 +1,23 @@
<template>
    <Device />
    <div>
        <Device />
        <Legend class="legend"/>
    </div>
</template>
<script setup>
    import Device from "@/components/menu/Device.vue"
import Legend from "@/components/tools/Legend_zhjc.vue";
import Device from "@/components/menu/Device.vue"
</script>
<style lang="less" scoped>
    .legend{
    // background: url("@/assets/img/right/rightbg.png");
    color: white;
        position: fixed;
        bottom: 6%;
        right: 1%;
        z-index: 3333;
    }
    @import url("../assets/css/home.css");
</style>