|
@@ -0,0 +1,236 @@
|
|
|
+<template>
|
|
|
+ <Dialog :title="dialogTitle" v-model="dialogVisible" width="680px">
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="formRules"
|
|
|
+ label-width="120px"
|
|
|
+ label-position="left"
|
|
|
+ >
|
|
|
+ <!-- 文件类型切换 -->
|
|
|
+ <el-form-item label="文件类型" prop="fileType">
|
|
|
+ <el-radio-group
|
|
|
+ v-model="formData.fileType"
|
|
|
+ @change="handleTypeChange"
|
|
|
+ class="type-radio-group"
|
|
|
+ >
|
|
|
+ <el-radio-button label="shp">
|
|
|
+ <i class="el-icon-folder-opened"></i>
|
|
|
+ <span>SHP文件</span>
|
|
|
+ </el-radio-button>
|
|
|
+ <el-radio-button label="gdb">
|
|
|
+ <i class="el-icon-folder"></i>
|
|
|
+ <span>GDB文件</span>
|
|
|
+ </el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="图层名称" prop="shpName">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.shpName"
|
|
|
+ placeholder="请输入图层名称(英文、下划线)"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item v-if="formData.fileType !== 'gdb'" label="图层描述" prop="description">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.description"
|
|
|
+ :rows="3"
|
|
|
+ type="textarea"
|
|
|
+ placeholder="请输入图层描述"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item :label="uploadLabel" prop="shpFile">
|
|
|
+ <el-upload
|
|
|
+ ref="uploadRef"
|
|
|
+ v-model:file-list="fileList"
|
|
|
+ :auto-upload="false"
|
|
|
+ :disabled="formLoading"
|
|
|
+ :limit="1"
|
|
|
+ :on-change="handleFileChange"
|
|
|
+ :on-error="submitFormError"
|
|
|
+ :on-exceed="handleExceed"
|
|
|
+ :on-success="submitFormSuccess"
|
|
|
+ :http-request="handleHttpRequest"
|
|
|
+ :accept="fileAccept"
|
|
|
+ drag
|
|
|
+ class="upload-container"
|
|
|
+ >
|
|
|
+ <template #trigger>
|
|
|
+ <div class="upload-trigger">
|
|
|
+ <i class="el-icon-upload text-4xl mb-2"></i>
|
|
|
+ <div class="el-upload__text">
|
|
|
+ <div>将{{ formData.fileType === 'shp' ? 'SHP' : 'GDB' }}压缩包拖到此处</div>
|
|
|
+ <em class="mt-1 text-gray-400">或点击上传</em>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #tip>
|
|
|
+ <div class="el-upload__tip text-center">
|
|
|
+ {{ fileList.length > 0 ? '✓ 文件已准备就绪' :
|
|
|
+ `请上传${formData.fileType === 'shp' ?
|
|
|
+ '包含.shp/.shx/.dbf等文件的ZIP压缩包' :
|
|
|
+ '包含.gdb目录的ZIP压缩包'}` }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :loading="formLoading"
|
|
|
+ @click="submitFileForm"
|
|
|
+ >
|
|
|
+ {{ formLoading ? '导入中...' : '确定' }}
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ref, reactive, computed } from 'vue'
|
|
|
+import type { UploadRequestOptions } from "element-plus/es/components/upload/src/upload"
|
|
|
+import { GisNameApi } from "@/api/layer/gisname"
|
|
|
+
|
|
|
+const dialogVisible = ref(false)
|
|
|
+const formLoading = ref(false)
|
|
|
+const fileList = ref<File[]>([])
|
|
|
+const uploadRef = ref()
|
|
|
+
|
|
|
+// 计算属性
|
|
|
+const dialogTitle = computed(() => formData.value.fileType === 'shp' ? 'SHP文件导入' : 'GDB文件导入')
|
|
|
+const uploadLabel = computed(() => formData.value.fileType === 'shp' ? 'SHP压缩包' : 'GDB压缩包')
|
|
|
+const fileAccept = computed(() => '.zip')
|
|
|
+
|
|
|
+// 表单数据
|
|
|
+const formData = ref({
|
|
|
+ fileType: 'shp',
|
|
|
+ shpName: '',
|
|
|
+ description: ''
|
|
|
+})
|
|
|
+
|
|
|
+// 表单校验规则
|
|
|
+const formRules = reactive({
|
|
|
+ shpName: [
|
|
|
+ { required: true, message: '图层名称不能为空', trigger: 'blur' },
|
|
|
+ {
|
|
|
+ pattern: /^[a-z_][a-z0-9_]*$/,
|
|
|
+ message: '名称只能包含小写字母、数字和下划线,且不能以数字开头',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+const handleTypeChange = () => {
|
|
|
+ fileList.value = []
|
|
|
+ uploadRef.value?.clearFiles()
|
|
|
+}
|
|
|
+
|
|
|
+const handleHttpRequest = async (options: UploadRequestOptions) => {
|
|
|
+ const fd = new FormData()
|
|
|
+ fd.append('shpName', formData.value.shpName)
|
|
|
+ fd.append('description', formData.value.description)
|
|
|
+ fd.append('shpFile', options.file)
|
|
|
+
|
|
|
+ try {
|
|
|
+ const api = formData.value.fileType === 'shp' ? GisNameApi.createShp : GisNameApi.importGdb
|
|
|
+ const res = await api(fd)
|
|
|
+ return res.code === 0 ? Promise.resolve(res) : Promise.reject(res)
|
|
|
+ } catch (error) {
|
|
|
+ return Promise.reject(error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleFileChange = (file: File) => {
|
|
|
+ if (!file.name.endsWith('.zip')) {
|
|
|
+ ElMessage.error('只能上传ZIP格式的压缩包')
|
|
|
+ fileList.value = []
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const submitFileForm = async () => {
|
|
|
+ if (!formData.value.shpName.match(/^[a-z_][a-z0-9_]*$/)) {
|
|
|
+ return ElMessage.error('图层名称格式错误')
|
|
|
+ }
|
|
|
+ if (fileList.value.length === 0) {
|
|
|
+ return ElMessage.error('请上传压缩包文件')
|
|
|
+ }
|
|
|
+
|
|
|
+ formLoading.value = true
|
|
|
+ try {
|
|
|
+ await uploadRef.value?.submit()
|
|
|
+ } finally {
|
|
|
+ formLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const emit = defineEmits(['success'])
|
|
|
+const submitFormSuccess = (response: any) => {
|
|
|
+ ElMessage.success(response.data?.featureCount ?
|
|
|
+ `导入成功,共${response.data.featureCount}个要素` : '导入成功')
|
|
|
+ resetForm()
|
|
|
+ emit('success')
|
|
|
+}
|
|
|
+
|
|
|
+const submitFormError = (error: Error) => {
|
|
|
+ ElMessage.error(`上传失败:${error.message || '未知错误'}`)
|
|
|
+}
|
|
|
+
|
|
|
+const handleExceed = () => {
|
|
|
+ ElMessage.error('每次只能上传一个压缩包!')
|
|
|
+}
|
|
|
+
|
|
|
+const resetForm = () => {
|
|
|
+ formData.value = { fileType: 'shp', shpName: '', description: '' }
|
|
|
+ fileList.value = []
|
|
|
+ dialogVisible.value = false
|
|
|
+ uploadRef.value?.clearFiles()
|
|
|
+}
|
|
|
+
|
|
|
+const open = () => {
|
|
|
+ resetForm()
|
|
|
+ dialogVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+defineExpose({ open })
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.type-radio-group {
|
|
|
+ gap: 16px;
|
|
|
+ margin: 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-container {
|
|
|
+ width: 100%;
|
|
|
+ border: 2px dashed var(--el-border-color);
|
|
|
+ border-radius: 8px;
|
|
|
+ transition: border-color 0.3s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: var(--el-color-primary);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.upload-trigger {
|
|
|
+ padding: 24px 0;
|
|
|
+ color: var(--el-color-info);
|
|
|
+
|
|
|
+ .el-icon-upload {
|
|
|
+ color: var(--el-color-primary);
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.el-upload__tip {
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+ margin-top: 8px;
|
|
|
+}
|
|
|
+</style>
|