From a57caa72a54efe9de3fe26a6c36d3e8038267377 Mon Sep 17 00:00:00 2001
From: guonan <guonan201020@163.com>
Date: 星期四, 17 七月 2025 09:09:49 +0800
Subject: [PATCH] 修改x按钮

---
 src/components/menu/TimeLine.vue |  789 ++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 560 insertions(+), 229 deletions(-)

diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue
index e18acb9..6951358 100644
--- a/src/components/menu/TimeLine.vue
+++ b/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>
@@ -91,6 +130,7 @@
   onBeforeUnmount,
   inject,
   reactive,
+  watchEffect,
 } from "vue";
 import ratelevel from "@/components/menu/flowRate_waterLevel.vue";
 import crossanalysis from "@/components/menu/CrossSectionalAnalysis.vue";
@@ -106,14 +146,16 @@
   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";
 const simStore = useSimStore();
-const { selectedScheme, frameNum, layerDate } = storeToRefs(simStore);
+const { selectedScheme, frameNum, layerDate, schemWaterInfo } =
+  storeToRefs(simStore);
+import { clearAllPoints } from "@/utils/map";
 
 const emit = defineEmits([
   "timeUpdate",
@@ -162,9 +204,6 @@
 });
 let minFlowRate = ref();
 let maxFlowRate = ref();
-// 鍏ㄥ眬鍙橀噺璁板綍鏈�澶ч樁娈靛拰閫忔槑搴�
-let maxStage = 0;
-let maxAlpha = -0.3; // 鍒濆閫忔槑搴﹀搴攕tage 0
 // 璁$畻灞炴��
 const progressPercentage = computed(
   () => (currentTime.value / duration.value) * 100
@@ -174,6 +213,9 @@
     new Set(waterTimestamps.value.map((ts) => dayjs(ts).format("YYYY-MM-DD")))
   ).map((date) => dayjs(date).toDate())
 );
+
+// 鎴戦渶瑕佸姞涓�涓垽鏂�
+const finishPlay = ref(false);
 // 鎾斁鎺у埗
 const togglePlay = () => {
   // 杩欓噷搴旇鍐嶈瀹氬嚑涓檺鍒讹紝濡傛灉缂哄皯浠�涔堟暟鎹紝鏃犳硶杩涜浠跨湡
@@ -241,43 +283,118 @@
   8: 125, // 8鍊嶉��
 };
 // 鎾斁閫昏緫
