微信小程序+wx.connectSocket客服问答

news2024/11/16 21:56:38

项目需求,记录一下:

1.要求websocket实时返回会话结果

我项目这边是后端一次返回一个字,–finish–结束,所以实现方法是每获取到数据时就setData一次,直到获取到的数据为finish,停止setData
后端返回结果如图
在这里插入图片描述

2.会话自动回滚到底部

用wx.createSelectorQuery()获取页面上的节点信息,可获得相对于显示区域的上下左右边界坐标,详情可点开链接查看
注意:每次发出问题,或者接受结果时都要重新计算节点信息

3.会话缓存(我这里用到的是wx.setStorageSync())

在这里插入图片描述
话不多说,上代码
wxml

<view >
<!-- isHe是为了首次进入页面时,要不要计算节点信息,如果没有缓存默认高度撑起来;有缓存,计算页面节点信息,获取滚动高度 -->
<view id="idView" style="height:{{isHe?'90vh':'auto'}};padding-bottom: 15vh;overflow: scroll;">
  <block wx:key wx:for='{{msgList}}' wx:for-index="index">
    <!-- 单个消息1 客服发出(左) -->
    <view wx:if='{{item.speaker=="server"}}' class="servers" id='msg-{{index}}' style='display: flex; padding: 2vw 11vw 2vw 2vw;'>
      <view style='width: 11vw; height: 11vw;'>
        <!-- 机器人图片 -->
        <image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='../../../assets/images/member/robot.png'></image>
      </view>
      <view style='width: 4vw; height: 11vw; margin-left: 0.5vw; display: flex; align-items: center; z-index: 9;'>
        <image style='width: 4vw;' src='../../../assets/images/member/left.png' mode='widthFix'></image>
      </view>
      <block>
        <!-- 发出消息等待返回结果时,三点加载动画 -->
        <view wx:if="{{isDisable && item.content==''}}" user-select='{{true}}' class='leftMsg loadView' space="nbsp" decode="{{true}}">
          <view class="dot1"> </view>
          <view class="dot2"></view>
          <view class="dot3"></view>
        </view>
        <text user-select='{{true}}' class='leftMsg' space="nbsp" decode="{{true}}">{{item.content}}</text>
      </block>
    </view>

    <!-- 单个消息2 用户发出(右) -->
    <view wx:else id='msg-{{index}}' style='display: flex; justify-content: flex-end; padding: 2vw 2vw 2vw 11vw;'>
      <view class='rightMsg'>{{item.content}}</view>
      <view style='width: 4vw; height: 11vw; margin-right: 0.5vw; display: flex; align-items: center; z-index: 9;'>
      	<!-- 左右箭头,见下图 -->
        <image style='width: 4vw;' src='../../../assets/images/member/right.png' mode='widthFix'></image>
      </view>
      <view style='width: 11vw; height: 11vw;'>
        <image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='{{cusHeadIcon}}'></image>
      </view>
    </view>
  </block>
</view>

<view class='inputRoom'>
  <input data-value="{{inputVal}}" disabled='{{isDisable}}' data-type="1" type="text" placeholder="请输入你的问题" confirm-type="send" bindconfirm='sendClick' value='{{inputVal}}' bindinput="ontext"></input>
  <image wx:if="{{!isDisable}}" data-type="2" bindtap='sendClick' class="sendIcon" src='../../../assets/images/member/send.png' mode='widthFix'></image>
  <image wx:else class="sendIcon" src='../../../assets/images/member/send.png' mode='widthFix'></image>
</view>
</view>


在这里插入图片描述
用到的api
wx.connectSocket()创建websocket连接
wx.onSocketOpen()监听websocket连接打开事件
wx.sendSocketMessage()发送数据,需要先 wx.connectSocket,并在 wx.onSocketOpen 回调之后才能发送
wx.onSocketMessage()监听websocket接收到服务器的消息事件
wx.createSelectorQuery()获取节点信息,如节点位置,文本内容等
wx.pageScrollTo()将页面滚动到目标位置,支持选择器和滚动距离两种方式定位
wx.closeSocket()关闭websocket连接
wx.onSocketClose()监听websocket连接关闭事件
js

const commonMixin = require('../../../utils/commonMixin')

const app = getApp();
var inputVal = '';
var msgList = [];
var windowWidth = wx.getSystemInfoSync().windowWidth;
var windowHeight = wx.getSystemInfoSync().windowHeight;
var keyHeight = 0;

let socketOpen = false;
let socketMsgQueue = [];
/**
 * 初始化数据
 */
function initData(that) {
  inputVal = '';
  msgList = [{
    speaker: 'server',
    contentType: 'text',
    content: '你好,我是人工智能助手,请问有什么可以帮你?'
  }, ]
  that.setData({
    msgList,
    inputVal
  })
}

