From e15245c624a20a3b46e428d646f5f2dd863cd1bc Mon Sep 17 00:00:00 2001
From: guonan <guonan201020@163.com>
Date: 星期四, 17 四月 2025 14:22:36 +0800
Subject: [PATCH] 完善

---
 src/views/left/CitySim.vue |  536 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 342 insertions(+), 194 deletions(-)

diff --git a/src/views/left/CitySim.vue b/src/views/left/CitySim.vue
index 7b7a347..b38e91f 100644
--- a/src/views/left/CitySim.vue
+++ b/src/views/left/CitySim.vue
@@ -1,14 +1,45 @@
 <template>
   <div style="width: 100%; height: 100%">
-    <div class="left-top" v-if="disForm == '琛屾斂鍖哄垝浠跨湡'">
+    <div
+      class="left-top"
+      v-if="simStore.selectTab == '琛屾斂鍖哄垝浠跨湡'"
+      style="margin-top: 0px"
+    >
       琛屾斂鍖哄垝浠跨湡锛�30m绮惧害锛�
     </div>
-    <div class="left-top" v-if="disForm == '閲嶇偣鍖哄煙浠跨湡'">
+    <div class="left-top" v-if="simStore.selectTab == '閲嶇偣鍖哄煙浠跨湡'">
       閲嶇偣鍖哄煙浠跨湡锛�10m绮惧害锛�
     </div>
     <div class="forms">
       <el-form :model="forms" label-width="auto" style="max-width: 600px">
-        <el-form-item label="琛屾斂鍖哄煙:" v-if="disForm == '琛屾斂鍖哄垝浠跨湡'">
+        <el-form-item label="鏂规鍚嶇О:">
+          <el-input
+            v-model="forms.name"
+            style="max-width: 600px"
+            placeholder="Please input"
+          >
+          </el-input>
+        </el-form-item>
+        <el-form-item label="涓婁紶鍙傛暟">
+          <el-upload
+            v-model:file-list="forms.fileList"
+            class="upload-demo"
+            :auto-upload="false"
+            :multiple="false"
+            :on-change="handleFileChange"
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeUpload"
+            accept=".xlsx,.xls,.csv"
+          >
+            <el-button type="primary">鐐瑰嚮涓婁紶闄嶉洦鏁版嵁</el-button>
+            <template #append>mm/h</template>
+          </el-upload>
+        </el-form-item>
+        <el-form-item
+          label="琛屾斂鍖哄煙:"
+          v-if="simStore.selectTab == '琛屾斂鍖哄垝浠跨湡'"
+        >
           <el-select
             v-model="forms.eare"
             placeholder="Select"
@@ -22,25 +53,10 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="涓婁紶鍙傛暟">
-          <el-upload
-            v-model:file-list="forms.fileList"
-            class="upload-demo"
-            action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
-            multiple
-            :on-preview="handlePreview"
-            :on-remove="handleRemove"
-            :before-remove="beforeRemove"
-            :limit="3"
-            :on-exceed="handleExceed"
-            :before-upload="beforeUpload"
-            accept=".xlsx,.xls,.csv"
-          >
-            <el-button type="primary">鐐瑰嚮涓婁紶闄嶉洦鏁版嵁</el-button>
-            <template #append>mm/h</template>
-          </el-upload>
-        </el-form-item>
-        <el-form-item label="閲嶇偣鍖哄煙" v-if="disForm == '閲嶇偣鍖哄煙浠跨湡'">
+        <el-form-item
+          label="閲嶇偣鍖哄煙:"
+          v-if="simStore.selectTab == '閲嶇偣鍖哄煙浠跨湡'"
+        >
           <el-select
             v-model="forms.eares"
             placeholder="Select"
@@ -64,6 +80,7 @@
             <template #append>mm</template>
           </el-input>
         </el-form-item>
+
         <el-form-item label="闄嶉洦鏃堕暱:">
           <el-input
             v-model="forms.duration"
@@ -71,8 +88,9 @@
             placeholder="Please input"
           >
             <template #append>h</template>
