From 00e645137f321079579ec49b876c511d410abfbf Mon Sep 17 00:00:00 2001 From: hcong <1050828145@qq.com> Date: 星期五, 27 十二月 2024 14:37:40 +0800 Subject: [PATCH] 1. 新增aod数据导入界面 2. 新增监测数据导入界面 --- src/views/satellitetelemetry/component/SatelliteImport.vue | 225 ++++++++++++++++++++++ src/api/gridApi.js | 70 ++++++ src/components.d.ts | 7 src/views/HomePage.vue | 20 ++ src/views/satellitetelemetry/component/AODImport.vue | 227 ++++++++++++++++++++++ 5 files changed, 542 insertions(+), 7 deletions(-) diff --git a/src/api/gridApi.js b/src/api/gridApi.js index 6eb09f2..696411f 100644 --- a/src/api/gridApi.js +++ b/src/api/gridApi.js @@ -1,5 +1,6 @@ import { $http } from './index'; +import { Base64 } from 'js-base64'; /** * 鍗槦閬ユ祴缃戞牸鐩稿叧鎺ュ彛API */ @@ -44,6 +45,23 @@ .then((res) => res.data); }, + /** + * 鑾峰彇缃戞牸缁勪笅鐨勯仴娴媋od + * @param {*} groupId + * @param {*} dataTime + * @returns + */ + fetchGridAod(groupId, dataTime) { + return $http + .get(`air/satellite/grid/aod`, { + params: { + groupId, + dataTime + } + }) + .then((res) => res.data); + }, + fetchGridDataDetail(dataId, groupId, cellId) { return $http .get(`air/satellite/grid/data/detail`, { @@ -54,5 +72,55 @@ } }) .then((res) => res.data); + }, + downloadTemplate() { + return $http + .get(`air/satellite/import/grid/data/download/template`, { + responseType: 'blob' + }) + .then((res) => { + const name = Base64.decode(res.headers.get('fileName')); + const blob = new Blob([res.data], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = name; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + }); + }, + importData(dataForm) { + return $http + .post(`air/satellite/import/grid/data`, dataForm) + .then((res) => res.data); + }, + downloadAODTemplate() { + return $http + .get(`air/satellite/import/grid/aod/download/template`, { + responseType: 'blob' + }) + .then((res) => { + const name = Base64.decode(res.headers.get('fileName')); + const blob = new Blob([res.data], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = name; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + }); + }, + importAOD(dataForm) { + return $http + .post(`air/satellite/import/grid/aod`, dataForm) + .then((res) => res.data); } -}; +}; \ No newline at end of file diff --git a/src/components.d.ts b/src/components.d.ts index 6d7e434..f0ccb89 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -33,19 +33,14 @@ ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElInput: typeof import('element-plus/es')['ElInput'] - ElInputNumber: (typeof import('element-plus/es'))['ElInputNumber'] ElOption: typeof import('element-plus/es')['ElOption'] - ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] - ElRadio: typeof import('element-plus/es')['ElRadio'] - ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] - ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] - ElSlider: typeof import('element-plus/es')['ElSlider'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElText: typeof import('element-plus/es')['ElText'] + ElUpload: typeof import('element-plus/es')['ElUpload'] FactorCheckbox: typeof import('./components/monitor/FactorCheckbox.vue')['default'] FactorLegend: typeof import('./components/monitor/FactorLegend.vue')['default'] FactorRadio: typeof import('./components/monitor/FactorRadio.vue')['default'] diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue index 49b914b..99df365 100644 --- a/src/views/HomePage.vue +++ b/src/views/HomePage.vue @@ -10,14 +10,23 @@ <!-- <MapLocation></MapLocation> --> <SceneSearch></SceneSearch> <MapScene></MapScene> + <el-button @click="satelliteImportVisible = !satelliteImportVisible" type="primary" class="el-button-custom satellite-right-top p-events-auto">鐩戞祴鏁版嵁瀵煎叆</el-button> + <el-button @click="aodImportVisible = !aodImportVisible" type="primary" class="el-button-custom aod-right-top p-events-auto">AOD鏁版嵁瀵煎叆</el-button> </el-row> <!-- <CoreMenu></CoreMenu> --> <router-view></router-view> </div> + <SatelliteImport v-model="satelliteImportVisible"></SatelliteImport> + <AODImport v-model="aodImportVisible"></AODImport> </template> <script setup> // import SatelliteTelemetry from '@/views/satellitetelemetry/SatelliteTelemetry.vue'; +import { ref } from 'vue'; +import SatelliteImport from './satellitetelemetry/component/SatelliteImport.vue'; +import AODImport from './satellitetelemetry/component/AODImport.vue'; +const satelliteImportVisible = ref(false) +const aodImportVisible = ref(false) </script> <style scoped> @@ -37,8 +46,19 @@ .dropdown-wrap { /* background-color: aliceblue; */ position: absolute; + width: 99.5vw; top: 10px; left: 2px; gap: 4px; } +.satellite-right-top { + width: 120px; + position: absolute; + right: 0px; +} + +.aod-right-top { + position: absolute; + right: 124px; +} </style> diff --git a/src/views/satellitetelemetry/component/AODImport.vue b/src/views/satellitetelemetry/component/AODImport.vue new file mode 100644 index 0000000..34167b4 --- /dev/null +++ b/src/views/satellitetelemetry/component/AODImport.vue @@ -0,0 +1,227 @@ +<template> + <CardDialog title="AOD鏁版嵁瀵煎叆" :model-value="modelValue" :width="420" @changed="handleChange"> + <div class="download"> + <el-button @click="downloadTemplate" type="primary" class="el-button-custom" size="small" + v-loading="downloadLoading">涓嬭浇妯℃澘</el-button> + </div> + <el-form :model="formObj" :rules="rules" ref="formRef" label-position="right" label-width="60px"> + <el-form-item label="鍖哄煙"> + <OptionLocation2 :level="3" :initValue="true" :checkStrictly="false" :allOption="true" v-model="location" + width="200"> + </OptionLocation2> + </el-form-item> + <OptionGridGroup ref="gridGroupRef" v-model="gridGroup"></OptionGridGroup> + <el-form-item label="鏃堕棿" prop="dateTime"> + <el-date-picker v-model="formObj.dateTime" type="date" placeholder="閫夋嫨鏃堕棿" size="small" :clearable="false" /> + </el-form-item> + <el-form-item label=""> + <el-row> + <el-col> + <label><el-checkbox v-model="formObj.update" label="" size="small" + :disabled="hasGridAod == undefined || hasGridAod == false" />鍚屾剰</label> + </el-col> + <el-col> + <el-text class="mx-1" type="danger" v-if="hasGridAod == true">褰撴棩AOD鏁版嵁宸插瓨鍦紝璇峰嬀閫夊悓鎰忓悗杩涜鏁版嵁鏇存柊瑕嗙洊</el-text> + <el-text class="mx-1" type="success" v-else-if="hasGridAod == false">褰撴棩AOD鏃犳暟鎹紝鍙柊澧炲鍏�</el-text> + </el-col> + </el-row> + </el-form-item> + <el-form-item> + <el-upload v-model:file-list="formObj.file" accept=".xlsx" :limit="1" :auto-upload="false" ref="uploadRef" + :on-exceed="handleUploadExceed" :on-change="handleUploadChange"> + <template #trigger> + <el-button :disabled="formObj.update == undefined || (hasGridAod == true && formObj.update == false)" + type="primary" class="el-button-custom select-file-button" size="small" accept=".xlsx">閫夋嫨鏂囦欢</el-button> + </template> + <el-button @click="onSubmit" type="primary" class="el-button-custom import-button" size="small" + :disabled="!formObj.file || formObj.file.length == 0" v-loading="loading"> + 瀵煎叆 + </el-button> + </el-upload> + </el-form-item> + <el-form-item> + <el-text class="mx-1" type="danger">{{ errorTipMsg }}</el-text> + <el-text class="mx-1" type="success">{{ successTipMsg }}</el-text> + </el-form-item> + </el-form> + </CardDialog> +</template> +<script setup> +import { ref, watch, defineProps, defineEmits } from 'vue'; +import gridApi from '@/api/gridApi'; +import { dayjs, ElMessage } from 'element-plus'; +import { useFormConfirm } from '@/composables/formConfirm'; + +const gridGroupRef = ref(null); +const uploadRef = ref(null); +// 鏄惁鏈夋暟鎹竷灏旂被鍨� 榛樿涓虹┖ +const hasGridAod = ref(null); +const location = ref({}); +const gridGroup = ref({}); +// 瀵煎叆鏃跺睍绀哄湪瀵煎叆鎸夐挳涓婄殑鍔犺浇 +const loading = ref(false); +// 涓嬭浇妯℃澘鏃跺睍绀哄湪涓嬭浇鎸夐挳涓婄殑鍔犺浇 +const downloadLoading = ref(false); +// 鍦ㄥ鍏ユ寜閽笅鏂癸紙鐣岄潰鐨勪笅闈級閿欒鍜屾纭俊鎭� +const errorTipMsg = ref(''); +const successTipMsg = ref(''); +const rules = { + dateTime: [{ required: true, message: '鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }] +}; + +const props = defineProps({ + modelValue: Boolean +}); + +const emit = defineEmits(['update:modelValue']); + +const handleChange = (value) => { + emit('update:modelValue', value); +}; + +const downloadTemplate = () => { + downloadLoading.value = true + gridApi.downloadAODTemplate().then(res => { + downloadLoading.value = false + }).catch(e => { + downloadLoading.value = false + }); +}; + +// 閫氳繃缃戞牸缁勫拰鏃堕棿 鏌ヨ 鍦ㄨ繖涓や釜鍙傛暟鏉′欢涓嬫槸鍚︽湁缃戞牸鏁版嵁锛屽苟鎻愮ず鍦ㄧ晫闈腑鏈夋垨鑰呮病鏈� +const checkEmpty = () => { + gridApi.fetchGridAod(gridGroup.value.id, dayjs(formObj.value.dateTime).format('YYYY-MM-DD HH:mm:ss')).then(res => { + if (res.data && res.data.length > 0) { + hasGridAod.value = true; + } else { + formObj.value.update = false + hasGridAod.value = false; + } + }) +}; +const handleImportClick = () => { + loading.value = true; + const isUpdate = formObj.value.update ? formObj.value.update : false; + + const formData = new FormData(); + // 鏂囦欢杞崲涓轰簩杩涘埗 + const reader = new FileReader(); + reader.readAsArrayBuffer(formObj.value.file[0].raw); + reader.onload = async (theFile) => { + const binary = new Blob([theFile.target.result], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + formData.append('excel', binary); + formData.append('groupId', gridGroup.value.id); + formData.append( + 'dateTime', + dayjs(formObj.value.dateTime).format('YYYY-MM-DD HH:mm:ss') + ); + formData.append('update', isUpdate); + gridApi + .importAOD(formData) + .then((res) => { + resetApiTipMsg() + loading.value = false; + if (res && res.success == true) { + // 瀵煎叆鎴愬姛锛�1.瀵煎叆鎴栬�呰鐩栨垚鍔燂紝鏄惁涓虹┖鐘舵�佹敼鍙樹簡锛岄噸鏂版鏌� + checkEmpty() + successTipMsg.value = res.data.result + } else { + errorTipMsg.value = res.message + } + }).catch(e => { + loading.value = false; + errorTipMsg.value = e + }) + } +}; +const resetApiTipMsg = () => { + successTipMsg.value = '' + errorTipMsg.value = '' +}; +// 褰撻�夋嫨鏂囦欢鍚庯細 1. 閲嶇疆鎻愮ず淇℃伅锛岄槻姝㈣瀵� 2.瀵规枃浠剁被鍨嬬殑妫�鏌� +const handleUploadChange = (file, files) => { + resetApiTipMsg() + const fileType = file.raw.type; + // 妫�鏌ユ枃浠剁被鍨嬫槸鍚︿负 'xlsx' + if (fileType !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { + ElMessage({ + message: '鏂囦欢绫诲瀷閿欒锛岃閲嶆柊涓婁紶xlsx绫诲瀷鏂囦欢', + type: 'error' + }) + files.splice(0, 1); // 闃绘涓婁紶 + } +}; +// 鏂伴�夋嫨鏂囦欢鏇挎崲鏃ф枃浠� +const handleUploadExceed = (files) => { + const file = files[0] + uploadRef.value.clearFiles() + uploadRef.value.handleStart(file) +}; +const { formObj, formRef, edit, onSubmit, onCancel } = useFormConfirm({ + submit: { + do: handleImportClick + }, + cancel: { + do: () => { + + } + } +}); + + + +watch(location, (nv, ov) => { + if (nv != ov) { + resetApiTipMsg() + const area = { + provinceCode: nv.pCode, + provinceName: nv.pName, + cityCode: nv.cCode, + cityName: nv.cName, + districtCode: nv.dCode, + districtName: nv.dName, + townCode: nv.tCode, + townName: nv.tName + }; + gridGroupRef.value.fetchGridGroup(area); + } +}); + +watch(gridGroup, (nv) => { + if (nv && Object.keys(nv).length === 0 && formObj.value.dateTime && Object.keys(formObj.value.dateTime).length === 0) { + checkEmpty() + } +}, { deep: true }); + +watch(formObj.value, (nv) => { + if (nv.dateTime && gridGroup.value) { + checkEmpty() + } +}, { deep: true }); +</script> +<style scoped> +.download { + display: flex; + justify-content: flex-end; +} + +.click_to_show-btn { + z-index: 1000; +} + +.select-file-button { + /* margin-left: 5px; */ +} + +.import-button { + margin-left: 20px; +} + +::v-deep .el-date-editor { + width: 200px !important; +} + +::v-deep .el-select { + width: 200px !important; +} +</style> \ No newline at end of file diff --git a/src/views/satellitetelemetry/component/SatelliteImport.vue b/src/views/satellitetelemetry/component/SatelliteImport.vue new file mode 100644 index 0000000..eb962bd --- /dev/null +++ b/src/views/satellitetelemetry/component/SatelliteImport.vue @@ -0,0 +1,225 @@ +<template> + <CardDialog title="鐩戞祴鏁版嵁瀵煎叆" :model-value="modelValue" :width="420" @changed="handleChange"> + <div class="download"> + <el-button @click="downloadTemplate" type="primary" class="el-button-custom" size="small" + v-loading="downloadLoading">涓嬭浇妯℃澘</el-button> + </div> + <el-form :model="formObj" :rules="rules" ref="formRef" label-position="right" label-width="60px"> + <el-form-item label="鍖哄煙"> + <OptionLocation2 :level="3" :initValue="true" :checkStrictly="false" :allOption="true" v-model="location" + width="200"> + </OptionLocation2> + </el-form-item> + <OptionGridGroup ref="gridGroupRef" v-model="gridGroup"></OptionGridGroup> + <el-form-item label="鏃堕棿" prop="dateTime"> + <el-date-picker v-model="formObj.dateTime" type="date" placeholder="閫夋嫨鏃堕棿" size="small" :clearable="false"/> + </el-form-item> + <el-form-item label=""> + <el-row> + <el-col> + <label><el-checkbox v-model="formObj.update" label="" size="small" + :disabled="hasGridData == undefined || hasGridData == false" />鍚屾剰</label> + </el-col> + <el-col> + <el-text class="mx-1" type="danger" v-if="hasGridData == true">褰撴棩閬ユ祴鏁版嵁宸插瓨鍦紝璇峰嬀閫夊悓鎰忓悗杩涜鏁版嵁鏇存柊瑕嗙洊</el-text> + <el-text class="mx-1" type="success" v-else-if="hasGridData == false">褰撴棩閬ユ祴鏃犳暟鎹紝鍙柊澧炲鍏�</el-text> + </el-col> + </el-row> + </el-form-item> + <el-form-item> + <el-upload v-model:file-list="formObj.file" accept=".xlsx" :limit="1" :auto-upload="false" ref="uploadRef" + :on-exceed="handleUploadExceed" :on-change="handleUploadChange"> + <template #trigger> + <el-button :disabled="formObj.update == undefined || (hasGridData == true && formObj.update == false)" + type="primary" class="el-button-custom select-file-button" size="small" accept=".xlsx">閫夋嫨鏂囦欢</el-button> + </template> + <el-button @click="onSubmit" type="primary" class="el-button-custom import-button" size="small" :disabled="!formObj.file || formObj.file.length == 0" + v-loading="loading"> + 瀵煎叆 + </el-button> + </el-upload> + </el-form-item> + <el-form-item> + <el-text class="mx-1" type="danger">{{ errorTipMsg }}</el-text> + <el-text class="mx-1" type="success">{{ successTipMsg }}</el-text> + </el-form-item> + </el-form> + </CardDialog> +</template> +<script setup> +import { ref, watch, defineProps, defineEmits } from 'vue'; +import gridApi from '@/api/gridApi'; +import { dayjs, ElMessage } from 'element-plus'; +import { useFormConfirm } from '@/composables/formConfirm'; + +const gridGroupRef = ref(null); +const uploadRef = ref(null); +// 鏄惁鏈夋暟鎹竷灏旂被鍨� 榛樿涓虹┖ +const hasGridData = ref(null); +const location = ref({}); +const gridGroup = ref({}); +// 瀵煎叆鏃跺睍绀哄湪瀵煎叆鎸夐挳涓婄殑鍔犺浇 +const loading = ref(false); +// 涓嬭浇妯℃澘鏃跺睍绀哄湪涓嬭浇鎸夐挳涓婄殑鍔犺浇 +const downloadLoading = ref(false); +// 鍦ㄥ鍏ユ寜閽笅鏂癸紙鐣岄潰鐨勪笅闈級閿欒鍜屾纭俊鎭� +const errorTipMsg = ref(''); +const successTipMsg = ref(''); +const rules = { + dateTime: [{ required: true, message: '鏃堕棿涓嶈兘涓虹┖', trigger: 'blur' }], +}; +const props = defineProps({ + modelValue: Boolean +}); + +const resetApiTipMsg = () => { + successTipMsg.value = '' + errorTipMsg.value = '' +}; + +const emit = defineEmits(['update:modelValue']); + +const handleChange = (value) => { + emit('update:modelValue', value); +}; + +const downloadTemplate = () => { + downloadLoading.value = true + gridApi.downloadTemplate().then(res => { + downloadLoading.value = false + }).catch(e => { + downloadLoading.value = false + }); +}; +// 閫氳繃缃戞牸缁勫拰鏃堕棿 鏌ヨ 鍦ㄨ繖涓や釜鍙傛暟鏉′欢涓嬫槸鍚︽湁缃戞牸鏁版嵁锛屽苟鎻愮ず鍦ㄧ晫闈腑鏈夋垨鑰呮病鏈� +const checkEmpty = () => { + gridApi.fetchGridData(gridGroup.value.id, dayjs(formObj.value.dateTime).format('YYYY-MM-DD HH:mm:ss')).then(res => { + if (res.data && res.data.length > 0) { + hasGridData.value = true; + } else { + formObj.value.update = false + hasGridData.value = false; + } + }) +}; +const handleImportClick = () => { + loading.value = true; + const isUpdate = formObj.value.update ? formObj.value.update : false; + const type = 0; + + const formData = new FormData(); + // 鏂囦欢杞崲涓轰簩杩涘埗 + const reader = new FileReader(); + reader.readAsArrayBuffer(formObj.value.file[0].raw); + reader.onload = async (theFile) => { + const binary = new Blob([theFile.target.result], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + formData.append('excel', binary); + formData.append('groupId', gridGroup.value.id); + formData.append('type', type); + formData.append( + 'dateTime', + dayjs(formObj.value.dateTime).format('YYYY-MM-DD HH:mm:ss') + ); + formData.append('update', isUpdate); + gridApi + .importData(formData) + .then((res) => { + resetApiTipMsg() + loading.value = false; + if (res && res.success == true) { + // 瀵煎叆鎴愬姛锛�1.瀵煎叆鎴栬�呰鐩栨垚鍔燂紝鏄惁涓虹┖鐘舵�佹敼鍙樹簡锛岄噸鏂版鏌� + checkEmpty() + successTipMsg.value = res.data.result + } else { + errorTipMsg.value = res.message + } + }).catch(e => { + loading.value = false; + errorTipMsg.value = e + }) + } +}; +// 褰撻�夋嫨鏂囦欢鍚庯細 1. 閲嶇疆鎻愮ず淇℃伅锛岄槻姝㈣瀵� 2.瀵规枃浠剁被鍨嬬殑妫�鏌� +const handleUploadChange = (file, files) => { + resetApiTipMsg() + const fileType = file.raw.type; + // 妫�鏌ユ枃浠剁被鍨嬫槸鍚︿负 'xlsx' + if (fileType !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { + ElMessage({ + message: '鏂囦欢绫诲瀷閿欒锛岃閲嶆柊涓婁紶xlsx绫诲瀷鏂囦欢', + type: 'error' + }) + files.splice(0, 1); // 闃绘涓婁紶 + } +}; +// 鏂伴�夋嫨鏂囦欢鏇挎崲鏃ф枃浠� +const handleUploadExceed = (files) => { + const file = files[0] + uploadRef.value.clearFiles() + uploadRef.value.handleStart(file) +}; +const { formObj, formRef, edit, onSubmit, onCancel } = useFormConfirm({ + submit: { + do: handleImportClick + }, + cancel: { + do: () => { + + } + } +}); +watch(location, (nv, ov) => { + if (nv != ov) { + resetApiTipMsg() + const area = { + provinceCode: nv.pCode, + provinceName: nv.pName, + cityCode: nv.cCode, + cityName: nv.cName, + districtCode: nv.dCode, + districtName: nv.dName, + townCode: nv.tCode, + townName: nv.tName + }; + gridGroupRef.value.fetchGridGroup(area); + } +}); +// 褰撶綉鏍肩粍鍜屾椂闂撮兘涓嶄负绌� 骞朵笖 鏈変竴涓潯浠舵敼鍙樺悗閲嶆柊妫�鏌ユ槸鍚︽湁缃戞牸鏁版嵁 +watch(gridGroup, (nv) => { + if (nv && Object.keys(nv).length === 0 && formObj.value.dateTime && Object.keys(formObj.value.dateTime).length === 0) { + checkEmpty() + } +}, { deep: true }); + +watch(formObj, (nv) => { + if (nv.dateTime && gridGroup.value) { + checkEmpty() + } +}, { deep: true }); +</script> +<style scoped> +.download { + display: flex; + justify-content: flex-end; +} + +.select-file-button { + /* margin-left: 5px; */ +} + +.import-button { + margin-left: 20px; +} + +.click_to_show-btn { + z-index: 1000; +} + +::v-deep .el-date-editor { + width: 200px !important; +} + +::v-deep .el-select { + width: 200px !important; +} +</style> -- Gitblit v1.9.3