【vue】Imitate WeChat conversation

Part One: Pull down to refresh

I will write down the main pull-down refresh here. The pull-up is the same, so I won’t write it down.

       <div class="talk_top" ref="listWrapper" id="listWrapper">
            <div class="loadingpic" v-loading="loading"></div>
            <div v-for="message in messages" :key="message.id" class="message">
                <div class="minetext" v-html="message.text"></div>
            </div>
          </div>
<script>
export default {
     data() {
        return {
              loading: false, // 加载中
              messages:[],
        }
     },
     mounted() {
       this.$nextTick(() => {
           this.getAiLogsByTopicId(); // 初始化数据
           this.re();
        });
      },
      methods: {
//这是放在mounted中获取初始数据
   getAiLogsByTopicId() {
      this.$axios
        .get("/userApp/ai/getAiLogsByTopicId", {
          params: {
            TopicId: this.topic.topicId,
            pageNum: 1,
            pageSize: this.page.pageSize
          }
        })
        .then(res => {
          if (res.code === 200) {
            this.messages = res.rows.reverse();
            // console.log(res.rows);
            this.total = Number(res.total);
          }
        });
    },
   //放在re()里面的数据接口
   getlist() {
     if (this.total >= this.messages.length) {
        this.page.pageNum++;
        this.loading = true;
        this.$axios
          .get("/userApp/ai/getAiLogsByTopicId", {
            params: {
              TopicId: this.topic.topicId,
              pageNum: this.page.pageNum,
              pageSize: this.page.pageSize
            }
          })
          .then(res => {
            if (res.code === 200) {
              if (this.page.pageNum >= Number(res.allPage)) {
                this.$message.success("数据到底啦");
                this.loading = false;
                return;
              } else {
                this.messages = [...res.rows.reverse(), ...this.messages];
                this.total = Number(res.total);
                // console.log(this.messages);
                this.loading = false;
              }
            }
          })
          .catch(error => {
            this.$message.error(error.msg);
            this.loading = false;
          });
      } else {
        this.$message.success("数据到底啦");
        // this.showdown = true;
        this.loading = false;
      }
    },
           // 下拉、上拉刷新
    re() {
      var flag = false;
      var PstartX;
      var PstartY;
      var PMoveX;
      var PMoveY;
      var PendX;
      var PendY;
      let that = this;
      document.onmousedown = function(ev) {
        flag = true;
        PstartX = ev.pageX;
        PstartY = ev.pageY;
        // console.log("start:" + PstartX, PstartY);
        document.onmousemove = function(ev) {
          PMoveX = ev.pageX;
          PMoveY = ev.pageY;
          if (flag) {
            // console.log("move:" + PMoveX, PMoveY);
            var resutl = getpostion(PMoveY, PstartY);
            switch (resutl) {
              case 0:
                // console.log("无操作");
                break;
              case 1:
                // console.log("向上");
                break;
              case 2:
                // console.log("向下");
                if (PMoveY - PstartY > 0) {
                  if (PMoveY - PstartY >= 50) {
                    document.getElementById("listWrapper").style.marginTop =
                      PMoveY - PstartY + "px";
                  }
                  that.loading = true;
                  // document.getElementById("loadingpic").style.display = "block";
                }
                break;
            }
          }
        };
        document.onmouseup = function(ev) {
          flag = false;
          PendX = ev.pageX;
          PendY = ev.pageY;
          // console.log("end:" + PendX, PendY);
          var resutl = getpostion(PMoveY, PstartY);
          switch (resutl) {
            case 0:
              // console.log("无操作");
              break;
            case 1:
              // console.log("向上");
              break;
            case 2:
              // console.log("向下");
              // location.reload();
              setTimeout(() => {
                that.getlist(); //调用接口
                //回弹到初始位置
                document.getElementById("listWrapper").style.marginTop = "0px";
              }, 500);
              break;
          }
        };
        // 判断是上拉还是下拉
        function getpostion(PMoveY, PstartY) {
          if (PMoveY - PstartY == 0) {
            return 0; //无操作
          }
          if (PMoveY - PstartY < 0) {
            return 1; //向上
          }
          if (PMoveY - PstartY > 0) {
            return 2; //向下
          }
        }
      };
    },
      }
}
</script>

