集成云信SDK-web版-vue客服(伸手党)

 <template>
  <div class="customer-servce">
    <div class="imServer-wrapper">
      <main class="imServer-main">
        <im-record
          class="item im-record"
          :session-list="sessions"
          :my-info="myInfo"
          :users="users"
          @selectedChat="selectedChat"
        />
        <im-chat
          v-if="JSON.stringify(msgsUser) !== '{}'"
          ref="im_chat"
          :msgs-user="msgsUser"
          class="item im-chat"
        >
          <common-chat
            ref="common_chat"
            :chat-info-en="chatInfo"
            :msgs-user="msgsUser"
            :my-info="myInfo"
            :opr-role-name="'server'"
            @sendText="sendMsg"
            @fileUpload="fileUpload"
            @transferChat="transferChat"
          />
        </im-chat>
      </main>
    </div>
  </div>
</template>
<script>
// 聊天列表
import imRecord from '@/components/imServer/imRecord.vue' 
// 聊天详情
import imChat from '@/components/imServer/imChat.vue'
// 聊天数据框
import commonChat from '@/components/common/common_chat.vue'
// SDK
import SDK from '../../../static/yx/js/NIM_Web_SDK_v4.0.0'
import { getUserId } from '@/utils/auth'
export default {
  components: {
    imRecord,
    imChat,
    commonChat
  },
  data() {
    return {
      nim: null,
      sessions: [],
      accountList: null,
      users: [],
      myInfo: {},
      chatInfo: [],
      msgsUser: {},
      chatType: '3', // 标识客服
      sysUserId: getUserId(), // 存储用户id
      transfer: false // 是否转客服
    }
  },
  computed: {
  },
  watch: {},
  async created() {
    await this.initSDK()
  },
  mounted() {
  },
  destroyed() {
  },
  methods: {
    initSDK() {
      this.nim = SDK.NIM.getInstance({
        // debug: true,
        // appKey: '',
        // account: '',
        // token: ''
        // privateConf: {}, // 私有化部署方案所需的配置
        onconnect: this.onConnect, // 链接已经建立(登录成功)
        onwillreconnect: this.onWillReconnect,
        ondisconnect: this.onDisconnect,
        onerror: this.onError,
        // 用户名片
        onmyinfo: this.onMyInfo,
        onupdatemyinfo: this.onUpdateMyInfo,
        onusers: this.onUsers,
        onupdateuser: this.onUpdateUser,
        // // 会话
        syncSessionUnread: true,
        onsessions: this.onSessions,
        onupdatesession: this.onUpdateSession,
        // 同步完成
        onsyncdone: this.onSyncDone
      })
    },
    onConnect(event) {
      console.log('已经连接', event)
      // if (loginInfo) {
      //   // 连接上以后更新uid
      //   commit('updateUserUID', loginInfo)
      // }
    },
    onWillReconnect(event) {
      // 此时说明 SDK 已经断开连接, 请开发者在界面上提示用户连接已断开, 而且正在 重新建立连接
      console.log(event)
    },
    onDisconnect(error) {
      // 此时说明 SDK 处于断开状态, 开发者此时应该根据错误码提示相应的错误信息, 并且跳转到登录页面
      switch (error.code) {
        // 账号或者密码错误, 请跳转到登录页面并提示错误
        case 302:
          console.log('帐号或密码错误', 'login')
          break
        // 被踢, 请提示错误后跳转到登录页面
        case 'kicked':
          // const map = {
          //   PC: '电脑版',
          //   Web: '网页版',
          //   Android: '手机版',
          //   iOS: '手机版',
          //   WindowsPhone: '手机版'
          // }
          // // // let str = error.from
          // const errorMsg = `你的帐号于${map.PC} || '其他端')}踢出下线,请确定帐号信息安全!`
          console.log(error, 'login')
          break
        default:
          break
      }
    },
    onError(event) {
      // alert(JSON.stringify(event))
      alert('网络连接状态异常')
      // location.href = config.loginUrl
    },
    onSyncDone() {
      console.log('数据同步完成')
      // 数据同步完成
      // dispatch('hideLoading')
      // // 说明在聊天列表页
      // if (store.state.currSessionId) {
      //   dispatch('setCurrSession', store.state.currSessionId)
      // }
    },
    onSessions(sessions) {
      // 这里使用sdk自带的方法合并会话列表重新赋值
      this.sessions = this.nim.mergeSessions(this.sessions, sessions)
      // this.usDateSessionsUI() // 更新UI
      this.sessions.forEach(item => {
        const { lastMsg: { custom }} = item
        if (custom) {
          const customList = item.lastMsg.custom = typeof (custom) === 'object' ? custom : JSON.parse(custom)
          if (customList.sysUserId && customList.sysUserId === this.sysUserId) {
            item.hiddleChat = customList.transfer
          } else {
            item.hiddleChat = false
          }
        } else {
          item.hiddleChat = false
        }
      })
      console.log(11111111, this.sessions)
    },
    // 更新会话
    onUpdateSession(session) {
      this.sessions = this.nim.mergeSessions(this.sessions, session)
      this.sessions.forEach(item => {
        const { lastMsg: { custom }} = item
        if (custom) {
          const customList = item.lastMsg.custom = typeof (custom) === 'object' ? custom : JSON.parse(custom)
          if (customList.sysUserId && customList.sysUserId === this.sysUserId) {
            item.hiddleChat = customList.transfer
          } else {
            item.hiddleChat = false
          }
        } else {
          item.hiddleChat = false
        }
      })
      console.log(2222222, this.sessions)
      // this.usDateSessionsUI()// 更新UI
    },
    // 获取历史记录
    getHistoryMsgs(e) {
      this.nim.getHistoryMsgs({
        scene: 'p2p',
        to: e,
        asc: true,
        done: getHistoryMsgsDone
      })
      const that = this
      function getHistoryMsgsDone(error, obj) {
        if (!error) {
          console.log('获取历史记录', obj.msgs)
          const msgs = obj.msgs
          that.chatInfo = msgs
          that.$refs.common_chat.goEnd()
        }
      }
    },
    // 名片
    onMyInfo(user) {
      console.log('收到我的名片', user)
      this.myInfo = user
    },
    onUpdateMyInfo(user) {
      console.log('我的名片更新了', user)
      this.myInfo = SDK.NIM.util.merge(this.myInfo, user)
    },
    onUsers(users) {
      console.log('收到用户名片列表', users)
      this.users = this.nim.mergeUsers(this.users, users)
      console.log(88888, this.users)
    },
    onUpdateUser(user) {
      console.log('用户名片更新了', user)
      this.users = this.nim.mergeUsers(this.users, user)
    },
    // 获取用户信息
    getUserInfo() {
      console.log(3333)
      const accounts = this.sessions.map((item) => {
        if (item.lastMsg) {
          if (item.lastMsg.flow === 'in') {
            return item.lastMsg.from
          } else {
            return item.lastMsg.to
          }
        }
      })
      console.log(7777, accounts)
      this.nim.getUsers({
        accounts: accounts,
        done: (error, users) => {
          console.log(888)
          if (!error) {
            this.accountList = users.map((it, idx) => {
              for (let i = 0; i < this.sessions.length; i++) {
                if (this.sessions[i].lastMsg.flow === 'in') {
                  if (it.account === this.sessions[i].lastMsg.from) {
                    console.log(33333, it)
                  }
                } else {
                  if (it.account === this.sessions[i].lastMsg.to) {
                    console.log(444444, it)
                  }
                }
              }
              return it
            })
          }
        }
      })
    },
    // 选中了会话
    selectedChat(e) {
      console.log('选中了会话', e)
      this.msgsUser = e
      this.getHistoryMsgs(e.to)
    },
    // 转移客服
    transferChat(e) {
      this.sendMsg(e, { transfer: true })
    },
    /**
     * 发送消息
     * @param {Object} rs 回调对象
     * @Chat 判断是否正在聊天中
     */
    sendMsg(rs, transfer) {
      const transferInfo = (transfer && transfer['transfer']) || this.transfer
      console.log('发送消息', this.msgsUser.to)
      this.nim.sendText({
        scene: 'p2p',
        to: this.msgsUser.to,
        text: rs,
        custom: JSON.stringify({
          chatType: this.chatType,
          sysUserId: this.sysUserId,
          transfer: transferInfo,
          customerAccid: this.msgsUser.to,
          customerId: this.msgsUser.lastMsg['customerId']
        }),
        done: sendMsgDone
      })
      const self = this
      function sendMsgDone(error, msg) {
        if (!error) {
          self.chatInfo.push(msg)
          self.$refs.common_chat.goEnd()
        }
      }
    },
    // 预览文件
    previewFile() {
      const self = this
      self.nim.previewFile({
        type: 'image',
        fileInput: 'common_chat_opr_fileUpload',
        done: function(error, file) {
          if (!error) {
            console.log(file)
          }
        }
      })
    },
    // 上传图片
    fileUpload() {
      const self = this
      self.nim.sendFile({
        scene: 'p2p',
        to: self.msgsUser.to,
        type: 'image',
        custom: JSON.stringify({
          chatType: self.chatType,
          sysUserId: self.sysUserId,
          transfer: self.transfer,
          customerAccid: self.msgsUser.to,
          customerId: this.msgsUser.lastMsg['customerId']
        }),
        fileInput: 'common_chat_opr_fileUpload',
        done: sendMsgDone
      })
      function sendMsgDone(error, msg) {
        if (!error) {
          self.chatInfo.push(msg)
          self.$refs.common_chat.goEnd()
        }
      }
    }
  }
}
</script>
<style lang="scss">
  .customer-servce {
    margin: 10px 20px 40px 20px;
    background-color: #FFFFFF;
    height: 100vh;
    .imServer-wrapper {
      box-shadow: 0 0 3px 3px #eee;
      background: #FFFFFF;
      width: 100%;
      height: 100%;
      overflow: hidden;
      .imServer-main {
        height: 100%;
        max-width: 100%;
        position: relative;
        & > .item {
          float: left;
          border-right: 1px solid #e6e6e6;
          height: 100%;
        }
        & > .im-record {
          width: 280px;
        }
        & > .im-chat {
          width: calc(100% - 280px);
        }
      }
    }
  }