-          </el-input></el-form-item
-        >
+          </el-input>
+        </el-form-item>
+
         <el-form-item label="闄嶉洦寮哄害:">
           <el-input
             v-model="forms.intensity"
@@ -82,197 +100,327 @@
             <template #append>mm/h</template>
           </el-input>
         </el-form-item>
-        <el-form-item label="浠跨湡鍙傛暟:"> </el-form-item>
+
+        <el-form-item label="浠跨湡鍙傛暟:"></el-form-item>
       </el-form>
       <div style="display: flex; justify-content: flex-end">
-        <el-button>淇濆瓨鏂规</el-button>
-        <el-button @click="startPlay">寮�濮嬫ā鎷�</el-button>
+        <el-button type="primary" @click="openSaveDialog">淇濆瓨鏂规</el-button>
+        <el-button type="success" @click="startPlay">寮�濮嬫ā鎷�</el-button>
       </div>
+      <!---------------------------- 淇濆瓨鏂规瀵硅瘽妗嗭紙鎺ュ彛鐗堟湰闇�鍒犻櫎锛� -------------------------------->
+      <el-dialog
+        v-model="saveDialogVisible"
+        :title="dialogTitle"
+        width="50%"
+        :before-close="handleClose"
+        custom-class="custom-dialog"
+      >
+        <div class="dialog-content">
+          <p><strong>妯℃嫙绫诲瀷锛�</strong>{{ dialogTitle }}</p>
+          <p v-if="disForm === '琛屾斂鍖哄垝浠跨湡'">
+            <strong>琛屾斂鍖哄煙锛�</strong>{{ forms.eare }}
+          </p>
+          <p v-if="disForm === '閲嶇偣鍖哄煙浠跨湡'">
+            <strong>閲嶇偣鍖哄煙锛�</strong>{{ forms.eares }}
+          </p>
+          <p><strong>闄嶉洦閲忥細</strong>{{ forms.rainfall }} mm</p>
+          <p><strong>闄嶉洦鏃堕暱锛�</strong>{{ forms.duration }} h</p>
+          <p><strong>闄嶉洦寮哄害锛�</strong>{{ forms.intensity }} mm/h</p>
+          <p><strong>涓婁紶鏂囦欢锛�</strong>{{ uploadedFilesText }}</p>
+        </div>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="saveDialogVisible = false">鍙栨秷</el-button>
+            <el-button type="primary" @click="confirmSave">纭畾淇濆瓨</el-button>
+          </span>
+        </template>
+      </el-dialog>
     </div>
   </div>
 </template>
+
 <script setup>
-import { reactive, ref, watch } from "vue";
+import { reactive, ref, watch, inject, computed } from "vue";
+import * as XLSX from "xlsx";
+import Papa from "papaparse";
+import { ElMessage, ElMessageBox } from "element-plus";
 import { initeWaterPrimitiveView } from "@/utils/water";
+import { createSimData } from "@/api/trApi";
 
-const emit = defineEmits(["start", "end"]);
-function endPlay() {
-  emit("end");
-}
+import { useSimStore } from "@/store/simulation";
 
-function startPlay() {
-  initeWaterPrimitiveView();
-  emit("start");
-}
+const simStore = useSimStore();
 