+// const startPlayback = () => {
+//   clearInterval(playInterval);
+
+//   playInterval = setInterval(() => {
+//     // 鎵惧埌褰撳墠鏃堕棿瀵瑰簲鐨勭储寮�
+//     const currentIndex = findClosestTimestampIndex(currentTime.value);
+//     const nextIndex = currentIndex + 1;
+
+//     // 濡傛灉宸茬粡鏄渶鍚庝竴涓椂闂寸偣锛屽仠姝㈡挱鏀�
+//     if (nextIndex >= waterTimestamps.value.length) {
+//       currentTime.value = duration.value;
+//       stopPlayback();
+//       isPlaying.value = false;
+//       emit("isPlaying", false);
+//       emit("playbackFinished", true);
+//       return;
+//     }
+
+//     // 鏇存柊鏃堕棿涓轰笅涓�涓椂闂寸偣鐨勬椂闂村樊锛堢锛�
+//     const nextTimestamp = waterTimestamps.value[nextIndex];
+//     const baseTimestamp = waterTimestamps.value[0];
+//     currentTime.value = (nextTimestamp - baseTimestamp) / 1000;
+
+//     // 瑙﹀彂鏇存柊
+//     if (selectedScheme.value.type !== 2) {
+//       updateWaterColorByTime();
+//       updateWeatherByProgress();
+//     }
+
+//     const progress = currentTime.value / duration.value;
+//     emit("timeUpdate", progress * 100);
+//   }, 1000 / playbackRate.value); // 鏍规嵁鎾斁閫熺巼璋冩暣闂撮殧
+// };
 const startPlayback = () => {
   clearInterval(playInterval);
 
-  playInterval = setInterval(() => {
-    // 鎵惧埌褰撳墠鏃堕棿瀵瑰簲鐨勭储寮�
-    const currentIndex = findClosestTimestampIndex(currentTime.value);
-    const nextIndex = currentIndex + 1;
+  // 鏂板缓鏂规涓殑瀹炴椂妯℃嫙涓嶈兘鍊嶉��
+  if (selectedScheme.value.type === 2 && simStore.rePlayList.length == 0) {
+    console.log("鏂板缓鏂规瀹炴椂妯℃嫙浜旂涓�璺�");
+    // 瀹炴椂妯℃嫙锛氭瘡 5 绉掕烦鍔ㄤ竴娆�
+    playInterval = setInterval(() => {
+      const fiveSeconds = 5;
+      const totalDuration = duration.value; // 鎬绘椂闀匡紙绉掞級
 
-    // 濡傛灉宸茬粡鏄渶鍚庝竴涓椂闂寸偣锛屽仠姝㈡挱鏀�
-    if (nextIndex >= waterTimestamps.value.length) {
-      currentTime.value = duration.value;
-      stopPlayback();
-      isPlaying.value = false;
-      emit("isPlaying", false);
-      emit("playbackFinished", true);
-      return;
-    }
+      currentTime.value += fiveSeconds;
 
-    // 鏇存柊鏃堕棿涓轰笅涓�涓椂闂寸偣鐨勬椂闂村樊锛堢锛�
-    const nextTimestamp = waterTimestamps.value[nextIndex];
-    const baseTimestamp = waterTimestamps.value[0];
-    currentTime.value = (nextTimestamp - baseTimestamp) / 1000;
+      if (currentTime.value >= totalDuration) {
+        currentTime.value = totalDuration;
+        stopPlayback();
+        isPlaying.value = false;
+        finishPlay.value = true;
+        emit("isPlaying", false);
+        emit("playbackFinished", true);
+        return;
+      }
 
-    // 瑙﹀彂鏇存柊
-    if (selectedScheme.value.type !== 2) {
+      // 瑙﹀彂杩涘害鏇存柊
+      // const progress = currentTime.value / totalDuration;
+      // 瀹炴椂妯℃嫙搴旇涓嶇敤鏄剧ず寮圭獥鍚�
+      // emit("timeUpdate", progress * 100);
+
+      // 濡傛灉闇�瑕佽Е鍙戞煇浜涙洿鏂板嚱鏁帮紝涔熷彲浠ヤ繚鐣�
       updateWaterColorByTime();
-      updateWeatherByProgress();
-    }
+      // updateWeatherByProgress();
+      // 淇敼涓哄浐瀹氶樁娈碉紝缂撴參涓嬮洦鐨勭姸鎬�
+      const rainParams = {
+        rainSize: 0.5,
+        rainSpeed: 20,
+        rainDensity: 15,
+        rainColor: "#ADD8E6",
+      };
+      console.log("瀹炴椂妯℃嫙寮�濮嬩笅闆�");
+      // 璋冪敤宸ュ叿鏂规硶鏇存柊闆ㄦ晥
+      mapUtils.toggleRain(rainParams, true);
+    }, 5000); // 姣� 5 绉掓墽琛屼竴娆�
+  } else {
+    // 杩欓噷闈㈣繕鏄綘鐨勬挱鏀句唬鐮侊紝涓婇潰鐨刬f涓槸浜旂閽熻烦鍔ㄤ竴娆$殑瀹炴椂妯℃嫙
+    playInterval = setInterval(() => {
+      const currentIndex = findClosestTimestampIndex(currentTime.value);
+      const nextIndex = currentIndex + 1;
 
-    const progress = currentTime.value / duration.value;
-    emit("timeUpdate", progress * 100);
-  }, 1000 / playbackRate.value); // 鏍规嵁鎾斁閫熺巼璋冩暣闂撮殧
+      if (nextIndex >= waterTimestamps.value.length) {
+        currentTime.value = duration.value;
+        stopPlayback();
+        isPlaying.value = false;
+        finishPlay.value = true;
+        emit("isPlaying", false);
+        emit("playbackFinished", true);
+        return;
+      }
+
+      const nextTimestamp = waterTimestamps.value[nextIndex];
+      const baseTimestamp = waterTimestamps.value[0];
+      currentTime.value = (nextTimestamp - baseTimestamp) / 1000;
+
+      if (selectedScheme.value.type !== 2) {
+        updateWaterColorByTime();
+        updateWeatherByProgress();
+      }
+
+      const progress = currentTime.value / duration.value;
+      if (selectedScheme.value.type !== 2) {
+        emit("timeUpdate", progress * 100);
+      }
+    }, 1000 / playbackRate.value);
+  }
 };
 // 闄嶉洦鍙樺寲閮ㄥ垎
 // 闄嶉洦鏁版嵁鐩稿叧鍙橀噺
 let rainFallValues = ref([]); // 瀛樺偍鍘熷闄嶉洦閲忔暟鎹�
 let minRainValue = ref(Infinity);
+let averageRainIntensity = ref();
 let maxRainValue = ref(-Infinity);
 // 鑾峰彇闄嶉洦鏁版嵁
 function getRainfallData() {
@@ -285,9 +402,10 @@
     console.warn("selectedScheme 鎴� data 涓嶅瓨鍦�");
     return;
   }
-  // 娉ㄦ剰锛氭湁鏃� data 鍙兘鏄竴涓瓧绗︿覆锛堜緥濡� JSON 瀛楃涓诧級
+
   let data = selectedScheme.value.data;
