From 6f3c7a7f01998a51cc70f7a6b5133a8253b51454 Mon Sep 17 00:00:00 2001
From: 张含笑 <zhx18749296735@163.com>
Date: Thu, 30 Oct 2025 17:05:44 +0800
Subject: [PATCH] feat:计算面积
---
src/views/layerManagement/components/rightEdit.vue | 56 ++++++++++--------
src/views/layerManagement/index.vue | 82 +++++++++++++++++++++------
2 files changed, 93 insertions(+), 45 deletions(-)
diff --git a/src/views/layerManagement/components/rightEdit.vue b/src/views/layerManagement/components/rightEdit.vue
index eb3a508..b16dbfc 100644
--- a/src/views/layerManagement/components/rightEdit.vue
+++ b/src/views/layerManagement/components/rightEdit.vue
@@ -52,17 +52,11 @@
</div>
<div class="detailInfo">
<div class="infpItem" v-if="layerParams.fenceType === 1">
+
<div class="itemData">
- <div class="title">围栏总数量</div>
+ <div class="title">围栏面积</div>
<div class="num">
- <span>{{ totalCount }}</span
- >个
- </div>
- </div>
- <div class="itemData">
- <div class="title">围栏总面积</div>
- <div class="num">
- <span>{{ totalArea }}</span
+ <span>{{ fenceArea }}</span
>m²
</div>
</div>
@@ -136,30 +130,38 @@
const detailData = ref(null);
const totalArea = ref(null);
const totalCount = ref(null);
+const fenceArea = ref(0)
detailData.value = layerParams.value.editDetailData;
totalArea.value = layerParams.value.total_area;
totalCount.value = layerParams.value.total_count;
+fenceArea.value = layerParams.value.fenceArea
+
+watch(
+ () => layerParams.value.fenceArea,
+ (newArea) => {
+ if (newArea !== undefined && newArea !== null) {
+ fenceArea.value = newArea;
+ formData.value.area = newArea;
+ }
+ },
+ { immediate: true }
+);
watch(
() => timeValue.value,
(newTimeArr) => {
- // timeValue 是数组:[开始时间, 结束时间](未选择时为 '' 或空数组)
- if (Array.isArray(newTimeArr) && newTimeArr.length === 2) {
- const startTime = newTimeArr[0]; // 开始时间(Date 对象或时间字符串)
- const endTime = newTimeArr[1]; // 结束时间(Date 对象或时间字符串)
- // 用 dayjs 格式化为 "YYYY-MM-DD HH:mm:ss" 格式
+ if (Array.isArray(newTimeArr) && newTimeArr.length === 2) {
+ const startTime = newTimeArr[0];
+ const endTime = newTimeArr[1];
formData.value.control_start_time = dayjs(startTime).format('YYYY-MM-DD HH:mm:ss');
formData.value.control_end_time = dayjs(endTime).format('YYYY-MM-DD HH:mm:ss');
-
- console.log('格式化后开始时间:', formData.value.control_start_time);
- console.log('格式化后结束时间:', formData.value.control_end_time);
} else {
- // 未选择时间时,清空两个字段
+
formData.value.control_start_time = '';
formData.value.control_end_time = '';
}
},
- { immediate: true } // 初始化时执行一次,处理默认值
+ { immediate: true }
);
const clearAllData = () => {
detailData.value = {};
@@ -229,10 +231,10 @@
onMounted(() => {
// 获取判断状态(默认设为 1)
const addOrEditStatus = layerParams.value.decideWhetherToAddOrEdit || 1;
-
if (addOrEditStatus === 2) {
// 编辑状态:回显数据(从 layerParams.editDetailData 读取)
const editData = layerParams.value.editDetailData || {};
+
formData.value = {
folder_id: editData.folder_id || '',
@@ -245,22 +247,24 @@
control_end_time: editData.control_end_time || '',
geo_data: editData.geo_data || '',
};
-
-
- if (editData.folder_id && options.value.length > 0) {
-
+ if (editData.folder_id && options.value.length > 0) {
const matchedFolder = options.value.find(
item => item.value === String(editData.folder_id)
);
-
if (matchedFolder) {
formData.value.folder_id = matchedFolder.value;
}
}
-
+ if (editData.control_start_time && editData.control_end_time) {
+ timeValue.value = [
+ dayjs(editData.control_start_time).toDate(),
+ dayjs(editData.control_end_time).toDate()
+ ];
+ }
// 回显总数和总面积(编辑时可能需要展示)
totalArea.value = layerParams.value.total_area || 0;
totalCount.value = layerParams.value.total_count || 0;
+ fenceArea.value = editData.area|| 0;
} else {
// 新增状态:不回显数据,清空总数和总面积
totalArea.value = null;
diff --git a/src/views/layerManagement/index.vue b/src/views/layerManagement/index.vue
index 3e3d1bb..969785e 100644
--- a/src/views/layerManagement/index.vue
+++ b/src/views/layerManagement/index.vue
@@ -29,6 +29,7 @@
</template>
<script setup>
+import * as turf from '@turf/turf'
import { dataFolderApi } from '@/api/layer/index';
import folderFile from '@/views/layerManagement/components/folderFile.vue'
import { parseGeoDataToPositions } from '@/utils/geoParseUtil';
@@ -42,6 +43,12 @@
import _, { cloneDeep, throttle } from 'lodash';
import { ElButton } from 'element-plus';
import { provide } from 'vue';
+import { useStore } from 'vuex';
+const store = useStore();
+const userInfo = computed(() => store.getters.userInfo);
+const areaCode = userInfo.value?.detail?.areaCode || '';
+// console.log('用户信息',areaCode);
+
const activeName = ref('电子围栏');
const activeType = ref('0');
let tbJwdList = [];
@@ -75,6 +82,7 @@
editFolder:false,
folderOption:[] ,//文件夹选项
fenceType:1,
+ fenceArea:0,//围栏面积
});
const handleClick = tab => {
@@ -179,11 +187,7 @@
});
});
focusOnAllFeatures();
- // 添加点击事件(参考 entitiesAddSpot 的 spotHighlighting 逻辑)
- // 移除已有点击事件,避免重复绑定
- // viewInstance.value?.removeLeftClickEvent('fenceHighlighting');
- // 绑定新的点击事件,用于高亮选中的围栏
- // viewInstance.value?.addLeftClickEvent(null, handleFenceClick, 'fenceHighlighting');
+ viewInstance.value?.addLeftClickEvent(null, handleFenceClick, );
};
//计算所有图斑的包围球并定位
const focusOnAllFeatures = () => {
@@ -203,26 +207,24 @@
),
});
};
-// 围栏点击处理函数(高亮选中项 + 可联动右侧编辑组件)
+// 围栏点击处理函数
const handleFenceClick = movement => {
if (!viewer) return;
-
- // 拾取点击的实体
const pickedObject = viewer.scene.pick(movement.position);
if (Cesium.defined(pickedObject) && pickedObject.id?.customType === 'fence_polygon') {
const selectedEntity = pickedObject.id;
console.log('选中的围栏数据:', selectedEntity.customInfo);
- // 1. 高亮处理(清除其他实体高亮,仅高亮当前选中)
- viewer.entities.values.forEach(entity => {
- if (entity.customType === 'fence_polygon') {
- // 恢复默认样式
- entity.polygon.material =
- entity === selectedEntity
- ? selectedEntity.polygon.material.color.withAlpha(0.8) // 选中时加深透明度
- : selectedEntity.polygon.material.color.withAlpha(0.5); // 未选中恢复默认
- }
- });
+ // // 1. 高亮处理(清除其他实体高亮,仅高亮当前选中)
+ // viewer.entities.values.forEach(entity => {
+ // if (entity.customType === 'fence_polygon') {
+ // // 恢复默认样式
+ // entity.polygon.material =
+ // entity === selectedEntity
+ // ? selectedEntity.polygon.material.color.withAlpha(0.8) // 选中时加深透明度
+ // : selectedEntity.polygon.material.color.withAlpha(0.5); // 未选中恢复默认
+ // }
+ // });
// 2. 联动右侧编辑组件(假设 rightEdit 有接收数据的方法)
// 例如:通过 ref 调用 rightEdit 的 setData 方法
@@ -238,6 +240,7 @@
const drawPolygonExample = new DrawPolygon();
// 地图初始化
+// 地图初始化
const initMap = () => {
publicCesiumInstance = new PublicCesium({
dom: 'layMap',
@@ -249,6 +252,23 @@
viewer = publicCesiumInstance.getViewer();
viewInstance.value = publicCesiumInstance;
+
+ const nanChangPosition = Cesium.Cartesian3.fromDegrees(
+ 115.892151, // 经度
+ 28.676493, // 纬度
+ 15000 // 相机高度
+ );
+
+ // 执行相机飞行
+ viewer.camera.flyTo({
+ destination: nanChangPosition,
+ duration: 0,
+ orientation: {
+ heading: Cesium.Math.toRadians(0),
+ pitch: Cesium.Math.toRadians(-90),
+ roll: 0
+ }
+ });
};
@@ -271,10 +291,34 @@
let polygon = curPolygonPosition.map(item => [item?.lng, item?.lat]);
+
let polygonString = JSON.stringify(polygon);
// polygon.push([curPolygonPosition[0]?.lng, curPolygonPosition[0]?.lat]);
layerParams.value.polygonPosition = polygonString
-
+ if (polygon.length >= 3) {
+ // 确保多边形闭合:最后一个点与第一个点一致(避免计算偏差)
+ const firstPoint = polygon[0];
+ const lastPoint = polygon[polygon.length - 1];
+ const isClosed = (
+ _.round(firstPoint[0], 6) === _.round(lastPoint[0], 6) &&
+ _.round(firstPoint[1], 6) === _.round(lastPoint[1], 6)
+ );
+ // 若未闭合,手动添加闭合点
+ const closedPolygon = isClosed ? polygon : [...polygon, firstPoint];
+
+ // 转换为 turf 支持的 GeoJSON 格式(Polygon 类型需外层嵌套数组)
+ const turfPolygon = turf.polygon([closedPolygon]);
+
+ // 计算面积(turf.area() 返回平方米,保留2位小数)
+ const area = _.round(turf.area(turfPolygon), 2);
+
+ // 赋值给 layerParams,供页面显示或提交使用
+ layerParams.value.fenceArea = area;
+ console.log('计算的多边形面积(平方米):', layerParams.value.fenceArea);
+ } else {
+ // 坐标点不足3个时,清空面积
+ layerParams.value.fenceArea = 0;
+ }
};
const throttleLoadPlanarRoute = throttle(loadPlanarRoute, 200);
drawPolygonExample.subscribe('getPolygonPositions', data => {
--
Gitblit v1.9.3