<template>
|
<el-dialog
|
class="spotDialog"
|
: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">
|
<span
|
v-if="
|
props.title === '图斑编辑' &&
|
(item.name === '文件名称' || item.name === '图斑类型')
|
"
|
style="color: red"
|
>*</span
|
>{{ item.name }}:
|
</div>
|
<div class="itemContent">
|
<template v-if="props.title === '图斑编辑' && item.editable">
|
<template v-if="item.name === '图斑类型'">
|
<el-select
|
v-model="item.value"
|
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" />
|
</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="is_exception" align="center" label="图斑状态">
|
<template #default="scope">
|
<span>{{ scope.row.is_exception === 2 ? '异常' : '正常' }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" align="center" v-if="props.title === '图斑编辑'">
|
<template #default="scope">
|
<span class="operationspan" @click="handleDelete(scope.row)">删除</span>
|
<span class="operationspan" @click="handleSelectionChange(scope.row)">编辑</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
<div class="pagination-container">
|
<el-pagination
|
:current-page="params.current"
|
:page-size="params.size"
|
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 @click="handleSave" src="@/assets/images/home/territory/savebtn.png" alt="" />
|
<img @click="handleCancel" 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 { ElMessage, ElMessageBox } from 'element-plus';
|
import {
|
patchEditApi,
|
spotManagementTableApi,
|
searchManagementApi,
|
uploadManagementApi,
|
tableMapListApi,
|
deletePatches,
|
} from '@/api/patchManagement/index';
|
import { getCenterPoint } 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, onMounted } from 'vue';
|
import FunButton from '@/views/resource/components/FunButton.vue';
|
const uploadPatchDialog = defineModel('show');
|
const props = defineProps(['title', 'detailid', 'detailList', 'spotTypeOption']);
|
const polygonTableEle = ref(null);
|
let publicCesiumInstance = null;
|
let viewer = null;
|
const viewInstance = shallowRef(null);
|
const homeViewer = shallowRef(null);
|
let tbJwdList = [];
|
let total = ref(0);
|
const refreshonload = inject('searchReset');
|
// 当前选中的图斑面数据
|
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([]);
|
const infoList = ref([
|
{ name: '文件名称', value: '', field: 'file_name', editable: true },
|
{ name: '图斑类型', value: '', field: 'lot_type_id', editable: true },
|
{ name: '图斑数量', value: '', field: 'patches_num', editable: false },
|
{ name: '异常图斑数量', value: '', field: 'exception_num', editable: false },
|
{ name: '行政区划', value: '', field: 'areaName', editable: false },
|
{ name: '数据来源', value: '', field: 'dataFrom', editable: false },
|
{ name: '创建时间', value: '', field: 'create_time', editable: false },
|
{ name: '创建人', value: '', field: 'user_name', editable: false },
|
]);
|
watch(
|
() => props.spotTypeOption,
|
newOptions => {
|
if (newOptions) {
|
spotTypeOptions.value = newOptions.map(opt => ({
|
label: opt.label,
|
value: String(opt.value),
|
}));
|
}
|
},
|
{ immediate: true }
|
);
|
watch(
|
() => props.detailList,
|
newVal => {
|
if (newVal) {
|
updateInfoList(newVal);
|
}
|
},
|
{ immediate: true }
|
);
|
// 将 lot_type_id 转换为对应的 label
|
const getPatchTypeLabel = lotTypeId => {
|
const option = spotTypeOptions.value.find(opt => opt.value === String(lotTypeId));
|
return option ? option.label : '';
|
};
|
const updateInfoList = detailData => {
|
infoList.value = infoList.value.map(item => {
|
let value = detailData[item.field] !== undefined ? detailData[item.field] : item.value;
|
// 处理图斑类型字段
|
if (item.name === '图斑类型') {
|
// 如果有 patches_type_desc,显示它(但存储的是 lot_type_id)
|
if (detailData.patches_type_desc !== undefined) {
|
return {
|
...item,
|
value: detailData.patches_type_desc,
|
// 保留原始 lot_type_id 用于提交
|
originalValue: detailData.lot_type_id,
|
};
|
}
|
// 否则根据 lot_type_id 查找对应的 label
|
else if (detailData.lot_type_id !== undefined) {
|
return {
|
...item,
|
value: getPatchTypeLabel(detailData.lot_type_id),
|
originalValue: detailData.lot_type_id,
|
};
|
}
|
}
|
|
return {
|
...item,
|
value: value,
|
};
|
});
|
};
|
const params = ref({
|
current: 1,
|
size: 20,
|
});
|
// 图斑管理表格
|
const getTableList = () => {
|
const params = {
|
patchesInfoId: props.detailid,
|
};
|
tableMapListApi(params).then(res => {
|
tableData.value = res.data.data.map(item => ({
|
...item,
|
dkfw: item.sdfw && item.is_exception == 1 ? item.sdfw : item.dkfw,
|
}));
|
// 先清空地图现有图斑
|
tbJwdList = [];
|
viewer?.entities.removeAll(); // 清除所有实体
|
// 加载图斑
|
entitiesAddSpot();
|
});
|
};
|
|
const handleSizeChange = () => {};
|
const handleCurrentChange = () => {};
|
const tableData = ref([]);
|
// 地图
|
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;
|
let clickTableID = tableData.value.findIndex(i => i.id == pick.id?.customInfo.id);
|
// 计算表格滚动至中间位置
|
const rows = polygonTableEle?.value.$el.querySelectorAll('.el-table__body tr');
|
let targetRow = rows[clickTableID];
|
nextTick(() => {
|
const table = polygonTableEle?.value;
|
if (!table) return;
|
if (targetRow) {
|
targetRow.scrollIntoView({
|
behavior: 'smooth',
|
block: 'center',
|
});
|
polygonTableEle?.value.setCurrentRow(tableData.value[clickTableID]);
|
}
|
});
|
// 表格也对应选中数据 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 => {
|
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;
|
}
|
};
|
// 删除
|
const handleDelete = row => {
|
ElMessageBox.confirm('确认删除当前行图斑?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning',
|
}).then(() => {
|
deletePatches({ ids: row.id }).then(res => {
|
if (res.data.code !== 0) return ElMessage.warning('删除失败');
|
ElMessage.success('删除成功');
|
getTableList();
|
});
|
});
|
};
|
|
// 完成
|
const handleSave = () => {
|
const fileNameItem = infoList.value.find(item => item.name === '文件名称');
|
const patchTypeItem = infoList.value.find(item => item.name === '图斑类型');
|
const updateParams = {
|
file_name: fileNameItem?.value || '',
|
lot_type_id: patchTypeItem?.originalValue || patchTypeItem?.value || '',
|
type: patchTypeItem?.originalValue || patchTypeItem?.value || '',
|
id: props.detailList.id,
|
};
|
|
patchEditApi(updateParams).then(res => {
|
console.log('111', res.data.data);
|
|
ElMessage.success(res.data.data);
|
refreshonload();
|
uploadPatchDialog.value = false;
|
});
|
};
|
// 取消
|
const handleCancel = () => {};
|
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();
|
}
|
});
|
onMounted(() => {});
|
onBeforeUnmount(() => {
|
destroyMap();
|
});
|
</script>
|
<style lang="scss">
|
.spotDialog {
|
.el-dialog.is-align-center .el-dialog__header .el-dialog__title {
|
padding-left: 16px !important;
|
}
|
}
|
</style>
|
<style scoped lang="scss">
|
// :deep(.el-dialog.is-align-center) {
|
// :deep(.el-dialog__header) {
|
// .el-dialog__title {
|
// padding-left: 14px !important;
|
// }
|
// }
|
// }
|
.container {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
padding: 10px 20px 23px 20px;
|
}
|
|
.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: 620px;
|
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>
|