Files
zyt/admin/src/components/chat-dialog/ChatMessageItem.vue
T
2026-04-01 09:46:25 +08:00

110 lines
3.4 KiB
Vue

<template>
<div v-if="showFriendlyCustom" class="chat-uikit-custom-msg">
<span v-if="friendlyCustom!.tag" class="chat-uikit-custom-msg__tag">{{ friendlyCustom!.tag }}</span>
<div class="chat-uikit-custom-msg__main">{{ friendlyCustom!.main }}</div>
<div v-if="friendlyCustom!.sub" class="chat-uikit-custom-msg__sub">{{ friendlyCustom!.sub }}</div>
</div>
<div v-else-if="isCustomType && customDescription" class="chat-uikit-custom-msg chat-uikit-custom-msg--plain">
<div class="chat-uikit-custom-msg__main">{{ customDescription }}</div>
</div>
<div v-else-if="isCustomType" class="chat-uikit-custom-msg chat-uikit-custom-msg--plain">
<div class="chat-uikit-custom-msg__main">系统消息</div>
<div v-if="customDataPreview" class="chat-uikit-custom-msg__sub">{{ customDataPreview }}</div>
</div>
<Message v-else v-bind="attrs" :message="message" />
</template>
<script setup lang="ts">
import { computed, useAttrs } from 'vue'
import { Message, MessageType } from '@tencentcloud/chat-uikit-vue3'
import type { MessageModel } from '@tencentcloud/chat-uikit-vue3'
import { parseImBusinessPayload } from '@/utils/im-business-message-parse'
defineOptions({ inheritAttrs: false })
const props = defineProps<{
message: MessageModel
}>()
const attrs = useAttrs()
function payloadDataString(payload: unknown): string | null {
if (!payload || typeof payload !== 'object') return null
const p = payload as Record<string, unknown>
const d = p.data
if (typeof d === 'string') return d
if (d && typeof d === 'object') return JSON.stringify(d)
const ext = p.extension
if (typeof ext === 'string' && ext.trim().startsWith('{')) return ext
return null
}
const isCustomType = computed(() => {
const t = props.message?.type as unknown
if (t === MessageType.CUSTOM) return true
if (typeof t === 'string' && /custom/i.test(t)) return true
return false
})
const friendlyCustom = computed(() => {
if (!isCustomType.value) return null
const raw = payloadDataString(props.message.payload)?.trim()
if (!raw) return null
return parseImBusinessPayload(raw)
})
const showFriendlyCustom = computed(() => isCustomType.value && !!friendlyCustom.value)
const customDescription = computed(() => {
const p = props.message.payload as Record<string, unknown> | undefined
const d = p?.description
return typeof d === 'string' && d.trim() ? d.trim() : ''
})
/** 无法识别结构时短预览,避免空白 */
const customDataPreview = computed(() => {
const raw = payloadDataString(props.message.payload)?.trim()
if (!raw || raw.length < 2) return ''
if (raw.length <= 120) return raw
return `${raw.slice(0, 117)}…`
})
</script>
<style scoped lang="scss">
.chat-uikit-custom-msg {
max-width: 85%;
padding: 8px 12px;
border-radius: 8px;
background: var(--el-fill-color-light, #f4f4f5);
color: var(--el-text-color-primary, #303133);
font-size: 13px;
line-height: 1.45;
border: 1px solid var(--el-border-color-lighter, #ebeef5);
}
.chat-uikit-custom-msg--plain {
opacity: 0.95;
}
.chat-uikit-custom-msg__tag {
display: inline-block;
font-size: 11px;
padding: 0 6px;
border-radius: 4px;
background: var(--el-color-info-light-9, #f4f4f5);
color: var(--el-color-info, #909399);
margin-bottom: 4px;
}
.chat-uikit-custom-msg__main {
font-weight: 500;
}
.chat-uikit-custom-msg__sub {
margin-top: 4px;
font-size: 12px;
color: var(--el-text-color-secondary, #909399);
word-break: break-all;
}
</style>