-const value = ref("");
-
-const cityOptions = [
-  {
-    value: "鍖椾含甯�",
-    label: "鍖椾含甯�",
-  },
-  {
-    value: "涓滃煄鍖�",
-    label: "涓滃煄鍖�",
-  },
-  {
-    value: "瑗垮煄鍖�",
-    label: "瑗垮煄鍖�",
-  },
-  {
-    value: "鏈濋槼鍖�",
-    label: "鏈濋槼鍖�",
-  },
-  {
-    value: "娴锋穩鍖�",
-    label: "娴锋穩鍖�",
-  },
-  {
-    value: "涓板彴鍖�",
-    label: "涓板彴鍖�",
-  },
-  {
-    value: "鐭虫櫙灞卞尯",
-    label: "鐭虫櫙灞卞尯",
-  },
-  {
-    value: "闂ㄥご娌熷尯",
-    label: "闂ㄥご娌熷尯",
-  },
-  {
-    value: "鎴垮北鍖�",
-    label: "鎴垮北鍖�",
-  },
-  {
-    value: "閫氬窞鍖�",
-    label: "閫氬窞鍖�",
-  },
-  {
-    value: "椤轰箟鍖�",
-    label: "椤轰箟鍖�",
-  },
-  {
-    value: "鏄屽钩鍖�",
-    label: "鏄屽钩鍖�",
-  },
-  {
-    value: "澶у叴鍖�",
-    label: "澶у叴鍖�",
-  },
-  {
-    value: "鎬�鏌斿尯",
-    label: "鎬�鏌斿尯",
-  },
-  {
-    value: "骞宠胺鍖�",
-    label: "骞宠胺鍖�",
-  },
-  {
-    value: "瀵嗕簯鍖�",
-    label: "瀵嗕簯鍖�",
-  },
-  {
-    value: "寤跺簡鍖�",
-    label: "寤跺簡鍖�",
-  },
-];
-const earesOptions = [
-  {
-    value: "瀛欒儭娌�",
-    label: "瀛欒儭娌�",
-  },
-  {
-    value: "楸兼按娲炲悗娌�",
-    label: "楸兼按娲炲悗娌�",
-  },
-  {
-    value: "浜庡瑗挎矡",
-    label: "浜庡瑗挎矡",
-  },
-  {
-    value: "鍖楁渤娌�",
-    label: "鍖楁渤娌�",
-  },
-  {
-    value: "榫欐硥宄潙",
-    label: "榫欐硥宄潙",
-  },
-];
-
+// 娉ㄥ叆鐖剁粍浠舵彁渚涚殑鏂规硶
+const { startSimulate, endSimulate } = inject("simulateActions");
+const saveDialogVisible = ref(false); // 鎺у埗淇濆瓨鏂规瀵硅瘽妗嗙殑鏄剧ず鐘舵�侊紙鎺ュ彛鐗堟湰鍒犻櫎锛�
+// 琛ㄥ崟鏁版嵁
 const forms = reactive({
+  name: "",
   eare: "鍖椾含甯�",
   eares: "瀛欒儭娌�",
-  rainfall: "50",
-  duration: "5",
-  intensity: "70",
+  rainfall: "",
+  duration: "",
+  intensity: "",
   fileList: [],
 });
 
-function handleRemove(file, uploadFiles) {
-  console.log(file, uploadFiles);
-}
+// 鍩庡競鍜岄噸鐐瑰尯鍩熼�夐」
+const cityOptions = [
+  { value: "鍖椾含甯�", label: "鍖椾含甯�" },
+  { value: "涓滃煄鍖�", label: "涓滃煄鍖�" },
+  { value: "瑗垮煄鍖�", label: "瑗垮煄鍖�" },
+  { value: "鏈濋槼鍖�", label: "鏈濋槼鍖�" },
+  { value: "娴锋穩鍖�", label: "娴锋穩鍖�" },
+  { value: "涓板彴鍖�", label: "涓板彴鍖�" },
+  { value: "鐭虫櫙灞卞尯", label: "鐭虫櫙灞卞尯" },
+  { value: "闂ㄥご娌熷尯", label: "闂ㄥご娌熷尯" },
+  { value: "鎴垮北鍖�", label: "鎴垮北鍖�" },
+  { value: "閫氬窞鍖�", label: "閫氬窞鍖�" },
+  { value: "椤轰箟鍖�", label: "椤轰箟鍖�" },
+  { value: "鏄屽钩鍖�", label: "鏄屽钩鍖�" },
+  { value: "澶у叴鍖�", label: "澶у叴鍖�" },
+  { value: "鎬�鏌斿尯", label: "鎬�鏌斿尯" },
+  { value: "骞宠胺鍖�", label: "骞宠胺鍖�" },
+  { value: "瀵嗕簯鍖�", label: "瀵嗕簯鍖�" },
+  { value: "寤跺簡鍖�", label: "寤跺簡鍖�" },
+];
+const earesOptions = [
+  { value: "瀛欒儭娌�", label: "瀛欒儭娌�" },
+  { value: "楸兼按娲炲悗娌�", label: "楸兼按娲炲悗娌�" },
+  { value: "浜庡瑗挎矡", label: "浜庡瑗挎矡" },
+  { value: "鍖楁渤娌�", label: "鍖楁渤娌�" },
+  { value: "榫欐硥宄潙", label: "榫欐硥宄潙" },
+];
 
