Browse Source

fix: 修复bug

lxf 5 giờ trước cách đây
mục cha
commit
fe826c18f5

+ 4 - 8
src/components/pageComponents/PhenologyTrackTimelineItem.vue

@@ -24,7 +24,7 @@
                     <div class="track-cards">
                         <div
                             class="track-card"
-                            :class="{ 'track-card--alert': item.isAlert }"
+                            :class="{ 'track-card--alert': item.type === 'abnormal' }"
                             v-for="item in group.items"
                             :key="item.id"
                         >
@@ -32,9 +32,9 @@
                             <div
                                 v-if="item.content"
                                 class="track-content"
-                                :class="{ 'track-content--alert': item.isAlert }"
+                                :class="{ 'track-content--alert': item.type === 'abnormal' }"
                             >
-                                <el-icon size="16" v-if="item.isAlert" class="track-content__warn"><WarnTriangleFilled /></el-icon>
+                                <el-icon size="16" v-if="item.type === 'abnormal'" class="track-content__warn"><WarnTriangleFilled /></el-icon>
                                 <span v-html="item.content"></span>
                             </div>
                         </div>
@@ -91,10 +91,6 @@ function formatDate(value) {
     return text;
 }
 
-function isAlertContent(text) {
-    return /异常|abnormal/i.test(String(text || ""));
-}
-
 function normalizeItem(item, index) {
     const rawDate = item.date || item.enter_date || item.trigger_date || item.latest_time || "";
     const content = item.content || item.sentence || item.desc || item.text || "";
@@ -104,7 +100,7 @@ function normalizeItem(item, index) {
         date: formatDate(rawDate),
         zone_name: item.zone_name || item.zoneName || "",
         content,
-        isAlert: isAlertContent(content),
+        type: item.type,
     };
 }
 

+ 5 - 0
src/components/popup/ImagePreviewPopup.vue

@@ -238,6 +238,11 @@ function handleClose() {
         flex: 1;
         display: flex;
         align-items: center;
+        ::v-deep {
+            .van-swipe__track {
+                align-items: center;
+            }
+        }
     }
 
     &__slide {

+ 6 - 3
src/components/popup/tipPopup.vue

@@ -164,7 +164,7 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 12%)
         border-radius: 16px;
         width: 100%;
         box-sizing: border-box;
-        padding: 20px 16px;
+        padding: 20px 16px 26px;
         display: flex;
         flex-direction: column;
         align-items: center;
@@ -233,12 +233,15 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 12%)
 
             .execute-success-title,
             .execute-success-subtitle {
-                font-size: 24px;
+                font-size: 22px;
+                color: #fff;
                 font-weight: 400;
             }
 
             .execute-success-subtitle {
-                padding-top: 4px;
+                padding-top: 8px;
+                font-size: 16px;
+                color: rgba(255, 255, 255, 0.6);
             }
         }
     }

+ 4 - 0
src/styles/common.scss

@@ -221,6 +221,10 @@ div {
     color: #FFD489;
 }
 
+.el-loading-spinner .path {
+    stroke: #FFD489;
+}
+
 @font-face {
     font-family: "SOURCEHANSANSCN_0";
     src: url("@/assets/font/SOURCEHANSANSCN-REGULAR_0.OTF");

+ 10 - 1
src/views/old_mini/agri_file/components/addZoneInfoPopup.vue

@@ -148,6 +148,11 @@ const props = defineProps({
         type: String,
         default: "",
     },
+    /** 提交成功后是否弹 ElMessage;父页面已有成功弹窗时传 false,避免重复提示 */
+    showSuccessMessage: {
+        type: Boolean,
+        default: true,
+    },
 });
 
 const emit = defineEmits(["update:show", "confirm"]);
