Browse Source

Merge branch 'farmer' of http://www.sysuimars.cn:3000/feiniao/feiniao-farm-h5 into farmer

lxf 1 week ago
parent
commit
f4d89ebc10

+ 40 - 37
src/components/popup/agriExecutePopup.vue

@@ -1,11 +1,5 @@
 <template>
-    <popup
-        v-model:show="showValue"
-        round
-        class="agri-execute-popup"
-        :z-index="zIndex"
-        teleport="body"
-    >
+    <popup v-model:show="showValue" round class="agri-execute-popup" :z-index="zIndex" teleport="body">
         <div class="popup-content">
             <div class="popup-tips">为了处方体系更加适应您当前的果园管理</div>
             <!-- 头部区域 -->
@@ -18,11 +12,11 @@
             </div>
 
             <!-- 标题 -->
-            <div class="popup-title">{{ popupData.title }}</div>
+            <div class="popup-title">{{ popupData.subjectName }}</div>
 
             <!-- 异常信息区域 -->
-            <div class="abnormal-info" v-if="popupData.abnormalText">
-                {{ popupData.abnormalText }}
+            <div class="abnormal-info" v-if="popupData.subjectRemark">
+                {{ popupData.subjectRemark }}
             </div>
 
             <!-- 图片区域 -->
@@ -34,7 +28,7 @@
                     {{ popupData.laterButtonText || "稍后执行" }}
                 </div>
                 <div class="btn-executed" @click="handleExecuted">
-                    {{ popupData.executedButtonText || "我已执行" }}
+                    开始采集
                 </div>
             </div>
         </div>
@@ -43,24 +37,12 @@
 
 <script setup>
 import { Popup } from "vant";
