vue 加 websocket 聊天

<template>
  <div style="height: 100%; width: 100%; background-color: #fff">
    <div class="wrap">
      <!-- 头部 -->
      <div class="titleBox">
        <img
          src="@/assets/image/avatar.png"
          style="argin: 10px 20px 10px 20px;width: 40px;height: 40px;"
          class="head_portrait"
        />
        <span style="color: #fff;font-size: 15px;">官方客服</span>

      </div>
      <!-- 底部 -->
      <div class="infoBox">
        <!-- 左边用户列表 -->
        <div class="userList">
          <div class="searchBox">
            <el-input  placeholder="请输入内容" v-model="search" class="input-with-select" size="mini" @input="inquire">
              <i  class="el-icon-search el-input__icon" slot="suffix" @click="handleIconClick"  />
            </el-input>
<!--            <el-button-->
<!--              icon="el-icon-plus"-->
<!--              size="mini"-->
<!--              type="primary"-->
<!--              @click="dialogVisible = true"-->
<!--            ></el-button>-->
          </div>
          <div class="userListBox" ref="scrollUserBox" id="userBox">

            <div v-if="list!=null && list.length > 0"  v-for="(item, index) in list" :key="index"
              @click="getAct(item, index)" :class="item.opposUserId == act ? 'userFlexAct' : 'userFlex'" >
              <el-badge :hidden="item.unreadCount ==0" :value="item.unreadCount" :max="99" class="item">
                <div>
                  <img  :src="item.avatar"   class="head_portrait2"  style="margin-left: 20px ; "  />
                </div>
              </el-badge>
              <div style="margin-right: 10px;"></div>
              <div style="margin-right: 40px">
                <div style="color: #565656" class="nickName">
                  {
  { item.nickName }}
                </div>
                <div class="userInfo" v-if="item.messageType==1" >{
  {item.message}}</div>
                <div class="userInfo" v-if="item.messageType==2" >[商品]</div>
                <div class="userInfo" v-if="item.messageType==3" >[图片]</div>
                <div class="userInfo" v-if="item.messageType==4" >[订单]</div>
              </div>
              <div style="margin-right: 10px; font-size: 14px; color: #ccc">
                {
  { formatDate(item.createTime) }}
              </div>


            </div>
          </div>
        </div>
        <!-- 右边输入框和信息展示 -->
        <div class="infoList">
          <!-- 信息 -->
          <div class="infoTop" ref="scrollBox" id="box">
            <div  v-for="(item, index) in info" :key="index">
              <!-- 显示时间信息 -->
              <div class="chatInfoRight1 " v-if="shouldShowTime(index)">
                {
  { formatDate1(item.createTime) }}
              </div>
              <div :class="(item.fromUserId == item.userId && item.fromUserType != 1) ?   'chatInfoRight' :'chatInfoLeft' ">
<!--                <img :src="item.avatar" alt="头像" class="head_portrait2" />-->
                <img :src="(item.fromUserId == item.userId && item.fromUserType != 1) ?  require('@/assets/image/avatar.png') : item.avatar" class="head_portrait2" style="margin-left: 20px;" />

                <div :class="(item.fromUserId == item.userId && item.fromUserType != 1) ?  'chatRight' : 'chatLeft'">
                  <!-- 文字 -->
                  <div class="text" v-if="item.messageType==1" >{
  {item.message}}</div>
                  <!-- 商品 -->
                  <div v-if="item.messageType==2" class="text">
                    <!--                  @click="openUrl(`/pages/goodsDetail?id=${parseMessage(item.message).productId}`)"-->
                    <div class="goods1"
                         style="width: 200px;height: 70px;margin: 0 auto;background-color: #FFF;display: flex; ">
                      <image-preview :src="item.message" :width="60" :height="60"/>
                      <div class="right1"
                           style="flex: 1;margin: auto 0;height: 60px;margin-left: 10px;">
                        <div style="color: #333;height: 30px;line-height: 30px;     font-size: 14px; " class="right_title">
                          {
  {parseMessage(item.message).productName}}
                        </div>
                        <div style="height: 30px;color: #ff0000;line-height: 30px;    font-size: 12px;">
                          ¥{
  {parseMessage(item.message).merchantPrice}}</div>
                      </div>
                    </div>
                  </div>
                  <!-- 图片 -->
                  <div v-if="item.messageType==3" class="text">
                    <image-preview :src="item.message" :width="70" :height="70"/>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <!-- 输入框 -->
          <div class="infoBottom">
            <div class="infoIcon">
              <mesImg v-if='isshow==1?true:false'  v-model="imgUrl"/>
<!--              <i @click="extend('发送商品')" class="el-icon-sell"></i>-->
<!--              <i @click="extend('设置')" class="el-icon-setting"></i>-->
<!--              <i @click="extend('聊天记录')" class="el-icon-chat-dot-round"></i>-->
<!--              <i @click="extend('更多选项')" class="el-icon-more-outline"></i>-->
            </div>
            <textarea   maxlength="255"
                      show-word-limit
              type="textarea"
              class="infoInput"
              v-model="textarea"
              @keydown.enter.exact="handlePushKeyword($event)"
              @keyup.ctrl.enter="lineFeed"
              :disabled='isshow==1?false:true'
            />
            <div class="fasong" @click="setUp(1)" v-show="isshow==1?true:false">发送</div>
          </div>
        </div>
      </div>
    </div>
    <!-- 搜索框边 + 号弹框 -->
    <el-dialog
      title="选择需要添加的联系人"
      :visible.sync="dialogVisible"
      width="30%"
      :modal="false"
    >
      <span>自定义页面,还没想好写什么功能</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false"
        >确 定</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import {getMesList,getMesInfo} from "@/api/ums/umsUser";
