Jelajahi Sumber

feat:对接病虫害接口

wangsisi 6 hari lalu
induk
melakukan
a34b57e867

+ 4 - 4
src/api/modules/bbs.js

@@ -2,19 +2,19 @@ const config = require("../config")
 
 module.exports = {
     list: {
-        url: config.base_dev_url + "bbs_chat_session/list",
+        url: config.base_dev_url + "chat/list",
         type: "get",
     },
     createSession: {
-        url: config.base_dev_url + "bbs_chat_session/createSession",
+        url: config.base_dev_url + "chat/createSession",
         type: "get",
     },
     sendMsg: {
-        url: config.base_dev_url + "bbs_chat_session/send",
+        url: config.base_dev_url + "chat/send",
         type: "post",
     },
     readUpdate: {
-        url: config.base_dev_url + "bbs_chat_session/readUpdate",
+        url: config.base_dev_url + "chat/markRead",
         type: "get",
     },
 }

+ 4 - 0
src/api/modules/farm.js

@@ -29,4 +29,8 @@ module.exports = {
         url: config.base_dev_url + "v2/farm/getFarmDetail",
         type: "get",
     },
+    listByIds: {
+        url: config.base_dev_url + "image/listByIds",
+        type: "post",
+    },
 }

+ 51 - 42
src/components/chatWindow.vue

@@ -206,37 +206,39 @@ const receiverIcon = ref('')
 const receiverIdVal = ref(null)
 
 //聊天会话
