CaiYuanYiTiHua/src/views/demo/system/geoservermanagement/clound/uploadFrom.vue

457 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="current1">
<div class="upload-div w-1/2 xl:w-1/2 m-4 mr-0" v-if="!isEdit">
<a-upload-dragger
v-model:fileList="shpFileList"
name="shpFileName"
style="height: 274px; width: 300px"
class="upload-dragger"
:multiple="false"
:maxCount="1"
:before-upload="shpBeforeUpload"
:customRequest="shpCustomRequest"
accept=".zip,.xls,.xlsx"
>
<p class="ant-upload-drag-icon">
<PlusOutlined />
</p>
<div style="opacity: 0.7"> 文件上传 </div>
<div class="upload-span">
<div class="upload-span-content">
<div style="opacity: 0.7">将文件拖拽到这里或点击上传按钮</div>
<div style="color: #1e5eff">支持扩展名zipxlsxlsx</div>
<div style="opacity: 0.7"> zip中需要包含 .shp .shx .dbf 文件 </div>
<div style="opacity: 0.7"> .shp文件大小小于3GB </div>
</div>
</div>
</a-upload-dragger>
</div>
<div class="upload-form w-1/2 xl:w-1/2 m-4 mr-0">
<a-form
ref="formRef"
:model="uploadFrom"
:labelCol="{ width: '75px' }"
labelAlign="right"
:rules="uploadFormRules"
>
<a-form-item label="服务名称" name="serverName">
<a-input v-model:value="uploadFrom.serverName" placeholder="请输入服务名称" />
</a-form-item>
<a-form-item label="空间参考" name="spatialRef">
<a-select
v-model:value="uploadFrom.spatialRef"
placeholder="请选择空间参考"
:disabled="isEdit"
>
<a-select-option value="EPSG:4326">EPSG:4326</a-select-option>
<a-select-option value="EPSG:3857">EPSG:3857</a-select-option>
<a-select-option value="EPSG:900913">EPSG:900913</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="数据表名" name="dataTable">
<a-input
v-model:value="uploadFrom.dataTable"
placeholder="请输入表名"
:disabled="isEdit"
/>
</a-form-item>
<a-form-item label="图层样式" name="appendPath">
<a-upload
v-model:fileList="tucengFileList"
name="tucengFileName"
list-type="picture-card"
class="upload-dragger"
:multiple="false"
:maxCount="1"
:show-upload-list="false"
:before-upload="tucengBeforeUpload"
:custom-request="tucengCustomRequest"
accept=".sld"
>
<div>
<PlusOutlined />
<div class="ant-upload-text">上传图层样式</div>
</div>
</a-upload>
<div style="position: relative; top: 5px" v-if="tucengFileName">
{{ tucengFileName }}
<DeleteOutlined @click="deleteTuceng" />
</div>
</a-form-item>
</a-form>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
// vben
import { PermissionBtn } from '@/components/PermissionBtn/index';
import { useMessage } from '@/hooks/web/useMessage';
import type { UploadProps } from 'ant-design-vue';
import { message, Upload } from 'ant-design-vue';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { ShpGeoLayerParseShpInfo } from '@/api/demo/system';
import { CheckTableExist } from '@/api/database/index';
import axios from 'axios';
import { cloneDeep } from 'lodash-es';
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_API_URL } = getAppEnvConfig();
const { createMessage } = useMessage();
const formRef = ref();
const props = defineProps(['uploadForm', 'isEdit']);
const uploadFrom = ref(props.uploadForm);
const isEdit = ref(props.isEdit);
const emit = defineEmits([
'uploadFormSubmit',
'setDataSourceType',
'setShpUploadType',
'setSldUploadType',
]);
watch(
() => props.uploadForm,
() => {
if (props.isEdit) {
uploadFrom.value = props.uploadForm;
}
},
);
const uploadFormRules = reactive({
serverName: [{ required: true, message: '请输入服务名称', trigger: 'blur' }],
spatialRef: [{ required: true, message: '请选择空间参考', trigger: 'blur' }],
// dataType: [{ required: true, message: '请选择数据类型', trigger: 'blur' }],
appendPath: [{ required: true, message: '请上传图层样式', trigger: 'blur' }],
dataTable: [
{ required: true, message: '请输入数据表名', trigger: 'blur' },
{
validator: (rule, value, callback) => {
let reg = /^[a-z]\w{0,28}$/;
if (value !== '' && !reg.test(value)) {
callback(
new Error('小写字母开头可包含下划线但不能有汉字和大写字母不能超过30字符'),
);
}
callback();
},
trigger: 'blur',
},
{
validator: (rule, value, callback) => {
let query: any = { tableName: value };
CheckTableExist(query)
.then((res) => {
if (res) {
callback(new Error('数据库已有此数据表名,请更换表名'));
} else {
callback();
}
})
.catch(() => {
callback(new Error('检查数据表名时发生错误'));
});
},
trigger: 'blur',
},
],
});
// 步骤1-提交
const submit1 = () => {
formRef.value
.validate()
.then(() => {
let params = {
zipFilePath: uploadFrom.value.shpPath,
tableName: uploadFrom.value.dataTable,
srid: uploadFrom.value.spatialRef,
};
ShpGeoLayerParseShpInfo(params).then((res) => {
uploadFrom.value.dataType = res.dataType;
uploadFrom.value.headers = res.headers;
emit('uploadFormSubmit', uploadFrom.value);
});
})
.catch((error) => {
console.log(error);
});
};
// 步骤1-shp上传
const shpFileList = ref<UploadProps['fileList']>([]);
const shpFileName = ref<string>('');
let isShpUpload = false;
// 步骤1-shp上传之前
const shpBeforeUpload: UploadProps['beforeUpload'] = (file) => {
let extension = file.name.substring(file.name.lastIndexOf('.') + 1);
let size = file.size / 1024 / 1024;
const isZipOrXls = extension === 'zip' || extension === 'xls' || extension === 'xlsx';
const suitableSize = size < 1024 * 3;
if (!isZipOrXls) {
createMessage.error('只能上传后缀是.zip .xls或者.xlsx的文件');
}
if (extension == 'zip') {
emit('setDataSourceType', 'shp');
} else if (['xls', 'xlsx'].includes(extension)) {
emit('setDataSourceType', 'excel');
}
if (!suitableSize) {
createMessage.error('文件大小不得超过3GB');
}
isShpUpload = isZipOrXls && suitableSize;
if (isShpUpload) {
emit('setShpUploadType', true);
}
return isShpUpload;
};
// 步骤1-shp上传文件接口
const shpCustomRequest = (options) => {
if (isShpUpload) {
const formData = new FormData();
formData.append('files', options.file);
// 假设 Token 存储在 localStorage 中
const token = localStorage.getItem('X-Token');
// 设置请求头部,带上 Token
const headers = {
'X-Token': token,
};
axios
.post(VITE_GLOB_API_URL + '/api/Files/Upload', formData, { headers, timeout: 0 })
.then((response) => {
options.onSuccess(response.data, options.file);
shpFileName.value = response.data.result[0].fileName;
uploadFrom.value.shpPath = response.data.result[0].filePath;
emit('setShpUploadType', false);
// uploadFrom.value.shpFileName = response.data.result[0].fileName;
})
.catch((error) => {
options.onError(error);
});
}
};
// 步骤1-图层样式上传
const tucengFileList = ref<UploadProps['fileList']>([]);
const tucengFileName = ref<string>('');
let isSldUpload = false;
// 步骤1-图层上传之前
const tucengBeforeUpload: UploadProps['beforeUpload'] = (file) => {
let extension = file.name.substring(file.name.lastIndexOf('.') + 1);
let size = file.size / 1024 / 1024;
const isSld = extension === 'sld';
const suitableSize = size < 1;
if (!isSld) {
createMessage.error('只能上传后缀是.sld的文件');
}
if (!suitableSize) {
createMessage.error('文件大小不得超过1M');
}
isSldUpload = isSld && suitableSize;
if (isSldUpload) {
emit('setSldUploadType', true);
}
return isSldUpload;
};
// 步骤1-图层上传文件接口
const tucengCustomRequest = (options) => {
if (isSldUpload) {
const formData = new FormData();
readAndParseSLDFile(options.file);
formData.append('files', options.file);
// 假设 Token 存储在 localStorage 中
const token = localStorage.getItem('X-Token');
// 设置请求头部,带上 Token
const headers = {
'X-Token': token,
};
axios
.post(VITE_GLOB_API_URL + '/api/Files/Upload', formData, { headers })
.then((response) => {
options.onSuccess(response.data, options.file);
tucengFileName.value = response.data.result[0].fileName;
uploadFrom.value.appendPath = response.data.result[0].filePath;
emit('setSldUploadType', false);
// uploadFrom.value.appendFileName = response.data.result[0].fileName;
})
.catch((error) => {
options.onError(error);
});
console.log(uploadFrom.value);
}
};
// 步骤1-删除图层样式
const deleteTuceng = () => {
tucengFileName.value = '';
uploadFrom.value.appendPath = '';
// uploadFrom.value.appendFileName = '';
};
// 清除验证
const clearValidation = () => {
formRef.value.clearValidate();
shpFileName.value = '';
tucengFileName.value = '';
};
// 读取文件内容
const readAndParseSLDFile = async (file) => {
const reader = new FileReader();
reader.onload = (e) => {
const sldContent = e.target.result;
const styles = parseSLD(sldContent);
assemblyPaint(styles);
// uploadFrom.value.style = styles;
};
reader.onerror = (error) => {
console.error('Error reading the file:', error);
};
reader.readAsText(file);
};
// 解析sld文件
const parseSLD = (sldFileContent) => {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(sldFileContent, 'application/xml');
const namedLayers = xmlDoc.querySelectorAll('NamedLayer');
const styles: any = [];
namedLayers.forEach((namedLayer) => {
const userStyles = namedLayer.querySelectorAll('UserStyle');
userStyles.forEach((userStyle) => {
userStyle.children?.forEach((element) => {
if (element && element.nodeName == 'se:FeatureTypeStyle') {
element.children.forEach((featureTypeStyle) => {
let style: any = {};
const rules = featureTypeStyle.children;
rules.forEach((rule) => {
// se:Name
if (rule.nodeName == 'se:Name') {
style.ruleName = rule.textContent;
}
// ogc:Filter
if (rule.nodeName == 'ogc:Filter') {
const ogcFilter = rule.children;
if (ogcFilter[0].nodeName == 'ogc:PropertyIsEqualTo') {
ogcFilter[0].children.forEach((item) => {
if (item.nodeName == 'ogc:PropertyName') {
style.ogcPropertyName = item.textContent.toLowerCase();
}
if (item.nodeName == 'ogc:Literal') {
style.ogcLiteral = item.textContent;
}
});
}
}
// se:PolygonSymbolizer
if (rule.nodeName == 'se:PolygonSymbolizer') {
const sePolygonSymbolizers = rule.children;
const fillParams: any = [];
const strokeParams: any = [];
sePolygonSymbolizers.forEach((sePolygonSymbolizer) => {
if (sePolygonSymbolizer.nodeName == 'se:Fill') {
const fills = sePolygonSymbolizer.children;
fills.forEach((fill) => {
if (fill.nodeName == 'se:SvgParameter') {
fillParams[fill.getAttribute('name')] = fill.textContent;
}
});
}
if (sePolygonSymbolizer.nodeName == 'se:Stroke') {
const fills = sePolygonSymbolizer.children;
fills.forEach((fill) => {
if (fill.nodeName == 'se:SvgParameter') {
strokeParams[fill.getAttribute('name')] = fill.textContent;
}
});
}
});
style.seFill = fillParams;
style.seStroke = strokeParams;
styles.push(style);
}
});
});
}
});
});
});
return styles;
};
// 生成paint
const assemblyPaint = (styles) => {
let result: any = {};
// fill-opacity
result['fill-opacity'] = styles[0].seFill['fill-opacity']
? parseFloat(styles[0].seFill['fill-opacity'])
: 1;
// fill-color
let onlyFillColor: any = [];
const fillColor = styles.map((style) => {
const { ruleName, ogcPropertyName, ogcLiteral, seFill, seStroke } = style;
onlyFillColor.push(seFill['fill']);
if (ogcLiteral) {
return [['==', ['get', ogcPropertyName], ogcLiteral], seFill['fill']];
} else {
return seFill['fill'];
}
});
result['fill-color'] = ['case', ...fillColor.flat()];
onlyFillColor = [...new Set(onlyFillColor)];
if (onlyFillColor.length == 1) {
result['fill-color'] = onlyFillColor[0];
}
// fill-outline-color
let onlyFillOutlineColor: any = [];
const fillOutlineColor = styles.map((style) => {
const { ruleName, ogcPropertyName, ogcLiteral, seFill, seStroke } = style;
onlyFillOutlineColor.push(seStroke['stroke']);
if (ogcLiteral) {
return [['==', ['get', ogcPropertyName], ogcLiteral], seStroke['stroke']];
} else {
return seStroke['stroke'];
}
});
result['fill-outline-color'] = ['case', ...fillOutlineColor.flat()];
onlyFillOutlineColor = [...new Set(onlyFillOutlineColor)];
if (onlyFillOutlineColor.length == 1) {
result['fill-outline-color'] = onlyFillOutlineColor[0];
}
// style
uploadFrom.value.style = JSON.stringify(result);
console.log(uploadFrom.value.style);
};
defineExpose({
submit1,
clearValidation,
});
</script>
<style lang="less" scoped>
.current1 {
display: flex;
}
.upload-div {
display: flex;
align-items: center;
justify-content: center;
position: relative;
top: -30px;
}
.upload-span {
margin: 30px;
}
.upload-form {
margin-left: 100px;
}
</style>