Prechádzať zdrojové kódy

feat:对接农场详情页面接口

wangsisi 1 deň pred
rodič
commit
d807c647b6

+ 29 - 0
src/api/modules/user.js

@@ -0,0 +1,29 @@
+const config = require("../config")
+
+module.exports = {
+    //用户列表
+    userList: {
+        url: config.base_dev_url + "z_agricultural_store_farm/list",
+        type: "get",
+    },
+    //农场信息
+    getFarmDetail: {
+        url: config.base_dev_url + "v2/farm/getFarmDetail",
+        type: "get",
+    },
+    //根据农场ID查询农事互动列表
+    getFarmWorkList: {
+        url: config.base_dev_url + "work_code/phenology/quest/listByFarmId/{page}/{limit}",
+        type: "get",
+    },
+    //获取农事记录详情列表 V2版本
+    getDetailList: {
+        url: config.base_dev_url + "z_farm_work_record/detail-list",
+        type: "get",
+    },
+    //获取未来农事列表
+    getFutureFarmWorkList: {
+        url: config.base_dev_url + "container_farm_work_arrange/futureFarmWorkList/{page}/{limit}",
+        type: "get",
+    }
+}

+ 232 - 205
src/components/chatWindow.vue

@@ -6,15 +6,27 @@
                 <!-- 对方消息 -->
                 <template v-if="msg.sender === 'received'">
                     <!-- <div class="avatar">{{ msg.receiverName.charAt(0) }}</div> -->
-                    <el-avatar class="avatar" :size="40" :src="msg.receiverIcon || 'https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png'" />
-                    <img src="" alt="">
+                    <el-avatar
+                        class="avatar"
+                        :size="40"
+                        :src="
+                            msg.receiverIcon ||
+                            'https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png'
+                        "
+                    />
+                    <img src="" alt="" />
                     <div class="bubble" :class="{ 'no-bubble': msg.messageType === 'image' }">
                         <!-- 文本消息 -->
                         <div v-if="msg.messageType === 'text'" class="content">{{ msg.content }}</div>
 
                         <!-- 图片消息 -->
                         <div v-if="msg.messageType === 'image'" class="image-message">
-                            <img :src="msg.content + resize" @click="showImagePreview(msg.content)" @load="handleImageLoad" alt="图片" />
+                            <img
+                                :src="msg.content + resize"
+                                @click="showImagePreview(msg.content)"
+                                @load="handleImageLoad"
+                                alt="图片"
+                            />
                         </div>
 
                         <!-- 语音消息 -->
@@ -74,7 +86,12 @@
 
                         <!-- 图片消息 -->
                         <div v-if="msg.messageType === 'image'" class="image-message">
-                            <img :src="msg.content + resize" @click="showImagePreview(msg.content)" @load="handleImageLoad" alt="图片" />
+                            <img
+                                :src="msg.content + resize"
+                                @click="showImagePreview(msg.content)"
+                                @load="handleImageLoad"
+                                alt="图片"
+                            />
                         </div>
 
                         <!-- 语音消息 -->
@@ -86,44 +103,46 @@
                         <!-- 对话样式消息 -->
                         <div v-if="msg.messageType === 'dialog'" class="dialog-message">
                             <template v-if="msg.content.type === 'farm_report'">
-                                <div class="report-title" >{{ msg.content.title }}</div>
+                                <div class="report-title">{{ msg.content.title }}</div>
                                 <div class="dialog-title">{{ msg.content.content }}</div>
-                                <img src="@/assets/img/monitor/aaa.png" alt="" class="monitor-image">
+                                <img src="@/assets/img/monitor/aaa.png" alt="" class="monitor-image" />
                             </template>
                             <template v-else>
                                 <div class="dialog-title">{{ msg.content.title }}</div>
-                                <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image">
+                                <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image" />
                             </template>
                         </div>
 
                         <!-- <div class="time">{{ msg.time }}</div> -->
                     </div>
                     <!-- <div class="avatar avatar-r">{{ msg.senderName.charAt(0) }}</div> -->
-                    <el-avatar class="avatar avatar-r" :size="40" :src="msg.senderIcon || 'https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png'" />
+                    <el-avatar
+                        class="avatar avatar-r"
+                        :size="40"
+                        :src="
+                            msg.senderIcon ||
+                            'https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png'
+                        "
+                    />
                 </template>
             </div>
         </div>
-        
+
         <!-- 功能按钮区域 -->
         <div class="function-buttons">
-            <el-select v-model="farmVal" size="large">
+            <el-select v-model="farmVal" size="large" @change="handleFarmChange()">
                 <el-option
-                v-for="item in options"
-                :key="item.id"
-                :label="item.name"
-                :value="item.id"
+                    v-for="item in options"
+                    :key="item.id"
+                    :label="item.name"
+                    :value="item.id"
                 />
             </el-select>
-            <div 
-                v-for="(btn, index) in functionButtons" 
-                :key="index" 
-                class="function-btn" 
-                @click="btn.handler"
-            >
+            <div v-for="(btn, index) in functionButtons" :key="index" class="function-btn" @click="btn.handler">
                 <span class="btn-text">{{ btn.text }}</span>
             </div>
         </div>
-        
+
         <!-- 输入框区域 -->
         <div class="input-area">
             <div class="toolbar">
@@ -175,19 +194,19 @@ const resize = "?x-oss-process=image/resize,p_120/format,webp/quality,q_100";
 const router = useRouter();
 
 const props = defineProps({
-    text:{
-        type:String,
-        defalut:''
+    text: {
+        type: String,
+        defalut: "",
     },
-    img:{
-        type:String,
-        defalut:''
+    img: {
+        type: String,
+        defalut: "",
     },
-    userId:{
-        type:[String,Number],
-        defalut:''
-    }
-})
+    userId: {
+        type: [String, Number],
+        defalut: "",
+    },
+});
 
 const defalutMsg = ref([
     {
@@ -198,128 +217,136 @@ const defalutMsg = ref([
             "你好,我叫陈晓晓。有100亩荔枝,30亩桂味,70亩妃子笑,位置在广州市番禺区大学城110号,希望您可以来指导。",
         time: "上午10:32",
     },
-])
+]);
 
-const curUserId = Number(localStorage.getItem('MINI_USER_ID'))
-const senderIcon = ref('')
-const receiverIcon = ref('')
-const receiverIdVal = ref(null)
+const curUserId = Number(localStorage.getItem("MINI_USER_ID"));
+const senderIcon = ref("");
+const receiverIcon = ref("");
+const receiverIdVal = ref(null);
 
 // 本地用户头像
 const localUserInfoIcon = (() => {
     try {
-        const info = JSON.parse(localStorage.getItem('localUserInfo') || '{}')
-        return info?.icon || ''
+        const info = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
+        return info?.icon || "";
     } catch (e) {
-        return ''
+        return "";
     }
-})()
+})();
 
 // 初始化本地头像为默认发送者头像
-senderIcon.value = localUserInfoIcon
+senderIcon.value = localUserInfoIcon;
 
 //聊天会话
