297 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Vue
		
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Vue
		
	
	
<template>
 | 
						|
  <view class="chat-box">
 | 
						|
    <!--  消息渲染  -->
 | 
						|
    <view class="message-item ss-flex-col scroll-item">
 | 
						|
      <view class="ss-flex ss-row-center ss-col-center">
 | 
						|
        <!-- 日期 -->
 | 
						|
        <view v-if="message.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(message, messageIndex)"
 | 
						|
              class="date-message">
 | 
						|
          {{ formatDate(message.createTime) }}
 | 
						|
        </view>
 | 
						|
        <!-- 系统消息 -->
 | 
						|
        <view v-if="message.contentType === KeFuMessageContentTypeEnum.SYSTEM" class="system-message">
 | 
						|
          {{ message.content }}
 | 
						|
        </view>
 | 
						|
      </view>
 | 
						|
      <!-- 消息体渲染管理员消息和用户消息并左右展示  -->
 | 
						|
      <view
 | 
						|
        v-if="message.contentType !== KeFuMessageContentTypeEnum.SYSTEM"
 | 
						|
        class="ss-flex ss-col-top"
 | 
						|
        :class="[
 | 
						|
              message.senderType === UserTypeEnum.ADMIN
 | 
						|
                ? `ss-row-left`
 | 
						|
                : message.senderType === UserTypeEnum.MEMBER
 | 
						|
                ? `ss-row-right`
 | 
						|
                : '',
 | 
						|
            ]"
 | 
						|
      >
 | 
						|
        <!-- 客服头像 -->
 | 
						|
        <image
 | 
						|
          v-show="message.senderType === UserTypeEnum.ADMIN"
 | 
						|
          class="chat-avatar ss-m-r-24"
 | 
						|
          :src="
 | 
						|
                sheep.$url.cdn(message.senderAvatar) ||
 | 
						|
                sheep.$url.static('/static/img/shop/chat/default.png')
 | 
						|
              "
 | 
						|
          mode="aspectFill"
 | 
						|
        ></image>
 | 
						|
        <!-- 内容 -->
 | 
						|
        <template v-if="message.contentType === KeFuMessageContentTypeEnum.TEXT">
 | 
						|
          <view class="message-box" :class="{'admin': message.senderType === UserTypeEnum.ADMIN}">
 | 
						|
            <mp-html :content="replaceEmoji(message.content)" />
 | 
						|
          </view>
 | 
						|
        </template>
 | 
						|
        <template v-if="message.contentType === KeFuMessageContentTypeEnum.IMAGE">
 | 
						|
          <view class="message-box" :class="{'admin': message.senderType === UserTypeEnum.ADMIN}"
 | 
						|
                :style="{ width: '200rpx' }">
 | 
						|
            <su-image
 | 
						|
              class="message-img"
 | 
						|
              isPreview
 | 
						|
              :previewList="[sheep.$url.cdn(message.content)]"
 | 
						|
              :current="0"
 | 
						|
              :src="sheep.$url.cdn(message.content)"
 | 
						|
              :height="200"
 | 
						|
              :width="200"
 | 
						|
              mode="aspectFill"
 | 
						|
            ></su-image>
 | 
						|
          </view>
 | 
						|
        </template>
 | 
						|
        <template v-if="message.contentType === KeFuMessageContentTypeEnum.PRODUCT">
 | 
						|
          <GoodsItem
 | 
						|
            :goodsData="getMessageContent(message)"
 | 
						|
            @tap="
 | 
						|
                    sheep.$router.go('/pages/goods/index', {
 | 
						|
                      id: getMessageContent(message).id,
 | 
						|
                    })
 | 
						|
                  "
 | 
						|
          />
 | 
						|
        </template>
 | 
						|
        <template v-if="message.contentType === KeFuMessageContentTypeEnum.ORDER">
 | 
						|
          <OrderItem
 | 
						|
            :orderData="getMessageContent(message)"
 | 
						|
            @tap="
 | 
						|
                  sheep.$router.go('/pages/order/detail', {
 | 
						|
                    id: getMessageContent(message).id,
 | 
						|
                  })
 | 
						|
                "
 | 
						|
          />
 | 
						|
        </template>
 | 
						|
        <!-- user头像 -->
 | 
						|
        <image
 | 
						|
          v-if="message.senderType === UserTypeEnum.MEMBER"
 | 
						|
          class="chat-avatar ss-m-l-24"
 | 
						|
          :src="sheep.$url.cdn(message.senderAvatar) ||
 | 
						|
                sheep.$url.static('/static/img/shop/chat/default.png')"
 | 
						|
          mode="aspectFill"
 | 
						|
        >
 | 
						|
        </image>
 | 
						|
      </view>
 | 
						|
    </view>
 | 
						|
  </view>
 | 
						|
