Procházet zdrojové kódy

faet:对接农情弹窗接口和修改上传组件显示内容

wangsisi před 1 týdnem
rodič
revize
dd63acc88e

+ 1 - 15
src/components/popup/agriExecutePopup.vue

@@ -3,8 +3,6 @@
         v-model:show="showValue"
         round
         class="agri-execute-popup"
-        :overlay-style="overlayStyle"
-        :close-on-click-overlay="closeOnClickOverlay"
         :z-index="zIndex"
         teleport="body"
     >
@@ -27,7 +25,7 @@
             </div>
 
             <!-- 图片区域 -->
-            <img src="@/assets/img/home/example-4.png" alt="农事执行图片" class="execute-image" />
+            <img :src="popupData.exampleImg" alt="农事执行图片" class="execute-image" />
 
             <!-- 按钮区域 -->
             <div class="popup-buttons">
@@ -62,18 +60,6 @@ const props = defineProps({
             imageUrl: "",
         }),
     },
-    // 遮罩层样式
-    overlayStyle: {
-        type: Object,
-        default: () => ({
-            "backdrop-filter": "blur(4px)",
-        }),
-    },
-    // 是否在点击遮罩层后关闭弹窗
-    closeOnClickOverlay: {
-        type: Boolean,
-        default: false,
-    },
     // 遮罩层z-index
     zIndex: {
         type: Number,

+ 74 - 21
src/components/upload.vue

@@ -9,24 +9,30 @@
       </el-icon>
       <span>上传照片可精准预测最佳病虫防治时间</span>
     </div>
-    <img v-if="exampleImg" @click="showExample" class="example" src="@/assets/img/home/example-4.png" alt="" />
-    <uploader class="uploader" :class="{ 'uploader-list': exampleImg }" v-model="fileList" :multiple="props.maxCount > 1"
-      :max-count="props.maxCount" :after-read="afterRead" @delete="deleteImg">
-      <template v-if="exampleImg">
-        <slot v-if="!fileList.length"></slot>
+    <div class="upload-content">
+      <img v-if="exampleImg" @click="showExample" class="example" src="@/assets/img/home/example-4.png" alt="" />
+      <div class="example-list-wrapper" v-if="exampleList.length > 0">
+        <div class="example-list">
+          <div class="image-item-wrapper" v-for="example in exampleList" :key="example" @click="showExample(example)">
+            <img class="image-item" :src="example" alt="" />
+          </div>
+        </div>
+      </div>
+      <uploader class="uploader" :class="{ 'uploader-list': exampleImg }" v-model="fileList"
+        :multiple="props.maxCount > 1" :max-count="props.maxCount" :after-read="afterRead" @delete="deleteImg">
+        <template v-if="exampleImg">
+          <slot v-if="!fileList.length"></slot>
+          <img class="plus" v-else src="@/assets/img/home/plus.png" alt="">
+        </template>
         <img class="plus" v-else src="@/assets/img/home/plus.png" alt="">
-      </template>
-      <img class="plus" v-else src="@/assets/img/home/plus.png" alt="">
-    </uploader>
+      </uploader>
+    </div>
   </div>
-
-
   <!-- 示例照片 -->
   <popup v-model:show="showExamplePopup" overlay-class="example-overlay" class="example-popup">
     <div class="example-content">
       <!-- <img src="@/assets/img/home/example-4.png" alt="" /> -->
-      <img class="example-img"
-        src="https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/94379/1768801082504.png" alt="" />
+      <img class="example-img" :src="exampleImgData || 'https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/94379/1768801082504.png'" alt="" />
       <div class="example-tips">
         拍摄要求:请采集代表农场作物物候期的照片,请采集代表农场作物物候期的照片。
       </div>
@@ -66,6 +72,10 @@ const props = defineProps({
     type: Number,
     default: 3
   },
+  exampleList: {
+    type: Array,
+    default: () => []
+  }
 })
 
 
@@ -81,7 +91,9 @@ const imgArr = ref([])
 const uploadFileObj = new UploadFile();
 
 const showExamplePopup = ref(false);
