guonan
2025-07-03 ca74058a77d7c9000a485502a2b53fbef5807ef5
历史回放
已修改6个文件
510 ■■■■ 文件已修改
src/api/trApi.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/TimeLine.vue 238 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monifangzhen/schemeCard.vue 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/simulation.js 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/left/CitySim.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/left/KGSimOption/RealTimeSimulation.vue 134 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/trApi.js
@@ -81,6 +81,28 @@
    throw error;
  }
}
// 实时模拟的结果
export async function getSimresult(ids) {
  try {
    const res = await instance.get(`/simu/results?id=${ids}`);
    return res.data;
  } catch (error) {
    console.error("Error deleting simulation data:", error);
    throw error;
  }
}
// 结束实时模拟
export async function stopSim(ids) {
  try {
    const res = await instance.get(`/simu/stop?id=${ids}`);
    return res.data;
  } catch (error) {
    console.error("Error deleting simulation data:", error);
    throw error;
  }
}
// **************************************************************************************************************
// 解析json获取泥石流参数
export function parseWaterSimulationData(jsonData) {
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" v-show="speedShow">
        <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,19 +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" />
          <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>
@@ -46,8 +70,12 @@
          <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
            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>
@@ -56,27 +84,38 @@
    </div>
    <div>
      <div style="display: flex">
        <ratelevel ref="ratelevelRef" :playing-time="sendCurrentPlayingTime"
          @finish-calculation="handleFinishCalculation" style="
        <ratelevel
          ref="ratelevelRef"
          :playing-time="sendCurrentPlayingTime"
          @finish-calculation="handleFinishCalculation"
          style="
            margin-top: 12px;
            margin-left: 28px;
            margin-right: 10px;
            justify-content: flex-end;
          " />
        <crossanalysis ref="crossRef" style="
          "
        />
        <crossanalysis
          ref="crossRef"
          style="
            margin-top: 12px;
            margin-left: 16px;
            margin-right: 20px;
            justify-content: flex-end;
          " />
          "
        />
      </div>
      <el-button @click="handleBack" style="
      <el-button
        @click="handleBack"
        style="
          margin-top: 3px;
          margin-left: 28px;
          margin-right: 10px;
          width: 75%;
          height: 30%;
        ">结束模拟</el-button>
        "
        >结束模拟</el-button
      >
    </div>
  </div>
</template>
@@ -107,9 +146,9 @@
  updateWaterColor,
} from "@/utils/water";
import mapUtils from "@/utils/tools.js";
import { fetchWaterSimulationData } from "@/api/trApi.js";
import { fetchWaterSimulationData, stopSim } from "@/api/trApi.js";
import { EventBus } from "@/eventBus";
import { ElMessage } from "element-plus";
import { ElMessage, ElMessageBox } from "element-plus";
// 状态管理器
import { useSimStore } from "@/store/simulation";
import { storeToRefs } from "pinia";
@@ -278,7 +317,8 @@
const startPlayback = () => {
  clearInterval(playInterval);
  if (selectedScheme.value.type === 2) {
  // 新建方案中的实时模拟不能倍速
  if (selectedScheme.value.type === 2 && simStore.rePlayList.length == 0) {
    // 类型为 2:每 5 秒跳动一次
    playInterval = setInterval(() => {
      const fiveSeconds = 5;
@@ -541,9 +581,9 @@
// 全局状态记录
const colorState = {
  currentColor: "#F5F0E6", // 当前颜色
  currentAlpha: -0.3,      // 当前透明度
  colorStages: null,       // 预计算的颜色阶段时间点
  maxColorTime: null       // 记录达到最深颜色时的时间点
  currentAlpha: -0.3, // 当前透明度
  colorStages: null, // 预计算的颜色阶段时间点
  maxColorTime: null, // 记录达到最深颜色时的时间点
};
// 预计算颜色阶段时间点
@@ -556,17 +596,17 @@
    { hex: "#D4B483", luminance: 184.0 }, // stage 2
    { hex: "#B78B6A", luminance: 148.4 }, // stage 3
    { hex: "#8B5A3A", luminance: 101.0 }, // stage 4
    { hex: "#744C33", luminance: 84.5 },  // stage 5
    { hex: "#5D3D2C", luminance: 68.1 }   // stage 6
    { hex: "#744C33", luminance: 84.5 }, // stage 5
    { hex: "#5D3D2C", luminance: 68.1 }, // stage 6
  ];
  const alphaStops = [
    -0.2,   // stage 0
    -0.3,   // stage 1
    -0.4,   // stage 2
    -0.5,   // stage 3
    -0.6,   // stage 4
    -0.7,   // stage 5
    -0.8    // stage 6
    -0.2, // stage 0
    -0.3, // stage 1
    -0.4, // stage 2
    -0.5, // stage 3
    -0.6, // stage 4
    -0.7, // stage 5
    -0.8, // stage 6
  ];
  // 累计降雨量阈值(mm)
  const R_THRESHOLDS = [0, 200, 240, 280, 310, 350]; // 共6个阶段对应6个阈值
@@ -579,7 +619,7 @@
    const total = rainTotalInfo.value[i].total; // 使用 total 替代 intensity
    timeTotals.push({
      time,
      total
      total,
    });
  }
@@ -594,7 +634,7 @@
          startTime: time,
          color: COLOR_STOPS[stage].hex,
          alpha: alphaStops[stage],
          threshold
          threshold,
        };
        break;
      }
@@ -606,7 +646,7 @@
    startTime: 0,
    color: COLOR_STOPS[0].hex,
    alpha: alphaStops[0],
    threshold: 0
    threshold: 0,
  };
  colorState.colorStages = stages;
