Riku
2025-01-01 f4b965dbad0b4f5693b6271232ef4120ba39ddae
Merge remote-tracking branch 'origin/hc-satellite-dataimport-1227_2' into master-temp
已修改3个文件
已添加2个文件
541 ■■■■■ 文件已修改
src/api/gridApi.js 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomePage.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/satellitetelemetry/component/AODImport.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/satellitetelemetry/component/SatelliteImport.vue 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/gridApi.js
@@ -1,5 +1,6 @@
import { $http } from './index';
import { Base64 } from 'js-base64';
/**
 * å«æ˜Ÿé¥æµ‹ç½‘格相关接口API
 */
@@ -47,6 +48,23 @@
      .then((res) => res.data);
  },
  /**
   * èŽ·å–ç½‘æ ¼ç»„ä¸‹çš„é¥æµ‹aod
   * @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`, {
@@ -57,5 +75,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);
  }
};
src/components.d.ts
@@ -40,6 +40,7 @@
    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']
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>
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>
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>