</style>

// 聊天列表
<!-- 会话记录 -->
<template>
  <div class="imRecord-wrapper">
    <header class="header">
      <div class="kf-info-wrapper">
        <img class="kf-avatar" :src="myInfo['avatar'] || ''">
        <span class="kf-name position-h-v-mid">
          {{ myInfo.nick }}
          <span>{{ myInfo.sign }}</span>
        </span>
      </div>
    </header>
    <main class="main">
      <div v-if="sessionList.length > 0" class="item-list">
        <div
          v-for="(tmpEn, index) in sessionList"
          :key="index"
          class="item"
          :class="{ active: tmpEn.id === activeId}"
          @click="selectChat(tmpEn, users[index])"
        >
          <div class="followicon-wrapper">
            <i class="iconfont icon-zhidingwujiaoxing position-h-v-mid" :class="{ active: tmpEn.id === activeId}" @click.stop="toggleFollowIcon(tmpEn)" />
          </div>
          <!-- 客户端头像 -->
          <div class="platicon-wrapper">
            <div class="listImg header-img">
              <img :key="users[index]['avatar']" v-lazy="users[index]['avatar']" alt="">
            </div>
          </div>
          <div class="info-wrapper">
            <p class="first-p">
              <span class="name">
                {{ users[index].nick }}
                <span v-if="tmpEn.hiddleChat" style="color:#F56C6C; font-size: 12px">转</span>
              </span>
              <span class="lastMsgTime">{{ getLastMsgTimeStr(tmpEn.lastMsg.time) }}</span>
            </p>
            <p class="second-p">
              <span class="lastMsgContent">{{ tmpEn.lastMsg.text }}</span>
              <el-badge v-show="tmpEn.unread > 0" class="newMsgCount" :value="tmpEn.unread" :max="99" />
            </p>
          </div>
        </div>
      </div>
      <div v-else class="empty-wrapper">
        <div class="content">
          <i class="iconfont fa fa-commenting-o" />
          <p class="title">当前没有会话</p>
        </div>
      </div>
    </main>
  </div>
