|
@@ -1,6 +1,17 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="edit-map">
|
|
<div class="edit-map">
|
|
|
<custom-header @goback="goBack" :isGoBack="true" :name="viewOnly ? '查看区域' : '勾选地块'"></custom-header>
|
|
<custom-header @goback="goBack" :isGoBack="true" :name="viewOnly ? '查看区域' : '勾选地块'"></custom-header>
|
|
|
|
|
+ <div class="region-type-tabs">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in regionTypeTabs"
|
|
|
|
|
+ :key="item.value"
|
|
|
|
|
+ class="region-type-tab"
|
|
|
|
|
+ :class="{ 'region-type-tab--active': activeRegionType === item.value }"
|
|
|
|
|
+ @click="handleRegionTypeClick(item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item.label }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
<div class="variety-tabs" v-if="varietyTabs.length > 0">
|
|
<div class="variety-tabs" v-if="varietyTabs.length > 0">
|
|
|
<div v-for="(v, index) in varietyTabs" :key="index" class="variety-tab"
|
|
<div v-for="(v, index) in varietyTabs" :key="index" class="variety-tab"
|
|
|
:class="{ 'variety-tab--active': activeVariety === index }" @click="handleVarietyClick(v, index)">
|
|
:class="{ 'variety-tab--active': activeVariety === index }" @click="handleVarietyClick(v, index)">
|
|
@@ -40,10 +51,16 @@ import SaveRegionSuccessPopup from "@/components/popup/saveRegionSuccessPopup.vu
|
|
|
import { ref, computed, onActivated, onDeactivated, nextTick } from "vue";
|
|
import { ref, computed, onActivated, onDeactivated, nextTick } from "vue";
|
|
|
import { useStore } from "vuex";
|
|
import { useStore } from "vuex";
|
|
|
import DrawRegionMap from "../../interactionList/map/drawRegionMap.js";
|
|
import DrawRegionMap from "../../interactionList/map/drawRegionMap.js";
|
|
|
|
|
+import { Map as KMapMap } from "@/utils/ol-map/KMap";
|
|
|
import { useRouter, useRoute } from "vue-router";
|
|
import { useRouter, useRoute } from "vue-router";
|
|
|
import { convertPointToArray } from "@/utils/index";
|
|
import { convertPointToArray } from "@/utils/index";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
import TipPopup from "@/components/popup/tipPopup.vue";
|
|
import TipPopup from "@/components/popup/tipPopup.vue";
|
|
|
|
|
+import Style from "ol/style/Style";
|
|
|
|
|
+import { Fill, Stroke, Circle, Text } from "ol/style.js";
|
|
|
|
|
+import { Point } from "ol/geom";
|
|
|
|
|
+import * as proj from "ol/proj";
|
|
|
|
|
+import { getArea } from "ol/sphere.js";
|
|
|
|
|
|
|
|
const store = useStore();
|
|
const store = useStore();
|
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
@@ -65,6 +82,125 @@ const varietyTabs = ref([]);
|
|
|
const activeVariety = ref(0);
|
|
const activeVariety = ref(0);
|
|
|
const regionGeom = ref(null);
|
|
const regionGeom = ref(null);
|
|
|
|
|
|
|
|
|
|
+const regionTypeTabs = [
|
|
|
|
|
+ { label: "品种区", value: "variety" },
|
|
|
|
|
+ { label: "异常问题区", value: "abnormal" },
|
|
|
|
|
+ { label: "环境问题区", value: "environment" },
|
|
|
|
|
+ { label: "休眠区", value: "sleep" },
|
|
|
|
|
+];
|
|
|
|
|
+const activeRegionType = ref("variety");
|
|
|
|
|
+
|
|
|
|
|
+const handleRegionTypeClick = (item) => {
|
|
|
|
|
+ activeRegionType.value = item.value;
|
|
|
|
|
+ if (drawRegionMap.kmap) {
|
|
|
|
|
+ applyRegionStyles();
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const createPolygonStyleFunc = (fillColor, strokeColor) => {
|
|
|
|
|
+ return (feature) => {
|
|
|
|
|
+ const styles = [];
|
|
|
|
|
+ const coord = feature.getGeometry().getCoordinates()[0];
|
|
|
|
|
+ for (let i = 0; i < coord[0].length - 1; i++) {
|
|
|
|
|
+ if (i % 2) {
|
|
|
|
|
+ styles.push(
|
|
|
|
|
+ new Style({
|
|
|
|
|
+ geometry: new Point(coord[0][i]),
|
|
|
|
|
+ image: new Circle({
|
|
|
|
|
+ radius: 4,
|
|
|
|
|
+ fill: new Fill({
|
|
|
|
|
+ color: strokeColor,
|
|
|
|
|
+ }),
|
|
|
|
|
+ stroke: new Stroke({
|
|
|
|
|
+ color: "#fff",
|
|
|
|
|
+ width: 1,
|
|
|
|
|
+ }),
|
|
|
|
|
+ }),
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+ } else {
|
|
|
|
|
+ styles.push(
|
|
|
|
|
+ new Style({
|
|
|
|
|
+ geometry: new Point(coord[0][i]),
|
|
|
|
|
+ image: new Circle({
|
|
|
|
|
+ radius: 6,
|
|
|
|
|
+ fill: new Fill({
|
|
|
|
|
+ color: "#fff",
|
|
|
|
|
+ }),
|
|
|
|
|
+ }),
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ const fillStyle = new Style({
|
|
|
|
|
+ fill: new Fill({
|
|
|
|
|
+ color: fillColor,
|
|
|
|
|
+ }),
|
|
|
|
|
+ stroke: new Stroke({
|
|
|
|
|
+ color: strokeColor,
|
|
|
|
|
+ width: 2,
|
|
|
|
|
+ }),
|
|
|
|
|
+ });
|
|
|
|
|
+ let geom = feature.getGeometry().clone();
|
|
|
|
|
+ geom.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572"));
|
|
|
|
|
+ let area = getArea(geom);
|
|
|
|
|
+ area = (area + area / 2) / 1000;
|
|
|
|
|
+ const areaValStyle = new Style({
|
|
|
|
|
+ text: new Text({
|
|
|
|
|
+ font: "16px sans-serif",
|
|
|
|
|
+ text: area.toFixed(2) + "亩",
|
|
|
|
|
+ fill: new Fill({ color: "#fff" }),
|
|
|
|
|
+ }),
|
|
|
|
|
+ });
|
|
|
|
|
+ styles.push(fillStyle, areaValStyle);
|
|
|
|
|
+ return styles;
|
|
|
|
|
+ };
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const applyRegionStyles = () => {
|
|
|
|
|
+ const kmap = drawRegionMap.kmap;
|
|
|
|
|
+ if (!kmap) return;
|
|
|
|
|
+
|
|
|
|
|
+ let lineColor = "#2199F8";
|
|
|
|
|
+ let vertexColor = "#2199F8";
|
|
|
|
|
+ let fillColor = [0, 0, 0, 0.5];
|
|
|
|
|
+ let strokeColor = "#2199F8";
|
|
|
|
|
+
|
|
|
|
|
+ if (activeRegionType.value === "variety") {
|
|
|
|
|
+ lineColor = "#18AA8B";
|
|
|
|
|
+ vertexColor = "#18AA8B";
|
|
|
|
|
+ fillColor = [0, 57, 44, 0.5];
|
|
|
|
|
+ strokeColor = "#18AA8B";
|
|
|
|
|
+ } else if (activeRegionType.value === "abnormal") {
|
|
|
|
|
+ lineColor = "#E03131";
|
|
|
|
|
+ vertexColor = "#E03131";
|
|
|
|
|
+ fillColor = [100, 0, 0, 0.5];
|
|
|
|
|
+ strokeColor = "#E03131";
|
|
|
|
|
+ }else if (activeRegionType.value === "environment") {
|
|
|
|
|
+ lineColor = "#FDCF7F";
|
|
|
|
|
+ vertexColor = "#FDCF7F";
|
|
|
|
|
+ fillColor = [151, 96, 0, 0.5];
|
|
|
|
|
+ strokeColor = "#FDCF7F";
|
|
|
|
|
+ }else{
|
|
|
|
|
+ lineColor = "#A6A6A6";
|
|
|
|
|
+ vertexColor = "#A6A6A6";
|
|
|
|
|
+ fillColor = [166, 166, 166, 0.25];
|
|
|
|
|
+ strokeColor = "#A6A6A6";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 勾画进行中:通过 Map.drawStyleColors 影响底层 drawStyleFunc 颜色
|
|
|
|
|
+ KMapMap.drawStyleColors = {
|
|
|
|
|
+ line: lineColor,
|
|
|
|
|
+ vertex: vertexColor,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ kmap.polygonStyle = createPolygonStyleFunc(fillColor, strokeColor);
|
|
|
|
|
+ if (kmap.polygonLayer?.layer && typeof kmap.polygonLayer.layer.setStyle === "function") {
|
|
|
|
|
+ kmap.polygonLayer.layer.setStyle(kmap.polygonStyle);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const isValidGeom = (geom) => {
|
|
const isValidGeom = (geom) => {
|
|
|
if (typeof geom !== "string") return false;
|
|
if (typeof geom !== "string") return false;
|
|
|
const normalized = geom.trim();
|
|
const normalized = geom.trim();
|
|
@@ -171,6 +307,7 @@ onActivated(async () => {
|
|
|
await fetchFarmSubjectDetail();
|
|
await fetchFarmSubjectDetail();
|
|
|
|
|
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, editable, true, true);
|
|
drawRegionMap.initMap(point.value, mapContainer.value, editable, true, true);
|
|
|
|
|
+ applyRegionStyles();
|
|
|
|
|
|
|
|
// 首次进入时,fetch 阶段可能先于地图初始化触发了 tab 渲染;
|
|
// 首次进入时,fetch 阶段可能先于地图初始化触发了 tab 渲染;
|
|
|
// 这里在地图可用后再补渲一次,确保“其他品种只读地块”能显示出来
|
|
// 这里在地图可用后再补渲一次,确保“其他品种只读地块”能显示出来
|
|
@@ -183,6 +320,7 @@ onActivated(async () => {
|
|
|
if (viewOnly.value && drawRegionMap.kmap && drawRegionMap.editable) {
|
|
if (viewOnly.value && drawRegionMap.kmap && drawRegionMap.editable) {
|
|
|
drawRegionMap.destroyMap();
|
|
drawRegionMap.destroyMap();
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, false, true, false);
|
|
drawRegionMap.initMap(point.value, mapContainer.value, false, true, false);
|
|
|
|
|
+ applyRegionStyles();
|
|
|
if (varietyTabs.value.length > 0 && varietyTabs.value[activeVariety.value]) {
|
|
if (varietyTabs.value.length > 0 && varietyTabs.value[activeVariety.value]) {
|
|
|
handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
}
|
|
}
|
|
@@ -192,6 +330,7 @@ onActivated(async () => {
|
|
|
if (!viewOnly.value && drawRegionMap.kmap && !drawRegionMap.editable) {
|
|
if (!viewOnly.value && drawRegionMap.kmap && !drawRegionMap.editable) {
|
|
|
drawRegionMap.destroyMap();
|
|
drawRegionMap.destroyMap();
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
|
|
|
+ applyRegionStyles();
|
|
|
if (varietyTabs.value.length > 0 && varietyTabs.value[activeVariety.value]) {
|
|
if (varietyTabs.value.length > 0 && varietyTabs.value[activeVariety.value]) {
|
|
|
handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
}
|
|
}
|
|
@@ -377,6 +516,7 @@ const handleEditRegion = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
|
|
|
+ applyRegionStyles();
|
|
|
|
|
|
|
|
// 切到编辑态后立即补渲“其他品种只读地块”,避免首次点击编辑时不显示
|
|
// 切到编辑态后立即补渲“其他品种只读地块”,避免首次点击编辑时不显示
|
|
|
renderReadonlyVarietyRegions(activeVariety.value);
|
|
renderReadonlyVarietyRegions(activeVariety.value);
|
|
@@ -409,6 +549,29 @@ const handleTipConfirm = () => {
|
|
|
height: 100vh;
|
|
height: 100vh;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
+ .region-type-tabs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ background: #f4f4f4;
|
|
|
|
|
+ margin: 10px 10px 0;
|
|
|
|
|
+ padding: 3px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+
|
|
|
|
|
+ .region-type-tab {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 5px 0;
|
|
|
|
|
+ color: #767676;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .region-type-tab--active {
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ color: #0D0D0D;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
.variety-tabs {
|
|
.variety-tabs {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
@@ -422,22 +585,23 @@ const handleTipConfirm = () => {
|
|
|
.variety-tab {
|
|
.variety-tab {
|
|
|
padding: 4px 12px;
|
|
padding: 4px 12px;
|
|
|
border-radius: 2px;
|
|
border-radius: 2px;
|
|
|
- color: #767676;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- border: 0.5px solid rgba(174, 174, 174, 0.8);
|
|
|
|
|
|
|
+ color: #575757;
|
|
|
|
|
+ background: #F4F4F4;
|
|
|
|
|
+ border: 1px solid transparent;
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.variety-tab--active {
|
|
.variety-tab--active {
|
|
|
- background: #2199F8;
|
|
|
|
|
- color: #ffffff;
|
|
|
|
|
|
|
+ background: rgba(33, 153, 248, 0.1);
|
|
|
|
|
+ color: #2199F8;
|
|
|
|
|
+ border: 1px solid #2199F8;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.edit-map-content {
|
|
.edit-map-content {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|
|
|
- height: calc(100% - 58px);
|
|
|
|
|
|
|
+ height: calc(100% - 202px);
|
|
|
position: relative;
|
|
position: relative;
|
|
|
|
|
|
|
|
.edit-map-tip {
|
|
.edit-map-tip {
|
|
@@ -459,7 +623,7 @@ const handleTipConfirm = () => {
|
|
|
|
|
|
|
|
.edit-map-footer {
|
|
.edit-map-footer {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
- bottom: 110px;
|
|
|
|
|
|
|
+ bottom: 35px;
|
|
|
left: 12px;
|
|
left: 12px;
|
|
|
width: calc(100% - 24px);
|
|
width: calc(100% - 24px);
|
|
|
display: flex;
|
|
display: flex;
|