function sendSocketMessage(msg) {
  console.log(socketOpen,'socketOpen',msg);
  if (socketOpen) {
    wx.sendSocketMessage({
      data: msg
    })
  } else {
    socketMsgQueue.push(msg)
  }
}



Page(Object.assign({
  /**
   * 页面的初始数据
   */
  data: {
    scrollTop: 0,
    isHe: false,
    text:'',
    isDisable:false,  // 发送消息等待回话时,input框禁用
    inputBottom: 0
  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    initData(this);
    this.setData({
      cusHeadIcon: app.globalData.userInfo.avatar || app.globalData.userInfo.avatarUrl,
    });
  },



  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    let that = this;
    let list =wx.getStorageSync('memberList')
    console.log(list,'list');
    // 判断是否有缓存,有缓存时,计算页面节点信息,设置滚动距离
    if (list?.length>0) { // 有缓存
      that.setData({
        msgList:JSON.parse(list)
      })
      wx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {
        // 使页面滚动到底部
        wx.pageScrollTo({
          scrollTop: rect.height+rect.bottom   // 滚动距离
        })
        that.setData({
          scrollTop: rect.height+rect.bottom,
          isHe: false
        });
      }).exec()
    }else{  //没有缓存,默认高度是90vh
      wx.setStorageSync('memberList', JSON.stringify(this.data.msgList))
      that.setData({
        isHe: true,
      })
    }
   
    wx.connectSocket({
      url: 'wss://' + 连接地址 
      success(){
        console.log('连接成功')
      }
    })

    wx.onSocketOpen((res) => {
      socketOpen = true
      console.log("打开socket");
      socketMsgQueue = []
      wx.onSocketMessage((result) => {
        result.data = result.data.replace(" ", "&nbsp;");
        var str = result.data.indexOf("--finish--") != -1  // 判断返回的数据中是否包含‘--finish--’
        wx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {
        	// 使页面滚动到底部
        	wx.pageScrollTo({
           		scrollTop: rect.height+rect.bottom
        	})
        	that.setData({
           		scrollTop: rect.height+rect.bottom,
        	 	isHe: false
           	});
        }).exec()
        
        if (!!result.data) {
          result.data=str?result.data.replace('--finish--',''):result.data
          console.log(that.data.msgList,'-');
          that.data.msgList[that.data.msgList.length - 1].content = that.data.msgList[that.data.msgList.length - 1].content + result.data
          that.setData({
              msgList:that.data.msgList
            })
          if (str) {
          	// 包含‘finish’结束字符,将返回结果存入缓存 
            let list =wx.getStorageSync('memberList')?JSON.parse(wx.getStorageSync('memberList')):[]
            list.push({
              speaker: 'server',
              contentType: 'text',
              content: that.data.msgList[that.data.msgList.length - 1].content
            })
            wx.setStorageSync('memberList',JSON.stringify(list))
          }
        }
        
        if(str){
          that.setData({
            isDisable:false,
          })
        }
        
      })
    })
  },
  onHide: function () {
    console.log('onhide');
    wx.closeSocket()
    wx.onSocketClose((result) => {
      console.log("socket关闭成功");
      wx.showToast({
        icon: 'none',
        title: '会话关闭成功',
        duration: 500
      })
    })
  },
  onUnload:function(){
    console.log('onUnload',);
    wx.closeSocket()
    wx.onSocketClose((result) => {
      console.log("socket关闭成功");
    })
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  ontext:function(e){
    this.setData({
      text:e.detail.value
    })
  },
  sendClick:function(e){ 
   	// 发送问题计算页面信息,滚动距离
    let that = this
    wx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {
      // 使页面滚动到底部
      wx.pageScrollTo({
        scrollTop: rect.height+rect.bottom
      })
      that.setData({
        height: 'auto',
        scrollTop: rect.height+rect.bottom
      });
    }).exec()
    that.setData({
      isDisable:true
    })
    sendSocketMessage(that.data.text)  //发送问题
    msgList.push({
      speaker: 'customer',
      contentType: 'text',
      content: that.data.text
    })
    let list =wx.getStorageSync('memberList')?JSON.parse(wx.getStorageSync('memberList')):[]
    list.push({
      speaker: 'customer',
      contentType: 'text',
      content: that.data.text
    })
    // 将发送的问题存入缓存
    wx.setStorageSync('memberList', JSON.stringify(list))
    msgList.push({
      speaker: 'server',
      contentType: 'text',
      content: ''
    })
    inputVal = '';
    // 这里list.push一个空内容,是为了让三个点加载出现,相当于一个占位符
    list.push({
      speaker: 'server',
      contentType: 'text',
      content: ''
    })
    that.setData({
      msgList:list,
      text:'',
      inputVal
    });
  }
}, commonMixin))

wxss

