From 089bf5d2378b3c4a61d795b2a92bede2c193b771 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 06 Jan 2026 11:22:58 +0800
Subject: [PATCH] 1

---
 src/components/chat2/index.vue |  548 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 548 insertions(+), 0 deletions(-)

diff --git a/src/components/chat2/index.vue b/src/components/chat2/index.vue
new file mode 100644
index 0000000..b347ccb
--- /dev/null
+++ b/src/components/chat2/index.vue
@@ -0,0 +1,548 @@
+<template>
+  <div class="chat" v-loading="loading">
+    <el-scrollbar style="height: 500px" ref="scroll">
+      <div
+        class="history"
+        @click="onMore"
+        :style="{ visibility: finished ? 'hidden' : 'visiable' }"
+      >
+        历史记录
+      </div>
+      <!-- 对话框消息 -->
+      <ul>
+        <li v-for="(item, index) in chatList" :key="item.id">
+          <!-- v-if="showTime(index)" -->
+          <p class="date">
+            {{ item.createtime}}
+          </p>
+
+          <div
+            class="content-box"
+            :class="
+              item.send_receive === 'receive' ? 'justify-end' : 'justify-start'
+            "
+          >
+            <!-- 机器人消息 -->
+            <template v-if="item.send_receive === 'receive'">
+              <div
+                class="responser bg-grey px-50 py-35 font-30 rounded-lg font-26"
+                style="background: #1ebafc;color: #fff;" 
+              >
+              <span style="font-size: 13px;margin-right: 10px;margin-top: 10px;">{{ item.delete_status == -1 ? '已撤回' :
+                item.is_read == 1 ? '已读' : '未读' }}</span>
+                <p
+                  class="break-words"
+                  style="max-width: 300px;background: #1ebafc;color: #fff;"
+                  v-if="item.type === 'text'"
+                >
+                  {{ item.content }}
+                </p>
+                <!-- <img v-else :src="item.content" class="w-200 h-200" @click="onPreview(item.content)"/> -->
+                <el-image
+                  v-if="item.type === 'img' && !status[item.id] "
+                  src="./load.png"
+                  class="w-200 h-200"
+                  @click="openLoad(`${item.id}`)"
+                ></el-image>
+                <el-image
+                  v-if="item.type === 'img' && status[item.id] == 2 "
+                  :src="item.content"
+                  class="w-200 h-200"
+                  @click="open(`${item.content}`)"
+                ></el-image>
+
+                <div class="loading" v-if="status[item.id]==1"></div>
+
+              </div>
+              <img src="./responser.png" class="avatar" style="margin-left: 20px;"/>
+            </template>
+            <!-- 用户消息 -->
+            <template v-else>
+              <img src="./avatar1.png" class="avatar" style=""/>
+              <div class="responser" >
+                
+                <div>
+                  <el-image
+                    src="./load.png"
+                    class="w-200 h-200"
+                    :preview-src-list="[item.content]"
+                    v-if="item.type === 'img' && !status[item.id] "
+                    @click="openLoad(`${item.id}`)"
+                  ></el-image>
+
+                  <el-image
+                    :src="`${item.content}`"
+                    class="w-200 h-200"
+                    :preview-src-list="[item.content]"
+                    v-if="item.type === 'img' && status[item.id] == 2"
+                    @click="open(`${item.content}`)"
+                  ></el-image>
+                  <div class="loading" v-if="status[item.id] == 1"></div>
+
+                  <p class="break-words" v-if="item.type === 'text'" style="max-width: 300px">
+                    {{ item.content }}
+                  </p>
+                </div>
+        
+              </div>
+            </template>
+
+          </div>
+        </li>
+      </ul>
+    </el-scrollbar>
+    <div class="input-box">
+      <img src="./photo.png" class="w-72 h-72" @click="test" />
+      <input
+        ref="upload"
+        type="file"
+        hidden
+        @change="onImageFileChanged"
+        accept="image/png, image/gif, image/jpeg, image/bmp, image/x-icon"
+      />
+      <input
+        ref="input"
+        type="text"
+        v-model="value"
+        placeholder="请输入您的消息..."
+        class="flex-1 mx-20 h-full border-none"
+      />
+      <!-- <el-input v-model="value" placeholder="请输入内容"></el-input> -->
+      <img v-if="this.$store.state.talks.sendStatus == 0" src="./send.png" class="w-72 h-72" @click="send('text', value)" />
+      <div v-if="this.$store.state.talks.sendStatus == 1" class="loading2"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { _sendMsg, _getMsg, _uploadImage ,uploadImageChange} from "@/api/chat.api";
+import { openImage} from "@/common/image";
+export default {
+  name: "Chat",
+  data() {
+    return {
+      allChatList: [],
+      chatList: [],
+      value: "", //客服输入的消息
+      lastMsgId: "",
+      interval: null,
+      unread: 0,
+      loading: false,
+      finished: false, // 没有历史消息
+      msg:{},
+      order_no:0,
+      isShow:false,
+      lastId:"",
+      status:{}
+    };
+  },
+  created() {
+    
+    // const model=navigator.userAgent;
+    // 判断是否是安卓手机,是则是true
+    // this.androidAttrs=model.indexOf('Android') > -1 || model.indexOf('Linux') >-1
+    // _getMsg().then(data => {
+    //     console.log(data)
+    // })
+  },
+  beforeDestroy() {
+    this.clearInterval();
+    this.isShow = false;
+  },
+  methods: {
+    // onPreview(url) { // 预览
+    //     ImagePreview([url])
+    // },
+    openLoad(id){
+      this.status[id] = 1;
+     let timer = setTimeout(() => {
+        clearTimeout(timer);
+        this.status[id] = 2;
+      },1500)
+    },
+    open(img) {
+      openImage(img);
+    },
+    close(){
+      this.isShow = false;
+      this.order_no = 0;
+      this.clearInterval();
+      this.chatList = [];
+      this.allChatList = [];
+    },
+    init(msg1){
+      this.isShow = true;
+      this.clearInterval();
+      this.chatList = [];
+      this.order_no = msg1.order_no || 0;
+      this.msg = msg1;
+      this.fetchList();
+      console.log("index = " + JSON.stringify(this.msg));
+    },
+    test() {
+      this.$refs["upload"].click();
+      console.log(111);
+    },
+    showTime(index) {
+      // 时间显示
+      if (index === 0) {
+        return true;
+      }
+      if (index === this.chatList.length - 1) {
+        return false;
+      }
+      if (
+        this.chatList[index].createtime.split(" ")[0] ===
+        this.chatList[index + 1].createtime.split(" ")[1]
+      ) {
+        return false;
+      }
+    },
+    onImageFileChanged(e) {
+      const file = e.target.files[0];
+      const isLt2M = file.size / 1024 / 1024 < 2;
+      if (!isLt2M) {
+          Toast.fail('上传头像图片大小不能超过 2MB!');
+          return false;
+      }
+      this.afterRead(file);
+    },
+    afterRead(file) {
+      // 文件上传
+      this.loading = true;
+      uploadImageChange(file,(url)=>{
+        if(!url){
+          this.loading = false;
+          return;
+        }
+        _sendMsg("img", url,this.msg.order_no||"",this.msg.party_id||"").then((data) => {
+          console.log(data.code)
+          console.log("已经发送消息了", data);
+          this.value = "";
+          this.scrollToBottom();
+          // document.getElementById('bottom').click()
+          this.fetchList();
+          this.loading = false;
+        });
+      })
+      // _uploadImage(file, (percent) => {
+      //   console.log(percent);
+      // })
+      //   .then((data) => {
+      //     this.loading = false;
+      //     this.send("img", data);
+      //   })
+      //   .catch(() => {
+      //     this.loading = false;
+      //   });
+    },
+    fetchList(message_id = "") {
+      // 获取消息列表
+      _getMsg(message_id,this.msg.order_no||"",this.msg.party_id||"").then((data1) => {
+        if(this.msg.order_no != this.order_no){
+          this.chatList = [];
+        }
+        let data = data1.data;
+        // console.log("获取消息列表 = " + JSON.stringify(data));
+        // this.lastMsgId
+        if (!this.lastMsgId) {
+          this.lastMsgId = data.length && data[data.length - 1]["id"];
+        }
+        //
+        if (data.length) {
+          if(!this.allChatList[this.msg.order_no]){
+            this.allChatList[this.msg.order_no] = [];
+          }
+          if (message_id) {
+            // 加载更多
+            this.lastMsgId = data[data.length - 1]["id"];
+            this.allChatList[this.msg.order_no] = [...data.reverse(), ...this.allChatList[this.msg.order_no]];
+          } else {
+            this.allChatList[this.msg.order_no] = [...this.allChatList[this.msg.order_no], ...data.reverse()];
+            let hash = {};
+            this.allChatList[this.msg.order_no] = this.allChatList[this.msg.order_no].reduce(function (preVal, curVal) {
+              hash[curVal.id]
+                ? " "
+                : (hash[curVal.id] = true && preVal.push(curVal));
+              return preVal;
+            }, []);
+          }
+          this.chatList = [...this.allChatList[this.msg.order_no]]
+          if (data.length < 10) {
+            this.finished = true;
+          }
+        } else {
+          this.chatList = [
+            // {
+            //   id: "1",
+            //   send_receive: "receive",
+            //   content: "你好,欢迎来到我们的数字货币平台!",
+            //   type: "text",
+            // },
+          ];
+        }
+        if (!message_id) {
+          this.clearInterval();
+          console.log("this.isShow = " + this.isShow);
+          if(this.isShow){
+            this.interval = setInterval(() => {
+              this.fetchList();
+            }, 1000);
+          }
+        }
+        if (!this.lastMsgId) {
+          this.scrollToBottom();
+        }
+        if(data.length > 0){
+          if(this.lastId!=data[data.length - 1]["id"]){
+            this.lastId = data[data.length - 1]["id"];
+            this.scrollToBottom();
+            if(data[data.length - 1]["send_receive"] != "receive"){
+              this.playAudioOfMute();
+            }
+          }
+        }
+        
+      });
+    },
+    scrollToBottom() {
+      let timer = setTimeout(() => {
+        clearTimeout(timer);
+        this.$nextTick(() => {
+        this.$refs["scroll"].wrap.scrollTop = 20000000;
+      });
+      }, 500);
+      // this.$nextTick(() => {
+      //   let scrollElem = this.$refs.scroll;
+      //   scrollElem.scrollTo({ top: scrollElem.scrollHeight, behavior: 'smooth' });
+      // });
+    },
+    onMore() {
+      // 加载更多
+      this.fetchList(this.lastMsgId);
+    },
+    clearInterval() {
+      if (this.interval) {
+        clearInterval(this.interval);
+        this.interval = null;
+      }
+    },
+    fetchUnread() {
+      // 获取未读
+      _getUnreadMsg(this.msg.order_no||"",this.msg.party_id||"").then((data) => {
+        this.unread = data;
+        // console.log(data)
+      });
+    },
+    send(type = "text", content = "") {
+      // 发送消息, img 也当消息text
+      if (!content) {
+        const text = "请输入消息内容";
+        this.$message(text);
+        return;
+      }
+      if(this.$store.state.talks.sendStatus == 1){return;}
+      this.$store.commit('SET_SEND_STATUS', 1)
+      let timer = setTimeout(() => {
+            clearTimeout(timer);
+            this.$store.commit('SET_SEND_STATUS', 0);
+        },5000);
+      _sendMsg(type, content,this.msg.order_no||"",this.msg.party_id||"").then((data) => {
+        console.log("已经发送消息了", data);
+        this.$store.commit('SET_SEND_STATUS', 0)
+        this.value = "";
+        this.scrollToBottom();
+        // document.getElementById('bottom').click()
+        this.fetchList();
+      });
+    },
+  },
+  beforeDestroy() {
+    this.clearInterval();
+    this.isShow = false;
+  },
+};
+</script>
+
+<style scoped>
+/deep/ .el-scrollbar .el-scrollbar__wrap {
+  /* height: 620px; */
+  overflow-x: hidden;
+}
+
+.w-100 {
+  width: 200px;
+}
+.h-200 {
+  height: 200px;
+}
+.date {
+  text-align: center;
+  padding: 5px 0;
+  /* color: #fff; */
+  color:#000;
+}
+.justify-end {
+  justify-content: flex-end;
+}
+.chat {
+  width: 100%;
+  display: flex;
+  height: 100%;
+  flex-direction: column;
+}
+.history {
+  padding: 10px 0;
+  text-align: center;
+  width: 160px;
+  height: 40px;
+  line-height: 30px;
+  background: #f0f0f0;
+  margin: 0 auto;
+  cursor: pointer;
+  border-radius: 10px;
+  margin-top: 10px;
+}
+.history:hover {
+  background: #a8d3ec;
+  color: #fff;
+}
+ul {
+  /* display: flex; */
+  flex: 1;
+  /* overflow-y: scroll; */
+  /* flex-direction: column; */
+}
+ul li {
+  display: flex;
+  margin-bottom: 10px;
+  flex-direction: column;
+}
+ul li .content-box {
+  display: flex;
+  padding: 15px 10px;
+  width: 100%;
+  box-sizing: border-box;
+}
+ul li .content-box .avatar {
+  width: 40px;
+  height: 40px;
+  margin-right: 10px;
+}
+
+ul li .content-box .responser {
+  position: relative;
+  background: #f0f0f0;
+  padding: 10px 20px;
+  border-radius: 10px;
+}
+
+ul li .content-box.justify-end {
+  padding-right: 20px;
+}
+ul li .content-box.justify-end .responser::after {
+  content: "";
+  width: 0;
+  height: 0;
+  border-top: 10px solid transparent;
+  border-bottom: 10px solid transparent;
+  position: absolute;
+  top: 10px;
+  border-left: 20px solid #1ebafc;
+  right: -10px;
+  /* background-color: #1ebafc; */
+  color: #1ebafc;
+}
+
+ul li .content-box.justify-start .responser::after {
+  content: "";
+  width: 0;
+  height: 0;
+  border-top: 10px solid transparent;
+  border-bottom: 10px solid transparent;
+  border-right: 20px solid #f3f3f3;
+  position: absolute;
+  left: -10px;
+  top: 10px;
+}
+
+ul li .content-box .responser .break-words {
+  font-size: 16px;
+  color: #000;
+  word-break: break-all;
+}
+.input-box {
+  height: 50px;
+  border-top: 1px solid #f0f0f0;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  box-sizing: border-box;
+  padding: 0 10px;
+  position: relative;
+  z-index: 2;
+}
+.input-box input {
+  flex: 1;
+  height: 100%;
+  border: none;
+  outline: none;
+  padding-left: 5px;
+}
+.input-box img {
+  width: 35px;
+  height: 35px;
+}
+</style>
+
+<style>
+.loading {
+  position: relative;
+  width: 200px;
+  height: 200px;
+  border: 2px solid #000;
+  border-top-color: rgba(0, 0, 0, 0.2);
+  border-right-color: rgba(0, 0, 0, 0.2);
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  border-radius: 100%;
+
+  animation: circle infinite 0.75s linear;
+}
+
+@keyframes circle {
+  0% {
+    transform: rotate(0);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+
+.loading2 {
+  position: relative;
+  left: 0%;
+  top: 0%;
+  width: 33px;
+  height: 33px;
+  border: 2px solid #000;
+  border-top-color: rgba(0, 0, 0, 0.2);
+  border-right-color: rgba(0, 0, 0, 0.2);
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  border-radius: 100%;
+
+  animation: circle infinite 0.75s linear;
+}
+
+@keyframes circle {
+  0% {
+    transform: rotate(0);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+
+
+</style>
\ No newline at end of file

--
Gitblit v1.9.3