274 lines
6.2 KiB
Vue
274 lines
6.2 KiB
Vue
<template>
|
|
<div :class="['message-text-container', isPC && 'text-select']">
|
|
<span v-for="(item, index) in processedContent" :key="index">
|
|
<!-- -->
|
|
<span v-if="item.name === 'text'" class="text">
|
|
<span
|
|
v-if="textpl(item.text)"
|
|
class="text_span"
|
|
@click="toPage(item.text)"
|
|
>
|
|
<img
|
|
class="imgemo"
|
|
:src="
|
|
config.img+
|
|
imgsplit(item.text)
|
|
"
|
|
:alt="item.emojiKey"
|
|
/>
|
|
<br />
|
|
|
|
<div class="link">
|
|
<div>{{ item.text.split(",")[0] }}</div>
|
|
<div>{{ item.text.split(",")[1] }}¥</div>
|
|
</div>
|
|
</span>
|
|
<span v-else> {{ item.text }}</span>
|
|
</span>
|
|
<span
|
|
v-else-if="item.name === 'url'"
|
|
class="url-link"
|
|
@click="navigateToUrl(item.url)"
|
|
>
|
|
{{ item.text }}
|
|
</span>
|
|
<img v-else class="emoji" :src="item.src" :alt="item.emojiKey" />
|
|
</span>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import config from "../../../../../config/config";
|
|
import { watch, ref } from "../../../../adapter-vue";
|
|
import {
|
|
TUIStore,
|
|
IMessageModel,
|
|
TUIReportService,
|
|
} from "@tencentcloud/chat-uikit-engine";
|
|
import {
|
|
TUIGlobal,
|
|
parseTextAndValidateUrls,
|
|
} from "@tencentcloud/universal-api";
|
|
import {
|
|
CUSTOM_BASIC_EMOJI_URL,
|
|
CUSTOM_BASIC_EMOJI_URL_MAPPING,
|
|
} from "../../emoji-config";
|
|
import { isPC, isUniFrameWork } from "../../../../utils/env";
|
|
|
|
interface IProps {
|
|
content: Record<string, any>;
|
|
messageItem: IMessageModel;
|
|
enableURLHighlight?: boolean;
|
|
}
|
|
|
|
interface TextItem {
|
|
name: string;
|
|
text: string;
|
|
src?: string;
|
|
type?: string;
|
|
emojiKey?: string;
|
|
url?: string;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<IProps>(), {
|
|
content: () => ({}),
|
|
messageItem: () => ({} as IMessageModel),
|
|
enableURLHighlight: false,
|
|
});
|
|
|
|
const processedContent = ref<TextItem>([]);
|
|
const textpl = (text: string) => {
|
|
const fn = text.includes("&goodsId=");
|
|
return fn;
|
|
};
|
|
|
|
const toPage = (text: string) => {
|
|
// "测试31 11, 1, /3e12e653ecc143879ce782d8f2ef1d0e.png, /pages/product/goods?id=1912784394254852100&goodsId=1912784393931890690"
|
|
const url = "/pages/product/goods?" + text.split(",")[3]; // 替换为你的目标 URL
|
|
TUIGlobal.navigateTo({
|
|
url, // Assuming you have a webview page to handle external URLs
|
|
});
|
|
};
|
|
const imgsplit = (text: string) => {
|
|
// const
|
|
const url = text.split(",")[2]; // 替换为你的目标 URL
|
|
console.log(url);
|
|
return url;
|
|
};
|
|
|
|
watch(
|
|
() => props.messageItem,
|
|
(newValue: IMessageModel, oldValue: IMessageModel) => {
|
|
if (newValue?.ID === oldValue?.ID) {
|
|
return;
|
|
}
|
|
|
|
if (props.enableURLHighlight) {
|
|
TUIReportService.reportFeature(208);
|
|
}
|
|
|
|
if (props.messageItem.getMessageContent) {
|
|
processedContent.value = props.messageItem.getMessageContent()?.text;
|
|
} else {
|
|
processedContent.value = TUIStore.getMessageModel(
|
|
props.messageItem.ID
|
|
)?.getMessageContent()?.text;
|
|
}
|
|
processedContent.value = processedContent.value || props.content?.text;
|
|
|
|
if (!processedContent.value?.length) {
|
|
processedContent.value = [];
|
|
return;
|
|
}
|
|
|
|
processedContent.value = processedContent.value
|
|
.map((item: TextItem) => {
|
|
// handle custom emoji
|
|
if (item.name === "img" && item?.type === "custom") {
|
|
if (!CUSTOM_BASIC_EMOJI_URL) {
|
|
console.warn(
|
|
"CUSTOM_BASIC_EMOJI_URL is required for custom emoji."
|
|
);
|
|
return item;
|
|
}
|
|
if (
|
|
!item.emojiKey ||
|
|
!CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey]
|
|
) {
|
|
console.warn("emojiKey is required for custom emoji.");
|
|
return item;
|
|
}
|
|
return {
|
|
...item,
|
|
src:
|
|
CUSTOM_BASIC_EMOJI_URL +
|
|
CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey],
|
|
};
|
|
}
|
|
|
|
// handle url
|
|
if (props.enableURLHighlight && item.name === "text" && item.text) {
|
|
if (!parseTextAndValidateUrls) {
|
|
console.warn(
|
|
"parseTextAndValidateUrls not found. Please update @tencentcloud/universal-api to 2.3.7 or higher."
|
|
);
|
|
return item;
|
|
}
|
|
const segments = parseTextAndValidateUrls(item.text);
|
|
if (segments.length) {
|
|
return segments.map((segment) => ({
|
|
name: segment.type,
|
|
text: segment.text,
|
|
url: segment.url,
|
|
}));
|
|
}
|
|
}
|
|
|
|
return item;
|
|
})
|
|
?.flat();
|
|
},
|
|
{
|
|
deep: true,
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
// Function to handle navigation
|
|
function navigateToUrl(url: string) {
|
|
if (url) {
|
|
if (isUniFrameWork) {
|
|
// Use UniApp navigation
|
|
TUIGlobal.navigateTo({
|
|
url: `/pages/views/webview?url=${url}`, // Assuming you have a webview page to handle external URLs
|
|
});
|
|
} else {
|
|
// Use standard browser navigation
|
|
TUIGlobal.open(url, "_blank");
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.text_span {
|
|
display: flex;
|
|
padding: 5px 5px;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
color: #999;
|
|
|
|
.imgemo {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 8px;
|
|
}
|
|
.link {
|
|
margin-left: 8px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
.hide_txt {
|
|
width: 100%;
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
.message-text-container {
|
|
display: inline;
|
|
font-size: 0;
|
|
letter-spacing: -1px;
|
|
}
|
|
|
|
.text-select {
|
|
-webkit-user-select: text;
|
|
-moz-user-select: text;
|
|
-ms-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.text,
|
|
.emoji,
|
|
.url-link {
|
|
&::selection {
|
|
background-color: #b4d5fe;
|
|
color: inherit;
|
|
cursor: text;
|
|
}
|
|
}
|
|
|
|
.emoji {
|
|
font-size: 0;
|
|
vertical-align: bottom;
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.text,
|
|
.url-link {
|
|
font-size: 14px;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
letter-spacing: normal;
|
|
}
|
|
|
|
.url-link {
|
|
color: #0366d6;
|
|
text-decoration: none;
|
|
word-break: break-all;
|
|
cursor: text;
|
|
|
|
&:hover:not(:active) {
|
|
cursor: pointer;
|
|
}
|
|
|
|
&:visited {
|
|
color: #0366d6;
|
|
}
|
|
}
|
|
</style>
|