From c104bf2b4ecf604245b38590bf1e8119530de10b Mon Sep 17 00:00:00 2001
From: yaowanxin <3588231647@qq.com>
Date: 星期二, 12 八月 2025 16:26:55 +0800
Subject: [PATCH] Merge branch 'ywx' of http://114.132.189.42:9002/r/product-inventory-management into dev_ai

---
 src/views/chatHome/chatHomeIndex/MobileChat.vue |  461 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 461 insertions(+), 0 deletions(-)

diff --git a/src/views/chatHome/chatHomeIndex/MobileChat.vue b/src/views/chatHome/chatHomeIndex/MobileChat.vue
new file mode 100644
index 0000000..5b06e76
--- /dev/null
+++ b/src/views/chatHome/chatHomeIndex/MobileChat.vue
@@ -0,0 +1,461 @@
+<template>
+  <div class="mobile-chat-wrapper" style="height: 91vh;">
+    <div class="chat-history">
+      <div class="chat-content" ref="chatContent">
+        <div class="chat-wrapper" v-for="(item, index) in chatList" :key="index">
+          <div class="chat-friend" v-if="item.uid !== '1001'">
+            <div class="info-time">
+              <img :src="item.headImg" alt="" />
+              <span>{{ item.name }}</span>
+              <span>{{ item.time }}</span>
+            </div>
+            <div class="chat-text" v-if="item.chatType == 0">
+              <template v-if="isSend && index === chatList.length - 1">
+                <span class="flash_cursor"></span>
+              </template>
+              <template v-else>
+                <pre>{{ item.msg }}</pre>
+              </template>
+            </div>
+            <div class="chat-img" v-if="item.chatType == 1">
+              <img :src="item.msg" alt="琛ㄦ儏" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" />
+              <el-image :src="item.msg" :preview-src-list="srcImgList" v-else> </el-image>
+            </div>
+            <div class="chat-img" v-if="item.chatType == 2">
+              <div class="word-file">
+                <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
+              </div>
+            </div>
+          </div>
+          <div class="chat-me" v-else>
+            <div class="info-time">
+              <span>{{ item.name }}</span>
+              <span>{{ item.time }}</span>
+              <img :src="item.headImg" alt="" />
+            </div>
+            <div class="chat-text" v-if="item.chatType == 0">
+              {{ item.msg }}
+            </div>
+            <div class="chat-img" v-if="item.chatType == 1">
+              <img :src="item.msg" alt="琛ㄦ儏" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" />
+              <el-image style="max-width: 300px; border-radius: 10px" :src="item.msg" :preview-src-list="srcImgList" v-else> </el-image>
+            </div>
+            <div class="chat-img" v-if="item.chatType == 2">
+              <div class="word-file">
+                <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="chat-input-wrapper">
+      <div style="display: flex; align-items: center">
+          <input v-model="inputMsg" @change="sendText" :disabled="loading" class="input-text" autofocus placeholder="缁欏皬鏅哄彂閫佹秷鎭�" />
+          <img class="send-icon" src="@/assets/img/emoji/rocket.png" alt="" @click="sendText" />
+
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, nextTick,onActivated } from 'vue'
+import { useRoute } from 'vue-router'
+import { animation } from '@/utils/util'
+import chatGPTHeadImg from '@/assets/img/head_portrait1.png'
+import headPortrait from '@/assets/img/head_portrait.jpg'
+import FileCard from '@/components/FileCard.vue'
+import { ElMessage } from "element-plus"
+import {checking} from './ai-wd.js'
+
+// 瀹氫箟鍝嶅簲寮忔暟鎹�
+const route = useRoute()
+const chatContent = ref(null)
+const ws = ref(null)
+const chatList = ref([
+  {
+    headImg: chatGPTHeadImg,
+    name: '灏忔櫤',
+    time: new Date().toLocaleTimeString(),
+    msg: ' 灏忔櫤涓烘偍鏈嶅姟',
+    chatType: 0,
+    uid: '1002'
+  }
+])
+const inputMsg = ref('')
+const isSend = ref(false)
+const fileList = ref([])
+const isProcessing = ref(false)
+const loading = ref(true)
+const srcImgList = ref([])
+
+// 鍒犻櫎鍥剧墖
+const deleteImg = (index) => {
+  if (index >= 0 && index < fileList.value.length) {
+    fileList.value.splice(index, 1)
+  }
+}
+
+// WebSocket娑堟伅鎺ユ敹
+const websocketonmessage = (e) => {
+  const redata = JSON.parse(e.data)
+  //鏁版嵁鎺ユ敹
+  let chatGPT = {
+    headImg: headPortrait,
+    name: 'DeepSeek',
+    time: new Date().toLocaleTimeString(),
+    msg: redata[0].text,
+    chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖
+    uid: '1002' //uid
+  }
+  sendMsg(chatGPT)
+  isSend.value = false
+}
+
+// WebSocket鍙戦�佹秷鎭�
+const websocketsend = (Data) => {
+  console.log("鍗冲皢鍙戦�佹秷鎭�", Data)
+  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
+    console.log("鍙戦�佹秷鎭�", ws.value)
+    console.log("鍙戦�佹秷鎭�", Data)
+    let fileUrls = fileList.value.map(item => item.file.fileUrl)
+    //鏁版嵁鍙戦��
+    ws.value.send(Data + ":" + fileUrls.join(","))
+    fileList.value = []
+    inputMsg.value = ''
+  }
+}
+
+// 鍙戦�佹枃鏈秷鎭�
+const sendText = () => {
+  if (inputMsg.value) {
+    let chatMsg = {
+      headImg: headPortrait,
+      name: '鍗ч緳',
+      time: new Date().toLocaleTimeString(),
+      msg: inputMsg.value,
+      chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖
+      uid: '1001' //uid
+    }
+    chatList.value.push(chatMsg)
+    let chatGPT = {
+      headImg: headPortrait,
+      name: '灏忔櫤',
+      time: new Date().toLocaleTimeString(),
+      msg: "",
+      chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖
+      uid: '1002' //uid
+    }
+    chatList.value.push(chatGPT) // 灏嗘帴鏀跺埌鐨勬秷鎭瓨鍌ㄥ埌 messages 鏁扮粍
+    simulateStreamingOutput(chatGPT, inputMsg.value)
+    inputMsg.value = ''
+
+  } else {
+    ElMessage({
+      message: '娑堟伅涓嶈兘涓虹┖鍝',
+      type: 'warning'
+    })
+  }
+}
+
+// 鍙戦�佷俊鎭�
+const sendMsg = (msgList) => {
+  chatList.value.push(msgList)
+  scrollBottom()
+}
+
+// 鑾峰彇绐楀彛楂樺害骞舵粴鍔ㄨ嚦鏈�搴曞眰
+const scrollBottom = () => {
+  nextTick(() => {
+    const scrollDom = chatContent.value
+    animation(scrollDom, scrollDom.scrollHeight - scrollDom.offsetHeight)
+  })
+}
+
+// 缁勪欢鎸傝浇鏃舵墽琛�
+onActivated(() => {
+  chatList.value = []
+  chatList.value.push({
+    headImg: chatGPTHeadImg,
+    name: '灏忔櫤',
+    time: new Date().toLocaleTimeString(),
+    msg: '灏忔櫤涓烘偍鏈嶅姟',
+    chatType: 0,
+    uid: '1002'
+  })
+  chatList.value.push({
+    headImg: chatGPTHeadImg,
+    name: '鍗ч緳',
+    time: new Date().toLocaleTimeString(),
+    msg: route.query.keyWord,
+    chatType: 0,
+    uid: '1001'
+  })
+  // 娣诲姞涓�涓┖鐨勫洖澶嶆秷鎭崰浣�
+  const replyMsg = {
+    headImg: chatGPTHeadImg,
+    name: '灏忔櫤',
+    time: new Date().toLocaleTimeString(),
+    msg: '',
+    chatType: 0,
+    uid: '1002'
+  }
+  chatList.value.push(replyMsg)
+  scrollBottom()
+  loading.value = false
+  // 濡傛灉鏈夋煡璇㈠叧閿瓧锛屽垯妯℃嫙娴佸紡杈撳嚭
+  if (route.query.keyWord) {
+    simulateStreamingOutput(replyMsg, route.query.keyWord)
+  }
+})
+// 妯℃嫙娴佸紡杈撳嚭
+const simulateStreamingOutput = async (msgObj, keyWord) => {
+  loading.value = true
+  // 鐢熸垚0.8-1.3绉掍箣闂寸殑闅忔満寤惰繜
+  const delay = Math.random() * 500 + 800
+
+  // 妯℃嫙鍥炲鍐呭锛堝疄闄呭簲鐢ㄤ腑搴斾粠API鑾峰彇锛�
+  const responseText = `鍏充簬"${keyWord}"鐨勯棶棰橈紝鎴戞潵涓烘偍瑙g瓟锛歕n` + checking(keyWord)
+
+  isSend.value = true
+
+  let index = 0
+  setTimeout(() => {
+    const interval = setInterval(() => {
+      isSend.value = true
+      if (index < responseText.length) {
+        msgObj.msg += responseText.charAt(index)
+        index++
+        isSend.value = false
+        scrollBottom()
+      } else {
+        clearInterval(interval)
+        isSend.value = false
+        loading.value = false
+      }
+    }, 50) // 姣�50ms杈撳嚭涓�涓瓧绗︼紝妯℃嫙娴佸紡鏁堟灉
+  }, delay)
+
+}
+</script>
+
+<style lang="scss" scoped>
+.mobile-chat-wrapper {
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  height: 91vh;
+  position: relative;
+  background-color: white;
+
+  .chat-history {
+    flex: 1 1 0;
+    overflow-y: auto;
+  }
+
+  .chat-input-wrapper {
+    padding: 8px 16px 8px 8px;
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+      .file-tt{
+          flex-direction: column;
+          width: 200px;
+          display: flex;
+          padding: 5px;
+          border-radius: 5px;
+          margin-right: 5px;
+          background: #cacaca;
+          .file-item{
+              width: 200px;
+              overflow:hidden;
+              word-wrap: break-word;
+              text-overflow:ellipsis;
+              display:-webkit-box;
+              -webkit-box-orient:vertical;
+              -webkit-line-clamp:2;
+          }
+      }
+
+    .send-icon {
+      height: 40px;
+      margin-left: 16px;
+    }
+      .input-text{
+          font-size: 18px;
+          width: 100%;
+          border-radius: 20px;
+          height: 80px;
+          padding-left: 10px;
+          //padding-top: 10px;
+          border: none;
+          color: black;                 /* 淇敼鏂囨湰棰滆壊涓虹櫧鑹� */
+          background-color: #f5f4f4;   /* 淇敼鑳屾櫙棰滆壊涓烘繁鐏拌壊 */
+      }
+  }
+
+  .chat-content {
+    width: 100%;
+    height: 80%;
+    overflow-y: scroll;
+    padding: 20px;
+    box-sizing: border-box;
+
+    &::-webkit-scrollbar {
+      width: 0;
+      /* Safari,Chrome 闅愯棌婊氬姩鏉� */
+      height: 0;
+      /* Safari,Chrome 闅愯棌婊氬姩鏉� */
+      display: none;
+      /* 绉诲姩绔�乸ad 涓奡afari锛孋hrome锛岄殣钘忔粴鍔ㄦ潯 */
+    }
+
+    .chat-wrapper {
+      position: relative;
+      word-break: break-all;
+
+      .chat-friend {
+        width: 100%;
+        float: left;
+        margin-bottom: 20px;
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: flex-start;
+
+        .chat-text {
+          max-width: 90%;
+          padding: 20px;
+          border-radius: 20px 20px 20px 5px;
+          background-color: rgb(245, 248, 248);
+          color: black;
+
+          &:hover {
+            background-color: rgb(232, 232, 232);
+          }
+
+          pre {
+            white-space: break-spaces;
+          }
+        }
+
+        .chat-img {
+          img {
+            width: 100px;
+            height: 100px;
+          }
+        }
+
+        .info-time {
+          margin: 10px 0;
+          color: black;
+          font-size: 14px;
+
+          img {
+            width: 30px;
+            height: 30px;
+            border-radius: 50%;
+            vertical-align: middle;
+            margin-right: 10px;
+          }
+
+          span:last-child {
+            color: rgb(101, 104, 115);
+            margin-left: 10px;
+            vertical-align: middle;
+          }
+        }
+      }
+
+      .chat-me {
+        width: 100%;
+        float: right;
+        margin-bottom: 20px;
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-end;
+        align-items: flex-end;
+
+        .chat-text {
+          float: right;
+          max-width: 90%;
+          padding: 20px;
+          border-radius: 20px 20px 5px 20px;
+          background-color: rgb(29, 144, 245);
+          color: #fff;
+
+          &:hover {
+            background-color: rgb(26, 129, 219);
+          }
+        }
+
+        .chat-img {
+          img {
+            max-width: 300px;
+            max-height: 200px;
+            border-radius: 10px;
+          }
+        }
+
+        .info-time {
+          margin: 10px 0;
+          color: black;
+          font-size: 14px;
+          display: flex;
+          justify-content: flex-end;
+
+          img {
+            width: 30px;
+            height: 30px;
+            border-radius: 50%;
+            vertical-align: middle;
+            margin-left: 10px;
+          }
+
+          span {
+            line-height: 30px;
+          }
+
+          span:first-child {
+            color: rgb(101, 104, 115);
+            margin-right: 10px;
+            vertical-align: middle;
+          }
+        }
+      }
+    }
+  }
+  .flash_cursor {
+    width: 20px;
+    height: 30px;
+    display: inline-block;
+    background: #d6e3f5;
+    opacity: 1;
+    animation: glow 800ms ease-out infinite alternate;
+  }
+  @keyframes glow {
+    0% {
+      opacity: 1;
+    }
+
+    25% {
+      opacity: 0.5;
+    }
+
+    50% {
+      opacity: 0;
+    }
+
+    75% {
+      opacity: 0.5;
+    }
+
+    100% {
+      opacity: 1;
+    }
+  }
+}
+</style>

--
Gitblit v1.9.3