-const createSession = (targetUserId,callback) =>{
+const createSession = (targetUserId, callback) => {
     // 先保存当前的对话样式消息  要注释
-    const dialogMessages = messages.value.filter(msg => msg.messageType === 'dialog');
-    
-    VE_API.bbs.createSession({farmId:farmVal.value,targetUserId}).then(({data,code}) => {
-        if(code === 0){
-            senderIcon.value = localUserInfoIcon
-            receiverIcon.value = data.session.targetUserAvatar
-            receiverIdVal.value = data.session.targetUserId
-            messages.value = data.messages.map(item =>{
-                let content = item.content
-                if(item.messageType==='image'){
+    const dialogMessages = messages.value.filter((msg) => msg.messageType === "dialog");
+
+    VE_API.bbs.createSession({ farmId: farmVal.value, targetUserId }).then(({ data, code }) => {
+        if (code === 0) {
+            senderIcon.value = localUserInfoIcon;
+            receiverIcon.value = data.session.targetUserAvatar;
+            receiverIdVal.value = data.session.targetUserId;
+            messages.value = data.messages.map((item) => {
+                let content = item.content;
+                if (item.messageType === "image") {
                     // 优先读取后端的 image 字段,其次兼容旧的 content(JSON)
                     if (item.image && (item.image.url || item.image.originUrl)) {
-                        content = item.image.url || item.image.originUrl
+                        content = item.image.url || item.image.originUrl;
                     } else if (item.content) {
                         try {
-                            const imgObj = JSON.parse(item.content)
-                            content = imgObj.url || imgObj.originUrl
+                            const imgObj = JSON.parse(item.content);
+                            content = imgObj.url || imgObj.originUrl;
                         } catch (e) {
-                            console.error(e,'e')
+                            console.error(e, "e");
                         }
                     }
                 }
                 return {
                     ...item,
                     content,
-                    sender:item.senderId===curUserId?'sent':'received',
-                    senderIcon:item.senderId===curUserId ? localUserInfoIcon : data.session.targetUserAvatar,
-                    receiverIcon:data.session.targetUserAvatar
-                }
-            })
-            
+                    sender: item.senderId === curUserId ? "sent" : "received",
+                    senderIcon: item.senderId === curUserId ? localUserInfoIcon : data.session.targetUserAvatar,
+                    receiverIcon: data.session.targetUserAvatar,
+                };
+            });
+
             // 重新添加对话样式消息   要注释
-            if(dialogMessages.length > 0) {
+            if (dialogMessages.length > 0) {
                 messages.value = [...messages.value, ...dialogMessages];
             }
-            
-            setTimeout(()=>{
+
+            setTimeout(() => {
                 scrollToBottom();
-            },300)
-            callback && callback()
+            }, 300);
+            callback && callback();
         }
     });
-}
+};
+
+const handleFarmChange = (e) => {
+    createSession(userId.value);
+    initMqtt();
+};
 
 //发送消息接口
 //类型 text ,file,image
-const sendMsg = (messageType = 'text',content = '',image = {}) =>{
+const sendMsg = (messageType = "text", content = "", image = {}) => {
     const params = {
-        farmId:farmVal.value,
-        senderId:curUserId,
-        receiverId:userId.value,
+        farmId: farmVal.value,
+        senderId: curUserId,
+        receiverId: userId.value,
         content,
         image,
-        messageType
-    }
+        messageType,
+    };
     VE_API.bbs.sendMsg(params);
-}
+};
 
-const userId = ref(null)
-
-watch(()=>props.userId, async (newValue) =>{
-    if(newValue){
-        await getFarmList();
-        userId.value = newValue
-        createSession(newValue,()=>{
-            if(props.text){
-                sendMsg('text',props.text)
-                messages.value.push({
-                    sender: "sent",
-                    senderIcon: senderIcon.value,
-                    messageType: "text",
-                    content:props.text,
-                })
-                if(props.img){
-                    const imgArr = JSON.parse(props.img)
-                    if(imgArr.length){
-                        imgArr.forEach(item =>{
-                            sendMsg('image', '', { url: item, thumbnailUrl: item + resize })
-                            messages.value.push({
-                                sender: "sent",
-                                senderIcon: senderIcon.value,
-                                messageType: "image",
-                                content:item,
-                            })
-                        })
+const userId = ref(null);
+
+watch(
+    () => props.userId,
+    async (newValue) => {
+        if (newValue) {
+            await getFarmList();
+            userId.value = newValue;
+            createSession(newValue, () => {
+                if (props.text) {
+                    sendMsg("text", props.text);
+                    messages.value.push({
+                        sender: "sent",
+                        senderIcon: senderIcon.value,
+                        messageType: "text",
+                        content: props.text,
+                    });
+                    if (props.img) {
+                        const imgArr = JSON.parse(props.img);
+                        if (imgArr.length) {
+                            imgArr.forEach((item) => {
+                                sendMsg("image", "", { url: item, thumbnailUrl: item + resize });
+                                messages.value.push({
+                                    sender: "sent",
+                                    senderIcon: senderIcon.value,
+                                    messageType: "image",
+                                    content: item,
+                                });
+                            });
+                        }
                     }
                 }
-            }
-        })
-        initMqtt()
+            });
+            initMqtt();
+        }
     }
-})
+);
 
-onDeactivated(()=>{
+onDeactivated(() => {
     // mqttClient.value.client.end(true);
-})
+});
 
 // mqtt 连接
-const mqttClient = ref(null)
+const mqttClient = ref(null);
 const messagesContainer = ref(null);
 
 // 消息数据
@@ -349,30 +376,29 @@ const previewImage = ref(null);
 const initMqtt = () => {
     const topics = [`user/chat/message/${farmVal.value}/${curUserId}`]; // 订阅的主题数组
     mqttClient.value = new MqttClient(topics, (topic, message) => {
-        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"){
+        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") {
                     if (obj.image && (obj.image.url || obj.image.originUrl)) {
-                        obj.content = obj.image.url || obj.image.originUrl
+                        obj.content = obj.image.url || obj.image.originUrl;
                     } else if (obj.content) {
                         try {
-                            const img = JSON.parse(obj.content)
-                            obj.content = img.url || img.originUrl
+                            const img = JSON.parse(obj.content);
+                            obj.content = img.url || img.originUrl;
                         } catch (e) {
-                            console.error(e,'e')
+                            console.error(e, "e");
                         }
                     }
                 }
-                obj.receiverId = curUserId
-                obj.sender = obj.senderId === curUserId ?'sent':'received',
-                obj.senderIcon = senderIcon.value
-                obj.receiverIcon = receiverIcon.value
-                messages.value.push(obj)
-                
+                obj.receiverId = curUserId;
+                (obj.sender = obj.senderId === curUserId ? "sent" : "received"), (obj.senderIcon = senderIcon.value);
+                obj.receiverIcon = receiverIcon.value;
+                messages.value.push(obj);
+
                 scrollToBottom();
             }
         }
@@ -383,14 +409,14 @@ const initMqtt = () => {
 
 // 发送消息
 const sendMessage = (message) => {
-    if(message.messageType === 'text'){
-        sendMsg('text',message.content)
-    }else if(message.messageType === 'image'){
+    if (message.messageType === "text") {
+        sendMsg("text", message.content);
+    } else if (message.messageType === "image") {
         // 按新协议:不传 content,传 image 对象
-        sendMsg('image', '', { url: message.content, thumbnailUrl: message.content + resize })
-    }else if(message.messageType === 'dialog'){
+        sendMsg("image", "", { url: message.content, thumbnailUrl: message.content + resize });
+    } else if (message.messageType === "dialog") {
         // 对话样式消息不发送到服务器,只显示在本地
-        console.log('发送对话样式消息:', message.content);
+        console.log("发送对话样式消息:", message.content);
     }
     messages.value.push(message);
     scrollToBottom();
@@ -447,10 +473,10 @@ const handleImageUpload = (event) => {
     const file = event.target.files[0];
     if (file) {
         // 实际项目中应该上传到服务器,这里使用本地URL模拟
-        const miniUserId = localStorage.getItem('MINI_USER_ID')
+        const miniUserId = localStorage.getItem("MINI_USER_ID");
         let ext = getFileExt(file.name);
         let key = `birdseye-look-mini/${miniUserId}/${new Date().getTime()}.${ext}`;
-        let imageUrl = ''
+        let imageUrl = "";
         uploadFileObj.put(key, file).then((resFilename) => {
             imageUrl = base_img_url2 + resFilename;
             sendImageMessage(imageUrl);
@@ -534,19 +560,19 @@ const addEmoji = (emoji) => {
 // 功能按钮配置
 const functionButtons = ref([
     {
-        text: '农场报告',
+        text: "农场报告",
         handler: () => {
-            console.log('点击农场报告,农场ID:', farmVal.value);
+            console.log("点击农场报告,农场ID:", farmVal.value);
             // 发送农场报告对话框消息
             sendFarmReportDialog();
-        }
+        },
     },
     {
-        text: '农事卡片',
+        text: "农事卡片",
         handler: () => {
             // 跳转到农事卡片页面
             router.push(`/farm_card?farmId=${farmVal.value}`);
-        }
+        },
     },
     // {
     //     text: '农场相册',
@@ -567,47 +593,47 @@ const getCurrentTime = () => {
 
 const scrollToBottom = () => {
     nextTick(() => {
-        setTimeout(()=>{
+        setTimeout(() => {
             if (messagesContainer.value) {
-                messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
+                messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
             }
-        },300)
+        }, 300);
     });
 };
 
-const farmVal = ref('')
-const options = ref([])
+const farmVal = ref("");
+const options = ref([]);
 
 // 获取农场列表
 function getFarmList() {
-    return VE_API.farm.userFarmSelectOption().then(({data}) => {
-        options.value = data || []
+    return VE_API.farm.userFarmSelectOption().then(({ data }) => {
+        options.value = data || [];
         if (data && data.length > 0) {
-            const defaultOption = data.find(item => item.defaultOption === true)
-            farmVal.value = defaultOption ? defaultOption.id : data[0].id
+            const defaultOption = data.find((item) => item.defaultOption === true);
+            farmVal.value = defaultOption ? defaultOption.id : data[0].id;
         }
-    })
+    });
 }
 
-onActivated(()=>{
-    if(props.userId){
-       scrollToBottom();
+onActivated(() => {
+    if (props.userId) {
+        scrollToBottom();
     }
     // 检查是否有选中的农事工作数据
     checkSelectedFarmWork();
-})
+});
 
 // 检查选中的农事工作数据
 const checkSelectedFarmWork = () => {
-    const selectedFarmWork = localStorage.getItem('selectedFarmWork');
+    const selectedFarmWork = localStorage.getItem("selectedFarmWork");
     if (selectedFarmWork) {
         const data = JSON.parse(selectedFarmWork);
         // 发送对话样式的消息
         sendDialogMessage(data.dialogMessage);
         // 清除localStorage中的数据
-        localStorage.removeItem('selectedFarmWork');
+        localStorage.removeItem("selectedFarmWork");
     }
-}
+};
 
 // 发送对话样式的消息
 const sendDialogMessage = (dialogData) => {
@@ -619,25 +645,25 @@ const sendDialogMessage = (dialogData) => {
         time: getCurrentTime(),
     };
     sendMessage(message);
-}
+};
 
 // 发送农场报告对话框
 const sendFarmReportDialog = () => {
-    const currentFarmName = options.value.find(opt => opt.id === farmVal.value)?.name || '当前农场';
-    
+    const currentFarmName = options.value.find((opt) => opt.id === farmVal.value)?.name || "当前农场";
+
     const farmReportData = {
-        type: 'farm_report',
+        type: "farm_report",
         title: currentFarmName,
-        content: '这是我的果园情况,请查看~',
+        content: "这是我的果园情况,请查看~",
         reportDetails: {
             farmId: farmVal.value,
             farmName: currentFarmName,
-            reportDate: new Date().toLocaleDateString('zh-CN'),
-            reportType: '综合报告',
-            status: '正常'
-        }
+            reportDate: new Date().toLocaleDateString("zh-CN"),
+            reportType: "综合报告",
+            status: "正常",
+        },
     };
-    
+
     const message = {
         sender: "sent",
         messageType: "dialog",
@@ -647,7 +673,7 @@ const sendFarmReportDialog = () => {
         time: getCurrentTime(),
     };
     sendMessage(message);
-}
+};
 </script>
 
 <style scoped lang="scss">
@@ -897,7 +923,6 @@ const sendFarmReportDialog = () => {
     }
 }
 
-
 /* 图片预览 */
 .image-preview {
     position: fixed;
@@ -924,58 +949,60 @@ const sendFarmReportDialog = () => {
     background: #fff !important;
     padding: 10px;
     border-radius: 10px;
-    .report-title{
+    .report-title {
         font-size: 16px;
         font-weight: 600;
         color: #000;
         margin-bottom: 5px;
     }
-    
+
     .dialog-title {
         font-size: 12px;
         color: rgba(0, 0, 0, 0.6);
         margin-bottom: 10px;
     }
-     .monitor-image{
-         width: 222px;
-         height: 180px;
+    .monitor-image {
+        width: 222px;
+        height: 180px;
         object-fit: cover;
-     }
-     
-     .farm-report-content, .farm-work-content {
-         .report-details, .work-details {
-             background: #f8f9fa;
-             border-radius: 8px;
-             padding: 12px;
-             margin-top: 10px;
-             
-             .detail-item {
-                 display: flex;
-                 margin-bottom: 6px;
-                 font-size: 13px;
-                 
-                 &:last-child {
-                     margin-bottom: 0;
-                 }
-                 
-                 .detail-label {
-                     color: #666;
-                     min-width: 80px;
-                 }
-                 
-                 .detail-value {
-                     color: #333;
-                     flex: 1;
-                 }
-             }
-         }
-     }
+    }
+
+    .farm-report-content,
+    .farm-work-content {
+        .report-details,
+        .work-details {
+            background: #f8f9fa;
+            border-radius: 8px;
+            padding: 12px;
+            margin-top: 10px;
+
+            .detail-item {
+                display: flex;
+                margin-bottom: 6px;
+                font-size: 13px;
+
+                &:last-child {
+                    margin-bottom: 0;
+                }
+
+                .detail-label {
+                    color: #666;
+                    min-width: 80px;
+                }
+
+                .detail-value {
+                    color: #333;
+                    flex: 1;
+                }
+            }
+        }
+    }
 }
 
 /* 我方消息中的对话样式 */
 .message.sent .dialog-message {
     background: #e3f2fd;
-    
+
     .work-details {
         background: #f0f8ff;
     }

+ 44 - 12
src/components/pageComponents/FarmInfoCard.vue

@@ -32,22 +32,31 @@
         <!-- 底部提示框:需求信息和预计收益 -->
         <template v-if="showBottomTip">
             <slot name="bottomTip">
-                <div class="item-footer" v-if="data.day">
-                    距离农事执行已
-                    <span class="service-count">{{ data.day }}</span>
-                    天,提醒用户拍照,增加信誉度!
+                <div class="item-footer remind-footer" v-if="data.day">
+                    <div>
+                        距离农事执行已
+                        <span class="service-count">{{ data.day }}</span>
+                        天,提醒用户拍照!
+                    </div>
+                    <span class="remind-text" @click.stop="handleRemind">提醒他</span>
                 </div>
                 <div class="item-footer item-bottom-tip" v-if="data.estimatedIncome">
-                    <div>当前农场有 <span>{{ data.farmInfo }}</span> 的农情需求</div>
-                    <div class="income-text">预计收益 <span>{{ data.estimatedIncome }}元</span></div>
+                    <div>
+                        当前农场有 <span>{{ data.farmInfo }}</span> 的农情需求
+                    </div>
+                    <div class="income-text">
+                        预计收益 <span>{{ data.estimatedIncome }}元</span>
+                    </div>
                 </div>
             </slot>
         </template>
+        <share-sheet class="share-sheet" teleport="#app" v-model:show="showShare" title="立即分享给好友" :options="options" @select="onSelect" />
     </div>
 </template>
 
 <script setup>
-import { computed, useSlots } from "vue";
+import { computed, useSlots, ref } from "vue";
+import { ShareSheet } from "vant";
 
 const props = defineProps({
     data: {
@@ -66,7 +75,6 @@ const props = defineProps({
 
 const emit = defineEmits(["click"]);
 const slots = useSlots();
-
 const showFooter = computed(() => {
     return props.data.serviceCount !== undefined || !!slots.footer;
 });
@@ -82,6 +90,19 @@ const showBottomTip = computed(() => {
 const handleClick = () => {
     emit("click", props.data);
 };
+
+const showShare = ref(false);
+const options = [
+    { name: "飞鸟用户", icon: "https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png" },
+    { name: "微信", icon: "wechat" },
+];
+const onSelect = (option) => {
+    showShare.value = false;
+    console.log(option);
+};
+const handleRemind = () => {
+    showShare.value = true;
+};
 </script>
 
 <style lang="scss" scoped>
@@ -164,6 +185,9 @@ const handleClick = () => {
         margin-top: 10px;
         color: #2e2e2e;
         font-size: 12px;
+        &.remind-footer {
+            justify-content: space-between;
+        }
         span {
             color: #2199f8;
             font-weight: 500;
@@ -174,6 +198,9 @@ const handleClick = () => {
         .view-detail {
             margin-left: 10px;
         }
+        .remind-text {
+            font-weight: 400;
+        }
     }
 
     .item-right-btn {
@@ -190,12 +217,12 @@ const handleClick = () => {
         align-items: center;
         justify-content: space-between;
         background: linear-gradient(90deg, rgba(254, 164, 94, 0.2) 0%, transparent 100%);
-        span{
-            color: #EB7B20;
+        span {
+            color: #eb7b20;
             font-weight: 500;
         }
-        .income-text{
-            color: #EFB789;
+        .income-text {
+            color: #efb789;
         }
     }
 }
@@ -204,3 +231,8 @@ const handleClick = () => {
     margin-top: 12px;
 }
 </style>
+<style>
+.share-sheet{
+    bottom: 50px;
+}
+</style>

+ 63 - 49
src/components/recordItem.vue

@@ -4,13 +4,13 @@
             <!-- 内置标题模板 -->
             <div v-if="titleMode === 'default'" class="box-title">
                 <div class="title-l">
-                    {{ recordItemData.title || recordItemData.farmWorkDetail?.name || '' }}
-                    <span v-if="getParentTitle()" class="parent-text">
-                        {{ getParentTitle() }}
-                    </span>
+                    {{ recordItemData.farmWorkName }}
+                    <span class="parent-text"> {{ getFarmTypeText(recordItemData.type || recordItemData.farmWorkType) }} </span>
                 </div>
                 <!-- 按钮样式 -->
-                <div v-if="titleRightText && titleRightType !== 'dot'" class="title-r title-r-button">{{ titleRightText }}</div>
+                <div v-if="titleRightText && titleRightType !== 'dot'" class="title-r title-r-button">
+                    {{ titleRightText }}
+                </div>
                 <!-- 点样式 -->
                 <div v-if="titleRightDotText && titleRightType === 'dot'" class="title-r title-r-dot">
                     <span class="r-dot"></span>
@@ -29,7 +29,7 @@
                 <div class="review-title info-line">
                     复核成效
                     <div class="info-val">
-                        {{ recordItemData.reCheckText || '通过精准农业技术的应用,作物产量实现了两位数的增长,病虫害的发生率大幅下降,土壤肥力的提升' }}
+                        {{ recordItemData.reCheckText || '暂无复核成效' }}
                     </div>
                 </div>
                 <div class="review-image" v-if="recordItemData.beforeImage || recordItemData.afterImage">
@@ -50,31 +50,37 @@
         <div class="record-content" v-else>
             <div class="info-item">
                 推荐时间:
-                <span class="info-val">{{ recordItemData?.executeDate }}</span>
+                <span class="info-val">{{ recordItemData?.executeDate || '--' }}</span>
             </div>
-            <div class="info-item recipe-name" v-if="onlyRecipeName && recordItemData?.prescriptionList && recordItemData?.prescriptionList.length">
+            <div
+                class="info-item recipe-name"
+                v-if="onlyRecipeName && recordItemData?.prescriptionList && recordItemData?.prescriptionList.length"
+            >
                 <span class="name-text">药物处方:</span>
                 <div class="rescription info-val">
-                        <span
-                            v-for="(
-                                fertilizer, fertilizerI
-                            ) in recordItemData.prescriptionList"
-                            :key="fertilizerI"
-                        >
-                            <span v-for="(pest, pestI) in fertilizer.pesticideFertilizerList" :key="'sub' + pestI">
-                                {{ pest.defaultName }}
-                                <span
-                                    v-if="
-                                        (pestI !== fertilizer.pesticideFertilizerList.length - 1) || (fertilizerI !== recordItemData.prescriptionList.length - 1)
-                                    "
-                                >
-                                    +
-                                </span>
+                    <span v-for="(fertilizer, fertilizerI) in recordItemData.prescriptionList" :key="fertilizerI">
+                        <span v-for="(pest, pestI) in fertilizer.pesticideFertilizerList" :key="'sub' + pestI">
+                            {{ pest.defaultName }}
+                            <span
+                                v-if="
+                                    pestI !== fertilizer.pesticideFertilizerList.length - 1 ||
+                                    fertilizerI !== recordItemData.prescriptionList.length - 1
+                                "
+                            >
+                                +
                             </span>
                         </span>
-                    </div>
+                    </span>
+                </div>
             </div>
-            <div class="info-item" v-if="!onlyRecipeName && recordItemData?.farmWorkDetail?.prescription && recordItemData?.farmWorkDetail?.prescription">
+            <div
+                class="info-item"
+                v-if="
+                    !onlyRecipeName &&
+                    recordItemData?.farmWorkDetail?.prescription &&
+                    recordItemData?.farmWorkDetail?.prescription
+                "
+            >
                 药物处方
                 <div class="info-table">
                     <div class="table">
@@ -93,7 +99,12 @@
                             </div>
                         </div> -->
                         <div>
-                            <div class="tr" v-for="(subP, subI) in recordItemData.farmWorkDetail.prescription.pesticideFertilizerList" :key="subI">
+                            <div
+                                class="tr"
+                                v-for="(subP, subI) in recordItemData.farmWorkDetail.prescription
+                                    .pesticideFertilizerList"
+                                :key="subI"
+                            >
                                 <div class="td">{{ subP.typeName }}</div>
                                 <div class="td width">{{ subP.name }}</div>
                                 <div class="td">{{ subP.ratio }}</div>
@@ -111,11 +122,11 @@
             </div>
             <div class="info-item">
                 触发条件:
-                <span class="info-val">{{ recordItemData?.farmWorkDetail?.condition }}</span>
+                <span class="info-val">{{ recordItemData?.farmWorkDetail?.condition || '暂无触发条件' }}</span>
             </div>
             <div class="info-item one-text">
                 农事编号:
-                <span class="info-val">{{ recordItemData?.farmWorkDetail?.code }}</span>
+                <span class="info-val">{{ recordItemData?.farmWorkDetail?.code ||recordItemData.farmWorkCode }}</span>
             </div>
             <div class="info-item" v-if="recordItemData?.attention">
                 巡园提醒:
@@ -142,46 +153,49 @@ const props = defineProps({
     },
     contentMode: {
         type: String,
-        default: '',
-        validator: (value) => ['', 'serviceDetail'].includes(value),
+        default: "",
+        validator: (value) => ["", "serviceDetail"].includes(value),
     },
     titleMode: {
         type: String,
-        default: '',
-        validator: (value) => ['', 'default'].includes(value),
+        default: "",
+        validator: (value) => ["", "default"].includes(value),
     },
     titleRightText: {
         type: String,
-        default: '',
+        default: "",
     },
     titleRightType: {
         type: String,
-        default: 'button',
-        validator: (value) => ['button', 'dot'].includes(value),
+        default: "button",
+        validator: (value) => ["button", "dot"].includes(value),
     },
     titleRightDotText: {
         type: String,
-        default: '',
+        default: "",
     },
 });
 
 const getPrescriptionInfo = (section) => {
-    // 从section的prescriptionList中获取药物信息
-    if (section.prescriptionList && section.prescriptionList.length > 0) {
-        const firstPrescription = section.prescriptionList[0];
-        if (firstPrescription.pesticideFertilizerList && firstPrescription.pesticideFertilizerList.length > 0) {
-            const firstDrug = firstPrescription.pesticideFertilizerList[0];
-            const ratio = firstDrug.ratio || firstDrug.defaultRatio || 1000;
-            return `${ratio}倍${firstDrug.brand}${firstDrug.pesticideFertilizerName}`;
+    // 将 prescriptionList 中所有 pesticideFertilizerName 用 + 连接
+    if (section && Array.isArray(section.prescriptionList)) {
+        const names = section.prescriptionList
+            .flatMap((item) => Array.isArray(item?.pesticideFertilizerList) ? item.pesticideFertilizerList : [])
+            .map((sub) => sub?.pesticideFertilizerName)
+            .filter((name) => typeof name === "string" && name.trim().length > 0);
+        if (names.length > 0) {
+            return names.join("+");
         }
     }
-    return "1000倍国光乙烯利"; // 默认值
+    return "";
 };
 
-const getParentTitle = () => {
-    return props.recordItemData?.parentTitle || 
-           props.recordItemData?.farmWorkDetail?.parentTitle || 
-           '';
+const getFarmTypeText = (type) => {
+    const value = typeof type === "string" ? type.trim() : type;
+    if (value === 0 || value === "0") return "预警农事";
+    if (value === 1 || value === "1") return "标准农事";
+    if (value === 2 || value === "2") return "建议农事";
+    return "";
 };
 </script>
 
@@ -266,7 +280,7 @@ const getParentTitle = () => {
             .name-text {
                 flex: none;
             }
-            
+
             .rescription {
                 max-width: 100%;
                 white-space: nowrap;

+ 14 - 2
src/router/globalRoutes.js

@@ -135,7 +135,7 @@ export default [
     {
         path: "/user",
         name: "User",
-        meta: { showTabbar: true, keepAlive: true },
+        meta: { showTabbar: true },
         component: () => import("@/views/old_mini/user/index.vue"),
     },
     // 用户管理详情
@@ -160,7 +160,7 @@ export default [
     },
     // 农场报告
     {
-        path: "/farm-report",
+        path: "/farm_report",
         name: "ReportDetail",
         component: () => import("@/views/old_mini/report_detail/index.vue"),
     },
@@ -314,4 +314,16 @@ export default [
         name: "EditPlan",
         component: () => import("@/views/old_mini/plan/editPlan.vue"),
     },
+    // 农场列表
+    {
+        path: "/farm_list",
+        name: "FarmList",
+        component: () => import("@/views/old_mini/user/subPages/farmList.vue"),
+    },
+    // 农事服务列表
+    {
+        path: "/service_list",
+        name: "ServiceList",
+        component: () => import("@/views/old_mini/user/subPages/serviceList.vue"),
+    },
 ];

+ 1 - 1
src/views/old_mini/agri_services/components/farmDynamics.vue

@@ -14,7 +14,7 @@
                             <div class="box-title">
                                 <div class="title-l">
                                     {{ section.farmWorkName }}
-                                    <span class="parent-text">{{ section.parentTitle || "秋梢期" }}</span>
+                                    <span class="parent-text">{{ section.parentTitle || "标准农事" }}</span>
                                 </div>
                                 <div class="title-r">
                                     <span class="r-dot"></span>

+ 5 - 1
src/views/old_mini/home/components/farmInfoPopup.vue

@@ -25,7 +25,7 @@
                     <checkbox class="checkbox" icon-size="16px" shape="square" v-model="farmInfo.defaultOption">是否勾选为默认农场</checkbox>
                 </cell-group>
             </div>
-            <div class="popup-footer">
+            <div class="popup-footer" v-if="!showBtn">
                 <div class="footer-btn no-btn" @click="handleCancel">取消</div>
                 <div class="footer-btn yes-btn" @click="handleEdit">去编辑</div>
             </div>
@@ -45,6 +45,10 @@ const props = defineProps({
         type: [Number, String],
         default: null,
     },
+    showBtn: {
+        type: Boolean,
+        default: false,
+    },
 });
 
 const store = useStore();

+ 22 - 5
src/views/old_mini/home/components/problemReminder.vue

@@ -12,7 +12,7 @@
             <div class="question-section-wrapper">
                 <span class="question-text">{{ questPopupData.quest }}</span>
                 <div class="img">
-                    <img :src="questPopupData.image" alt="" />
+                    <img :src="questPopupData.backgroundImage" alt="" />
                 </div>
                 <div class="options-section">
                     <span class="options-label">您可以选择</span>
@@ -45,12 +45,16 @@
     </Popup>
     <!-- 农事信息弹窗 -->
     <detail-dialog ref="detailDialogRef"></detail-dialog>
+    <!-- 新增:激活上传弹窗 -->
+    <active-upload-popup></active-upload-popup>
 </template>
 <script setup>
 import { Popup } from "vant";
 import { ref, onActivated } from "vue";
 import wx from "weixin-js-sdk";
+import activeUploadPopup from "@/components/popup/activeUploadPopup.vue";
 import detailDialog from "@/components/detailDialog.vue";
+import eventBus from "@/api/eventBus";
 import { useRouter } from "vue-router";
 const router = useRouter();
 
@@ -145,8 +149,17 @@ function onBottomOptionClick(opt) {
         })
         .then((res) => {
             if (res.code === 0) {
-                show.value = false;
-                noShow.value = true;
+                if (opt.value == 1) {
+                    show.value = false;
+                    // 打开同级的激活上传弹窗
+                    eventBus.emit("activeUpload:show", {
+                        gardenIdVal: 766,
+                        problemTitleVal: '请选择您出现白点的时间',
+                    });
+                } else {
+                    show.value = false;
+                    noShow.value = true;
+                }
             }
         });
 }
@@ -208,8 +221,12 @@ function getTodayStr() {
                 margin: 12px 0;
                 width: 100%;
                 height: 140px;
-                border-radius: 6px;
-                background-color: green;
+                img{
+                    width: 100%;
+                    height: 100%;
+                    border-radius: 6px;
+                    object-fit: cover;
+                }
             }
             .options-section {
                 display: flex;

+ 84 - 113
src/views/old_mini/user/farmDetails.vue

@@ -4,29 +4,33 @@
         <div class="farm-details-content">
             <farm-info-card
                 :data="{
-                    farmName: '从化荔博园',
-                    area: '200亩',
-                    variety: '桂味',
-                    address: '广东省广州市从化区从化区',
+                    farmName: farmDetail.name,
+                    area: farmDetail.mianji + '亩',
+                    variety: farmDetail.typeName,
+                    address: farmDetail.address,
                     mapImage: '/map.png',
                 }"
             >
                 <template #right>
-                    <div>基本信息</div>
+                    <div @click="handleFarmInfo">基本信息</div>
                 </template>
             </farm-info-card>
             <tabs v-model:active="activeTab" class="custom-tabs" scrollspy sticky offset-top="40" background="#f5f7fb">
                 <tab title="农情互动" class="tab-item">
                     <common-box title="农情互动">
                         <template #right>
-                            <span>查看详情</span>
+                            <span @click="handleDetail('farm_list')">查看详情</span>
                         </template>
                         <div class="question-header">
                             <img class="question-icon" src="@/assets/img/home/ask-icon.png" alt="" />
-                            <div class="question-title">在白点期,您当前农场是否出现白点?</div>
+                            <div class="question-title">{{ farmWorkData.quest }}</div>
                         </div>
                         <template v-if="isImg">
-                            <div class="answer-content">答:2025.05.18 已经出现白点</div>
+                            <div class="answer-content">
+                                答:{{ farmWorkData.agriDate }} {{ farmWorkData.answerLabel }}出现{{
+                                    farmWorkData.indicatorName
+                                }}
+                            </div>
                             <div class="answer-img">
                                 <img src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" alt="" />
                                 <img src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" alt="" />
@@ -45,7 +49,7 @@
                 <tab title="农事服务" class="tab-item">
                     <common-box title="农事服务">
                         <template #right>
-                            <span>查看详情</span>
+                            <span @click="handleDetail('service_list')">查看详情</span>
                         </template>
                         <tab-list
                             type="light"
@@ -54,14 +58,15 @@
                             @change="handleFarmServiceTabChange"
                         />
                         <stats-box :stats-data="serviceStatsData" />
-                        <div v-for="(section, index) in contentData" :key="index" class="content-section">
+                        <div v-for="(section, index) in detailList" :key="index" class="content-section">
                             <record-item
                                 :record-item-data="section"
                                 onlyRecipeName
                                 :content-mode="farmServiceActiveTab === 0 ? 'serviceDetail' : ''"
                                 title-mode="default"
-                                title-right-type="dot"
-                                title-right-dot-text="2区"
+                                :title-right-text="farmServiceActiveTab === 0 ? '分享成果' : ''"
+                                :title-right-type="farmServiceActiveTab === 1 ? 'dot' : null"
+                                :title-right-dot-text="farmServiceActiveTab === 1 ? '2区' : ''"
                                 class="recipe-item"
                             />
                         </div>
@@ -70,7 +75,7 @@
                 <tab title="农场报告" class="tab-item">
                     <common-box title="农场报告">
                         <template #right>
-                            <span>查看详情</span>
+                            <span @click="handleDetail('farm_report')">查看详情</span>
                         </template>
                         <span class="report-content"
                             >果园面积共XX亩,共有XX棵生产树。果园面积共XX亩,共有XX棵生产树。果园面积共XX亩,共有XX棵生产树。果园面积共XX亩,共有XX棵生产树。果园面积共XX亩,共有XX棵生产树。果园面积共XX亩,共有XX棵生产树。</span
@@ -80,9 +85,9 @@
                 <tab title="农事方案" class="tab-item plan-tab-item">
                     <common-box title="农事方案">
                         <template #right>
-                            <span>查看更多</span>
+                            <span @click="handleDetail('agricultural_plan')">查看更多</span>
                         </template>
-                        <record-item :record-item-data="contentData[0]" title-mode="default" class="recipe-item" />
+                        <record-item :record-item-data="detailList[0]" title-mode="default" class="recipe-item" />
                         <!-- <plan-list :farm-id="93301" :container-id="route.query.containerId || 2" class="plan-list-wrapper" /> -->
                     </common-box>
                 </tab>
@@ -93,11 +98,13 @@
             <div class="bottom-btn primary-btn">在线沟通</div>
         </div>
     </div>
+    <!-- 农场信息 -->
+    <farm-info-popup ref="farmInfoRef" :farmId="farmIdVal" :showBtn="true"></farm-info-popup>
 </template>
 
 <script setup>
-import { ref } from "vue";
-import { useRoute } from "vue-router";
+import { ref, onMounted } from "vue";
+import { useRoute, useRouter } from "vue-router";
 import { Tab, Tabs } from "vant";
 import customHeader from "@/components/customHeader.vue";
 import FarmInfoCard from "@/components/pageComponents/FarmInfoCard.vue";
@@ -106,13 +113,19 @@ import commonBox from "@/components/pageComponents/CommonBox.vue";
 import StatsBox from "@/components/pageComponents/StatsBox.vue";
 import recordItem from "@/components/recordItem.vue";
 import PlanList from "@/components/pageComponents/PlanList.vue";
+import farmInfoPopup from "../home/components/farmInfoPopup.vue";
 
+const router = useRouter();
 const route = useRoute();
 const activeTab = ref(0);
-
 const farmServiceTabs = ["过往服务", "未来服务"];
 const farmServiceActiveTab = ref(0);
 
+const farmInfoRef = ref(null);
+const handleFarmInfo = () => {
+    farmInfoRef.value.handleShow();
+};
+
 const handleFarmServiceTabChange = (index) => {
     console.log("切换到标签页:", index, farmServiceTabs[index]);
     if (index === 0) {
@@ -121,7 +134,9 @@ const handleFarmServiceTabChange = (index) => {
             { value: "1258", unit: "元", desc: "投入成本" },
             { value: "118", unit: "次", desc: "服务次数" },
         ];
+        getDetailList();
     } else {
+        getFutureFarmWorkList();
         serviceStatsData.value = [
             { value: "1258", unit: "元", desc: "预计收益" },
             { value: "1258", unit: "元", desc: "预计成本" },
@@ -135,102 +150,58 @@ const serviceStatsData = ref([
     { value: "118", unit: "次", desc: "服务次数" },
 ]);
 
-const contentData = ref([
-    {
-        targetId: "part1",
-        title: "巡园农事",
-        parentTitle: "秋梢期",
-        isExpanded: false, // 添加展开状态
-        hasApplied: false, // 是否已发起需求
-        reCheckText: "通过精准农业技术的应用,作物产量实现了两位数的增长,病虫害的发生率大幅下降,土壤肥力的提升",
-        beforeImage: "https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png",
-        afterImage: "https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png",
-        expert: 91356,
-        orderStatus: 3,
-        activeStatus: 0,
-        regionId: 2,
-        speciesId: "1",
-        speciesName: "荔枝",
-        farmWorkId: "699343457474318336",
-        farmWorkLibId: "699343457474318336",
-        farmWorkLibName: "梢期防虫",
-        farmWorkName: "梢期防虫",
-        expertIcon:
-            "https://birdseye-img.sysuimars.com/birdseye-look-vue/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250411150343.png",
-        expertName: "韦帮稳",
-        icon: 4,
-        beforeExecuteDate: "2025-08-01",
-        executeDate: "2025-08-15",
-        code: "BZ-BC-04-SQFC-20",
-        expertPrescription: "",
-        condition: "单树嫩叶率大于20.0%",
-        defaultFarmWork: 0,
-        farmWorkType: 3,
-        farmWorkTypeName: "病虫",
-        usageMode: "叶面施",
-        serviceMain: "广州泽秾丰农资有限公司",
-        updateDate6: null,
-        confirmPicture: [],
-        executeMain: "广州泽秾丰农资有限公司",
-        storeShortName: "泽秾丰",
-        serviceRegion: "广州市从化区荔枝博览园",
-        prescriptionList: [
-            {
-                name: "营养",
-                pesticideFertilizerList: [
-                    {
-                        defaultDroneRatio: null,
-                        defaultName: "尿素",
-                        defaultRatio: 0,
-                        id: null,
-                        muPrice: null,
-                        muUsage: 15000.0,
-                        muUsage2: 15000.0,
-                        ratio: 0,
-                        ratio2: 0,
-                        remark: "",
-                        usageMode: "",
-                        usageModeList: ["叶面施、根部施"],
-                        orderId: null,
-                        pesticideFertilizerCode: "1001",
-                        pesticideFertilizerId: "1",
-                        pesticideFertilizerName: "尿素",
-                        brand: "山东联盟",
-                        typeName: "营养",
-                        price: 132,
-                        unit: "g",
-                        executeStyle: null,
-                    },
-                    {
-                        defaultDroneRatio: null,
-                        defaultName: "15-15-15复合肥",
-                        defaultRatio: 0,
-                        id: null,
-                        muPrice: null,
-                        muUsage: 45000.0,
-                        muUsage2: 45000.0,
-                        ratio: 0,
-                        ratio2: 0,
-                        remark: "",
-                        usageMode: "",
-                        usageModeList: ["根部施"],
-                        orderId: null,
-                        pesticideFertilizerCode: "1002",
-                        pesticideFertilizerId: "2",
-                        pesticideFertilizerName: "15-15-15复合肥",
-                        brand: "金正大",
-                        typeName: "营养",
-                        price: 220,
-                        unit: "g",
-                        executeStyle: null,
-                    },
-                ],
-            },
-        ],
-    },
-]);
-
 const isImg = ref(true);
+
+onMounted(() => {
+    farmIdVal.value = route.query.farmId;
+    paramsPage.value = {
+        farmId: farmIdVal.value,
+        limit: 1,
+        page: 1,
+    }
+    getFarmDetail();
+    getFarmWorkList();
+    getDetailList();
+});
+const farmIdVal = ref(null);
+const farmDetail = ref({});
+const paramsPage = ref({});
+const getFarmDetail = () => {
+    VE_API.user.getFarmDetail({ farmId: farmIdVal.value }).then(({ data }) => {
+        farmDetail.value = data || {};
+    });
+};
+
+const farmWorkData = ref({});
+const getFarmWorkList = () => {
+    VE_API.user.getFarmWorkList(paramsPage.value).then(({ data }) => {
+        if (data && data.length > 0) {
+            farmWorkData.value = data[0] || {};
+        }
+    });
+};
+
+const detailList = ref([]);
+const getDetailList = () => {
+    const params = {
+        farmId: 766,
+        flowStatus: 0,
+        limit: 1,
+        page: 1,
+    };
+    VE_API.user.getDetailList(params).then(({ data }) => {
+        detailList.value = data || [];
+    });
+};
+const getFutureFarmWorkList = () => {
+    VE_API.user.getFutureFarmWorkList(paramsPage.value).then(({ data }) => {
+        detailList.value = data || [];
+    });
+};
+
+const handleDetail = (path) => {
+    router.push(`/${path}?farmId=${farmIdVal.value}`);
+};
 </script>
 
 <style scoped lang="scss">

+ 49 - 52
src/views/old_mini/user/index.vue

@@ -13,30 +13,30 @@
         </div>
         <div class="list">
             <collapse v-model="activeNames">
-                <collapse-item :name="index" v-for="(item, index) in list" :key="index" :is-link="false">
+                <collapse-item :name="index" v-for="(item, index) in dataList" :key="index" :is-link="false">
                     <template #title>
                         <el-icon class="icon"><CaretRight /></el-icon>
                         {{ item.name }}
-                        <span class="span">{{ item.children.length }}</span>
+                        <span class="span">{{ item.children?.length || 0 }}</span>
                     </template>
                     <template #value>
                         <div @click.stop="hadnleManage(item)" class="text">管理</div>
                     </template>
                     <farm-info-card
-                        v-for="(ele, idx) in item.children"
-                        :key="idx + ele.id"
+                        v-for="ele in item.children"
+                        :key="ele.agriculturalStoreId"
                         class="list-item"
                         :data="{
-                            farmName: ele.farmName || '农场111',
-                            area: ele.area || '190亩',
-                            variety: ele.variety || `荔枝-${ele.name}`,
-                            address: ele.address || '湖北省武汉市富里唱鑫园5023',
+                            farmName: ele.farmName,
+                            area: ele.mianji + '亩',
+                            variety: ele.typeName,
+                            address: ele.address,
                             mapImage: ele.mapImage || '/map.png',
                             // day: 15,
-                            farmInfo: '梢期杀虫',
-                            estimatedIncome: ele.estimatedIncome || 2585
+                            // farmInfo: '梢期杀虫',
+                            // estimatedIncome: ele.estimatedIncome || 2585
                         }"
-                        @click="handleItemClick"
+                        @click="handleItemClick(ele)"
                     >
                         <template #right>
                             <div>在线沟通</div>
@@ -55,12 +55,49 @@
 
 <script setup>
 import { Collapse, CollapseItem } from "vant";
-import { ref } from "vue";
+import { ref, onMounted } from "vue";
 import { useRouter } from "vue-router";
 import addPopup from "./components/addPopup.vue";
 import FarmInfoCard from "@/components/pageComponents/FarmInfoCard.vue";
 const router = useRouter();
 
+onMounted(() => {
+    getUserList();
+});
+
+const activeNames = ref([0]);
+const dataList = ref([
+    {
+        name: "Vip客户",
+        isGroup: 0,
+        children:[]  
+    },
+    {
+        name: "农场客户",
+        isGroup: 1,
+        children:[]  
+    }
+]);
+const getUserList = async () => {
+    const { data } = await VE_API.user.userList();
+    if(data.length){
+        // 清空现有的子项
+        dataList.value[0].children = [];
+        dataList.value[1].children = [];
+        
+        // 根据 isVip 字段分类
+        data.forEach(item => {
+            if(item.isVip === 1) {
+                // Vip客户
+                dataList.value[0].children.push(item);
+            } else {
+                // 农场客户
+                dataList.value[1].children.push(item);
+            }
+        });
+    }
+};
+
 const input = ref("");
 //新建分组
 const showGroupPopup = ref(false);
@@ -82,46 +119,6 @@ const hadnleManage = (value) => {
 const handleItemClick = (data) => {
     router.push(`/farm_details?farmId=${data.farmId}`);
 };
-
-const list = ref([
-    {
-        name: "常用列表",
-        id: "1",
-        isGroup: 0,
-        children: [
-            {
-                id: "3",
-                name: "糯米糍",
-            },
-            {
-                id: "4",
-                name: "桂味",
-            },
-        ],
-    },
-    {
-        name: "未分组标签好友",
-        id: "2",
-        isGroup: 1,
-        children: [
-            {
-                id: "5",
-                name: "井冈红糯",
-            },
-            {
-                id: "6",
-                name: "测试",
-            },
-        ],
-    },
-    {
-        name: "其他列表",
-        id: "3",
-        children: [],
-    },
-]);
-
-const activeNames = ref([0]);
 </script>
 
 <style lang="scss" scoped>

+ 123 - 0
src/views/old_mini/user/subPages/farmList.vue

@@ -0,0 +1,123 @@
+<template>
+    <div class="farm-page">
+        <custom-header name="农情互动"></custom-header>
+        <div class="farm-list">
+            <div class="list-item" v-for="item in farmList" :key="item.id">
+                <div class="question-header">
+                    <img class="question-icon" src="@/assets/img/home/ask-icon.png" alt="" />
+                    <div class="question-title">{{ item.quest }}</div>
+                </div>
+                <template v-if="true">
+                    <div class="answer-content">
+                        答:{{ item.agriDate }} {{ item.answerLabel }}出现{{ item.indicatorName }}
+                    </div>
+                    <div class="answer-img" >
+                        <img src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" alt="" />
+                        <img src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" alt="" />
+                        <img src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" alt="" />
+                    </div>
+                </template>
+                <div v-else class="answer-btn">
+                    <div class="answer-btn-item">转发给客户</div>
+                    <div class="answer-btn-item-group">
+                        <div class="answer-btn-item">否</div>
+                        <div class="answer-btn-item primary">是</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import customHeader from "@/components/customHeader.vue";
+import { useRoute } from "vue-router";
+
+const route = useRoute();
+onMounted(() => {
+    getFarmWorkList();
+});
+
+const farmList = ref([]);
+const paramsPage = ref(1);
+const getFarmWorkList = () => {
+    const params = {
+        farmId: route.query.farmId,
+        limit: 99,
+        page: paramsPage.value,
+    }
+    VE_API.user.getFarmWorkList(params).then(({ data }) => {
+        farmList.value = data || [];
+    });
+};
+</script>
+
+<style scoped lang="scss">
+.farm-page {
+    width: 100%;
+    height: 100vh;
+    background-color: #f7f7f7;
+    .farm-list {
+        width: 100%;
+        height: 100%;
+        box-sizing: border-box;
+        padding: 12px;
+        overflow: auto;
+        .list-item {
+            background-color: #fff;
+            border-radius: 8px;
+            padding: 10px;
+            box-sizing: border-box;
+            .question-header {
+                display: flex;
+                align-items: center;
+                margin-bottom: 6px;
+                gap: 8px;
+                font-weight: 500;
+                .question-icon {
+                    width: 22px;
+                    height: 20px;
+                }
+            }
+            .answer-content {
+                color: #333333;
+                margin: 6px 0 10px 0;
+            }
+            .answer-img {
+                display: flex;
+                gap: 5px;
+                img {
+                    flex: 1;
+                    height: 105px;
+                    border-radius: 5px;
+                }
+            }
+            .answer-btn {
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                margin-top: 10px;
+                > div {
+                    display: flex;
+                    gap: 10px;
+                }
+            }
+            .answer-btn-item {
+                padding: 7px 12px;
+                border-radius: 25px;
+                font-size: 12px;
+                text-align: center;
+                background: rgba(33, 153, 248, 0.1);
+                color: #2199f8;
+                min-width: 52px;
+                box-sizing: border-box;
+                &.primary {
+                    background: #2199f8;
+                    color: #ffffff;
+                }
+            }
+        }
+    }
+}
+</style>

+ 113 - 0
src/views/old_mini/user/subPages/serviceList.vue

@@ -0,0 +1,113 @@
+<template>
+    <div class="service-list-page">
+        <custom-header name="农事服务"></custom-header>
+        <div class="service-content">
+            <tab-list
+                type="light"
+                v-model="farmServiceActiveTab"
+                :tabs="farmServiceTabs"
+                @change="handleFarmServiceTabChange"
+            />
+            <stats-box :stats-data="serviceStatsData" />
+            <div class="content-section">
+                <record-item
+                    v-for="(section, index) in detailList"
+                    :key="index"
+                    :record-item-data="section"
+                    onlyRecipeName
+                    :content-mode="farmServiceActiveTab === 0 ? 'serviceDetail' : ''"
+                    title-mode="default"
+                    :title-right-text="farmServiceActiveTab === 0 ? '分享成果' : ''"
+                    :title-right-type="farmServiceActiveTab === 1 ? 'dot' : null"
+                    :title-right-dot-text="farmServiceActiveTab === 1 ? '2区' : ''"
+                    class="recipe-item"
+                />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import customHeader from "@/components/customHeader.vue";
+import tabList from "@/components/pageComponents/TabList.vue";
+import StatsBox from "@/components/pageComponents/StatsBox.vue";
+import recordItem from "@/components/recordItem.vue";
+import { useRoute } from "vue-router";
+import { ref, onMounted } from "vue";
+
+const route = useRoute();
+const farmIdVal = ref(null);
+onMounted(() => {
+    farmIdVal.value = route.query.farmId;
+    getDetailList();
+});
+
+const farmServiceTabs = ["过往服务", "未来服务"];
+const farmServiceActiveTab = ref(0);
+const serviceStatsData = ref([
+    { value: "1258", unit: "元", desc: "总收益" },
+    { value: "1258", unit: "元", desc: "投入成本" },
+    { value: "118", unit: "次", desc: "服务次数" },
+]);
+
+const handleFarmServiceTabChange = (index) => {
+    if (index === 0) {
+        serviceStatsData.value = [
+            { value: "1258", unit: "元", desc: "总收益" },
+            { value: "1258", unit: "元", desc: "投入成本" },
+            { value: "118", unit: "次", desc: "服务次数" },
+        ];
+        getDetailList();
+    } else {
+        getFutureFarmWorkList();
+        serviceStatsData.value = [
+            { value: "1258", unit: "元", desc: "预计收益" },
+            { value: "1258", unit: "元", desc: "预计成本" },
+        ];
+    }
+};
+const paramsPage = ref(1);
+const paramsLimit = ref(99);
+const detailList = ref([]);
+const getDetailList = () => {
+    const params = {
+        farmId: 766,
+        flowStatus: 0,
+        limit: paramsLimit.value,
+        page: paramsPage.value,
+    };
+    VE_API.user.getDetailList(params).then(({ data }) => {
+        detailList.value = data || [];
+    });
+};
+const getFutureFarmWorkList = () => {
+    const params = {
+        farmId: farmIdVal.value,
+        limit: paramsLimit.value,
+        page: paramsPage.value,
+    };
+    VE_API.user.getFutureFarmWorkList(params).then(({ data }) => {
+        detailList.value = data || [];
+    });
+};
+</script>
+
+<style scoped lang="scss">
+.service-list-page {
+    width: 100%;
+    height: 100vh;
+    background-color: #f7f7f7;
+    .service-content {
+        box-sizing: border-box;
+        padding: 12px;
+        .content-section {
+            overflow: auto;
+            height: calc(100vh - 95px - 70px);
+            .recipe-item {
+                border: 1px solid rgba(0, 0, 0, 0.1);
+                margin: 12px 0 0 0;
+            }
+        }
+    }
+}
+</style>