-function handlePreview(uploadFile) {
-  console.log(uploadFile);
-}
-
-function handleExceed(files, uploadFiles) {
-  ElMessage.warning(
-    `The limit is 3, you selected ${files.length} files this time, add up to ${
-      files.length + uploadFiles.length
-    } totally`
-  );
-}
-const beforeUpload = (file) => {
-  const allowedTypes = [
-    "application/vnd.ms-excel",
-    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
-    "text/csv",
-    "application/csv",
-    "text/x-csv",
-    "application/x-csv",
-    "text/comma-separated-values",
-    "text/x-comma-separated-values",
-  ];
-
-  const isAllowed = allowedTypes.includes(file.type);
-  const extension = file.name.split(".").pop().toLowerCase();
-  const isExtensionValid = ["xls", "xlsx", "csv"].includes(extension);
-
-  if (!isAllowed || !isExtensionValid) {
-    ElMessage.error("鍙兘涓婁紶 Excel (.xls, .xlsx) 鎴� CSV 鏂囦欢");
-    return false; // 闃绘涓婁紶
-  }
-
-  return true; // 鍏佽涓婁紶
-};
-
-function beforeRemove(uploadFile, uploadFiles) {
-  return ElMessageBox.confirm(
-    `Cancel the transfer of ${uploadFile.name} ?`
-  ).then(
-    () => true,
-    () => false
-  );
-}
-
-const disForm = ref("");
-
-// 瀹氫箟 Props
-const props = defineProps({
-  clickValue: String,
+// 璁$畻灞炴�э細鑾峰彇瀵硅瘽妗嗘爣棰�
+const dialogTitle = computed(() => {
+  return simStore.selectTab === "琛屾斂鍖哄垝浠跨湡"
+    ? "琛屾斂鍖哄垝浠跨湡"
+    : "閲嶇偣鍖哄煙浠跨湡";
 });
 
-// 鐩戝惉 Props 鍙樺寲
-watch(
-  () => props.clickValue,
-  (newValue) => {
-    disForm.value = newValue || "琛屾斂鍖哄垝浠跨湡";
-  },
-  { immediate: true, deep: true }
-);
+// 璁$畻灞炴�э細鑾峰彇涓婁紶鏂囦欢鐨勫悕绉板垪琛�
+const uploadedFilesText = computed(() => {
+  return forms.fileList.map((file) => file.name).join(", ") || "鏃�";
+});
+
+////////////////////////////////////// 鎺ュ彛鐗堟湰闇�鍒犻櫎//////////////////////////////////////
+// 鎵撳紑淇濆瓨鏂规瀵硅瘽妗�
+const openSaveDialog = () => {
+  if (
+    !forms.rainfall ||
+    !forms.duration ||
+    !forms.intensity ||
+    (simStore.selectTab === "琛屾斂鍖哄垝浠跨湡" && !forms.eare) ||
+    (simStore.selectTab === "閲嶇偣鍖哄煙浠跨湡" && !forms.eares)
+  ) {
+    ElMessage.warning("璇峰厛濉啓鎵�鏈夊繀濉」");
+    return;
+  }
+  saveDialogVisible.value = true;
+}
+const handleClose = () => {
+  saveDialogVisible.value = false;
+};
+
+// 纭淇濆瓨
+const confirmSave = () => {
+  console.log("淇濆瓨鏂规鎴愬姛", {
+    妯℃嫙绫诲瀷: dialogTitle.value,
+    琛屾斂鍖哄煙: simStore.selectTab === "琛屾斂鍖哄垝浠跨湡" ? forms.eare : null,
+    閲嶇偣鍖哄煙: simStore.selectTab === "閲嶇偣鍖哄煙浠跨湡" ? forms.eares : null,
+    闄嶉洦閲�: `${forms.rainfall} mm`,
+    闄嶉洦鏃堕暱: `${forms.duration} h`,
+    闄嶉洦寮哄害: `${forms.intensity} mm/h`,
+    涓婁紶鏂囦欢: forms.fileList.map((file) => file.name),
+  });
+  ElMessage.success("鏂规宸蹭繚瀛�");
+  saveDialogVisible.value = false;
+  resetForm();
+};
+////////////////////////////////////// 缁撴潫鍒犻櫎//////////////////////////////////////
+
+//////////////////////////////////鎺ュ彛鐗堟湰鍚敤//////////////////////////////////
+// const isLoading = ref(false);
+// // 淇濆瓨鏂规
+// const openSaveDialog = () => {
+//   if (
+//     !forms.rainfall ||
+//     !forms.duration ||
+//     !forms.intensity ||
+//     (simStore.selectTab === "琛屾斂鍖哄垝浠跨湡" && !forms.eare) ||
+//     (simStore.selectTab === "閲嶇偣鍖哄煙浠跨湡" && !forms.eares)
+//   ) {
+//     ElMessage.warning("璇峰厛濉啓鎵�鏈夊繀濉」");
+//     return;
+//   }
+//   ElMessageBox.confirm("纭畾瑕佷繚瀛樺綋鍓嶆柟妗堝悧?", dialogTitle.value, {
+//     confirmButtonText: "纭畾",
+//     cancelButtonText: "鍙栨秷",
+//     type: "warning",
+//   })
+//     .then(confirmSave)
+//     .catch(() => {
+//       ElMessage({
+//         type: "info",
+//         message: "宸插彇娑堜繚瀛�",
+//       });
+//     });
+// };
+// const confirmSave = async () => {
+//   if (isLoading.value) {
+//     ElMessage.warning("姝e湪淇濆瓨锛岃绋嶅��...");
+//     return; // 闃叉閲嶅鎻愪氦
+//   }
+//   isLoading.value = true; // 寮�濮嬪姞杞界姸鎬�
+//   try {
+//     await simStore.createSimulation(forms); // 璋冪敤 Store 涓殑淇濆瓨鏂规硶
+//     ElMessage.success("淇濆瓨鎴愬姛");
+//     saveDialogVisible.value = true; // 鏄剧ず淇濆瓨瀵硅瘽妗嗭紙濡傛灉闇�瑕侊級
+//   } catch (error) {
+//     console.error("淇濆瓨澶辫触:", error);
+//     ElMessage.error("淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯");
+//   } finally {
+//     isLoading.value = false; // 缁撴潫鍔犺浇鐘舵��
+//   }
+// };
+//////////////////////////////////鎺ュ彛鐗堟湰鍚敤//////////////////////////////////
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+  forms.eare = "鍖椾含甯�";
+  forms.eares = "瀛欒儭娌�";
+  forms.rainfall = "";
+  forms.duration = "";
+  forms.intensity = "";
+  forms.fileList = [];
+};
+
+// 鏂囦欢鍙樺寲鏃惰Е鍙戣В鏋�
+const handleFileChange = (file) => {
+  const reader = new FileReader();
+  reader.onload = (e) => {
+    const data = e.target.result;
+    if (file.name.endsWith(".csv")) {
+      parseCSV(data);
+    } else {
+      parseExcel(data);
+    }
+  };
+  reader.readAsArrayBuffer(file.raw);
+};
+
+// 瑙f瀽CSV鏂囦欢
+const parseCSV = (data) => {
+  Papa.parse(new TextDecoder("utf-8").decode(data), {
+    complete: (results) => {
+      if (results.data.length > 0) {
+        processData(results.data);
+      }
+    },
+    header: true,
+    skipEmptyLines: true,
+  });
+};
+
+// 瑙f瀽Excel鏂囦欢
+const parseExcel = (data) => {
+  const workbook = XLSX.read(data, { type: "array" });
+  const firstSheetName = workbook.SheetNames[0];
+  const worksheet = workbook.Sheets[firstSheetName];
+  const jsonData = XLSX.utils.sheet_to_json(worksheet);
+  processData(jsonData);
+};
+
+// 澶勭悊鏁版嵁
+const processData = (data) => {
+  if (data.length === 0) return;
+
+  const tableColumns = Object.keys(data[0]);
+
+  // 绗竴鍒楋細鏃堕棿
+  const firstTime = parseDateTime(data[0][tableColumns[0]]);
+  const lastTime = parseDateTime(data[data.length - 1][tableColumns[0]]);
+  const timeDuration = Math.floor((lastTime - firstTime) / 1000);
+  forms.duration = (timeDuration / 3600).toFixed(2); // 鏇存柊闄嶉洦鏃堕暱
+
+  // 绗簩鍒楋細闄嶉洦寮哄害
+  const maxValue = Math.max(
+    ...data.map((row) => {
+      const value = parseFloat(row[tableColumns[1]]);
+      return isNaN(value) ? -Infinity : value;
+    })
+  ).toFixed(2);
+  forms.intensity = maxValue; // 鏇存柊闄嶉洦寮哄害
+
+  // 绗笁鍒楋細绱闄嶉洦閲�
+  const lastValue = data[data.length - 1][tableColumns[2]];
+  forms.rainfall = lastValue; // 鏇存柊闄嶉洦閲�
+};
+
+// 瑙f瀽鏃ユ湡鏃堕棿
+const parseDateTime = (dateString) => {
+  if (typeof dateString === "number") {
+    const parsedDate = XLSX.SSF.parse_date_code(dateString);
+    if (parsedDate) {
+      return new Date(
+        parsedDate.y,
+        parsedDate.m - 1,
+        parsedDate.d,
+        parsedDate.H || 0,
+        parsedDate.M || 0,
+        parsedDate.S || 0
+      ).getTime();
+    }
+  }
+
+  const parsedDate = new Date(dateString);
+  if (!isNaN(parsedDate.getTime())) {
+    return parsedDate.getTime();
+  }
+
+  const parts = dateString.split(/[/\s:]/);
+  if (parts.length >= 6) {
+    const year = parseInt(parts[0], 10);
+    const month = parseInt(parts[1], 10) - 1;
+    const day = parseInt(parts[2], 10);
+    const hour = parseInt(parts[3], 10) || 0;
+    const minute = parseInt(parts[4], 10) || 0;
+    const second = parseInt(parts[5], 10) || 0;
+
+    const date = new Date(year, month, day, hour, minute, second);
+    if (!isNaN(date.getTime())) {
+      return date.getTime();
+    }
+  }
+
+  console.warn(`鏃犳硶瑙f瀽鏃ユ湡: ${dateString}`);
+  return NaN;
+};
+
+const handleExceed = () => {
+  ElMessage.warning("姣忔鍙兘涓婁紶涓�涓枃浠�");
+};
+
+const beforeUpload = (file) => {
+  const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls");
+  const isCSV = file.name.endsWith(".csv");
+  if (!isExcel && !isCSV) {
+    ElMessage.error("鍙兘涓婁紶Excel鎴朇SV鏂囦欢");
+    return false;
+  }
+  return true;
+};
+
+
+// 寮�濮嬫ā鎷�
+function startPlay() {
+  initeWaterPrimitiveView();
+  startSimulate();
+}
 </script>
+
 <style lang="less" scoped>
 .forms {
   background: url("@/assets/img/screen/leftbg.png");

--
Gitblit v1.9.3