@@ -623,7 +663,10 @@
  // 查找当前时间点所属的阶段
  let currentStage = 0;
  for (let i = colorState.colorStages.length - 1; i >= 0; i--) {
    if (colorState.colorStages[i] && currentTime.value >= colorState.colorStages[i].startTime) {
    if (
      colorState.colorStages[i] &&
      currentTime.value >= colorState.colorStages[i].startTime
    ) {
      currentStage = i;
      break;
    }
@@ -631,15 +674,21 @@
  // 记录达到最深颜色的时间点
  if (currentStage >= colorState.colorStages.length - 1) {
    if (colorState.maxColorTime === null || currentTime.value > colorState.maxColorTime) {
    if (
      colorState.maxColorTime === null ||
      currentTime.value > colorState.maxColorTime
    ) {
      colorState.maxColorTime = currentTime.value;
    }
  }
  // 判断是否需要强制更新颜色
  const isTimeGoingBackward = currentTime.value < colorState.lastTime;
  const isBeforeMaxColorTime = colorState.maxColorTime !== null && currentTime.value <= colorState.maxColorTime;
  const shouldForceUpdate = isForceUpdate && (isTimeGoingBackward || isBeforeMaxColorTime);
  const isBeforeMaxColorTime =
    colorState.maxColorTime !== null &&
    currentTime.value <= colorState.maxColorTime;
  const shouldForceUpdate =
    isForceUpdate && (isTimeGoingBackward || isBeforeMaxColorTime);
  // 更新颜色逻辑
  if (shouldForceUpdate || isTimeGoingBackward) {
@@ -652,7 +701,9 @@
    const newAlpha = colorState.colorStages[currentStage].alpha;
    // 只应用更暗的颜色和更低的透明度
    if (calculateLuminance(newColor) < calculateLuminance(colorState.currentColor)) {
    if (
      calculateLuminance(newColor) < calculateLuminance(colorState.currentColor)
    ) {
      colorState.currentColor = newColor;
    }
    if (newAlpha < colorState.currentAlpha) {
@@ -717,7 +768,8 @@
  // 判断是否需要强制更新颜色
  const isGoingBackward = newTime < currentTime.value;
  const isBeforeMaxColor = colorState.maxColorTime !== null && newTime <= colorState.maxColorTime;
  const isBeforeMaxColor =
    colorState.maxColorTime !== null && newTime <= colorState.maxColorTime;
  const shouldForceUpdate = isGoingBackward || isBeforeMaxColor;
  currentTime.value = newTime;
@@ -910,16 +962,25 @@
);
const jsonFetch = ref(null);
const currentReplayIndex = ref(0); // 当前播放的rePlayList索引
// 提取为独立函数
async function initializeSimulationData(force = false) {
async function initializeSimulationData(replayItem = null) {
  try {
    const schemeInfo = selectedScheme.value;
    serviceInfo = schemeInfo.serviceName;
    if (schemeInfo.type == 2) {
      speedShow.value = false;
      jsonFetch.value = layerDate.value;
      if (
        replayItem ||
        (simStore.rePlayList && simStore.rePlayList.length != 0)
      ) {
        jsonFetch.value =
          replayItem || simStore.rePlayList[currentReplayIndex.value];
        speedShow.value = true;
      } else {
        jsonFetch.value = layerDate.value;
        speedShow.value = false;
      }
    } else {
      getRainfallData();
      speedShow.value = true;
@@ -962,11 +1023,36 @@
  }
}
// 挂载时调用
onMounted(async () => {
  // 因为这个函数实时模拟监听也需要使用,所以封装了一个函数
  await initializeSimulationData();
});
// 播放完成后的回调
function handlePlayFinished() {
  if (selectedScheme.value.type !== 2) return;
  finishPlay.value = false;
  currentReplayIndex.value++;
  if (currentReplayIndex.value < simStore.rePlayList.length) {
    console.log(currentReplayIndex.value);
    // 自动播放下一个
    initializeSimulationData(simStore.rePlayList[currentReplayIndex.value]);
    togglePlay();
    shouldAutoPlay.value = false;
  } else {
    // 所有项目播放完成
    currentReplayIndex.value = 0; // 重置索引
    isPlaying.value = false; // 停止播放
  }
}
// 监听播放完成事件
watch(
  () => finishPlay.value,
  (newVal) => {
    if (newVal && selectedScheme.value.type === 2) {
      handlePlayFinished();
    }
  }
);
const shouldAutoPlay = ref(false);
// 监听 layerDate 变化后标记准备播放
watch(
@@ -986,6 +1072,13 @@
    shouldAutoPlay.value = false;
  }
});
// 挂载时调用
onMounted(async () => {
  // 因为这个函数实时模拟监听也需要使用,所以封装了一个函数
  await initializeSimulationData();
});
// 根据返回数据的个数去渲染时间轴
function updateTimelineRange() {
  if (waterTimestamps.value.length > 0) {
@@ -1002,28 +1095,63 @@
});
const { endSimulate } = inject("simulateActions");
function handleBack() {
  endSimulate();
  // 停止实时模拟定时器
  EventBus.emit("close-time");
async function handleBack() {
  // 实时模拟弹窗确认是返回方案列表还是停止模拟
  if (selectedScheme.value.type === 2) {
    try {
      await ElMessageBox.confirm("方案未停止时结束模拟后,后台将停止计算", {
        confirmButtonText: "返回列表",
        cancelButtonText: "结束模拟",
        type: "warning",
      });
      // 用户点击了确认,这里不执行任何操作,仅关闭对话框
    } catch (error) {
      stopSim(selectedScheme.value.id).then((res) => {
        if (res.code == 404) {
          ElMessage.warning("该服务已停止");
        } else {
          ElMessage.success("服务正在停止中");
        }
      });
      // return;
    }
  }
  // 不管type是不是2,最终都执行结束模拟的操作
  endSimulation();
}
async function endSimulation() {
  EventBus.emit("close-time");
  endSimulate();
  isWaterPrimitiveCreated.value = false;
  // 结束计算和停止拾取
  if (ratelevelRef.value) {
    ratelevelRef.value.endCalculation();
    ratelevelRef.value.stopPicking();
  }
  // 清除点
  if (crossRef.value) {
    crossRef.value.clearPoints();
    console.log("执行删除点功能");
  }
  emit("isColorRender", false);
  // 延迟删除雨量图层
  setTimeout(() => {
    mapUtils.delRain();
  }, 3000);
  destoryWaterPrimitive();
  // 发送事件隐藏相关信息
  EventBus.emit("hide-schemeInfo");
  EventBus.emit("clear-water-depth");
  EventBus.emit("clear-water-velocity");
  ElMessage({ message: "模拟进程正在关闭中...", type: "success" });
}
</script>
src/components/monifangzhen/schemeCard.vue
@@ -29,6 +29,9 @@
            @click="startPlay(item)"
            >进入模拟</el-button
          >
          <el-button size="small" v-show="item.type == 2" @click="rePlay(item)"
            >历史回放</el-button
          >
          <!--  :disabled="item.status !== 2" -->
        </div>
      </div>
@@ -50,7 +53,15 @@
<script setup>
import { EventBus } from "@/eventBus"; // 引入事件总线
import { onMounted, ref, watch, defineEmits, onUnmounted } from "vue";
import {
  nextTick,
  onMounted,
  ref,
  watch,
  defineEmits,
  onUnmounted,
  inject,
} from "vue";
import dayjs from "dayjs";
import { initeWaterPrimitiveView } from "@/utils/water";
import Message from "@/components/tools/Message.vue";
@@ -61,11 +72,11 @@
import { ElMessage, ElMessageBox } from "element-plus";
const emit = defineEmits(["start", "end", "reset", "closeBtn"]);
import {
  getRegionData,
  getSimData,
  deleteSimData,
  getSimStart,
  getSimDataById,
  getSimresult,
} from "@/api/trApi.js";
const simStore = useSimStore();
@@ -101,8 +112,9 @@
// 实时模拟五分钟请求一次的定时器
const realTimeSimInterval = ref(null);
const { startSimulate, endSimulate } = inject("simulateActions");
async function startPlay(item) {
  console.log(item, "item");
  if (item.status === 2) {
    ElMessage.warning("当前方案正在分析中,无法进入模拟!");
    return;
@@ -131,7 +143,7 @@
    currentScheme.value = item;
    schemeInfoShow.value = true;
    emit("closeBtn", false);
    emit("start");
    startSimulate();
    return;
  }
@@ -151,47 +163,35 @@
    return;
  }
  // 处理 type == 2 的情况(实时模拟)
  if (item.type === 2) {
    // 清除已有定时器,防止重复启动
    if (realTimeSimInterval.value) {
      clearInterval(realTimeSimInterval.value);
    }
    // 即刻执行一次
    await executeRealTimeSimulation(item);
    // 每隔 5 分钟执行一次
    realTimeSimInterval.value = setInterval(() => {
      executeRealTimeSimulation(item);
    }, 5 * 60 * 1000); // 5分钟
    return;
  }
  // 默认情况:有服务名称
  simStore.setSelectedScheme(item);
}
// 封装实时模拟的异步操作
async function executeRealTimeSimulation(item) {
  try {
    const ress = await getSimStart(item.id);
    const res = await getSimDataById(item.id);
    item.serviceName = res.data[0]?.serviceName || null;
    simStore.setSelectedScheme(item);
    getScheme();
    if (ress.code === 200) {
      simStore.layerDate = ress.data;
      initeWaterPrimitiveView();
      emit("start");
    }
  } catch (e) {
    console.error("实时模拟获取模拟数据失败:", e);
  }
// 实时模拟历史回放
function rePlay(item) {
  // 当前选中的方案
  simStore.setSelectedScheme(item);
  // 拿id去请求results接口,如果长度不为0,则可以进行历史回放
  getSimresult(item.id)
    .then((res) => {
      if (res.code == 500) {
        // 如果长度为0,提示用户并且不进行后续操作
        ElMessage.warning("提示:没有可回放的数据!");
        return; // 阻止后续操作
      } else {
        simStore.rePlayList = res.data;
        console.log(simStore.rePlayList, "lisi");
      }
      // 使用 nextTick 确保 DOM 更新后再执行后续操作
      nextTick(() => {
        initeWaterPrimitiveView();
        startSimulate();
      });
    })
    .catch((error) => {
      console.log("请求失败:", error);
      // 错误处理
    });
}
function handleBack(value) {
@@ -221,10 +221,10 @@
        item.result == "创建仿真" ||
        item.result == "完成" ||
        item.result == "-1" ||
        item.result == null
        item.result == "停止" ||
        item.result == "进行中"
    );
    simAPIStore.shouldPoll = !shouldStop; // 修改 Pinia 状态
    console.log(shouldStop, "aaaaaaaaaaaaaaaa");
    // 3. 如果需要停止
    if (shouldStop) {
      if (intervalId) {
src/store/simulation.js
@@ -2,6 +2,8 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useSimStore = defineStore('simulation', () => {
    // 历史回放列表
    const rePlayList = ref([])
    // 北京市所有村的code
    const townCodeAll = ref([])
    // 实时模拟最新的layer
@@ -47,10 +49,22 @@
    // 降雨单位
    const intensityUnit = ref()
    const setSelectedScheme = (scheme) => {
        selectedScheme.value = scheme
        rainFalls.value = JSON.parse(scheme.data).rainfalls
        intensityUnit.value = JSON.parse(scheme.data).intensityUnit
    }
        selectedScheme.value = scheme;
        try {
            const parsedData = JSON.parse(scheme.data);
            // 只有当 rainfalls 和 intensityUnit 存在且非空时才赋值
            if (parsedData.rainfalls && parsedData.intensityUnit) {
                rainFalls.value = parsedData.rainfalls;
                intensityUnit.value = parsedData.intensityUnit;
            } else {
                console.warn("缺少必要的 rainfalls 或 intensityUnit 字段");
            }
        } catch (error) {
            console.error("解析 scheme.data 出错", error);
        }
    };
    const clearSelectedScheme = () => {
        selectedScheme.value = null
    }
@@ -200,6 +214,7 @@
        devices,
        frameNum,
        layerDate,
        rePlayList,
        // 方案相关方法
        setSchemCard,
src/views/left/CitySim.vue
@@ -495,7 +495,9 @@
      : undefined,
  }));
  console.log(rawRainFallList, "原始降雨数据");
  // 更新 forms.rainFallList,可用于图表显示等用途
  forms.rainFallList = rawRainFallList;
  // 判断是否为整小时数据(即相邻时间间隔是否为整小时)
  const isHourlyData = checkIfHourlyData(rawRainFallList);
@@ -513,9 +515,6 @@
      intensity: item.intensity,
    }));
  }
  // 更新 forms.rainFallList,可用于图表显示等用途
  forms.rainFallList = rawRainFallList;
  // 计算起始时间和结束时间(毫秒数)
  const firstTime = parseDateTime(hourlyRainfallList[0]?.time);
src/views/left/KGSimOption/RealTimeSimulation.vue
@@ -81,7 +81,8 @@
import { useSimStore } from "@/store/simulation.js";
import { EventBus } from "@/eventBus"; // 引入事件总线
import { getDeviceInfoSHG, getYLJData } from "@/api/hpApi";
import { getSimStart, getSimDataById } from "@/api/trApi";
import { getSimStart, getSimDataById, getSimresult } from "@/api/trApi";
import { ControlSchemeType } from "@/assets/js/lib-pixelstreamingfrontend.esm";
// 获取 Store 实例
const simAPIStore = SimAPIStore();
@@ -219,6 +220,8 @@
// 实时模拟定时器
let pollingInterval = null;
// 用于记录上次数据条数
let lastDataLength = 0;
async function startPlay() {
  // 开始模拟前需要先保存方案
@@ -246,30 +249,27 @@
  });
  try {
    // 调用求解器并初始化模拟
    const resStart = await getSimStart(schemeId);
    // 启动模拟
    await getSimStart(schemeId);
    // 请求完成后关闭加载提示
    loadingMessage.close();
    if (resStart.code === 200) {
      const res = await getSimDataById(schemeId);
      simStore.setSelectedScheme(res.data[0]);
      simStore.layerDate = resStart.data;
      initeWaterPrimitiveView();
    // 首次请求延迟 90s
    setTimeout(async () => {
      try {
        startSimulate(); // 这里可能会报错
      } catch (error) {
        console.error("调用 startSimulate 出错:", error);
      }
        const res = await getSimresult(schemeId);
        console.log(res.data, "实时模拟 - 初始结果");
      // 开始轮询任务:每 5 分钟调用一次 getSimStart 并更新方案数据
      startPolling(schemeId);
    } else {
      ElMessage.error(resStart.message || "调用求解器失败");
    }
        if (res.data.length > 0) {
          handleNewData(res.data, schemeId);
        }
        // 显示结果并开始轮询
        loadingMessage.close();
        startPolling(schemeId);
      } catch (error) {
        console.error("首次请求模拟结果失败", error);
        loadingMessage.close();
      }
    }, 3 * 60 * 1000); // 1.5 分钟后第一次请求
  } catch (error) {
    loadingMessage.close();
    ElMessage.error("请求失败:" + (error.message || "未知错误"));
@@ -277,27 +277,85 @@
  }
}
// 启动轮询函数
// 定时五分钟请求
function startPolling(schemeId) {
  stopPolling(); // 避免重复启动
  stopPolling(); // 确保不会重复启动
  pollingInterval = setInterval(async () => {
    try {
      const resStart = await getSimStart(schemeId);
      const res = await getSimresult(schemeId);
      if (resStart.code === 200) {
        const res = await getSimDataById(schemeId);
        simStore.setSelectedScheme(res.data[0]); // 更新方案数据
        simStore.layerDate = resStart.data; // 更新 layer 数据
      if (res.data && res.data.length > 0) {
        if (res.data.length === lastDataLength) {
          console.log("主轮询:无新数据,切换为 10 秒高频轮询");
        console.log("轮询获取最新数据成功");
      } else {
        console.warn("轮询请求失败:", resStart.message);
          clearInterval(pollingInterval);
          pollingInterval = null;
          startFastPolling(schemeId); // 启动高频轮询
        } else {
          handleNewData(res.data, schemeId);
        }
      }
    } catch (error) {
      console.error("轮询请求异常:", error);
      console.error("轮询获取模拟结果失败", error);
    }
  }, 5 * 60 * 1000); // 每 5 分钟执行一次
  }, 5.6 * 60 * 1000); // 每 5.5 分钟执行一次
}
let fastPollingInterval = null;
// 如果五分钟没拿到最新的数据,则开启十秒钟调用一次,拿到最新的数据就停止
function startFastPolling(schemeId) {
  fastPollingInterval = setInterval(async () => {
    try {
      const res = await getSimresult(schemeId);
      if (res.data && res.data.length > 0) {
        if (res.data.length !== lastDataLength) {
          console.log("高频轮询:检测到新数据,恢复主轮询");
          clearInterval(fastPollingInterval);
          fastPollingInterval = null;
          handleNewData(res.data, schemeId);
          startPolling(schemeId); // 重新启动主轮询
        }
      }
    } catch (error) {
      console.error("高频轮询获取模拟结果失败", error);
    }
  }, 10 * 1000); // 每 10 秒执行一次
}
// 拿取最新的layer.json存储到pinia中
async function handleNewData(dataArray, schemeId) {
  // 拿服务名称
  const res = await getSimDataById(schemeId);
  simStore.setSelectedScheme(res.data[0]); // 更新方案数据
  const latestItem = dataArray[dataArray.length - 1];
  const currentLength = dataArray.length;
  if (currentLength <= lastDataLength) {
    console.log("本轮无新数据(长度未变化)");
    return;
  }
  // 更新标识
  lastDataLength = currentLength;
  // 执行更新逻辑
  console.log("检测到新数据,更新中...");
  console.log(latestItem, "last");
  simStore.layerDate = latestItem;
  initeWaterPrimitiveView();
  try {
    startSimulate();
  } catch (error) {
    console.error("调用 startSimulate 出错:", error);
  }
}
// 停止轮询函数
@@ -305,8 +363,14 @@
  if (pollingInterval) {
    clearInterval(pollingInterval);
    pollingInterval = null;
    console.log("轮询已停止");
  }
  if (fastPollingInterval) {
    clearInterval(fastPollingInterval);
    fastPollingInterval = null;
  }
  console.log("轮询已停止");
}
EventBus.on("close-time", () => {