Files
lanecarford_front/src/views/asistant/components/NoticeItem.vue
2025-10-28 11:33:20 +08:00

182 lines
3.2 KiB
Vue

<template>
<div class="chat-message" :class="{ 'user-message': isMyself, 'ai-message': !isMyself }">
<!-- AI消息显示头像 -->
<div v-if="!isMyself" class="chat-avatar">
<img src="@/assets/images/asistant.png" alt="AI Avatar" />
</div>
<!-- 消息内容 -->
<div class="message-content">
<div class="message-text" :class="{ streaming: isStreaming }">
<div v-html="content"></div>
<span v-if="isStreaming" class="streaming-cursor">|</span>
</div>
<!-- <div v-if="!isMyself" class="message-actions flex">
<SvgIcon
v-for="item in actionList"
:key="item.value"
:name="item.icon"
size="39"
@click.stop="handleClickAction(item.value)"
/>
</div> -->
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import MarkdownIt from 'markdown-it'
const md = new MarkdownIt()
// 定义消息类型
interface ChatMessage {
sessionId: string | number
type: string
content: string
timestamp: string
id?: string
self?: boolean
}
// 定义操作项类型
interface ActionItem {
value: string
icon: string
}
// 定义组件props类型
interface NoticeItemProps {
value: ChatMessage
isStreaming?: boolean
}
const props = defineProps<NoticeItemProps>()
const isMyself = computed(() => {
return props.value.self || false
})
const content = computed(() => {
return md.render(props.value.content)
})
const handleClickAction = (value: string): void => {
console.log('click Action', value)
}
const actionList: ActionItem[] = [
{
value: 'thumbup',
icon: 'thumbup'
},
{
value: 'thumbdown',
icon: 'thumbdown'
},
{
value: 'refresh',
icon: 'refresh'
},
{
value: 'upload',
icon: 'upload'
},
{
value: 'more',
icon: 'more'
}
]
</script>
<style lang="less" scoped>
.chat-message {
display: flex;
margin-bottom: 16px;
align-items: flex-start;
.message-text {
font-size: 4.2rem;
font-family: 'robotoBold';
line-height: 121%;
font-weight: 400;
background-color: #efefef;
padding: 4.95rem 3.95rem;
}
&.user-message {
justify-content: flex-end;
.message-content {
align-items: flex-end;
.message-text {
border-radius: 2rem 2rem 0 2rem;
}
}
}
&.ai-message {
justify-content: flex-start;
.message-content {
align-items: flex-start;
.message-text {
color: #000;
border-radius: 0 2rem 2rem 2rem;
word-break: break-word;
}
}
}
}
.chat-avatar {
width: 7.8rem;
height: 7.4rem;
border-radius: 50%;
margin-right: 1.88rem;
border: 2px solid #000;
padding: 1.4rem;
img {
width: 4.9rem;
height: 4.9rem;
border-radius: 50%;
// object-fit: cover;
}
}
.message-content {
display: flex;
flex-direction: column;
max-width: 70%;
}
.message-actions {
margin-top: 2.6rem;
color: #6b6b6b;
column-gap: 1.61rem;
.svg-icon {
cursor: pointer;
}
}
.streaming-cursor {
animation: blink 1s infinite;
font-weight: bold;
color: #000;
}
@keyframes blink {
0%,
50% {
opacity: 1;
}
51%,
100% {
opacity: 0;
}
}
</style>