dialog-实现滚动聊天窗口

未完待续...

1.实现的vue

<!--聊天窗口-->
<template>
  <div class="soundRecordDialog">
    <el-dialog
      title="聊天窗口"
      :visible="soundVisible"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      center
      @close="closeAudioWindow()"
    >
      <audio :src="audioUrl" style=" 85%;outline:0;" controls></audio>
      <!-- <iframe :src="audioUrl" width="100%" height="140px" frameborder="0"></iframe> -->
      <div class="dialog-box">
      <div class="dialog-main">
        <div class="dialog-content">
          <img slot="reference" class="dialog-content-sub" src="@/assets/callingResult/callingResult_phone.png" />
          <span class="dialog-content-sub"> {{ detailName }}</span>
          <span class="dialog-content-sub">{{ detailPhone }}</span>
          <span class="dialog-content-sub">{{ detailCallingStatus }}</span>
        </div>
      </div>
      <div class="dialog-message" id="scroll">
        <ul class="position-box">
          <li v-for="item in detailList" :key="item.index">
            <div class="main">
              <div v-if="item.sRobotSpeech || item.sRobotSpeechId" class="dialog-robot">
                <img class="avatar" src="@/assets/callingResult/callingResult_system_icon.png" />
                <div class="text" v-html="handleRobotText(item)" style="text-align:left"></div>
              </div>
              <div v-if="item.sCustomerSpeech || item.sIntentionId || item.sIntention" class="dialog-self">
                <img class="avatar" src="@/assets/callingResult/callingResult_self_icon.png" />
                <div class="text" style="text-align: center" v-html="handleCustomPeopleText(item)"></div>
              </div>
            </div>
          </li>
        </ul>
          <div style="text-align: center;height:25px;" v-if="callLoading">
            <img src="@/assets/loading.gif" style="20px; height:20px;">
          </div>
          <div v-if="!loadMore" style="text-align: center;height:30px;">
            {{ handleLoadMoreText(loadMore, this.detailList) }}
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { setRobotText, setCustomPeopleText, setLoadMoreText, hanldPhoneFormatToValue } from '@/utils/common'
export default {
  name: 'soundRecord',
  data () {
    return {
      callLoading: true,
      loadMore: true, // 加载更多,默认Yes
      detailName: '',
      detailPhone: '',
      detailCallingStatus: '',
      detailParams: {
        pageNum: 1,
        pageSize: 10,
        callId: ''
      },
      soundCallList: [],
      detailCallResData: [], // 列表
      detailList: [] // 列表
    }
  },
  props: {
    audioUrl: {
      default: '',
      type: String
    },
    callSoundData: {
      default: null,
      type: Object
    },
    soundVisible: {
      default: false,
      type: Boolean
    }
  },
  async created () {
    if (this.callSoundData && this.callSoundData.callId && this.callSoundData.callId.length > 0) {
      this.detailParams.callId = this.callSoundData.callId
      this.detailParams.pageNum = 1
      this.detailName = this.callSoundData.customerName
      this.detailPhone = this.hanlePhoneFormat(this.callSoundData.customerPhone)
      this.detailCallingStatus = this.callSoundData.callState
      await this.callDetaiList()
      this.detailList = this.detailCallResData
      if (this.detailList.length > 0) {
        this.$nextTick(() => {
          this.detailParams.pageNum = 1
          document.getElementById('scroll').scrollTop = 0
          if (this.detailParams.pageNum === 1 && this.detailList && this.detailList.length < 10) {
            this.callDetailListLoadMoreFlag(false)
            return
          } else if (document.getElementById('scroll').clientHeight === document.getElementById('scroll').scrollHeight) {
            this.handleScroll()
            return
          } else {
            this.callDetailListLoadMoreFlag(true)
          }
          document.getElementById('scroll').addEventListener('scroll', this.handleScroll)
        })
      } else {
        this.callDetailListLoadMoreFlag(false)
      }
    }
  },
  methods: {
    // 关闭录音
    closeAudioWindow () {
      this.$emit('close')
    },
    // 处理机器人话术
    handleRobotText (item) {
      return setRobotText(item)
    },
    handleCustomPeopleText (item) {
      return setCustomPeopleText(item)
    },
    // 处理没有更多数据了文字
    handleLoadMoreText (loadMore, soundCallList) {
      return setLoadMoreText(loadMore, soundCallList)
    },
    // 明细列表
    async callDetaiList () {
      await this.$store.dispatch('callResultDetailList', this.detailParams).then(res => {
        this.detailCallResData = res.data.detailLists
      })
    },
    // 处理电话显示
    hanlePhoneFormat (phone) {
      return hanldPhoneFormatToValue(phone)
    },
    // 处理更多
    callDetailListLoadMoreFlag (flag) {
      this.loadMore = flag
      this.callLoading = flag
    },
    // 处理滚动到底部的事件
    handleScroll () {
      if (this.detailParams.pageNum === 1 && this.detailList && this.detailList.length < 10) {
        this.callDetailListLoadMoreFlag(false)
        this.removeCallDetailScrollLiten()
        return
      }
      var clientHeight = document.getElementById('scroll').clientHeight // 客户区大小
      var scrollHeight = document.getElementById('scroll').scrollHeight // 没用滚动条的情况下,元素内容的总高度
      var scrollTop = document.getElementById('scroll').scrollTop // 被隐藏在内容区域上方的像素数
      if (scrollTop + clientHeight + 0.5 >= scrollHeight && this.loadMore) {
        this.onPullingUp()
      }
      if (!this.loadMore) {
        this.callDetailListLoadMoreFlag(false)
        this.removeCallDetailScrollLiten()
      }
    },
    // 删除明细滚动监听
    removeCallDetailScrollLiten () {
      document.getElementById('scroll').removeEventListener('scroll', this.handleScroll)
    },
    async onPullingUp () {
      this.detailCallResData = []
      this.detailParams.pageNum++
      this.callLoading = true
      await this.callDetaiList()
      if (this.detailCallResData && this.detailCallResData.length > 0) {
        this.detailList = this.detailList.concat(this.detailCallResData)
        console.log('--detailCallResData--', this.detailList)
        if (this.detailCallResData.length < 10) {
          this.callDetailListLoadMoreFlag(false)
          this.removeCallDetailScrollLiten()
        }
      } else {
        this.callDetailListLoadMoreFlag(false)
        this.removeCallDetailScrollLiten()
      }
    }
  }
}
</script>
<style lang="scss">
  .soundRecordDialog {
    display: flex;
    justify-content: center;
    align-items: Center;
    overflow: hidden;
    .el-dialog {
      margin: 60px auto !important;
      height: 90%;
      overflow: hidden;
      .el-dialog__header {
        text-align: left;
      }
      .el-dialog__body {
        padding: 20px 0px 20px 0px;
        position: absolute;
        left: 0;
        top: 54px;
        bottom: 0;
        right: 0;
        padding: 0;
        z-index: 1;
        overflow: hidden;
        text-align: center;
        .dialog-box {
        .dialog-main {
          background: #fef7ea;
          height: 40px;
          .dialog-content {
            padding: 11px 20px 8px 11px;
            font-size: #686A76;
            float:left;
            .dialog-content-sub {
              margin-right: 2px;
            }
          }
        }
        .dialog-message {
            overflow-y: scroll;
            position: absolute;
            top: 104px;
            bottom:0;
            right: 0;
            left: 0;
            .position-box {
              margin-top: 60px;
              padding-left: 20px;
              .main {
                text-align: left;
              }
            ul {
              margin-left: -20px;
            }
            li {
              list-style-type: none;
              margin-bottom: 15px;
            }
            .avatar {
              float: left;
              margin: 0 10px 0 0;
              border-radius: 3px;
               33px;
              height: 32px;
            }
            .text {
              display: inline-block;
              position: relative;
              padding: 0 10px;
              max- calc(100% - 120px);
              min-height: 30px;
              line-height: 30px;
              font-size: 12px;
              text-align: left;
              word-break: break-all;
              background-color: #fafafa;
              border-radius: 4px;
              &:before {
                content: " ";
                position: absolute;
                top: 9px;
                right: 100%;
                border: 6px solid transparent;
                border-right-color: #fafafa;
              }
            }
          .dialog-robot {
            display: inline;
            text-align: left;
          }
          .dialog-self {
              text-align: right;
              margin-top: 20px;
              .avatar {
                float: right;
                margin: 0 20px 0 10px;
              }
              .text {
                background-color: #b2e281;
                &:before {
                  right: inherit;
                  left: 100%;
                  border-right-color: transparent;
                  border-left-color: #b2e281;
                }
              }
            }
          }
        }
      }
    }
  }
}
</style>

