From 58b4e83e8079146007873d7ac40d76b21cbe3340 Mon Sep 17 00:00:00 2001 From: guonan <guonan201020@163.com> Date: 星期二, 15 四月 2025 11:13:57 +0800 Subject: [PATCH] 解析表格文件以及方案保存合并 --- src/views/left/CitySim.vue | 414 +++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 251 insertions(+), 163 deletions(-) diff --git a/src/views/left/CitySim.vue b/src/views/left/CitySim.vue index 788cb29..2c489ca 100644 --- a/src/views/left/CitySim.vue +++ b/src/views/left/CitySim.vue @@ -22,16 +22,15 @@ /> </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" + :auto-upload="false" + :multiple="false" + :on-change="handleFileChange" + :limit="1" :on-exceed="handleExceed" :before-upload="beforeUpload" accept=".xlsx,.xls,.csv" @@ -40,6 +39,7 @@ <template #append>mm/h</template> </el-upload> </el-form-item> + <el-form-item label="閲嶇偣鍖哄煙" v-if="disForm == '閲嶇偣鍖哄煙浠跨湡'"> <el-select v-model="forms.eares" @@ -64,6 +64,7 @@ <template #append>mm</template> </el-input> </el-form-item> + <el-form-item label="闄嶉洦鏃堕暱:"> <el-input v-model="forms.duration" @@ -71,8 +72,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,183 +84,263 @@ <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, inject } from "vue"; -import { initeWaterPrimitiveView } from "@/utils/water"; +import { reactive, ref, watch, inject, computed } from "vue"; +import * as XLSX from "xlsx"; +import Papa from "papaparse"; +import { ElMessage } from "element-plus"; // 娉ㄥ叆鐖剁粍浠舵彁渚涚殑鏂规硶 const { startSimulate, endSimulate } = inject("simulateActions"); - -// const emit = defineEmits(["start", "end"]); -// function endPlay() { -// emit("end"); -// } - -function startPlay() { - initeWaterPrimitiveView(); - startSimulate(); -} - -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 saveDialogVisible = ref(false); // 鎺у埗淇濆瓨鏂规瀵硅瘽妗嗙殑鏄剧ず鐘舵�� +// 琛ㄥ崟鏁版嵁 const forms = reactive({ 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); -} +// 璁$畻灞炴�э細鑾峰彇瀵硅瘽妗嗘爣棰� +const dialogTitle = computed(() => { + return disForm.value === "琛屾斂鍖哄垝浠跨湡" ? "琛屾斂鍖哄垝浠跨湡" : "閲嶇偣鍖哄煙浠跨湡"; +}); -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 uploadedFilesText = computed(() => { + return forms.fileList.map((file) => file.name).join(", ") || "鏃�"; +}); - 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; // 闃绘涓婁紶 +// 鎵撳紑淇濆瓨鏂规瀵硅瘽妗� +const openSaveDialog = () => { + if ( + !forms.rainfall || + !forms.duration || + !forms.intensity || + (disForm.value === "琛屾斂鍖哄垝浠跨湡" && !forms.eare) || + (disForm.value === "閲嶇偣鍖哄煙浠跨湡" && !forms.eares) + ) { + ElMessage.warning("璇峰厛濉啓鎵�鏈夊繀濉」"); + return; } - - return true; // 鍏佽涓婁紶 + saveDialogVisible.value = true; }; -function beforeRemove(uploadFile, uploadFiles) { - return ElMessageBox.confirm( - `Cancel the transfer of ${uploadFile.name} ?` - ).then( - () => true, - () => false - ); -} +// 鍏抽棴淇濆瓨鏂规瀵硅瘽妗� +const handleClose = () => { + saveDialogVisible.value = false; +}; + +// 纭淇濆瓨 +const confirmSave = () => { + console.log("淇濆瓨鏂规鎴愬姛", { + 妯℃嫙绫诲瀷: dialogTitle.value, + 琛屾斂鍖哄煙: disForm.value === "琛屾斂鍖哄垝浠跨湡" ? forms.eare : null, + 閲嶇偣鍖哄煙: disForm.value === "閲嶇偣鍖哄煙浠跨湡" ? 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 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; +}; const disForm = ref(""); @@ -275,7 +357,13 @@ }, { immediate: true, deep: true } ); + +// 寮�濮嬫ā鎷� +function startPlay() { + startSimulate(); +} </script> + <style lang="less" scoped> .forms { background: url("@/assets/img/screen/leftbg.png"); -- Gitblit v1.9.3