import axios from 'axios'
export default {
  watch: {
    imgUrl(newVal, oldVal) {
      if (newVal) {
        this.textarea =this.$constants.baseURL + this.imgUrl;
        this.setUp(3);
      }
    },

  },
  data() {
    return {
      socket: null,
      imgUrl: "",
      queryParams:{
        pageNum: 1,
        pageSize: 10,
        userId:this.$store.getters.userId,
        userType:2,
      },
      queryParamsUser:{
        pageNum: 1,
        pageSize: 10,
        userId:this.$store.getters.userId,
        userType:2,
      },
      // 在线状态
      state: 1,
      //搜索用户
      search: "",
      user: "",
      info: [],
      list:[],
      total:0,
      userIdserTotal:0,

      //用户点击选中变色
      act: Number,
      // 加号弹框
      dialogVisible: false,
      //历史信息
      userInfoList: [],
      //输入框
      textarea: "",
      //滚动条距离顶部距离
      scrollTop: 0,
      //滚动条距离顶部距离
      scrollUserTop: 0,
      //发送和输入显隐
      isshow:0
    };
  },
  created() {
    this.socket = new WebSocket('ws://192.168.1.140:9092/front/websocket/2:'+this.$store.getters.userId); // 替换成你的WebSocket服务器地址
    this.socket.onmessage = this.handleMessage;
    this.handleMesList()
      // this.setUserPageScrollTo()
  },
  methods: {
    // 计算是否显示时间信息的函数
    shouldShowTime(index) {
      if (index === 0) {
        return true; // 第一条消息肯定要显示时间信息
      }
      const currentItem = this.info[index];
      const prevItem = this.info[index - 1];
      const currentTime = new Date(currentItem.createTime);
      const prevTime = new Date(prevItem.createTime);
      const timeDiff = currentTime - prevTime; // 计算时间差,单位为毫秒
      const minutesDiff = Math.floor(timeDiff / 1000 / 60); // 转换为分钟
      return minutesDiff >= 3; // 如果时间差大于等于3分钟,则显示时间信息
    },
    // 解析消息字符串为对象
    parseMessage(message) {
      try {
        return JSON.parse(message);
      } catch (error) {
        console.error("Error parsing message:", error);
        return {}; // 返回空对象以避免渲染错误
      }
    },
    handleMessage(event) {
      try {
        const message = JSON.parse(event.data);
        // 判断发的信息是不是当前会话
        if (this.user.opposUserId == message.userId){
          this.getAct(this.user);
        }else {
          this.queryParams.pageNum = 1
          this.handleMesList();
        }
        // 处理收到的消息
        // 例如,将消息添加到相应的聊天记录中
      } catch (error) {
        // console.error('Received message is not in JSON format:', event.data);
      }
    },
    // 左侧列表
    handleMesList(){
      getMesList(this.queryParams).then(response => {
        this.list = response.rows
        this.total = response.total
      });
      // 直接调用不生效:因为你历史数据刚给,渲染的时候盒子高度还没有成型,所以直接调用拿不到,用个定时器让他在下一轮循环中调用,盒子就已经生成了
      this.$nextTick(() => { // 一定要用nextTick
        this.setUserPageScrollTo();
        //页面滚动条距离顶部高度等于这个盒子的高度
        this.$refs.scrollUserBox.scrollUserTop = this.$refs.scrollUserBox.scrollHeight;
      })
    },
    //切换客服状态
    uploadState(state) {
      if (state !== 4) {
        this.state = state;
      } else {
        this.$confirm("是否退出登录?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        })
          .then(() => {
            this.$message({
              type: "success",
              message: "退出成功!",
            });
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "已取消退出",
            });
          });
      }
    },
    //搜索icon
    handleIconClick() {
      alert("搜索");
      console.log(1);
    },
    //点击用户
    getAct(val) {
      console.log(val,11)
      this.isshow=1
      // 点击用户切换数据时先清除监听滚动事件,防止出现没有历史数据的用户,滚动条为0,会触发滚动事件
      this.$refs.scrollBox.removeEventListener("scroll", this.srTop);
      //点击变色
      this.act = val.opposUserId;
      //清空消息数组
      // this.info = [];
      this.queryParamsUser.toUserId = val.opposUserId
      this.queryParamsUser.pageNum = 1
      getMesInfo(this.queryParamsUser).then(response => {
        this.info = response.rows
        this.userTotal = response.total
        this.queryParams.pageNum = 1
        this.handleMesList()
        // 直接调用不生效:因为你历史数据刚给,渲染的时候盒子高度还没有成型,所以直接调用拿不到,用个定时器让他在下一轮循环中调用,盒子就已经生成了
        this.$nextTick(() => { // 一定要用nextTick
          this.setPageScrollTo();
          //页面滚动条距离顶部高度等于这个盒子的高度
          this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.s
  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值