</template>

<script>
import { formatTime } from '@/utils'
export default {
  name: 'ImRecord',
  props: {
    sessionList: {
      type: Array,
      default() {
        return []
      }
    },
    myInfo: {
      type: Object,
      default() {
        return {}
      }
    },
    users: {
      type: Array,
      default() {
        return []
      }
    }
  },
  data() {
    return {
      session: [],
      activeId: ''
    }
  },
  watch: {
  },
  created() {
  },
  methods: {
    /**
         * 选中当前列表的chat
         * @param {Object} en call实体类
         */
    selectChat(en, users) {
      this.activeId = en.id
      // this.$store.dispatch('selectChat', { clientChatId: en.clientChatId })
      this.$emit('selectedChat', { ...en, ...users }) // 事件上传
    },

    /**
         * 设置关注
         */
    toggleFollowIcon: function(en) {
      en.isFollow = !en.isFollow
      // 排序
      this.$store.imServerStore.commit('sortCurrentChatEnlist', {})
    },

    /**
         * 获取背景class
         * @param {string} clientChatName 姓名
         */
    getBgClass: function(clientChatName) {
      const rs = clientChatName.charCodeAt(0) % 5
      return 'bg' + rs
    },

    /**
         * 返回chat对象的最后一次消息时间
         * @param {String|Date} sValue 传入的时间字符串
         */
    getLastMsgTimeStr: function(sValue) {
      if (sValue === null) {
        return ''
      }
      const rs = formatTime(sValue)
      return rs
    }
  }
}
</script>