@@ -648,7 +653,9 @@ const handleConfirm = async () => {
     try {
         const res = await VE_API.questionnaire.createZone(payload);
         if (res?.code === 200) {
-            ElMessage.success(res.msg || t("agriFile.createZoneSuccess"));
+            if (props.showSuccessMessage) {
+                ElMessage.success(res.msg || t("agriFile.createZoneSuccess"));
+            }
             applyCreatedFarmToCache({
                 created: res?.data,
                 payload,
@@ -660,6 +667,8 @@ const handleConfirm = async () => {
             });
             emit("confirm", {
                 ...payload,
+                // createZone 返回的新建分区数据(含新 zone_id),供父页面上传照片跳转使用
+                created: res?.data || {},
                 category_id: form.categoryId,
                 category_name: category?.name || "",
                 variety_id: form.varietyId,

+ 1 - 2
src/views/old_mini/agri_file/components/albumPanel.vue

@@ -323,7 +323,7 @@ const goAddZone = (type) => {
         path: "/add_zone",
         query: {
             type,
-            isSuccessPopup: type === "farm" ? "1" : "0",
+            isSuccessPopup: "1",
         },
     });
 };
@@ -345,7 +345,6 @@ const goAlbumDetail = (item) => {
 
 const handleUploadClick = (zoneId, geom) => {
     const needDraw = geom ? false : true;
-    console.log('needDraw, ',geom,  needDraw);
     // 上传照片
     emit('open-upload', zoneId, needDraw)
 };

+ 26 - 3
src/views/old_mini/agri_file/components/albumUploadPopup.vue

@@ -135,6 +135,10 @@ const uploadedKeys = ref([]);
 const description = ref("");
 const uploadDate = ref("");
 const confirming = ref(false);
+/** 进行中的图片上传 key 集合:不依赖 vant 的 item.status,判断更可靠 */
+const pendingUploads = new Set();
+/** 表单代次:弹窗重置后丢弃仍在飞的上传结果 */
+let formToken = 0;
 
 function formatDate(date = new Date()) {
     const year = date.getFullYear();
@@ -165,6 +169,8 @@ watch(showValue, (val) => {
 });
 
 function resetForm() {
+    formToken += 1;
+    pendingUploads.clear();
     fileList.value = [];
     uploadedKeys.value = [];
     description.value = "";
@@ -174,6 +180,7 @@ function resetForm() {
 
 const afterRead = (file) => {
     const files = Array.isArray(file) ? file : [file];
+    const token = formToken;
     files.forEach((item) => {
         const fileVal = item.file;
         if (!fileVal) return;
@@ -183,15 +190,21 @@ const afterRead = (file) => {
         const key = `birdseye-look-mini/${miniUserId}/${Date.now()}_${Math.random()
             .toString(36)
             .slice(2, 8)}.${ext}`;
+        item.uploadKey = key;
+        pendingUploads.add(key);
         uploadFileObj
             .put(key, fileVal)
             .then((resFilename) => {
+                pendingUploads.delete(key);
+                if (token !== formToken || item.isRemoved) return;
                 item.status = "done";
                 item.message = "";
                 item.resFilename = resFilename || key;
                 uploadedKeys.value.push(item.resFilename);
             })
             .catch(() => {
+                pendingUploads.delete(key);
+                if (token !== formToken || item.isRemoved) return;
                 item.status = "failed";
                 item.message = "上传失败";
                 toast("error", "图片上传失败,请稍后再试!");
@@ -200,7 +213,11 @@ const afterRead = (file) => {
 };
 
 const onDelete = (file) => {
-    const key = file?.resFilename;
+    if (!file) return;
+    if (file.uploadKey) pendingUploads.delete(file.uploadKey);
+    file.isRemoved = true;
+    file.status = "";
+    const key = file.resFilename;
     if (!key) return;
     uploadedKeys.value = uploadedKeys.value.filter((item) => item !== key);
 };
@@ -212,9 +229,11 @@ const handleCancel = () => {
 
 const handleConfirm = () => {
     if (confirming.value) return;
-    const uploading = fileList.value.some((item) => item.status === "uploading");
+    const uploading =
+        pendingUploads.size > 0 ||
+        fileList.value.some((item) => item.status === "uploading");
     if (uploading) {
-        toast("warning", "图片上传中,请稍候");
+        toast("warning", "图片上传中,请稍后");
         return;
     }
     const failed = fileList.value.some((item) => item.status === "failed");
@@ -476,6 +495,10 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.42) 0%, rgba(255, 255, 255, 0) 12%
 </style>
 
 <style lang="scss">
+.van-image-preview {
+    z-index: 30000 !important;
+    background-color: rgba(0, 0, 0, 0.8);
+}
 /* teleported 到 body,需高于 vant popup(20000) */
 .album-upload-date-popper {
     z-index: 30050 !important;

+ 8 - 8
src/views/old_mini/agri_file/components/patrolPanel.vue

@@ -20,11 +20,11 @@
                 <span>新增品种</span>
             </div>
         </div>
-        <div v-if="loading" class="patrol-loading">
+        <!-- <div v-if="loading" class="patrol-loading">
             <span class="patrol-loading__spinner"></span>
             <span class="patrol-loading__text">加载中...</span>
-        </div>
-        <template v-else>
+        </div> -->
+        <div v-loading="loading" element-loading-background="rgba(15, 15, 15, 0.55)" element-loading-text="加载中...">
             <div
                 v-for="item in patrolList"
                 :key="item.id"
@@ -84,13 +84,13 @@
                 </div>
             </div>
         </div>
-        </template>
+    </div>
         <div class="crop-archive">
             <!-- <div class="crop-archive__title">{{ t("agriFile.cropArchive") }}</div> -->
             <PhenologyTrackTimelineItem theme="dark" :list="cropArchiveList" />
         </div>
         <album-upload-popup v-model:show="showUploadPopup" @confirm="handleUploadConfirm" />
-        <tip-popup v-model:show="showSuccessPopup" type="executeSuccess" text="您已上传成功" text2="请等待诊断报告生成" hideBtn>
+        <tip-popup v-model:show="showSuccessPopup" type="executeSuccess" text="您已上传成功" text2="诊断报告正在生成,请稍后..." hideBtn>
             <template #footer>
                 <div class="bottom-btn-container">
                     <div class="bottom-btn primary-btn" @click="handleComplete">完成</div>
@@ -323,10 +323,10 @@ const fetchZones = async () => {
     try {
         const res = await VE_API.questionnaire.getZones({ farm_id: farmId });
         const zones = Array.isArray(res?.data?.zones) ? res.data.zones : [];
-        zoneList.value = zones;
+        zoneList.value = zones.reverse();
         // 优先沿用当前选中;否则默认第一个
         const matched = zones.find((z) => z.zone_id === selectedZoneId.value);
-        applySelectedZone(matched || zones[0] || null);
+        applySelectedZone(matched || zoneList.value[0] || null);
     } catch (e) {
         console.warn("[patrolPanel] getZones failed", e);
         zoneList.value = [];
@@ -425,7 +425,7 @@ const handleSelectZone = (zone) => {
 const goAddVariety = () => {
     router.push({
         path: "/add_zone",
-        query: { type: "region", isSuccessPopup: "0" },
+        query: { type: "region", isSuccessPopup: "1" },
     });
 };
 

+ 1 - 1
src/views/old_mini/agri_file/index.vue

@@ -40,7 +40,7 @@
             <report-panel v-show="activeNav === 'report'" />
         </div>
         <album-upload-popup v-model:show="showUploadPopup" @confirm="handleUploadConfirm" />
-        <tip-popup v-model:show="showSuccessPopup" type="executeSuccess" text="您已上传成功" text2="请等待诊断报告生成" hideBtn>
+        <tip-popup v-model:show="showSuccessPopup" type="executeSuccess" text="您已上传成功" text2="诊断报告正在生成,请稍后..." hideBtn>
             <template #footer>
                 <div class="bottom-btn-container">
                     <div class="bottom-btn primary-btn" @click="handleComplete">完成</div>

+ 1 - 1
src/views/old_mini/agri_file/pages/abnormalTrack.vue

@@ -128,7 +128,7 @@
             v-model:show="showSuccessPopup"
             type="executeSuccess"
             text="您已上传成功"
-            text2="请等待诊断报告生成"
+            text2="诊断报告正在生成,请稍后..."
             hideBtn
         >
             <template #footer>

+ 30 - 8
src/views/old_mini/agri_file/pages/addZone.vue

@@ -39,15 +39,22 @@
         <add-zone-info-popup
             v-model:show="showZoneInfoPopup"
             :polygon="drawnPolygon"
+            :show-success-message="!isSuccessPopupParam"
             @confirm="handleZoneInfoConfirm"
         />
 
         <tip-popup v-model:show="showExecuteSuccessPopup" type="executeSuccess" text="分区/相册已创建成功" buttonText="完成" @confirm="handleComplete">
-            <!-- <template #footer>
-                <div class="bottom-btn-container">
-                    <div class="bottom-btn secondary-btn" @click="handleComplete">完成</div>
+            <template #footer>
+                <div class="draw-success-upload" @click="handleUploadCropPhoto">
+                    <div class="draw-success-upload__text">
+                        <div class="draw-success-upload__title">可上传作物照片</div>
+                        <div class="draw-success-upload__desc">持续记录这块地的长势情况</div>
+                    </div>
+                    <div class="draw-success-upload__camera">
+                        <img class="draw-success-upload__camera__icon" src="@/assets/img/common/camera.png" alt="">
+                    </div>
                 </div>
-            </template> -->
+            </template>
         </tip-popup>
 
         <tip-popup
@@ -386,8 +393,10 @@ function resolveSubmitRegionName() {
 }
 
 const submittingZoneRange = ref(false);
-/** drawZoneRange 成功后的返回,上传照片跳转用 */
+/** drawZoneRange(type=farm)成功后的返回,上传照片跳转用 */
 const lastDrawZoneResult = ref(null);
+/** createZone(type=region)返回的新建分区,上传照片跳转用 */
+const lastCreatedZoneResult = ref(null);
 
 /** 巡园要点 needDraw 进入:填名称后提交分区范围 */
 const handleFarmNameConfirm = async (regionName) => {
@@ -472,13 +481,25 @@ function leaveAfterZoneCreated() {
 }
 
 const handleZoneInfoConfirm = (formData) => {
+    const { created, ...formValues } = formData || {};
     const payload = mapManage.getAreaGeometry();
     const geometryData = {
-        ...formData,
+        ...formValues,
         geometryArr: payload.geometryArr,
         mianji: payload.mianji,
     };
     sessionStorage.setItem("ADD_ZONE_GEOMETRY", JSON.stringify(geometryData));
+
+    // 记录 createZone 返回的新建分区,供「可上传作物照片」跳转使用,
+    // 避免回退到 selectedFarmData 里的旧分区
+    const data = created && typeof created === "object" ? created : {};
+    lastCreatedZoneResult.value = {
+        farm_id: data.farm_id ?? data.id ?? formValues.farm_id ?? resolveSubmitFarmId(),
+        zone_id: data.zone_id ?? data.zoneId ?? "",
+        zone_name:
+            data.zone_name || data.name || formValues.zone_name || resolveSubmitRegionName(),
+    };
+
     // isSuccessPopup=1 才出 tip;=0 时子组件已 ElMessage,直接离开
     if (isSuccessPopupParam.value) {
         showExecuteSuccessPopup.value = true;
@@ -492,9 +513,9 @@ const handleDrawSuccessClosed = () => {
     leaveAfterConfirm();
 };
 
-/** 勾画成功弹窗:上传作物照片,优先用 drawZoneRange 返回 */
+/** 成功弹窗:上传作物照片,优先用本次新建分区 / 勾画范围接口返回的数据 */
 const handleUploadCropPhoto = () => {
-    const result = lastDrawZoneResult.value || {};
+    const result = lastCreatedZoneResult.value || lastDrawZoneResult.value || {};
     router.replace({
         path: "/region_albums",
         query: {
@@ -519,6 +540,7 @@ function resetPageTransientState() {
     drawnPolygon.value = "";
     submittingZoneRange.value = false;
     lastDrawZoneResult.value = null;
+    lastCreatedZoneResult.value = null;
 }
 
 onActivated(() => {

+ 1 - 1
src/views/old_mini/agri_file/pages/growthTrack.vue

@@ -121,7 +121,7 @@
             v-model:show="showSuccessPopup"
             type="executeSuccess"
             text="您已上传成功"
-            text2="请等待诊断报告生成"
+            text2="诊断报告正在生成,请稍后..."
             hideBtn
         >
             <template #footer>

+ 1 - 1
src/views/old_mini/agri_file/pages/pestInteract.vue

@@ -21,7 +21,7 @@
             v-model:show="showSuccessPopup"
             type="executeSuccess"
             text="您已上传成功"
-            text2="请等待诊断报告生成"
+            text2="诊断报告正在生成,请稍后..."
             hideBtn
         >
             <template #footer>

+ 83 - 10
src/views/old_mini/agri_file/pages/regionAlbums.vue

@@ -10,7 +10,7 @@
             <div class="region-albums__hero-info">
                 <div class="region-albums__title">
                     {{ regionName }}
-                    <el-icon class="edit-icon"><EditPen /></el-icon>
+                    <el-icon class="edit-icon" @click="handleEditName"><EditPen /></el-icon>
                 </div>
                 <div class="region-albums__count">
                     <img class="count-icon" src="@/assets/img/agricultural/img-icon.png" alt="">
@@ -38,7 +38,13 @@
                         class="album-group"
                     >
                         <div class="album-group__header">
-                            <div class="album-group__date">{{ group.dateLabel }}</div>
+                            <div class="album-group__date">
+                                <div class="date-line">
+                                    <span class="date-dot"></span>
+                                    {{ group.dateLabel }}
+                                </div>
+                                <span class="num-val">{{ group.list.length }}张</span>
+                            </div>
                             <div v-if="group.remark" class="album-group__remark">{{ group.remark }}</div>
                         </div>
                         <div class="album-group__grid">
@@ -65,6 +71,16 @@
             @confirm="handleUploadConfirm"
         />
 
+        <RegionNamePopup
+            v-model:show="showRenamePopup"
+            theme="dark"
+            title="修改分区名称"
+            field-label="分区名称"
+            confirm-text="确认修改"
+            :default-name="regionName"
+            @confirm="handleRenameConfirm"
+        />
+
         <ImagePreviewPopup
             v-model:show="showPreview"
             :images="previewImages"
@@ -80,10 +96,11 @@
 import { computed, onActivated, onDeactivated, onMounted, ref } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { ElMessage } from "element-plus";
-import { ArrowLeftBold, Plus } from "@element-plus/icons-vue";
+import { ArrowLeftBold, EditPen, Plus } from "@element-plus/icons-vue";
 import { base_img_url2, resize_300 } from "@/api/config";
 import { useI18n } from "@/i18n";
 import ImagePreviewPopup from "@/components/popup/ImagePreviewPopup.vue";
+import RegionNamePopup from "@/views/old_mini/recordDetails/components/RegionNamePopup.vue";
 import albumUploadPopup from "../components/albumUploadPopup.vue";
 
 const { t } = useI18n();
@@ -99,9 +116,15 @@ const showPreview = ref(false);
 const previewImages = ref([]);
 const previewIndex = ref(0);
 const showUploadPopup = ref(false);
+const showRenamePopup = ref(false);
+/** 本地重命名(接口暂无改分区名能力),按 farm+zone 缓存 */
+const renamedZoneName = ref("");
 
 const farmId = computed(() => route.query.farm_id || "");
 const zoneId = computed(() => route.query.zone_id || "");
+const renameStorageKey = computed(
+    () => `REGION_ALBUMS_ZONE_NAME_${farmId.value}_${zoneId.value}`
+);
 
 const getSelectedFarm = () => {
     try {
@@ -112,7 +135,11 @@ const getSelectedFarm = () => {
 };
 
 const regionName = computed(
-    () => zoneNameFromApi.value || route.query.name || t("agriFile.zoneOne")
+    () =>
+        renamedZoneName.value ||
+        zoneNameFromApi.value ||
+        route.query.name ||
+        t("agriFile.zoneOne")
 );
 
 const totalCount = computed(() => imageCount.value);
@@ -170,7 +197,7 @@ const applyAlbumData = (data) => {
     const groups = Array.isArray(data?.farmImgs) ? data.farmImgs : [];
     farmImgs.value = groups;
     imageCount.value = Number(data?.image_count) || 0;
-    zoneNameFromApi.value = groups[0]?.imgList?.[0]?.zone_name || "";
+    zoneNameFromApi.value = data?.zone_name || "";
     imageList.value = groups.flatMap((group) =>
         (group.imgList || []).map((img) => ({
             id: img.id,
@@ -245,6 +272,30 @@ const handleRemarkConfirm = ({ index, remark, image }) => {
     }
 };
 
+const readRenamedZoneName = () => {
+    try {
+        return localStorage.getItem(renameStorageKey.value) || "";
+    } catch {
+        return "";
+    }
+};
+
+const handleEditName = () => {
+    showRenamePopup.value = true;
+};
+
+const handleRenameConfirm = (name) => {
+    const next = String(name || "").trim();
+    if (!next || next === regionName.value) return;
+    renamedZoneName.value = next;
+    try {
+        localStorage.setItem(renameStorageKey.value, next);
+    } catch {
+        // ignore
+    }
+    ElMessage.success("修改成功");
+};
+
 const handleAdd = () => {
     showUploadPopup.value = true;
 };
@@ -286,6 +337,8 @@ const goBack = () => {
 };
 
 const syncAlbumByRoute = () => {
+    // 切换分区时重置并读取该分区的本地重命名
+    renamedZoneName.value = readRenamedZoneName();
     fetchAlbumImages();
 };
 
@@ -326,6 +379,7 @@ onDeactivated(() => {
 
 
         &.is-light {
+            top: 0;
             background: url('@/assets/img/agricultural/album-bg.png') no-repeat center center /100% 100%;
         }
     }
@@ -402,7 +456,7 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 72.1
             height: 100%;
             overflow-y: auto;
             background: #1A191D;
-            padding: 0 6px 40px;
+            padding: 0 6px 0px;
             box-sizing: border-box;
         }
     }
@@ -442,7 +496,7 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 72.1
     &__album-list {
         overflow-y: auto;
         height: 100%;
-        padding: 12px 6px 40px;
+        padding: 12px 6px calc(16px + env(safe-area-inset-bottom));
         box-sizing: border-box;
     }
 
@@ -477,19 +531,38 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 72.1
         font-weight: 600;
         line-height: 22px;
         color: #fff;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .date-line {
+            display: inline-flex;
+            align-items: center;
+            gap: 7px;
+            .date-dot {
+                width: 6px;
+                height: 6px;
+                border-radius: 50%;
+                background-color: #FFD489;
+            }
+        }
+        .num-val {
+            font-size: 12px;
+            font-weight: 500;
+            color: rgba(255, 255, 255, 0.5);
+        }
     }
 
     &__remark {
-        margin-top: 2px;
+        margin-top: 8px;
         font-size: 12px;
         line-height: 18px;
-        color: rgba(1, 1, 1, 0.5);
+        color: rgba(255, 255, 255, 0.6);
     }
 
     &__grid {
         display: grid;
         grid-template-columns: repeat(3, 1fr);
-        gap: 4px;
+        gap: 8px;
     }
 
     &__item {

+ 1 - 1
src/views/old_mini/agri_file/pages/soilRootTrack.vue

@@ -226,7 +226,7 @@
             v-model:show="showSuccessPopup"
             type="executeSuccess"
             text="您已上传成功"
-            text2="请等待诊断报告生成"
+            text2="诊断报告正在生成,请稍后..."
             hideBtn
         >
             <template #footer>

+ 1 - 1
src/views/old_mini/growth_report/components/CropAlertPanel.vue

@@ -142,7 +142,7 @@ const props = defineProps({
         type: [String, Number],
         default: "",
     },
-    /** 无农场时区县码,与 getHomeMapCalcByCounty 同源 */
+    /** 无农场时区县码,由父页逆地理得到,用于点位预警 */
     countyCode: {
         type: [String, Number],
         default: "",

+ 0 - 26
src/views/old_mini/growth_report/growthReportMap.js

@@ -1,7 +1,6 @@
 import * as KMap from "@/utils/ol-map/KMap";
 import * as util from "@/common/ol_common.js";
 import config from "@/api/config.js";
-import StaticImgLayer from "@/utils/ol-map/StaticImgLayer";
 import Style from "ol/style/Style";
 import Icon from "ol/style/Icon";
 import Fill from "ol/style/Fill";
@@ -28,7 +27,6 @@ class IndexMap {
     let vectorStyle = new KMap.VectorStyle();
     this.vectorStyle = vectorStyle;
     this.noRangeTipOverlay = null;
-    this.remoteImageLayer = null;
 
     // 位置图标
     this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
@@ -56,30 +54,6 @@ class IndexMap {
     });
   }
 
-  /** 叠加静态风险底图(与 demo growthReportMap.showRemoteImage 一致) */
-  showRemoteImage(url, extent, options = {}) {
-    this.hideRemoteImage();
-    if (!url || !extent?.length || !this.kmap) return;
-    this.remoteImageLayer = new StaticImgLayer(
-      url,
-      {
-        extent,
-        minZoom: 6,
-        maxZoom: 22,
-        opacity: options.opacity ?? 0.5,
-      },
-      50,
-      this.kmap,
-    );
-  }
-
-  hideRemoteImage() {
-    if (this.remoteImageLayer?.layer && this.kmap?.map) {
-      this.kmap.map.removeLayer(this.remoteImageLayer.layer);
-    }
-    this.remoteImageLayer = null;
-  }
-
   initMap(location, target) {
     let level = 16;
     let coordinate = util.wktCastGeom(location).getFirstCoordinate();

+ 5 - 306
src/views/old_mini/growth_report/index.vue

@@ -62,19 +62,7 @@
                 </div>
             </div>
 
-            <div class="growth-top__content" :class="{'space-pos': stressMenuItems.length}">
-                <!-- 左侧:气象底图图层菜单(有农场 getHomeMapCalc / 无农场 getHomeMapCalcByCounty) -->
-                <div v-if="stressMenuItems.length" class="side-menu side-menu--left">
-                    <div v-for="item in stressMenuItems" :key="item.key" class="side-menu__item"
-                        :class="{ active: activeMenuKey === item.key }" @click="handleSelectMenu(item.key)">
-                        <img class="side-menu__icon" :src="base_img_url3 + item.icon_path" alt="" />
-                        <div class="side-menu__text">
-                            <span>{{ item.line1 }}</span>
-                            <span>{{ item.line2 }}</span>
-                        </div>
-                    </div>
-                </div>
-                
+            <div class="growth-top__content">
                 <div class="invite-group">
                     <div class="invite-btn" @click="handleLocateToCenter">
                         <img class="current-icon" src="@/assets/img/home/current.png" alt="">
@@ -93,12 +81,8 @@
         </div>
 
 
-        <div v-if="activeLegendUrl" class="map-legend map-legend--image" :style="{ bottom: `${inviteBottom + 10}px` }">
-            <img class="map-legend__img" :src="activeLegendUrl" alt="" />
-        </div>
-
         <crop-alert-panel :crop-name="currentCropName" :farm-id="selectedFarmId" :county-code="countyCode"
-            @zone-change="handleZoneChange" @height-change="handlePanelHeightChange" />
+            @zone-change="handleZoneChange" />
     </div>
 
     <!-- 恢复种植弹窗 -->
@@ -117,7 +101,6 @@ import GrowthReportMap from "./growthReportMap.js";
 import CropAlertPanel from "./components/CropAlertPanel.vue";
 import wx from "weixin-js-sdk";
 
-import { base_img_url3 } from "@/api/config";
 import restorePlantingPopup from "@/components/popup/restorePlantingPopup.vue";
 
 const router = useRouter();
@@ -125,10 +108,9 @@ const router = useRouter();
 const DEFAULT_MAP_POINT = "POINT(113.6142086995688 23.585836479509055)";
 const LOCATION_SESSION_KEY = "GROWTH_REPORT_LOCATION";
 const MAP_POINT_STORAGE_KEY = "GROWTH_REPORT_MAP_POINT";
-/** 无农场时逆地理得到的区县码,供底图 / 点位预警共用 */
+/** 无农场时逆地理得到的区县码,供点位预警使用 */
 const COUNTY_CODE_STORAGE_KEY = "GROWTH_REPORT_COUNTY_CODE";
 
-const menuIcon = require("@/assets/img/common/farm-active.png");
 const periodIcon = require("@/assets/img/agricultural/period.png");
 const lightningIcon = require("@/assets/img/agricultural/lightning.png");
 const soilIcon = require("@/assets/img/agricultural/soil.png");
@@ -158,16 +140,6 @@ const currentCropName = computed(() => {
         ""
     );
 });
-/** 侧边气象图层菜单(有农场 getHomeMapCalc / 无农场 getHomeMapCalcByCounty) */
-const stressMenuItems = ref([]);
-const activeMenuKey = ref("");
-/** 当前选中图层图例图 */
-const activeLegendUrl = ref("");
-const panelHeight = ref(280);
-const inviteBottom = computed(() => panelHeight.value);
-/** 防止切换农场/分区时旧请求回写 */
-let mapCalcToken = 0;
-
 const getSelectedFarm = () => {
     try {
         return JSON.parse(localStorage.getItem("selectedFarmData") || "{}");
@@ -285,7 +257,7 @@ const goAddZone = (type) => {
         path: "/add_zone",
         query: {
             type,
-            isSuccessPopup: type === "farm" ? "1" : "0",
+            isSuccessPopup: "1",
         },
     });
 };
@@ -523,132 +495,8 @@ function resolveCropCode(farm = getSelectedFarm()) {
     return farm.category_code || farm.categorycode || farm.crop_code || farm.crop_type || "";
 }
 
-/** 本地 dem 路径转 mapimg 可访问地址:取文件名挂到 /mapimg/ */
-function resolveCalcAssetUrl(path) {
-    if (!path) return "";
-    const raw = String(path).trim();
-    if (/^https?:\/\//i.test(raw)) return raw;
-    const fileName = raw.replace(/\\/g, "/").split("/").filter(Boolean).pop();
-    if (!fileName) return "";
-    // /home/dem_ditu/输出/从化区_xxx.png → https://feiniao-farm-h5-v3.feiniaotech.com/mapimg/从化区_xxx.png
-    return `https://feiniao-farm-h5-v3.feiniaotech.com/mapimg/${encodeURIComponent(fileName)}`;
-}
-
-/** risk_name 拆成两行展示,如「高温高湿」→ 高温 / 高湿 */
-function splitRiskName(name) {
-    const text = String(name || "").trim();
-    if (!text) return { line1: "-", line2: "" };
-    if (text.length <= 2) return { line1: text, line2: "" };
-    const mid = Math.ceil(text.length / 2);
-    return { line1: text.slice(0, mid), line2: text.slice(mid) };
-}
-
-function mapCalcRecordToMenuItem(record) {
-    const { line1, line2 } = splitRiskName(record?.risk_name);
-    const bounds = Array.isArray(record?.bounds) ? record.bounds.map(Number) : [];
-    const extent =
-        bounds.length === 4 && bounds.every((n) => Number.isFinite(n)) ? bounds : null;
-    return {
-        key: String(record?.id ?? record?.risk_name ?? ""),
-        line1,
-        line2,
-        icon_path: record?.icon_path || menuIcon,
-        mapUrl: resolveCalcAssetUrl(record?.png_path),
-        extent,
-        legendUrl: resolveCalcAssetUrl(record?.legend_path),
-    };
-}
-
-function clearMapCalcState() {
-    stressMenuItems.value = [];
-    activeMenuKey.value = "";
-    activeLegendUrl.value = "";
-    growthReportMap.hideRemoteImage();
-}
-
-/** 按侧边菜单叠加对应气象底图 + 图例 */
-function applyMenuOverlay(key) {
-    const item = stressMenuItems.value.find((m) => m.key === key);
-    if (!item?.mapUrl || !item.extent || !growthReportMap.kmap) {
-        growthReportMap.hideRemoteImage();
-        activeLegendUrl.value = "";
-        return;
-    }
-    growthReportMap.showRemoteImage(item.mapUrl, item.extent);
-    activeLegendUrl.value = item.legendUrl || "";
-}
-
-function applyMapCalcRecords(records) {
-    stressMenuItems.value = records.map(mapCalcRecordToMenuItem).filter((item) => item.key);
-    const first = stressMenuItems.value[0];
-    if (first) {
-        activeMenuKey.value = first.key;
-        applyMenuOverlay(first.key);
-    } else {
-        clearMapCalcState();
-    }
-}
-
-/** 无农场:按区县 adcode 拉气象底图 */
-async function fetchHomeMapCalcByCounty(countyCode) {
-    const token = ++mapCalcToken;
-    if (!countyCode) {
-        clearMapCalcState();
-        return;
-    }
-    try {
-        const res = await VE_API.questionnaire.getHomeMapCalcByCounty({
-            county_code: countyCode,
-        });
-        if (token !== mapCalcToken) return;
-        const records = Array.isArray(res?.data?.records) ? res.data.records.slice(0, 3) : [];
-        applyMapCalcRecords(records);
-    } catch (e) {
-        if (token !== mapCalcToken) return;
-        console.warn("[growth_report] getHomeMapCalcByCounty failed", e);
-        clearMapCalcState();
-    }
-}
-
-/** 有农场:按农场/分区拉气象底图 */
-async function fetchHomeMapCalc() {
-    if (!hasSelectedFarm()) return;
-
-    const token = ++mapCalcToken;
-    const farm = getSelectedFarm();
-    const farmId = selectedFarmId.value || farm.farm_id || farm.id;
-    const zoneId = panelZoneId.value;
-    const cropCode = resolveCropCode(farm);
-    if (
-        farmId == null ||
-        farmId === "" ||
-        zoneId == null ||
-        zoneId === "" ||
-        !cropCode
-    ) {
-        clearMapCalcState();
-        return;
-    }
-    try {
-        const res = await VE_API.questionnaire.getHomeMapCalc({
-            farm_id: farmId,
-            zone_id: zoneId,
-            calc_date: formatToday(),
-            crop_code: cropCode,
-        });
-        if (token !== mapCalcToken) return;
-        const records = Array.isArray(res?.data?.records) ? res.data.records.slice(0, 3) : [];
-        applyMapCalcRecords(records);
-    } catch (e) {
-        if (token !== mapCalcToken) return;
-        console.warn("[growth_report] getHomeMapCalc failed", e);
-        clearMapCalcState();
-    }
-}
-
 const handleZoneChange = (zoneId) => {
     panelZoneId.value = zoneId != null && zoneId !== "" ? zoneId : null;
-    fetchHomeMapCalc();
     fetchFarmRangeStatus();
     fetchInteractTask();
 };
@@ -679,18 +527,16 @@ async function getLocationName(point = currentMapPoint.value) {
         locationName.value = result?.address_component
             ? result.address_component.city + result.address_component.district
             : (result?.address || "") + "";
-        // 无农场时用 adcode 拉区县气象底图,并同步给预警面板
+        // 无农场时用 adcode 同步给点位预警面板
         if (!hasSelectedFarm()) {
             const adcode = result?.ad_info?.adcode;
             if (adcode != null && adcode !== "") {
                 const code = String(adcode);
                 countyCode.value = code;
                 localStorage.setItem(COUNTY_CODE_STORAGE_KEY, code);
-                await fetchHomeMapCalcByCounty(code);
             } else {
                 countyCode.value = "";
                 localStorage.removeItem(COUNTY_CODE_STORAGE_KEY);
-                clearMapCalcState();
             }
         }
     } catch (e) {
@@ -714,14 +560,12 @@ const initMap = async () => {
             growthReportMap.setMapPosition(coordinate);
         }
         await syncNoRangeGuide();
-        applyMenuOverlay(activeMenuKey.value);
         return;
     }
     const location = currentMapPoint.value || store.state.home.miniUserLocationPoint || DEFAULT_MAP_POINT;
     currentMapPoint.value = location;
     growthReportMap.initMap(location, mapContainer.value);
     await syncNoRangeGuide();
-    applyMenuOverlay(activeMenuKey.value);
 };
 
 function applySelectedLocation() {
@@ -792,19 +636,6 @@ const handleSwitchLocation = () => {
     });
 };
 
-const handleSelectMenu = (key) => {
-    if (!key) return;
-    // 再次点击同一项则关闭叠加
-    if (activeMenuKey.value === key) {
-        activeMenuKey.value = "";
-        activeLegendUrl.value = "";
-        growthReportMap.hideRemoteImage();
-        return;
-    }
-    activeMenuKey.value = key;
-    applyMenuOverlay(key);
-};
-
 const handleInvite = (type) => {
     const isService = type === "service";
     let inviteName = "好友";
@@ -828,10 +659,6 @@ const handleInvite = (type) => {
     });
 }
 
-const handlePanelHeightChange = (height) => {
-    panelHeight.value = Number(height) || 0;
-};
-
 onMounted(() => {
     // syncSelectedFarmId();
     // syncMapFromSelectedFarm();
@@ -1069,64 +896,9 @@ onActivated(() => {
             display: flex;
             align-items: flex-start;
             justify-content: end;
-            &.space-pos {
-                justify-content: space-between;
-            }
-        }
-    }
-
-    .side-menu {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        gap: 12px;
-        padding: 4px;
-        border-radius: 10px;
-        pointer-events: auto;
-        background: #1b1b1d;
-        box-sizing: border-box;
-        border: 1px solid rgba(255, 255, 255, 0.12);
-
-        &__item {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            gap: 4px;
-            width: 45px;
-            color: #C1C1C1;
-            padding: 5px 10px;
-            box-sizing: border-box;
-            cursor: pointer;
-
-            &.active {
-                color: #FFD489;
-                background: #2C2C2C;
-                border-radius: 6px;
-
-                .side-menu__icon {
-                    opacity: 1;
-                    // filter: brightness(0) saturate(100%) invert(48%) sepia(98%) saturate(1805%) hue-rotate(178deg) brightness(98%) contrast(97%);
-                }
-            }
-        }
-
-        &__icon {
-            width: 21px;
-            object-fit: contain;
-            filter: grayscale(1);
-        }
-
-        &__text {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            font-size: 12px;
-            line-height: 14px;
-            text-align: center;
         }
     }
 
-
     .invite-group {
         pointer-events: none;
 
@@ -1159,79 +931,6 @@ onActivated(() => {
     }
 
 
-    .map-legend {
-        position: fixed;
-        right: 10px;
-        z-index: 20;
-        pointer-events: none;
-        // transition: bottom 0.2s ease;
-        // display: flex;
-        // align-items: center;
-        // gap: 10px;
-        // box-sizing: border-box;
-
-        &__img {
-            display: block;
-            max-width: 180px;
-            max-height: 160px;
-            object-fit: contain;
-        }
-
-        &--en {
-            flex-direction: column;
-            align-items: flex-start;
-            gap: 6px;
-            padding: 8px 10px;
-            background: rgba(0, 0, 0, 0.72);
-            border-radius: 6px;
-
-            .map-legend__item {
-                gap: 6px;
-            }
-
-            .map-legend__pill {
-                width: 18px;
-                height: 4px;
-                flex-shrink: 0;
-            }
-
-            .map-legend__text {
-                font-size: 11px;
-                line-height: 1.2;
-                white-space: nowrap;
-            }
-        }
-
-        &__item {
-            display: flex;
-            align-items: center;
-            gap: 5px;
-        }
-
-        &__pill {
-            width: 16px;
-            height: 5px;
-            border-radius: 10px;
-
-            &--zone {
-                background: #13a27f;
-            }
-
-            &--growth {
-                background: #ff9138;
-            }
-
-            &--pest {
-                background: #e62e2d;
-            }
-        }
-
-        &__text {
-            font-size: 12px;
-            color: #fff;
-        }
-    }
-
     .report-content {
         position: relative;
         height: 100%;