I modified it based on his work, but there are some minor problemshttps://www.cnblogs.com/zmcxsf/p/10443189.html

Part Two: Scroll Bar to Bottom

1. Call the interface data, and then call the re() method. If the re method is not called, the page will not respond.

2. Get the document of the scrolling area in mounted, and then call the method to scroll the box to the bottom, so that as soon as the page is opened, the scroll bar will be at the bottom.

3. Monitor scrolling events and determine the user’s scrolling status

<template>
  <div class="chat">
    <div class="center">
      <div v-if="pasId === 0">
        <div class="talk_history" id="chat">
          <div class="talk_top" ref="listWrapper" id="listWrapper">
            <div class="loadingpic" v-loading="loading"></div>
            <div v-for="message in messages" :key="message.id" class="message">
             。。。。内容
            </div>
          </div>
        </div>
        <div class="talk_huifu">
          <div style="border-bottom:1px solid #f8f8f8;display:flex">
            <el-upload
              ref="upload"
              class="upload-demo"
              action="https://jsonplaceholder.typicode.com/posts/"
              :show-file-list="false"
              :file-list="fileList"
              accept=".pdf"
              :on-change="talkchange"
              :http-request="http"
            >
              <img
                style="margin:0 15px 0 10px"
                src="../../assets/img/wenjianjia.png"
                title="发送文件"
              />
            </el-upload>
          </div>
          <div align="right">
            <el-input
              type="textarea"
              v-model="talk"
              :maxlength="4000"
              :rows="3"
              resize="none"
              placeholder="有什么我可以帮您?"
            ></el-input>
            <el-button size="medium" :disabled="disabled" @click="sub(0)"
              >发送</el-button
            >
          </div>
        </div>
      </div>
  </div>
</template>

<script>
let source = null;
var AIurl = "http://192.168.4.172:8081/userApp/ai/sse";
var resultUrl = "http://192.168.4.172:8081/userApp/ai/aiHelp";

