From fa541dda36e58de1d491b3ff4073c51b16606515 Mon Sep 17 00:00:00 2001
From: wangjuncheng <1>
Date: 星期三, 25 六月 2025 17:29:42 +0800
Subject: [PATCH] 2

---
 src/components/menu/TimeLine.vue |  282 ++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 183 insertions(+), 99 deletions(-)

diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue
index 91d7acb..e18acb9 100644
--- a/src/components/menu/TimeLine.vue
+++ b/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" 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>
@@ -35,33 +25,19 @@
     <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>
@@ -70,12 +46,8 @@
           <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>
@@ -84,38 +56,27 @@
     </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>
@@ -152,7 +113,7 @@
 import { useSimStore } from "@/store/simulation";
 import { storeToRefs } from "pinia";
 const simStore = useSimStore();
-const { selectedScheme, frameNum } = storeToRefs(simStore);
+const { selectedScheme, frameNum, layerDate } = storeToRefs(simStore);
 
 const emit = defineEmits([
   "timeUpdate",
@@ -191,7 +152,7 @@
 const isWaterPrimitiveCreated = ref(false);
 let playInterval = null;
 let timeStepInfo = null;
-let rainTotalInfo = ([]);
+let rainTotalInfo = [];
 const isRainEnabled = ref(false);
 const rainParams = reactive({
   rainSize: 0.5,
@@ -201,6 +162,9 @@
 });
 let minFlowRate = ref();
 let maxFlowRate = ref();
+// 鍏ㄥ眬鍙橀噺璁板綍鏈�澶ч樁娈靛拰閫忔槑搴�
+let maxStage = 0;
+let maxAlpha = -0.3; // 鍒濆閫忔槑搴﹀搴攕tage 0
 // 璁$畻灞炴��
 const progressPercentage = computed(
   () => (currentTime.value / duration.value) * 100
@@ -348,10 +312,10 @@
 
   const rainfallList = data.rainfalls;
   console.log("鏈�缁堢殑 rainfallList:", rainfallList);
-  rainTotalInfo.value = rainfallList
-  calculateTimeStep(rainTotalInfo.value)
+  rainTotalInfo.value = rainfallList;
+  calculateTimeStep(rainTotalInfo.value);
   // 浣跨敤绀轰緥
- timeStepInfo = calculateTimeStep(rainTotalInfo.value);
+  timeStepInfo = calculateTimeStep(rainTotalInfo.value);
 
   // 鎻愬彇 intensity 鍊�
   rainFallValues.value = rainfallList.map((r) => r.intensity);
@@ -430,13 +394,13 @@
 
 function calculateTimeStep(dataArray) {
   if (!dataArray || dataArray.length < 2) {
-    console.warn('鏁版嵁涓嶈冻锛屾棤娉曡绠楁椂闂存闀�');
+    console.warn("鏁版嵁涓嶈冻锛屾棤娉曡绠楁椂闂存闀�");
     return null;
   }
 
   // 瑙f瀽鏃堕棿瀛楃涓蹭负 Date 瀵硅薄
   function parseTime(timeStr) {
-    return new Date(timeStr.replace(' ', 'T')); // 鍏煎 ISO 鏍煎紡
+    return new Date(timeStr.replace(" ", "T")); // 鍏煎 ISO 鏍煎紡
   }
 
   const firstTime = parseTime(dataArray[0].time);
@@ -454,45 +418,161 @@
     const next = parseTime(dataArray[i + 1].time);
     const step = Math.abs(next - current) / (1000 * 60 * 60); // 姣 -> 灏忔椂
     if (Math.abs(step - timeStepHours) > 0.01) {
-      console.warn(`鍦ㄧ储寮� ${i} 澶勫彂鐜颁簡涓嶅悓鐨勬椂闂存闀�: ${step.toFixed(2)} 灏忔椂`);
+      console.warn(
+        `鍦ㄧ储寮� ${i} 澶勫彂鐜颁簡涓嶅悓鐨勬椂闂存闀�: ${step.toFixed(2)} 灏忔椂`
+      );
     }
   }
 
   return timeStepHours;
 }
+// 鍏ㄥ眬鐘舵�佽褰�
+const colorState = {
+  maxStage: 0,       // 璁板綍鍘嗗彶鏈�楂橀樁娈�
+  maxAlpha: -0.3,    // 璁板綍鍘嗗彶鏈�灏忛�忔槑搴︼紙璐熷�硷級
+  maxLuminance: 240.4, // 璁板綍鍘嗗彶鏈�浣庝寒搴︼紙瀵瑰簲stage 0鍒濆鍊硷級
+  currentColor: "#F5F0E6" // 褰撳墠棰滆壊
+};
 
 function updateWaterColorByTime() {
   if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return;
-  const progress = currentTime.value / duration.value;
-  const floatIndex = progress * (rainTotalInfo.value.length - 1);
-  const index = Math.floor(floatIndex);
-  const nextIndex = Math.min(index + 1, rainTotalInfo.value.length - 1);
-  const currentData = rainTotalInfo.value[index];
-  const nextData = rainTotalInfo.value[nextIndex];
-  // 鍚敤鎻掑�硷紙alpha 骞虫粦杩囨浮锛�
-  const alpha = floatIndex - index;
-  const currentTotal = currentData.total;
-  const nextTotal = nextData.total;
-  const total = currentTotal + (nextTotal - currentTotal) * alpha;
-  console.log(`璁$畻寰楀埌鐨勬椂闂存闀夸负: ${timeStepInfo} 灏忔椂`);
-  // 鏍规嵁 total 璁剧疆棰滆壊
-  let color = "#D4F2E7"; // 榛樿钃濊壊
 
-  if (total >= 150) {
-    color = '#663300'; 
-  } else if (total >= 125) {
-    color = '#B26633'; 
-  } else if (total >= 100) {
-    color = '#CC9966';
-  } else if (total >= 75) {
-    color = '#CCE5FF'; 
-  } else if (total >= 50) {
-    color = '#99CCFF';
-  } else if (total >= 25) {
-    color = '#66B3FF'; 
+  // 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
+  ];
+  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
+  ];
+  // 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 };
   }
-  // console.log(`褰撳墠 total: ${total.toFixed(2)}, 棰滆壊: ${color}`);
-  // updateWaterColor(color)
+
+  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;
+        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;
+    }
+
+    // 璁$畻褰撳墠闃舵杩涘害
+    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;
+  }
 }
 
 function updateWeatherByProgress() {
@@ -509,11 +589,11 @@
   // const rainValue = currentRain + (nextRain - currentRain) * alpha;
   const rainValue = currentRain + (nextRain - currentRain);
   // 鎵撳嵃褰撳墠澶勭悊鐨勯洦閲忔暟鎹�
-  console.log(
-    `姝e湪澶勭悊鐨勯洦閲忔暟鎹偣: 褰撳墠=${currentRain}, 涓嬩竴涓�=${nextRain}, 鎻掑�煎悗=${rainValue.toFixed(
-      2
-    )}, 绱㈠紩=${index}`
-  );
+  // console.log(
+  //   `姝e湪澶勭悊鐨勯洦閲忔暟鎹偣: 褰撳墠=${currentRain}, 涓嬩竴涓�=${nextRain}, 鎻掑�煎悗=${rainValue.toFixed(
+  //     2
+  //   )}, 绱㈠紩=${index}`
+  // );
   // 濡傛灉褰撳墠绱㈠紩鏈彉鍖栦笖鎻掑�煎樊寮備笉澶э紝璺宠繃閲嶅鏇存柊
   if (index === lastUsedIndex && Math.abs(rainValue - lastRainValue) < 0.1) {
     // console.log('鐢变簬鏁版嵁鏃犳樉钁楀彉鍖栵紝璺宠繃鏈鏇存柊');
@@ -698,12 +778,16 @@
   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;
     } else {
       getRainfallData();
       speedShow.value = true;
+      jsonFetch.value = null;
     }
 
     // console.log('鑾峰彇鍒扮殑 serviceName:', serviceInfo);
@@ -713,7 +797,7 @@
       waterTimestamps: timestamps,
       watersMaxHeight,
       watersMinHeight,
-    } = await fetchWaterSimulationData(serviceInfo);
+    } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value);
     console.log(
       "褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�",
       watersMaxHeight,

--
Gitblit v1.9.3