消息
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<!-- Custom message keyword keyword search description, so here only a few custom messages that need to display highlighted description type are parsed -->
|
||||
<div
|
||||
:class="['message-abstract-custom']"
|
||||
@click.capture.stop
|
||||
>
|
||||
<template v-if="businessID === CHAT_MSG_CUSTOM_TYPE.SERVICE">
|
||||
<div :class="['service']">
|
||||
<h1 :class="['service-header']">
|
||||
<label :class="['service-header-title']">{{ extensionJSON.title }}</label>
|
||||
<a
|
||||
v-if="extensionJSON.hyperlinks_text"
|
||||
:class="['service-header-link', 'link']"
|
||||
:href="extensionJSON.hyperlinks_text.value"
|
||||
target="view_window"
|
||||
>
|
||||
{{ extensionJSON.hyperlinks_text.key }}
|
||||
</a>
|
||||
</h1>
|
||||
<ul
|
||||
v-if="extensionJSON.item && extensionJSON.item.length > 0"
|
||||
:class="['service-list']"
|
||||
>
|
||||
<li
|
||||
v-for="(item, index) in extensionJSON.item"
|
||||
:key="index"
|
||||
:class="['service-list-item']"
|
||||
>
|
||||
<a
|
||||
v-if="isUrl(item.value)"
|
||||
:class="['service-list-item-link', 'link']"
|
||||
:href="item.value"
|
||||
target="view_window"
|
||||
>{{ item.key }}</a>
|
||||
<p
|
||||
v-else
|
||||
:class="['service-list-item-key']"
|
||||
>
|
||||
{{ item.key }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div :class="['service-description', 'description']">
|
||||
<span
|
||||
v-for="(contentItem, index) in descriptionForShow"
|
||||
:key="index"
|
||||
:class="[(contentItem && contentItem.isHighlight) ? 'highlight' : 'normal']"
|
||||
>
|
||||
{{ contentItem.text }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="businessID === CHAT_MSG_CUSTOM_TYPE.EVALUATE">
|
||||
<div class="evaluate">
|
||||
<div :class="['evaluate-description', 'description']">
|
||||
<span
|
||||
v-for="(contentItem, index) in descriptionForShow"
|
||||
:key="index"
|
||||
:class="[(contentItem && contentItem.isHighlight) ? 'highlight' : 'normal']"
|
||||
>
|
||||
{{ contentItem.text }}
|
||||
</span>
|
||||
</div>
|
||||
<ul
|
||||
v-if="extensionJSON.score"
|
||||
class="evaluate-list"
|
||||
>
|
||||
<li
|
||||
v-for="(item, index) in Math.max(extensionJSON.score, 0)"
|
||||
:key="index"
|
||||
class="evaluate-list-item"
|
||||
>
|
||||
<Icon
|
||||
:file="star"
|
||||
class="file-icon"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<article>{{ extensionJSON.comment }}</article>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="businessID === CHAT_MSG_CUSTOM_TYPE.ORDER">
|
||||
<div class="order">
|
||||
<img
|
||||
class="order-image"
|
||||
:src="extensionJSON.imageUrl"
|
||||
alt=""
|
||||
>
|
||||
<main class="order-main">
|
||||
<h1 class="order-main-title">
|
||||
{{ extensionJSON.title }}
|
||||
</h1>
|
||||
<div :class="['order-main-description', 'description']">
|
||||
<span
|
||||
v-for="(contentItem, index) in descriptionForShow"
|
||||
:key="index"
|
||||
:class="[(contentItem && contentItem.isHighlight) ? 'highlight' : 'normal']"
|
||||
>
|
||||
{{ contentItem.text }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="order-main-price">{{ extensionJSON.price }}</span>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="businessID === CHAT_MSG_CUSTOM_TYPE.LINK">
|
||||
<div class="text-link">
|
||||
<div :class="['text-link-description', 'description']">
|
||||
<p>{{ extensionJSON.text }}</p>
|
||||
</div>
|
||||
<a
|
||||
:class="['link']"
|
||||
:href="extensionJSON.link"
|
||||
target="view_window"
|
||||
>{{
|
||||
TUITranslateService.t("message.custom.查看详情>>")
|
||||
}}</a>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>{{ defaultMessageContent }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { TUITranslateService, IMessageModel } from '@tencentcloud/chat-uikit-engine';
|
||||
import { ref, computed, withDefaults } from '../../../../../adapter-vue';
|
||||
import { CHAT_MSG_CUSTOM_TYPE } from '../../../../../constant';
|
||||
import { JSONToObject, isUrl } from '../../../../../utils/index';
|
||||
import Icon from '../../../../common/Icon.vue';
|
||||
import star from '../../../../../assets/icon/star-light.png';
|
||||
import { IHighlightContent } from '../../../type';
|
||||
import { ISearchResultListItem } from '../../../../../interface';
|
||||
interface IProps {
|
||||
contentText: IHighlightContent[];
|
||||
message: IMessageModel | ISearchResultListItem;
|
||||
messageContent: Record<string, unknown> | undefined;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
contentText: () => ([]) as IHighlightContent[],
|
||||
message: () => ({}) as IMessageModel,
|
||||
messageContent: () => ({}) as Record<string, unknown>,
|
||||
});
|
||||
|
||||
const custom = ref<{ data?: string; description?: string; extension?: string }>(
|
||||
(props?.message as IMessageModel)?.payload,
|
||||
);
|
||||
const extensionJSON = computed(() => custom?.value?.data ? JSONToObject(custom.value.data) : custom?.value?.data);
|
||||
const businessID = computed(() => extensionJSON?.value?.businessID);
|
||||
const descriptionForShow = ref<Array<{ text: string; isHighlight: boolean }>>(props?.contentText);
|
||||
const defaultMessageContent = ref<string>(props?.messageContent?.custom as string || '[自定义消息]');
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../../../../assets/styles/common";
|
||||
|
||||
.message-abstract-custom {
|
||||
.service {
|
||||
.service-header {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.service-list {
|
||||
.service-list-item {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.evaluate {
|
||||
.evaluate-list {
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.evaluate-item {
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order {
|
||||
display: flex;
|
||||
|
||||
.order-main {
|
||||
padding-left: 5px;
|
||||
|
||||
.order-main-title {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.order-main-description {
|
||||
font-family: PingFangSC-Regular, sans-serif;
|
||||
width: 145px;
|
||||
line-height: 17px;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
letter-spacing: 0;
|
||||
margin-bottom: 6px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.order-main-price {
|
||||
font-family: PingFangSC-Regular, sans-serif;
|
||||
line-height: 25px;
|
||||
color: #ff7201;
|
||||
}
|
||||
}
|
||||
|
||||
.order-img {
|
||||
width: 67px;
|
||||
height: 67px;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
font-size: 14px;
|
||||
color: #679ce1;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
|
||||
.highlight {
|
||||
background-color: #007aff33;
|
||||
}
|
||||
|
||||
.normal {
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div :class="['message-abstract-file', `message-abstract-file-${displayType}`]">
|
||||
<div :class="['message-abstract-file-left']">
|
||||
<img
|
||||
:class="['message-abstract-file-left-icon']"
|
||||
:src="typeIcon.iconSrc"
|
||||
>
|
||||
</div>
|
||||
<div :class="['message-abstract-file-main']">
|
||||
<div :class="['message-abstract-file-main-name']">
|
||||
<span
|
||||
v-for="(contentItem, index) in contentText"
|
||||
:key="index"
|
||||
:class="[(contentItem && contentItem.isHighlight) ? 'highlight' : 'normal']"
|
||||
>
|
||||
{{ contentItem.text }}
|
||||
</span>
|
||||
</div>
|
||||
<div :class="['message-abstract-file-main-size']">
|
||||
{{ fileSize }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, withDefaults } from '../../../../../adapter-vue';
|
||||
import { IHighlightContent } from '../../../type';
|
||||
interface IProps {
|
||||
contentText: Array<IHighlightContent>;
|
||||
messageContent: Record<string, unknown> | undefined;
|
||||
displayType: 'bubble' | 'info';
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
contentText: () => ([]) as Array<IHighlightContent>,
|
||||
messageContent: () => ({}) as Record<string, unknown>,
|
||||
displayType: 'bubble',
|
||||
});
|
||||
|
||||
const contentText = ref<Array<{ text: string; isHighlight: boolean }>>(props.contentText);
|
||||
const typeIcon = computed(() => {
|
||||
const fileUrl = props?.messageContent?.url as string;
|
||||
const index = fileUrl?.lastIndexOf('.');
|
||||
const type = fileUrl?.substring(index + 1);
|
||||
return handleFileIconForShow(type);
|
||||
});
|
||||
const fileSize = computed(() => props?.messageContent?.size);
|
||||
const handleFileIconForShow = (type: string) => {
|
||||
const urlBase = 'https://web.sdk.qcloud.com/component/TUIKit/assets/file-';
|
||||
const fileTypes = [
|
||||
'image',
|
||||
'pdf',
|
||||
'text',
|
||||
'ppt',
|
||||
'presentation',
|
||||
'sheet',
|
||||
'zip',
|
||||
'word',
|
||||
'video',
|
||||
'unknown',
|
||||
];
|
||||
let url = '';
|
||||
let iconType = '';
|
||||
fileTypes?.forEach((typeName: string) => {
|
||||
if (type?.includes(typeName)) {
|
||||
url = urlBase + typeName + '.svg';
|
||||
iconType = typeName;
|
||||
}
|
||||
});
|
||||
return {
|
||||
iconSrc: url ? url : urlBase + 'unknown.svg',
|
||||
iconType: iconType ? iconType : 'unknown',
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../../../../assets/styles/common";
|
||||
|
||||
.message-abstract-file {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-left {
|
||||
width: 42px;
|
||||
height: 32px;
|
||||
|
||||
&-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&-main {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
&-name {
|
||||
width: 100%;
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
.highlight {
|
||||
background-color: #007aff33;
|
||||
}
|
||||
|
||||
.normal {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&-size {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&-bubble {
|
||||
background-color: #f1f1f1;
|
||||
|
||||
.message-abstract-file-main {
|
||||
.message-abstract-file-main-name {
|
||||
color: #1f2329;
|
||||
|
||||
.normal {
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-file {
|
||||
margin: 8px 10px 5px;
|
||||
padding: 10px;
|
||||
background-color: #f1f1f1;
|
||||
height: 51px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div :class="['message-abstract-image-container']">
|
||||
<img
|
||||
:class="['message-abstract-image']"
|
||||
:src="imageUrl"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { withDefaults, computed } from '../../../../../adapter-vue';
|
||||
import { IImageMessageContent } from '../../../../../interface';
|
||||
interface IProps {
|
||||
messageContent: Record<string, unknown> | IImageMessageContent | undefined;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
messageContent: () => ({}) as IImageMessageContent,
|
||||
});
|
||||
|
||||
const imageUrl = computed<string>(() => (props.messageContent as IImageMessageContent).url || '');
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../../../../assets/styles/common";
|
||||
|
||||
.message-abstract-image-container {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
|
||||
.message-abstract-image {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'message-abstract-text',
|
||||
`message-abstract-text-${highlightType}`,
|
||||
`message-abstract-text-${displayType}`,
|
||||
]"
|
||||
>
|
||||
<span
|
||||
v-for="(contentItem, index) in contentText"
|
||||
:key="index"
|
||||
:class="[(contentItem && contentItem.isHighlight) ? 'highlight' : 'normal']"
|
||||
>
|
||||
{{ transformTextWithKeysToEmojiNames(contentItem.text) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, withDefaults } from '../../../../../adapter-vue';
|
||||
import { transformTextWithKeysToEmojiNames } from '../../../../TUIChat/emoji-config';
|
||||
import { IHighlightContent } from '../../../type';
|
||||
|
||||
interface IProps {
|
||||
content: IHighlightContent[];
|
||||
highlightType: 'font' | 'background';
|
||||
displayType: 'info' | 'bubble';
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
content: () => ([]) as IHighlightContent[],
|
||||
highlightType: 'font',
|
||||
displayType: 'info',
|
||||
});
|
||||
|
||||
const contentText = ref<Array<{ text: string; isHighlight: boolean }>>(props.content);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../../../../assets/styles/common";
|
||||
|
||||
.message-abstract-text {
|
||||
justify-content: flex-start;
|
||||
|
||||
&-font {
|
||||
color: #999;
|
||||
|
||||
.highlight {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.normal {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&-background {
|
||||
color: #1f2329;
|
||||
|
||||
.highlight {
|
||||
background-color: #007aff33;
|
||||
}
|
||||
|
||||
.normal {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
|
||||
.highlight {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.normal {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&-bubble {
|
||||
font-size: 14px;
|
||||
|
||||
.highlight {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.normal {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div :class="['message-abstract-video']">
|
||||
<div class="message-abstract-video-box">
|
||||
<img
|
||||
:src="videoUrl"
|
||||
:class="['video-snapshot']"
|
||||
>
|
||||
<Icon
|
||||
:file="playIcon"
|
||||
class="video-play"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from '../../../../../adapter-vue';
|
||||
import Icon from '../../../../common/Icon.vue';
|
||||
import playIcon from '../../../../../assets/icon/video-play.png';
|
||||
import { IVideoMessageContent } from '../../../../../interface';
|
||||
interface IProps {
|
||||
messageContent: Record<string, unknown> | IVideoMessageContent | undefined;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
messageContent: () => ({}) as IVideoMessageContent,
|
||||
});
|
||||
const videoUrl = computed<string>(() => {
|
||||
return (props.messageContent as IVideoMessageContent).snapshotUrl || (props.messageContent as IVideoMessageContent).url;
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../../../../../assets/styles/common";
|
||||
|
||||
.message-abstract-video {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
|
||||
&-box {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
|
||||
.video-snapshot {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.video-play {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}</style>
|
||||
Reference in New Issue
Block a user