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

feat:修改互动列表的颜色回显

wangsisi 1 день назад
Родитель
Сommit
2d36248787

+ 517 - 0
src/views/old_mini/interactionList/drawRegion copy.vue

@@ -0,0 +1,517 @@
+<template>
+    <div class="edit-map">
+        <custom-header :name="viewOnly ? '查看区域' : '勾画区域'"></custom-header>
+        <div class="region-type-tabs">
+            <div v-for="(item,index) in regionTypeTabs" :key="item.code" class="region-type-tab"
+                :class="{ 'region-type-tab--active': activeRegionType === index }">
+                {{ item.name }}
+            </div>
+        </div>
+        <div class="variety-tabs" v-if="varietyTabs.length > 0 && activeRegionType !== 'DORMANCY'">
+            <div v-for="(v, index) in varietyTabs" :key="index" class="variety-tab"
+                :class="{ 'variety-tab--active': activeVariety === index }">
+                {{ v.regionName || v.problemZoneTypeName }}
+            </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" :style="{ 'bottom': activeRegionType !== 'DORMANCY' ? '85px' : '59px' }">
+                <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-delete" @click="deletePolygon">删除地块</div>
+                    <div class="btn-cancel" @click="goBack">取消</div>
+                    <div class="btn-confirm" @click="confirm">确认</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import customHeader from "@/components/customHeader.vue";
+import { ref, computed, onMounted, onActivated, onDeactivated } from "vue";
+import DrawRegionMap from "./map/drawRegionMap.js";
+import { Map as KMapMap } from "@/utils/ol-map/KMap";
+import { useRouter, useRoute } from "vue-router";
+import { convertPointToArray } from "@/utils/index";
+import { ElMessage, ElMessageBox } from "element-plus";
+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 router = useRouter();
+const route = useRoute();
+const mapContainer = ref(null);
+const drawRegionMap = new DrawRegionMap();
+
+const type = ref(null);
+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);
+    applyRegionStyles();
+
+    // 地图初始化之后(比如 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(async () => {
+    const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
+    await fetchRegionInfo();
+
+    // 从编辑态进入仅查看时,需重新初始化为不可编辑
+    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);
+    }
+
+    applyRegionStyles();
+
+    // 先绘制地块
+    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",
+                    reproductiveName: route.query.reproductiveName,
+                    updatedTime: route.query.updatedTime,
+                }));
+            } else if (typeof rangeWkt === "string" && rangeWkt.trim().length > 10) {
+                regions = [{ geometry: rangeWkt.trim(), status: "unresolved", reproductiveName: route.query.reproductiveName, updatedTime: route.query.updatedTime }];
+            }
+        } catch (_) {
+            if (typeof rangeWkt === "string" && rangeWkt.trim().length > 10) {
+                regions = [{ geometry: rangeWkt.trim(), status: "unresolved", reproductiveName: route.query.reproductiveName, 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,
+            false,
+            undefined,
+            undefined,
+            getAbnormalGrowthOverlayMeta()
+        );
+    }
+
+    // 查看模式下已通过 fitAllRegions 适配;编辑模式再设置地图中心
+    if (!viewOnly.value) {
+        drawRegionMap.setMapPosition(convertPointToArray(point));
+    }
+
+    applyRegionStyles();
+});
+
+const regionTypeTabs = ref([]);
+const activeRegionType = ref("variety");
+const regionInfo = ref([]);
+async function fetchRegionInfo() {
+    const { data } = await VE_API.basic_farm.fetchRegionInfo({ subjectId: route.query.subjectId || 109 });
+    if (data && data.length > 0) {
+        regionInfo.value = data[0] || [];
+        regionTypeTabs.value = regionInfo.value.problemZoneList || [];
+        regionTypeTabs.value.unshift({ name: "品种区", code: "variety" });
+        if (data[0]?.regionList?.length) {
+            // if (!hasAppliedInitialVariety.value && route.query?.varietyId) {
+            //     activeVariety.value = resolveInitialVarietyIndex(data[0]?.regionList);
+            //     hasAppliedInitialVariety.value = true;
+            // }
+
+            // point.value = data[0].point;
+            varietyTabs.value = regionInfo.value.regionList || [];
+        }
+    }
+}
+
+const varietyTabs = ref([]);
+const activeVariety = ref(0);
+
+/** 样式用的大类:与接口 tab.code 解耦(避免 ABNORMAL / 数字 code 等导致勾画色落到默认灰) */
+const getCanonicalRegionTypeForStyles = () => {
+    const raw = activeRegionType.value;
+    if (raw === "variety") return "variety";
+    const tabs = regionTypeTabs.value || [];
+    const item = tabs.find((t) => String(t?.code) === String(raw));
+    if (item) {
+        const kind = item.code;
+        if (kind) return kind;
+    }
+    return "SLEEP";
+};
+
+const ABNORMAL_BADGE_BG_DISEASE_PEST = "#E32A28";
+const ABNORMAL_BADGE_BG_GROWTH = "#F76F00";
+
+/** 异常区小类(长势/病害/虫害等)闭合地块后在多边形内展示标签与发现日期 */
+const getAbnormalGrowthOverlayMeta = () => {
+    if (getCanonicalRegionTypeForStyles() !== "ABNORMAL") return null;
+    const tab = varietyTabs.value?.[activeVariety.value];
+    if (!tab) return null;
+    const name = (tab.problemZoneTypeName || tab.regionName || "").toString();
+    let badgeText = "";
+    let badgeBackground = ABNORMAL_BADGE_BG_GROWTH;
+    if (name.includes("病害")) {
+        badgeText = "新增病害";
+        badgeBackground = ABNORMAL_BADGE_BG_DISEASE_PEST;
+    } else if (name.includes("虫害")) {
+        badgeText = "新增虫害";
+        badgeBackground = ABNORMAL_BADGE_BG_DISEASE_PEST;
+    } else if (name.includes("过慢")) {
+        badgeText = "新增长势过慢";
+    } else if (name.includes("过快")) {
+        badgeText = "新增长势过快";
+    } else {
+        return null;
+    }
+    const now = new Date();
+    const y = now.getFullYear();
+    const m = String(now.getMonth() + 1).padStart(2, "0");
+    const d = String(now.getDate()).padStart(2, "0");
+    return { badgeText, discoveryDate: `${y}.${m}.${d}`, badgeBackground };
+};
+
+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 growth = getAbnormalGrowthOverlayMeta();
+        if (growth) {
+            styles.push(
+                new Style({
+                    text: new Text({
+                        text: growth.badgeText,
+                        font: "bold 13px sans-serif",
+                        fill: new Fill({ color: "#ffffff" }),
+                        backgroundFill: new Fill({ color: growth.badgeBackground || ABNORMAL_BADGE_BG_GROWTH }),
+                        padding: [4, 10, 4, 10],
+                        offsetY: -40,
+                    }),
+                }),
+                new Style({
+                    text: new Text({
+                        text: `发现时间:${growth.discoveryDate}`,
+                        font: "12px sans-serif",
+                        fill: new Fill({ color: "#ffffff" }),
+                        offsetY: -16,
+                    }),
+                })
+            );
+        }
+        const areaValStyle = new Style({
+            text: new Text({
+                font: "16px sans-serif",
+                text: area.toFixed(2) + "亩",
+                fill: new Fill({ color: "#fff" }),
+                offsetY: growth ? 14 : 0,
+            }),
+        });
+        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";
+
+    const styleKind = getCanonicalRegionTypeForStyles();
+    if (styleKind === "variety") {
+        lineColor = "#18AA8B";
+        vertexColor = "#18AA8B";
+        fillColor = [0, 57, 44, 0.5];
+        strokeColor = "#18AA8B";
+    } else if (styleKind === "ABNORMAL") {
+        if (activeVariety.value < 2) {
+            lineColor = "#E03131";
+            vertexColor = "#E03131";
+            fillColor = [100, 0, 0, 0.5];
+            strokeColor = "#E03131";
+        } else {
+            lineColor = "#FF7300";
+            vertexColor = "#FF7300";
+            fillColor = [124, 46, 0, 0.5];
+            strokeColor = "#FF7300";
+        }
+    } else if (styleKind === "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";
+    }
+
+    KMapMap.drawStyleColors = {
+        line: lineColor,
+        vertex: vertexColor,
+        fill: fillColor,
+        stroke: strokeColor,
+    };
+
+    kmap.polygonStyle = createPolygonStyleFunc(fillColor, strokeColor);
+    if (kmap.polygonLayer?.layer && typeof kmap.polygonLayer.layer.setStyle === "function") {
+        kmap.polygonLayer.layer.setStyle(kmap.polygonStyle);
+    }
+};
+
+onDeactivated(() => {
+    drawRegionMap.clearLayer()
+})
+const goBack = () => {
+    // drawRegionMap.clearLayer()
+    router.back()
+};
+
+const deletePolygon = () => {
+    ElMessageBox.confirm(
+        '确认要删除当前地块吗?删除后可以重新勾画。',
+        '删除确认',
+        {
+            confirmButtonText: '确认删除',
+            cancelButtonText: '取消',
+            type: 'warning',
+        }
+    ).then(() => {
+        drawRegionMap.abortOngoingDrawSketch();
+        if (drawRegionMap.kmap && drawRegionMap.kmap.polygonLayer && drawRegionMap.kmap.polygonLayer.source) {
+            drawRegionMap.kmap.polygonLayer.source.clear();
+        }
+        ElMessage.success("地块已删除");
+    }).catch(() => {
+        // 用户取消删除,不做任何操作
+    });
+};
+
+const confirm = () => {
+    const polygonData = drawRegionMap.getAreaGeometry();
+    sessionStorage.setItem("drawRegionPolygonData", JSON.stringify(polygonData));
+    router.back();
+};
+</script>
+
+<style lang="scss" scoped>
+.edit-map {
+    width: 100%;
+    height: 100vh;
+    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 {
+        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: #575757;
+            background: #F4F4F4;
+            border: 1px solid transparent;
+            white-space: nowrap;
+        }
+
+        .variety-tab--active {
+            background: rgba(33, 153, 248, 0.1);
+            color: #2199F8;
+            border: 1px solid #2199F8;
+        }
+    }
+
+    .edit-map-content {
+        width: 100%;
+        height: calc(100% - 96px);
+        margin-top: 10px;
+        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: 85px;
+            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: 30px;
+
+                .back-icon {
+                    width: 20px;
+                    height: 18px;
+                }
+            }
+
+            .edit-map-footer-btn {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                width: 100%;
+                gap: 8px;
+
+                div {
+                    flex: 1;
+                    max-width: 100px;
+                    text-align: center;
+                    color: #666666;
+                    font-size: 14px;
+                    padding: 8px 0;
+                    border-radius: 25px;
+                    background: #fff;
+                }
+
+                .btn-delete {
+                    background: #ff4d4f;
+                    color: #fff;
+                }
+
+                .btn-confirm {
+                    background: #000;
+                    background-image: linear-gradient(180deg, #76c3ff 0%, #2199f8 100%);
+                    color: #fff;
+                }
+            }
+        }
+    }
+}
+</style>