-  // 濡傛灉鏄瓧绗︿覆锛屽垯灏濊瘯瑙f瀽鎴愬璞�
+
+  // 濡傛灉鏄瓧绗︿覆锛屽垯灏濊瘯瑙f瀽涓哄璞�
   if (typeof data === "string") {
     try {
       data = JSON.parse(data);
@@ -297,30 +415,82 @@
       return;
     }
   }
-  // 鎵撳嵃闄嶉洦寮哄害鐨勫崟浣�
+
   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 鍗曚綅锛屾棤娉曡繘琛岃浆鎹�");
+
+  // 鍒ゆ柇 rainfalls 鏄惁涓哄璞★紝濡傛灉鏄垯杞垚鏁扮粍
+  let rainfalls = data.rainfalls;
+  if (typeof rainfalls === "object" && !Array.isArray(rainfalls)) {
+    rainfalls = Object.values(rainfalls);
+    console.warn("鈿狅笍 rainfalls 鏄璞★紝宸茶浆鎹负鏁扮粍");
   }
 
-  const rainfallList = data.rainfalls;
-  console.log("鏈�缁堢殑 rainfallList:", rainfallList);
-  rainTotalInfo.value = rainfallList;
-  calculateTimeStep(rainTotalInfo.value);
-  // 浣跨敤绀轰緥
+  // 鎸夊皬鏃惰仛鍚堥檷闆ㄦ暟鎹�
+  const hourlyRainfallMap = {};
+
+  rainfalls.forEach((record) => {
+    const originalTime = new Date(record.time);
+    if (isNaN(originalTime.getTime())) {
+      console.warn("鏃犳晥鐨勬椂闂存牸寮忥細", record.time);
+      return;
+    }
+
+    // 鏋勯�犫�滃皬鏃垛�濈骇鍒殑鏃堕棿閿紝姣斿锛�2024-08-25 20:00:00
+    const hourKey = new Date(
+      originalTime.getFullYear(),
+      originalTime.getMonth(),
+      originalTime.getDate(),
+      originalTime.getHours()
+    );
+
+    const hourStr = hourKey.toISOString().slice(0, 16).replace("T", " ");
+
+    if (!hourlyRainfallMap[hourStr]) {
+      hourlyRainfallMap[hourStr] = {
+        intensity: 0,
+        time: hourStr,
+        total: record.total, // 榛樿鐢ㄧ涓�涓褰曠殑 total
+      };
+    }
+
+    hourlyRainfallMap[hourStr].intensity += record.intensity;
+    // 鍙栨渶澶х殑 total锛堝洜涓烘槸绱Н鍊硷級
+    if (record.total > hourlyRainfallMap[hourStr].total) {
+      hourlyRainfallMap[hourStr].total = record.total;
+    }
+  });
+
+  // 杞崲 map 鎴愭暟缁勫苟鎺掑簭
+  const hourlyRainfallList = Object.values(hourlyRainfallMap).sort((a, b) =>
+    a.time.localeCompare(b.time)
+  );
+
+  console.log("鉁� 鎸夊皬鏃惰仛鍚堝悗鐨勯檷闆ㄦ暟鎹細", hourlyRainfallList);
+
+  // 璁剧疆鍏ㄥ眬鍙橀噺
+  rainTotalInfo.value = hourlyRainfallList;
+
+  // 璁$畻鏃堕棿姝ラ暱
   timeStepInfo = calculateTimeStep(rainTotalInfo.value);
 
   // 鎻愬彇 intensity 鍊�
-  rainFallValues.value = rainfallList.map((r) => r.intensity);
+  rainFallValues.value = hourlyRainfallList.map((r) => r.intensity);
+  // 璁$畻骞冲潎闆ㄥ己
+  if (rainFallValues.value.length > 0) {
+    const sumIntensity = rainFallValues.value.reduce(
+      (sum, val) => sum + val,
+      0
+    );
+    averageRainIntensity.value = sumIntensity / rainFallValues.value.length;
+  } else {
+    averageRainIntensity.value = 0; // 鎴栬�� null 琛ㄧず鏃犳暟鎹�
+  }
+
+  console.log("骞冲潎闆ㄥ己涓猴細", averageRainIntensity.value);
+
   minRainValue.value = Math.min(...rainFallValues.value);
   maxRainValue.value = Math.max(...rainFallValues.value);
+
   console.log(
     "褰撳墠鏂规涓嬫渶灏忛洦閲忓拰鏈�澶ч洦閲忥細",
     minRainValue.value,
@@ -426,154 +596,218 @@
 
   return timeStepHours;
 }
