|
@@ -0,0 +1,349 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="edit-map">
|
|
|
|
|
+ <custom-header :name="viewOnly ? '查看区域' : '勾选地块'"></custom-header>
|
|
|
|
|
+ <div class="variety-tabs" v-if="varietyTabs.length > 0">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(v, index) in varietyTabs"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="variety-tab"
|
|
|
|
|
+ :class="{ 'variety-tab--active': activeVariety === index }"
|
|
|
|
|
+ @click="handleVarietyClick(v, index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ v.regionName }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="edit-map-content">
|
|
|
|
|
+ <div class="edit-map-tip" v-if="!viewOnly">操作提示:拖动圆点,即可调整地块边界</div>
|
|
|
|
|
+ <div class="map-container" ref="mapContainer"></div>
|
|
|
|
|
+ <div class="edit-map-footer">
|
|
|
|
|
+ <div class="footer-back" @click="goBack">
|
|
|
|
|
+ <img class="back-icon" src="@/assets/img/home/go-back.png" alt="" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="edit-map-footer-btn" v-if="!viewOnly">
|
|
|
|
|
+ <div class="btn-reset" @click="resetPolygon">重置区域</div>
|
|
|
|
|
+ <div class="btn-confirm" @click="confirm">确认</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <save-region-success-popup
|
|
|
|
|
+ v-if="!viewOnly"
|
|
|
|
|
+ v-model:show="showSuccessPopup"
|
|
|
|
|
+ :title="`${activeVarietyName} 区域已保存成功`"
|
|
|
|
|
+ @know="handleKnow"
|
|
|
|
|
+ @next="handleSelectNextVariety"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import customHeader from "@/components/customHeader.vue";
|
|
|
|
|
+import SaveRegionSuccessPopup from "@/components/popup/saveRegionSuccessPopup.vue";
|
|
|
|
|
+import { ref, computed, onMounted, onActivated, onDeactivated } from "vue";
|
|
|
|
|
+import { useStore } from "vuex";
|
|
|
|
|
+import DrawRegionMap from "../../interactionList/map/drawRegionMap.js";
|
|
|
|
|
+import { useRouter, useRoute } from "vue-router";
|
|
|
|
|
+import { convertPointToArray } from "@/utils/index";
|
|
|
|
|
+import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
|
|
+
|
|
|
|
|
+const store = useStore();
|
|
|
|
|
+const router = useRouter();
|
|
|
|
|
+const route = useRoute();
|
|
|
|
|
+const mapContainer = ref(null);
|
|
|
|
|
+const drawRegionMap = new DrawRegionMap();
|
|
|
|
|
+
|
|
|
|
|
+const showSuccessPopup = ref(true);
|
|
|
|
|
+
|
|
|
|
|
+const type = ref(null);
|
|
|
|
|
+const varietyTabs = ref([]);
|
|
|
|
|
+const activeVariety = ref(0);
|
|
|
|
|
+const farmIdData = ref(null);
|
|
|
|
|
+const gardenId = ref(store.state.home.gardenId);
|
|
|
|
|
+
|
|
|
|
|
+const getVarietyTabs = async () => {
|
|
|
|
|
+ if (!gardenId.value) return;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await VE_API.monitor.listRegionsBySubjectId({
|
|
|
|
|
+ subjectId: gardenId.value,
|
|
|
|
|
+ });
|
|
|
|
|
+ varietyTabs.value = res.data || [];
|
|
|
|
|
+ if (varietyTabs.value.length > 0) {
|
|
|
|
|
+ handleVarietyClick(varietyTabs.value[0], 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error("获取主体分区列表失败:", error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleVarietyClick = (tab, index) => {
|
|
|
|
|
+ activeVariety.value = index;
|
|
|
|
|
+ farmIdData.value = tab.farmId;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const activeVarietyName = computed(() => {
|
|
|
|
|
+ const current = varietyTabs.value[activeVariety.value];
|
|
|
|
|
+ return current?.regionName || "";
|
|
|
|
|
+});
|
|
|
|
|
+const viewOnly = computed(() => route.query.viewOnly === "1" || route.query.viewOnly === "true");
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ type.value = route.query.type;
|
|
|
|
|
+ const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
|
|
|
|
|
+ const editable = !viewOnly.value;
|
|
|
|
|
+ const showPoint = !viewOnly.value;
|
|
|
|
|
+ drawRegionMap.initMap(point, mapContainer.value, editable, true, showPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化品种 tabs
|
|
|
|
|
+ getVarietyTabs();
|
|
|
|
|
+
|
|
|
|
|
+ // 地图初始化之后(比如 initPreviewMap 里)
|
|
|
|
|
+ // const regions = [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // geometry:
|
|
|
|
|
+ // "MULTIPOLYGON(((113.61674040430906 23.586573370597367,113.61586610436014 23.585922976493354,113.61710291900188 23.58486741952544,113.61770000158238 23.585651090473736,113.61674040430906 23.586573370597367)))",
|
|
|
|
|
+ // status: "unresolved", // 未解决(蓝色)
|
|
|
|
|
+ // },
|
|
|
|
|
+ // {
|
|
|
|
|
+ // geometry:
|
|
|
|
|
+ // "MULTIPOLYGON(((113.61516640298626 23.588441931082958,113.61445736699218 23.58799411906573,113.61572616841707 23.586954554834552,113.61642987338976 23.588180707433526,113.61516640298626 23.588441931082958)))",
|
|
|
|
|
+ // status: "resolved", // 已解决(灰色)
|
|
|
|
|
+ // },
|
|
|
|
|
+ // ];
|
|
|
|
|
+
|
|
|
|
|
+ // drawRegionMap.setStatusRegions(regions);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onActivated(() => {
|
|
|
|
|
+ const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
|
|
|
|
|
+
|
|
|
|
|
+ // 从编辑态进入仅查看时,需重新初始化为不可编辑
|
|
|
|
|
+ if (viewOnly.value && drawRegionMap.kmap && drawRegionMap.editable) {
|
|
|
|
|
+ drawRegionMap.destroyMap();
|
|
|
|
|
+ drawRegionMap.initMap(point, mapContainer.value, false, true, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从仅查看进入勾画(编辑)时,需重新初始化为可编辑
|
|
|
|
|
+ if (!viewOnly.value && drawRegionMap.kmap && !drawRegionMap.editable) {
|
|
|
|
|
+ drawRegionMap.destroyMap();
|
|
|
|
|
+ drawRegionMap.initMap(point, mapContainer.value, true, true, true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 先绘制地块
|
|
|
|
|
+ const polygonData = route.query.polygonData;
|
|
|
|
|
+ const rawRangeWkt = route.query.rangeWkt;
|
|
|
|
|
+ const rangeWkt = rawRangeWkt ? decodeURIComponent(rawRangeWkt) : null;
|
|
|
|
|
+
|
|
|
|
|
+ if (rangeWkt) {
|
|
|
|
|
+ let regions = [];
|
|
|
|
|
+ try {
|
|
|
|
|
+ const parsed = JSON.parse(rangeWkt);
|
|
|
|
|
+ if (parsed && Array.isArray(parsed.geometryArr)) {
|
|
|
|
|
+ regions = parsed.geometryArr.map((item) => ({
|
|
|
|
|
+ geometry: item,
|
|
|
|
|
+ status: "unresolved",
|
|
|
|
|
+ updatedTime: route.query.updatedTime,
|
|
|
|
|
+ }));
|
|
|
|
|
+ } else if (typeof rangeWkt === "string" && rangeWkt.trim().length > 10) {
|
|
|
|
|
+ regions = [{ geometry: rangeWkt.trim(), status: "unresolved", updatedTime: route.query.updatedTime }];
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (_) {
|
|
|
|
|
+ if (typeof rangeWkt === "string" && rangeWkt.trim().length > 10) {
|
|
|
|
|
+ regions = [{ geometry: rangeWkt.trim(), status: "unresolved", updatedTime: route.query.updatedTime }];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (regions.length) {
|
|
|
|
|
+ drawRegionMap.setStatusRegions(regions);
|
|
|
|
|
+ if (viewOnly.value && drawRegionMap.fitAllRegions) {
|
|
|
|
|
+ drawRegionMap.fitAllRegions();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!viewOnly.value && polygonData) {
|
|
|
|
|
+ drawRegionMap.setAreaGeometry(JSON.parse(polygonData)?.geometryArr);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查看模式下已通过 fitAllRegions 适配;编辑模式再设置地图中心
|
|
|
|
|
+ if (!viewOnly.value) {
|
|
|
|
|
+ drawRegionMap.setMapPosition(convertPointToArray(point));
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onDeactivated(() => {
|
|
|
|
|
+ drawRegionMap.clearLayer()
|
|
|
|
|
+})
|
|
|
|
|
+const goBack = () => {
|
|
|
|
|
+ // drawRegionMap.clearLayer()
|
|
|
|
|
+ router.back()
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const resetPolygon = () => {
|
|
|
|
|
+ ElMessageBox.confirm(
|
|
|
|
|
+ "确认要重置当前地块吗?重置后将恢复到进入页面时的区域形状。",
|
|
|
|
|
+ "重置确认",
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: "确认重置",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning",
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ .then(() => {
|
|
|
|
|
+ // 只清空当前可编辑多边形,不影响只读状态图层
|
|
|
|
|
+ if (drawRegionMap.kmap && drawRegionMap.kmap.polygonLayer && drawRegionMap.kmap.polygonLayer.source) {
|
|
|
|
|
+ drawRegionMap.kmap.polygonLayer.source.clear();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用进入页面时路由上带的 polygonData 作为“初始形状”进行回显
|
|
|
|
|
+ const polygonDataStr = route.query.polygonData;
|
|
|
|
|
+ if (polygonDataStr) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const parsed = JSON.parse(polygonDataStr);
|
|
|
|
|
+ if (parsed && Array.isArray(parsed.geometryArr) && parsed.geometryArr.length) {
|
|
|
|
|
+ drawRegionMap.setAreaGeometry(parsed.geometryArr);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (_) {
|
|
|
|
|
+ // 解析失败则不做处理,仅相当于清空重画
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ElMessage.success("地块已重置");
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ // 用户取消重置,不做任何操作
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const confirm = () => {
|
|
|
|
|
+ // const polygonData = drawRegionMap.getAreaGeometry();
|
|
|
|
|
+ // sessionStorage.setItem("drawRegionPolygonData", JSON.stringify(polygonData));
|
|
|
|
|
+ showSuccessPopup.value = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleKnow = () => {
|
|
|
|
|
+ showSuccessPopup.value = false;
|
|
|
|
|
+ router.back();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleSelectNextVariety = () => {
|
|
|
|
|
+ if (varietyTabs.value.length === 0) {
|
|
|
|
|
+ handleKnow();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const nextIndex = activeVariety.value + 1;
|
|
|
|
|
+ if (nextIndex < varietyTabs.value.length) {
|
|
|
|
|
+ const nextTab = varietyTabs.value[nextIndex];
|
|
|
|
|
+ handleVarietyClick(nextTab, nextIndex);
|
|
|
|
|
+ showSuccessPopup.value = false;
|
|
|
|
|
+ // 可根据业务需要在这里重置绘制区域
|
|
|
|
|
+ // drawRegionMap.clearLayer();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果已经是最后一个品种,则直接返回上一页
|
|
|
|
|
+ handleKnow();
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.edit-map {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+
|
|
|
|
|
+ .variety-tabs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ padding: 10px 12px 0;
|
|
|
|
|
+ overflow-x: auto;
|
|
|
|
|
+ overflow-y: hidden;
|
|
|
|
|
+ flex-wrap: nowrap;
|
|
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
|
|
+
|
|
|
|
|
+ .variety-tab {
|
|
|
|
|
+ padding: 4px 12px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ color: #767676;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border: 0.5px solid rgba(174, 174, 174, 0.8);
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .variety-tab--active {
|
|
|
|
|
+ background: #2199F8;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .edit-map-content {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
+ height: calc(100% - 58px);
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ .edit-map-tip {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 23px;
|
|
|
|
|
+ left: calc(50% - 256px / 2);
|
|
|
|
|
+ z-index: 1;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ padding: 9px 20px;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .map-container {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .edit-map-footer {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: 110px;
|
|
|
|
|
+ left: 12px;
|
|
|
|
|
+ width: calc(100% - 24px);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: flex-end;
|
|
|
|
|
+
|
|
|
|
|
+ .footer-back {
|
|
|
|
|
+ padding: 6px 7px 9px;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+
|
|
|
|
|
+ .back-icon {
|
|
|
|
|
+ width: 20px;
|
|
|
|
|
+ height: 18px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .edit-map-footer-btn {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ padding: 10px 12px 20px 12px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+
|
|
|
|
|
+ div {
|
|
|
|
|
+ width: 100px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ padding: 8px 0;
|
|
|
|
|
+ border-radius: 25px;
|
|
|
|
|
+ border: 0.5px solid rgba(153, 153, 153, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .btn-confirm {
|
|
|
|
|
+ background: #000;
|
|
|
|
|
+ background-image: linear-gradient(180deg, #76c3ff 0%, #2199f8 100%);
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|