-const createSession = (toUserId,callback) =>{
+const createSession = (targetUserId,callback) =>{
     // 先保存当前的对话样式消息  要注释
     const dialogMessages = messages.value.filter(msg => msg.messageType === 'dialog');
     
-    VE_API.bbs.createSession({toUserId}).then((res) => {
-        senderIcon.value = res.data.senderIcon
-        receiverIcon.value = res.data.receiverIcon
-        receiverIdVal.value = res.data.receiverId
-        messages.value = res.data.messages.map(item =>{
-            let content = item.content
-            if(item.messageType==='image'){
-                content = JSON.parse(item.content).originUrl
-            }
-            return {
-                ...item,
-                content,
-                sender:item.senderId===curUserId?'sent':'received',
-                senderIcon:res.data.senderIcon,
-                receiverIcon:res.data.receiverIcon
+    VE_API.bbs.createSession({farmId:766,targetUserId}).then(({data,code}) => {
+        if(code === 0){
+            senderIcon.value = data.session.aaa
+            receiverIcon.value = data.session.targetUserAvatar
+            receiverIdVal.value = data.session.targetUserId
+            messages.value = data.messages.map(item =>{
+                let content = item.content
+                if(item.messageType==='image'){
+                    content = JSON.parse(item.content).originUrl
+                }
+                return {
+                    ...item,
+                    content,
+                    sender:item.senderId===curUserId?'sent':'received',
+                    senderIcon:data.session.aaa,
+                    receiverIcon:data.session.targetUserAvatar
+                }
+            })
+            
+            // 重新添加对话样式消息   要注释
+            if(dialogMessages.length > 0) {
+                messages.value = [...messages.value, ...dialogMessages];
             }
-        })
-        
-        // 重新添加对话样式消息   要注释
-        if(dialogMessages.length > 0) {
-            messages.value = [...messages.value, ...dialogMessages];
+            
+            setTimeout(()=>{
+                scrollToBottom();
+            },300)
+            callback && callback()
         }
-        
-        setTimeout(()=>{
-            scrollToBottom();
-        },300)
-        callback && callback()
     });
 }
 
@@ -244,6 +246,7 @@ const createSession = (toUserId,callback) =>{
 //类型 text ,file,image
 const sendMsg = (messageType = 'text',content = '',image = {}) =>{
     const params = {
+        farmId:766,
         senderId:curUserId,
         receiverId:userId.value,
         content,
@@ -322,21 +325,26 @@ const previewImage = ref(null);
 
 // 初始化 mqtt
 const initMqtt = () => {
-    const topics = ['chat/message/'+curUserId]; // 订阅的主题数组
+    const topics = [`user/chat/message/${766}/${curUserId}`]; // 订阅的主题数组
     mqttClient.value = new MqttClient(topics, (topic, message) => {
-        const obj = JSON.parse(message)
-        if(obj.senderId === receiverIdVal.value){
-            if(obj.messageType==="image"){
-                const img = JSON.parse(obj.content)
-                obj.content = img.originUrl
+        console.log(topic,'topic')
+        console.log('接收推送信息:', message);
+        if(message && message.length > 10){
+            const obj = JSON.parse(message)
+            console.log('message有值',obj)
+            if(obj.senderId === receiverIdVal.value){
+                if(obj.messageType==="image"){
+                    const img = JSON.parse(obj.content)
+                    obj.content = img.originUrl
+                }
+                obj.receiverId = curUserId
+                obj.sender = obj.senderId === curUserId ?'sent':'received',
+                obj.senderIcon = senderIcon.value
+                obj.receiverIcon = receiverIcon.value
+                messages.value.push(obj)
+                
+                scrollToBottom();
             }
-            obj.receiverId = curUserId
-            obj.sender = obj.senderId === curUserId ?'sent':'received',
-            obj.senderIcon = senderIcon.value
-            obj.receiverIcon = receiverIcon.value
-            messages.value.push(obj)
-            
-            scrollToBottom();
         }
     });
 
@@ -348,9 +356,10 @@ const sendMessage = (message) => {
     if(message.messageType === 'text'){
         sendMsg('text',message.content)
     }else if(message.messageType === 'image'){
-        sendMsg('image','',{
-            originUrl:message.content
-        })
+        // sendMsg('image','',{
+        //     originUrl:message.content
+        // })
+        sendMsg('image',message.content)
     }else if(message.messageType === 'dialog'){
         // 对话样式消息不发送到服务器,只显示在本地
         console.log('发送对话样式消息:', message.content);

+ 18 - 6
src/components/detailDialog.vue

@@ -98,6 +98,13 @@ import wx from "weixin-js-sdk";
 import { Popup } from "vant";
 import { useRoute, useRouter } from "vue-router";
 
+const props = defineProps({
+    showSuccessOnly: {
+        type: Boolean,
+        default: false
+    }
+});
+
 const winDialogVisible = ref(false);
 const noShow = ref(false);
 
@@ -107,13 +114,18 @@ const sampleId = route.query.sampleId
 const farmId = route.query.farmId;
 
 const triggerClick = () => {
-    console.log('triggerClick called, emitting activeUpload:show', { farmId: dialogData.value.farmId, farmWorkName: dialogData.value.farmWorkName })
     winDialogVisible.value = false;
-    // 打开同级的激活上传弹窗
-    eventBus.emit("activeUpload:show", { 
-        gardenIdVal: dialogData.value.farmId,
-        problemTitleVal: dialogData.value.farmWorkName
-    });
+    
+    // 如果只显示成功弹窗(来自 album_recognize 页面)
+    if (props.showSuccessOnly) {
+        eventBus.emit("activeUpload:success");
+    } else {
+        // 打开同级的激活上传弹窗
+        eventBus.emit("activeUpload:show", { 
+            gardenIdVal: dialogData.value.farmId,
+            problemTitleVal: dialogData.value.farmWorkName
+        });
+    }
 }
 
 const dialogData = ref({

+ 6 - 0
src/components/popup/activeUploadPopup.vue

@@ -49,6 +49,7 @@ onMounted(() => {
     eventBus.off("upload:changeArr", uploadChange);
     eventBus.on("upload:changeArr", uploadChange);
     eventBus.on("activeUpload:show", handleShow);
+    eventBus.on("activeUpload:success", handleSuccess);
 });
 
 function uploadChange(arr) {
@@ -71,6 +72,10 @@ function handleShow({ gardenIdVal, problemTitleVal }) {
     show.value = true;
 }
 
+function handleSuccess() {
+    successShow.value = true;
+}
+
 const handleUpload = () => {
     if (images.value.length === 0) return ElMessage.warning("请上传图片");
     const params = {
@@ -96,6 +101,7 @@ function handleClosed() {
 
 onUnmounted(() => {
     eventBus.off("activeUpload:show", handleShow);
+    eventBus.off("activeUpload:success", handleSuccess);
     eventBus.off("upload:changeArr", uploadChange);
     show.value = false;
 });

+ 153 - 98
src/views/old_mini/album_recognize/index.vue

@@ -6,130 +6,164 @@
         </div>
         <div class="detail-content">
             <div class="detail-img">
-                <div class="card-item">
-                    <div class="ing-wrap" v-if="isRecognize">
-                        <div>
-                            <el-icon size="20" class="is-loading">
-                                <Loading />
-                            </el-icon>
+                <Swipe class="card-swipe-wrapper" :show-indicators="imgKey && imgKey.length > 1" :loop="false">
+                    <SwipeItem v-for="(img, index) in imgKey" :key="index">
+                        <div class="card-item">
+                            <div class="ing-wrap" v-if="isRecognize">
+                                <div>
+                                    <el-icon size="20" class="is-loading">
+                                        <Loading />
+                                    </el-icon>
+                                </div>
+                                正在识别,请稍后...
+                            </div>
+                            <img class="card-bg" :src="displayUrls[index]" />
+                            <div class="card-content" v-if="!isRecognize && resultsByIndex[index]?.status === 'ok'">
+                                <div class="title-ques">
+                                    <div class="ques-text">病虫名称:{{ resultsByIndex[index]?.data?.name }}</div>
+                                </div>
+                                <div class="dialog-famous">管理方法:</div>
+                                <div class="dialog-answer">
+                                    {{ resultsByIndex[index]?.data?.cure }}
+                                </div>
+                                <div v-if="resultsByIndex[index]?.data?.info" class="advice-wrap">
+                                    <div class="item-tag">基本信息</div>
+                                    <div v-html="resultsByIndex[index]?.data?.info"></div>
+                                </div>
+                                <div class="famous-info" @click="toDetail">
+                                    <img src="@/assets/img/home/link-icon.png" />
+                                    <span>点击查看农事详情</span>
+                                </div>
+                            </div>
+                            <div class="card-content no-data" v-if="!isRecognize && resultsByIndex[index]?.status === 'nodata'">
+                                <img src="@/assets/img/home/good-fill.png" />
+                                长势良好,并未发现病虫害
+                            </div>
                         </div>
-                        正在识别,请稍后...
-                    </div>
-                    <!-- <img class="card-bg" src="@/assets/img/diseases/1.jpg" /> -->
-                    <img class="card-bg" :src="base_img_url2 + imgKey + resize" />
-                    <div class="card-content" v-if="!isRecognize && !noData">
-                        <div class="title-ques">
-                            <div class="ques-text">病虫名称:{{ resList?.name }}</div>
-                        </div>
-                        <div class="dialog-famous">管理方法:</div>
-                        <div class="dialog-answer">
-                            {{ resList.cure }}
-                            <!-- <template v-if="resData?.phenologyName">
-                            ,物候期为<span style="color: #ffd786;">{{resData?.phenologyName}}</span>
-                          </template>
-                          <template v-if="resData?.pestOrDiseaseName">
-                            ,发现<span style="color: #ffd786;">{{resData?.pestOrDiseaseName}}</span>
-                          </template>
-                          <template v-if="resData?.growthAbnormal">
-                            ,出现<span style="color: #ffd786;">{{resData?.growthAbnormal}}</span>
-                          </template>
-                          <template v-else>
-                            ,暂未发现生长异常。
-                          </template> -->
-                        </div>
-                        <div v-if="resList?.info" class="advice-wrap">
-                            <div class="item-tag">基本信息</div>
-                            <div v-html="resList?.info"></div>
-                        </div>
-                        <!-- <div class="info">基本信息:</div>
-                        <div class="desc">
-                            炭疽病是幼龄树的重要病,严重发病时,病叶率可达30-45%。严重影响幼龄树的生长发育。
-                        </div>
-                        <div class="famous-info">
-                            <img src="@/assets/img/old_mini/link-icon.png" />
-                            <span class="type-name">蛀蒂虫</span>
-                            <span>合作专家:陈晓晓</span>
-                        </div> -->
-                    </div>
-
-                    <div class="card-content no-data" v-if="!isRecognize && noData">
-                        <!-- <img src="@/assets/img/weather_index/good-fill.png" /> -->
-                        长势良好,并未发现病虫害
-                    </div>
-                </div>
+                    </SwipeItem>
+                </Swipe>
             </div>
             <div class="btn-wrap" v-if="!isRecognize">
                 <div class="btn primary" @click="goBack">咨询专家</div>
             </div>
-            <!-- <div class="recognizing-box" v-if="isRecognize">正在识别,请稍等~</div> -->
         </div>
     </div>
+    <!-- 农事信息弹窗 -->
+    <detail-dialog ref="detailDialogRef" :show-success-only="true"></detail-dialog>
+    <!-- 上传弹窗组件 -->
+    <active-upload-popup></active-upload-popup>
 </template>
 
 <script setup>
 import { onMounted, ref } from "vue";
+import { Swipe, SwipeItem } from "vant";
 import { useRouter, useRoute } from "vue-router";
 import { base_img_url2 } from "@/api/config.js";
 import wx from "weixin-js-sdk";
 import MqttClient from "@/mqtt/MqttClient";
+import detailDialog from "@/components/detailDialog.vue";
+import activeUploadPopup from "@/components/popup/activeUploadPopup.vue";
 
-let resize = '?x-oss-process=image/resize,w_300'
+let resize = "?x-oss-process=image/resize,w_300";
 const route = useRoute();
-// const json = JSON.parse(route.query.json || "{}");
-const json = JSON.parse(`{"imgKey":["birdseye-look-mini/766/1761548221155.png","birdseye-look-mini/766/1761548221431.png"],"imgId":["770662355804622848","770662355804622849"],"farmId":766,"token":"bcc0e12d-bff6-4f1f-8edc-2ab80b19af41"}`)
+const json = JSON.parse(route.query.json || "{}");
+// const json = JSON.parse(
+//     `{"imgKey":["birdseye-look-mini/766/1761641209074.png","birdseye-look-mini/766/1761641220101.png","birdseye-look-mini/766/1761641220390.png"],"farmId":766,"id":"51","imageIds":["771059829916569600","771059829916569601","771059829916569602"],"token":"bcc0e12d-bff6-4f1f-8edc-2ab80b19af41"}`)
 const imgKey = json.imgKey;
 const farmId = json.farmId;
+const imageIds = json.imageIds || [];
 
 const isRecognize = ref(true);
-const recoginizeResult = ref({});
 const noData = ref(false);
-const resList = ref({});
+const resultsByIndex = ref({});
+// 预置显示地址:默认使用传入的 cloudFilename
+const displayUrls = ref(imgKey.map((p) => base_img_url2 + p + resize));
+const detailDialogRef = ref(null);
 onMounted(() => {
-    console.log(json,'json')
-    const aaa = `{"result":["06"],"updateTime":"2025-10-27T15:03:44.859","taskId":"18","imageIds":[770662364482637824,770662364482637825],"status":1}`
-    console.log(JSON.parse(aaa),'JSON.parse(aaa)')
-    const mqttClient = new MqttClient(['farm/pest_recognition/task/'+farmId], mqttListener);
+    const mqttClient = new MqttClient(["farm/pest_recognition/task/" + farmId], mqttListener);
     mqttClient.connect();
 });
 
 const mqttListener = (topic, message) => {
-  let res = message.toString();
-  console.log("接收推送信息:", res);
-  let status = JSON.parse(res).status;
-  if (status === 1) {
-    let res =  JSON.parse(message)
-    if(res.result && res.result.length > 0){
-      VE_API.home.fetchDiseaseDetail(res.result).then(({data,code}) => {
-        if(code === 0){
-          resList.value = data[0];
+    let resData = JSON.parse(message);
+    if (json.id == resData.taskId) {
+        if (resData.status === 1) {
+            const resultMap = resData.result || {};
+            // 初始化每张图片的结果状态
+            const fetchPromises = [];
+            imageIds.forEach((imgId, index) => {
+                const codes = resultMap[imgId];
+                if (Array.isArray(codes) && codes.length > 0) {
+                    const p = VE_API.home.fetchDiseaseDetail(codes).then(({ data, code: respCode }) => {
+                        if (respCode === 0) {
+                            const detail = Array.isArray(data) ? data[0] : data;
+                            resultsByIndex.value = {
+                                ...resultsByIndex.value,
+                                [index]: { status: 'ok', data: detail }
+                            };
+                        } else {
+                            resultsByIndex.value = {
+                                ...resultsByIndex.value,
+                                [index]: { status: 'nodata' }
+                            };
+                        }
+                    }).catch(() => {
+                        resultsByIndex.value = {
+                            ...resultsByIndex.value,
+                            [index]: { status: 'nodata' }
+                        };
+                    });
+                    fetchPromises.push(p);
+                } else {
+                    resultsByIndex.value = {
+                        ...resultsByIndex.value,
+                        [index]: { status: 'nodata' }
+                    };
+                }
+            });
+
+            VE_API.farm.listByIds(resData.imageIds).then(({ data, code: respCode }) => {
+                if (respCode === 0) {
+                    // 按 imageIds 顺序,为每张图优先选择 cloudResFilename,否则 cloudFilename
+                    const idToRecord = {};
+                    (data || []).forEach((item) => {
+                        if (item && item.id) idToRecord[item.id] = item;
+                    });
+                    const urls = [...displayUrls.value];
+                    imageIds.forEach((id, idx) => {
+                        const rec = idToRecord[id];
+                        if (rec) {
+                            const path = (rec.cloudResFilename && rec.cloudResFilename.trim() !== '')
+                                ? rec.cloudResFilename
+                                : (rec.cloudFilename || imgKey[idx]);
+                            urls[idx] = base_img_url2 + path + resize;
+                        }
+                    });
+                    displayUrls.value = urls;
+                }
+            });
+
+            if (fetchPromises.length > 0) {
+                Promise.allSettled(fetchPromises).finally(() => {
+                    isRecognize.value = false;
+                });
+            } else {
+                // 全部无病虫
+                noData.value = true;
+                isRecognize.value = false;
+            }
         }
-      })
-    }else{
-        noData.value = true;
     }
-    isRecognize.value = false;
-  }
-}
+};
 
 const router = useRouter();
 const goBack = () => {
     // router.go(-1);
     router.push(`/home`);
-    // router.push(`/feature_home_album?activeImgIndex=13&token=${token}`)
 };
 
 const toDetail = () => {
-    router.push("/diseases_dictionary_detail");
-};
-
-const toRecognize = () => {
-    // router.push("/diseases_recognize")
-    const gardenData = {
-        organId: 25862,
-    };
-    wx.miniProgram.navigateTo({
-        url: `/pages/subPages/recognize_carmera/index?gardenData=${JSON.stringify(gardenData)}`,
-    });
+    detailDialogRef.value.showDialog();
 };
 </script>
 
@@ -162,6 +196,35 @@ const toRecognize = () => {
             height: calc(100% - 100px);
             position: relative;
             padding: 4px 16px 30px 16px;
+            .card-swipe-wrapper {
+                width: 100%;
+                height: 100%;
+                border-radius: 24px 0 36px 4px;
+                overflow: hidden;
+                :deep(.van-swipe-item) {
+                    width: 100%;
+                    height: 100%;
+                    display: flex;
+                    flex-direction: column;
+                }
+                :deep(.van-swipe__indicators) {
+                    bottom: 10px;
+                }
+                :deep(.van-swipe__indicator) {
+                    width: 6px;
+                    height: 6px;
+                    background-color: #cccccc;
+                    border-radius: 50%;
+                    margin: 0 4px;
+                    transition: all 0.3s;
+                }
+                :deep(.van-swipe__indicator--active) {
+                    width: 20px;
+                    height: 6px;
+                    background-color: #2199f8;
+                    border-radius: 3px;
+                }
+            }
             .card-item {
                 width: 100%;
                 height: 100%;
@@ -182,6 +245,7 @@ const toRecognize = () => {
                     flex-direction: column;
                     align-items: center;
                     justify-content: center;
+                    z-index: 10;
                 }
                 .card-bg {
                     border-radius: 24px 0 36px 4px;
@@ -265,18 +329,14 @@ const toRecognize = () => {
                         color: #ffd786;
                         font-size: 16px;
                         padding: 8px 0 0px 0;
-                        .type-name {
-                            padding: 0 4px 0 8px;
-                        }
                         img {
                             width: 16px;
+                            height: 16px;
+                            margin-right: 4px;
                         }
                     }
                 }
             }
-            .recognize-img {
-                width: 100%;
-            }
         }
         .btn-wrap {
             width: 100%;
@@ -311,11 +371,6 @@ const toRecognize = () => {
                 margin-left: 15px;
             }
         }
-        .recognizing-box {
-            padding-top: 30px;
-            text-align: center;
-            font-size: 16px;
-        }
         .box-title {
             font-size: 16px;
             font-weight: bold;

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

@@ -84,7 +84,7 @@ const monitorCards = ref({
         {
             title: "专家咨询",
             content: "专业农技专家在线解答疑问",
-            route: "/chat_frame?userId=81881&name=专家1",
+            route: "/chat_frame?userId=91754&name=专家1",
         },
     ],
 });