+// ============================================================================
+// 浼樺寲鏂瑰紡锛屽彲浠ユ眰鍑烘暣涓椂闂磋酱涓婏紝绗竴娆¢亣鍒拌繖鍏釜闃堝�煎緱鏃堕棿鐐癸紝鐒跺悗鍒嗘椂闂存鏄剧ず锛宎鏃堕棿鍐呮樉绀虹姸鎬�1锛岀劧鍚庣姸鎬佷氦鐣屽璁剧疆棰滆壊娓愬彉锛屽叾浣欏悓鐞嗭紝杩欐牱璺宠浆寰楁椂鍊欒兘澶熺洿鎺ヨ烦杞埌褰撳墠寰楅鑹蹭俊鎭樁娈碉紝鐩存帴搴旂敤锛屽嵆鍙�
+// ============================================================================
 // 鍏ㄥ眬鐘舵�佽褰�
 const colorState = {
-  maxStage: 0,       // 璁板綍鍘嗗彶鏈�楂橀樁娈�
-  maxAlpha: -0.3,    // 璁板綍鍘嗗彶鏈�灏忛�忔槑搴︼紙璐熷�硷級
-  maxLuminance: 240.4, // 璁板綍鍘嗗彶鏈�浣庝寒搴︼紙瀵瑰簲stage 0鍒濆鍊硷級
-  currentColor: "#F5F0E6" // 褰撳墠棰滆壊
+  currentColor: "#F5F0E6", // 褰撳墠棰滆壊
+  currentAlpha: -0.3, // 褰撳墠閫忔槑搴�
+  colorStages: null, // 棰勮绠楃殑棰滆壊闃舵鏃堕棿鐐�
+  maxColorTime: null, // 璁板綍杈惧埌鏈�娣遍鑹叉椂鐨勬椂闂寸偣
 };
 