+ 18 - 6
src/views/old_mini/interactionList/index.vue

@@ -291,6 +291,11 @@ const format = () => {
 };
 
 const drawRegionMap = new DrawRegionMap();
+/** 上传进度弹窗内地图为只读回显时,多边形配色与列表主题蓝一致(避免沿用勾画页默认绿色) */
+const READONLY_AREA_STYLE_BLUE = {
+    fill: "rgba(33, 153, 248, 0.35)",
+    stroke: "#2199F8",
+};
 const mapContainer = ref(null);
 const itemSubmittingMap = ref({});
 const confirmUploadLoading = ref(false);
@@ -363,7 +368,12 @@ const renderRegionFromSession = () => {
             ) {
                 // 注意这里不再调用 clearLayer,避免清掉上一步 setStatusRegions 的只读区域
                 // 此处也不单独做 fit,由下方统一调用 fitAllRegions 适配所有图层
-                drawRegionMap.setAreaGeometry(polygonData.geometryArr, false, polygonData.mianji);
+                drawRegionMap.setAreaGeometry(
+                    polygonData.geometryArr,
+                    false,
+                    polygonData.mianji,
+                    READONLY_AREA_STYLE_BLUE
+                );
             }
         } catch (e) {
             console.error("解析 drawRegionPolygonData 失败:", e);
@@ -402,7 +412,8 @@ const renderRegionFromItemWkt = (item) => {
             .filter(wkt => wkt && typeof wkt === 'string' && wkt.trim().length > 10)
             .map(wkt => ({
                 geometry: wkt.trim(),
-                status: 'unresolved' // 接口返回的区域默认显示为未解决状态
+                status: 'unresolved', // 接口返回的区域默认显示为未解决状态
+                unresolvedBlueFill: true, // 与列表主题蓝一致,避免深灰填充
             }));
         if (regions.length > 0) {
             drawRegionMap.setStatusRegions(regions);
@@ -509,7 +520,8 @@ const afterReadUpload = async (data) => {
                             drawRegionMap.setAreaGeometry(
                                 polygonData.geometryArr,
                                 true,
-                                polygonData.mianji
+                                polygonData.mianji,
+                                READONLY_AREA_STYLE_BLUE
                             );
                         }
                     } catch (e) {
@@ -755,12 +767,12 @@ const handleDrawRegion = (item) => {
     }
 
     if (item.rangeWkt && item.rangeWkt.length > 10) {
-        router.push(`/draw_region?polygonData=${polygonData}&rangeWkt=${item.rangeWkt}&updatedTime=${item.updatedTime.slice(0, 10)}&reproductiveName=${item.reproductiveName}&mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}`);
+        router.push(`/draw_region?polygonData=${polygonData}&rangeWkt=${item.rangeWkt}&updatedTime=${item.updatedTime.slice(0, 10)}&reproductiveName=${item.reproductiveName}&mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}&firstAct=0&secondAct=0`);
     } else {
         if (polygonData) {
-            router.push(`/draw_region?polygonData=${polygonData}&mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}`);
+            router.push(`/draw_region?polygonData=${polygonData}&mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}&firstAct=0&secondAct=0`);
         } else {
-            router.push(`/draw_region?mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}`);
+            router.push(`/draw_region?mapCenter=${localStorage.getItem('selectedFarmPoint') || 'POINT (113.6142086995688 23.585836479509055)'}&firstAct=0&secondAct=0`);
         }
     }
 };

+ 9 - 3
src/views/old_mini/interactionList/map/drawRegionMap.js

@@ -63,8 +63,13 @@ class DrawRegionMap {
                 const status = f.get("status"); // 'resolved' | 'unresolved'
                 const reproductiveName = f.get("reproductiveName") || "";
                 const isResolved = status === "resolved";
-                // 已解决:深灰填充,浅白描边;未解决:浅蓝填充,亮蓝描边
-                const fillColor = isResolved ? "rgba(0, 0, 0, 0.6)" : "rgba(0, 0, 0, 0.5)";
+                const unresolvedBlueFill = f.get("unresolvedBlueFill") === true;
+                // 已解决:深灰填充,浅白描边;未解决:默认深灰半透明 + 蓝描边;unresolvedBlueFill 时浅蓝填充(互动列表等)
+                const fillColor = isResolved
+                    ? "rgba(0, 0, 0, 0.6)"
+                    : unresolvedBlueFill
+                      ? "rgba(33, 153, 248, 0.35)"
+                      : "rgba(0, 0, 0, 0.5)";
                 const strokeColor = isResolved ? "#7C7C7C" : "#2199F8";
 
                 const text = new Text({
@@ -354,7 +359,7 @@ class DrawRegionMap {
 
     /**
      * 设置只读状态区域图层(多个 polygon,不可编辑)
-     * @param {Array<{ geometry: string, status?: 'resolved' | 'unresolved', label?: string, displayMode?: string }>} regions
+     * @param {Array<{ geometry: string, status?: 'resolved' | 'unresolved', label?: string, displayMode?: string, unresolvedBlueFill?: boolean }>} regions
      *
      * 使用示例:
      * drawRegionMap.setStatusRegions([
@@ -385,6 +390,7 @@ class DrawRegionMap {
                 feature.set("updatedTime", region.updatedTime);
                 feature.set("label", region.label || "");
                 feature.set("displayMode", region.displayMode || "");
+                feature.set("unresolvedBlueFill", region.unresolvedBlueFill === true);
                 this.staticRegionLayer.addFeature(feature);
             } catch (e) {
                 // 单个区域解析失败时忽略