<style lang="scss">
.imRecord-wrapper {
  p {
    margin: 0;
  }
    width: 100%;
    height: 550px;
    overflow: hidden;
    border: 0;
    & > .header {
        background: url('../../assets/systemManage/LoginBg.png') no-repeat 100% center scroll;
        overflow: hidden;
        display: flex;
        align-items: center;
        height: 60px;
        border-bottom: 1px solid #e6e6e6;
        .kf-info-wrapper {
            display: flex;
            width: 100%;
            height: 50px;
            padding: 0 20px;
            .kf-avatar {
                align-self: center;
                width: 45px;
                height: 45px;
                border-radius: 50%;
            }
            .kf-name {
                margin-left: 10px;
                align-self: center;
                font-size: 16px;
                span {
                  display: inline-block;
                  font-size: 12px;
                  color: #eaf4fb;
                }
            }
        }
        .client-info-wrapper {
            p:first-child {
                margin-bottom: 5px;
            }
            .fa {
                margin-right: 10px;
            }
        }
    }
    & > .main {
        height: calc(100% - 50px);
        position: relative;
        .item-list {
            height: calc(100% - 46px);
            overflow-y: auto;
            .item {
                position: relative;
                height: 63px;
                padding: 0px;
                border-bottom: 1px solid #e6e6e6;
                cursor: pointer;
                &.active,
                &:hover {
                     background-color: #eee;
                    .info-wrapper .first-p .name,
                    .info-wrapper .second-p .lastMsgContent,
                    .info-wrapper .first-p .lastMsgTime {
                        color: #8d8d8d;
                    }
                    .iconfont {
                        display: initial !important;
                    }
                }
                .followicon-wrapper {
                    position: relative;
                    float: left;
                    width: 25px;
                    height: 100%;
                    .iconfont {
                        display: none;
                        font-size: 12px;
                        color: #eaf4fb;
                        &.active {
                            display: initial;
                            color: #f9ce1d;
                        }
                    }
                }
                .platicon-wrapper {
                    display: flex;
                    align-items: center;
                    float: left;
                    width: 50px;
                    height: 100%;
                    .header-img {
                      width: 40px;
                      height: 40px;
                        /*&.bg0 {*/
                        /*    background-color: #ef7777;*/
                        /*}*/
                        /*&.bg1 {*/
                        /*    background-color: #00bcd4;*/
                        /*}*/
                        /*&.bg2 {*/
                        /*    background-color: #009688;*/
                        /*}*/
                        /*&.bg3 {*/
                        /*    background-color: #ffc107;*/
                        /*}*/
                        /*&.bg4 {*/
                        /*    background-color: #ff5722;*/
                        /*}*/
                    }
                }
                .info-wrapper {
                    position: relative;
                    float: left;
                    width: 185px;
                    padding-top: 5px;
                    padding-left: 5px;
                    .first-p {
                        clear: both;
                        padding-top: 11px;
                        .name {
                            display: inline-block;
                            float: left;
                            width: 50%;
                            font-size: 14px;
                            color: #3e3e3e;
                            white-space: nowrap;
                            text-overflow: ellipsis;
                            overflow: hidden;
                            text-align: left;
                            font-weight: bolder;
                        }
                        .lastMsgTime {
                            float: right;
                            font-size: 12px;
                            color: #8d8d8d;
                        }
                    }
                    .second-p {
                        clear: both;
                        padding-top: 5px;
                        line-height: 1.2;
                        .lastMsgContent {
                            display: inline-block;
                            width: 150px;
                            margin-top: 3px;
                            font-size: 12px;
                            color: #8d8d8d;
                            white-space: nowrap;
                            text-overflow: ellipsis;
                            text-align: left;
                            overflow: hidden;
                        }
                        .newMsgCount {
                            position: relative;
                            top: 4px;
                            float: right;
                            .el-badge__content {
                                border: 1px solid #ffffff00;
                            }
                        }
                    }
                }
            }
        }
        .empty-wrapper {
            font-size: 16px;
            color: #3e3e3e;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            .content {
                width: 170px;
                height: 200px;
                margin: 0px auto;
                text-align: center;
                color: #867c7c;
                .iconfont {
                    font-size: 90px;
                }
                .title {
                    margin-top: 25px;
                }
            }
        }
    }
}
</style>

聊天内容

<!-- 聊天记录 -->
<template>
  <div class="imChat-wrapper">
    <!-- 头部 -->
    <header class="imChat-header">
      <span class="name">
        {{ msgsUser.nick }}
        <span style=" color: #8d8d8d; font-size: 15px;">{{ msgsUser.sign }}</span>
      </span>
    </header>
    <main class="imChat-main">
      <slot />
    </main>
  </div>
</template>

<script>
export default {
  components: {
  },
  props: {
    msgsUser: {
      type: Object,
      default() {
        return []
      }
    }
  }
}
</script>
<style lang="scss">
.imChat-wrapper {
    .imChat-header {
        display: flex;
        align-items: center;
        width: 100%;
        height: 60px;
        // background: #eee;
        padding-left: 10px;
        border-bottom: 1px solid #e6e6e6;
        font-size: 16px;
        span {
            margin-right: 20px;
        }
        .on-line {
            color: #70ed3a;
        }
        .off-line {
            color: #bbbbbb;
        }
    }
    .imChat-main {
        height: calc(100% - 50px);
    }
}
</style>


聊天框

