2025-04-21 18:05:32 +08:00

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>