page {
    background-color: #f1f1f1;
  }
.inputRoom{
  height: 10vh;
  display: flex;
  align-items: center;
  z-index: 999;
  background: #f1f1f1;
  position: fixed;
  bottom: 0;
  width: 100%;
}
  
  input {
    width: 76vw;
    height: 9.33vw;
    background-color: #fff;
    border-radius: 40rpx;
    margin-left: 2vw;
    padding: 0 3vw;
    font-size: 28rpx;
    color: #444;
  }
  
  .leftMsg {
    font-size: 35rpx;
    color: #444;
    line-height: 7vw;
    padding: 2vw 2.5vw;
    background-color: #fff;
    margin-left: -1.6vw;
    border-radius: 10rpx;
    z-index: 10;
    word-break: break-all;
  }
  
  .rightMsg {
    font-size: 35rpx;
    color: #444;
    line-height: 7vw;
    padding: 2vw 2.5vw;
    background-color: #96EB6A;
    margin-right: -1.6vw;
    border-radius: 10rpx;
    z-index: 10;
  }
  input{
    height: 12vw !important;
    margin-bottom: 3vh;
  }
  .servers:nth-last-of-type(2){
    margin-bottom: 5vw;
  }
  .servers:nth-last-of-type(2)>.leftMsg{
    padding-bottom: 5vw;
  }
  .sendIcon{
    width: 7vw;
    margin-left: 3.2vw;
    margin-bottom: 3vh
  }
  .loadView{
    display: flex;
    padding-top: 4vw;
  }
  .dot1, .dot2, .dot3 {
    background: #fff;
    width: 10rpx;
    height: 10rpx;
    border-radius: 50%;
    margin: 10rpx;
}

.dot1 {
    animation: jump 1.6s -0.32s linear infinite;
    background: #ccc;
}
.dot2 {
    animation: jump 1.6s -0.16s linear infinite;
    background: #ccc;
}
.dot3 {
    animation: jump 1.6s linear infinite;
    background: #ccc;
}

@keyframes jump {
    0%, 80%, 100% {
        -webkit-transform: scale(0);
        transform: scale(0);
    } 40% {
          -webkit-transform: scale(2.0);
          transform: scale(2.0);
      }
}

至此就结束啦!有不足之处欢迎指出~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/452264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Banana Pi BPI-Centi-S3 使用MicroPython编程显示JPG图片

BPI-Centi-S3是我们新推出的一款板载1.9英寸彩屏的小尺寸ESP32-S3开发板&#xff01; BPI-Centi-S3 banana-pi wiki BPI-Centi-S3 bpi-steam wiki 1 关键特性 ESP32-S3&#xff0c;Xtensa 32 bit LX72M PSRAM , 8M FLASH2.4G WIFI &#xff0c;Bluetooth 5 &#xff0c;Blue…

Windows下安装使用Kafka(使用Kafka内置的ZooKeeper)

Windows下安装使用Kafka(使用Kafka内置的ZooKeeper) Kafka2.8版本才开始自带了Zookeeper&#xff0c;所以注意下版本 kafka官网&#xff1a;https://kafka.apache.org kafka配置快速入门&#xff1a;https://kafka.apache.org/quickstart kafka下载页面&#xff1a;https:/…

找出1-1000中的所有完美数

再次练习查找完美数&#xff0c;找出 1-1000 中的所有完美数。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… 地址&#xff1a;https://l…

【LeetCode】剑指 Offer 62. 圆圈中最后剩下的数字(约瑟夫环问题) p300 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ 1. 题目介绍&#xff08;62. 圆圈中最后剩下的数字&#xff09; 0,1,,n-1 这n个数字排成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这个圆圈里删除第m个数字&a…

人工标注或成过去式?SSA语义分割框架、SSA-engine自动类别标注引擎,大幅提升细粒度语义标注效率

推荐语 4月5日&#xff0c;Meta发布 Segment Anything 模型和 SA-1B 数据集&#xff0c;引发CV届“地震”&#xff0c;其凭借一己之力&#xff0c;成功改写了物体检测、数据标注、图像分割等任务的游戏规则。 复旦大学ZVG实验室团队基于此最新开源了SSA语义分割框架和SSA-engin…

javaEE初阶 — Servlet API 详解

文章目录 HttpServlet1 Servlet 的生命周期2 代码示例3 使用 postman 构造请求4 使用 ajax 构造请求 HttpServletRequest1 代码示例 前端如何给后端传参1 通过 GET 里的 query string 传参2 通过 POST 借助 form 表单传参3 通过 json 格式传参 HttpServletResponse1 代码示例1.…

ChatGPT会取代RPA?ta自己可不是这么说的!

