• 融云群聊/单聊移动端模板(附图) 支持文件上传 图片上传 表情发送 超链接跳转


    功能:基础功能群聊 文件上传 图片上传 表情发送 超链接跳转

    注:里面涉及到诸多函数依赖,请忽略,只看主要功能即可

     

    html

    <template>
      <div class="container" :style="{'top':'calc('+marginTop+' + 0.16rem)'}">
        <div class="chart-message  display-flex" :style="{'height':'calc(100vh - '+marginTop+' - '+(KEYBOARD_H+0.16)+'rem)'}">
          <div class="chart-header">
            <h2>{{groupChatInfo.groupName}}({{chatGroupList.length}})</h2>
            <div @click="handleGroupUser" class="more-user display-flex hvc">
              <i class="icon icon-more"></i>
            </div>
          </div>
          <div class="chart-message-cont  flex-1"  @touchstart="handleMessageInputBlur">
            <div class="chart-message-cont-wrap">
              <div class="load-more" v-if="hasMore">
                <span @click="getHistoryMessage({type:'loadMore'})">加载更多</span>
              </div>
              <template v-for="(item,index) in historyMessageList">
                <!--加入者信息-->
                <div v-if="item.messageType == 'RC:InfoNtf'" class="chart-message-item message-time">
                  <p>{{item.content.message}}</p>
                </div>
                <!--接收者-->
                <div v-if="item.messageDirection == '2'&&item.messageType != 'RC:InfoNtf'" class="chart-message-item message-receive display-flex">
                  <div class="user-avatar" @click="handleAvatar({type:'2',data:item.content.extra})">
                    <img v-if="item.content.extra" :src="item.content.extra.avatar" alt="">
                    <img v-else src="./../../assets/images/industry/icon-avatar.png" alt="">
                  </div>
                  <div>
                    <p v-if="item.content.extra" style="color: #555;font-size: 0.2rem;line-height: 1.5;">{{item.content.extra.name}}</p>
                    <div  @click="handleDownloadFile({type:item.messageType,data:item})"  class="user-msg " :class="{'display-flex':item.messageType == 'RC:FileMsg'}">
                      <template v-if="item.messageType == 'RC:TxtMsg'">
                        <p @contextmenu.stop.prevent="handleCopyText({data:item.content.content,eType:'contextmenu'})"  @click="handleCopyText({data:item.content.content,eType:'click'})"  v-html="chatMessageFormat({data:item.content.content,type:2})"></p>
                      </template>
                      <template v-else-if="item.messageType=='RC:ImgMsg'">
                        <img @click="handleImagePreview({url:item.content.imageUri})" :src="item.content.imageUri" alt="">
                      </template>
                      <template v-else-if="item.messageType == 'RC:FileMsg'">
                        <div class="file-info">
                          <p class="file-name">{{item.content.name}}</p>
                          <p class="file-size">{{item.content.size>1024*1024?(item.content.size/1024/1024).toFixed(2)+'MB':(item.content.size/1024).toFixed(2)+'KB'}}</p>
                        </div>
                        <div class="file-icon">
                          <img src="./../../assets/images/chat/icon-file.png" style="height: 0.68rem; 0.68rem;" alt="">
                        </div>
                      </template>
                    </div>
                  </div>
                </div>
                <!--发送者-->
                <div  v-if="item.messageDirection == '1'&&item.messageType != 'RC:InfoNtf'" class="chart-message-item message-send display-flex">
                  <div>
                    <p v-if="item.content.extra" style="text-align: right;color: #555;font-size: 0.2rem;line-height: 1.5;">{{item.content.extra.name}}</p>
                    <div  @click="handleDownloadFile({type:item.messageType,data:item})"  class="user-msg" :class="{'user-msg--file display-flex':item.messageType == 'RC:FileMsg'}">
                      <template v-if="item.messageType == 'RC:TxtMsg'">
                        <p  @contextmenu.stop.prevent="handleCopyText({data:item.content.content,eType:'contextmenu'})" @click="handleCopyText({data:item.content.content,eType:'click'})" v-html="chatMessageFormat({data:item.content.content,type:1})"></p>
                      </template>
                      <template v-else-if="item.messageType=='RC:ImgMsg'">
                        <img @click="handleImagePreview({url:item.content.imageUri})" :src="item.content.imageUri" alt="">
                      </template>
                      <template v-else-if="item.messageType == 'RC:FileMsg'">
                        <div class="file-icon">
                          <img src="./../../assets/images/chat/icon-file.png" style="height: 0.68rem; 0.68rem;" alt="">
                        </div>
                        <div class="file-info">
                          <p class="file-name">{{item.content.name}}</p>
                          <p class="file-size">{{item.content.size>1024*1024?(item.content.size/1024/1024).toFixed(2)+'MB':(item.content.size/1024).toFixed(2)+'KB'}}</p>
                        </div>
                      </template>
                    </div>
                  </div>
                  <div @click="handleAvatar({type:'1',data:item.content.extra})" class="user-avatar">
                    <img v-if="item.content.extra" :src="item.content.extra.avatar" alt="">
                    <img v-else src="./../../assets/images/industry/icon-avatar.png" alt="">
                  </div>
                </div>
                <!--时间类型-->
                <div v-if="index < historyMessageList.length-1 &&historyMessageList[index+1].sentTime-historyMessageList[index].sentTime>10*60*1000" class="chart-message-item message-time">
                  <p v-html="chatMessageTimeFormat({data:historyMessageList[index+1]})"></p>
                </div>
              </template>
            </div>
          </div>
          <div class="chart-message-footer" v-if="sendMsgState">
            <div class="btn-group display-flex">
              <div class="btn-industry-map display-flex hvc">
                <i  v-if="browser.mobile" @touchstart="handleIndustryMap"  class="icon icon-industryMap"></i>
                <i v-else @click="handleIndustryMap"  class="icon icon-industryMap"></i>
              </div>
              <textarea @blur="messageBlur" ref="messageContent" @focus="messageFocus" @keydown.enter="handleSendMessage({event:$event,sendType:'text'})"  v-model.trim="messageContent" placeholder="请输入内容" :class="messageContent?'message-val':'message-placeholder'" class="message-input flex-1"></textarea>
              <div class="btn-smile display-flex hvc">
                <i class="icon icon-smile"  v-if="browser.mobile" @touchstart="handleTogglePanelEmtion({event:$event})"></i>
                <i class="icon icon-smile" v-else @click="handleTogglePanelEmtion({event:$event})"></i>
              </div>
              <template v-if="messageContent">
                <div class="btn-send  display-flex hvc">
                  <span v-if="browser.mobile"  @touchstart="handleSendMessage({event:$event,sendType:'text'})">发送</span>
                  <span v-else  @click="handleSendMessage({event:$event,sendType:'text'})">发送</span>
                </div>
              </template>
              <template v-else>
                <div class="btn-add display-flex hvc">
                  <i class="icon icon-add" v-if="browser.mobile" @touchstart="handleTogglePanelImage({event:$event})"></i>
                  <i class="icon icon-add"  v-else @click="handleTogglePanelImage({event:$event})"></i>
                </div>
              </template>
            </div>
            <div class="multi-fun-panel">
              <div v-show="panelImageState"  class="panel-image">
                <ul>
                  <li>
                    <label for="uploadImage">
                      <input @change.prevent="handleUploadImg({event: $event})" style="display: none" accept="image/*" type="file" ref="uploadImage" id="uploadImage">
                      <img style=" 1.16rem;" src="./../../assets/images/chat/icon-upload-images.png" alt="">
                      <p>照片</p>
                    </label>
                  </li>
                  <li>
                    <label for="uploadFile">
                      <input @change.prevent="handleUploadFile({event: $event})" style="display: none"  type="file" ref="uploadFile" id="uploadFile">
                      <img style=" 1.16rem;" src="./../../assets/images/chat/icon-upload-file.png" alt="">
                      <p>文件</p>
                    </label>
                  </li>
                </ul>
              </div>
              <div v-show="panelEmtionState" class="panel-emtion display-flex">
                <template v-if="browser.mobile">
                  <Emotion class="emotion-item" v-for="(item, i) in emoticon" :key="i" @touchend.native="handleEmotion({data:item})">{{item}}</Emotion>
                </template>
                <template v-else>
                  <Emotion class="emotion-item" v-for="(item, i) in emoticon" :key="i" @click.native="handleEmotion({event:$event,data:item})">{{item}}</Emotion>
                </template>
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    

    js

    <script>
      import {ImagePreview} from 'vant'
      import {formatDate,browser,getOpenId,emotionParams ,addEvent,regularExpression,copyText,globalStatistics} from "../../../static/js/help";
      import {getByToken,groupBoardChat,setMessageRead,groupChatInfo,getWechatInfoByUnionId ,attachUpload,chatAutoQuote,groupChatMembers} from "../../../static/js/api";
      import {mapGetters} from 'vuex';
      import Emotion from './../../components/chat/emotion'
      const avatar = require('./../../assets/images/industry/icon-avatar.png');
      import {Dialog} from 'vant'
      window.vueThis = null;
      export default {
        name: "chatMessage",
        components:{
          Emotion
        },
        data() {
          return {
            userInfo:{
              name:'',
              icon:'',
              appUserId:''
            },//自己的用户信息
            receiveTargetId:'',//接送消息的userId
            messageContent:'',//消息内容
            historyMessageList:[],//历史消息
            scrollDirection:'down',//down 向下,up向上
            timestrap:new Date().getTime(),//历史消息limit
            hasMore:false,//是否展示加载更多
            beforeScrollHeight:0,//滚动之前高度
            sentTime:localStorage.sentTime,//记录已读消息时间
            groupChatInfo:{},//群聊信息
            wxUserInfo:{},//微信用户信息
            emoticon:emotionParams.list,
            panelImageState:false,//图片上传面板
            panelEmtionState:false,//表情面板
            sendImage:'',//图片发送
            chatGroupList:[],
            chatFilter:process.env.CHAT_FILTER,//聊天用户过滤列表
            browser:browser.versions,
            KEYBOARD_H:0,//软盘高度
          }
        },
        watch:{
          'historyMessageList'(){
            this.$nextTick(()=>{
              this.scrollView();
            })
          },
          'im'(){
            this.creatRongIMConnect();
          },
        },
        computed:{
          ...mapGetters ([
            'im',
            'sysUserInfo'
          ]),
          deviceInfo() {
            return this.$store.getters.deviceInfo;
          },
          marginTop() {
            if (this.deviceInfo.grade == '1.3' || this.deviceInfo.grade == '1.4') {//App
              return '0rem'
            } else if (this.deviceInfo.grade == '2') {//PC
              return '1.78rem'
            } else {//手机微信
              return '0.9rem'
            }
          },
          //发送框状态
          sendMsgState(){
            let state = true;
            for(let i  = 0;i<this.chatFilter.length;i++){
              if(this.chatFilter[i].id == this.receiveTargetId){
                return false
                continue
              }
            }
            return state
          }
        },
        methods: {
          //让input失去焦点
          handleMessageInputBlur(){
            this.$refs.messageContent.blur();
          },
          //点击头像
          handleAvatar({type,data} = {}){
            if(type == '1'){
              this.$router.push({
                name:'industrySetting'
              })
            }else if(type == '2'){
              this.$router.push({
                name:'industryContacts',
                query:{
                  clientId:data.clientId
                }
              })
            }
          },
          //图片面板切换
          handleTogglePanelImage({event} = {}){
            this.panelImageState = !this.panelImageState;
            this.panelEmtionState = false;
            if(this.panelImageState){
              this.$refs.messageContent.blur();
            }else {
              this.$refs.messageContent.focus();
            }
            event.preventDefault();
          },
          //表情面板切换
          handleTogglePanelEmtion({event} = {}){
            this.panelEmtionState = !this.panelEmtionState;
            this.panelImageState = false;
            if(this.panelEmtionState){
              this.$refs.messageContent.blur();
            }else {
              this.$refs.messageContent.focus();
            }
            event.preventDefault();
          },
          //图片预览
          handleImagePreview({url} = {}){
            ImagePreview({
              images: [url],
              closeable: true,
            });
          },
          //图片上传
          handleUploadImg({event} = {}){
            let file = event.target.files[0];
            if(file.size>10*1024*1024){
              this.$_toast('图片大小需小于1OMB')
              this.$refs.uploadImage.value = '';
              return
            }
            attachUpload({
              multipartFile:file
            }).then((res)=>{
              if(res.data.state == 'SUCCESS'){
                let url = res.data.url;
                this.sendImage = url;
                this.handleSendMessage({event:event,sendType:'image'});
                this.$refs.uploadImage.value = '';
              }
            })
            event.preventDefault();
          },
          //文件上传
          handleUploadFile({event} = {}){
            let file = event.target.files[0];
            let fileInfo = {
              name: file.name,
              size: file.size,
              type: file.type,
            }
            if(file.size>10*1024*1024){
              this.$_toast('文件大小需小于1OMB')
              this.$refs.uploadFile.value = '';
              return
            }
            attachUpload({
              multipartFile:file
            }).then((res)=>{
              if(res.data.state == 'SUCCESS'){
                let url = res.data.url;
                this.sendImage = url;
                fileInfo.fileUrl = url;
                this.handleSendMessage({event:event,sendType:'file',fileInfo});
                this.$refs.uploadFile.value = '';
              }
            })
            event.preventDefault();
          },
          //文件下载
          handleDownloadFile({type,data} = {}){
            if(type == 'RC:FileMsg'){
              let {fileUrl,name,size} = data.content;
              this.$router.push({
                name:'downloadFile',
                query:{
                  params:JSON.stringify({
                    fileUrl,
                    name,
                    size,
                  })
                }
              })
            }
          },
          //聊天消息格式化
          chatMessageFormat({data,type} = {}){
            if(type == 1){
              var style = "color:#232323;text-decoration: underline"
            }else if(type == 2){
              var style = "color:#333;text-decoration: underline"
            }
            let _html = data.replace(regularExpression.http, (res)=> {
              let url = res;
              if(res.indexOf('http')=='-1'){
                url ='http://'+url;
              }
              return  `<a style="${style}"  onclick="handleCopyTextByMiniProgarm({event:event,url:'${url}'})"    href="javascript:;">${res}</a>`;
              return this.deviceInfo.terminalType == 'MINIPROGRAM'?`<a style="${style}"  onclick="handleCopyTextByMiniProgarm(event,'${res}')"    href="javascript:;">${res}</a>`:`<a onclick="handleCopyTextByMiniProgarm(event,'${res}')" style="${style}" target="_blank" href="${url}">${res}</a>`
            })
             _html = _html.replace(/#[u4E00-u9FA5]{1,3};/gi, this.emotionFormat)
            return _html
          },
          //表情格式化
          emotionFormat (res) {
            let word = res.replace(/#|;/gi,'')
            const list = emotionParams.list
            let index = list.indexOf(word)
            return `<img style=" 0.343rem;height: 0.343rem;display: inline-block;vertical-align: -4px" src="${emotionParams.url}${index}.gif" align="middle">`
          },
          //选择表情
          handleEmotion({event,data} ={}){
            let emotion = `#${data};`;
            this.messageContent +=emotion;
            let h = this.$refs.messageContent.scrollHeight;
            let fontSize = 100/parseFloat($('html').css('font-size'));//px换算rem
            this.$refs.messageContent.scrollTop =h*fontSize*2;
            //event.preventDefault();
          },
          //切换到地图
          handleIndustryMap(){
            this.handleMessageInputBlur();
            this.$parent.type = 1;
            localStorage.industryType = 1;
            globalStatistics({
              eventType:'E_033',
              clickType:'C_032_0002'
            })
          },
          //聊天用户
          getGroupChatMembers(){
            groupChatMembers({
              groupId:this.$route.query.groupId
            }).then((res)=>{
              if(res.data.code == '0000'){
                let data = res.data.data;
                this.chatGroupList = data;
              }
            })
          },
          //获取微信用户信息
          getWechatInfoByUnionId(){
            getWechatInfoByUnionId({
              unionId:getOpenId()
            }).then((res)=>{
              if(res.data.code == '0000'){
                let data = res.data.data;
                this.wxUserInfo = data;
              }
            })
          },
          //input失去焦点滚动到可视区域 https://cdn.ronghub.com/RongIMLib-3.0.6-dev.min.js
          handleScrolltoView() {
            document.querySelector(".chart-message").scrollIntoView(true);
          },
          //与建立融云连接
          creatRongIMConnect(){
            //只有获取到了targetId才能做其他操作
            this.getGroupChatInfo().then(()=>{
              this.watchRongIMLib();//监测
              this.getHistoryMessage();//历史消息
              this.clearnUnReadConvert() //清除未读
            })
          },
          //设置监听
          watchRongIMLib(){
            this.im.watch({
              conversation: ()=>{
                console.log('消息列表更新');
              },
              message: (event)=>{
                if(this.$route.name !='industry') return
                var message = event.message;
                let {messageUId,sentTime,type} = message;
                if(message.messageType !='RC:ReadNtf'){
                  if(message.type == 3){
                    message.receivedStatus = 0;
                    this.historyMessageList.push(message);
                    this.setMessageRead({
                      messageUId,
                      lastMessageSendTime:sentTime,
                      type});
                    this.clearnUnReadConvert() //清除未读
                  }
                  console.log('我已接收到新消息');
                }else {
                  this.sentTime  = localStorage.sentTime = message.sentTime;
                  this.SetServerMessageRead();//服务器已读
                  console.log('我已接收到已读通知')
                }
              }
            });
          },
          //message失去焦点
          messageBlur(){
            this.handleScrolltoView();
          },
          //message获取焦点
          messageFocus(){
            this.panelImageState = false;
            this.panelEmtionState = false;
          },
          //消息发送
          handleSendMessage({event,sendType,fileInfo} = {}){
            //手机回车不发消息
            var conversation = this.im.Conversation.get({
              targetId: this.receiveTargetId,//接收方USERID
              type: RongIMLib.CONVERSATION_TYPE.GROUP
            });
            //发送文本
            if(sendType == 'text'){
              if(this.browser.mobile&&event.keyCode == '13'){
                return
              }
              if(!this.messageContent) {
                this.$_toast('请输入内容');
                return
              }
              //发送文本
              var sendParams = {
                messageType: RongIMLib.MESSAGE_TYPE.TEXT, // 填写开发者定义的 messageType
                content: { // 填写开发者定义的消息内容
                  content:this.messageContent,
                  extra:{
                    avatar:this.wxUserInfo.headImgUrl,
                    name:this.sysUserInfo.name,
                    clientId:this.sysUserInfo.client_id
                  },
                },
                isPersited: true,// 是否存储在服务端,默认为 true
                isCounted: true,  // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
                pushContent:'user 发送了一条消息',  // Push 显示内容
                pushData: 'Push 通知时附加信息',  // Push 通知时附加信息, 可不填
                isStatusMessage: false,  // 设置为 true 后 isPersited 和 isCounted 属性失效
                disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
              }
            }else if(sendType == 'image'){
              //发送图片
              var sendParams = {
                messageType: RongIMLib.MESSAGE_TYPE.IMAGE, // 填写开发者定义的 messageType
                content: { // 填写开发者定义的消息内容
                  content:'',//base64图片地址
                  imageUri:this.sendImage,//图片url
                  extra:{
                    avatar:this.wxUserInfo.headImgUrl,
                    name:this.sysUserInfo.name,
                    clientId:this.sysUserInfo.client_id
                  },
                },
                isPersited: true,// 是否存储在服务端,默认为 true
                isCounted: true,  // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
                pushContent:'user 发送了一条消息',  // Push 显示内容
                pushData: 'Push 通知时附加信息',  // Push 通知时附加信息, 可不填
                isStatusMessage: false,  // 设置为 true 后 isPersited 和 isCounted 属性失效
                disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
              }
            }else if(sendType == 'file'){
              //发文件
              var sendParams = {
                messageType: RongIMLib.MESSAGE_TYPE.FILE, // 填写开发者定义的 messageType
                content: {
                  ...fileInfo,
                  extra:{
                    avatar:this.wxUserInfo.headImgUrl,
                    name:this.sysUserInfo.name,
                    clientId:this.sysUserInfo.client_id
                  }
                },
                isPersited: true,// 是否存储在服务端,默认为 true
                isCounted: true,  // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
                pushContent:'user 发送了一条消息',  // Push 显示内容
                pushData: 'Push 通知时附加信息',  // Push 通知时附加信息, 可不填
                isStatusMessage: false,  // 设置为 true 后 isPersited 和 isCounted 属性失效
                disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
              }
            }
            conversation.send(sendParams).then((message)=>{
              this.scrollDirection = 'down';
              this.historyMessageList.push(message);
              if(sendType == 'text'){
                //自动报单
                chatAutoQuote({
                  wechatNickName:this.wxUserInfo.nickname,
                  content:this.messageContent
                })
              }
              this.messageContent = '';
            });
    
            groupBoardChat({
              targetToken:this.receiveTargetId,
              content:this.messageContent
            })
            event.preventDefault();
          },
          //告诉对方,该消息已读过了
          setMessageRead({messageUId,lastMessageSendTime,type}){
            var conversation = this.im.Conversation.get({
              targetId:this.receiveTargetId,
              type: RongIMLib.CONVERSATION_TYPE.GROUP
            });
            // 以上 3 个属性在会话的最后一条消息中可以获得
            conversation.send({
              messageType: 'RC:ReadNtf',
              content: {
                messageUId: messageUId,
                lastMessageSendTime: lastMessageSendTime,
                type: type
              }
            }).then((message)=>{
              console.log('消息我已经读了,发了通知给你');
            });
          },
          //获取历史消息
          getHistoryMessage({type}={}){
            if(type == 'loadMore'){
              this.scrollDirection = 'up'
            }else {
              this.scrollDirection = 'down'
            }
    
            var conversation = this.im.Conversation.get({
              targetId: this.receiveTargetId,//接收方的 userId
              type: RongIMLib.CONVERSATION_TYPE.GROUP
            });
            conversation.getMessages({
              timestrap:this.timestrap,
              count: 20
            }).then((result)=>{
              console.log(result.list)
              this.scrollDirection = 'up';
              this.beforeScrollHeight = $('.chart-message-cont-wrap').height();
              this.historyMessageList = [...result.list,...this.historyMessageList]; // 历史消息列表
              this.hasMore = result.hasMore;
              if(result.list.length){
                this.timestrap = result.list[0].sentTime;
              }
            });
    
          },
    
          //滚动到可视区域
          scrollView({animate}={animate:true}){
            let scrollHeight = $('.chart-message-cont-wrap').height();
            if(this.scrollDirection == 'down'){
              if(animate){
                $('.chart-message-cont').animate({scrollTop: scrollHeight+'px'}, 500);
              }else {
                $('.chart-message-cont').scrollTop(scrollHeight)
              }
            }else if(this.scrollDirection == 'up'){
              $('.chart-message-cont').animate({scrollTop: (scrollHeight- this.beforeScrollHeight)+'px'}, 0);
            }
    
          },
          //时间格式化
          chatMessageTimeFormat({data}={}){
            let currentDate = formatDate({date:data.sentTime});
            let nowDate = formatDate();
            if(currentDate == nowDate){
              return formatDate({
                date:data.sentTime,
                fmt:'hh:mm',
              })
            }else {
              return formatDate({
                date:data.sentTime,
                fmt:'yyyy-MM-dd hh:mm'
              })
            }
          },
          //清除未读数
          clearnUnReadConvert(){
            this.im.Conversation.get({
              targetId:this.receiveTargetId,
              type: RongIMLib.CONVERSATION_TYPE.GROUP
            }).read().then(()=>{
              console.log('清除未读数成功'); // im.watch conversation 将被触发
            });
          },
          getUserInfo(){
            getByToken({
              targetId:this.receiveTargetId
            }).then((res)=>{
              if(res.data.code == '0000'){
                let data = res.data.data;
                if(data){
                  this.userInfo = data;
                }
              }
            })
          },
          //服务器已读
          SetServerMessageRead(){
            setMessageRead({
              targetToken:this.receiveTargetId
            })
          },
          //获取群聊信息
          getGroupChatInfo(){
            return new Promise((resolve,reject)=>{
              groupChatInfo({}).then((res)=>{
                if(res.data.code == '0000'){
                  let data = res.data.data;
                  this.groupChatInfo = data;
                  this.receiveTargetId = data.groupId;
                  document.title = data.groupName
                  resolve();
                }
              })
            })
    
          },
          //查看群组用户
          handleGroupUser(){
            this.$router.push({
              name:'chatGroupUser',
              query:{
                groupId:this.receiveTargetId
              }
            })
          },
          //复制
          handleCopyText({data,eType} ={}){
            if(!this.browser.mobile&&eType =='click') return
            if(this.deviceInfo.grade == '2.1') {
              this.$_toast('请使用ctrl+c复制')
              return;
            }
            copyText({text:data})
          },
          stopEvent(event) { //阻止冒泡事件
            //取消事件冒泡
            var e =  event; //若省略此句,下面的e改为event,IE运行可以,但是其他浏览器就不兼容
            if (e && e.stopPropagation) {
              // this code is for Mozilla and Opera
              e.stopPropagation();
            } else if (window.event) {
              // this code is for IE
              window.event.cancelBubble = true;
            }
          }
        },
        created(){
          this.getGroupChatMembers();
          window.vueThis = this;
        },
        activated(){
          this.scrollView();
          this.getGroupChatMembers();
          if(this.im){
            this.clearnUnReadConvert() //清除未读
          }
        },
        mounted() {
          this.SetServerMessageRead();
          this.getWechatInfoByUnionId();
          if(this.im){
            this.creatRongIMConnect();
          }
          addEvent({ele:'.panel-emtion'})
        }
    
      }
      window.handleCopyTextByMiniProgarm = function(data){
        if(window.vueThis.deviceInfo.terminalType == 'MINIPROGRAM'){
          copyText({text:data.url,isTip:false})
          Dialog.alert({
            message: '小程序不支持打开链接,链接已复制请在浏览器中打开',
          })
        }else {
          window.open(data.url,'_blank')
        }
        window.vueThis.stopEvent(event);
      }
    </script>
    

    css

    <style lang="scss" scoped>
    
      .container{ 7.5rem;margin: auto;position: relative;
        -moz-user-select:text;
        -webkit-user-select:text;
      }
      .chart-header{height: 0.93rem; 7.5rem;background: #fff;
        h2{font-size: 0.3rem;color: #2C2C2C;text-align: center;line-height: 0.93rem;font-weight: 700}
        .more-user{
           0.93rem;
          height: 0.93rem;
          position: absolute;right: 0;top: 0;
          .icon-more{ 0.36rem;height: 0.09rem;background: url("././../../assets/images/chat/icon-more.png") no-repeat;background-size: contain;}
        }
    
      }
      .chart-message{flex-direction: column;height: 100vh;
        .load-more{text-align: center;padding: 0.3rem 0;cursor: pointer;
          span{color: #555;}
        }
        .chart-message{
          &-item{margin: 0.7rem 0;
            .user-avatar{ 0.88rem;
              img{ 0.88rem;height: 0.88rem;background: #fff;border-radius: 0.88rem;overflow: hidden;border: 0.01rem solid #eee;}
            }
          }
          &-cont{padding: 0 0.18rem;overflow: scroll;background: #f5f5f5;
            .message-time{color: #888888;font-size: 0.26rem;text-align: center;margin: 0.2rem 0;
              p{display: inline-block;
                background: rgba(0,0,0,0.2);
                padding: 2px 5px;
                color: #fff;
                border-radius: 2px;}
            }
            .message-receive{margin-right: 1.2rem;
              .user-avatar{margin-right: 0.2rem;}
              .user-msg {background: #fff;padding: 0.25rem 0.3rem;border: 0.01rem solid #DDDDDD;border-radius: 0.04rem 0.2rem 0.2rem 0.2rem;
                img{ auto;height: auto;max- 1.8rem;}
                .href{color: #333;text-decoration: underline}
              }
    
              .file-info{margin-right: 0.6rem;}
              .file-size{color: #999;font-size: 0.24rem;}
              p{font-size:0.28rem;color: #333;line-height: 0.45rem;word-break: break-all;}
    
              }
            .message-send{margin-left: 1.2rem;justify-content: flex-end;
              .user-avatar{margin-left: 0.2rem;}
              .user-msg {background: #9eea6a;padding: 0.25rem 0.3rem;border: 0.01rem solid #9eea6a;border-radius: 0.2rem  0.04rem 0.2rem 0.2rem;position: relative;
                img{ auto;height: auto;max- 1.8rem;}
              }
              .user-msg.user-msg--file{background: #fff;border: 0.01rem solid #DDDDDD;}
              .file-info{margin-left: 0.6rem;}
              .file-size{color: #232323;font-size: 0.24rem;}
              .href{color: #232323;text-decoration: underline;border: 1px solid red;}
              .read-state{position: absolute;font-size: 0.24rem; 0.6rem;text-align: center;right: 0;bottom: -0.4rem;background: rgba(0,0,0,0.1);border-radius: 0.05rem;color: #555;}
              p{font-size:0.28rem;color: #232323;line-height: 0.45rem;word-break: break-all;}
            }
          }
          &-footer{
            .btn-group{
              background: #fff;padding: 0.15rem 0.25rem;box-sizing: border-box;padding-bottom: 0.4rem;
            }
            .btn-industry-map{ 0.68rem;margin-right: 0.34rem;
              .icon-industryMap{ 0.68rem;height: 0.68rem;display: inline-block;background: url("./../../assets/images/industry/icon-industryMap.png") no-repeat;background-size: contain;cursor: pointer}
            }
            .btn-smile{ 0.56rem;margin-right: 0.24rem;margin-left: 0.24rem;
              .icon-smile{ 0.56rem;height: 0.56rem;display: inline-block;background: url("./../../assets/images/industry/icon-smile.png") no-repeat;background-size: contain;cursor: pointer}
            }
            .btn-add{ 0.56rem;
              .icon-add{ 0.56rem;height: 0.56rem;display: inline-block;background: url("./../../assets/images/industry/icon-add.png") no-repeat;background-size: contain;;cursor: pointer}
            }
            .btn-send{ 0.56rem;
              span{color: #5C86F7;font-size: 0.3rem;background: transparent;border: none;text-align: center;font-weight: bold;min- 1rem;white-space: nowrap;cursor: pointer}
            }
            .message-input{padding: 0;margin: 0;border: none;height: 0.8rem;border-radius: 0.12rem;background:#F1F3FA;box-sizing: border-box;font-size: 0.28rem;color: #555;
              &::-webkit-scrollbar {
                 0.05rem;
                height: 0.1rem
              }
              &::-webkit-scrollbar-thumb {
                min-height: 0.05rem;
                background: #c4c6cc;
                border-radius: 0.02rem;
              }
              &::-webkit-scrollbar-track-piece {
                background: #fff
              }
              &::placeholder{color: #999;}
            }
            .message-placeholder{
              padding: 0.2rem  0.1rem;
              line-height: 0.4rem;
            }
            .message-val{
              padding: 0.1rem  0.1rem;
              line-height: 0.35rem;
            }
          }
    
        }
        .multi-fun-panel{background: #F7F7F7;
          .panel-image{
            ul{
              li{text-align: center;display: inline-block;margin:0.3rem 0.33rem;
                p{text-align: center;color: #4C4C4C;font-size: 0.24rem;margin-top: 0.1rem;}
              }
            }
          }
        }
        .panel-emtion{flex-direction: row;flex-wrap: wrap;max-height: 3rem;overflow: scroll;padding: 0.1rem ;box-sizing: border-box;}
      }
    
    </style>
    愿你走出半生,归来仍是少年
  • 相关阅读:
    玩转Redis之Window安装使用(干货)
    如何用AJax提交name[]数组?
    Java中native关键字使用
    Kafka — 高吞吐量的分布式发布订阅消息系统【转】
    Permission denied: user=dr.who, access=READ_EXECUTE, inode="/tmp":student:supergroup:drwx------权限问题
    hdfs中删除文件、文件夹、抓取内容
    1. hadoop使用启动命令时报错之分析解决
    第三次迭代会议
    IAR Embedded Workbench for ARM 8.22.1 基础使用教程
    个人作业1——四则运算题目生成程序(基于java)
  • 原文地址:https://www.cnblogs.com/yz-blog/p/14308514.html
Copyright © 2020-2023  润新知