<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('https://zysc.fjptzykj.com:3000/shangcheng/d1e722fb4a257a9ab28c7aca2df004d0159a8ee9cc1d02bccf7ef27b55fcc526.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>