先说一个AI热知识&#xff1a;ChatGPT 的推出在科技界引发了一场狂潮。 聊天机器人ChatGPT以及其背后的AI大模型GPT&#xff0c;在2023年引爆全球。GPT 全称为 Generative Pre-trained Transformer&#xff0c;是一种使用人工神经网络的深度学习技术&#xff0c;能够使机器像人…

Transformer and Self-attention

一谈到 NLP&#xff0c;大家都听说过 Transformer&#xff0c; Self-attention 这些词汇&#xff0c;以及 Attension is all you need 这篇论文。 大家可能多多少少看过这类博客&#xff0c;对这些概念有一些了解&#xff0c;什么 QKV呀&#xff0c; encoder&#xff0c; decod…

贪心-刷杂技的牛

题意 农民约翰的 N 头奶牛&#xff08;编号为 1..N&#xff09;计划逃跑并加入马戏团&#xff0c;为此它们决定练习表演杂技。 奶牛们不是非常有创意&#xff0c;只提出了一个杂技表演&#xff1a; 叠罗汉&#xff0c;表演时&#xff0c;奶牛们站在彼此的身上&#xff0c;形成一…

Revit中如何绘制轴线?CAD图纸转轴网操作

一、如何用revit来制作这么一个简单的轴线呢? 01 、新建项目 绘制轴线&#xff0c;首先新建项目建筑样板 02 、轴线快捷键 绘制轴线的快捷键需要牢记&#xff0c;因为经常使用GR 03 、编辑轴线类型 当你画好第一条轴线&#xff0c;需要对轴线类型属性进行调节&#xff0c;一般…

基于vivado(语言Verilog)的FPGA学习(5)——跨时钟处理

基于vivado&#xff08;语言Verilog&#xff09;的FPGA学习&#xff08;5&#xff09;——跨时钟处理 1. 为什么要解决跨时钟处理问题 慢时钟到快时钟一般都不需要处理&#xff0c;关键需要解决从快时钟到慢时钟的问题&#xff0c;因为可能会漏信号或者失真&#xff0c;比如&…

基于HTML5智慧监所三维可视化安防管控系统

前言 物联网技术的发展使云计算技术得到了迅猛的发展及广泛的应用&#xff0c;智能体系的创建已经成为监狱发展的必然趋势。 智慧监狱的创建、智能化管理的推行是监狱管理的创新&#xff0c;也是监狱整体工作水平提升的具体体现。 建设背景 近年来&#xff0c;司法部不断加大…

jumpserver设置密码强度

1、点击系统设置 – 点击安全设置 2、设置密码强弱规则

【SVN】window SVN安装使用教程(服务器4.3.4版本/客户端1.11.0版本)

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

为什么建企业网站对企业来说非常重要?

随着互联网的飞速发展&#xff0c;建企业网站已经成为了企业重要的一部分。企业网站是企业与外界沟通的重要渠道&#xff0c;对于企业的品牌形象、市场推广和销售业绩都有着不可替代的作用。本文将从以下几个方面&#xff0c;阐述为什么建企业网站对企业来说非常重要&#xff0…

Spring5学习总结(五)Spring5的新特性Log4j2@Nullable注解支持函数式风格支持JUnit5

Spring5学习总结&#xff08;五&#xff09;Spring5的新特性/Log4j2/Nullable注解/支持函数式风格/支持JUnit5 整个 Spring5 框架的代码基于 Java8&#xff0c;运行时兼容 JDK9&#xff0c;许多不建议使用的类和方法在代码库中删除 一、支持整合Log4j2 Spring 5.0 框架自带了…

【Java笔试强训】day26编程题

目录 编程题快到碗里来跳台阶问题 编程题 快到碗里来 import java.math.BigDecimal; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);while (sc.hasNext()) {BigDecimal n sc.nextBigDecimal();B…

【leetcode速通java版】04——哈希表

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;代码随想录leetcode速通训练营java版本 &#x1f330; 文章简介&#xff1a;哈希表理论&#xff0c;leetcodeT242,T3…

jekyll+GithubPage搭建一个免费的个人网站

文章目录 Jekyll环境搭建windows安装RUBY、gem、Jekyll用Jekyll搭建本地博客 用jekyll模板搭建githubpage Jekyll环境搭建 windows安装RUBY、gem、Jekyll 安装ruby RUBY安装包下载地址&#xff1a;https://rubyinstaller.org/downloads/&#xff0c;一路默认选项next即可。 最…

热闻丨ChatGPT会替代你我吗?让它写了封情书后,我得到答案

ChatGPT毕竟不是人 2023年的科技圈儿被ChatGPT占据&#xff0c;上线仅仅两个月&#xff0c;活跃用户就突破一亿。上知天文下知地理&#xff0c;ChatGPT以它的强大功能让许多人生出疑问&#xff1a;ChatGPT会替代你我吗&#xff1f; 记者挑选了一些尖锐问题进行询问&#xff0…