-import { computed } from "vue";
+import { ref } from "vue";
+import { useRouter } from "vue-router";
+
+const router = useRouter();
 
 const props = defineProps({
-    // 控制弹窗显示/隐藏
-    show: {
-        type: Boolean,
-        default: false,
-    },
-    // 标题
-    popupData: {
-        type: Object,
-        default: () => ({
-            expertName: "韦帮稳",
-            title: "梢期杀虫 农事执行",
-            abnormalText: "由于***异常的出现,由于***异常的出现,由于***异常的出现,由于***异常的出现,",
-            imageUrl: "",
-        }),
-    },
     // 遮罩层z-index
     zIndex: {
         type: Number,
@@ -68,13 +50,9 @@ const props = defineProps({
     },
 });
 
-const emit = defineEmits(["update:show", "later", "executed"]);
+const emit = defineEmits(["later"]);
 
-// 处理v-model双向绑定
-const showValue = computed({
-    get: () => props.show,
-    set: (value) => emit("update:show", value),
-});
+const showValue = ref(false);
 
 // 稍后执行
 const handleLater = () => {
@@ -84,9 +62,32 @@ const handleLater = () => {
 
 // 我已执行
 const handleExecuted = () => {
-    emit("executed");
-    emit("update:show", false);
+    showValue.value = false;
+    router.push(`/interaction_list?farmId=${farmIdData.value}&regionId=${popupData.value.regionId}&interactionTypeId=${popupData.value.interactionTypeId}`);
+};
+
+const popupData = ref({});
+const farmIdData = ref(null);
+const showPopup = async (farmId) => {
+    farmIdData.value = farmId;
+    const { data } = await VE_API.home.hasUnrepliedTriggeredInteraction({ subjectId: localStorage.getItem("selectedFarmId") });
+    if (data && data.id != null) {
+        popupData.value = data;
+        showValue.value = true;
+        popupData.value.exampleImg = JSON.parse(data.exampleImagesJson)[0];
+    }
 };
+
+// const handleClosePopup = () => {
+//     VE_API.monitor.closeTodayPopup({
+//         interactionId: popupData.value.id,
+//     });
+// }
+
+defineExpose({
+    showPopup,
+});
+
 </script>
 
 <style scoped lang="scss">
@@ -100,7 +101,7 @@ const handleExecuted = () => {
         flex-direction: column;
     }
 
-    .popup-tips{
+    .popup-tips {
         color: rgba(93, 93, 93, 0.8);
         margin-bottom: 5px;
     }
@@ -110,6 +111,7 @@ const handleExecuted = () => {
         display: flex;
         align-items: center;
         gap: 6px;
+
         .expert-logo {
             width: 26px;
             height: 26px;
@@ -119,6 +121,7 @@ const handleExecuted = () => {
 
         .expert-info {
             font-size: 16px;
+
             .invite-text {
                 margin-left: 6px;
             }
@@ -140,7 +143,7 @@ const handleExecuted = () => {
         border-radius: 8px;
         position: relative;
         margin-top: 5px;
-        
+
         // 三角形小尖尖
         &::before {
             content: "";

+ 8 - 4
src/views/old_mini/create_farm/index.vue

@@ -851,14 +851,18 @@ function populateEditData() {
     }
 
     // 处理作物数据(兼容多选)
-    if (Array.isArray(editData.cropList) && editData.cropList.length > 0) {
-        // editData.cropList 中带有 speciesId,根据 speciesId 去匹配当前 specieList 里的 id
+    if (Array.isArray(editData.regionList) && editData.regionList.length > 0) {
         const selected = [];
-        editData.cropList.forEach((crop) => {
-            const targetId = crop.speciesId ?? crop.id;
+        const speciesIdSet = new Set();
+        editData.regionList.forEach((region) => {
+            const targetId = region.speciesId;
             if (targetId == null) return;
+            // 去重:同一个 speciesId 只保留一条
+            const speciesKey = String(targetId);
+            if (speciesIdSet.has(speciesKey)) return;
             const match = specieList.value.find((s) => String(s.id) === String(targetId));
             if (match) {
+                speciesIdSet.add(speciesKey);
                 selected.push({
                     value: match.id,
                     ...match,

+ 28 - 16
src/views/old_mini/interactionList/index.vue

@@ -7,8 +7,11 @@
             <!-- 标题区域 -->
             <div class="item-header-wrapper" :class="{ 'has-status': item.questionStatus !== 3 }">
                 <div class="item-header">
-                    <div class="title">{{ item.interactionTypeName }}</div>
-                    <div class="status" :class="['urgent-' + item.urgent]" v-if="item.questionStatus === 3">{{
+                    <div class="header-wrapper">
+                        <div class="title title-block">{{ item.varietyName }}</div>
+                        <div class="title title-block">{{ item.interactionTypeName }}</div>
+                    </div>
+                    <div class="status title-block" :class="['urgent-' + item.urgent]" v-if="item.questionStatus === 3">{{
                         urgentType[item.urgent] }}</div>
                     <!-- <div class="location-error">
                         <el-icon size="16"><InfoFilled /></el-icon>
@@ -46,7 +49,7 @@
                     </div>
                     <text-ellipsis class="patrol-suggestion" rows="2" :content="'巡园建议:' + item.patrolSuggestion">
                         <template #action="{ expanded }"><span class="action-text">{{ expanded ? '收起' : '展开'
-                                }}</span></template>
+                        }}</span></template>
                     </text-ellipsis>
                 </div>
 
@@ -123,7 +126,7 @@
                     </div>
                 </div>
 
-                <div class="invite-btn" v-if="item.imagePaths.length === 0">邀请农情互动</div>
+                <div class="invite-btn" v-if="item.imagePaths.length === 0 && item.questionStatus === 3">邀请农情互动</div>
             </div>
 
             <!-- 比例信息(已上传状态显示) -->
@@ -135,7 +138,7 @@
                             (item.indicators[i]?.unit
                                 ?? item.indicators[0]?.unit ?? '%')).join('')
                         : item.question + ':' + (item.answerValues[0] ?? '') + (item.indicators[0]?.unit ?? '%'))
-                        }}</span>
+                    }}</span>
                 </template>
                 <div class="toggle-btn" @click="toggleExpand(item)">
                     <span>{{ item.expanded ? "收起" : "展开" }}</span>
@@ -465,7 +468,7 @@ const exampleShowTitleAndTips = ref(true);
 const currentPhotData = ref({})
 const showExample = (item, index, options = {}) => {
     currentPhotData.value = item;
-    exampleList.value = options?.hideLabel ? item.imagePaths.map(p => ({exampleImageUrl: base_img_url2 + p})) : item.exampleImageWithAnnotations || [];
+    exampleList.value = options?.hideLabel ? item.imagePaths.map(p => ({ exampleImageUrl: base_img_url2 + p })) : item.exampleImageWithAnnotations || [];
     exampleStartIndex.value = index || 0;
     exampleShowTitleAndTips.value = options.hideLabel !== true;
     showExamplePopup.value = true;
@@ -476,7 +479,7 @@ const showExample = (item, index, options = {}) => {
 const loadData = async () => {
     loading.value = true;
     try {
-        const { data } = await VE_API.home.listTriggeredByFarm({ farmId: query.value.farmId,regionId:query.value.regionId,interactionTypeId:query.value.interactionTypeId })
+        const { data } = await VE_API.home.listTriggeredByFarm({ farmId: query.value.farmId, regionId: query.value.regionId, interactionTypeId: query.value.interactionTypeId })
         listData.value = data.map(item => {
             // question 按 || 切割成数组,用于循环渲染
             const questionStr = item.question != null ? String(item.question) : '';
@@ -540,7 +543,7 @@ const handleConfirm = async (item, isConfirm) => {
         interactionId: item.id,
         replyText: item.replyText,
         answerValues: item.answerValues,
-        regionId:''
+        regionId: ''
     }
     await VE_API.home.uploadAnswerData(parmas);
     const { code, msg } = await VE_API.home.uploadAnswer(parmas);
@@ -662,7 +665,7 @@ const onCopyWechatId = () => {
 const oldUser = ref(false);
 // 页面从勾画页返回时,如果组件被 keep-alive 缓存,则会触发 onActivated,在此再做一次回显
 onActivated(() => {
-    if(!localStorage.getItem('showUploadTipsPopup')) {
+    if (!localStorage.getItem('showUploadTipsPopup')) {
         showUploadTipsPopup.value = true;
         setTimeout(() => {
             showUploadTipsPopup.value = false;
@@ -670,7 +673,7 @@ onActivated(() => {
         }, 3000);
     }
     // 初始化加载
-    getFarmList();
+    // getFarmList();
     // 加载数据
     loadData();
     renderRegionFromSession();
@@ -713,7 +716,7 @@ const handleSubmitAll = () => {
     box-sizing: border-box;
     overflow-y: auto;
 
-    .tips-text{
+    .tips-text {
         color: #FA7406;
         padding: 5px 10px;
         border: 1px solid #FA7406;
@@ -737,8 +740,13 @@ const handleSubmitAll = () => {
                 display: flex;
                 align-items: center;
                 justify-content: space-between;
+                .header-wrapper {
+                    display: flex;
+                    align-items: center;
+                    gap: 5px;
+                }
 
-                div {
+                .title-block {
                     font-size: 16px;
                     color: #6f6f6f;
                     font-family: "PangMenZhengDao";
@@ -767,7 +775,8 @@ const handleSubmitAll = () => {
                         background: rgba(238, 70, 70, 0.1);
                     }
                 }
-                .location-error{
+
+                .location-error {
                     display: flex;
                     align-items: center;
                     font-family: "Helvetica Neue, Helvetica, Tahoma, Arial, sans-serif";
@@ -997,7 +1006,7 @@ const handleSubmitAll = () => {
             }
         }
 
-        .invite-btn{
+        .invite-btn {
             color: #2199f8;
             border: 1px solid rgba(33, 153, 248, 0.2);
             border-radius: 4px;
@@ -1089,14 +1098,17 @@ const handleSubmitAll = () => {
     }
 }
 
-.custom-bottom-fixed-btns{
+.custom-bottom-fixed-btns {
     justify-content: space-between;
-    .secondary-btn{
+
+    .secondary-btn {
         padding: 10px 20px;
     }
 }
+
 .center-btn {
     justify-content: center;
+
     .primary-btn {
         padding: 10px 32px;
         background: #2199F8;

+ 14 - 81
src/views/old_mini/monitor/index.vue

@@ -11,7 +11,7 @@
             <div class="archives-time-line-header">
                 <div class="line-title" @click="handlePage">作物档案</div>
                 <div class="header-right">
-                    <div class="add-variety-btn" @click="handleAddVariety">
+                    <div class="add-variety-btn" v-if="varietyTabs.length > 0" @click="handleAddVariety">
                         <el-icon size="12">
                             <Plus />
                         </el-icon>
@@ -64,8 +64,9 @@
         sub-title="精准匹配农情信息,高效管理分区" @confirm="handleGoSelectRegion" @skip="handleSkipSelectRegion" />
 
     <!-- 农事执行弹窗 -->
-    <agri-execute-popup v-model:show="showAgriExecutePopup" :popupData="agriExecuteData" @executed="handleAgriExecuted"
-        @close="handleClosePopup" />
+    <agri-execute-popup ref="agriExecutePopupRef" />
+
+    <start-interact-popup ref="startInteractPopupRef" />
 </template>
 
 <script setup>
@@ -79,11 +80,16 @@ import selectRegionPopup from "@/components/popup/selectRegionPopup.vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import ArchivesFarmTimeLine from "@/components/pageComponents/ArchivesFarmTimeLine.vue";
 import agriExecutePopup from "@/components/popup/agriExecutePopup.vue";
+import startInteractPopup from "@/components/popup/startInteractPopup.vue";
 
+const startInteractPopupRef = ref(null);
 const handlePage = () => {
     router.push("/interaction_list");
 }
 
+const agriExecutePopupRef = ref(null);
+
+
 // 品种选择(作物档案内)- 根据主体ID动态获取分区列表
 const varietyTabs = ref([]);
 const activeVariety = ref(0);
@@ -132,31 +138,6 @@ const handleGoSelectRegion = () => {
     router.push("/draw_area");
 };
 
-const showAgriExecutePopup = ref(false); // 农事执行弹窗
-const agriExecuteData = ref({});
-const handleAgriExecuted = () => {
-    showAgriExecutePopup.value = false;
-    handleClosePopup();
-    router.push(`/interaction_list?farmId=${farmIdData.value}&regionId=${regionData.value}&interactionTypeId=${expertInfo.value.interactionTypeId}`);
-};
-
-const expertInfo = ref({});
-const checkHasUnrepliedTriggeredInteraction = async () => {
-    const { data } = await VE_API.home.hasUnrepliedTriggeredInteraction({ subjectId: gardenId.value });
-    if (data && data.id != null) {
-        expertInfo.value = data;
-        agriExecuteData.value = {
-            expertAvatar: data.expertAvatar,
-            expertName: data.expertName,
-            title: data.subjectName,
-            abnormalText: data.subjectRemark,
-            exampleImg: JSON.parse(data.exampleImagesJson)[0],
-            executedButtonText: '开始采集',
-        };
-        showAgriExecutePopup.value = true;
-    }
-};
-
 const showFarmPopup = ref(false); // 农场领取成功弹窗
 
 const defaultGardenId = ref(null);
@@ -194,53 +175,8 @@ const handleLockClick = () => {
 
 // 实时播报数据
 const broadcastList = ref([]);
-const loading = ref(false);
 const finished = ref(false);
 const currentPage = ref(1);
-const pageSize = ref(10);
-
-const getBroadcastList = async (page = 1, isLoadMore = false) => {
-    if (!gardenId.value) {
-        loading.value = false;
-        return;
-    }
-
-    // 如果正在加载,直接返回(避免重复请求)
-    if (loading.value) {
-        return;
-    }
-
-    loading.value = true;
-    try {
-        const res = await VE_API.monitor.broadcastPage({
-            farmId: gardenId.value,
-            limit: pageSize.value,
-            page: page,
-        });
-
-        const newData = res.data || [];
-        if (isLoadMore) {
-            broadcastList.value = [...broadcastList.value, ...newData];
-        } else {
-            broadcastList.value = newData;
-        }
-
-        // 判断是否还有更多数据
-        if (newData.length < pageSize.value) {
-            finished.value = true;
-        } else {
-            finished.value = false;
-            // 如果未完成,页码+1,为下次加载做准备
-            currentPage.value = page + 1;
-        }
-    } catch (error) {
-        console.error("获取播报列表失败:", error);
-        finished.value = true;
-    } finally {
-        // 确保 loading 状态被正确设置为 false
-        loading.value = false;
-    }
-};
 
 // 播报相关事件
 const isSpeaking = ref(false);
@@ -289,10 +225,13 @@ const changeGarden = ({ id }) => {
     currentPage.value = 1;
     finished.value = false;
     broadcastList.value = [];
-    getBroadcastList(1, false);
-    checkHasUnrepliedTriggeredInteraction();
     getReport();
     getVarietyTabs();
+
+    if(varietyTabs.value.length) {
+        agriExecutePopupRef.value.showPopup(varietyTabs.value[activeVariety.value].farmId);
+    }
+    startInteractPopupRef.value.getPhenologyInitOrConfirmStatus();
 };
 
 function handleReportClick() {
@@ -302,12 +241,6 @@ function handleReportClick() {
     });
 }
 
-const handleClosePopup = () => {
-    VE_API.monitor.closeTodayPopup({
-        interactionId: expertInfo.value.id,
-    });
-}
-
 const getReport = () => {
     VE_API.farm.growthReportBySubject({ subjectId: gardenId.value, limit: 20 }).then(({ data }) => {
         if (data && data.length > 0) {

+ 18 - 7
src/views/old_mini/monitor/subPages/darwArea.vue

@@ -62,9 +62,12 @@ const handleVarietyClick = (tab, index) => {
     activeVariety.value = index;
     regionGeom.value = tab.geom;
 
-    if (tab.geom?.length) {
+    // 每次切换/重绘地块前先清空,避免多边形叠加残留
+    if (drawRegionMap.kmap?.polygonLayer?.source) {
         drawRegionMap.kmap.polygonLayer.source.clear();
-        drawRegionMap.setAreaGeometry([tab.geom],true);
+    }
+    if (tab.geom?.length) {
+        drawRegionMap.setAreaGeometry([tab.geom], true);
     }
 };
 
@@ -74,15 +77,22 @@ const activeVarietyName = computed(() => {
 });
 const viewOnly = computed(() => route.query.type === "viewOnly");
 
+function fetchFarmSubjectDetail() {
+    VE_API.basic_farm.fetchFarmSubjectDetail({ subjectId: route.query.subjectId }).then(({ data }) => {
+        if(data?.regionList?.length) {
+            varietyTabs.value = data.regionList;
+            handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
+        }
+    });
+}
+
 onMounted(() => {
     type.value = route.query.type;
     const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
     const editable = !viewOnly.value;
     drawRegionMap.initMap(point, mapContainer.value, editable, true, true);
-    const regionData = route.query?.regionList || [];
-    if (regionData.length) {
-        varietyTabs.value = JSON.parse(regionData);
-        handleVarietyClick(varietyTabs.value[0], 0);
+    if (route.query?.subjectId) {
+        fetchFarmSubjectDetail();
     }
 });
 
@@ -212,6 +222,7 @@ const confirmArea = async () => {
 
     // 每次确认都提交接口(携带目前已确认过的所有品种 regions)
     const ok = await submitRegions();
+    fetchFarmSubjectDetail()
     if (!ok) return;
 
     // 引导流程:弹成功提示,由弹窗控制“下一步/完成”
@@ -267,7 +278,7 @@ const handleEditRegion = () => {
 
         drawRegionMap.initMap(point, mapContainer.value, true, true, true);
 
-        if (varietyTabs.value.length) {
+        if (varietyTabs.value.length && regionGeom.value.length) {
             drawRegionMap.setAreaGeometry([regionGeom.value],true);
         }
         // 切到编辑态后,统一自适应到所有区域,避免画面偏移

+ 1 - 2
src/views/old_mini/monitor/subPages/farmInfo.vue

@@ -25,7 +25,7 @@
                         <span class="info-value">{{ farmInfo.contactPhone }}</span>
                     </div>
                     <div class="info-row">
-                        <span class="info-label">种植作物:</span>
+                        <span class="info-label">种植品种:</span>
                         <div class="info-value crop-tags">
                             <span v-for="crop in farmInfo.regionList" :key="crop.regionId" class="crop-tag">
                                 {{ crop.regionName }}
@@ -217,7 +217,6 @@ const handleEditMap = () => {
                 type: "viewOnly",
                 subjectId: route.query.subjectId,
                 mapCenter,
-                regionList: farmInfo.value.regionList.length ? JSON.stringify(farmInfo.value.regionList) : null,
             },
         });
     } else {