<!-- 聊天记录 -->
<template>
  <div class="common_chat-wrapper">
    <div class="common_chat-inner">
      <!-- 聊天记录 -->
      <div id="common_chat_main" ref="common_chat_main" class="common_chat-main">
        <div class="common_chat-main-content">
          <div class="inner">
            <div v-for="(item ,index) in chatInfoEn" :key="index">
              <!-- 客户、客服 -->
              <div class="item" :class="{ sender: item.flow === 'out', receiver: item.flow === 'in' }">
                <!--时间-->
                <div
                  v-if="InfoToTime(item.time, chatInfoEn[index - 1]) !== ''"
                  style="text-align: center; clear: both; padding: 10px 0; color: rgb(131, 129, 135)"
                >
                  <span> -- {{ InfoToTime(item.time, chatInfoEn[index - 1]) }} --</span>
                </div>
                <div class="info-wrapper">
                  <!-- 头像 -->
                  <div class="avatar-wrapper">
                    <img :key="item.flow === 'out' ? myInfo.avatar : item.avatar" v-lazy="item.flow === 'out' ? myInfo.avatar : item.avatar" class="kf-img">
                  </div>
                  <!-- 1)文本类型 -->
                  <div v-if="item.type ==='text'" class="item-content common_chat_emoji-wrapper-global">
                    <p class="text">{{ item.text }}</p>
                  </div>
                  <!-- 2)图片类型 -->
                  <div v-else-if="item.type ==='image'" class="item-content">
                    <img class="img" :src="item.file.url" @click="imgViewDialog_show(item.file)">
                  </div>
                  <!-- 3)文件类型 -->
                  <div v-else-if="item.type ==='file'" class="item-content">
                    <div class="file">
                      <i class="file-icon iconfont fa fa-file" />
                      <div class="file-info">
                        <p class="file-name">{{ getFileName(item.fileName) }}</p>
                        <div class="file-opr">
                          <div v-show="item.state === 'success'">
                            <a class="file-download" :href="item.fileUrl" target="_blank" :download="item.fileUrl">下载</a>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  <!--                  &lt;!&ndash; 4)文本类型 &ndash;&gt;-->
                  <!--                  <div v-if="item.type ==='transformServer'" class="item-content common_chat_emoji-wrapper-global">-->
                  <!--                    <p class="text">-->
                  <!--                      当前没有配置机器人,-->
                  <!--                      <el-button type="text" @click="chatCallback('transformServer')">转接客服</el-button>-->
                  <!--                    </p>-->
                  <!--                  </div>-->
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="common_chat-footer">
        <div>
          <!-- 表情、文件选择等操作 -->
          <div class="opr-wrapper">
            <common-chat-emoji ref="qqemoji" class="item" @activeEmoji="qqemoji_selectFace" />
            <a class="item" href="javascript:void(0)" @click="fileUpload_click('file')">
              <i class="el-icon-picture-outline" style="font-size: 20px; color: #aaa" />
            </a>
            <form method="post" enctype="multipart/form-data">
              <input
                id="common_chat_opr_fileUpload"
                type="file"
                name="uploadFile"
                style="display:none;position:absolute;left:0;top:0;width:0%;height:0%;opacity:0;"
                accept="image/png,image/gif,image/jpg,image/jpeg"
              >
            </form>
          </div>
          <!-- 聊天输入框 -->
          <div class="input-wrapper">
            <el-input
              v-model="inputContent"
              type="textarea"
              placeholder="请输入内容"
              maxlength="500"
              @keydown.native="listenInput($event)"
            />
          </div>
          <!-- 发送按钮 -->
          <el-button
            v-if="!msgsUser.hiddleChat"
            size="small"
            class="send-btn"
            :disabled="inputContent.length === 0"
            @click="sendText"
          >
            发送
          </el-button>
          <el-button
            v-if="!msgsUser.hiddleChat"
            size="small"
            class="send-btn"
            @click="transferChat"
          >
            转移客服
          </el-button>
        </div>
        <!-- 离线 -->
        <div v-show="msgsUser.hiddleChat" class="off-wrapper">
          <span class="content">会话已经结束</span>
        </div>
      </div>
    </div>
    <!-- 图片查看dialog -->
    <el-dialog title :visible.sync="imgViewDialogVisible" class="imgView-dialog" :modal="false">
      <div class="header">
        <i class="iconfont fa fa-remove" @click="imgViewDialogVisible = !imgViewDialogVisible" />
      </div>
      <div class="main">
        <img class="img" :src="imgViewDialog_imgSrc.url" :width="imgViewDialog_imgSrc.width" :height="imgViewDialog_imgSrc.height">
      </div>
    </el-dialog>
  </div>
</template>

