<template>
|
<el-dialog
|
:title="props.title"
|
|
v-model="uploadPatchDialog"
|
width="75%"
|
align-center
|
>
|
<div class="container">
|
<!-- 信息展示区 -->
|
<div class="infoBox">
|
<div class="itemBoxLeft">
|
<div v-for="(item, index) in infoList" :key="index" class="itemCon">
|
<div class="itemBox">
|
<div class="itemTitle">{{ item.name }}:</div>
|
<div class="itemContent">
|
<template v-if="props.title === '图斑编辑' && item.editable">
|
<template v-if="item.name === '图斑类型'">
|
<el-select
|
v-model="item.value"
|
size="small"
|
placeholder="请选择图斑类型"
|
style="width: 100%"
|
>
|
<el-option
|
v-for="opt in spotTypeOptions"
|
:key="opt.value"
|
:label="opt.label"
|
:value="opt.value"
|
/>
|
</el-select>
|
</template>
|
<template v-else-if="item.name === '文件名称'">
|
<el-input v-model="item.value" size="small" />
|
</template>
|
</template>
|
<template v-else>
|
<div class="itemValue">{{ item.value }}</div>
|
</template>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 地图和表格容器 -->
|
<div class="map-container">
|
<!-- 图斑列表 -->
|
<div class="table-overlay">
|
<div class="table-content">
|
<div class="tabname">图斑列表</div>
|
<el-table
|
class="ztzf-table"
|
ref="polygonTableEle"
|
highlight-current-row
|
:row-class-name="tableRowClassName"
|
:data="tableData"
|
@row-click="handleLocationPolygon"
|
>
|
<el-table-column type="index" align="center" width="30" label="序号">
|
<template #default="{ $index }">
|
{{ ($index + 1).toString().padStart(2, '0') }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="dkbh" align="center" label="图斑名称" />
|
<el-table-column prop="investigate" align="center" label="图斑状态" />
|
<el-table-column label="操作" align="center" v-if="props.title === '图斑编辑'">
|
<template #default="scope">
|
<span class="operationspan">删除</span>
|
<span class="operationspan" @click.stop="handleSelectionChange(scope.row)"
|
>编辑</span
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
<div class="pagination-container">
|
<el-pagination
|
background
|
layout="prev, pager, next"
|
prev-text="上一页"
|
next-text="下一页"
|
:total="total"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</div>
|
<!--绘制按钮-->
|
<FunButton
|
ref="funButtonEle"
|
v-model:isBoxSelect="isBoxSelect"
|
v-model:isDrawPolygon="isDrawPolygon"
|
></FunButton>
|
<!-- 完成/取消 -->
|
<div class="btnGroups" v-if="props.title === '图斑编辑'">
|
<img src="@/assets/images/home/territory/savebtn.png" alt="" />
|
<img src="@/assets/images/home/territory/cancelbtn.png" alt="" />
|
</div>
|
<!-- 地图 -->
|
<div id="spotMap" class="ztzf-cesium" v-show="uploadPatchDialog"></div>
|
</div>
|
</div>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import {
|
getCenterPoint,
|
getLnglatDist,
|
getLnglatAltitude,
|
getPolygonMaxHeight,
|
cartesian3Convert,
|
getWaylineShowHeight,
|
} from '@/utils/cesium/mapUtil.js';
|
import { getPatchesSpotList } from '@/api/patchManagement/index';
|
import * as Cesium from 'cesium';
|
import { PublicCesium } from '@/utils/cesium/publicCesium';
|
import { ref, watch, onBeforeUnmount } from 'vue';
|
import FunButton from '@/views/resource/components/FunButton.vue';
|
const uploadPatchDialog = defineModel('show');
|
const props = defineProps(['title']);
|
const polygonTableEle = ref(null);
|
let publicCesiumInstance = null;
|
let viewer = null;
|
const viewInstance = shallowRef(null);
|
const homeViewer = shallowRef(null);
|
let tbJwdList = [];
|
let total = ref(0);
|
// 当前选中的图斑面数据
|
let nowSelectObj = ref({});
|
// 记录上一次点击高亮
|
let lastHighlightRow = null;
|
// 功能按钮区域相关:编辑图斑等
|
const funButtonEle = ref(null);
|
const isBoxSelect = ref(false);
|
const isDrawPolygon = ref(false);
|
// 选中了哪些图斑
|
const selectionIds = ref(null);
|
const selectionList = ref([]);
|
// 当前在编辑状态的异常图斑
|
let curCustomPolygon = null;
|
// 表格隔行变色
|
const tableRowClassName = ({ rowIndex }) => {
|
return rowIndex % 2 === 1 ? 'oddNumberRow' : 'even-row';
|
};
|
const spotTypeOptions = ref([
|
{ value: '1', label: '综合类' },
|
{ value: '2', label: '矿山类' },
|
{ value: '3', label: '农田类' },
|
]);
|
const infoList = ref([
|
{ name: '文件名称', value: '55', field: 'job_info_num', editable: true },
|
{ name: '图斑类型', value: 'ee', field: 'name', editable: true },
|
{ name: '图斑数量', value: '', field: 'industry_type_str', editable: false },
|
{ name: '异常图斑数量', value: '', field: 'event_number', editable: false },
|
{ name: '行政区划', value: '', field: 'device_names', editable: false },
|
{ name: '数据来源', value: '', field: 'dept_name', editable: false },
|
{ name: '创建时间', value: '', field: 'cycle_time_value', editable: false },
|
{ name: '创建人', value: '', field: 'ai_type_str', editable: false },
|
]);
|
const params = ref({
|
current: 1,
|
size: 20,
|
});
|
const handleSizeChange = () => {};
|
const handleCurrentChange = () => {};
|
const tableData = ref([]);
|
const polygonSearch = ref({
|
investigate: '',
|
isPush: '',
|
isException: '',
|
inRange: '1',
|
dkbh: '',
|
dkmj: '',
|
page: 1,
|
page_size: 1000,
|
total: 0,
|
workspaceId: 'ede19ef4-2e92-42f3-83cc-89afb54e95a7',
|
area_code: '360000000000',
|
device_sn: '',
|
});
|
// 获取列表数据
|
const getTableList = async () => {
|
tableData.value = [];
|
const res = await getPatchesSpotList(polygonSearch.value);
|
if (res.data.code !== 0) return;
|
tableData.value = res.data.data.list.map(item => ({
|
...item,
|
dkfw: item.sdfw && item.is_exception == 1 ? item.sdfw : item.dkfw,
|
}));
|
total.value = res.data.data.pagination.total;
|
// 先清空地图现有图斑
|
tbJwdList = [];
|
viewer.entities.removeAll(); // 清除所有实体
|
// 加载图斑
|
entitiesAddSpot();
|
};
|
|
// 地图
|
const initMap = () => {
|
if (!document.getElementById('spotMap')) {
|
return;
|
}
|
publicCesiumInstance = new PublicCesium({
|
dom: 'spotMap',
|
flatMode: false,
|
terrain: true,
|
layerMode: 4,
|
contour: false,
|
});
|
homeViewer.value = publicCesiumInstance.getViewer();
|
viewer = publicCesiumInstance.getViewer();
|
viewInstance.value = publicCesiumInstance;
|
viewer.scene.globe.depthTestAgainstTerrain = true;
|
};
|
// 初始化所有图斑
|
const entitiesAddSpot = () => {
|
tableData.value.forEach(item => {
|
// 取出当中经纬度
|
const numbersWithCommas = item.dkfw.match(/\d+(\.\d+)?/g);
|
if (!numbersWithCommas) return;
|
// 绘制图斑
|
const grouped = numbersWithCommas.map(item => Number(item));
|
// 为框选存储对比值
|
tbJwdList.push({
|
...item,
|
grouped: grouped,
|
});
|
// 根据 is_exception 设置颜色
|
const color =
|
item.is_exception == 2 ? Cesium.Color.RED.withAlpha(0.5) : Cesium.Color.YELLOW.withAlpha(0.5);
|
const outlineColor = item.is_exception == 2 ? Cesium.Color.RED : Cesium.Color.YELLOW;
|
viewInstance.value.removeById('polygon_dk' + item.id);
|
homeViewer.value.entities?.add({
|
id: 'polygon_dk' + item.id,
|
customType: 'pattern_spot_polygon',
|
customInfo: {
|
...item,
|
},
|
polygon: {
|
hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(grouped)),
|
material: color,
|
outline: true,
|
outlineColor: outlineColor,
|
outlineWidth: 2,
|
clampToGround: true,
|
outlineDepthFailColor: outlineColor,
|
},
|
polyline: {
|
positions: Cesium.Cartesian3.fromDegreesArray(grouped),
|
width: 2,
|
material: color,
|
clampToGround: true,
|
},
|
zIndex: 99,
|
});
|
|
if (tbJwdList.length > 0) {
|
const positions = tbJwdList.flatMap(item => Cesium.Cartesian3.fromDegreesArray(item.grouped));
|
homeViewer.value.camera.flyToBoundingSphere(new Cesium.BoundingSphere.fromPoints(positions));
|
}
|
viewInstance.value.removeLeftClickEvent('spotHighlighting');
|
viewInstance.value.addLeftClickEvent(null, spotHighlighting, 'spotHighlighting');
|
});
|
};
|
|
// 高亮当前选中图斑,并定位
|
const handleLocationPolygon = (data, Deselect) => {
|
heightlightSpot(data);
|
};
|
// 鼠标触发点击图斑高亮 pick:可以获取当前图斑数据
|
const spotHighlighting = (click, pick, viewer) => {
|
if (!pick || !(pick.id?.customType == 'pattern_spot_polygon')) return;
|
// 表格也对应选中数据 TODO
|
const data = pick.id?.customInfo;
|
// 高亮图斑
|
heightlightSpot(data);
|
};
|
// 选中列表或者点击地图内的图斑 高亮图斑
|
const heightlightSpot = data => {
|
nowSelectObj.value = data;
|
if (!data) {
|
clearSelect();
|
return;
|
}
|
|
const numbersWithCommas = data.dkfw.match(/\d+(\.\d+)?/g);
|
const groupedArr = numbersWithCommas.reduce((acc, val, index, src) => {
|
if (index % 2 === 0) acc.push(src.slice(index, index + 2));
|
return acc;
|
}, []);
|
|
const polygonCenter = getCenterPoint(groupedArr);
|
if (viewInstance.value.getEntityById('polygon_center')) {
|
viewInstance.value.removeById('polygon_center');
|
}
|
|
// 恢复上一个高亮图斑的原始颜色
|
if (lastHighlightRow) {
|
let lastentity = homeViewer.value.entities?.getById('polygon_dk' + lastHighlightRow.id);
|
if (lastentity && lastentity.polygon) {
|
// 根据is_exception恢复原始颜色
|
const originalColor =
|
lastHighlightRow.is_exception == 2
|
? Cesium.Color.RED.withAlpha(0.5)
|
: Cesium.Color.YELLOW.withAlpha(0.5);
|
const originalOutline =
|
lastHighlightRow.is_exception == 2 ? Cesium.Color.RED : Cesium.Color.YELLOW;
|
|
lastentity.polygon.material = originalColor;
|
lastentity.polygon.outlineColor = originalOutline;
|
lastentity.polygon.outlineWidth = 2; // 恢复默认边框宽度
|
}
|
}
|
|
let Nowentity = homeViewer.value.entities?.getById('polygon_dk' + data.id);
|
if (Nowentity && Nowentity.polygon) {
|
Nowentity.polygon.material = Cesium.Color.RED.withAlpha(0);
|
Nowentity.polygon.outlineColor = Cesium.Color.RED;
|
}
|
homeViewer.value.scene.camera.setView({
|
destination: Cesium.Cartesian3.fromDegrees(
|
Number(polygonCenter.lng),
|
Number(polygonCenter.lat),
|
2000
|
),
|
zIndex: 100,
|
});
|
lastHighlightRow = data;
|
};
|
// 清空选中的数据
|
const clearSelect = () => {
|
lastHighlightRow = null;
|
selectionList.value = [];
|
};
|
// 编辑
|
const handleSelectionChange = row => {
|
// console.log('编辑', row.id);
|
let curRowIsSelect = row;
|
selectionIds.value = row.id;
|
selectionList.value = row;
|
curRowIsSelect && handleLocationPolygon(row);
|
if (row.is_exception == 2 && curRowIsSelect) {
|
isDrawPolygon.value = true;
|
funButtonEle.value.upDateDrawState(true);
|
handleLocationPolygon(row);
|
} else {
|
isDrawPolygon.value = false;
|
}
|
};
|
provide('selectionIds', selectionIds);
|
provide('homeViewer', homeViewer);
|
provide('viewInstance', viewInstance);
|
provide('clearSelect', clearSelect);
|
provide('getTableList', getTableList);
|
// 销毁
|
const destroyMap = () => {
|
if (viewer) {
|
viewer.destroy();
|
viewer = null;
|
}
|
publicCesiumInstance = null;
|
};
|
|
watch(uploadPatchDialog, newVal => {
|
if (newVal) {
|
setTimeout(() => {
|
initMap();
|
getTableList();
|
}, 0);
|
} else {
|
if (funButtonEle.value) {
|
isBoxSelect.value = false;
|
isDrawPolygon.value = false;
|
}
|
destroyMap();
|
}
|
});
|
|
onBeforeUnmount(() => {
|
destroyMap();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
:deep(.el-dialog__body) {
|
padding: 10px 39px 43px 39px !important;
|
}
|
|
.container {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
}
|
|
.infoBox {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 16px;
|
border: 1px solid;
|
border: 1px solid #e8e8e8;
|
border-radius: 4px;
|
background: #fff;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
.itemBoxLeft {
|
flex: 1;
|
display: grid;
|
grid-template-columns: repeat(2, 1fr);
|
row-gap: 0;
|
padding: 0; // 移除内边距,让边框贴合
|
font-size: 14px;
|
}
|
|
.itemCon {
|
border-bottom: 1px solid #e8e8e8;
|
|
&:nth-child(2n) {
|
.itemBox {
|
border-right: none;
|
}
|
}
|
|
&:nth-last-child(-n + 2) {
|
border-bottom: none;
|
}
|
}
|
|
.itemBox {
|
display: flex;
|
align-items: center;
|
height: 33px;
|
padding: 0 10px;
|
border-right: 1px solid #e8e8e8;
|
border-bottom: none; // 由.itemCon控制底部边框
|
|
.itemTitle {
|
width: 202px;
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: 400;
|
font-size: 14px;
|
color: #383838;
|
text-align: right;
|
background: #fafafa;
|
height: 100%;
|
line-height: 33px;
|
padding-right: 10px;
|
margin: 0 -10px 0 -10px; // 拉伸背景色
|
}
|
|
.itemContent {
|
flex: 1;
|
padding-left: 10px;
|
}
|
}
|
}
|
|
.map-container {
|
position: relative;
|
height: 650px;
|
width: 100%;
|
}
|
.table-overlay {
|
position: absolute;
|
top: 0;
|
left: 0;
|
height: 99%;
|
z-index: 999;
|
width: 277px;
|
overflow: hidden;
|
background: rgba(0, 0, 0, 0.4);
|
backdrop-filter: blur(5px);
|
border-radius: 8px 8px 8px 8px;
|
padding: 6px 10px 0 10px;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.table-content {
|
width: 100%;
|
display: flex;
|
flex-direction: column;
|
height: 99%;
|
.tabname {
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: bold;
|
font-size: 14px;
|
color: #ffffff;
|
}
|
// 表格样式
|
:deep(.el-table) {
|
// 清除表格内部横线和竖线
|
&::before,
|
&::after,
|
.el-table__inner-wrapper::before,
|
.el-table__inner-wrapper::after {
|
background-color: transparent !important;
|
display: none !important; // 彻底隐藏伪元素边框
|
}
|
.el-table__header-wrapper th {
|
border: none !important;
|
}
|
--el-table-bg-color: transparent !important;
|
--el-table-tr-bg-color: transparent !important;
|
|
--el-table-row-hover-bg-color: rgba(30, 58, 138, 0.5) !important;
|
--el-table-current-row-bg-color: rgba(30, 58, 138, 0.7) !important;
|
color: #fff !important;
|
.cell {
|
padding: 0px !important;
|
}
|
// 隔行变色
|
.even-row {
|
background-color: rgba(255, 255, 255, 0.17) !important;
|
}
|
.oddNumberRow {
|
background-color: rgba(255, 255, 255, 0.08) !important;
|
}
|
|
// 表头样式
|
.el-table__header {
|
th {
|
background: rgba(51, 51, 51, 0.32) !important;
|
font-family: Source Han Sans CN;
|
font-weight: 500;
|
font-size: 14px;
|
color: #ffffff;
|
.cell {
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
}
|
}
|
|
// 表格主体
|
.el-table__body {
|
tr:hover > td {
|
background-color: var(--el-table-row-hover-bg-color) !important;
|
}
|
|
td {
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
|
}
|
}
|
|
// 选中行
|
.current-row td {
|
background-color: var(--el-table-current-row-bg-color) !important;
|
}
|
}
|
|
.operationspan {
|
cursor: pointer;
|
}
|
.operationspan:first-child {
|
margin-right: 10px;
|
}
|
// 分页
|
:deep(.pagination-container) {
|
background: transparent !important;
|
}
|
:deep(.el-pagination) {
|
.btn-prev,
|
.btn-next {
|
padding: 5px 13px;
|
}
|
}
|
:deep(.el-pager li) {
|
margin: 0 0.4rem;
|
background: rgba(34, 34, 34, 0.9) !important;
|
box-shadow: 0px 4px 72px 0px rgba(0, 0, 0, 0.25) !important;
|
border-radius: 8px 8px 8px 8px !important;
|
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: 400;
|
font-size: 14px;
|
color: #ededed !important;
|
}
|
:deep(.el-pager li.is-active) {
|
border: 1px solid rgba(255, 255, 255, 0.99) !important;
|
}
|
:deep(.el-pagination button) {
|
background: rgba(34, 34, 34, 0.9) !important;
|
color: #ededed !important;
|
border-radius: 8px 8px 8px 8px !important;
|
}
|
.pagination-container {
|
margin-top: auto;
|
padding: 10px 0;
|
background: white;
|
display: flex;
|
justify-content: center;
|
height: 20px;
|
margin: 24px 0 14px 0;
|
}
|
}
|
|
.el-table {
|
flex: 1; /* 让表格占据剩余空间 */
|
overflow: auto;
|
}
|
.btnGroups {
|
position: absolute;
|
bottom: 49px;
|
left: 50%;
|
img {
|
width: 125px;
|
height: 45px;
|
cursor: pointer;
|
}
|
}
|
.btnGroups img:first-child {
|
margin-right: 21px;
|
}
|
#spotMap {
|
height: 100%;
|
width: 100%;
|
}
|
</style>
|