Ver código fonte

feat:添加诊断报告弹窗,删除无用的文件

wangsisi 6 dias atrás
pai
commit
80adc600f5

BIN
src/assets/img/agricultural/notice.png


BIN
src/assets/img/agricultural/report.png


BIN
src/assets/img/common/yw-en.png


BIN
src/assets/img/common/yw.png


BIN
src/assets/img/home/book.png


BIN
src/assets/img/home/report_bg.png


BIN
src/assets/img/home/vs.png


BIN
src/assets/img/monitor/image.png


+ 0 - 1166
src/components/chatWindow.vue

@@ -1,1166 +0,0 @@
-<template>
-    <div class="chat-container">
-        <!-- 聊天消息区域 -->
-        <div class="chat-messages" ref="messagesContainer">
-            <div v-for="(msg, index) in messages" :key="index" class="message" :class="msg.sender">
-                <!-- 对方消息 -->
-                <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/dinggou-mini/defalut-icon.png'
-                        "
-                    />
-                    <img src="" alt="" />
-                    <div class="bubble" :class="{ 'no-bubble': msg.messageType === 'image' ,'card-bubble': msg.messageType === 'card'}">
-                        <!-- 文本消息 -->
-                        <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="图片"
-                            />
-                        </div>
-
-                        <!-- 语音消息 -->
-                        <div v-if="msg.messageType === 'audio'" class="audio-message" @click="playAudio(msg.content)">
-                            <span class="audio-icon">🎵</span>
-                            <span class="duration">{{ msg.duration }}"</span>
-                        </div>
-
-                        <!-- 对话样式消息 -->
-                        <div v-if="msg.messageType === 'report'" class="dialog-message" @click="handleReportClick(msg)">
-                            <template v-if="(msg.reportType || msg.content.reportType) === 'farm_report'">
-                                <div class="report-title">{{ msg.title ||msg.content.title }}</div>
-                                <div class="dialog-title">这是{{curRole == 2 ? '该农场' : '我'}}的果园情况,请查看~</div>
-                                <img src="https://birdseye-img.sysuimars.com/birdseye-look-mini/share-report-bg.png" alt="" class="monitor-image" />
-                            </template>
-                            <template v-else>
-                                <div class="dialog-title">{{ msg.title || msg.content.title}}</div>
-                                <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image" />
-                            </template>
-                        </div>
-
-                         <!-- 对话样式消息 -->
-                        <div v-if="msg.messageType === 'card'" class="card-message" @click="handleCardClick(msg)">
-                            <template v-if="(msg.cardType || msg.content.cardType) === 'quotation'">
-                                <div class="card-title">{{ $t('向您发送了一张 服务报价单') }}</div>
-                                <img src="https://birdseye-img.sysuimars.com/temp/price.png" alt="" />
-                            </template>
-                            <template v-else>
-                                <div class="card-title">{{ msg.title || msg.content.title }}</div>
-                                <img :src="handleImgUrl(msg.coverUrl || msg.content.coverUrl)" alt="" />
-                            </template>
-                        </div>
-
-                        <!-- <div class="time">{{ msg.time }}</div> -->
-                    </div>
-                </template>
-
-                <!-- 我方消息 -->
-                <template v-else>
-                    <div class="bubble" :class="{ 'no-bubble': msg.messageType === 'image','card-bubble': msg.messageType === 'card' || msg.messageType === 'report' }">
-                        <!-- 文本消息 -->
-                        <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="图片"
-                            />
-                        </div>
-
-                        <!-- 语音消息 -->
-                        <div v-if="msg.messageType === 'audio'" class="audio-message" @click="playAudio(msg.content)">
-                            <span class="audio-icon">🎵</span>
-                            <span class="duration">{{ msg.duration }}"</span>
-                        </div>
-
-                        <!-- 对话样式消息 -->
-                        <div v-if="msg.messageType === 'report'" class="dialog-message" @click="handleReportClick(msg)">
-                            <template v-if="(msg.reportType || msg.content.reportType) === 'farm_report'">
-                                <div class="report-title">{{ msg.title ||msg.content.title }}</div>
-                                <div class="dialog-title">这是{{curRole == 2 ? '该农场' : '我'}}果园情况,请查看~</div>
-                                <img src="https://birdseye-img.sysuimars.com/birdseye-look-mini/share-report-bg.png" alt="" class="monitor-image" />
-                            </template>
-                            <template v-else>
-                                <div class="dialog-title">{{ msg.title || msg.content.title}}</div>
-                                <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image" />
-                            </template>
-                        </div>
-
-                        <!-- 对话样式消息 -->
-                        <div v-if="msg.messageType === 'card'" class="card-message" @click="handleCardClick(msg)">
-                            <template v-if="(msg.cardType || msg.content.cardType) === 'quotation'">
-                                <div class="card-title">{{ $t('向您发送了一张 服务报价单') }}</div>
-                                <img src="https://birdseye-img.sysuimars.com/temp/price.png" alt="" />
-                            </template>
-                            <template v-else>
-                                <div class="card-title">{{ msg.title || msg.content.title }}</div>
-                                <img :src="handleImgUrl(msg.coverUrl || msg.content.coverUrl)" alt="" />
-                            </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/dinggou-mini/defalut-icon.png'
-                        "
-                    />
-                </template>
-            </div>
-        </div>
-
-        <!-- 功能按钮区域 -->
-        <div class="function-buttons">
-            <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"
-                />
-            </el-select>
-            <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">
-                <!-- <button @click="toggleEmojiPicker">😊</button> -->
-                <!-- <button @click="startImageUpload">📷</button> -->
-                <!-- <button
-                    @mousedown="startRecording"
-                    @mouseup="stopRecording"
-                    @touchstart="startRecording"
-                    @touchend="stopRecording"
-                >
-                    🎤
-                </button> -->
-                <el-icon class="link" @click="startImageUpload"><Link /></el-icon>
-                <input type="file" ref="fileInput" accept="image/*" style="display: none" @change="handleImageUpload" />
-            </div>
-
-            <input type="text" v-model="inputMessage" :placeholder="$t('请输入你想说的话~')" @keyup.enter="sendTextMessage" />
-            <div class="send" @click="sendTextMessage">{{ $t('发送') }}</div>
-
-            <!-- 录音指示器 -->
-            <div v-if="isRecording" class="recording-indicator">
-                <div class="pulse"></div>
-                录音中... {{ recordingDuration }}s
-            </div>
-        </div>
-
-        <!-- Emoji 选择器 -->
-        <div v-if="showEmojiPicker" class="emoji-picker">
-            <span v-for="emoji in emojis" :key="emoji" @click="addEmoji(emoji)">{{ emoji }}</span>
-        </div>
-
-        <!-- 图片预览模态框 -->
-        <div v-if="previewImage" class="image-preview" @click="previewImage = null">
-            <img :src="previewImage" alt="预览" />
-        </div>
-    </div>
-</template>
-
-<script setup>
-import { ref, onUnmounted, nextTick, watch, onActivated, onDeactivated } from "vue";
-import { useRouter ,useRoute} from "vue-router";
-import { base_img_url2 } from "@/api/config";
-import { getFileExt } from "@/utils/util";
-import UploadFile from "@/utils/upliadFile";
-import MqttClient from "@/plugins/MqttClient";
-import customHeader from "@/components/customHeader.vue";
-
-const resize = "?x-oss-process=image/resize,p_120/format,webp/quality,q_100";
-const router = useRouter();
-
-const props = defineProps({
-    text: {
-        type: String,
-        defalut: "",
-    },
-    img: {
-        type: String,
-        defalut: "",
-    },
-    userId: {
-        type: [String, Number],
-        defalut: "",
-    },
-});
-
-const emit = defineEmits(['update:name']);
-
-const defalutMsg = ref([
-    {
-        sender: "sent",
-        senderIcon: "王",
-        messageType: "text",
-        content:
-            "你好,我叫陈晓晓。有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 localUserInfoIcon = (() => {
-    try {
-        const info = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
-        return info?.icon || "";
-    } catch (e) {
-        return "";
-    }
-})();
-
-// 初始化本地头像为默认发送者头像
-senderIcon.value = localUserInfoIcon;
-const nameVal = ref('');
-
-// 监听 nameVal 变化,传递给父组件
-watch(nameVal, (newVal) => {
-    emit('update:name', newVal);
-});
-
-//聊天会话
-const createSession = (targetUserId, callback) => {
-    nameVal.value = '';
-    VE_API.bbs.createSession({ farmId: farmVal.value, targetUserId }).then(({ data, code }) => {
-        if (code === 0) {
-            nameVal.value = data.session.targetUserName;
-            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;
-                    } else if (item.content) {
-                        try {
-                            const imgObj = JSON.parse(item.content);
-                            content = imgObj.url || imgObj.originUrl;
-                        } catch (e) {
-                            console.error(e, "e");
-                        }
-                    }
-                }else if(item.messageType !== 'text'){
-                    content = JSON.parse(item.content);
-                }
-                return {
-                    ...item,
-                    content,
-                    sender: item.senderId === curUserId ? "sent" : "received",
-                    senderIcon: item.senderId === curUserId ? localUserInfoIcon : data.session.targetUserAvatar,
-                    receiverIcon: data.session.targetUserAvatar,
-                };
-            });
-
-            setTimeout(() => {
-                scrollToBottom();
-            }, 300);
-            callback && callback();
-        }
-    });
-};
-
-const handleFarmChange = (e) => {
-    sessionStorage.setItem('selectedFarmId', e);
-    createSession(userId.value);
-    initMqtt();
-};
-
-//发送消息接口
-//类型 text ,file,image
-const sendMsg = (messageType = "text", content = "", obj = {}) => {
-    const params = {
-        farmId: farmVal.value,
-        senderId: curUserId,
-        receiverId: userId.value,
-        content,
-        [messageType]:obj,
-        messageType,
-    };
-    VE_API.bbs.sendMsg(params);
-};
-
-const userId = ref(null);
-
-const handleCardClick = (msg) => {
-    router.push(msg.linkUrl || msg.content.linkUrl);
-}
-
-const handleImgUrl = (url) => {
-    if (url && url.includes('https://')) {
-        return url;
-    } else {
-        return base_img_url2 + url + resize;
-    }
-}
-
-watch(
-    () => props.userId,
-    async (newValue) => {
-        if (newValue) {
-            await getFarmList();
-            userId.value = newValue;
-            createSession(newValue, () => {
-                if(route.query.pageParams) {
-                    const params = JSON.parse(route.query.pageParams);
-                    const message = {
-                        sender: "sent",
-                        messageType: "card",
-                        senderIcon: senderIcon.value,
-                        title: params.farmWorkName + ' 农事已完成,请您确认',
-                        cardType:'farm_work',
-                        linkUrl:`/completed_work?miniJson=${JSON.stringify({id:params.id})}`,
-                        time: getCurrentTime(),
-                    };
-                    if(params.executeEvidence && params.executeEvidence.length > 5) {
-                        const imgArr = JSON.parse(params.executeEvidence);
-                        message.coverUrl = imgArr[imgArr.length - 1];
-                    }
-
-                    if(params.imageList && params.imageList.length) {
-                        const img = params.imageList[params.imageList.length - 1];
-                        if (img.cloudFilename) {
-                            message.coverUrl = img.cloudFilename;
-                        } else {
-                            message.coverUrl = img;
-                        }
-                    }
-                    
-                    if(params.type === 'quotation') {
-                        message.cardType = 'quotation';
-                        message.title = '向您发送了一张服务报价单'
-                        const jsonParams = {
-                            id:params.id,
-                            farmWorkOrderId:params.farmWorkOrderId,
-                            isAssign: true
-                        }
-                        message.linkUrl = `/completed_work?miniJson=${JSON.stringify(jsonParams)}`;
-                    }
-
-                    if(params.type === 'reviewWork') {
-                        message.cardType = 'reviewWork';
-                        message.title = '向您分享了农事执行成果'
-                        message.linkUrl = `/review_work?miniJson=${JSON.stringify({id: params.id,goBack: true})}`;
-                    }
-
-                    if(params.type === 'remindExecute' || params.type === 'remindUser') {
-                        const jsonParams = {
-                            id:params.id,
-                            farmWorkOrderId:params.farmWorkOrderId
-                        }
-                        if(params.type === 'remindExecute') {
-                            message.title = '请您尽快执行 ' + params.farmWorkName + ' 农事';
-                            message.linkUrl = `/completed_work?miniJson=${JSON.stringify(jsonParams)}`;
-                        } else if(params.type === 'remindUser') {
-                            message.title = '请您尽快完成复核';
-                            message.linkUrl = `/review_work?miniJson=${JSON.stringify({id:params.id,goBack: true})}`;
-                        }
-                        message.cardType = params.type
-                    }
-
-                    sendMessage(message);
-                    
-                    // 清除路由中的 pageParams 参数
-                    const newQuery = { ...route.query };
-                    delete newQuery.pageParams;
-                    router.replace({
-                        path: route.path,
-                        query: newQuery
-                    });
-                }
-                if (route.query.selectedImgs) {
-                    const imgArr = JSON.parse(route.query.selectedImgs);
-                    if (imgArr && imgArr.length) {
-                        imgArr.forEach((item) => {
-                            sendImageMessage(item);
-                        });
-                        // 图片发送完成后,清除路由中的 selectedImgs 参数
-                        const newQuery = { ...route.query };
-                        delete newQuery.selectedImgs;
-                        router.replace({
-                            path: route.path,
-                            query: newQuery
-                        });
-                    }
-                }
-            });
-            initMqtt();
-        }
-    }
-);
-
-onDeactivated(() => {
-    if(clearSession.value){
-        sessionStorage.removeItem('selectedFarmId');
-    }
-    mqttClient.value && mqttClient.value.client.end(true);
-});
-
-// mqtt 连接
-const mqttClient = ref(null);
-const messagesContainer = ref(null);
-
-// 消息数据
-const messages = ref([]);
-
-// 输入相关
-const inputMessage = ref("");
-const fileInput = ref(null);
-const showEmojiPicker = ref(false);
-const emojis = ["😀", "😂", "😍", "👍", "👋", "🎉", "❤️", "🙏"];
-
-// 录音相关
-const isRecording = ref(false);
-const recordingDuration = ref(0);
-const audioChunks = ref([]);
-const mediaRecorder = ref(null);
-const audioContext = ref(null);
-
-function handleImageLoad() {
-    scrollToBottom();
-}
-
-// 图片预览
-const previewImage = ref(null);
-
-// 初始化 mqtt
-const initMqtt = () => {
-    const topics = [`user/chat/message/${farmVal.value}/${curUserId}`]; // 订阅的主题数组
-    mqttClient.value = new MqttClient(topics, (topic, message) => {
-        if (message && message.length > 10) {
-            const obj = JSON.parse(message);
-            console.log("message有值", obj);
-            if(obj.senderId === curUserId){
-                return;
-            }
-            if (obj.senderId === receiverIdVal.value) {
-                // 检查是否已存在相同 id 的消息,避免重复添加
-                if (obj.id && messages.value.some(msg => msg.id === obj.id)) {
-                    return;
-                }
-                if (obj.messageType === "image") {
-                    if (obj.image && (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;
-                        } catch (e) {
-                            console.error(e, "e");
-                        }
-                    }
-                }else if(obj.messageType !== 'text'){
-                    obj.content = JSON.parse(obj.content);
-                }
-                obj.receiverId = curUserId;
-                (obj.sender = obj.senderId === curUserId ? "sent" : "received"), (obj.senderIcon = senderIcon.value);
-                obj.receiverIcon = receiverIcon.value;
-                messages.value.push(obj);
-
-                scrollToBottom();
-            }
-        }
-    });
-
-    mqttClient.value.connect();
-};
-
-// 发送消息
-const sendMessage = (message) => {
-    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 === "report") {
-        // 对话样式消息不发送到服务器,只显示在本地
-        console.log("发送对话样式消息:", message);
-        if(message.reportType === 'farm_report'){
-            sendMsg('report','',{
-                title: message.title,
-                reportId: message.reportId,
-                reportType: message.reportType,
-            });
-        }else{
-            sendMsg('report','',{
-                title: message.title,
-                reportId: message.reportId,
-                reportType: message.reportType,
-            });
-            console.log('其他文件1');
-        }
-    }else{
-        sendMsg('card','',{
-            title: message.title,
-            coverUrl: message.coverUrl,
-            cardType: message.cardType,
-            linkUrl: message.linkUrl
-        });
-    }
-    messages.value.push(message);
-    scrollToBottom();
-};
-
-// 发送文本消息
-const sendTextMessage = () => {
-    if (inputMessage.value.trim()) {
-        const message = {
-            sender: "sent",
-            messageType: "text",
-            senderIcon: senderIcon.value,
-            content: inputMessage.value,
-            time: getCurrentTime(),
-        };
-        sendMessage(message);
-        inputMessage.value = "";
-    }
-};
-
-// 发送图片消息
-const sendImageMessage = (thumbnailUrl) => {
-    const message = {
-        sender: "sent",
-        messageType: "image",
-        senderIcon: senderIcon.value,
-        content: thumbnailUrl,
-        time: getCurrentTime(),
-    };
-    sendMessage(message);
-};
-
-// 发送语音消息
-const sendAudioMessage = (audioUrl, duration) => {
-    const message = {
-        sender: "sent",
-        messageType: "audio",
-        senderIcon: senderIcon.value,
-        content: audioUrl,
-        duration: duration,
-        time: getCurrentTime(),
-    };
-    sendMessage(message);
-};
-
-// 图片处理
-const startImageUpload = () => {
-    fileInput.value.click();
-};
-
-const uploadFileObj = new UploadFile();
-
-const handleImageUpload = (event) => {
-    const file = event.target.files[0];
-    if (file) {
-        // 实际项目中应该上传到服务器,这里使用本地URL模拟
-        const miniUserId = localStorage.getItem("MINI_USER_ID");
-        let ext = getFileExt(file.name);
-        let key = `birdseye-look-mini/${miniUserId}/${new Date().getTime()}.${ext}`;
-        let imageUrl = "";
-        uploadFileObj.put(key, file).then((resFilename) => {
-            imageUrl = base_img_url2 + resFilename;
-            sendImageMessage(imageUrl);
-        });
-    }
-};
-
-const showImagePreview = (imageUrl) => {
-    previewImage.value = imageUrl;
-};
-
-// 语音处理
-const startRecording = async () => {
-    try {
-        audioChunks.value = [];
-        recordingDuration.value = 0;
-
-        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-        mediaRecorder.value = new MediaRecorder(stream);
-        audioContext.value = new (window.AudioContext || window.webkitAudioContext)();
-
-        mediaRecorder.value.ondataavailable = (event) => {
-            if (event.data.size > 0) {
-                audioChunks.value.push(event.data);
-            }
-        };
-
-        mediaRecorder.value.onstop = async () => {
-            const audioBlob = new Blob(audioChunks.value, { type: "audio/wav" });
-            const audioUrl = URL.createObjectURL(audioBlob);
-
-            // 计算录音时长
-            const duration = Math.round(recordingDuration.value);
-
-            // 实际项目中应该上传到服务器,这里使用本地URL模拟
-            sendAudioMessage(audioUrl, duration);
-
-            // 释放资源
-            stream.getTracks().forEach((track) => track.stop());
-        };
-
-        mediaRecorder.value.start();
-        isRecording.value = true;
-
-        // 更新录音计时器
-        const timer = setInterval(() => {
-            recordingDuration.value += 0.1;
-            if (!isRecording.value) {
-                clearInterval(timer);
-            }
-        }, 100);
-    } catch (error) {
-        console.error("录音失败:", error);
-        alert("无法访问麦克风,请检查权限设置");
-    }
-};
-
-const stopRecording = () => {
-    if (mediaRecorder.value && isRecording.value) {
-        mediaRecorder.value.stop();
-        isRecording.value = false;
-    }
-};
-
-const playAudio = (audioUrl) => {
-    const audio = new Audio(audioUrl);
-    audio.play();
-};
-
-// Emoji 处理
-const toggleEmojiPicker = () => {
-    showEmojiPicker.value = !showEmojiPicker.value;
-};
-
-const addEmoji = (emoji) => {
-    inputMessage.value += emoji;
-    showEmojiPicker.value = false;
-};
-
-// 功能按钮配置
-const functionButtons = ref([
-    {
-        text: "农场报告",
-        handler: () => {
-            // 发送农场报告对话框消息
-            sendFarmReportDialog();
-        },
-    },
-    // {
-    //     text: "农事卡片",
-    //     handler: () => {
-    //         clearSession.value = false
-    //         // 跳转到农事卡片页面
-    //         router.push(`/farm_card?farmId=${farmVal.value}`);
-    //     },
-    // },
-    {
-        text: '农场相册',
-        handler: () => {
-            clearSession.value = false
-            // 跳转到农场相册页面
-            router.push(`/farm_photo?farmId=${farmVal.value}&isCheck=true&userId=${props.userId}`);
-        }
-    }
-]);
-
-// 辅助函数
-const getCurrentTime = () => {
-    return new Date().toLocaleTimeString("zh-CN", {
-        hour: "2-digit",
-        minute: "2-digit",
-    });
-};
-
-const scrollToBottom = () => {
-    nextTick(() => {
-        setTimeout(() => {
-            if (messagesContainer.value) {
-                messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
-            }
-        }, 300);
-    });
-};
-
-const farmVal = ref("");
-const options = ref([]);
-const route = useRoute();
-
-// 获取农场列表
-function getFarmList() {
-    let params = {
-        agriculturalQuery: false,
-    }
-    if(curRole.value == 2){
-        params.userId = props.userId;
-    }
-    return VE_API.farm.userFarmSelectOption(params).then(({ data }) => {
-        options.value = data || [];
-        if (data && data.length > 0) {
-            const defaultOption = data.find((item) => item.defaultOption === true);
-            // 优先使用 sessionStorage 中保存的农场ID(用户刚刚切换的农场)
-            const savedFarmId = sessionStorage.getItem('selectedFarmId');
-            if (savedFarmId) {
-                // 检查保存的农场是否还在当前列表中
-                const savedFarm = data.find((item) => item.id == savedFarmId);
-                if (savedFarm) {
-                    farmVal.value = Number(savedFarmId);
-                } else {
-                    // 如果保存的农场不在列表中,使用路由参数或默认农场
-                    farmVal.value = route.query.farmId ? Number(route.query.farmId) : (defaultOption ? defaultOption.id : data[0].id);
-                }
-            } else if(route.query.farmId) {
-                // 如果没有保存的农场,使用路由参数
-                farmVal.value = Number(route.query.farmId);
-            } else {
-                // 都没有则使用默认农场
-                farmVal.value = defaultOption ? defaultOption.id : data[0].id;
-            }
-        }
-    });
-}
-
-const curRole = ref(null);
-onActivated(() => {
-    curRole.value = localStorage.getItem("SET_USER_CUR_ROLE");
-    if (props.userId) {
-        scrollToBottom();
-    }
-    // 检查是否有选中的农事工作数据
-    checkSelectedFarmWork();
-});
-
-// 检查选中的农事工作数据
-const checkSelectedFarmWork = () => {
-    const selectedFarmWork = sessionStorage.getItem("selectedFarmWork");
-    if (selectedFarmWork) {
-        const data = JSON.parse(selectedFarmWork);
-        const message = {
-            ...data,
-            coverUrl:''
-        };
-        // 发送对话样式的消息
-        sendMessage(data);
-        // 清除localStorage中的数据
-        sessionStorage.removeItem("selectedFarmWork");
-    }
-};
-
-// 发送对话样式的消息
-const sendDialogMessage = (dialogData) => {
-    const message = {
-        sender: "sent",
-        messageType: "report",
-        senderIcon: senderIcon.value,
-        content: dialogData,
-        time: getCurrentTime(),
-    };
-    sendMessage(message);
-};
-
-const clearSession = ref(true);
-// 点击农场报告对话框
-const handleReportClick = (msg) => {
-    console.log(msg);
-    if(msg.reportType === 'farm_report' || msg.messageType === 'report'){
-        clearSession.value = false;
-        const params = {
-            farmId: msg.reportId || msg.content?.reportId,
-            showFilter: true,
-        }
-        router.push(`/farm_report?miniJson=${JSON.stringify(params)}`);
-    }else{
-        console.log('其他文件');
-    }
-}
-
-// 发送农场报告对话框
-const sendFarmReportDialog = () => {
-    const currentFarmName = options.value.find((opt) => opt.id === farmVal.value)?.name || "当前农场";
-
-    const message = {
-        sender: "sent",
-        messageType: "report",
-        senderIcon: senderIcon.value,
-        title: currentFarmName,
-        reportId:farmVal.value,
-        reportType:'farm_report',
-        time: getCurrentTime(),
-    };
-    sendMessage(message);
-};
-</script>
-
-<style scoped lang="scss">
-/* 基础样式(保持之前的不变) */
-.chat-container {
-    display: flex;
-    flex-direction: column;
-    height: 100%;
-    width: 100%;
-    margin: 0 auto;
-    border: 1px solid #e6e6e6;
-    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
-    position: relative;
-    box-sizing: border-box;
-    .chat-messages {
-        flex: 1;
-        padding: 12px;
-        overflow-y: auto;
-        background-color: #f5f5f5;
-        box-sizing: border-box;
-        .message {
-            display: flex;
-            margin-bottom: 15px;
-        }
-        .received {
-            justify-content: flex-start;
-            .bubble {
-                background-color: white;
-                border-radius: 0 10px 10px 10px;
-                padding: 10px 12px;
-                box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
-            }
-        }
-        .sent {
-            justify-content: flex-end;
-            .bubble {
-                background-color: #07c160;
-                border-radius: 10px 0 10px 10px;
-                padding: 10px 15px;
-                color: #fff;
-                box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
-            }
-        }
-        .avatar {
-            width: 40px;
-            height: 40px;
-            border-radius: 50%;
-            background-color: #07c160;
-            color: white;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            margin-right: 10px;
-            font-weight: bold;
-        }
-
-        .avatar-r {
-            margin: 0 0 0 10px;
-        }
-        .bubble {
-            max-width: 70%;
-        }
-    }
-}
-
-.content {
-    font-size: 16px;
-    line-height: 1.4;
-}
-
-.time {
-    font-size: 12px;
-    color: #fff;
-    margin-top: 5px;
-    text-align: right;
-}
-
-.input-area {
-    display: flex;
-    align-items: center;
-    padding: 15px 10px;
-    border-top: 1px solid #e6e6e6;
-    background-color: white;
-    position: relative;
-    width: 100%;
-    box-sizing: border-box;
-    input {
-        flex: 1;
-        padding: 10px;
-        border: 1px solid #e6e6e6;
-        border-radius: 20px;
-        outline: none;
-    }
-    .send {
-        margin-left: 10px;
-        padding: 8px 20px;
-        background-color: #07c160;
-        color: white;
-        border: none;
-        border-radius: 20px;
-        cursor: pointer;
-    }
-}
-// .input-area button:hover {
-//     background-color: #06ad56;
-// }
-
-/* 新增的多媒体消息样式 */
-.image-message {
-    img {
-        max-width: 200px;
-        max-height: 200px;
-        border-radius: 8px;
-        cursor: pointer;
-    }
-}
-
-/* 图片消息不使用对话气泡样式 */
-.no-bubble {
-    background: transparent !important;
-    border-radius: 0 !important;
-    padding: 0 !important;
-    box-shadow: none !important;
-    color: inherit !important;
-}
-.card-bubble{
-    background: #fff !important;
-}
-
-.audio-message {
-    display: flex;
-    align-items: center;
-    padding: 10px 15px;
-    background-color: #f0f0f0;
-    border-radius: 20px;
-    cursor: pointer;
-}
-
-.audio-message .audio-icon {
-    margin-right: 8px;
-    font-size: 20px;
-}
-
-.audio-message .duration {
-    font-size: 14px;
-    color: #666;
-}
-
-.message.sent .audio-message {
-    background-color: #d8f1cb;
-}
-
-/* 工具栏样式 */
-.toolbar {
-    display: flex;
-    align-items: center;
-    button {
-        background: none;
-        border: none;
-        font-size: 20px;
-        margin-right: 10px;
-        cursor: pointer;
-        padding: 5px;
-    }
-    .link {
-        font-size: 24px;
-        margin-right: 10px;
-    }
-}
-
-/* 录音指示器 */
-.recording-indicator {
-    position: absolute;
-    top: -40px;
-    left: 0;
-    right: 0;
-    background-color: #ff4d4f;
-    color: white;
-    padding: 8px;
-    text-align: center;
-    border-radius: 4px;
-    font-size: 14px;
-}
-
-.recording-indicator .pulse {
-    display: inline-block;
-    width: 10px;
-    height: 10px;
-    border-radius: 50%;
-    background: white;
-    margin-right: 8px;
-    animation: pulse 1.5s infinite;
-}
-
-@keyframes pulse {
-    0% {
-        transform: scale(0.95);
-        opacity: 1;
-    }
-    50% {
-        transform: scale(1.1);
-        opacity: 0.7;
-    }
-    100% {
-        transform: scale(0.95);
-        opacity: 1;
-    }
-}
-
-/* Emoji 选择器 */
-.emoji-picker {
-    position: absolute;
-    bottom: 60px;
-    right: 10px;
-    background: white;
-    border: 1px solid #e6e6e6;
-    border-radius: 8px;
-    padding: 10px;
-    display: grid;
-    grid-template-columns: repeat(4, 1fr);
-    gap: 8px;
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-    z-index: 100;
-}
-
-.emoji-picker span {
-    font-size: 24px;
-    text-align: center;
-}
-
-.emoji-picker span:hover {
-    transform: scale(1.2);
-}
-
-/* 功能按钮样式 */
-.function-buttons {
-    display: flex;
-    gap: 5px;
-    padding: 5px 10px;
-    box-sizing: border-box;
-    .function-btn {
-        background-color: white;
-        border-radius: 8px;
-        padding: 10px 10px;
-        min-width: 60px;
-        text-align: center;
-        .btn-text {
-            font-size: 14px;
-        }
-    }
-}
-
-/* 图片预览 */
-.image-preview {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background: rgba(0, 0, 0, 0.8);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    z-index: 1000;
-}
-
-.image-preview img {
-    max-width: 90%;
-    max-height: 90%;
-    object-fit: contain;
-}
-
-/* 对话样式消息 */
-.dialog-message {
-    max-width: 100%;
-    background: #fff !important;
-    border-radius: 10px;
-    .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;
-        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;
-                }
-            }
-        }
-    }
-}
-
-.card-message{
-    .card-title{
-        font-size: 15px;
-        font-weight: 600;
-        color: #000;
-        margin-bottom: 5px;
-    }
-    img{
-        width: 222px;
-        height: 180px;
-        object-fit: cover;
-    }
-}
-
-/* 我方消息中的对话样式 */
-.message.sent .dialog-message {
-    background: #e3f2fd;
-
-    .work-details {
-        background: #f0f8ff;
-    }
-}
-</style>