</template>
 | 
						|
 | 
						|
<script setup>
 | 
						|
  import { computed, unref } from 'vue';
 | 
						|
  import dayjs from 'dayjs';
 | 
						|
  import { KeFuMessageContentTypeEnum, UserTypeEnum } from '@/pages/chat/util/constants';
 | 
						|
  import { emojiList } from '@/pages/chat/util/emoji';
 | 
						|
  import sheep from '@/sheep';
 | 
						|
  import { formatDate } from '@/sheep/util';
 | 
						|
  import GoodsItem from '@/pages/chat/components/goods.vue';
 | 
						|
  import OrderItem from '@/pages/chat/components/order.vue';
 | 
						|
 | 
						|
  const props = defineProps({
 | 
						|
    // 消息
 | 
						|
    message: {
 | 
						|
      type: Object,
 | 
						|
      default: ()=>({}),
 | 
						|
    },
 | 
						|
    // 消息索引
 | 
						|
    messageIndex: {
 | 
						|
      type: Number,
 | 
						|
      default: 0,
 | 
						|
    },
 | 
						|
    // 消息列表
 | 
						|
    messageList:{
 | 
						|
      type: Array,
 | 
						|
      default: () => [],
 | 
						|
    }
 | 
						|
  });
 | 
						|
  const getMessageContent = computed(() => (item) => JSON.parse(item.content)); // 解析消息内容
 | 
						|
 | 
						|
  //======================= 工具 =======================
 | 
						|
 | 
						|
  const showTime = computed(() => (item, index) => {
 | 
						|
    if (unref(props.messageList)[index + 1]) {
 | 
						|
      let dateString = dayjs(unref(props.messageList)[index + 1].createTime).fromNow();
 | 
						|
      return dateString !== dayjs(unref(item).createTime).fromNow();
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  });
 | 
						|
 | 
						|
  // 处理表情
 | 
						|
  function replaceEmoji(data) {
 | 
						|
    let newData = data;
 | 
						|
    if (typeof newData !== 'object') {
 | 
						|
      let reg = /\[(.+?)]/g; // [] 中括号
 | 
						|
      let zhEmojiName = newData.match(reg);
 | 
						|
      if (zhEmojiName) {
 | 
						|
        zhEmojiName.forEach((item) => {
 | 
						|
          let emojiFile = selEmojiFile(item);
 | 
						|
          newData = newData.replace(
 | 
						|
            item,
 | 
						|
            `<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${sheep.$url.cdn(
 | 
						|
              '/static/img/chat/emoji/' + emojiFile,
 | 
						|
            )}"/>`,
 | 
						|
          );
 | 
						|
        });
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return newData;
 | 
						|
  }
 | 
						|
 | 
						|
  function selEmojiFile(name) {
 | 
						|
    for (let index in emojiList) {
 | 
						|
      if (emojiList[index].name === name) {
 | 
						|
        return emojiList[index].file;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
</script>
 | 
						|
 | 
						|
<style scoped lang="scss">
 | 
						|
  .message-item {
 | 
						|
    margin-bottom: 33rpx;
 | 
						|
  }
 | 
						|
 | 
						|
  .date-message,
 | 
						|
  .system-message {
 | 
						|
    width: fit-content;
 | 
						|
    border-radius: 12rpx;
 | 
						|
    padding: 8rpx 16rpx;
 | 
						|
    margin-bottom: 16rpx;
 | 
						|
    background-color: var(--ui-BG-3);
 | 
						|
    color: #999;
 | 
						|
    font-size: 24rpx;
 | 
						|
  }
 | 
						|
 | 
						|
  .chat-avatar {
 | 
						|
    width: 70rpx;
 | 
						|
    height: 70rpx;
 | 
						|
    border-radius: 50%;
 | 
						|
  }
 | 
						|
 | 
						|
  .send-status {
 | 
						|
    color: #333;
 | 
						|
    height: 80rpx;
 | 
						|
    margin-right: 8rpx;
 | 
						|
    display: flex;
 | 
						|
    align-items: center;
 | 
						|
 | 
						|
    .loading {
 | 
						|
      width: 32rpx;
 | 
						|
      height: 32rpx;
 | 
						|
      -webkit-animation: rotating 2s linear infinite;
 | 
						|
      animation: rotating 2s linear infinite;
 | 
						|
 | 
						|
      @-webkit-keyframes rotating {
 | 
						|
        0% {
 | 
						|
          transform: rotateZ(0);
 | 
						|
        }
 | 
						|
 | 
						|
        100% {
 | 
						|
          transform: rotateZ(360deg);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      @keyframes rotating {
 | 
						|
        0% {
 | 
						|
          transform: rotateZ(0);
 | 
						|
        }
 | 
						|
 | 
						|
        100% {
 | 
						|
          transform: rotateZ(360deg);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    .warning {
 | 
						|
      width: 32rpx;
 | 
						|
      height: 32rpx;
 | 
						|
      color: #ff3000;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  .message-box {
 | 
						|
    max-width: 50%;
 | 
						|
    font-size: 16px;
 | 
						|
    line-height: 20px;
 | 
						|
    white-space: normal;
 | 
						|
    word-break: break-all;
 | 
						|
    word-wrap: break-word;
 | 
						|
    padding: 20rpx;
 | 
						|
    border-radius: 10rpx;
 | 
						|
    color: #fff;
 | 
						|
    background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
 | 
						|
 | 
						|
    &.admin {
 | 
						|
      background: #fff;
 | 
						|
      color: #333;
 | 
						|
    }
 | 
						|
 | 
						|
    :deep() {
 | 
						|
      .imgred {
 | 
						|
        width: 100%;
 | 
						|
      }
 | 
						|
 | 
						|
      .imgred,
 | 
						|
      img {
 | 
						|
        width: 100%;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  :deep() {
 | 
						|
    .goods,
 | 
						|
    .order {
 | 
						|
      max-width: 500rpx;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  .message-img {
 | 
						|
    width: 100px;
 | 
						|
    height: 100px;
 | 
						|
    border-radius: 6rpx;
 | 
						|
  }
 | 
						|
 | 
						|
  .template-wrap {
 | 
						|
    // width: 100%;
 | 
						|
    padding: 20rpx 24rpx;
 | 
						|
    background: #fff;
 | 
						|
    border-radius: 10rpx;
 | 
						|
 | 
						|
    .title {
 | 
						|
      font-size: 26rpx;
 | 
						|
      font-weight: 500;
 | 
						|
      color: #333;
 | 
						|
      margin-bottom: 29rpx;
 | 
						|
    }
 | 
						|
 | 
						|
    .item {
 | 
						|
      font-size: 24rpx;
 | 
						|
      color: var(--ui-BG-Main);
 | 
						|
      margin-bottom: 16rpx;
 | 
						|
 | 
						|
      &:last-of-type {
 | 
						|
        margin-bottom: 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  .error-img {
 | 
						|
    width: 400rpx;
 | 
						|
    height: 400rpx;
 | 
						|
  }
 | 
						|
</style>
 |