522 lines
17 KiB
Vue
522 lines
17 KiB
Vue
<template>
|
||
<div>
|
||
<a-row ::gutter="0">
|
||
<a-col :span="12">
|
||
<BasicTable @register="registerTable" @row-click="handRowClick">
|
||
<template #toolbar>
|
||
<a-button type="primary" @click="updateGeoTiff">更新最新影像</a-button>
|
||
<a-button type="success" @click="updateYearWeekThumbnail">更新缩略图</a-button>
|
||
<a-button type="error" @click="deleteGeoTiff">删除影像</a-button>
|
||
</template>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'layerName'">
|
||
<span class="content-full">{{ record.layerName }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'dataTable'">
|
||
<span class="content-full">{{ record.dataTable }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'shpPath'">
|
||
<span class="content-full">{{ record.shpPath }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'tiffPath'">
|
||
<span class="content-full">{{ record.tiffPath }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'createTime'">
|
||
<span class="content-full">{{ record.createTime }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'updateTime'">
|
||
<span class="content-full">{{ record.updateTime }}</span>
|
||
</template>
|
||
<template v-if="column.key === 'accessUrl'">
|
||
<a-image
|
||
:src="'/geoserver/group/1/' + record.layerName + '/' + record.layerName + '.png'"
|
||
:fallback="getUrl(record.accessUrl, record.layerName)"
|
||
:style="{ marginRight: '10px' }"
|
||
:width="100"
|
||
:height="100"
|
||
:preview="{
|
||
visible,
|
||
onVisibleChange: setVisible,
|
||
}"
|
||
/>
|
||
</template>
|
||
</template>
|
||
</BasicTable>
|
||
</a-col>
|
||
<a-col :span="12">
|
||
<div>
|
||
<MapComponent
|
||
ref="mapboxComponentRef"
|
||
style="
|
||
position: absolute;
|
||
top: 16px;
|
||
left: 0px;
|
||
height: calc(100vh - 112px);
|
||
width: calc(85vh);
|
||
z-index: 0;
|
||
"
|
||
/>
|
||
</div>
|
||
</a-col>
|
||
</a-row>
|
||
|
||
<a-modal
|
||
title="更新失败的影像"
|
||
:open="failOpen"
|
||
:maskClosable="false"
|
||
:footer="null"
|
||
:width="1000"
|
||
@cancel="failOpenClose"
|
||
>
|
||
<FailYingxiang :failYingxiangData="failYingxiangData" />
|
||
</a-modal>
|
||
|
||
<a-modal
|
||
title="选择更新的影像"
|
||
style="top: 50px"
|
||
:open="chooseUpdateOpen"
|
||
:maskClosable="false"
|
||
:width="600"
|
||
:footer="null"
|
||
@cancel="chooseUpdateClose"
|
||
>
|
||
<ChooseUpdate
|
||
ref="chooseUpdateRef"
|
||
:chooseUpdateData_yearweeks="chooseUpdateData_yearweeks"
|
||
:chooseUpdateData_layernames="chooseUpdateData_layernames"
|
||
@generateThumbnail="generateThumbnail"
|
||
/>
|
||
</a-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, watch, onMounted, createVNode } from 'vue';
|
||
// vben
|
||
import { useMessage } from '@/hooks/web/useMessage';
|
||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||
import { Modal } from 'ant-design-vue';
|
||
import proj4 from 'proj4';
|
||
import dayjs from 'dayjs';
|
||
import { getAppEnvConfig } from '@/utils/env';
|
||
import { BasicTable, useTable } from '@/components/Table';
|
||
import { columns, searchFormSchema, data } from './util';
|
||
import MapComponent from '@/views/demo/system/geoservermanagement/clound/mapComponent.vue';
|
||
import FailYingxiang from './failYingxiang.vue';
|
||
import ChooseUpdate from './chooseUpdate.vue';
|
||
// api
|
||
import {
|
||
GeoTiffManagerUpdateGeoTiff,
|
||
GeoTiffManagerLoadPage,
|
||
GeoTiffManagerGet,
|
||
GeoTiffManagerDeleteTifStore,
|
||
GeoTiffManagerUpdateLayerGroupThumb,
|
||
} from '@/api/demo/system';
|
||
import { RecordList } from '../../geoservermanagement/page';
|
||
|
||
// 图片路径拼接
|
||
const { VITE_GLOB_API_URL } = getAppEnvConfig();
|
||
const VITE_GLOB_API_URL_VAR = ref<String>(VITE_GLOB_API_URL + '/');
|
||
|
||
const { createMessage } = useMessage();
|
||
|
||
proj4.defs(
|
||
'EPSG:4548',
|
||
'+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
|
||
);
|
||
|
||
// 影像管理-----------------------------------------------------------------------------------------------
|
||
const [registerTable, { reload, getSelectRows }] = useTable({
|
||
title: '影像管理',
|
||
api: GeoTiffManagerLoadPage,
|
||
// dataSource: data,
|
||
columns: columns,
|
||
useSearchForm: true,
|
||
formConfig: {
|
||
labelWidth: 120,
|
||
schemas: searchFormSchema,
|
||
},
|
||
showIndexColumn: true,
|
||
rowSelection: {
|
||
type: 'radio',
|
||
},
|
||
bordered: true,
|
||
showTableSetting: true,
|
||
handleSearchInfoFn(info) {
|
||
return info;
|
||
},
|
||
immediate: false,
|
||
});
|
||
|
||
// 更新失败的影像-----------------------------------------------------------------------------------------
|
||
const failOpen = ref(false);
|
||
const failYingxiangData: any = ref();
|
||
// 更新失败的影像弹窗关闭
|
||
function failOpenClose() {
|
||
failOpen.value = false;
|
||
}
|
||
|
||
// 更新tiff影像
|
||
const updateGeoTiff = () => {
|
||
GeoTiffManagerUpdateGeoTiff()
|
||
.then((res) => {
|
||
if (res.length == 0) {
|
||
createMessage.success('影像更新成功');
|
||
reload();
|
||
} else {
|
||
failYingxiangData.value = getFailYingxiangData(res);
|
||
failOpen.value = true;
|
||
reload();
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.log(error);
|
||
});
|
||
};
|
||
|
||
// 切割路径
|
||
function getFailYingxiangData(table) {
|
||
let result: any = [];
|
||
table.forEach((fullPath) => {
|
||
const lastSlashIndex = fullPath.lastIndexOf('/');
|
||
if (lastSlashIndex != -1) {
|
||
result.push({
|
||
fileName: fullPath.substring(lastSlashIndex + 1),
|
||
filePath: fullPath.substring(0, lastSlashIndex + 1),
|
||
});
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
// 删除tiff影像---------------------------------------------------------------------------------------
|
||
const deleteGeoTiff = () => {
|
||
let rows = getSelectRows();
|
||
if (rows.length == 0) {
|
||
return createMessage.warn('请勾选一条数据进行删除');
|
||
}
|
||
const record = rows[0];
|
||
isPngImageUrl(getUrl(record.accessUrl, record.layerName))
|
||
.then((isPng) => {
|
||
if (isPng) {
|
||
createMessage.warn('所选影像完好,不能删除!');
|
||
} else {
|
||
Modal.confirm({
|
||
title: '是否确认删除此影像?',
|
||
icon: createVNode(ExclamationCircleOutlined),
|
||
onCancel() {},
|
||
onOk() {
|
||
// 删除有问题的影像
|
||
let params = { stores: record.storeName };
|
||
GeoTiffManagerDeleteTifStore(params).then((res) => {
|
||
if (res) {
|
||
createMessage.success('所选影像删除成功!');
|
||
reload();
|
||
} else {
|
||
createMessage.error('所选影像删除失败!');
|
||
reload();
|
||
}
|
||
});
|
||
},
|
||
});
|
||
}
|
||
})
|
||
.catch(console.error);
|
||
};
|
||
|
||
// 判断链接获取到的图片是否是png
|
||
async function isPngImageUrl(url) {
|
||
try {
|
||
const response = await fetch(url, { method: 'HEAD' });
|
||
if (!response.ok) {
|
||
throw new Error('请求失败');
|
||
}
|
||
const contentType = response.headers.get('content-type');
|
||
return contentType && contentType.startsWith('image/png');
|
||
} catch (error) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 在本地路径生成缩略图-------------------------------------------------------------------------------
|
||
// 选择生成缩略图的影像ref、open、数据
|
||
const chooseUpdateRef = ref();
|
||
const chooseUpdateOpen = ref(false);
|
||
const chooseUpdateData_yearweeks: any = ref([]);
|
||
const chooseUpdateData_layernames: any = ref([]);
|
||
// 选择更新的周数影像弹窗关闭
|
||
function chooseUpdateClose() {
|
||
chooseUpdateOpen.value = false;
|
||
chooseUpdateRef.value.clearSelect_layernames();
|
||
chooseUpdateRef.value.clearSelect_yearweeks();
|
||
}
|
||
// 在本地路径生成缩略图
|
||
async function updateYearWeekThumbnail() {
|
||
// allDataForClearMap = data;
|
||
// 按照时间分类
|
||
allDataForClearMap = allDataForClearMap.sort((a, b) => dayjs(b.dateDir) - dayjs(a.dateDir));
|
||
let uniqueKeysArray = [...new Set(allDataForClearMap.map((item) => item.dateDir))];
|
||
// 转换时间数组(年份-周数)
|
||
uniqueKeysArray = [...new Set(uniqueKeysArray.map(convertToYearWeek))];
|
||
// 生成对应年份-周数的缩略图
|
||
chooseUpdateData_yearweeks.value = [];
|
||
uniqueKeysArray.forEach((item, index) => {
|
||
chooseUpdateData_yearweeks.value.push({
|
||
rowname: item,
|
||
});
|
||
});
|
||
// 影像名称更换全部影像的缩略图
|
||
chooseUpdateData_layernames.value = [];
|
||
allDataForClearMap.forEach((item, index) => {
|
||
chooseUpdateData_layernames.value.push({
|
||
rowname: item.layerName,
|
||
bbox: getBboxFromUrl(item.accessUrl),
|
||
});
|
||
});
|
||
chooseUpdateOpen.value = true;
|
||
}
|
||
|
||
// 生成缩略图
|
||
async function generateThumbnail(
|
||
layerNames,
|
||
bbox,
|
||
length,
|
||
index,
|
||
widthAndHeightValue = 1024,
|
||
numValue = 1,
|
||
) {
|
||
if (bbox) {
|
||
// 检查bbox是否是ESG:4326,不是的话转换成
|
||
let bboxSplit = bbox.split(',');
|
||
const result1 = isProjectedCoordinates(parseFloat(bboxSplit[0]), parseFloat(bboxSplit[1]));
|
||
if (result1) {
|
||
const result2 = isProjectedCoordinates(parseFloat(bboxSplit[2]), parseFloat(bboxSplit[3]));
|
||
bbox = result1.concat(result2).toString();
|
||
}
|
||
GeoTiffManagerUpdateLayerGroupThumb({
|
||
layerGroups: layerNames,
|
||
bbox: bbox,
|
||
num: 1,
|
||
width: widthAndHeightValue,
|
||
height: widthAndHeightValue,
|
||
})
|
||
.then((res) => {
|
||
if (res && length == index) {
|
||
createMessage.success('生成新的缩略图成功!');
|
||
chooseUpdateRef.value.clearSelect_layernames();
|
||
chooseUpdateRef.value.loading_layernames = false;
|
||
} else if (length == index) {
|
||
createMessage.error('生成新的缩略图失败!');
|
||
chooseUpdateRef.value.loading_layernames = false;
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
if (length == index) {
|
||
createMessage.error('生成新的缩略图失败!');
|
||
chooseUpdateRef.value.loading_layernames = false;
|
||
}
|
||
});
|
||
} else {
|
||
// 分割的生成缩略图
|
||
GeoTiffManagerUpdateLayerGroupThumb({
|
||
layerGroups: layerNames,
|
||
num: numValue,
|
||
width: widthAndHeightValue,
|
||
height: widthAndHeightValue,
|
||
})
|
||
.then((res) => {
|
||
if (res) {
|
||
createMessage.success('生成新的缩略图成功!');
|
||
chooseUpdateRef.value.loading_yearweeks = false;
|
||
chooseUpdateRef.value.clearSelect_yearweeks();
|
||
if (numValue != 1) {
|
||
// 生成总的缩略图
|
||
GeoTiffManagerUpdateLayerGroupThumb({
|
||
layerGroups: layerNames,
|
||
num: 1,
|
||
width: widthAndHeightValue,
|
||
height: widthAndHeightValue,
|
||
});
|
||
}
|
||
} else {
|
||
createMessage.error('生成新的缩略图失败!');
|
||
chooseUpdateRef.value.loading_yearweeks = false;
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
createMessage.error('生成新的缩略图失败!');
|
||
chooseUpdateRef.value.loading_yearweeks = false;
|
||
});
|
||
}
|
||
}
|
||
|
||
// 获取年份-周数
|
||
function convertToYearWeek(dateStr) {
|
||
const date = dayjs(dateStr, 'YYYYMMDD');
|
||
// 返回格式化的字符串
|
||
return `${date.year()}-${getWeekOfYear(date)}`;
|
||
}
|
||
|
||
// 每周从周一开始
|
||
function getWeekOfYear(date) {
|
||
const firstDayOfYear = dayjs(date).startOf('year');
|
||
const firstMondayOfYear =
|
||
firstDayOfYear.day() === 1
|
||
? firstDayOfYear
|
||
: firstDayOfYear.add(1 - firstDayOfYear.day(), 'day');
|
||
const diffInDays = date.diff(firstMondayOfYear, 'days');
|
||
const weekNumber = Math.floor(diffInDays / 7) + 1;
|
||
return weekNumber;
|
||
}
|
||
|
||
// 行选中-----------------------------------------------------------------------------------------
|
||
const mapboxComponentRef = ref();
|
||
function handRowClick(record) {
|
||
allDataForClearMap.forEach((data) => {
|
||
mapboxComponentRef.value.clearTaskLayer(data.layerName);
|
||
});
|
||
let lngLat = getlngLatByAccessUrl(record.accessUrl);
|
||
let chooseRows: any = [];
|
||
record.bbox = getBboxFromUrl(record.accessUrl);
|
||
chooseRows.push(record);
|
||
mapboxComponentRef.value.GeoTiffManagerRaster(chooseRows, lngLat, 11, true);
|
||
}
|
||
|
||
// 获取中心点的坐标
|
||
function getlngLatByAccessUrl(accessUrl) {
|
||
let bbox = getBboxFromUrl(accessUrl);
|
||
let lngLat = getCenterPoint(bbox);
|
||
// 检测坐标系
|
||
const result = isProjectedCoordinates(parseFloat(lngLat[0]), parseFloat(lngLat[1]));
|
||
if (result) {
|
||
lngLat[0] = result[0];
|
||
lngLat[1] = result[1];
|
||
}
|
||
return lngLat;
|
||
}
|
||
|
||
function isProjectedCoordinates(x, y) {
|
||
// 检查是否在地理坐标系的范围内
|
||
const isGeoXInRange = -180 <= x && x <= 180;
|
||
const isGeoYInRange = -90 <= y && y <= 90;
|
||
// 定义坐标系
|
||
const fromCrs1 = 'EPSG:3857'; // 假设输入坐标是 Web Mercator
|
||
const fromCrs2 = 'EPSG:4548';
|
||
const toCrs = 'EPSG:4326'; // 目标坐标系是地理坐标系
|
||
// 如果不在地理坐标系范围内,则认为是投影坐标系
|
||
if (!isGeoXInRange || !isGeoYInRange) {
|
||
// 转换坐标
|
||
// 根据输入坐标的范围来判断是哪个坐标系
|
||
const fromCrs = isProjectedCoordinate(x, y) ? fromCrs2 : fromCrs1;
|
||
return proj4(fromCrs, toCrs, [x, y]);
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
const isProjectedCoordinate = (x, y) => {
|
||
// 检查坐标是否符合 EPSG:4548 的大致范围
|
||
const is4548XInRange = 0 <= x && x <= 1000000;
|
||
const is4548YInRange = 0 <= y && y <= 6000000;
|
||
return is4548XInRange && is4548YInRange;
|
||
};
|
||
|
||
// 从参数中获取 bbox 的值
|
||
function getBboxFromUrl(url) {
|
||
const urlObj = new URL(url);
|
||
const params = new URLSearchParams(urlObj.search);
|
||
const bbox = params.get('bbox');
|
||
return bbox;
|
||
}
|
||
|
||
// 计算中心点
|
||
function getCenterPoint(bbox) {
|
||
const coords = bbox.split(',').map((coord) => parseFloat(coord));
|
||
const [minLon, minLat, maxLon, maxLat] = coords;
|
||
const centerLon = (minLon + maxLon) / 2;
|
||
const centerLat = (minLat + maxLat) / 2;
|
||
return [centerLon, centerLat];
|
||
}
|
||
|
||
// 缩略图的预览不使用----------------------------------------------------------------------------
|
||
const visible = ref<boolean>(false);
|
||
const setVisible = (value): void => {
|
||
visible.value = false;
|
||
};
|
||
|
||
// 从geoserver获取缩略图
|
||
function getUrl(accessUrl, name) {
|
||
let r1 = [117.34046403513817, 34.331716698906675];
|
||
let r2 = [119.27763051149853, 36.263686454243626];
|
||
let size = 4096;
|
||
if (accessUrl) {
|
||
let bbox: any = getBboxFromUrl(accessUrl);
|
||
// 检查bbox是否是ESG:4326,不是的话转换成
|
||
let bboxSplit = bbox.split(',');
|
||
const result1 = isProjectedCoordinates(parseFloat(bboxSplit[0]), parseFloat(bboxSplit[1]));
|
||
if (result1) {
|
||
const result2 = isProjectedCoordinates(parseFloat(bboxSplit[2]), parseFloat(bboxSplit[3]));
|
||
bbox = result1.concat(result2).toString();
|
||
}
|
||
const coords = bbox.split(',').map((coord) => parseFloat(coord));
|
||
r1 = [coords[0], coords[1]];
|
||
r2 = [coords[2], coords[3]];
|
||
size = 256;
|
||
}
|
||
let titeUrl: any = null;
|
||
if (new URL(VITE_GLOB_API_URL).hostname == 'localhost') {
|
||
titeUrl =
|
||
'http://localhost:8080/geoserver/my_workspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=my_workspace:';
|
||
} else {
|
||
titeUrl =
|
||
'http://192.168.10.141:8080/geoserver/my_workspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=my_workspace:';
|
||
}
|
||
let url =
|
||
titeUrl +
|
||
name +
|
||
'&styles=&bbox=' +
|
||
r1[0] +
|
||
',' +
|
||
r1[1] +
|
||
',' +
|
||
r2[0] +
|
||
',' +
|
||
r2[1] +
|
||
'&width=' +
|
||
size +
|
||
'&height=' +
|
||
size +
|
||
'&srs=EPSG:4326&format=image/png&TRANSPARENT=TRUE';
|
||
return url;
|
||
}
|
||
|
||
// 用于去除分页后地图还有前一页的图层--------------------------------------------------------------
|
||
let allDataForClearMap: any = [];
|
||
function forClearMap() {
|
||
GeoTiffManagerLoadPage({
|
||
page: 1,
|
||
limit: 100000,
|
||
}).then((res) => {
|
||
allDataForClearMap = res.items;
|
||
});
|
||
}
|
||
|
||
onMounted(() => {
|
||
reload();
|
||
// 用于去除分页后地图还有前一页的图层
|
||
forClearMap();
|
||
});
|
||
</script>
|
||
<style lang="less" scoped>
|
||
.content-full {
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
overflow-wrap: break-word;
|
||
max-width: 100%;
|
||
display: block;
|
||
}
|
||
::v-deep .ant-image-mask {
|
||
display: none !important;
|
||
}
|
||
</style>
|