+ 88 - 0
src/components/popup/diagnosisReportPopup.vue

@@ -0,0 +1,88 @@
+<template>
+    <popup
+        v-model:show="showValue"
+        round
+        teleport="body"
+        class="diagnosis-report-popup"
+        :close-on-click-overlay="true"
+    >
+        <img class="diagnosis-report-popup__image" src="@/assets/img/agricultural/report.png" alt="" />
+        <div class="diagnosis-report-popup__title">
+            <div>{{ t("agriFile.plantingDiagnosisReport") }}</div>
+            <div>{{ t("agriFile.reportGenerated") }}</div>
+        </div>
+        <div class="diagnosis-report-popup__btn" @click="handleView">{{ t("agriFile.clickToView") }}</div>
+        <div class="diagnosis-report-popup__hint">{{ t("agriFile.viewInDiagnosisHint") }}</div>
+    </popup>
+</template>
+
+<script setup>
+import { computed } from "vue";
+import { Popup } from "vant";
+import { useI18n } from "@/i18n";
+
+const { t } = useI18n();
+
+const props = defineProps({
+    show: {
+        type: Boolean,
+        default: false,
+    },
+});
+
+const emit = defineEmits(["update:show", "confirm"]);
+
+const showValue = computed({
+    get: () => props.show,
+    set: (val) => emit("update:show", val),
+});
+
+const handleView = () => {
+    emit("confirm");
+    showValue.value = false;
+};
+</script>
+
+<style scoped lang="scss">
+.diagnosis-report-popup {
+    width: 78%;
+    padding: 90px 20px 22px;
+    text-align: center;
+    overflow: visible;
+    background: linear-gradient(360deg, #FFFFFF 0%, #D3EBFF 100%);
+
+    &__image {
+        display: block;
+        width: 138px;
+        height: 138px;
+        margin: 0 auto 16px;
+        position: absolute;
+        top: -54px;
+        left: 50%;
+        transform: translateX(-50%);
+    }
+
+    &__title {
+        font-size: 30px;
+        color: #010101;
+        line-height: 32px;
+        div{
+            font-family: "pangmenzhengdao";
+        }
+    }
+
+    &__btn {
+        width: 162px;
+        margin: 18px auto 10px;
+        padding: 8px 0;
+        border-radius: 25px;
+        background: linear-gradient(180deg, #96D1FF 0%, #2199F8 100%);
+        color: #fff;
+        font-size: 16px;
+    }
+
+    &__hint {
+        color: #1D1919;
+    }
+}
+</style>

+ 8 - 2
src/i18n/messages.js

@@ -6,7 +6,6 @@ export default {
             situationAssessment: "农情研判",
             agriFile: "农事档案",
             agriRecord: "农事规划",
-            trace: "有味溯源",
             schedule: "农事列表",
         },
         common: {
@@ -174,6 +173,10 @@ export default {
             getImmediately: "马上获取",
             patrolDiagnosisService: "巡田诊断服务",
             goEnable: "去开启",
+            plantingDiagnosisReport: "种植诊断报告",
+            reportGenerated: "已生成",
+            clickToView: "点击查看",
+            viewInDiagnosisHint: "还可在 农事档案-诊断报告 中查看",
             agriAlbum: "农情相册",
             diagnosisReport: "诊断报告",
             reportUpdate: "更新",
@@ -397,7 +400,6 @@ export default {
             situationAssessment: "Situation Assessment",
             agriFile: "Crop Archives",
             agriRecord: "Farm Planning",
-            trace: "Traceability",
             schedule: "Schedule",
         },
         common: {
@@ -565,6 +567,10 @@ export default {
             getImmediately: "Get",
             patrolDiagnosisService: "field diagnosis now",
             goEnable: "Get started",
+            plantingDiagnosisReport: "Planting diagnosis report",
+            reportGenerated: "Generated",
+            clickToView: "View now",
+            viewInDiagnosisHint: "Also available in Crop Archives - Diagnosis report",
             agriAlbum: "Agri album",
             diagnosisReport: "Diagnosis report",
             reportUpdate: "Update",

+ 0 - 34
src/router/globalRoutes.js

@@ -33,20 +33,6 @@ export default [
         meta: { keepAlive: true },
         component: () => import("@/views/old_mini/create_farm/editMap.vue"),
     },
-    // 聊天
-    {
-        path: "/chat_frame",
-        name: "ChatFrame",
-        meta: { keepAlive: true },
-        component: () => import("@/views/old_mini/chat_frame/index.vue"),
-    },
-    // 成果报告
-    {
-        path: "/achievement_report",
-        name: "AchievementReport",
-        meta: { keepAlive: true },
-        component: () => import("@/views/old_mini/achievement_report/index.vue"),
-    },
     // 长势报告
     {
         path: "/growth_report",
@@ -54,12 +40,6 @@ export default [
         meta: { showTabbar: true, keepAlive: true },
         component: () => import("@/views/old_mini/growth_report/index.vue"),
     },
-    // 咨询专家
-    {
-        path: "/consult",
-        name: "Consult",
-        component: () => import("@/views/old_mini/chat_frame/consult.vue"),
-    },
     // 农事互动列表
     {
         path: "/interaction_list",
@@ -74,20 +54,6 @@ export default [
         meta: { keepAlive: true },
         component: () => import("@/views/old_mini/interactionList/drawRegion.vue"),
     },
-    //确认区域
-    {
-        path: "/confirm_area",
-        name: "ConfirmArea",
-        meta: { keepAlive: true },
-        component: () => import("@/views/old_mini/interactionList/confirmArea.vue"),
-    },
-    //有味溯源
-    {
-        path: "/youwei_trace",
-        name: "YouweiTrace",
-        component: () => import("@/views/old_mini/youwei_trace/index.vue"),
-        meta: { showTabbar: true, keepAlive: true },
-    },
     // 农事详情
     {
         path: "/work_detail",

+ 0 - 784
src/views/old_mini/achievement_report/index.vue

@@ -1,784 +0,0 @@
-<template>
-    <div class="achievement-report-page">
-        <custom-header :name="$t('生成成果报告')"></custom-header>
-        <div class="report-content-wrap" v-loading="loading">
-            <div class="report-content" ref="reportDom">
-                <img src="@/assets/img/home/qrcode.png" alt="" class="code-icon" />
-                <div class="report-header">
-                    <img class="header-book" src="@/assets/img/home/book.png" alt="" />
-                    <div class="time-tag">{{ workItem?.executeDate }}</div>
-                    <div class="report-title">{{ t('成果报告') }}</div>
-                    <div class="report-info">
-                        <div class="info-item">
-                            <img class="info-icon" :src="workItem?.executorIcon || 'https://birdseye-img.sysuimars.com/dinggou-mini/defalut-icon.png'" alt="" />
-                            <span class="info-text">执行组织:{{ workItem?.executeMain }}</span>
-                        </div>
-                        <div class="info-item">
-                            <img class="info-icon" src="@/assets/img/home/farm.png" alt="" />
-                            <span class="info-text">服务农场:{{ workItem?.farmName }}</span>
-                        </div>
-                    </div>
-                </div>
-
-                <div class="report-box">
-                    <div class="report-box-item">
-                        <div class="item-content">{{ workItem?.farmWorkName || "--" }}</div>
-                        <div class="item-title">{{ t('作业农事') }}</div>
-                    </div>
-                    <div class="report-box-item">
-                        <div class="item-content">{{ formatArea(workItem?.area) || "--" }}</div>
-                        <div class="item-title">{{ t('作业面积') }}</div>
-                    </div>
-                    <div class="report-box-item">
-                        <div class="item-content">{{ reportData?.workCycle ? (reportData?.workCycle + '天') : "--" }}</div>
-                        <div class="item-title">{{ t('作业周期') }}</div>
-                    </div>
-                    <div class="report-box-item">
-                        <div class="item-content">{{ reportData?.deviceName || "--" }}</div>
-                        <div class="item-title">{{ t('使用设备') }}</div>
-                    </div>
-                </div>
-
-                <!-- <div class="report-box">
-                    <div class="box-title">{{ t('精准施治,智慧护航') }}</div>
-                    <div class="box-text">
-                        {{ reportData?.resultInfo || "--" }}
-                    </div>
-                </div> -->
-
-                <div class="report-excute" v-for="(item, index) in workItem?.executeEvidence" :key="index">
-                    <div class="tag-label">{{ t('执行照片') }}</div>
-                    <album-draw-box :key="paramsPage.id" :isShowNum="0" :imgData="workItem" :photo="item" :current="index" :index="index" :length="workItem?.executeEvidence?.length"></album-draw-box>
-                </div>
-                <div class="report-excute" v-for="(item, index) in workItem?.reviewImage" :key="index">
-                    <div class="tag-label">{{ t('复核照片') }}</div>
-                    <album-draw-box :key="paramsPage.id+'复核'" :isShowNum="0" :isAchievementImgs="true" :imgData="workItem" :photo="item" :current="index" :index="index" :length="workItem?.reviewImage?.length"></album-draw-box>
-                </div>
-                <!-- <div class="report-excute" v-for="(item, index) in workItem?.reviewImage" :key="index">
-                    <div class="tag-label">{{ t('复核照片') }}</div>
-                    <album-draw-box :isShowNum="0" :photo="item" :current="index" :index="'review'+index" :length="workItem?.reviewImage?.length"></album-draw-box>
-                </div> -->
-                <!-- <div class="report-excute">
-                    <album-carousel
-                        :key="93"
-                        :isAchievementImgs="true"
-                        :images="combinedReviewImages"
-                    ></album-carousel>
-                </div> -->
-            </div>
-
-            <div class="bottom-btn">
-                <div class="btn-item second" @click="handleDownload">{{ t('保存图片') }}</div>
-                <div class="btn-item primay" @click="handleDownload">{{ t('转发') }}</div>
-            </div>
-        </div>
-
-        <!-- 组合照片(用于生成合成图片) -->
-        <div class="review-hide-box">
-            <div class="review-image" ref="reviewComboRef">
-                <div class="review-mask">
-                    <div class="review-text">{{ t('复核成效') }}</div>
-                    <div class="review-content">
-                        {{ workItem?.reCheckText }}
-                    </div>
-                </div>
-                <div class="vs-wrap" v-if="workItem?.reviewImage && workItem?.reviewImage?.length">
-                    <img src="@/assets/img/home/vs.png" alt="" />
-                </div>
-                <div class="review-image-item" v-if="workItem?.executeEvidence?.length">
-                    <div class="review-image-item-title">{{ t('复核照片') }}</div>
-                    <img
-                        class="review-image-item-img left-img"
-                        :src="leftCoverImg"
-                        style="width: 100%; height: 255px; display: block; image-rendering: auto"
-                    />
-                </div>
-                <div class="review-image-item" v-if="workItem?.reviewImage?.length">
-                    <img
-                        class="review-image-item-img right-img"
-                        :src="rightCoverImg"
-                        style="width: 100%; height: 255px; display: block; image-rendering: auto"
-                    />
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <popup class="cavans-popup" v-model:show="showPopup">
-        <div class="cavans-content">
-            <img class="current-img" :src="pageImg" alt="" />
-        </div>
-        <!-- 底部操作按钮 -->
-        <div class="bottom-actions" @click.stop="showPopup = false">
-            <div class="action-buttons">
-                
-                <div class="action-btn text-btn">
-                    &lt;&lt;长按图片保存或转发&gt;&gt;
-                </div>
-            </div>
-            <div class="cancel-btn" @click="handleCancel">{{ t('取消') }}</div>
-        </div>
-    </popup>
-</template>
-
-<script setup>
-import { useI18n } from "@/i18n";
-const { t } = useI18n();
-import CustomHeader from "@/components/customHeader.vue";
-import AlbumCarousel from "@/components/album_compoents/albumCarousel";
-import { ref, onActivated, onDeactivated, onUnmounted, nextTick, watch } from "vue";
-import html2canvas from "html2canvas";
-import { uploadBase64 } from "@/common/uploadImg";
-import { detectRuntimeEnvironment } from "@/common/commonFun";
-import { useRoute } from "vue-router";
-import { Popup } from "vant";
-import { base_img_url2 } from "@/api/config";
-import wx from "weixin-js-sdk";
-import AlbumDrawBox from "@/components/album_compoents/albumDrawBox.vue";
-
-const route = useRoute();
-const loading = ref(false);
-const workItem = ref({});
-const showPopup = ref(false);
-function formatArea(val) {
-    const num = typeof val === "number" ? val : parseFloat(val);
-    if (Number.isNaN(num)) return val;
-    return Number.isInteger(num) ? num : num.toFixed(2) + "亩";
-}
-const paramsPage = ref({});
-onActivated(() => {
-    window.scrollTo(0, 0);
-    paramsPage.value = route.query.miniJson ? JSON.parse(route.query.miniJson) : {};
-    getDetail();
-    getResultReport();
-});
-
-const reportData = ref({});
-const getResultReport = () => {
-    VE_API.z_farm_work_record.resultReport({ recordId: paramsPage.value.id }).then((res) => {
-        if (res.code === 0) {
-            reportData.value = res.data;
-        }
-    });
-};
-
-const getDetail = () => {
-    if (!paramsPage.value.id) return;
-    loading.value = true;
-    VE_API.z_farm_work_record
-        .getDetail({ id: paramsPage.value.id })
-        .then(({ data }) => {
-            workItem.value = data[0];
-        })
-        .finally(() => {
-            loading.value = false;
-        });
-};
-
-const isDowload = ref(true);
-const reportDom = ref(null);
-const pageImg = ref(null);
-
-async function handleDownload() {
-    isDowload.value = false;
-    setTimeout(async () => {
-        // 获取要截图的DOM元素
-        const element = reportDom.value;
-
-        try {
-            const canvas = await html2canvas(element, {
-                scrollY: -window.scrollY, // 处理滚动条位置
-                allowTaint: true, // 允许跨域图片
-                useCORS: true, // 使用CORS
-                scale: 2, // 提高分辨率(2倍)
-                height: element.scrollHeight, // 设置完整高度
-                width: element.scrollWidth, // 设置完整宽度
-                logging: true, // 开启日志(调试用)
-            });
-
-            // 转换为图片并下载
-            const image = canvas.toDataURL("image/png");
-            pageImg.value = image;
-            nextTick(() => {
-                showPopup.value = true;
-            })
-        } catch (error) {
-            isDowload.value = true;
-        }
-    });
-}
-
-const handleCancel = () => {
-    showPopup.value = false;
-};
-
-function downloadImage(dataUrl, filename) {
-    const link = document.createElement("a");
-    link.href = dataUrl;
-    link.download = filename;
-    document.body.appendChild(link);
-    link.click();
-    document.body.removeChild(link);
-}
-
-const reviewComboRef = ref(null);
-const combinedReviewImages = ref([]);
-// 生成组合照片,传给相册组件
-const generateCombinedReviewImage = async () => {
-    try {
-        await prepareCoverImages();
-        await nextTick();
-
-        const canvas = await html2canvas(reviewComboRef.value, {
-            backgroundColor: null,
-            useCORS: true,
-            allowTaint: true,
-            scale: window.devicePixelRatio || 2,
-        });
-
-        combinedReviewImages.value = [canvas.toDataURL("image/png")];
-    } catch (e) {
-        console.error("生成组合照片失败", e);
-    }
-};
-
-const prepareCoverImages = async () => {
-    await nextTick();
-
-    const itemEl = reviewComboRef.value.querySelector(".review-image-item");
-
-    const cssWidth = itemEl.offsetWidth;
-    const cssHeight = 255;
-
-    if (workItem.value?.executeEvidence?.length) {
-        leftCoverImg.value = await coverImageToBase64HD(
-            base_img_url2 + workItem.value.executeEvidence.at(-1),
-            cssWidth,
-            cssHeight
-        );
-    }
-
-    if (workItem.value?.reviewImage?.length) {
-        rightCoverImg.value = await coverImageToBase64HD(
-            base_img_url2 + workItem.value.reviewImage.at(-1),
-            cssWidth,
-            cssHeight
-        );
-    }
-};
-
-const leftCoverImg = ref("");
-const rightCoverImg = ref("");
-
-function coverImageToBase64HD(imgUrl, cssWidth, cssHeight) {
-    return new Promise((resolve, reject) => {
-        const dpr = window.devicePixelRatio || 2;
-
-        const img = new Image();
-        img.crossOrigin = "anonymous";
-        img.src = imgUrl;
-
-        img.onload = () => {
-            // ⚠️ 用“物理像素”创建 canvas
-            const canvas = document.createElement("canvas");
-            canvas.width = cssWidth * dpr;
-            canvas.height = cssHeight * dpr;
-
-            const ctx = canvas.getContext("2d");
-            ctx.scale(dpr, dpr);
-
-            const imgRatio = img.width / img.height;
-            const targetRatio = cssWidth / cssHeight;
-
-            let sx = 0,
-                sy = 0,
-                sw = img.width,
-                sh = img.height;
-
-            if (imgRatio > targetRatio) {
-                sw = img.height * targetRatio;
-                sx = (img.width - sw) / 2;
-            } else {
-                sh = img.width / targetRatio;
-                sy = (img.height - sh) / 2;
-            }
-
-            ctx.drawImage(img, sx, sy, sw, sh, 0, 0, cssWidth, cssHeight);
-
-            resolve(canvas.toDataURL("image/png"));
-        };
-
-        img.onerror = reject;
-    });
-}
-
-
-const userInfoStr = localStorage.getItem("localUserInfo");
-const userInfo = userInfoStr ? JSON.parse(userInfoStr) : {};
-
-async function handleForward() {
-    setTimeout(async () => {
-        // 获取要截图的DOM元素
-        const element = reportDom.value;
-
-        try {
-            const canvas = await html2canvas(element, {
-                scrollY: -window.scrollY, // 处理滚动条位置
-                allowTaint: true, // 允许跨域图片
-                useCORS: true, // 使用CORS
-                scale: 2, // 提高分辨率(2倍)
-                height: element.scrollHeight, // 设置完整高度
-                width: element.scrollWidth, // 设置完整宽度
-                logging: true, // 开启日志(调试用)
-            });
-
-            // 转换为图片并下载
-            const image = canvas.toDataURL("image/png");
-            const process = detectRuntimeEnvironment();
-            // if (process === "wechat-webview") {
-                const imgUrl = await uploadBase64(image, false);
-                const params = {
-                    val: 'share',
-                    key: "report",
-                };
-                VE_API.mine.saveSessionStore({ ...params, text: imgUrl }).then((res) => {
-                    if (res.success) {
-                        wx.miniProgram.navigateTo({
-                            url: `/pages/subPages/report_page/index`,
-                        });
-                    }
-                });
-            // }
-            isDowload.value = true;
-        } catch (error) {
-            isDowload.value = true;
-        }
-    });
-
-
-    // const image = await handleDownload(true);
-    // const imgUrl = await uploadBase64(image, false);
-    // const params = {
-    //     miniUserId: 766,
-    //     key: "report",
-    // };
-    // VE_API.mine.saveSessionStore({ ...params, text: imgUrl }).then((res) => {
-    //     if (res.success) {
-    //         wx.miniProgram.navigateTo({
-    //             url: `/pages/subPages/report_page/index`,
-    //         });
-    //     }
-    // });
-}
-
-watch(
-    () => [workItem.value.executeEvidence, workItem.value.reviewImage],
-    ([preImgs, reviewImgs]) => {
-        if (preImgs && preImgs.length && reviewImgs && reviewImgs.length) {
-            generateCombinedReviewImage();
-        }
-    },
-    { deep: true }
-);
-
-// 清理数据的函数
-const clearData = () => {
-    workItem.value = {};
-    reportData.value = {};
-    paramsPage.value = {};
-    loading.value = false;
-    isDowload.value = true;
-    combinedReviewImages.value = [];
-    leftCoverImg.value = "";
-    rightCoverImg.value = "";
-};
-
-onDeactivated(() => {
-    clearData();
-});
-
-onUnmounted(() => {
-    clearData();
-});
-</script>
-
-<style lang="scss" scoped>
-.achievement-report-page {
-    width: 100%;
-    height: 100vh;
-    background: linear-gradient(195.35deg, #d4e4ff 16.34%, rgba(93, 189, 255, 0) 50.3%),
-        linear-gradient(156.64deg, rgba(255, 255, 255, 0.16) 27.7%, rgba(255, 255, 255, 0) 72.82%);
-
-    .report-content-wrap {
-        height: calc(100% - 40px);
-        padding-bottom: 60px;
-        overflow: auto;
-        box-sizing: border-box;
-        position: relative;
-        .bottom-btn {
-            z-index: 2;
-            position: fixed;
-            bottom: 0;
-            left: 0;
-            width: 100%;
-            background: #fff;
-            height: 60px;
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-            padding: 0 12px;
-            box-sizing: border-box;
-            box-shadow: 2px 2px 4.5px 0px rgba(0, 0, 0, 0.4);
-            .btn-item {
-                height: 40px;
-                line-height: 40px;
-                padding: 0 24px;
-                border-radius: 20px;
-                font-size: 14px;
-                &.second {
-                    color: #666666;
-                    border: 1px solid rgba(153, 153, 153, 0.5);
-                }
-                &.primay {
-                    padding: 0 34px;
-                    background: linear-gradient(180deg, #76c3ff, #2199f8);
-                    color: #fff;
-                }
-            }
-        }
-    }
-    
-    .code-icon {
-        position: absolute;
-        right: 10px;
-        top: 12px;
-        width: 48px;
-    }
-    .report-content {
-        background: url("@/assets/img/home/report_bg.png") no-repeat center center;
-        background-size: 100% auto;
-        background-position: top center;
-        padding: 24px 16px 16px;
-        box-sizing: border-box;
-        position: relative;
-        .report-header {
-            position: relative;
-            .header-book {
-                position: absolute;
-                right: 0;
-                bottom: -6px;
-                height: 88px;
-                z-index: 10;
-            }
-            .time-tag {
-                background: linear-gradient(137.86deg, #9fd5ff 5.87%, #2199f8 82.98%);
-                border-radius: 5px 0 5px 0;
-                height: 23px;
-                line-height: 23px;
-                font-size: 13px;
-                font-weight: 500;
-                color: #fff;
-                padding: 0 9px;
-                width: fit-content;
-            }
-            .report-title {
-                font-family: "PangMenZhengDao";
-                font-size: 34px;
-                line-height: 38px;
-                color: #000000;
-            }
-            .report-info {
-                padding: 10px 0 16px 0;
-                .info-item {
-                    width: fit-content;
-                    display: flex;
-                    height: 33px;
-                    align-items: center;
-                    padding: 0 6px 0 3px;
-                    background: linear-gradient(90deg, rgba(255, 255, 255, 0.58) 0%, rgba(255, 255, 255, 0.0696) 100%);
-                    border-radius: 20px;
-                    border: 0.5px solid rgba(33, 153, 248, 0.35);
-                    gap: 3px;
-                    .info-icon {
-                        width: 26px;
-                        height: 26px;
-                        object-fit: cover;
-                        border-radius: 50%;
-                    }
-                    .info-text {
-                        font-size: 14px;
-                        color: #2199f8;
-                    }
-                }
-                .info-item + .info-item {
-                    margin-top: 5px;
-                }
-            }
-        }
-
-        .report-box {
-            display: flex;
-            align-items: center;
-            padding: 8px;
-            background: linear-gradient(0deg, #ffffff 86.32%, #2199f8 136.87%);
-            border: 1px solid #ffffff;
-            border-radius: 8px;
-            gap: 5px;
-            position: relative;
-            .report-box-item {
-                flex: 1;
-                background: rgba(33, 153, 248, 0.1);
-                border-radius: 8px;
-                min-height: 62px;
-                box-sizing: border-box;
-                padding: 2px 4px;
-                display: flex;
-                flex-direction: column;
-                justify-content: center;
-                .item-content {
-                    color: #2199f8;
-                    font-size: 14px;
-                    text-align: center;
-                }
-                .item-title {
-                    color: #000000;
-                    font-size: 10px;
-                    text-align: center;
-                    padding-top: 5px;
-                }
-            }
-
-            .box-title {
-                position: absolute;
-                top: -8px;
-                left: 0;
-                height: 32px;
-                line-height: 26px;
-                padding: 0 10px;
-                color: #ffffff;
-                background: url("@/assets/img/home/title-bg.png") no-repeat center center / 100% 100%;
-            }
-            .box-text {
-                padding: 22px 0 12px 0;
-            }
-        }
-        .report-box + .report-box {
-            margin-top: 20px;
-        }
-        .report-excute {
-            position: relative;
-            margin-top: 12px;
-            .tag-label {
-                position: absolute;
-                top: 0;
-                left: 0;
-                padding: 4px 10px;
-                background: rgba(54, 52, 52, 0.8);
-                color: #fff;
-                font-size: 12px;
-                border-radius: 8px 0 8px 0;
-                z-index: 1;
-            }
-            ::v-deep {
-                .carousel-container .carousel-wrapper .carousel-img {
-                    min-width: calc(100vw - 32px);
-                    width: calc(100vw - 32px);
-                }
-            }
-        }
-    }
-    .download-btn {
-        position: fixed;
-        bottom: 20px;
-        left: 50%;
-        // background: #fff;
-        // box-shadow: 2px 2px 4.5px 0px #00000066;
-        // width: 100%;
-        transform: translateX(-50%);
-    }
-
-    .review-hide-box {
-        position: absolute;
-        left: 0;
-        width: 100%;
-        height: 100%;
-        z-index: -1;
-        bottom: 0;
-    }
-
-    .review-image {
-        position: relative;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        gap: 8px;
-        margin: 12px;
-        background: #fff;
-        border-radius: 8px;
-        .review-mask {
-            z-index: 1;
-            pointer-events: none;
-            position: absolute;
-            left: 0;
-            top: 0;
-            width: 100%;
-            height: 100%;
-            border-radius: 8px;
-            background: linear-gradient(
-                360deg,
-                rgba(0, 0, 0, 0.78) 0%,
-                rgba(0, 0, 0, 0.437208) 19.87%,
-                rgba(0, 0, 0, 0) 33.99%
-            );
-            display: flex;
-            flex-direction: column;
-            align-items: baseline;
-            justify-content: end;
-            padding: 12px;
-            box-sizing: border-box;
-            color: #fff;
-            .review-text {
-                font-family: "PangMenZhengDao";
-                font-size: 16px;
-                margin-bottom: 1px;
-            }
-            .review-content {
-                font-size: 10px;
-                line-height: 15px;
-            }
-        }
-        .vs-wrap {
-            position: absolute;
-            left: 50%;
-            top: 50%;
-            transform: translate(-50%, -50%);
-            width: 40px;
-            height: 40px;
-            z-index: 10;
-            img {
-                width: 100%;
-                height: 100%;
-                object-fit: cover;
-            }
-        }
-        .review-image-item {
-            position: relative;
-            flex: 1;
-            .review-image-item-title {
-                position: absolute;
-                top: 0;
-                left: 0;
-                background: rgba(54, 52, 52, 0.6);
-                padding: 4px 10px;
-                border-radius: 8px 0 8px 0;
-                backdrop-filter: 4px;
-                font-size: 12px;
-                color: #fff;
-            }
-            // .review-image-item-img {
-            //     width: 100%;
-            //     height: 250px;
-            //     object-fit: cover;
-            // }
-            .review-image-item-img {
-                width: 100%;
-                height: 100%;
-                object-fit: cover;
-                object-position: center;
-            }
-            .left-img {
-                border-radius: 8px 0 0 8px;
-            }
-            .right-img {
-                border-radius: 0 8px 8px 0;
-            }
-        }
-    }
-}
-
-
-.cavans-popup {
-    width: 100%;
-    max-width: 100%;
-    max-height: 92vh;
-    background: none;
-    border-radius: 12px;
-    overflow: auto;
-    display: flex;
-    flex-direction: column;
-    backdrop-filter: 4px;
-    .cavans-content {
-        text-align: center;
-        padding: 0 12px;
-        height: fit-content;
-        overflow: auto;
-        .current-img {
-            width: 100%;
-        }
-    }
-
-    // 底部操作按钮
-    .bottom-actions {
-        flex-shrink: 0;
-
-        .action-buttons {
-            padding: 12px 0 4px 0;
-            display: flex;
-            justify-content: space-around;
-
-            .action-btn {
-                display: flex;
-                flex-direction: column;
-                align-items: center;
-                cursor: pointer;
-                &.text-btn {
-                    font-size: 12px;
-                    color: rgba(255, 255, 255, 0.7);
-                }
-
-                .icon-circle {
-                    width: 48px;
-                    height: 48px;
-                    border-radius: 50%;
-                    display: flex;
-                    align-items: center;
-                    justify-content: center;
-                    color: #fff;
-                    margin-bottom: 4px;
-
-                    .el-icon {
-                        color: #fff;
-                    }
-                    img {
-                        width: 50px;
-                    }
-                }
-
-                &.blue-btn .icon-circle {
-                    background: #2199f8;
-                }
-
-                &.green-btn .icon-circle {
-                    background: #07c160;
-                }
-
-                &.orange-btn .icon-circle {
-                    background: #ff790b;
-                }
-
-                .btn-label {
-                    font-size: 12px;
-                    color: #fff;
-                }
-            }
-        }
-
-        .cancel-btn {
-            text-align: center;
-            font-size: 18px;
-            color: #fff;
-            cursor: pointer;
-        }
-    }
-}
-</style>

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

@@ -112,6 +112,7 @@
         </div>
         <album-upload-popup v-model:show="showUploadPopup" />
         <complete-farm-info-popup v-model:show="showCompleteFarmPopup" @confirm="goCompleteFarmInfo" />
+        <diagnosis-report-popup v-model:show="showDiagnosisReportPopup" @confirm="goDiagnosisReport" />
     </div>
 </template>
 
@@ -127,6 +128,7 @@ import * as util from "@/common/ol_common.js";
 import farmHeader from "@/components/farmHeader.vue";
 import albumUploadPopup from "./components/albumUploadPopup.vue";
 import completeFarmInfoPopup from "@/components/popup/completeFarmInfoPopup.vue";
+import diagnosisReportPopup from "@/components/popup/diagnosisReportPopup.vue";
 import PhenologyTrackTimelineItem from "@/components/pageComponents/PhenologyTrackTimelineItem.vue";
 
 const { t } = useI18n();
@@ -182,7 +184,8 @@ const reportList = ref([
 ]);
 
 const showUploadPopup = ref(false);
-const showCompleteFarmPopup = ref(true);
+const showCompleteFarmPopup = ref(false);
+const showDiagnosisReportPopup = ref(false);
 const patrolList = ref([
     {
         id: 1,
@@ -315,6 +318,10 @@ const goCompleteFarmInfo = () => {
     router.push("/entry_information");
 };
 
+const goDiagnosisReport = () => {
+    activeNav.value = "report";
+};
+
 onMounted(() => {
     fillMockLabels();
     initAlbumMap();

+ 0 - 690
src/views/old_mini/chat_frame/consult.vue

@@ -1,690 +0,0 @@
-<template>
-    <div class="consult">
-        <custom-header :name="$t('咨询专家')"></custom-header>
-        <div class="consult-content">
-            <!-- 聊天消息区域 -->
-            <div class="chat-messages" ref="messagesContainer">
-                <div v-for="(msg, index) in messages" :key="index" class="message" :class="msg.sender">
-                    <!-- 对方消息 -->
-                    <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/dinggou-mini/defalut-icon.png'
-                            " />
-                        <div class="bubble"
-                            :class="{ 'no-bubble': msg.messageType === 'image', 'card-bubble': msg.messageType === 'card' }">
-                            <!-- 文本消息 -->
-                            <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="图片" />
-                            </div>
-
-                            <!-- 对话样式消息 -->
-                            <div v-if="msg.messageType === 'report'" class="dialog-message"
-                                @click="handleReportClick(msg)">
-                                <template v-if="(msg.reportType || msg.content.reportType) === 'farm_report'">
-                                    <div class="report-title">{{ msg.title || msg.content.title }}</div>
-                                    <div class="dialog-title">这是{{ curRole == 2 ? '该农场' : '我' }}的果园情况,请查看~</div>
-                                    <img src="https://birdseye-img.sysuimars.com/birdseye-look-mini/share-report-bg.png"
-                                        alt="" class="monitor-image" />
-                                </template>
-                                <template v-else>
-                                    <div class="dialog-title">{{ msg.title || msg.content.title }}</div>
-                                    <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image" />
-                                </template>
-                            </div>
-
-                            <!-- 对话样式消息 -->
-                            <div v-if="msg.messageType === 'card'" class="question-message">
-                                <div class="question-title">{{ msg.title || msg.content.title }}</div>
-                                <div class="image-wrap">
-                                    <!-- coverUrl 为 JSON 字符串的数组时,解析后遍历 -->
-                                    <template
-                                        v-if="msg.content && msg.content.coverUrl && Array.isArray(msg.content.coverUrl)">
-                                        <img v-for="item in msg.content.coverUrl" :key="item" :src="handleImgUrl(item)"
-                                            alt="" />
-                                    </template>
-                                    <!-- 否则当作普通字符串 URL 使用 -->
-                                    <img v-else :src="handleImgUrl(msg.content.coverUrl)" alt="">
-                                </div>
-                                <div class="btn-detail" @click="handleDetailClick">{{ $t('查看详情') }}</div>
-                            </div>
-                        </div>
-                    </template>
-
-                    <!-- 我方消息 -->
-                    <template v-else>
-                        <div class="bubble"
-                            :class="{ 'no-bubble': msg.messageType === 'image', 'card-bubble': msg.messageType === 'card' || msg.messageType === 'report' }">
-                            <!-- 文本消息 -->
-                            <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="图片" />
-                            </div>
-
-                            <!-- 对话样式消息 -->
-                            <div v-if="msg.messageType === 'report'" class="dialog-message"
-                                @click="handleReportClick(msg)">
-                                <template v-if="(msg.reportType || msg.content.reportType) === 'farm_report'">
-                                    <div class="report-title">{{ msg.title || msg.content.title }}</div>
-                                    <div class="dialog-title">这是{{ curRole == 2 ? '该农场' : '我' }}果园情况,请查看~</div>
-                                    <img src="https://birdseye-img.sysuimars.com/birdseye-look-mini/share-report-bg.png"
-                                        alt="" class="monitor-image" />
-                                </template>
-                                <template v-else>
-                                    <div class="dialog-title">{{ msg.title || msg.content.title }}</div>
-                                    <img src="@/assets/img/monitor/image.png" alt="" class="monitor-image" />
-                                </template>
-                            </div>
-
-                            <!-- 对话样式消息 -->
-                            <div v-if="msg.messageType === 'card'" class="question-message">
-                                <div class="question-title">{{ msg.title || msg.content.title }}</div>
-                                <div class="image-wrap">
-                                    <!-- coverUrl 为 JSON 字符串的数组时,解析后遍历 -->
-                                    <template
-                                        v-if="msg.content && msg.content.coverUrl && Array.isArray(msg.content.coverUrl)">
-                                        <img v-for="item in msg.content.coverUrl" :key="item" :src="handleImgUrl(item)"
-                                            alt="" />
-                                    </template>
-                                    <!-- 否则当作普通字符串 URL 使用 -->
-                                    <img v-else :src="handleImgUrl(msg.content.coverUrl)" alt="">
-                                </div>
-                                <div class="btn-detail" @click="handleDetailClick">{{ $t('查看详情') }}</div>
-                            </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/dinggou-mini/defalut-icon.png'
-                            " />
-                    </template>
-                </div>
-            </div>
-
-            <!-- 输入框区域 -->
-            <div class="input-area">
-                <!-- <div class="toolbar">
-                    <el-icon class="link" @click="startImageUpload"><Link /></el-icon>
-                    <input type="file" ref="fileInput" accept="image/*" style="display: none" @change="handleImageUpload" />
-                </div> -->
-
-                <input type="text" v-model="inputMessage" :placeholder="$t('请输入你想说的话~')" @keyup.enter="sendTextMessage" />
-                <div class="send" @click="sendTextMessage">{{ $t('发送') }}</div>
-            </div>
-
-            <!-- 图片预览模态框 -->
-            <div v-if="previewImage" class="image-preview" @click="previewImage = null">
-                <img :src="previewImage" alt="预览" />
-            </div>
-        </div>
-    </div>
-</template>
-
-<script setup>
-import { ref, nextTick, onDeactivated, onMounted } from "vue";
-import { useRouter, useRoute } from "vue-router";
-import { base_img_url2 } from "@/api/config";
-import { getFileExt } from "@/utils/util";
-import UploadFile from "@/utils/upliadFile";
-import MqttClient from "@/plugins/MqttClient";
-import customHeader from "@/components/customHeader.vue";
-import { useStore } from "vuex";
-const store = useStore();
-const resize = "?x-oss-process=image/resize,p_120/format,webp/quality,q_100";
-const router = useRouter();
-const route = useRoute();
-
-
-const curUserId = Number(localStorage.getItem("MINI_USER_ID"));
-const storeFarmId = ref(store.state.home.gardenId)
-const senderIcon = ref("");
-const receiverIcon = ref("");
-
-// 本地用户头像
-const localUserInfoIcon = (() => {
-    try {
-        const info = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
-        return info?.icon || "";
-    } catch (e) {
-        return "";
-    }
-})();
-
-// mqtt 连接
-const mqttClient = ref(null);
-const messagesContainer = ref(null);
-
-// 初始化 mqtt
-const initMqtt = () => {
-    const topics = [`user/chat/message/${storeFarmId.value}/${curUserId}`]; // 订阅的主题数组
-    mqttClient.value = new MqttClient(topics, (topic, message) => {
-        if (message && message.length > 10) {
-            const obj = JSON.parse(message);
-            console.log("message有值", obj);
-            if (obj.senderId === curUserId) {
-                return;
-            }
-            if (obj.senderId === Number(route.query.userId)) {
-                // 检查是否已存在相同 id 的消息,避免重复添加
-                if (obj.id && messages.value.some(msg => msg.id === obj.id)) {
-                    return;
-                }
-                if (obj.messageType === "image") {
-                    if (obj.image && (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;
-                        } catch (e) {
-                            console.error(e, "e");
-                        }
-                    }
-                } else if (obj.messageType !== 'text') {
-                    obj.content = JSON.parse(obj.content);
-                    // card 类型的 content 中,如果 coverUrl 是数组,则转成字符串(兼容旧格式)
-                    if (obj.messageType === 'card' && obj.content && Array.isArray(obj.content.coverUrl)) {
-                        obj.content.coverUrl = JSON.stringify(obj.content.coverUrl);
-                    }
-                }
-                obj.receiverId = curUserId;
-                (obj.sender = obj.senderId === curUserId ? "sent" : "received"), (obj.senderIcon = senderIcon.value);
-                obj.receiverIcon = receiverIcon.value;
-                messages.value.push(obj);
-
-                scrollToBottom();
-            }
-        }
-    });
-
-    mqttClient.value.connect();
-};
-
-// 消息数据
-const messages = ref([]);
-
-// 输入相关
-const inputMessage = ref("");
-const fileInput = ref(null);
-
-function handleImageLoad() {
-    scrollToBottom();
-}
-
-const handleDetailClick = () => {
-    router.push(`/interaction_list?expertMiniUserId=${route.query.userId}`);
-}
-
-// 图片预览
-const previewImage = ref(null);
-
-const handleCardClick = (msg) => {
-    router.push(msg.linkUrl || msg.content.linkUrl);
-}
-
-const handleImgUrl = (url) => {
-    if (url && url.includes('https://')) {
-        return url;
-    } else {
-        return base_img_url2 + url + resize;
-    }
-}
-
-// 图片处理
-const startImageUpload = () => {
-    fileInput.value.click();
-};
-
-const uploadFileObj = new UploadFile();
-
-const handleImageUpload = (event) => {
-    const file = event.target.files[0];
-    if (file) {
-        // 实际项目中应该上传到服务器,这里使用本地URL模拟
-        const miniUserId = localStorage.getItem("MINI_USER_ID");
-        let ext = getFileExt(file.name);
-        let key = `birdseye-look-mini/${miniUserId}/${new Date().getTime()}.${ext}`;
-        let imageUrl = "";
-        uploadFileObj.put(key, file).then((resFilename) => {
-            imageUrl = base_img_url2 + resFilename;
-            sendImageMessage(imageUrl);
-        });
-    }
-};
-
-const showImagePreview = (imageUrl) => {
-    previewImage.value = imageUrl;
-};
-
-// 发送图片消息
-const sendImageMessage = (thumbnailUrl) => {
-    const message = {
-        sender: "sent",
-        messageType: "image",
-        senderIcon: senderIcon.value,
-        content: thumbnailUrl,
-    };
-    sendMessage(message);
-};
-
-//发送消息接口
-//类型 text ,file,image
-const sendMsg = (messageType = "text", content = "", obj = {}) => {
-    const params = {
-        farmId: storeFarmId.value,
-        receiverId: route.query.userId,
-        content,
-        [messageType]: obj,
-        messageType,
-    };
-    VE_API.bbs.sendMsg(params);
-};
-
-// 发送消息
-const sendMessage = (message) => {
-    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 === "report") {
-        // 对话样式消息不发送到服务器,只显示在本地
-        console.log("发送对话样式消息:", message);
-        if (message.reportType === 'farm_report') {
-            sendMsg('report', '', {
-                title: message.title,
-                reportId: message.reportId,
-                reportType: message.reportType,
-            });
-        } else {
-            sendMsg('report', '', {
-                title: message.title,
-                reportId: message.reportId,
-                reportType: message.reportType,
-            });
-            console.log('其他文件1');
-        }
-    } else {
-        sendMsg('card', '', {
-            title: message.title,
-            coverUrl: message.coverUrl,
-            cardType: message.cardType,
-            linkUrl: message.linkUrl
-        });
-    }
-    messages.value.push(message);
-    scrollToBottom();
-};
-
-// 发送文本消息
-const sendTextMessage = () => {
-    if (inputMessage.value.trim()) {
-        const message = {
-            sender: "sent",
-            messageType: "text",
-            senderIcon: senderIcon.value,
-            content: inputMessage.value,
-        };
-        sendMessage(message);
-        inputMessage.value = "";
-    }
-};
-
-const scrollToBottom = () => {
-    nextTick(() => {
-        setTimeout(() => {
-            if (messagesContainer.value) {
-                messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
-            }
-        }, 300);
-    });
-};
-
-const curRole = ref(null);
-
-// 点击农场报告对话框
-const handleReportClick = (msg) => {
-    if (msg.reportType === 'farm_report' || msg.messageType === 'report') {
-        const params = {
-            farmId: msg.reportId || msg.content?.reportId,
-            showFilter: true,
-        }
-        router.push(`/farm_report?miniJson=${JSON.stringify(params)}`);
-    } else {
-        console.log('其他文件');
-    }
-}
-
-// 页面加载时自动添加欢迎消息
-onMounted(() => {
-    createSession(route.query.userId);
-    scrollToBottom();
-});
-
-//聊天会话
-const createSession = (targetUserId, callback) => {
-    VE_API.bbs.createSession({ farmId: storeFarmId.value, targetUserId }).then(({ data, code }) => {
-        if (code === 0) {
-            senderIcon.value = localUserInfoIcon;
-            receiverIcon.value = data.session.targetUserAvatar;
-            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;
-                    } else if (item.content) {
-                        try {
-                            const imgObj = JSON.parse(item.content);
-                            content = imgObj.url || imgObj.originUrl;
-                        } catch (e) {
-                            console.error(e, "e");
-                        }
-                    }
-                } else if (item.messageType !== 'text') {
-                    content = JSON.parse(item.content);
-                }
-                return {
-                    ...item,
-                    content,
-                    sender: item.senderId === curUserId ? "sent" : "received",
-                    senderIcon: item.senderId === curUserId ? localUserInfoIcon : data.session.targetUserAvatar,
-                    receiverIcon: data.session.targetUserAvatar,
-                };
-            });
-
-            setTimeout(() => {
-                scrollToBottom();
-            }, 300);
-            callback && callback();
-
-            // 初始化mqtt
-            initMqtt();
-        }
-    });
-};
-
-onDeactivated(() => {
-    mqttClient.value && mqttClient.value.client.end(true);
-});
-</script>
-
-<style scoped lang="scss">
-.consult {
-    width: 100%;
-    height: calc(100vh - 40px);
-    box-sizing: border-box;
-
-    .consult-content {
-        width: 100%;
-        height: 100%;
-        display: flex;
-        flex-direction: column;
-        position: relative;
-    }
-}
-
-/* 聊天消息区域样式 */
-.chat-messages {
-    flex: 1;
-    padding: 12px;
-    overflow-y: auto;
-    background-color: #fff;
-    box-sizing: border-box;
-
-    .message {
-        display: flex;
-        margin-bottom: 15px;
-    }
-
-    .received {
-        justify-content: flex-start;
-
-        .bubble {
-            background-color: #F4F5F8;
-            border-radius: 0 10px 10px 10px;
-            padding: 10px 12px;
-            box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
-
-            .content {
-                font-size: 16px;
-                color: #666666;
-            }
-        }
-    }
-
-    .sent {
-        justify-content: flex-end;
-
-        .bubble {
-            background-color: #07c160;
-            border-radius: 10px 0 10px 10px;
-            padding: 10px 15px;
-            box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
-
-            .content {
-                font-size: 16px;
-                color: #000;
-            }
-        }
-        .question-message {
-            .question-title{
-                color: #000;
-            }
-        }
-    }
-
-    .avatar {
-        width: 40px;
-        height: 40px;
-        border-radius: 50%;
-        background-color: #07c160;
-        color: white;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        margin-right: 10px;
-        font-weight: bold;
-    }
-
-    .avatar-r {
-        margin: 0 0 0 10px;
-    }
-
-    .bubble {
-        max-width: 70%;
-    }
-}
-
-
-
-.input-area {
-    display: flex;
-    align-items: center;
-    padding: 15px 10px;
-    border-top: 1px solid #e6e6e6;
-    background-color: white;
-    position: relative;
-    width: 100%;
-    box-sizing: border-box;
-
-    input {
-        flex: 1;
-        padding: 10px;
-        border: 1px solid #e6e6e6;
-        border-radius: 20px;
-        outline: none;
-    }
-
-    .send {
-        margin-left: 10px;
-        padding: 8px 20px;
-        background-color: #07c160;
-        color: white;
-        border: none;
-        border-radius: 20px;
-        cursor: pointer;
-    }
-}
-
-/* 新增的多媒体消息样式 */
-.image-message {
-    img {
-        max-width: 200px;
-        max-height: 200px;
-        border-radius: 8px;
-    }
-}
-
-/* 图片消息不使用对话气泡样式 */
-.no-bubble {
-    background: transparent !important;
-    border-radius: 0 !important;
-    padding: 0 !important;
-    box-shadow: none !important;
-    color: inherit !important;
-}
-
-/* 工具栏样式 */
-.toolbar {
-    display: flex;
-    align-items: center;
-
-    button {
-        background: none;
-        border: none;
-        font-size: 20px;
-        margin-right: 10px;
-        cursor: pointer;
-        padding: 5px;
-    }
-
-    .link {
-        font-size: 24px;
-        margin-right: 10px;
-    }
-}
-
-/* 图片预览 */
-.image-preview {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background: rgba(0, 0, 0, 0.8);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    z-index: 1000;
-}
-
-.image-preview img {
-    max-width: 90%;
-    max-height: 90%;
-    object-fit: contain;
-}
-
-/* 对话样式消息 */
-.dialog-message {
-    max-width: 100%;
-    background: #fff !important;
-    border-radius: 10px;
-
-    .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;
-        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;
-                }
-            }
-        }
-    }
-}
-
-.question-message {
-    .question-title {
-        font-size: 16px;
-        color: #666666;
-        margin-bottom: 6px;
-    }
-
-    .image-wrap {
-        display: flex;
-        // flex-wrap: wrap;
-        gap: 10px;
-
-        img {
-            width: 75px;
-            height: 70px;
-            border-radius: 8px;
-            object-fit: cover;
-        }
-    }
-
-    .btn-detail {
-        font-size: 14px;
-        margin-top: 8px;
-        background: #FFFFFF;
-        border-radius: 6px;
-        text-align: center;
-        padding: 6px;
-    }
-}
-
-/* 我方消息中的对话样式 */
-.message.sent .dialog-message {
-    background: #e3f2fd;
-
-    .work-details {
-        background: #f0f8ff;
-    }
-}
-</style>

+ 0 - 66
src/views/old_mini/chat_frame/index.vue

@@ -1,66 +0,0 @@
-<template>
-    <div class="dialogue">
-        <custom-header :name="nameVal || '飞鸟种植助手'" bgColor="#f2f3f5" isGoBack @goback="headerCallBack"></custom-header>
-        <chat-window :text="desc" :userId="userIdVal" :img="imgVal" @update:name="nameVal = $event"></chat-window>
-    </div>
-</template>
-
-<script setup>
-import customHeader from "@/components/customHeader.vue";
-import { onActivated, ref } from "vue";
-import chatWindow from "@/components/chatWindow";
-import { useRoute, useRouter } from "vue-router";
-
-const route = useRoute();
-const router = useRouter();
-const desc = ref("");
-const nameVal = ref("");
-const userIdVal = ref(null);
-const imgVal = ref("");
-const formPageVal = ref("");
-onActivated(() => {
-    userIdVal.value = null;
-    setTimeout(() => {
-        const { text, formPage, userId, img } = route.query;
-        desc.value = text;
-        userIdVal.value = userId;
-        imgVal.value = img;
-        formPageVal.value = formPage;
-        if(formPage) {
-            sessionStorage.setItem('chat_frame_page', formPage);
-        }
-    }, 100);
-});
-
-function headerCallBack() {
-    const page = sessionStorage.getItem('chat_frame_page');
-    if(page === 'messageList' || page === 'monitor') {
-        VE_API.bbs.readUpdate({ targetUserId: userIdVal.value, farmId: route.query.farmId }).then((res) => {
-            if (res.code === 0) {
-                sessionStorage.removeItem('chat_frame_page');
-                router.replace({ path: '/message_list', query: { farmId: route.query.farmId, from: 'monitor' } });
-            }
-        });
-    } else {
-        router.go(-1);
-    }
-}
-</script>
-
-<style lang="scss" scoped>
-.dialogue {
-    width: 100%;
-    height: calc(100vh - 40px);
-    background: #f2f3f5;
-    box-sizing: border-box;
-    .chat-container {
-        display: flex;
-        flex-direction: column;
-        height: 100%;
-        width: 100%;
-        margin: 0 auto;
-        border: 1px solid #e6e6e6;
-        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
-    }
-}
-</style>

+ 0 - 2
src/views/old_mini/growth_report/index copy.vue

@@ -180,7 +180,6 @@
 
                 <img class="header-img" src="@/assets/img/home/report.png" alt="" />
                 <div class="report-header" :class="{ 'no-farm': !currentFarmName }">
-                    <!-- <img class="header-book" src="@/assets/img/home/book.png" alt="" /> -->
                     <div class="time-tag">{{ new Date().toISOString().split('T')[0] }}</div>
                     <div
                         class="report-title"
@@ -836,7 +835,6 @@ onUnmounted(() => {
     }
 
     .report-content {
-        // background: url("@/assets/img/home/report_bg.png") no-repeat center center;
         // background: linear-gradient(0deg, #9BCCFF, #9BCCFF),
         //     linear-gradient(160deg, rgba(255, 255, 255, 0.16) 30%, rgba(255, 255, 255, 0) 72%);
         background: #abd4ff;

+ 0 - 209
src/views/old_mini/interactionList/confirmArea.vue

@@ -1,209 +0,0 @@
-<template>
-    <div class="edit-map">
-        <custom-header :name="$t('确认农场区域')"></custom-header>
-        <div class="edit-map-content">
-            <div class="edit-map-tip">{{ t('操作提示:拖动圆点,即可调整地块边界') }}</div>
-            <div class="map-container" ref="mapContainer"></div>
-            <div class="edit-map-footer">
-                <div class="footer-back" @click="goBack">
-                    <img class="back-icon" src="@/assets/img/home/go-back.png" alt="" />
-                </div>
-                <div class="footer-address-box">
-                    <div class="footer-address">
-                        <div class="address-title">111</div>
-                        <div class="address-detail">2222</div>
-                    </div>
-                    <div class="address-btn" @click="goBack">{{ t('修改地址') }}</div>
-                </div>
-                <div class="edit-map-footer-btn">
-                    <div class="btn-cancel" @click="goBack">{{ t('取消') }}</div>
-                    <div class="btn-confirm" @click="confirm">{{ t('确认') }}</div>
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <!-- 地形/建模航线提示弹窗(复用 droneConsultPopup:terrainRoute 立即获取 → terrainRouteSuccess 航线已生成) -->
-    <drone-consult-popup v-model:show="showTerrainRoutePopup" :type="terrainPopupType"
-        @confirm="onTerrainRouteConfirm" />
-</template>
-
-<script setup>
-import { useI18n } from "@/i18n";
-const { t } = useI18n();
-import customHeader from "@/components/customHeader.vue";
-import DroneConsultPopup from "@/components/popup/droneConsultPopup.vue";
-import { ref, onMounted, onActivated, onDeactivated } from "vue";
-import DrawRegionMap from "./map/drawRegionMap.js";
-import { useRouter, useRoute } from "vue-router";
-import { convertPointToArray } from "@/utils/index";
-import { ElMessage, ElMessageBox } from "element-plus";
-
-const router = useRouter();
-const route = useRoute();
-const mapContainer = ref(null);
-const drawRegionMap = new DrawRegionMap();
-
-const type = ref('droneConsult');
-const gardenName = ref('荔博园')
-const showTerrainRoutePopup = ref(false);
-/** 弹窗类型:terrainRoute 立即获取 | terrainRouteSuccess 航线已生成 */
-const terrainPopupType = ref("terrainRoute");
-
-onMounted(() => {
-    const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
-    drawRegionMap.initMap(point, mapContainer.value);
-});
-
-onActivated(() => {
-    const point = route.query.mapCenter || "POINT (113.6142086995688 23.585836479509055)";
-
-    // 先绘制地块
-    const polygonData = route.query.polygonData;
-
-    if (polygonData) {
-        drawRegionMap.setAreaGeometry(JSON.parse(polygonData)?.geometryArr);
-    }
-
-    // 再设置地图中心位置,确保视图在 mapCenter
-    drawRegionMap.setMapPosition(convertPointToArray(point));
-});
-
-onDeactivated(() => {
-    drawRegionMap.clearLayer()
-})
-const goBack = () => {
-    // drawRegionMap.clearLayer()
-    router.back()
-};
-
-const onTerrainRouteConfirm = () => {
-    if (terrainPopupType.value === "terrainRoute") {
-        setTimeout(() => {
-            terrainPopupType.value = "terrainRouteSuccess";
-            showTerrainRoutePopup.value = true;
-        }, 1000);
-    } else {
-        showTerrainRoutePopup.value = false;
-        router.back();
-    }
-};
-
-const confirm = () => {
-    if (type.value === "droneConsult") {
-        terrainPopupType.value = "terrainRoute";
-        showTerrainRoutePopup.value = true;
-    }
-    // const polygonData = drawRegionMap.getAreaGeometry();
-    // sessionStorage.setItem("drawRegionPolygonData", JSON.stringify(polygonData));
-    // router.back();
-};
-</script>
-
-<style lang="scss" scoped>
-.edit-map {
-    width: 100%;
-    height: 100vh;
-    overflow: hidden;
-
-    .edit-map-content {
-        width: 100%;
-        height: 100%;
-        position: relative;
-
-        .edit-map-tip {
-            position: absolute;
-            top: 23px;
-            left: calc(50% - 256px / 2);
-            z-index: 1;
-            font-size: 12px;
-            color: #fff;
-            padding: 9px 20px;
-            background: rgba(0, 0, 0, 0.5);
-            border-radius: 20px;
-        }
-
-        .map-container {
-            width: 100%;
-            height: 100%;
-        }
-
-        .edit-map-footer {
-            position: absolute;
-            bottom: 80px;
-            left: 12px;
-            width: calc(100% - 24px);
-            display: flex;
-            flex-direction: column;
-            align-items: flex-end;
-
-            .footer-back {
-                padding: 6px 7px 9px;
-                background: #fff;
-                border-radius: 8px;
-
-                .back-icon {
-                    width: 20px;
-                    height: 18px;
-                }
-            }
-
-            .footer-address-box {
-                width: 100%;
-                box-sizing: border-box;
-                margin: 19px 0 14px 0;
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                background: #fff;
-                border-radius: 14px;
-                padding: 14px 12px;
-
-                .footer-address {
-                    font-size: 12px;
-                    color: rgba(0, 0, 0, 0.6);
-
-                    .address-title {
-                        font-weight: 500;
-                        font-size: 16px;
-                        color: #000;
-                    }
-                }
-
-                .address-btn {
-                    color: #2199f8;
-                    border: 1px solid #2199f8;
-                    border-radius: 25px;
-                    padding: 6px 10px;
-                    flex: none;
-                }
-            }
-
-            .edit-map-footer-btn {
-                display: flex;
-                justify-content: center;
-                align-items: center;
-                width: 100%;
-                gap: 8px;
-
-                div {
-                    flex: 1;
-                    max-width: 100px;
-                    text-align: center;
-                    color: #666666;
-                    font-size: 14px;
-                    padding: 8px 0;
-                    border-radius: 25px;
-                    background: #fff;
-                }
-
-                .btn-confirm {
-                    background: #000;
-                    background-image: linear-gradient(180deg, #76c3ff 0%, #2199f8 100%);
-                    color: #fff;
-                }
-            }
-        }
-    }
-}
-</style>

+ 1 - 4
src/views/old_mini/interactionList/index.vue

@@ -281,10 +281,7 @@ const SCROLL_KEY = 'interactionListScrollTop';
 
 const showDroneConsultPopup = ref(false);
 const handleShowDroneConsultPopup = () => {
-    // showDroneConsultPopup.value = true;
-    router.push(
-        `/confirm_area`
-    );
+    showDroneConsultPopup.value = true;
 }
 
 const showFarmInfoPopup = ref(false);

+ 0 - 44
src/views/old_mini/youwei_trace/index.vue

@@ -1,44 +0,0 @@
-<template>
-    <div class="youwei-trace-page" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
-        <empty
-            v-if="!showTraceImg"
-            image="https://birdseye-img.sysuimars.com/birdseye-look-mini/custom-empty-image.png"
-            image-size="80"
-            description="暂无报告"
-            class="trace-empty"
-        />
-        <img v-else class="yw-trace-img" :src="traceImgSrc" alt="">
-    </div>
-</template>
-
-<script setup>
-import { computed } from "vue";
-import { useStore } from "vuex";
-import { Empty } from "vant";
-import { useI18n } from "@/i18n";
-import ywImg from "@/assets/img/common/yw.png";
-import ywEnImg from "@/assets/img/common/yw-en.png";
-
-const store = useStore();
-const { locale } = useI18n();
-const tabBarHeight = computed(() => store.state.home.tabBarHeight);
-const traceImgSrc = computed(() => (locale.value === "en" ? ywEnImg : ywImg));
-const showTraceImg = computed(() => String(store.state.home.gardenId) === "314");
-</script>
-
-<style scoped lang="scss">
-.youwei-trace-page {
-    width: 100%;
-    height: 100%;
-    overflow: auto;
-    box-sizing: border-box;
-
-    .trace-empty {
-        padding-top: 120px;
-    }
-}
-.yw-trace-img {
-    width: 100%;
-    object-fit: cover;
-}
-</style>