-const showExample = () => {
+const exampleImgData = ref(null);
+const showExample = (example) => {
+  exampleImgData.value = example;
   showExamplePopup.value = true;
 };
 
@@ -148,6 +160,44 @@ onMounted(() => {
 .upload-wrap {
   position: relative;
 
+  .upload-content {
+    display: flex;
+
+    .example-list-wrapper {
+      display: inline-block;
+    }
+
+    .example-list {
+      display: flex;
+      align-items: center;
+
+      .image-item-wrapper {
+        position: relative;
+        margin-right: 8px;
+
+        &::after {
+          content: '示例';
+          position: absolute;
+          top: 0;
+          left: 0;
+          background: rgba(0, 0, 0, 0.7);
+          color: #F2F4F5;
+          padding: 2px 6px;
+          border-radius: 8px 0 2px 0;
+          font-size: 10px;
+          z-index: 1;
+        }
+      }
+
+      .image-item {
+        width: calc((100vw - 68px) / 4);
+        height: calc((100vw - 68px) / 4);
+        border-radius: 8px;
+        object-fit: cover;
+      }
+    }
+  }
+
   .tips {
     display: flex;
     align-items: center;
@@ -197,9 +247,12 @@ onMounted(() => {
   }
 
   .uploader {
-    .plus {
-        width: calc((100vw - 68px) / 3);
-        height: calc((100vw - 68px) / 3);
+
+    .plus,
+    .example,
+    .van-uploader__wrapper {
+      width: calc((100vw - 68px) / 4);
+      height: calc((100vw - 68px) / 4);
     }
   }
 
@@ -207,20 +260,20 @@ onMounted(() => {
     ::v-deep {
       .van-uploader__wrapper {
         >div:first-child {
-          margin-left: calc((100vw - 68px) / 3 + 8px);
+          margin-left: calc((100vw - 68px) / 4 + 8px);
         }
       }
 
       .van-uploader__preview-image {
-        width: calc((100vw - 68px) / 3);
-        height: calc((100vw - 68px) / 3);
+        width: calc((100vw - 68px) / 4);
+        height: calc((100vw - 68px) / 4);
       }
     }
   }
 
   .example {
-    width: calc((100vw - 68px) / 3);
-    height: calc((100vw - 68px) / 3);
+    width: calc((100vw - 68px) / 4);
+    height: calc((100vw - 68px) / 4);
     margin: 0 12px 8px 0;
     position: absolute;
     z-index: 2;

+ 2 - 2
src/views/old_mini/agri_record/subPages/statusDetail.vue

@@ -703,8 +703,8 @@ const handleShowQrCodePopup = (type) => {
         align-items: center;
 
         .example {
-            width: calc((100vw - 68px) / 3);
-            height: calc((100vw - 68px) / 3);
+            width: calc((100vw - 68px) / 4);
+            height: calc((100vw - 68px) / 4);
             margin-right: 8px;
         }
     }

+ 6 - 6
src/views/old_mini/home/index.vue

@@ -199,6 +199,7 @@ onActivated(() => {
             query: { reload: route.query.reload },
         });
     }
+    checkHasUnrepliedTriggeredInteraction();
 });
 
 const userType = ref(localStorage.getItem("USER_TYPE"));
@@ -210,17 +211,16 @@ onMounted(() => {
             route: "/create_farm?type=client&isReload=true&from=home",
         });
     }
-    checkHasUnrepliedTriggeredInteraction();
 });
 
 const checkHasUnrepliedTriggeredInteraction = async () => {
     const { data } = await VE_API.home.hasUnrepliedTriggeredInteraction({ farmId: localStorage.getItem("selectedFarmId") });
-    if (data.hasUnfinishedTask) {
+    if (data && data.interactionTypeName?.length) {
         agriExecuteData.value = {
-            expertName: "韦帮稳",
-            title: "农情互动任务采集",
-            abnormalText: `现在已处于 ${data.phenologyName},上传照片反馈您的荔枝生长近况`,
-            imageUrl: "",
+            expertName: data.expertName || "韦帮稳",
+            title: data.interactionTypeName,
+            abnormalText: data.reason,
+            exampleImg: JSON.parse(data.exampleImagesJson)[0],
             executedButtonText: '查看任务',
         };
         showAgriExecutePopup.value = true;

+ 101 - 61
src/views/old_mini/interactionList/index.vue

@@ -1,13 +1,12 @@
 <template>
     <custom-header name="农情互动" bgColor="#f2f4f5"></custom-header>
     <div class="interaction-list">
-        <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
-            <div class="list-item" v-for="(item, index) in listData" :key="item.id || index"
-                :class="{ 'uploaded-item': item.upload }">
+        <div class="list-item" v-for="(item, index) in listData" :key="item.id || index"
+            :class="{ 'uploaded-item': item.imageIds.length }">
                 <!-- 标题区域 -->
-                <div class="item-header-wrapper" :class="{ 'has-status': item.isUploadPhoto }">
+                <div class="item-header-wrapper" :class="{ 'has-status': item.imageIds.length }">
                     <div class="item-header">{{ item.interactionTypeName }}</div>
-                    <div class="upload-status" v-show="item.upload">
+                    <div class="upload-status" v-show="item.imageIds.length">
                         <el-icon class="status-icon">
                             <SuccessFilled />
                         </el-icon>
@@ -16,7 +15,7 @@
                 </div>
 
                 <!-- 展开状态内容 -->
-                <div class="expanded-content" v-show="item.upload && item.expanded">
+                <div class="expanded-content" v-show="item.imageIds.length && item.expanded">
                     <!-- 原因说明 -->
                     <div class="reason-text">原因原因: 便于记录农场档案,及时调整农事规划</div>
 
@@ -29,19 +28,18 @@
                 </div>
 
                 <!-- 未上传状态内容 -->
-                <div v-show="!item.isUploadPhoto">
+                <div v-show="!item.imageIds.length">
                     <!-- 说明文字 -->
                     <div class="item-desc">{{ item.question }}</div>
 
-                    <upload exampleImg>
-                        <div class="upload-example">
-                            <img class="example" src="@/assets/img/home/plus.png" alt="" />
-                        </div>
-                    </upload>
+                    <upload @handleUpload="handleUploadSuccess" :exampleList="item.exampleImagesJson"></upload>
 
                     <div class="question-wrapper">
-                        <span class="question-text">{{ item.phenologyName }}占比</span>
-                        <el-input v-model="item.remark" style="width: 80px" />
+                        <div class="question-text">
+                            <span class="text-title">{{ item.phenologyName }}占比</span>
+                            <el-input v-model="item.replyText" type="number" style="width: 80px" />
+                            <span class="text-unit">%</span>
+                        </div>
                         <div class="draw-region-btn" @click="handleDrawRegion(item)">勾画发生区域</div>
                     </div>
                     <!-- 输入框 -->
@@ -57,7 +55,7 @@
                 </div>
 
                 <!-- 比例信息(已上传状态显示) -->
-                <div class="proportion-info" v-show="item.upload">
+                <div class="proportion-info" v-show="item.imageIds.length">
                     <span class="proportion-text">当前果园达到物候期的比例: {{ item.proportion || "10%" }}</span>
                     <div class="toggle-btn" @click="toggleExpand(item)">
                         <span>{{ item.expanded ? "收起" : "展开" }}</span>
@@ -68,15 +66,14 @@
                 </div>
             </div>
 
-            <div class="empty-data" v-if="!loading && listData.length === 0">暂无数据</div>
-        </van-list>
+        <div class="empty-data" v-if="!loading && listData.length === 0">暂无数据</div>
     </div>
     <!-- 农场信息完善弹窗 -->
-    <farm-info-popup :expertMiniUserId="query.expertMiniUserId" v-model:show="showFarmInfoPopup" @confirm="handleFarmInfoConfirm" />
+    <farm-info-popup :expertMiniUserId="query.expertMiniUserId" v-model:show="showFarmInfoPopup"
+        @confirm="handleFarmInfoConfirm" />
 </template>
 <script setup>
 import { ref, onMounted } from "vue";
-import { List as VanList } from "vant";
 import { ElMessage } from "element-plus";
 import customHeader from "@/components/customHeader.vue";
 import upload from "@/components/upload.vue";
@@ -85,46 +82,90 @@ import { useRouter, useRoute } from "vue-router";
 const showFarmInfoPopup = ref(false);
 const loading = ref(false);
 const router = useRouter();
-const finished = ref(false);
 const listData = ref([]);
 const query = ref(useRoute().query);
+
 // 加载数据
-const onLoad = async () => {
+const loadData = async () => {
     loading.value = true;
-    // 模拟接口请求
-    const { data } = await VE_API.home.listTriggeredByFarm({ farmId: 766 })
-    if (listData.value.length === 0) {
-        listData.value = [...data];
-    } else {
-        // 加载更多逻辑
-        finished.value = true;
+    try {
+        const { data } = await VE_API.home.listTriggeredByFarm({ farmId: 766 })
+        listData.value = data.map(item => {
+            // 将 exampleImagesJson 转换为数组
+            if (item.exampleImagesJson) {
+                try {
+                    item.exampleImagesJson = typeof item.exampleImagesJson === 'string' 
+                        ? JSON.parse(item.exampleImagesJson) 
+                        : item.exampleImagesJson;
+                    // 确保是数组格式
+                    if (!Array.isArray(item.exampleImagesJson)) {
+                        item.exampleImagesJson = [];
+                    }
+                } catch (e) {
+                    console.error('解析 exampleImagesJson 失败:', e);
+                    item.exampleImagesJson = [];
+                }
+            } else {
+                item.exampleImagesJson = [];
+            }
+            return item;
+        });
+    } catch (error) {
+        console.error("加载数据失败", error);
+    } finally {
+        loading.value = false;
     }
-    loading.value = false;
+};
+
+// 刷新列表数据
+const refreshList = async () => {
+    listData.value = [];
+    await loadData();
 };
 
 // 暂未到达进程
-const handleNotReached = (item) => {
-    console.log("暂未到达进程", item);
-    ElMessage.info("已标记为暂未到达进程");
+const handleNotReached = async (item) => {
     // 这里可以处理业务逻辑
+    const parmas = {
+        isConfirmed:false,
+        farmId: localStorage.getItem("selectedFarmId"),
+        imagePaths: uploadData.value,
+        isUploadPhoto: uploadData.value.length > 0 ? true : false,
+        rangeWkt:'',
+        interactionId:item.id,
+        replyText:item.replyText
+    }
+    const {code, msg} = await VE_API.home.uploadAnswer(parmas);
+    if (code === 0) {
+        ElMessage.success("回答成功");
+        // 清空上传数据
+        uploadData.value = [];
+        // 刷新列表
+        await refreshList();
+    } else {
+        ElMessage.error(msg || '回答失败');
+    }
 };
 
-const handleTipConfirm = () => {
-    router.push("/create_farm?type=farmer&from=interaction_list&expertMiniUserId=81881");
-}
-
 // 确认上传
-const handleConfirm = (item) => {
+const handleConfirm = async (item) => {
     if (!item.proportion) {
-        ElMessage.warning("请输入当前果园达到物候期的比例");
+        ElMessage.warning("请输入当前果园比例");
+        return;
+    }
+    if (uploadData.value.length === 0) {
+        ElMessage.warning("请上传图片");
         return;
     }
     console.log("确认上传", item);
-    ElMessage.success("上传成功");
-    // 标记为已上传状态
-    item.upload = true;
     item.expanded = false;
     // 这里可以处理提交逻辑
+    // const {code, msg} = await VE_API.home.uploadAnswer(item);
+    // if (code === 0) {
+    //     ElMessage.success("上传成功");
+    // } else {
+    //     ElMessage.error(msg || '上传失败');
+    // }
 };
 
 // 切换展开/收起
@@ -135,7 +176,7 @@ const toggleExpand = (item) => {
 // 确认农场信息
 const handleFarmInfoConfirm = async (data) => {
     // 这里可以处理提交逻辑
-    const {code, msg} = await VE_API.farm.saveFarm(data);
+    const { code, msg } = await VE_API.farm.saveFarm(data);
     if (code === 0) {
         ElMessage.success("农场信息确认成功");
     } else {
@@ -147,9 +188,16 @@ const handleDrawRegion = (item) => {
     console.log("勾画发生区域", item);
 };
 
+const uploadData = ref([]);
+const handleUploadSuccess = (data) => {
+    uploadData.value = data.imgArr;
+};
+
 onMounted(() => {
     // 初始化加载
     getFarmList();
+    // 加载数据
+    loadData();
 });
 
 const getFarmList = async () => {
@@ -251,20 +299,20 @@ const getFarmList = async () => {
 
             .btn-not-reached,
             .btn-confirm {
+                flex: 1;
                 text-align: center;
                 border-radius: 4px;
                 padding: 6px;
             }
 
             .btn-not-reached {
-                width: 104px;
+                max-width: fit-content;
                 background: #fff;
                 color: #2199f8;
                 border: 1px solid rgba(33, 153, 248, 0.2);
             }
 
             .btn-confirm {
-                width: calc(100% - 104px - 12px);
                 background: #2199f8;
                 color: #ffffff;
                 border: 1px solid #2199f8;
@@ -310,34 +358,26 @@ const getFarmList = async () => {
         color: #999999;
         font-size: 14px;
     }
-
-    .upload-example {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-
-        .example {
-            width: calc((100vw - 68px) / 3);
-            height: calc((100vw - 68px) / 3);
-            margin-right: 8px;
-        }
-    }
-
     .question-wrapper {
         display: flex;
         align-items: center;
+        justify-content: space-between;
         gap: 10px;
         margin: 12px 0 6px;
         box-sizing: border-box;
         width: 100%;
 
         .question-text {
-             width: calc(100% - 136px - 90px);
             background: #ffffff;
-            // border: 1px solid rgba(0, 0, 0, 0.05);
-            border-radius: 5px;
-            padding: 6px 10px;
             color: #6f6f6f;
+            display: flex;
+            align-items: center;
+            .text-title {
+                margin-right: 4px;
+            }
+            .text-unit {
+                margin-left: 4px;
+            }
         }
 
         .draw-region-btn {