|
|
<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(getMessageContent(message).text || 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(getMessageContent(message).picUrl || message.content)]" :current="0" :src="sheep.$url.cdn(getMessageContent(message).picUrl || message.content)" :height="200" :width="200" mode="aspectFill" ></su-image> </view> </template> <template v-if="message.contentType === KeFuMessageContentTypeEnum.PRODUCT"> <div class="ss-m-b-10"> <GoodsItem :goodsData="getMessageContent(message)" @tap="sheep.$router.go('/pages/goods/index', { id: getMessageContent(message).spuId })" /> </div> </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(userInfo.avatar) || 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, jsonParse } 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) => jsonParse(item.content)); // 解析消息内容
const userInfo = computed(() => sheep.$store('user').userInfo);
//======================= 工具 =======================
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;vertical-align: middle;" 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: 10rpx; }
.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; white-space: normal; word-break: break-all; word-wrap: break-word; padding: 20rpx; color: #fff; background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); margin-top: 3px; margin-bottom: 9px; border-top-left-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; &.admin { background: #fff; color: #333; margin-top: 3px; margin-bottom: 9px; border-radius: 0 10px 10px 10px; }
:deep() { .imgred { width: 100%; }
.imgred, img { width: 100%; } } }
:deep() { .goods, .order { max-width: 500rpx; } }
.message-img { width: 100px; height: 100px; border-radius: 6rpx; }
.error-img { width: 400rpx; height: 400rpx; }</style>
|