import { EventSourcePolyfill } from "event-source-polyfill";
export default {
  layout: "AI2",
  name: "",
  data() {
    return {
      disabled: false, //ai回答结束,按钮取消禁用
      showdown: false, //数据到底啦
      chatContent: null,
      isScrolling: true,
      loading: false, // 加载中
      page: 1,
      total: 0, //总条数
      
      talk: "", //发送的聊天信息
      len: true, //发送信息的次数
      fileList: [], //发送文件
      topic: {}, //新建对话的信息
      word: {}, //文件的信息
      messages: [], //聊天历史
      page: {
        pageNum: 0,
        pageSize: 10
      },
      total: 0,

      pasId: 0, //上一页的id
    };
  },
  mounted() {
      this.getAiLogsByTopicId(); // 初始化数据
      this.re();
      setTimeout(() => {
        this.chatContent = document.getElementsByClassName("talk_top")[0];
        this.scrollToBottom();
        // 监听滚动事件,判断用户滚动状态
        this.chatContent.addEventListener("scroll", this.handleScroll);
      }, 1000);
  },
  watch: {
    disabled: {
      handler(newval, oldval) {
        this.disabled = newval;
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    // 定义将滚动条定位在底部的方法
    scrollToBottom() {
      var that = this;
      this.$nextTick(() => {
        if (that.isScrolling) {
          that.chatContent.scrollTop =
            that.chatContent.scrollHeight - that.chatContent.offsetHeight;
          // console.log(that.chatContent.scrollTop);
        }
      });
    },
    handleScroll() {
      const scrollContainer = this.chatContent;
      const scrollTop = scrollContainer.scrollTop;
      const scrollHeight = scrollContainer.scrollHeight;
      const offsetHeight = scrollContainer.offsetHeight;

      if (scrollTop + offsetHeight < scrollHeight) {
        // 用户开始滚动并在最底部之上,取消保持在最底部的效果
        this.isScrolling = true;
      } else {
        // 用户停止滚动并滚动到最底部,开启保持到最底部的效果
        this.isScrolling = false;
      }
    },
    
    // 发送对话---------------------------------------------------
    // 加载数据对话
    getAiLogsByTopicId() {
      this.$axios
        .get("/userApp/ai/getAiLogsByTopicId", {
          params: {
            TopicId: this.topic.topicId,
            pageNum: 1,
            pageSize: this.page.pageSize
          }
        })
        .then(res => {
          if (res.code === 200) {
            this.messages = res.rows.reverse();
            // console.log(res.rows);
            this.total = Number(res.total);
          }
        });
    },
    getlist() {
      if (this.total >= this.messages.length) {
        this.page.pageNum++;
        this.loading = true;
        this.$axios
          .get("/userApp/ai/getAiLogsByTopicId", {
            params: {
              TopicId: this.topic.topicId,
              pageNum: this.page.pageNum,
              pageSize: this.page.pageSize
            }
          })
          .then(res => {
            if (res.code === 200) {
              if (this.page.pageNum >= Number(res.allPage)) {
                this.$message.success("数据到底啦");
                this.loading = false;
                return;
              } else {
                this.messages = [...res.rows.reverse(), ...this.messages];
                this.total = Number(res.total);
                // console.log(this.messages);
                this.loading = false;
              }
            }
          })
          .catch(error => {
            this.$message.error(error.msg);
            this.loading = false;
          });
      } else {
        this.$message.success("数据到底啦");
        // this.showdown = true;
        this.loading = false;
      }
    },
    // 下拉、上拉刷新
    re() {
      var flag = false;
      var PstartX;
      var PstartY;
      var PMoveX;
      var PMoveY;
      var PendX;
      var PendY;
      let that = this;
      document.onmousedown = function(ev) {
        flag = true;
        PstartX = ev.pageX;
        PstartY = ev.pageY;
        // console.log("start:" + PstartX, PstartY);
        document.onmousemove = function(ev) {
          PMoveX = ev.pageX;
          PMoveY = ev.pageY;
          if (flag) {
            // console.log("move:" + PMoveX, PMoveY);
            var resutl = getpostion(PMoveY, PstartY);
            switch (resutl) {
              case 0:
                // console.log("无操作");
                break;
              case 1:
                // console.log("向上");
                break;
              case 2:
                // console.log("向下");
                if (PMoveY - PstartY > 0) {
                  if (PMoveY - PstartY >= 50) {
                    document.getElementById("listWrapper").style.marginTop =
                      PMoveY - PstartY + "px";
                  }
                  that.loading = true;
                  // document.getElementById("loadingpic").style.display = "block";
                }
                break;
            }
          }
        };
        document.onmouseup = function(ev) {
          flag = false;
          PendX = ev.pageX;
          PendY = ev.pageY;
          // console.log("end:" + PendX, PendY);
          var resutl = getpostion(PMoveY, PstartY);
          switch (resutl) {
            case 0:
              // console.log("无操作");
              break;
            case 1:
              // console.log("向上");
              break;
            case 2:
              // console.log("向下");
              // location.reload();
              setTimeout(() => {
                that.getlist(); //调用接口
                //回弹到初始位置
                document.getElementById("listWrapper").style.marginTop = "0px";
              }, 500);
              break;
          }
        };
        // 判断是上拉还是下拉
        function getpostion(PMoveY, PstartY) {
          if (PMoveY - PstartY == 0) {
            return 0; //无操作
          }
          if (PMoveY - PstartY < 0) {
            return 1; //向上
          }
          if (PMoveY - PstartY > 0) {
            return 2; //向下
          }
        }
      };
    },
    
    sub(type) {
      let that = this;
      // 判断次数,在发送
      if (type === 1) {
        this.messages.push({
          aiId: "", //编号
          userId: "", //用户id
          userAsk: "", //用户询问
          aiReply: "", //ai回复
          askTime: "", //询问时间
          isPdf: true, //是否是pdf
          fileName: this.word.fileName, //文件名称
          fileSize: this.word.fileSize, //文件大小
          aiTopicId: this.topic.topicId //话题编号
        });
        this.$message.success("请稍等,正在响应中");
        this.load(this.messages[this.messages.length - 1], 1, that.chatContent);//调用接口
         setTimeout(() => {
            that.chatContent.scrollTop = that.chatContent.scrollHeight + 150;
          }, 500);
        this.word = {};
      } else {
        if (this.talk === "") {
          this.$message.error("请填写内容");
        } else {
          this.messages.push({
            aiId: "", //编号
            userId: "", //用户id
            userAsk: this.talk, //用户询问
            aiReply: "", //ai回复
            askTime: "", //询问时间
            isPdf: false, //是否是pdf
            fileName: null, //文件名称
            fileSize: null, //文件大小
            aiTopicId: this.topic.topicId //话题编号
          });
          this.$message.success("请稍等,正在响应中");
          this.load(
            this.messages[this.messages.length - 1],
            0,
            that.chatContent
          );
           setTimeout(() => {
            that.chatContent.scrollTop = that.chatContent.scrollHeight + 150;
          }, 500);
        }
        this.talk = "";
      }
    },
    // 获取ai结果
    load(item, type, chatContent) {
      this.disabled = true;
      if (type === 1) {
        source = new EventSourcePolyfill(
          Url +
            "userApp/ai/sse?question=" +
            this.word.fileDownloadPath +
            "&fileName=" +
            this.word.fileName +
            "&fileSize=" +
            this.word.fileSize +
            "&isPdf=true&aiTopicId=" +
            this.topic.topicId,
          {
            headers: {
              token: this.$cookies.get("userToken")
            }
          }
        );
      } else {
        source = new EventSourcePolyfill(
          Url +
            "userApp/ai/sse?question=" +
            this.talk +
            "&isPdf=false&aiTopicId=" +
            this.topic.topicId,
          {
            headers: {
              token: this.$cookies.get("userToken")
            }
          }
        );
      }
      // open:订阅成功(和后端连接成功)
      source.addEventListener("open", function(e) {});
      source.onmessage = e => {
        // console.log(JSON.parse(e.data));
        if (JSON.parse(e.data).end) {
          // 结束了
          item.aiId = JSON.parse(e.data).end;
          this.disabled = false;
          return;
        } else if (JSON.parse(e.data).error) {
          this.$message.error(JSON.parse(e.data).error);
          this.disabled = false;
          return;
        } else {
          item.aiReply += JSON.parse(e.data).content.replace(/\\n/g, "\n");
          if (this.isScrolling) {
            chatContent.scrollTop = chatContent.scrollHeight;
          }
        }
      };
      source.onerror = event => {
        if (event.error !== undefined) {
          this.$message.error("出错了,请联系客服人员");
        }
        this.disabled = false;
        event.target.close();
      };
    },
    // 上传文件
    talkchange(file, fileList) {
      this.$refs.upload.uploadFiles = [];
      this.fileList = [];
      this.fileList = fileList;
    },
    async http(file, fileList) {
      var formData = new FormData();
      formData.append("files", file.file);
      this.$axios.post("/dev/file/uploadFile", formData).then(res => {
        if (res.code === 200) {
          this.word = {
            fileName: res.data[0].fileName,
            fileSize: res.data[0].fileSize,
            fileDownloadPath: res.data[0].fileDownloadPath
          };
          // this.$message.success("上传成功");
          this.sub(1);
        }
      });
    },
  }
};
</script>

Guess you like

Origin blog.csdn.net/Qxn530/article/details/132761311