Просмотр исходного кода

feat:修改bug,添加分区管理删除功能和修改重置功能

wangsisi 14 часов назад
Родитель
Сommit
5c9acb78ec

BIN
src/assets/img/map/delete.png


+ 3 - 1
src/components/pageComponents/ArchivesFarmTimeLine.vue

@@ -180,7 +180,7 @@ const farmWorkType = {
     3: "自建农事",
 };
 
-const emits = defineEmits(["row-click"]);
+const emits = defineEmits(["row-click", "card-click"]);
 
 const solarTerms = ref([]);
 const phenologyList = ref([]);
@@ -596,6 +596,7 @@ const handleRowClick = (item) => {
 
 // 获取农事规划数据
 const getFarmWorkPlan = () => {
+    phenologyList.value = [];
     if (!props.farmId) return;
     const scopeKey = farmWorkPlanScopeKey();
     if (isRequesting.value || lastRequestedFarmId.value === scopeKey) return;
@@ -853,6 +854,7 @@ watch(
 const handleStatusDetail = (fw) => {
     // 跳转前记录当前滚动位置
     saveTimelineScrollTop();
+    emits('card-click');
     if (props.pageType === 'agri_plan') {
         if (fw?.sourceData && fw?.id) {
             router.push({

+ 11 - 1
src/views/old_mini/agri_record/index.vue

@@ -38,7 +38,7 @@
             </template>
             <div class="archives-time-line-content">
                 <archives-farm-time-line :farmId="farmIdData" :problemZoneId="currentVariety?.problemZoneTypeId" :regionId="regionData" :containerId="containerData"
-                    pageType="agri_record" :typeId="currentVariety?.typeId"></archives-farm-time-line>
+                    pageType="agri_record" :typeId="currentVariety?.typeId" @card-click="handleCardClick"></archives-farm-time-line>
             </div>
         </div>
     </div>
@@ -228,12 +228,22 @@ onMounted(() => {
 
 const changeGarden = ({ id }) => {
     gardenId.value = id;
+    if(sessionStorage.getItem('activeVariety')){
+        activeVariety.value = Number(sessionStorage.getItem('activeVariety'));
+        sessionStorage.removeItem('activeVariety');
+    } else {
+        activeVariety.value = 0;
+    }
     // 更新 store 中的状态
     store.commit("home/SET_GARDEN_ID", id);
     getVarietyTabs();
 
     startInteractPopupRef.value.getPhenologyInitOrConfirmStatus();
 };
+
+const handleCardClick = () => {
+    sessionStorage.setItem('activeVariety', activeVariety.value);
+}
 </script>
 
 <style scoped lang="scss">

+ 9 - 2
src/views/old_mini/interactionList/index.vue

@@ -593,7 +593,14 @@ const loadData = async () => {
             const interactionTypeNameList = interactionTypeNameStr
                 ? interactionTypeNameStr.split(':').map(s => s.trim()).filter(Boolean)
                 : [];
-            const interactionThemeText = `${interactionTypeNameList[0]}${interactionTypeNameList[1] ? ':' : ''}${item.reproductiveName || ''}`;
+            const reproductive = item.reproductiveName || '';
+            // 类型名各段用 : 连接;若有繁殖名则统一为「……:繁殖名」
+            let interactionThemeText = '';
+            if (!interactionTypeNameList.length) {
+                interactionThemeText = reproductive;
+            } else {
+                interactionThemeText = interactionTypeNameList[0] + ':' + reproductive;
+            }
             return {
                 ...item,
                 interactionTypeNameList,
@@ -943,7 +950,7 @@ const handleSubmitAll = () => {
                     }
 
                     .title-block {
-                        font-size: 16px;
+                        font-size: 15px;
                         color: #6f6f6f;
                         font-family: "PangMenZhengDao";
                         width: fit-content;

+ 0 - 2
src/views/old_mini/interactionList/map/drawRegionMap.js

@@ -337,13 +337,11 @@ class DrawRegionMap {
 
     getAreaGeometry() {
         const features = this.kmap.getLayerFeatures()
-        console.log(features, 'features');
         let geometryArr = []
         let area = 0
         const format = new WKT()
         // 获取图层上的Polygon,转成WKT用于回显
         features.forEach(item => {
-            console.log(item, 'item');
             // 使用 writeGeometry 而不是 writeFeature,因为 setLayerWkt 期望的是几何体的 WKT
             const geometry = item.getGeometry()
             geometryArr.push(format.writeGeometry(geometry, {

+ 11 - 2
src/views/old_mini/monitor/index.vue

@@ -50,7 +50,7 @@
                     <img src="@/assets/img/monitor/report-icon.png" alt="" class="report-icon" />
                 </div> -->
                 <div class="time-line">
-                    <archives-farm-time-line :problemZoneId="currentVariety?.id" :farmId="farmIdData" :regionId="regionData"></archives-farm-time-line>
+                    <archives-farm-time-line :problemZoneId="currentVariety?.id" :farmId="farmIdData" :regionId="regionData" @card-click="handleCardClick"></archives-farm-time-line>
                 </div>
             </div>
         </div>
@@ -231,7 +231,12 @@ onMounted(() => {
 
 const changeGarden = ({ id }) => {
     gardenId.value = id;
-    activeVariety.value = 0;
+    if(sessionStorage.getItem('activeVariety')){
+        activeVariety.value = Number(sessionStorage.getItem('activeVariety'));
+        sessionStorage.removeItem('activeVariety');
+    } else {
+        activeVariety.value = 0;
+    }
     // 更新 store 中的状态
     store.commit("home/SET_GARDEN_ID", id);
     getVarietyTabs();
@@ -246,6 +251,10 @@ function handleReportClick() {
     });
 }
 
+const handleCardClick = () => {
+    sessionStorage.setItem('activeVariety', activeVariety.value);
+}
+
 </script>
 
 <style scoped lang="scss">

+ 276 - 39
src/views/old_mini/monitor/subPages/darwArea.vue

@@ -18,8 +18,8 @@
             <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 v-if="viewOnly" class="footer-back" @click="deletePolygon">
+                    <img class="back-icon" src="@/assets/img/map/delete.png" alt="" />
                 </div>
                 <div class="edit-map-footer-btn" :class="{ 'confirm-btn-box': viewOnly }">
                     <template v-if="!viewOnly">
@@ -51,6 +51,7 @@ import Style from "ol/style/Style";
 import { Fill, Stroke, Circle, Text } from "ol/style.js";
 import { Point, Polygon, MultiPolygon } from "ol/geom";
 import WKT from "ol/format/WKT.js";
+import { unByKey } from "ol/Observable.js";
 import * as proj from "ol/proj";
 import { getArea } from "ol/sphere.js";
 
@@ -90,6 +91,10 @@ const regionsDraftByKey = ref({});
 const submitting = ref(false);
 // 仅在首次进入页面时根据路由 varietyId 定位一次,避免后续刷新覆盖当前流程进度
 const hasAppliedInitialVariety = ref(false);
+const selectedDeleteFeature = ref(null);
+const deleteSelectClickKey = ref(null);
+const selectedDeleteFeatureUid = ref("");
+const selectedDeleteFeatureOriginalStyle = ref(null);
 
 const type = ref(null);
 const varietyTabs = ref([]);
@@ -107,7 +112,96 @@ const clearAllRegionDrafts = () => {
     regionsDraftByIndex.value = {};
 };
 
+const clearDeleteSelectionState = () => {
+    if (selectedDeleteFeature.value) {
+        selectedDeleteFeature.value.setStyle(selectedDeleteFeatureOriginalStyle.value ?? undefined);
+        selectedDeleteFeature.value = null;
+    }
+    selectedDeleteFeatureUid.value = "";
+    selectedDeleteFeatureOriginalStyle.value = null;
+    if (deleteSelectClickKey.value) {
+        unByKey(deleteSelectClickKey.value);
+        deleteSelectClickKey.value = null;
+    }
+};
+
+const getDeleteHighlightStyle = () => {
+    const styleKind = getCanonicalRegionTypeForStyles();
+    if (styleKind === "variety") {
+        return {
+            fillColor: "rgba(24, 170, 139, 0.5)",
+            strokeColor: "#18AA8B",
+        };
+    }
+    if (styleKind === "ABNORMAL") {
+        if (activeVariety.value < 2) {
+            return {
+                fillColor: "rgba(224, 49, 49, 0.5)",
+                strokeColor: "#E03131",
+            }
+        } else {
+            return {
+                fillColor: "rgba(255, 115, 0, 0.5)",
+                strokeColor: "#FF7300",
+            };
+        }
+    }
+    if (styleKind === "ENVIRONMENT") {
+        return {
+            fillColor: "rgba(255, 199, 102, 0.5)",
+            strokeColor: "#FDCF7F",   
+        };
+    }
+    // 其余类型先给默认占位色,后续可按产品视觉再调整
+    return {
+        fillColor: "rgba(229, 229, 229, 0.5)",
+        strokeColor: "#A6A6A6",
+    };
+};
+
+const highlightDeleteSelectedFeature = (feature) => {
+    if (!feature) return;
+    if (selectedDeleteFeature.value === feature) return;
+    if (selectedDeleteFeature.value && selectedDeleteFeature.value !== feature) {
+        selectedDeleteFeature.value.setStyle(selectedDeleteFeatureOriginalStyle.value ?? undefined);
+    }
+    selectedDeleteFeatureOriginalStyle.value = feature.getStyle ? feature.getStyle() : null;
+    selectedDeleteFeature.value = feature;
+    selectedDeleteFeatureUid.value = String(feature?.ol_uid || feature?.getId?.() || "");
+    const { fillColor, strokeColor } = getDeleteHighlightStyle();
+    // 删除选择态:按当前类型动态高亮(单选)
+    feature.setStyle(
+        new Style({
+            fill: new Fill({ color: fillColor }),
+            stroke: new Stroke({ color: strokeColor, width: 2 }),
+        })
+    );
+};
+
+const enableDeleteSelectionMode = () => {
+    const map = drawRegionMap.kmap?.map;
+    const polygonLayer = drawRegionMap.kmap?.polygonLayer?.layer;
+    if (!map || !polygonLayer || deleteSelectClickKey.value) return;
+    deleteSelectClickKey.value = map.on("singleclick", (evt) => {
+        let hitFeature = null;
+        map.forEachFeatureAtPixel(
+            evt.pixel,
+            (feature) => {
+                hitFeature = feature;
+                return true;
+            },
+            {
+                layerFilter: (layer) => layer === polygonLayer,
+            }
+        );
+        if (hitFeature) {
+            highlightDeleteSelectedFeature(hitFeature);
+        }
+    });
+};
+
 const handleRegionTypeClick = (item) => {
+    clearDeleteSelectionState();
     const prevMajor = activeRegionType.value;
     if (item.code !== prevMajor) {
         clearDraftIndexOnly();
@@ -125,6 +219,87 @@ const handleRegionTypeClick = (item) => {
     }
 };
 
+// 删除当前地块
+const deletePolygon = () => {
+    const features = drawRegionMap.kmap?.polygonLayer?.source?.getFeatures?.() || [];
+    let matchedFeature = null;
+    if (features.length === 0) {
+        clearDeleteSelectionState();
+        ElMessage.warning("当前没有可删除的地块");
+        return;
+    }
+    if (features.length > 1) {
+        if (!selectedDeleteFeature.value) {
+            enableDeleteSelectionMode();
+            ElMessage.warning("当前有多个地块,请先选择地块");
+            return;
+        }
+        matchedFeature = features.find((f) => {
+            if (f === selectedDeleteFeature.value) return true;
+            const uid = String(f?.ol_uid || f?.getId?.() || "");
+            return uid && uid === selectedDeleteFeatureUid.value;
+        });
+        if (!matchedFeature) {
+            selectedDeleteFeature.value = null;
+            selectedDeleteFeatureUid.value = "";
+            ElMessage.warning("请选择地块后再删除");
+            return;
+        }
+    } else {
+        clearDeleteSelectionState();
+    }
+
+    ElMessageBox.confirm(
+        "确认删除当前地块吗?删除后可以重新勾画。",
+        "删除确认",
+        {
+            confirmButtonText: "确认删除",
+            cancelButtonText: "取消",
+            type: "warning",
+        }
+    ).then(async () => {
+        if (selectedDeleteFeature.value && features.length > 1) {
+            drawRegionMap.kmap?.polygonLayer?.source?.removeFeature?.(matchedFeature || selectedDeleteFeature.value);
+            clearDeleteSelectionState();
+        } else {
+            drawRegionMap.deleteCurrentPolygon();
+        }
+
+        const polygonData = drawRegionMap.getAreaGeometry?.();
+        const geometryArr = polygonData?.geometryArr || [];
+        const mergedGeom = mergePolygonWktsForApi(geometryArr);
+
+        try {
+            const ok = await submitCurrentTabGeometryChange(mergedGeom);
+            if (!ok) {
+                ElMessage.error("删除后保存失败");
+                return;
+            }
+            await fetchRegionInfo();
+            clearAllRegionDrafts();
+            if (activeRegionType.value === "variety") {
+                varietyTabs.value = regionInfo.value?.regionList || [];
+            } else {
+                const group = (regionTypeTabs.value || []).find(
+                    (x) => String(x?.code) === String(activeRegionType.value)
+                );
+                varietyTabs.value = group?.children || [];
+            }
+            const nextIndex = Math.min(activeVariety.value, Math.max(varietyTabs.value.length - 1, 0));
+            activeVariety.value = nextIndex;
+            if (varietyTabs.value.length > 0 && varietyTabs.value[nextIndex]) {
+                handleVarietyClick(varietyTabs.value[nextIndex], nextIndex);
+            } else {
+                drawRegionMap.kmap?.polygonLayer?.source?.clear?.();
+                drawRegionMap.fitAllRegions?.();
+            }
+            ElMessage.success("地块已删除");
+        } catch (_) {
+            ElMessage.error("删除后保存失败");
+        }
+    });
+};
+
 /** 取 Polygon / MultiPolygon 的外环坐标(地图投影),用于顶点样式 */
 const getOuterRingCoordinates = (geometry) => {
     if (!geometry || typeof geometry.getType !== "function") return [];
@@ -238,12 +413,12 @@ const applyRegionStyles = () => {
         fillColor = [0, 57, 44, 0.5];
         strokeColor = "#18AA8B";
     } else if (styleKind === "ABNORMAL") {
-        if(activeVariety.value < 2){
+        if (activeVariety.value < 2) {
             lineColor = "#E03131";
             vertexColor = "#E03131";
             fillColor = [100, 0, 0, 0.5];
             strokeColor = "#E03131";
-        }else{
+        } else {
             lineColor = "#FF7300";
             vertexColor = "#FF7300";
             fillColor = [124, 46, 0, 0.5];
@@ -475,6 +650,7 @@ const syncClosedDrawToDraft = () => {
 };
 
 const handleVarietyClick = (tab, index) => {
+    clearDeleteSelectionState();
     // 取消上一次延迟渲染,避免快速切换 tab / 切换编辑态时重复追加要素
     clearPendingGeomRenderTimer();
 
@@ -495,10 +671,10 @@ const handleVarietyClick = (tab, index) => {
         isValidGeom(draftGeom)
             ? [String(draftGeom).trim()]
             : (() => {
-                  const fromItems = getGeomArrFromGeomItems(tab);
-                  if (fromItems.length) return fromItems;
-                  return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
-              })();
+                const fromItems = getGeomArrFromGeomItems(tab);
+                if (fromItems.length) return fromItems;
+                return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
+            })();
     const geomArr = flattenGeomWktListForMap(rawGeomArr);
     // 保留一份“当前选中地块”的原始字符串形态给其它逻辑使用
     regionGeom.value = geomArr.length > 1 ? JSON.stringify(geomArr) : geomArr[0] || "";
@@ -769,6 +945,7 @@ watch(
 );
 
 onDeactivated(() => {
+    clearDeleteSelectionState();
     activeVariety.value = 0;
     activeRegionType.value = "variety";
     clearPendingGeomRenderTimer();
@@ -785,8 +962,9 @@ const goBack = () => {
 };
 
 const resetPolygon = () => {
+    clearDeleteSelectionState();
     ElMessageBox.confirm(
-        "确认要重置当前地块吗?重置后将恢复到进入页面时的区域形状。",
+        "确认重置当前地块吗?重置后将恢复为初始状态",
         "重置确认",
         {
             confirmButtonText: "确认重置",
@@ -802,24 +980,36 @@ const resetPolygon = () => {
                 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) {
-                        const resetGeomArr = flattenGeomWktListForMap(parsed.geometryArr);
-                        drawRegionMap.setAreaGeometry(
-                            resetGeomArr.length ? resetGeomArr : parsed.geometryArr,
-                            false,
-                            undefined,
-                            undefined,
-                            getAbnormalGrowthOverlayMeta()
-                        );
-                    }
-                } catch (_) {
-                    // 解析失败则不做处理,仅相当于清空重画
-                }
+            // 清空当前 tab 草稿,重置应回到“进入时初始化值”
+            const currentTab = varietyTabs.value?.[activeVariety.value];
+            const currentKey = draftKeyFromParts(activeRegionType.value, currentTab);
+            if (currentKey && regionsDraftByKey.value[currentKey]) {
+                delete regionsDraftByKey.value[currentKey];
+            }
+            if (regionsDraftByIndex.value[activeVariety.value]) {
+                delete regionsDraftByIndex.value[activeVariety.value];
+            }
+
+            // 当前品类有初始化地块则回显;没有则保持空地图
+            const initialGeomArrRaw = (() => {
+                const fromItems = getGeomArrFromGeomItems(currentTab);
+                if (fromItems.length) return fromItems;
+                return isValidGeom(currentTab?.geom) ? [String(currentTab.geom).trim()] : [];
+            })();
+            const initialGeomArr = flattenGeomWktListForMap(initialGeomArrRaw);
+            if (initialGeomArr.length > 0) {
+                drawRegionMap.setAreaGeometry(
+                    initialGeomArr,
+                    false,
+                    undefined,
+                    undefined,
+                    getAbnormalGrowthOverlayMeta()
+                );
+                regionGeom.value =
+                    initialGeomArr.length > 1 ? JSON.stringify(initialGeomArr) : initialGeomArr[0];
+            } else {
+                regionGeom.value = "";
+                drawRegionMap.fitAllRegions?.();
             }
             ElMessage.success("地块已重置");
         })
@@ -845,13 +1035,13 @@ const submitRegions = async () => {
         };
         const res = await VE_API.basic_farm.ediRegionZone(params);
         if (res?.code === 0) {
-            if(selectedDrawTypeMeta.value.type === 'ABNORMAL'){
+            if (selectedDrawTypeMeta.value.type === 'ABNORMAL') {
                 let problemZoneId = null;
-                if(params.problemZoneList.length){
+                if (params.problemZoneList.length) {
                     res.data[0].problemZoneList.forEach(element => {
-                        if(element.code === selectedDrawTypeMeta.value.type){
+                        if (element.code === selectedDrawTypeMeta.value.type) {
                             element.children.forEach(item => {
-                                if(item.problemZoneTypeName === selectedDrawTypeMeta.value.category.problemZoneTypeName){
+                                if (item.problemZoneTypeName === selectedDrawTypeMeta.value.category.problemZoneTypeName) {
                                     problemZoneId = item.id;
                                 }
                             });
@@ -875,6 +1065,51 @@ const submitRegions = async () => {
     }
 };
 
+const submitCurrentTabGeometryChange = async (geomWkt) => {
+    const tab = varietyTabs.value?.[activeVariety.value];
+    if (!tab) return false;
+    const normalizedGeom = isValidGeom(geomWkt) ? String(geomWkt).trim() : "";
+    const params = {
+        subjectId: route.query.subjectId,
+        regionList: [],
+        problemZoneList: [],
+    };
+
+    if (activeRegionType.value === "variety") {
+        params.regionList = [
+            {
+                regionId: tab.regionId,
+                typeId: tab.typeId,
+                regionName: tab.regionName,
+                geom: normalizedGeom,
+            },
+        ];
+    } else {
+        const group = findProblemZoneGroupByDrawType(activeRegionType.value);
+        if (!group) return false;
+        const remark = tab?.geomItems?.[0]?.remark || "";
+        params.problemZoneList = [
+            {
+                name: group.name,
+                code: group.code,
+                children: [
+                    {
+                        farmSubjectId: route.query.subjectId,
+                        problemZoneTypeId: tab.problemZoneTypeId ?? tab.typeId ?? "",
+                        problemZoneTypeName: tab.problemZoneTypeName ?? tab.regionName ?? "",
+                        parentName: group.name ?? "",
+                        parentCode: group.code ?? "",
+                        geomItems: normalizedGeom ? [{ geomWkt: normalizedGeom, remark: String(remark) }] : [],
+                    },
+                ],
+            },
+        ];
+    }
+
+    const res = await VE_API.basic_farm.ediRegionZone(params);
+    return res?.code === 0;
+};
+
 /** 以弹窗 confirm 传入的 drawMeta(大类 type + 小类 category + remark)为准写入草稿并提交 */
 const confirmArea = async (drawMeta) => {
     const meta =
@@ -989,6 +1224,7 @@ const handleConfirmDrawType = async (payload) => {
 };
 
 const handleEditRegion = async () => {
+    clearDeleteSelectionState();
     // 从查看态切换到可勾画编辑态:移除查看标记(所有大类共用)
     const nextQuery = { ...route.query };
     delete nextQuery.type;
@@ -1053,10 +1289,10 @@ const handleEditRegion = async () => {
                 isValidGeom(draftGeom)
                     ? [String(draftGeom).trim()]
                     : (() => {
-                          const fromItems = getGeomArrFromGeomItems(tab);
-                          if (fromItems.length) return fromItems;
-                          return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
-                      })();
+                        const fromItems = getGeomArrFromGeomItems(tab);
+                        if (fromItems.length) return fromItems;
+                        return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
+                    })();
             const geomArr = flattenGeomWktListForMap(rawGeomArr);
             drawRegionMap.kmap?.polygonLayer?.source?.clear?.();
             if (geomArr.length > 0) {
@@ -1107,7 +1343,7 @@ const handleTipConfirm = () => {
     flex-direction: column;
     box-sizing: border-box;
 
-    & > :first-child {
+    &> :first-child {
         flex-shrink: 0;
     }
 
@@ -1171,6 +1407,7 @@ const handleTipConfirm = () => {
         box-sizing: border-box;
         /* 底部「重置 / 确认」等为 position:fixed,占高约 68px,地图区域需预留避免被盖住 */
         padding-bottom: 68px;
+
         .edit-map-tip {
             position: absolute;
             top: 23px;
@@ -1198,14 +1435,14 @@ const handleTipConfirm = () => {
             align-items: flex-end;
 
             .footer-back {
-                padding: 6px 7px 9px;
+                padding: 4px 5px 7px;
                 background: #fff;
                 border-radius: 8px;
                 margin-bottom: 12px;
 
                 .back-icon {
-                    width: 20px;
-                    height: 18px;
+                    width: 23px;
+                    height: 23px;
                 }
             }