2. 调用的方法

// 处理聊天人A
export function setRobotText(item) {
  if (item.sRobotSpeechId && item.sRobotSpeechId.length) {
    return `<span style="font-weight: bolder;font-size: 13px;">${item.sRobotSpeechId}:</span>${item.sRobotSpeech}`
  }
  return item.sRobotSpeech
}
// 处理聊天人B
export function setCustomPeopleText(item) {
  if (item.sIntentionDetail && item.sIntentionDetail.length) {
    if (item.sIntention && item.sIntention.length > 0) {
      if (item.sCustomerSpeech && item.sCustomerSpeech.length > 0) {
        return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntention}-${item.sIntentionDetail}:</span>${item.sCustomerSpeech}`
      }else {
        return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntention}-${item.sIntentionDetail}`
      }
    } else if (item.sCustomerSpeech && item.sCustomerSpeech.length > 0) {
      return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntentionDetail}:</span>${item.sCustomerSpeech}`
    } else {
      return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntentionDetail}</span>`
    }
  } else if (item.sIntention && item.sIntention.length) {
    if (item.sCustomerSpeech && item.sCustomerSpeech.length > 0) {
      return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntention}:</span>${item.sCustomerSpeech}`
    } else {
      return `<span style="font-weight: bolder;font-size: 13px;">${item.sIntention}</span>`
    }
  }
  return item.sCustomerSpeech
}
export function setLoadMoreText(loadMore, detailList) {
  let text = '没有更多数据了'
  if (!loadMore && detailList && detailList.length > 0) {
    let item = detailList[detailList.length-1]
    if (item.robotId) {
      return `${item.robotId}聊天结束`
    }
    return text
  }
  return text
}
原文地址:https://www.cnblogs.com/TheYouth/p/14213080.html