-function updateWaterColorByTime() {
+// 棰勮绠楅鑹查樁娈垫椂闂寸偣
+function precomputeColorStages() {
   if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return;
-
-  // 1. 璁$畻鍩虹鏁版嵁
-  const { intensity, IR } = calculateRainData();
-
-  // 2. 棰滆壊閰嶇疆锛堜寒搴︿弗鏍奸�掑噺锛�
+  // 棰滆壊閰嶇疆锛堜寒搴﹂�掑噺锛�
   const COLOR_STOPS = [
     { hex: "#F5F0E6", luminance: 240.4 }, // stage 0
-    { hex: "#D4F2E7", luminance: 231.8 }, // stage 1
-    { hex: "#E6D5B8", luminance: 214.8 }, // stage 2
-    { hex: "#D4B483", luminance: 184.0 }, // stage 3
-    { hex: "#B78B6A", luminance: 148.4 }, // stage 4
-    { hex: "#8B5A3A", luminance: 101.0 }, // stage 5
-    { hex: "#4A3123", luminance: 54.9 }   // stage 6
+    { hex: "#E6D5B8", luminance: 214.8 }, // stage 1
+    { 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
   ];
-  const alphaStops = [1
-    -0.3,   // stage 0
-    -0.4,   // stage 1
-    -0.5,   // stage 2
-    -0.6,   // stage 3
-    -0.7,   // stage 4
-    -0.75,  // stage 5
-    -0.8    // 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
   ];
-  // 3. 鏇存柊闃舵鐘舵��
-  updateStageState(intensity, IR);
-
-  // 4. 璁$畻骞堕攣瀹氶鑹诧紙纭繚浜害涓嶅洖鍗囷級
-  updateColorState(COLOR_STOPS, intensity, IR);
-
-  // 5. 搴旂敤棰滆壊
-  updateWaterColor(colorState.currentColor, colorState.maxAlpha);
-
-  // --- 杈呭姪鍑芥暟 ---
-  function calculateRainData() {
-    const initialTimestamp = new Date(rainTotalInfo.value[0].time).getTime();
-    const currentTimestamp = new Date(
-      rainTotalInfo.value[Math.min(
-        Math.floor(currentTime.value / duration.value * (rainTotalInfo.value.length - 1)),
-        rainTotalInfo.value.length - 2
-      )].time
-    ).getTime();
-
-    // 闄嶉洦寮哄害璁$畻锛堝甫鎻掑�硷級
-    const progress = currentTime.value / duration.value;
-    const floatIndex = progress * (rainTotalInfo.value.length - 1);
-    let index = Math.floor(floatIndex);
-    if (index >= rainTotalInfo.value.length - 1) {
-      index = rainTotalInfo.value.length - 2; // 闃叉 index+1 瓒婄晫
-    }
-    const lerpAlpha = floatIndex - index;
-    const intensity = rainTotalInfo.value[index].intensity * (1 - lerpAlpha) +
-      rainTotalInfo.value[index + 1].intensity * lerpAlpha;
-
-    // 涓寸晫闄嶉洦寮哄害璁$畻
-    const D = (currentTimestamp - initialTimestamp) / (1000 * 60 * 60) + 0.0001;
-    const IR = 56.9 * Math.pow(D, -0.746);
-
-    return { intensity, IR };
+  // 绱闄嶉洦閲忛槇鍊硷紙mm锛�
+  const R_THRESHOLDS = [0, 200, 240, 280, 310, 350]; // 鍏�6涓樁娈靛搴�6涓槇鍊�
+  // 鏃堕棿鍜岄檷闆ㄩ噺淇℃伅
+  const timeTotals = [];
+  const initialTimestamp = new Date(rainTotalInfo.value[0].time).getTime();
+  for (let i = 0; i < rainTotalInfo.value.length; i++) {
+    const timestamp = new Date(rainTotalInfo.value[i].time).getTime();
+    const time = (timestamp - initialTimestamp) / 1000;
+    const total = rainTotalInfo.value[i].total; // 浣跨敤 total 鏇夸唬 intensity
+    timeTotals.push({
+      time,
+      total,
+    });
   }
 
-  function updateStageState(intensity, IR) {
-    // 璁$畻鐞嗚闃舵
-    let stage = 0;
-    const thresholds = [0, 0.2, 0.4, 0.6, 0.8, 1.0];
-    for (let i = thresholds.length - 1; i >= 0; i--) {
-      if (intensity >= thresholds[i] * IR) {
-        stage = i + 1;
+  // 鎵惧嚭姣忎釜闃舵棣栨杈惧埌鐨勬椂闂寸偣
+  const stages = [];
+  for (let stage = 1; stage < R_THRESHOLDS.length + 1; stage++) {
+    const threshold = R_THRESHOLDS[stage - 1];
+    for (let i = 0; i < timeTotals.length; i++) {
+      const { time, total } = timeTotals[i];
+      if (total >= threshold) {
+        stages[stage] = {
+          startTime: time,
+          color: COLOR_STOPS[stage].hex,
+          alpha: alphaStops[stage],
+          threshold,
+        };
         break;
       }
     }
-
-    // 鏇存柊鏈�澶ч樁娈碉紙鍗曞悜閫掑锛�
-    colorState.maxStage = Math.max(colorState.maxStage, stage);
   }
 
-  function updateColorState(colorStops, intensity, IR) {
-    // 宸茶揪鏈�缁堥樁娈�
-    if (colorState.maxStage >= colorStops.length - 1) {
-      colorState.currentColor = colorStops[colorStops.length - 1].hex;
-      colorState.maxAlpha = -0.8;
-      colorState.maxLuminance = colorStops[colorStops.length - 1].luminance;
-      return;
-    }
+  // 濉厖闃舵0
+  stages[0] = {
+    startTime: 0,
+    color: COLOR_STOPS[0].hex,
+    alpha: alphaStops[0],
+    threshold: 0,
+  };
 
-    // 璁$畻褰撳墠闃舵杩涘害
-    const stageThresholds = [0, 0.2, 0.4, 0.6, 0.8, 1.0];
-    const lowerThreshold = stageThresholds[colorState.maxStage - 1] * IR;
-    const upperThreshold = stageThresholds[colorState.maxStage] * IR;
-    const ratio = Math.min(1, Math.max(0, (intensity - lowerThreshold) / (upperThreshold - lowerThreshold)));
-
-    // 棰滆壊鎻掑��
-    const startColor = colorStops[colorState.maxStage];
-    const endColor = colorStops[colorState.maxStage + 1];
-    const newColor = lerpColor(startColor.hex, endColor.hex, ratio);
-    const newLuminance = calculateLuminance(newColor);
-
-    // 鍙帴鍙楁洿鏆楃殑棰滆壊锛堜寒搴︽洿浣庯級
-    if (newLuminance < colorState.maxLuminance) {
-      colorState.currentColor = newColor;
-      colorState.maxLuminance = newLuminance;
-      colorState.maxAlpha = Math.min(
-        colorState.maxAlpha,
-        lerp(alphaStops[colorState.maxStage], alphaStops[colorState.maxStage + 1], ratio)
-      );
-    }
-
-    console.log(`闃舵: ${colorState.maxStage} | 浜害: ${colorState.maxLuminance.toFixed(1)} | 棰滆壊: ${colorState.currentColor}`);
-  }
-
-  // 棰滆壊鎻掑�煎伐鍏峰嚱鏁�
-  function lerpColor(c1, c2, t) {
-    const [r1, g1, b1] = hexToRgb(c1);
-    const [r2, g2, b2] = hexToRgb(c2);
-    return rgbToHex(
-      r1 + (r2 - r1) * t,
-      g1 + (g2 - g1) * t,
-      b1 + (b2 - b1) * t
-    );
-  }
-
-  function calculateLuminance(hex) {
-    const [r, g, b] = hexToRgb(hex);
-    return 0.299 * r + 0.587 * g + 0.114 * b;
-  }
-
-  function hexToRgb(hex) {
-    const bigint = parseInt(hex.slice(1), 16);
-    return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
-  }
-
-  function rgbToHex(r, g, b) {
-    return `#${[r, g, b].map(x => Math.round(x).toString(16).padStart(2, '0')).join('')}`;
-  }
-
-  function lerp(a, b, t) {
-    return a + (b - a) * t;
-  }
+  colorState.colorStages = stages;
 }
+
+function updateWaterColorByTime(isForceUpdate = false) {
+  if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return;
+
+  // 棣栨璋冪敤鏃堕璁$畻棰滆壊闃舵
+  if (colorState.colorStages === null) {
+    precomputeColorStages();
+  }
+
+  // 鏌ユ壘褰撳墠鏃堕棿鐐规墍灞炵殑闃舵
+  let currentStage = 0;
+  for (let i = colorState.colorStages.length - 1; i >= 0; i--) {
+    if (
+      colorState.colorStages[i] &&
+      currentTime.value >= colorState.colorStages[i].startTime
+    ) {
+      currentStage = i;
+      break;
+    }
+  }
+
+  // 璁板綍杈惧埌鏈�娣遍鑹茬殑鏃堕棿鐐�
+  if (currentStage >= colorState.colorStages.length - 1) {
+    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);
+
+  // 鏇存柊棰滆壊閫昏緫
+  if (shouldForceUpdate || isTimeGoingBackward) {
+    // 寮哄埗鏇存柊鎴栨椂闂村洖閫�鏃讹紝鐩存帴搴旂敤褰撳墠闃舵鐨勯鑹�
+    colorState.currentColor = colorState.colorStages[currentStage].color;
+    colorState.currentAlpha = colorState.colorStages[currentStage].alpha;
+  } else {
+    // 姝e父鏃堕棿鍓嶈繘鏃讹紝淇濇寔娓愯繘鍙樺寲
+    const newColor = colorState.colorStages[currentStage].color;
+    const newAlpha = colorState.colorStages[currentStage].alpha;
+
+    // 鍙簲鐢ㄦ洿鏆楃殑棰滆壊鍜屾洿浣庣殑閫忔槑搴�
+    if (
+      calculateLuminance(newColor) < calculateLuminance(colorState.currentColor)
+    ) {
+      colorState.currentColor = newColor;
+    }
+    if (newAlpha < colorState.currentAlpha) {
+      colorState.currentAlpha = newAlpha;
+    }
+  }
+
+  // 鏇存柊鏃堕棿璁板綍
+  colorState.lastTime = currentTime.value;
+  // ====== 鏂板锛氬湪 updateWaterColor 鍓嶆墦鍗板綋鍓嶄俊鎭� ======
+  // // 鑾峰彇褰撳墠绱闄嶉洦閲�
+  let currentTotal = null;
+  const baseTimestamp = new Date(rainTotalInfo.value[0].time).getTime();
+  const currentTimeMs = baseTimestamp + currentTime.value * 1000;
+
+  // 鎵惧埌鏈�鎺ヨ繎鐨勯檷闆ㄦ暟鎹偣
+  for (let i = rainTotalInfo.value.length - 1; i >= 0; i--) {
+    const dataTimeMs = new Date(rainTotalInfo.value[i].time).getTime();
+    if (dataTimeMs <= currentTimeMs) {
+      currentTotal = rainTotalInfo.value[i].total;
+      break;
+    }
+  }
+
+  // 鎵撳嵃淇℃伅
+  // console.log("========================================");
+  // console.log(`銆愭椂闂存埑銆�: ${new Date(currentTimeMs).toLocaleString()}`);
+  console.log(
+    `銆愮疮璁¢檷闆ㄩ噺 R銆�: ${
+      currentTotal !== null ? currentTotal.toFixed(2) : "鏈煡"
+    } mm`
+  );
+  // console.log(`銆愬綋鍓嶉樁娈点��: 绗� ${currentStage} 闃舵`);
+  console.log(
+    `銆愰鑹� HEX銆�: ${colorState.colorStages[currentStage]?.color || "鏈畾涔�"}`
+  );
+  // console.log(`銆愰�忔槑搴� Alpha銆�: ${colorState.colorStages[currentStage]?.alpha || '鏈畾涔�'}`);
+  // console.log("========================================");
+  // 搴旂敤棰滆壊
+  updateWaterColor(colorState.currentColor, colorState.currentAlpha);
+}
+
+// 杈呭姪鍑芥暟淇濇寔涓嶅彉
+function calculateLuminance(hex) {
+  const [r, g, b] = hexToRgb(hex);
+  return 0.299 * r + 0.587 * g + 0.114 * b;
+}
+
+function hexToRgb(hex) {
+  const bigint = parseInt(hex.slice(1), 16);
+  return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
+}
+
+// 鏃堕棿杞磋烦杞嚱鏁�
+const seekToPosition = (event) => {
+  if (!isWaterPrimitiveCreated.value) {
+    ElMessage.warning("璇峰厛鍚姩姘翠綋妯℃嫙鍚庡啀杩涜鏃堕棿杞磋烦杞��");
+    return;
+  }
+
+  const rect = timelineTrack.value.getBoundingClientRect();
+  const percentage = (event.clientX - rect.left) / rect.width;
+  const targetTime = Math.round(percentage * duration.value);
+
+  const closestIndex = findClosestTimestampIndex(targetTime);
+  const baseTimestamp = waterTimestamps.value[0];
+  const newTime = (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000;
+
+  // 鍒ゆ柇鏄惁闇�瑕佸己鍒舵洿鏂伴鑹�
+  const isGoingBackward = newTime < currentTime.value;
+  const isBeforeMaxColor =
+    colorState.maxColorTime !== null && newTime <= colorState.maxColorTime;
+  const shouldForceUpdate = isGoingBackward || isBeforeMaxColor;
+
+  currentTime.value = newTime;
+  setTimeForWaterSimulation(closestIndex);
+
+  // 鏍规嵁鏉′欢鏇存柊棰滆壊
+  updateWaterColorByTime(shouldForceUpdate);
+
+  if (!isPlaying.value) pauseWaterSimulation();
+};
+// ============================================================================
 
 function updateWeatherByProgress() {
   if (rainFallValues.value.length === 0) return;
@@ -683,27 +917,7 @@
   EventBus.emit("clear-echart");
   EventBus.emit("reset-table");
 };
-// 鏃堕棿杞磋烦杞�
-const seekToPosition = (event) => {
-  if (!isWaterPrimitiveCreated.value) {
-    ElMessage.warning("璇峰厛鍚姩姘翠綋妯℃嫙鍚庡啀杩涜鏃堕棿杞磋烦杞��");
-    return;
-  }
 
-  const rect = timelineTrack.value.getBoundingClientRect();
-  const percentage = (event.clientX - rect.left) / rect.width;
-  const targetTime = Math.round(percentage * duration.value);
-
-  // 鐩存帴鎵惧埌鏈�杩戠殑 timestamp 绱㈠紩
-  const closestIndex = findClosestTimestampIndex(targetTime);
-  const baseTimestamp = waterTimestamps.value[0];
-  currentTime.value =
-    (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000;
-
-  // 鏇存柊姘翠綋妯℃嫙鏃堕棿
-  setTimeForWaterSimulation(closestIndex);
-  if (!isPlaying.value) pauseWaterSimulation();
-};
 // 杈呭姪鍑芥暟锛氭壘鍒版渶鎺ヨ繎鐨勬椂闂存埑绱㈠紩
 function findClosestTimestampIndex(currentTimeValue) {
   if (waterTimestamps.value.length === 0) return 0;
@@ -774,16 +988,26 @@
   { immediate: true }
 );
 
-onMounted(async () => {
+const jsonFetch = ref(null);
+const currentReplayIndex = ref(0); // 褰撳墠鎾斁鐨剅ePlayList绱㈠紩
+// 鎻愬彇涓虹嫭绔嬪嚱鏁�
+async function initializeSimulationData(replayItem = null) {
   try {
-    // 褰撳墠鏂规鐨勬墍鏈変俊鎭�
     const schemeInfo = selectedScheme.value;
-    const jsonFetch = ref(null);
     serviceInfo = schemeInfo.serviceName;
-    if (selectedScheme.value.type == 2) {
-      speedShow.value = false;
-      jsonFetch.value = layerDate.value;
-      // serviceInfo = layerDate.value;
+
+    if (schemeInfo.type == 2) {
+      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;
@@ -791,20 +1015,25 @@
     }
 
     // console.log('鑾峰彇鍒扮殑 serviceName:', serviceInfo);
-
-    // 鏍规嵁layer.json鍘昏幏鍙栨椂闂磋酱淇℃伅
+    // 鏍规嵁 layer.json 鑾峰彇鏃堕棿杞翠俊鎭�
     const {
       waterTimestamps: timestamps,
       watersMaxHeight,
       watersMinHeight,
     } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value);
+
     console.log(
       "褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�",
       watersMaxHeight,
       watersMinHeight
     );
-
-    // 鐜板湪鏄寜鐓ф�诲叡鏈夊灏戜釜鐐规潵娓叉煋鏃堕棿杞�
+    const waterInfoArr = [
+      watersMaxHeight,
+      maxRainValue.value,
+      averageRainIntensity.value,
+    ];
+    schemWaterInfo.value = waterInfoArr;
+    // 鏇存柊鏃堕棿杞寸浉鍏虫暟鎹�
     if (timestamps) {
       frameNum.value = timestamps.length;
       waterTimestamps.value = timestamps;
@@ -824,7 +1053,66 @@
       type: "warning",
     });
   }
+}
+// 鎾斁瀹屾垚鍚庣殑鍥炶皟
+function handlePlayFinished() {
+  if (selectedScheme.value.type !== 2) return;
+  finishPlay.value = false;
+  currentReplayIndex.value++;
+
+  if (currentReplayIndex.value < simStore.rePlayList.length) {
+    // 鑷姩鎾斁涓嬩竴涓�
+    initializeSimulationData(simStore.rePlayList[currentReplayIndex.value]);
+    togglePlay();
+    shouldAutoPlay.value = false;
+  } else {
+    // 鎵�鏈夐」鐩挱鏀惧畬鎴�
+    currentReplayIndex.value = 0; // 閲嶇疆绱㈠紩
+    isPlaying.value = false; // 鍋滄鎾斁
+    emit("timeUpdate", 100); // 鍦ㄦ墍鏈夐」鐩挱鏀惧畬姣曞悗瑙﹀彂
+  }
+}
+
+// 鐩戝惉鎾斁瀹屾垚浜嬩欢
+watch(
+  () => finishPlay.value,
+  (newVal) => {
+    if (
+      newVal &&
+      selectedScheme.value.type === 2 &&
+      simStore.rePlayList.length > 0
+    ) {
+      handlePlayFinished();
+    }
+  }
+);
+
+const shouldAutoPlay = ref(false);
+// 鐩戝惉 layerDate 鍙樺寲鍚庢爣璁板噯澶囨挱鏀�
+watch(
+  () => layerDate.value,
+  async (newVal) => {
+    if (selectedScheme.value.type === 2 && newVal) {
+      shouldAutoPlay.value = true;
+    }
+  },
+  { deep: true }
+);
+// 绛夊緟 finishPlay 鎴愬姛鍚庡啀鎾斁
+watchEffect(() => {
+  if (shouldAutoPlay.value && finishPlay.value && !isPlaying.value) {
+    initializeSimulationData();
+    togglePlay();
+    shouldAutoPlay.value = false;
+  }
 });
+
+// 鎸傝浇鏃惰皟鐢�
+onMounted(async () => {
+  // 鍥犱负杩欎釜鍑芥暟瀹炴椂妯℃嫙鐩戝惉涔熼渶瑕佷娇鐢紝鎵�浠ュ皝瑁呬簡涓�涓嚱鏁�
+  await initializeSimulationData();
+});
+
 // 鏍规嵁杩斿洖鏁版嵁鐨勪釜鏁板幓娓叉煋鏃堕棿杞�
 function updateTimelineRange() {
   if (waterTimestamps.value.length > 0) {
@@ -835,32 +1123,75 @@
     duration.value = (last - first) / 1000; // 姣杞
   }
 }
-
 onBeforeUnmount(() => {
   stopPlayback();
   destoryWaterPrimitive();
 });
 
 const { endSimulate } = inject("simulateActions");
-function handleBack() {
+
+async function handleBack() {
+  // 瀹炴椂妯℃嫙寮圭獥纭鏄繑鍥炴柟妗堝垪琛ㄨ繕鏄仠姝㈡ā鎷�
+  if (selectedScheme.value.type === 2) {
+    try {
+      await ElMessageBox.confirm("鏂规鏈仠姝㈡椂缁撴潫妯℃嫙鍚庯紝鍚庡彴灏嗗仠姝㈣绠�", {
+        confirmButtonText: "缁撴潫妯℃嫙",
+        cancelButtonText: "杩斿洖鍒楄〃",
+        type: "warning",
+      });
+
+      const res = await stopSim(selectedScheme.value.id);
+      if (res.code == 404) {
+        ElMessage.warning("璇ユ湇鍔″凡鍋滄");
+      } else {
+        ElMessage.success("鏈嶅姟姝e湪鍋滄涓�");
+      }
+    } catch (error) {
+      // 鐢ㄦ埛鐐瑰嚮浜嗐�愯繑鍥炲垪琛ㄣ�戞垨鑰呭嚭鐜伴敊璇�
+      return;
+    }
+  }
+
+  // 涓嶇 type 鏄笉鏄� 2锛屾渶缁堥兘鎵ц缁撴潫妯℃嫙鎿嶄綔
+  endSimulation();
+}
+
+async function endSimulation() {
+  clearAllPoints();
+  simStore.openDia = true;
+  simStore.crossSection = [];
+  // 缁撴潫妯℃嫙涔嬪悗娓呴櫎layer鍒楄〃
+  simStore.rePlayList = [];
+  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: "妯℃嫙杩涚▼姝e湪鍏抽棴涓�...", type: "success" });
 }
 </script>

--
Gitblit v1.9.3