guonan
2025-05-23 fef12378282c0a8cf44411b079ac20ad4f397817
修改比较多
已修改11个文件
已删除1个文件
620 ■■■■ 文件已修改
src/api/trApi.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/Device.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/Location.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/TimeLine.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monifangzhen/echartInfo.vue 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monifangzhen/schemeCard.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Message copy.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/simAPI.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/simulation.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/tools.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/GisView.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/left/CitySim.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/trApi.js
@@ -122,6 +122,7 @@
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const jsonData = await response.json(); // è§£æž JSON æ•°æ®
    console.log(jsonData,'jsonjsonjsonjson')
    return parseWaterSimulationData(jsonData); // è°ƒç”¨è§£æžå‡½æ•°
  } catch (error) {
    console.error("请求或解析数据时出错:", error);
src/components/menu/Device.vue
@@ -6,12 +6,28 @@
    <div class="left-content device-content">
      <div style="margin-left: 5px">
        <span style="color: white">重点沟:</span>
        <el-select @change="handleChange" v-model="selectValue" placeholder="Select" size="large" style="width: 240px">
          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
        <el-select
          @change="handleChange"
          v-model="selectValue"
          placeholder="Select"
          size="large"
          style="width: 240px"
        >
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </div>
      <el-tree :data="deviceTree" node-key="deviceId" :props="treeProps" @node-click="handleTreeNodeClick"
        class="device-tree">
      <el-tree
        :data="deviceTree"
        node-key="deviceId"
        :props="treeProps"
        @node-click="handleTreeNodeClick"
        class="device-tree"
      >
        <template #default="{ node, data }">
          <span v-if="!data.children" class="device-tree-item">
            <!-- <div class="device-item-icon"></div> -->
@@ -27,21 +43,23 @@
</template>
<script setup>
import { ref, computed, onMounted, watch, onBeforeUnmount, } from "vue";
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import { ref, computed, onMounted, watch, onBeforeUnmount } from "vue";
import { useRoute, onBeforeRouteUpdate } from "vue-router";
import { createPoint, removeEntities } from "@/utils/map";
import { deviceDictList, getDictName } from "@/constant/dict.js";
import { getDeviceInfo } from "@/api/hpApi";
import { initeWaterPrimitiveView } from "@/utils/water"; //相机flyTo函数,后续options列表中有对应经纬度后弃用
import { useSimStore } from "@/store/simulation";
const simStore = useSimStore();
onMounted(() => {
onMounted(async () => {
  // åŠ è½½æ‰€æœ‰çš„éšæ‚£ç‚¹ä¿¡æ¯
  await getData();
  loadDeviceList("孙胡沟");
  initeWaterPrimitiveView()
  initeWaterPrimitiveView();
});
onBeforeRouteUpdate((to, from, next) => {
  if (to.path !== '/zhjc') {
  if (to.path !== "/zhjc") {
    handleCleanup();
  }
  next();
@@ -49,24 +67,27 @@
const route = useRoute();
onBeforeUnmount(() => {
  if (route.path !== '/zhjc') {
  if (route.path !== "/zhjc") {
    handleCleanup();
  }
});
watch(() => simStore.DeviceShowSwitch, (newValue, oldValue) => {
  if (newValue) {
    initializeDevicePoints();
  } else {
    handleCleanup()
watch(
  () => simStore.DeviceShowSwitch,
  (newValue, oldValue) => {
    if (newValue) {
      initializeDevicePoints();
    } else {
      handleCleanup();
    }
  }
});
);
const deviceListAll = ref([]);
const deviceEntities = ref([]);
const handleCleanup = () => {
  deviceListAll.value.forEach(item => {
  deviceListAll.value.forEach((item) => {
    removeEntities(item.deviceId);
  });
}
};
const initializeDevicePoints = () => {
  const list = [];
  deviceListAll.value.forEach((item, index) => {
@@ -82,13 +103,18 @@
  });
  deviceEntities.value = list;
};
const allDevices = ref([]);
const getData = async () => {
  const res = await getDeviceInfo();
  allDevices.value = res.data.pageData;
};
// æ ¹æ®åŒºåŸŸåç§°åŠ è½½è®¾å¤‡åˆ—è¡¨
const loadDeviceList = async (areaName) => {
  try {
    handleCleanup()
    const res = await getDeviceInfo();
    const allDevices = res.data.pageData;
    const devicesInArea = allDevices.filter((item) =>
    handleCleanup();
    // const res = await getDeviceInfo();
    // const allDevices = res.data.pageData;
    const devicesInArea = allDevices.value.filter((item) =>
      item.deviceName?.includes(areaName)
    );
    deviceListAll.value = devicesInArea;
@@ -98,6 +124,7 @@
    console.error("加载设备信息失败", error);
  }
};
// å¤„理区域变化事件
const handleChange = (item) => {
  if (!item) {
src/components/menu/Location.vue
@@ -205,7 +205,7 @@
  left: 0px;
  right: 0px;
  bottom: 10px;
  background-color: rgba(236, 233, 233, 0.5);
  background-color: rgba(47, 44, 44, 0.5);
  /* åŠé€æ˜Žé®ç½© */
  display: flex;
  align-items: center;
src/components/menu/TimeLine.vue
@@ -2,20 +2,30 @@
  <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>
@@ -25,18 +35,33 @@
    <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>专题渲染:
          <el-switch v-model="isColorRenderEnabled" @change="handleColorRenderChange" style="margin-top:-3px"
            :disabled="!isPlaying || !isWaterPrimitiveCreated" />
        <div>
          ä¸“题渲染:
          <el-switch
            v-model="isColorRenderEnabled"
            @change="handleColorRenderChange"
            style="margin-top: -3px"
            :disabled="!isPlaying || !isWaterPrimitiveCreated"
          />
          <!-- active-text="开" inactive-text="关" -->
        </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="scale-markers">
          <div class="scale-marker" style="left: 0%"></div>
          <div class="scale-marker" style="left: 25%"></div>
@@ -45,20 +70,36 @@
          <div class="scale-marker" style="left: 100%"></div>
        </div>
        <div class="time-markers">
          <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker"
            :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }">
            <div class="date-part">{{ time.split(' ')[0] }}</div>
            <div class="time-part">{{ time.split(' ')[1] }}</div>
          <div
            v-for="(time, index) in timeMarkers"
            :key="index"
            class="time-marker"
            :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }"
          >
            <div class="date-part">{{ time.split(" ")[0] }}</div>
            <div class="time-part">{{ time.split(" ")[1] }}</div>
          </div>
        </div>
      </div>
    </div>
    <div>
      <ratelevel ref="ratelevelRef" :playing-time="sendCurrentPlayingTime" @finish-calculation="handleFinishCalculation"
        style="margin-top: 12px; margin-left: 28px; margin-right: 10px;justify-content: flex-end;"></ratelevel>
      <el-button @click="handleBack" style="margin-top: 3px; margin-left: 30px; margin-right: 10px">结束模拟</el-button>
      <ratelevel
        ref="ratelevelRef"
        :playing-time="sendCurrentPlayingTime"
        @finish-calculation="handleFinishCalculation"
        style="
          margin-top: 12px;
          margin-left: 28px;
          margin-right: 10px;
          justify-content: flex-end;
        "
      ></ratelevel>
      <el-button
        @click="handleBack"
        style="margin-top: 3px; margin-left: 30px; margin-right: 10px"
        >结束模拟</el-button
      >
    </div>
  </div>
</template>
@@ -71,7 +112,7 @@
  defineProps,
  onBeforeUnmount,
  inject,
  reactive
  reactive,
} from "vue";
import ratelevel from "@/components/menu/flowRate_waterLevel.vue";
@@ -94,7 +135,12 @@
const simStore = useSimStore();
const { selectedScheme } = storeToRefs(simStore);
const emit = defineEmits(["timeUpdate", "isPlaying", "playbackFinished", "isColorRender"]);
const emit = defineEmits([
  "timeUpdate",
  "isPlaying",
  "playbackFinished",
  "isColorRender",
]);
// å®šä¹‰props
const props = defineProps({
  waterSimulateParams: {
@@ -127,7 +173,7 @@
  rainSize: 0.5,
  rainSpeed: 50,
  rainColor: "#99B3CC",
  rainDensity: 30 // é›¨çš„密度
  rainDensity: 30, // é›¨çš„密度
});
// è®¡ç®—属性
const progressPercentage = computed(
@@ -157,7 +203,7 @@
        baseUrl: `/simu/${serviceInfo}`,
        // baseUrl: `/simu/c2h1dc`,
        interval: intervalMap[playbackRate.value],
        colorRender: isColorRenderEnabled.value
        colorRender: isColorRenderEnabled.value,
      });
      isWaterPrimitiveCreated.value = true;
    } else {
@@ -191,8 +237,8 @@
    return; // é˜»æ­¢åŽç»­é€»è¾‘执行
  }
  if (isWaterPrimitiveCreated.value) {
    console.log('当前是否开启专题渲染:', enabled);
    emit("isColorRender", enabled)
    console.log("当前是否开启专题渲染:", enabled);
    emit("isColorRender", enabled);
    toggleWaterColorRender(enabled);
  }
};
@@ -246,103 +292,112 @@
  // æ³¨æ„ï¼šæœ‰æ—¶ data å¯èƒ½æ˜¯ä¸€ä¸ªå­—符串(例如 JSON å­—符串)
  let data = selectedScheme.value.data;
  // å¦‚果是字符串,则尝试解析成对象
  if (typeof data === 'string') {
  if (typeof data === "string") {
    try {
      data = JSON.parse(data);
      console.log('解析后的降雨数据:', data);
      console.log("解析后的降雨数据:", data);
    } catch (e) {
      console.error("data ä¸æ˜¯æœ‰æ•ˆçš„ JSON å­—符串");
      return;
    }
  }
  // æ‰“印降雨强度的单位
  console.log('降雨强度的单位是:', data.intensityUnit);
  console.log("降雨强度的单位是:", data.intensityUnit);
  // æ ¹æ® intensityUnit è°ƒæ•´ rainfalls ä¸­çš„ intensity å€¼
  if (data.intensityUnit === 'mm/min') {
    data.rainfalls.forEach(r => r.intensity *= 60);
    console.log('将 mm/min è½¬æ¢ä¸º mm/h åŽçš„ rainfalls:', data.rainfalls);
  } else if (data.intensityUnit === 'mm/5min') {
    data.rainfalls.forEach(r => r.intensity *= 12);
    console.log('将 mm/5min è½¬æ¢ä¸º mm/h åŽçš„ rainfalls:', data.rainfalls);
  } else if (data.intensityUnit !== 'mm/h') {
    console.warn('未知的 intensity å•位,无法进行转换');
  if (data.intensityUnit === "mm/min") {
    data.rainfalls.forEach((r) => (r.intensity *= 60));
    console.log("将 mm/min è½¬æ¢ä¸º mm/h åŽçš„ rainfalls:", data.rainfalls);
  } else if (data.intensityUnit === "mm/5min") {
    data.rainfalls.forEach((r) => (r.intensity *= 12));
    console.log("将 mm/5min è½¬æ¢ä¸º mm/h åŽçš„ rainfalls:", data.rainfalls);
  } else if (data.intensityUnit !== "mm/h") {
    console.warn("未知的 intensity å•位,无法进行转换");
  }
  const rainfallList = data.rainfalls;
  console.log('最终的 rainfallList:', rainfallList);
  console.log("最终的 rainfallList:", rainfallList);
  // æå– intensity å€¼
  rainFallValues.value = rainfallList.map(r => r.intensity);
  rainFallValues.value = rainfallList.map((r) => r.intensity);
  minRainValue.value = Math.min(...rainFallValues.value);
  maxRainValue.value = Math.max(...rainFallValues.value);
  console.log('当前方案下最小雨量和最大雨量:', minRainValue.value, maxRainValue.value);
  console.log(
    "当前方案下最小雨量和最大雨量:",
    minRainValue.value,
    maxRainValue.value
  );
}
// å®šä¹‰é™é›¨ç­‰çº§åŠå…¶å¯¹åº”的视觉参数
const rainLevels = [
  {
    name: '小雨',
    name: "小雨",
    min: 0.1,
    max: 9.9,
    size: 0.5,     // é›¨æ»´å¤§å°ï¼šæ›´å°
    speed: 20,     // ä¸‹è½é€Ÿåº¦ï¼šæ›´æ…¢
    density: 15,   // é›¨æ»´å¯†åº¦ï¼šæ›´ç¨€ç–
    color: '#ADD8E6' // æµ…蓝色,象征轻柔的小雨
    size: 0.5, // é›¨æ»´å¤§å°ï¼šæ›´å°
    speed: 20, // ä¸‹è½é€Ÿåº¦ï¼šæ›´æ…¢
    density: 15, // é›¨æ»´å¯†åº¦ï¼šæ›´ç¨€ç–
    color: "#ADD8E6", // æµ…蓝色,象征轻柔的小雨
  },
  {
    name: '中雨',
    name: "中雨",
    min: 10,
    max: 24.9,
    size: 0.7,
    speed: 40,
    density: 35,
    color: '#ADD8E6'
    color: "#ADD8E6",
  },
  {
    name: '大雨',
    name: "大雨",
    min: 25,
    max: 49.9,
    size: 1.0,
    speed: 70,
    density: 60,
    color: '#ADD8E6'
    color: "#ADD8E6",
  },
  {
    name: '暴雨',
    name: "暴雨",
    min: 50,
    max: 99.9,
    size: 1.3,
    speed: 90,
    density: 80,
    color: '#ADD8E6'
    color: "#ADD8E6",
  },
  {
    name: '大暴雨',
    name: "大暴雨",
    min: 100,
    size: 1.6,
    speed: 110,
    density: 100,
    color: '#ADD8E6'
  }
    color: "#ADD8E6",
  },
];
// æ ¹æ®é™é›¨é‡è¿”回对应的雨形配置
function getRainLevel(rainValue) {
  for (let level of rainLevels) {
    if (level.min <= rainValue && (level.max === undefined || rainValue <= level.max)) {
    if (
      level.min <= rainValue &&
      (level.max === undefined || rainValue <= level.max)
    ) {
      return level;
    }
  }
  // é»˜è®¤æ— é›¨çŠ¶æ€
  return { name: '无雨', size: 0.5, speed: 30, density: 20, color: '#F0F8FF' };
  return { name: "无雨", size: 0.5, speed: 30, density: 20, color: "#F0F8FF" };
}
// æ ¹æ®æ’­æ”¾è¿›åº¦æ›´æ–°å¤©æ°”效果(已优化)
let lastUsedIndex = -1; // ç¼“存上一次使用的索引,防止重复更新
let lastRainValue = null;
function updateWeatherByProgress() {
  if (rainFallValues.value.length === 0) return;
  console.log(`时间轴总时长: ${duration.value}, å½“前时间: ${currentTime.value}`); // æ‰“印时间轴信息
  console.log(
    `时间轴总时长: ${duration.value}, å½“前时间: ${currentTime.value}`
  ); // æ‰“印时间轴信息
  const progress = currentTime.value / duration.value;
  const floatIndex = progress * (rainFallValues.value.length - 1);
  const index = Math.floor(floatIndex);            // å½“前索引
  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];
@@ -353,7 +408,7 @@
  // console.log(`正在处理的雨量数据点: å½“前=${currentRain}, ä¸‹ä¸€ä¸ª=${nextRain}, æ’值后=${rainValue.toFixed(2)}, ç´¢å¼•=${index}`);
  // å¦‚果当前索引未变化且插值差异不大,跳过重复更新
  if (index === lastUsedIndex && Math.abs(rainValue - lastRainValue) < 0.1) {
    console.log('由于数据无显著变化,跳过本次更新');
    console.log("由于数据无显著变化,跳过本次更新");
    return;
  }
@@ -363,10 +418,10 @@
  // èŽ·å–å¯¹åº”çš„é›¨å½¢é…ç½®
  const rainLevel = getRainLevel(rainValue);
  if (rainLevel.name === '无雨') {
  if (rainLevel.name === "无雨") {
    // æ— é›¨çŠ¶æ€ï¼šæ¸…é™¤é›¨æ•ˆ
    mapUtils.delRain();
    console.log('执行了无雨状态,清除了雨效');
    console.log("执行了无雨状态,清除了雨效");
    return;
  }
@@ -375,9 +430,9 @@
    rainSize: rainLevel.size,
    rainSpeed: rainLevel.speed,
    rainDensity: rainLevel.density,
    rainColor: rainLevel.color
    rainColor: rainLevel.color,
  };
  console.log('当前雨量数据:', rainValue, '当前雨形:', rainLevel);
  console.log("当前雨量数据:", rainValue, "当前雨形:", rainLevel);
  // è°ƒç”¨å·¥å…·æ–¹æ³•更新雨效
  mapUtils.toggleRain(rainParams, true);
}
@@ -414,7 +469,7 @@
// è®¾ç½®æ’­æ”¾é€Ÿçއ
const setPlaybackRate = (rate) => {
  isColorRenderEnabled.value = false
  isColorRenderEnabled.value = false;
  playbackRate.value = rate;
  showSpeedMenu.value = false;
  // åœæ­¢å½“前播放
@@ -454,7 +509,8 @@
  // ç›´æŽ¥æ‰¾åˆ°æœ€è¿‘çš„ timestamp ç´¢å¼•
  const closestIndex = findClosestTimestampIndex(targetTime);
  const baseTimestamp = waterTimestamps.value[0];
  currentTime.value = (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000;
  currentTime.value =
    (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000;
  // æ›´æ–°æ°´ä½“模拟时间
  setTimeForWaterSimulation(closestIndex);
@@ -486,7 +542,7 @@
  () => selectedScheme.value,
  (newVal) => {
    if (newVal) {
      console.log('选中方案已改变:', newVal)
      console.log("选中方案已改变:", newVal);
    }
  }
);
@@ -499,7 +555,9 @@
        .valueOf(); // ä½¿ç”¨ valueOf() èŽ·å–åŽŸå§‹æ—¶é—´æˆ³
      // æ›´æ–° currentPlayingTime æ ¼å¼åŒ–后的时间字符串
      currentPlayingTime.value = dayjs(sendCurrentPlayingTime.value).format("YYYY-MM-DD HH:mm:ss");
      currentPlayingTime.value = dayjs(sendCurrentPlayingTime.value).format(
        "YYYY-MM-DD HH:mm:ss"
      );
      EventBus.emit("time-update", currentPlayingTime.value);
    }
  }
@@ -534,15 +592,17 @@
    const schemeInfo = selectedScheme.value;
    serviceInfo = schemeInfo.serviceName;
    // console.log('获取到的 serviceName:', serviceInfo);
    getRainfallData()
    getRainfallData();
    // æ ¹æ®layer.json去获取时间轴信息
    const { waterTimestamps: timestamps } = await fetchWaterSimulationData(serviceInfo);
    const { waterTimestamps: timestamps } = await fetchWaterSimulationData(
      serviceInfo
    );
    // çŽ°åœ¨æ˜¯æŒ‰ç…§æ€»å…±æœ‰å¤šå°‘ä¸ªç‚¹æ¥æ¸²æŸ“æ—¶é—´è½´
    if (timestamps) {
      waterTimestamps.value = timestamps;
      updateTimelineRange();
      timeMarkers.value = generateTimeMarkers(timestamps);
      sendCurrentPlayingTime.value = timestamps[0]
      sendCurrentPlayingTime.value = timestamps[0];
      currentPlayingTime.value = dayjs(timestamps[0]).format(
        "YYYY-MM-DD HH:mm:ss"
      );
@@ -574,6 +634,7 @@
const { endSimulate } = inject("simulateActions");
function handleBack() {
  endSimulate();
  EventBus.emit("close-selectArea");
  isWaterPrimitiveCreated.value = false;
  if (ratelevelRef.value) {
    ratelevelRef.value.endCalculation();
src/components/monifangzhen/echartInfo.vue
@@ -107,7 +107,7 @@
import dayjs from "dayjs";
import { useSimStore } from "@/store/simulation";
const simStore = useSimStore();
const { rainFalls } = simStore;
const { rainFalls, intensityUnit } = simStore;
let dataIntervalId = null; // è¡¨æ ¼å®šæ—¶å™¨ ID
const jsonData = ref([]); // JSON æ•°æ®
@@ -226,11 +226,7 @@
  // è§¦å‘事件,将当前行的 ID å‘送到地图组件
  EventBus.emit("row-clicked", row.id);
}
// const listData = cityData.listData;
// const data = ref([
//   8.16, 15.38, 13.94, 9.46, 86.42, 71.32, 28.52, 25.9, 13.74, 14.54, 15.53,
//   9.17, 0, 0.09, 0.86, 8.15, 44.8, 21.86, 6.2, 4.98, 2.82, 2.36, 3.1, 1.06,
// ]);
const rainChangeShow = ref(false);
const tableContainer = ref(null);
@@ -298,8 +294,6 @@
};
const debuffClick = () => {
  // Assuming you have access to parent components in a different way in Vue 3
  // You might need to use provide/inject or props/emits instead
  console.log("Debuff click");
};
@@ -312,61 +306,14 @@
// æ—¶é—´è½´æ—¶é—´æˆªå–处理
const syncTimeWithTimeline = () => {
  // 2025-05-24 00:25
  // // å°†æ—¶é—´å­—符串转换为分钟数 (格式: "YYYY-MM-DD mm:ss")
  const timeParts = nowTime.value.split(" ");
  const timeOnly = timeParts[1]; // èŽ·å– "mm:ss" éƒ¨åˆ†
  return timeOnly;
  if (nowTime.value) {
    const timeParts = nowTime.value.split(" ");
    const timeOnly = timeParts[1]; // èŽ·å– "mm:ss" éƒ¨åˆ†
    console.log(nowTime.value, "nowTime.valuenowTime.value");
    return timeOnly;
  }
};
// æš‚时先不用,主要功能为一分钟插值六十个数据
// function processData(originalData) {
//   const processedData = [];
//   let currentTotal = 0; // åŠ¨æ€ç´¯åŠ çš„ total
//   for (let i = 0; i < originalData.length; i++) {
//     const current = originalData[i];
//     const targetIntensity = current.intensity;
//     let remainingIntensity = targetIntensity; // å‰©ä½™éœ€è¦åˆ†é…çš„ intensity
//     // ç”Ÿæˆ60个点(动态随机填充,允许出现低值和高值)
//     for (let j = 0; j < 60; j++) {
//       // 1. åŠ¨æ€ç”Ÿæˆ intensity(随机,但最后一点补足剩余值)
//       let intensity;
//       if (j === 59) {
//         intensity = remainingIntensity; // æœ€åŽä¸€ç‚¹å¼ºåˆ¶ç”¨å®Œå‰©ä½™å€¼
//       } else {
//         // éšæœºç”Ÿæˆä¸€ä¸ªæ¯”例(0.1~0.5之间的低概率 + å¶å°”高值)
//         const isLowValue = Math.random() < 0.7; // 70%概率生成低值
//         const maxAllowed = remainingIntensity / (60 - j); // ç¡®ä¿ä¸è¶…剩余值
//         intensity = isLowValue
//           ? Math.random() * maxAllowed * 0.3 // ä½Žå€¼èŒƒå›´
//           : Math.random() * maxAllowed * 1.5; // å¶å°”高值
//       }
//       remainingIntensity -= intensity;
//       // 2. å®žæ—¶ç´¯åŠ  total
//       currentTotal += intensity;
//       processedData.push({
//         time: current.time,
//         intensity: intensity,
//         total: currentTotal,
//       });
//     }
//     // éªŒè¯å½“前段的总 intensity æ˜¯å¦åŒ¹é…åŽŸå§‹æ•°æ®
//     console.log(
//       `Segment ${i}: Generated intensity sum = ${(
//         targetIntensity - remainingIntensity
//       ).toFixed(2)}, Original = ${targetIntensity}`
//     );
//   }
//   return processedData;
// }
// è®¾ç½®é™é›¨å›¾è¡¨
const setEcharts1 = () => {
  const chartDom = document.getElementById("echarts1");
  const myChart1 = echarts.init(chartDom);
@@ -392,17 +339,27 @@
  // åŠ è½½JSON数据
  const loadJsonData = async () => {
    try {
      // è¿™ä¸ªresult是用的上述的插值(暂时先不用)
      // const result = processData(simStore.rainFalls);
      const result = simStore.rainFalls;
      if (result?.length) {
        rainfallData.value = result;
        // åˆ¤æ–­ intensityUnit æ˜¯å¦ä¸º mm/15min
        if (rainfallData.value.length > 0) {
          // data1.value = [rainfallData.value[0].intensity];
          // data2.value = [rainfallData.value[0].total];
          // é»˜è®¤åˆå§‹ä»Ž0开始的
          // å¦‚果是 mm/15min,则将所有 intensity * 60
          if (intensityUnit === "mm/15min") {
            rainfallData.value = rainfallData.value.map((item) => ({
              ...item,
              intensity: item.intensity * 60,
            }));
          }
          // åˆå§‹åŒ– data1 å’Œ data2(从 0 å¼€å§‹ï¼‰
          data1.value = [0];
          data2.value = [0];
          // ä½¿ç”¨ç¬¬ä¸€ä¸ªæ•°æ®é¡¹çš„ time ä½œä¸ºåˆå§‹å€¼
          xAxisData.value = [rainfallData.value[0]?.time || "00:00"];
          updateChart();
        }
      }
@@ -416,10 +373,7 @@
    const option = {
      animation: false,
      tooltip: { trigger: "axis" },
      // // è°ƒæ•´grid布局解决Y轴标签显示问题
      grid: {
        // left: "1%", // å·¦ä¾§ç•™æ›´å¤šç©ºé—´
        // right: "1%", // å³ä¾§ç•™æ›´å¤šç©ºé—´
        bottom: "1%",
        containLabel: false,
      },
@@ -427,7 +381,6 @@
        data: ["降雨数据", "累计雨量"],
        textStyle: { color: "#fff" },
        right: "10px",
        // æ·»åŠ legend点击事件处理
        selected: {
          é™é›¨æ•°æ®: true,
          ç´¯è®¡é›¨é‡: true,
@@ -448,7 +401,6 @@
          ...getDynamicYAxis(data1.value),
          axisLabel: { color: "#fff" },
          splitLine: { show: false },
          // ç¡®ä¿åç§°æ˜¾ç¤ºå®Œæ•´
          nameTextStyle: {
            color: "#fff",
          },
@@ -468,13 +420,13 @@
      series: [
        {
          name: "降雨数据",
          type: "bar", // æ˜Žç¡®æŒ‡å®šç±»åž‹
          type: "bar",
          data: data1.value,
          itemStyle: { color: "#3268fe" },
        },
        {
          name: "累计雨量",
          type: "line", // æ˜Žç¡®æŒ‡å®šç±»åž‹
          type: "line",
          yAxisIndex: 1,
          data: data2.value,
          lineStyle: { color: "#ffb637" },
@@ -484,13 +436,13 @@
    myChart1.setOption(option, true);
  };
  // æ•°æ®æ›´æ–°
  // æ•°æ®æ›´æ–° - æ¯æ¬¡æ·»åŠ ä¸€æ¡æ•°æ®
  const updateData = () => {
    if (dataIndex.value < rainfallData.value.length) {
      const item = rainfallData.value[dataIndex.value];
      data1.value.push(item.intensity);
      data2.value.push(item.total);
      xAxisData.value.push(syncTimeWithTimeline());
      xAxisData.value.push(item.time); // âœ… æ”¹ç”¨ item.time
      dataIndex.value++;
      updateChart();
    } else {
@@ -498,28 +450,45 @@
    }
  };
  // æŽ§åˆ¶æ–¹æ³•
  const startUpdating = (interval = 60000) => {
    if (!updateInterval) {
      updateInterval = setInterval(updateData, interval);
    }
  // æŽ§åˆ¶æ–¹æ³•:精确控制动画时间,最后一帧在第 90 ç§’
  const startUpdating = () => {
    if (updateInterval || dataIndex.value >= rainfallData.value.length) return;
    const totalDuration = 90000; // 90秒
    const totalPoints = rainfallData.value.length;
    const startTime = Date.now();
    const animate = (index = 0) => {
      if (index >= totalPoints) {
        stopUpdating();
        return;
      }
      const now = Date.now();
      const expectedTime = (index / (totalPoints - 1)) * totalDuration;
      const delay = Math.max(0, startTime + expectedTime - now);
      updateInterval = setTimeout(() => {
        dataIndex.value = index + 1; // å› ä¸ºæ˜¯ä»Ž 0 å¼€å§‹ push çš„
        updateData();
        animate(index + 1);
      }, delay);
    };
    animate(dataIndex.value);
  };
  const stopUpdating = () => {
    clearInterval(updateInterval);
    clearTimeout(updateInterval);
    updateInterval = null;
  };
  const resetLoading = () => {
    stopUpdating();
    dataIndex.value = 0;
    data1.value = [];
    data2.value = [];
    xAxisData.value = ["00:00"];
    if (rainfallData.value.length) {
      data1.value = [rainfallData.value[0].intensity];
      data2.value = [rainfallData.value[0].total];
    }
    data1.value = [0];
    data2.value = [0];
    xAxisData.value = [rainfallData.value[0]?.time || "00:00"];
    updateChart();
  };
src/components/monifangzhen/schemeCard.vue
@@ -113,10 +113,22 @@
    simStore.setSelectedScheme(item);
    console.log("有服务名称");
  }
  const flyHeight = ref(100000);
  const shouldShowFill = false;
  // æ±‚解器求解完成之后才可以显示时间轴
  if (item.status == 10) {
    initeWaterPrimitiveView();
    // åªæœ‰è¡Œæ”¿åŒºåˆ’执行
    if (item.areaType == 1) {
      flyHeight.value = 100000;
      EventBus.emit("select-geom", {
        geom: item.geom,
        flyHeight: flyHeight.value,
        shouldShowFill: shouldShowFill,
      });
    } else {
      // å­™èƒ¡æ²ŸåŒºåŸŸè·³è½¬è§†è§’
      initeWaterPrimitiveView();
    }
    currentScheme.value = item;
    schemeInfoShow.value = true;
    emit("closeBtn", false);
src/components/tools/Message copy.vue
ÎļþÒÑɾ³ý
src/store/simAPI.js
@@ -76,10 +76,11 @@
                    mode: forms.mode,
                    gauges: forms.gauges,
                    rainfalls: forms.rainFallList,
                    intensityUnit: forms.intensityUnit
                    // intensityUnit: forms.intensityUnit
                    intensityUnit: forms.intensityUnit || 'mm/15min'
                })
            }
            console.log(params)
            console.log(params, '保存方案参数')
            const res = await createSimData(params)
            ElMessage.success('方案保存成功')
            return res
@@ -104,8 +105,9 @@
                confirmButtonText: '确定',
                cancelButtonText: '取消',
            })
            // ç”¨æˆ·ç¡®è®¤åŽæ‰§è¡Œä¿å­˜
            await saveScheme(forms)
            // ç”¨æˆ·ç¡®è®¤åŽæ‰§è¡Œä¿å­˜ï¼Œå¹¶è¿”回结果
            const res = await saveScheme(forms); // æ‰§è¡Œä¿å­˜å¹¶æŽ¥æ”¶ç»“æžœ
            return res; // è¿”回保存的结果
        } catch (error) {
            if (error !== 'cancel') {
                console.error('保存出错:', error)
src/store/simulation.js
@@ -31,10 +31,12 @@
    const backToHome = ref(false)
    const selectedScheme = ref(null)
    const rainFalls = ref()
    const intensityUnit = ref()
    const setSelectedScheme = (scheme) => {
        selectedScheme.value = scheme
        rainFalls.value = JSON.parse(scheme.data).rainfalls
        console.log(rainFalls.value, 'shceme')
        intensityUnit.value = JSON.parse(scheme.data).intensityUnit
        console.log(intensityUnit.value, 'shceme')
    }
    const clearSelectedScheme = () => {
        selectedScheme.value = null
@@ -148,6 +150,7 @@
        schemCard,
        backToHome,
        rainFalls,
        intensityUnit,
        DangerPoint,
        DeviceShowSwitch,
        DangerShowSwitch,
src/utils/tools.js
@@ -170,7 +170,6 @@
  CreateLabel(pic, show) {
    if (show) {
      earthCtrl.factory.createSimpleGraphic(pic, {}, function (entity) {
        console.log(entity.polyline.positions.getValue(), "entity");
        window.Viewer = earthCtrl.viewer;
        //开启编辑并启用属性弹窗
        earthCtrl.factory.SimpleGraphic.edit(true, {
@@ -300,7 +299,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => {}
      (e) => { }
    );
  },
  qxcl() {
@@ -310,7 +309,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => {}
      (e) => { }
    );
  },
  fwjcl() {
@@ -320,7 +319,7 @@
        polyline: Cesium.Color.fromCssColorString("#ffff0050"),
        polygon: Cesium.Color.fromCssColorString("#ffff0050"),
      },
      (e) => {}
      (e) => { }
    );
  },
  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>场景截图<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@@ -930,7 +929,7 @@
    };
    this.analysisFlood = earthCtrl.analysis.createSubmergence(
      method,
      (value) => {}
      (value) => { }
    );
  },
  clearFlood() {
src/views/GisView.vue
@@ -27,7 +27,7 @@
  // 1. è®¾ç½®åˆå§‹æ—¶é—´
  const date = new Date(2025, 3, 11, 12, 0, 0, 0);
  const julianDate = SmartEarth.Cesium.JulianDate.fromDate(date);
  const julianDate = SmartEarth.Cesium.JulianDate.fromDate(date);
  // earthCtrl.viewer.clock.currentTime = julianDate;
  // 2. é…ç½®æ—¶é’Ÿé€‰é¡¹ï¼Œç¦æ­¢è‡ªåŠ¨æŽ¨è¿›æ—¶é—´
@@ -58,10 +58,13 @@
const MULTIPOLYGON_COORDS = ref([]);
let previousEntities = []; // ç”¨äºŽå­˜å‚¨ä¹‹å‰åˆ›å»ºçš„实体
const flyToHeight = ref(null);
const ShowFill = ref(true);
// ç›‘听新建方案选择的区域范围
EventBus.on("select-geom", ({ geom, flyHeight }) => {
EventBus.on("select-geom", ({ geom, flyHeight, shouldShowFill }) => {
  flyToHeight.value = flyHeight;
  ShowFill.value = shouldShowFill;
  console.log(ShowFill.value, "ShowFill.valueShowFill.value");
  const coordsStr = geom
    .replace("MULTIPOLYGON(((", "") // åŽ»æŽ‰å¼€å¤´
    .replace(")))", ""); // åŽ»æŽ‰ç»“å°¾
@@ -87,7 +90,7 @@
  // æ¸…除之前的所有实体
  clearPreviousEntities();
  // é€‰ä¸­åŒºåŸŸæ ‡è‰²
  addCustomPolygon();
  addCustomPolygon(ShowFill.value);
});
// æ¸…除之前的所有实体
@@ -127,25 +130,27 @@
  };
}
function addCustomPolygon() {
function addCustomPolygon(ShowFill = true) {
  // å°† MULTIPOLYGON_COORDS.value è½¬æ¢ä¸º GeoJSON æ ¼å¼
  const geoJson = convertToGeoJson(MULTIPOLYGON_COORDS.value);
  const center = geoJson.properties.center;
  // åˆ›å»ºå¤šè¾¹å½¢å®žä½“
  // åˆ›å»ºå¤šè¾¹å½¢å®žä½“,并根据 ShowFill å‚数决定是否显示填充颜色
  const polygonEntity = viewer.entities.add({
    // name: "自定义区域",
    polygon: {
      hierarchy: Cesium.Cartesian3.fromDegreesArray(
        geoJson.geometry.coordinates[0][0].flat()
      ),
      material: Cesium.Color.RED.withAlpha(0.3), // åŠé€æ˜Žçº¢è‰²å¡«å……
      material: ShowFill
        ? Cesium.Color.RED.withAlpha(0.3) // åŠé€æ˜Žçº¢è‰²å¡«å……
        : new Cesium.ColorMaterialProperty(Cesium.Color.TRANSPARENT), // å¦‚果不需要填充,则使用透明材质
      outline: true,
      outlineColor: Cesium.Color.RED, // çº¢è‰²è¾¹æ¡†
      outlineWidth: 5,
      clampToGround: true, // è´´åœ°æ˜¾ç¤º
    },
  });
  previousEntities.push(polygonEntity);
  // é£žå‘中心点
@@ -154,14 +159,13 @@
      center.lon,
      center.lat,
      flyToHeight.value
    ), // æé«˜åˆ° 100000米高度
    ), // æé«˜åˆ°æŒ‡å®šé«˜åº¦
    orientation: {
      heading: Cesium.Math.toRadians(0), // æ­£åŒ—方向
      pitch: Cesium.Math.toRadians(-90), // å‘下倾斜90度(垂直俯视)
      roll: 0.0,
    },
  });
}
EventBus.on("close-selectArea", () => {
@@ -469,7 +473,7 @@
}
// // ä¿®æ”¹æŒ‡å—针位置
/deep/ .compass {
    right: 128px !important;
    top: 112px;
  right: 128px !important;
  top: 112px;
}
</style>
src/views/left/CitySim.vue
@@ -378,10 +378,6 @@
  console.log(intensityColumn, "intensityColumnintensityColumnintensityColumn");
  // 3. æå–第二列的单位(如 "(mm/h)" â†’ "mm/h")
  const intensityUnit = extractUnitFromHeader(intensityColumn);
  console.log(
    intensityUnit,
    "intensityUnitintensityUnitintensityUnitintensityUnit"
  );
  forms.intensityUnit = intensityUnit; // å­˜å‚¨å•位(可选)
  // 4. å¦‚果校验通过,继续处理数据
@@ -499,7 +495,7 @@
    });
  } catch (error) {
    console.error("启动模拟过程中发生错误:", error);
    ElMessage.error("启动模拟失败,请稍后再试");
    // ElMessage.error("启动模拟失败,请稍后再试");
  }
}
</script>