<script>
import common_chat_emoji from './common_chat_emoji.vue'
import { InfoTime, parseTime } from '@/utils'
export default {
  components: {
    commonChatEmoji: common_chat_emoji
  },
  props: {
    chatInfoEn: {
      type: Array,
      default() {
        return []
      }
    },
    myInfo: {
      type: Object,
      default() {
        return {}
      }
    },
    msgsUser: {
      type: Object,
      default() {
        return {}
      }
    },
    oprRoleName: {
      required: true,
      type: String,
      default: ''
    } // 操作者名称;e.g. server:服务端、client:客服端
  },
  data() {
    return {
      inputContent: '',
      transferInfo: '将为您转接人工客服,请稍等',
      imgViewDialogVisible: false, // 图片查看dialog的显示
      imgViewDialog_imgSrc: {} // 图片查看dialog的图片地址
    }
  },
  computed: {},
  watch: {
    chatInfoEn() {
      this.inputContent = ''
    }
  },
  mounted() {
  },
  methods: {
    // 转移客服
    transferChat() {
      this.$emit('transferChat', this.transferInfo)
    },
    // 键盘事件
    listenInput(event) {
      if (event.keyCode === 13) {
        event.preventDefault()
        this.sendText()
      }
    },
    InfoToTime(time, lastTime) {
      if (lastTime) {
        const Info = InfoTime(time, lastTime.time)
        return Info
      } else {
        return parseTime(time, '{m}-{d} {h}:{i}')
      }
    },
    // 发送文本
    sendText() {
      this.$emit('sendText', this.inputContent)
    },
    // 文件上传_点击
    fileUpload_click(fileType) {
      document.getElementById('common_chat_opr_fileUpload').onchange = this.fileUpload_change
      document.getElementById('common_chat_opr_fileUpload').click()
    },

    /**
     * 文件上传_选中文件
     */
    fileUpload_change(e) {
      this.$emit('fileUpload', e)
    },

    // qqemoji选中表情
    qqemoji_selectFace(rs) {
      this.inputContent += rs
    },
    /**
         * 转换文件名,若文件名称超过9个字符,将进行截取处理
         * @param {String} fileName 文件名称
         */
    getFileName: function(fileName) {
      if (!fileName) {
        return
      }
      let name = fileName.substring(0, fileName.lastIndexOf('.'))
      const extend = fileName.substring(fileName.lastIndexOf('.') + 1)
      if (name.length > 9) {
        name = name.substring(0, 3) + '...' + name.substring(name.length - 3)
      }
      return name + '.' + extend
    },
    // 图片查看dialog_显示
    imgViewDialog_show(item) {
      this.imgViewDialogVisible = true
      this.imgViewDialog_imgSrc = item
    },
    // 聊天记录滚动到底部
    goEnd() {
      this.$nextTick(() => {
        setTimeout(() => {
          this.$refs.common_chat_main.scrollTop = this.$refs.common_chat_main.scrollHeight
        }, 100)
      })
    }
  }
}
</script>
<style lang="scss">
.common_chat-wrapper {
  /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
  ::-webkit-scrollbar
  {
    width: 8px;
    height: 16px;
    background-color: #ffffff;
  }

  /*定义滚动条轨道 内阴影+圆角*/
  ::-webkit-scrollbar-track
  {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.2);
    border-radius: 10px;
    background-color: #ffffff;
  }

  /*定义滑块 内阴影+圆角*/
  ::-webkit-scrollbar-thumb
  {
    border-radius: 10px;
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
    background-color: #eee;
  }
  p {
    margin: 0;
  }
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
    font-size: 12px;
    float: left;
    border: 0;
    .common_chat-inner {
        width: 100%;
        height: 100%;
        .common_chat-main {
            position: relative;
            height: calc(100% - 150px);
            overflow-y: auto;
            overflow-x: hidden;
            .common_chat-main-header {
                padding-top: 14px;
                text-align: center;
                .el-button {
                    padding: 0;
                    font-size: 12px;
                    color: #8d8d8d;
                }
            }
            .common_chat-main-content {
                position: absolute;
                width: 100%;
                height: 100%;
                & > .inner {
                    padding-bottom: 20px;
                    .item {
                        clear: both;
                        overflow: hidden;
                    }
                    .sys {
                        color: #b0b0b0;
                        font-size: 12px;
                        text-align: center;
                        .text-content {
                            padding-top: 20px;
                        }
                        .myd-content {
                            .desc {
                                margin-top: 18px;
                            }
                            .text {
                                color: #3e3e3e;
                                margin-top: 12px;
                            }
                            .remark {
                                margin-top: 10px;
                            }
                        }
                    }
                    .receiver,
                    .sender {
                        margin-top: 18px;
                        font-size: 12px;
                        .avatar-wrapper {
                            float: left;
                            .kf-img {
                                width: 40px;
                                height: 40px;
                            }
                        }
                        .info-wrapper {
                            position: relative;
                            text-align: left;
                            font-size: 12px;
                            .item-content {
                                position: relative;
                                max-width: 330px;
                                color: #3e3e3e;
                                font-size: 13px;
                                border-radius: 3px;
                                .text {
                                    line-height: 1.8;
                                    white-space: normal;
                                    word-wrap: break-word;
                                    word-break: break-all;
                                    padding: 10px 12px;
                                }
                                .qqemoji {
                                    width: 24px;
                                    height: 24px;
                                }
                                .img {
                                    max-width: 320px;
                                    max-height: 240px;
                                    white-space: normal;
                                    word-wrap: break-word;
                                    word-break: break-all;
                                    padding: 5px;
                                    cursor: pointer;
                                }
                                .file {
                                    width: 220px;
                                    padding: 10px 8px;
                                    margin: 3px;
                                    overflow: hidden;
                                    background: #fff;
                                    border-radius: 5px;
                                    .el-button {
                                        padding: 0px;
                                        font-size: 12px;
                                    }
                                    .file-info {
                                        float: left;
                                        padding: 0px 8px;
                                        .file-name {
                                            width: 160px;
                                            display: inline-block;
                                            color: #333333;
                                            white-space: nowrap;
                                            text-overflow: ellipsis;
                                            overflow: hidden;
                                            line-height: 1.3;
                                        }
                                    }
                                    .file-opr {
                                        margin-top: 8px;
                                    }
                                    .file-icon {
                                        float: left;
                                        color: #663399;
                                        font-size: 40px;
                                    }
                                    .file-download {
                                        color: #00a8d7;
                                        cursor: pointer;
                                        text-decoration: blink;
                                    }
                                }
                                .preInput {
                                    position: relative;
                                    color: #8d8d8d;
                                    img {
                                        height: 15px;
                                        position: relative;
                                        top: 3px;
                                    }
                                }
                                .issueList {
                                    width: 250px;
                                    padding: 10px;
                                    .title {
                                        position: relative;
                                        .content {
                                            position: absolute;
                                            margin-top: -1px;
                                            margin-left: 6px;
                                        }
                                    }
                                    .el-collapse-item__wrap {
                                        background: transparent;
                                    }
                                    .el-collapse {
                                        border: 0px;
                                        margin-top: 8px;
                                        margin-bottom: -8px;
                                        .el-collapse-item__header {
                                            font-size: 13px;
                                            background: transparent;
                                            color: #f7455d;
                                            padding-left: 5px;
                                        }
                                        .el-collapse-item__wrap {
                                            .el-collapse-item__content {
                                                font-size: 12px;
                                                color: #3e3e3e;
                                                padding-left: 5px;
                                            }
                                        }
                                    }
                                }
                                .issueExtend {
                                    width: 250px;
                                    padding: 10px 10px 0px;
                                    .main {
                                        border-top: 1px solid #eeeff0;
                                        margin-top: 10px;
                                        padding-top: 10px;
                                        p {
                                            margin-bottom: 5px;
                                        }
                                        .el-button {
                                            font-size: 12px;
                                            color: #f7455d;
                                        }
                                    }
                                }
                                .issueResult {
                                    width: 250px;
                                    .main {
                                        padding: 10px;
                                    }
                                    .footer {
                                        border-top: 1px solid #eeeff0;
                                        height: 30px;
                                        .btn {
                                            width: 60px;
                                            margin: 0px 30px;
                                            padding: 6px 0px;
                                            display: inline-block;
                                            text-align: center;
                                            font-size: 10px;
                                            color: #8d8d8d;
                                            cursor: pointer;
                                            position: relative;
                                            &:first-child::after {
                                                top: 4px;
                                                right: -30px;
                                                width: 1px;
                                                height: 80%;
                                                content: '';
                                                position: absolute;
                                                background-color: #eeeff0;
                                                z-index: 0;
                                            }
                                        }
                                        .iconfont {
                                            font-size: 10px;
                                            margin-right: 5px;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    .item.receiver {
                        margin-left: 5px;
                        .avatar-wrapper {
                            margin-right: 15px;
                        }
                        .info-wrapper {
                            .item-content {
                                float: left;
                                color: #000000;
                                background-color: #f9fbfc;
                                border: 1px solid #ccc;
                                &::before {
                                    position: absolute;
                                    top: -1px;
                                    left: -10px;
                                    width: 0px;
                                    height: 0px;
                                    content: '';
                                    border-top: 0px;
                                    border-right: 10px solid #ccc;
                                    border-bottom: 5px solid transparent;
                                    border-left: 0px;
                                }
                            }
                        }
                    }
                    .item.sender {
                        margin-right: 5px;
                        .avatar-wrapper {
                            float: right;
                            margin-left: 15px;
                        }
                        .info-wrapper {
                            float: right;
                            .item-content {
                                float: right;
                                background: #eee;
                                border: 1px solid #eee;
                                &::before {
                                    position: absolute;
                                    top: -1px;
                                    right: -10px;
                                    width: 0;
                                    height: 0;
                                    content: '';
                                    border-top: 0;
                                    border-right: 0;
                                    border-bottom: 5px solid transparent;
                                    border-left: 10px solid #eee;
                                }
                            }
                        }
                    }
                }
            }
        }
        .common_chat-footer {
            position: relative;
            width: 100%;
            border-top: 1px solid #ccc;
            .opr-wrapper {
                height: 20px;
                padding: 10px;
                text-align: left;
                & > .item {
                    margin-right: 12px;
                    float: left;
                    font-weight: normal;
                    text-decoration: blink;
                    & > .iconfont {
                        color: #aaa;
                        font-size: 20px;
                    }
                }
            }
            .input-wrapper {
                position: relative;
                padding: 2px 0px 0px 10px;
                .inputContent {
                    width: 99%;
                    padding: 2px;
                    height: 85px;
                    resize: none;
                    overflow: auto;
                    line-height: 1.5;
                    outline: 0px solid transparent;
                }
                .shortcutPopover-wrapper {
                    position: absolute;
                    top: 30px;
                    left: 10px;
                    width: 440px;
                    max-height: 80px;
                    padding: 4px;
                    font-size: 12px;
                    overflow-y: auto;
                    border: 1px solid #9b9aab;
                    border-radius: 3px;
                    background-color: #fff;
                    cursor: pointer;
                    p {
                        padding: 4px;
                        &.selected {
                            background-color: #ded1cc;
                        }
                        .key {
                            display: inline-block;
                            width: 50px;
                            white-space: nowrap;
                            text-overflow: ellipsis;
                            overflow: hidden;
                        }
                        .content {
                            display: inline-block;
                            width: 350px;
                            margin-left: 10px;
                            white-space: nowrap;
                            text-overflow: ellipsis;
                            overflow: hidden;
                        }
                        .highlight {
                            color: #00a8d7;
                        }
                    }
                }
                .tips {
                    position: absolute;
                    top: 7px;
                    left: 20px;
                    width: auto;
                    color: #8d8d8d;
                }
            }
            .send-btn {
                float: right;
                margin-right: 16px;
                &.off,
                &.end {
                    background-color: #ccc;
                    border-color: #ccc;
                }
            }
            .off-wrapper {
                position: absolute;
                top: 0px;
                left: 0px;
                width: 100%;
                height: 100%;
                background-color: rgba(255, 255, 255, 0.6);
                font-size: 14px;
                .content {
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                }
            }
        }
    }
}
.imgView-dialog {
    background: #00000080;
    height: 100%;
    .el-dialog {
        max-width: 75%;
        position: relative;
        background: transparent;
        box-shadow: none;
        .el-dialog__header {
            display: none;
        }
        .el-dialog__body {
            padding: 0px;
            text-align: center;
            position: relative;
            .header {
                text-align: right;
                position: relative;
                height: 0px;
                .fa-remove {
                    font-size: 32px;
                    color: white;
                    position: relative;
                    right: -50px;
                    top: -30px;
                    cursor: pointer;
                }
            }
            .main {
                .img {
                    max-width: 100%;
                    max-height: 100%;
                    height: 100%;
                }
            }
        }
    }
}
</style>
<style lang="scss">
  .common_chat-wrapper {
    .el-textarea__inner {
      border: none;
      height: 100%;
      resize: none;
    }
    .common_chat-footer {
      .el-button {
        background-color: #eee;
        border-color: #eee;
        color: rgb(131, 129, 135);
        border-radius: 0;
      }
    }
  }
</style>


表情

export const emojiMap = new Map([
  ['grinning', '😀'],
  ['grin', '😁'],
  ['joy', '😂'],
  ['smiley', '😃'],
  ['smile', '😄'],
  ['sweat_smile', '😅'],
  ['laughing', '😆'],
  ['satisfied', '😆'],
  ['innocent', '😇'],
  ['smiling_imp', '😈'],
  ['wink', '😉'],
  ['blush', '😊'],
  ['yum', '😋'],
  ['relieved', '😌'],
  ['heart_eyes', '😍'],
  ['sunglasses', '😎'],
  ['smirk', '😏'],
  ['neutral_face', '😐'],
  ['expressionless', '😑'],
  ['unamused', '😒'],
  ['sweat', '😓'],
  ['pensive', '😔'],
  ['confused', '😕'],
  ['confounded', '😖'],
  ['kissing', '😗'],
  ['kissing_heart', '😘'],
  ['kissing_smiling_eyes', '😙'],
  ['kissing_closed_eyes', '😚'],
  ['stuck_out_tongue', '😛'],
  ['stuck_out_tongue_winking_eye', '😜'],
  ['stuck_out_tongue_closed_eyes', '😝'],
  ['disappointed', '😞'],
  ['worried', '😟'],
  ['angry', '😠'],
  ['rage', '😡'],
  ['cry', '😢'],
  ['persevere', '😣'],
  ['triumph', '😤'],
  ['disappointed_relieved', '😥'],
  ['frowning', '😦'],
  ['anguished', '😧'],
  ['fearful', '😨'],
  ['weary', '😩'],
  ['sleepy', '😪'],
  ['tired_face', '😫'],
  ['grimacing', '😬'],
  ['sob', '😭'],
  ['open_mouth', '😮'],
  ['hushed', '😯'],
  ['cold_sweat', '😰'],
  ['scream', '😱'],
  ['astonished', '😲'],
  ['flushed', '😳'],
  ['sleeping', '😴'],
  ['dizzy_face', '😵'],
  ['no_mouth', '😶'],
  ['mask', '😷'],
  ['smile_cat', '😸'],
  ['joy_cat', '😹'],
  ['smiley_cat', '😺'],
  ['heart_eyes_cat', '😻'],
  ['smirk_cat', '😼'],
  ['kissing_cat', '😽'],
  ['pouting_cat', '😾'],
  ['crying_cat_face', '😿'],
  ['scream_cat', '🙀'],
  ['no_good', '🙅'],
  ['ok_woman', '🙆'],
  ['bow', '🙇'],
  ['see_no_evil', '🙈'],
  ['hear_no_evil', '🙉'],
  ['speak_no_evil', '🙊'],
  ['raising_hand', '🙋'],
  ['raised_hands', '🙌'],
  ['person_frowning', '🙍'],
  ['person_with_pouting_face', '🙎'],
  ['pray', '🙏']
])
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜丶陌颜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值