feat: 消息展示的调整
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' http://8.138.234.141; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -417,7 +417,6 @@ const handleWebSocketMessage = (data: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'heartbeat') {
|
if (data.type === 'heartbeat') {
|
||||||
console.log("收到心跳消息:", data);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,10 +466,12 @@ const handleWebSocketMessage = (data: any) => {
|
|||||||
if (chatMsgList.value[aiMsgIndex].isLoading) {
|
if (chatMsgList.value[aiMsgIndex].isLoading) {
|
||||||
// 首次收到内容:替换“加载中”文案并取消 loading 状态(恢复原始渲染逻辑)
|
// 首次收到内容:替换“加载中”文案并取消 loading 状态(恢复原始渲染逻辑)
|
||||||
chatMsgList.value[aiMsgIndex].messageContent = data.content;
|
chatMsgList.value[aiMsgIndex].messageContent = data.content;
|
||||||
|
chatMsgList.value[aiMsgIndex].messageContentList = [data.content];
|
||||||
chatMsgList.value[aiMsgIndex].isLoading = false;
|
chatMsgList.value[aiMsgIndex].isLoading = false;
|
||||||
} else {
|
} else {
|
||||||
// 后续流式内容追加
|
// 后续流式内容追加
|
||||||
chatMsgList.value[aiMsgIndex].messageContent += data.content;
|
chatMsgList.value[aiMsgIndex].messageContent += data.content;
|
||||||
|
chatMsgList.value[aiMsgIndex].messageContentList.push(data.content);
|
||||||
}
|
}
|
||||||
nextTick(() => scrollToBottom());
|
nextTick(() => scrollToBottom());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="max-w-[75%] flex flex-col">
|
<div class="max-w-[75%] flex flex-col">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
<div class="text-sm text-gray-700 flex flex-row">
|
<div v-if="!msg.messageContentList" class="flex flex-row text-sm text-gray-700">
|
||||||
<div v-html="compiledMarkdown"></div>
|
<div v-html="compiledMarkdown"></div>
|
||||||
<ChatLoading v-if="msg.isLoading" />
|
<ChatLoading v-if="msg.isLoading" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="flex flex-col p-2 mb-2 text-sm text-gray-700 bg-[#f7f9fc] rounded-md"
|
||||||
|
v-for="(_, index) in msg.messageContentList" :key="index">
|
||||||
|
<div v-html="compiledAt(index)"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -23,6 +29,9 @@ interface Props {
|
|||||||
|
|
||||||
const { msg } = defineProps<Props>()
|
const { msg } = defineProps<Props>()
|
||||||
const md = new MarkdownIt({
|
const md = new MarkdownIt({
|
||||||
|
html: true,
|
||||||
|
linkify: true,
|
||||||
|
typographer: true,
|
||||||
highlight: function (str: string, lang: string) {
|
highlight: function (str: string, lang: string) {
|
||||||
if (lang && hljs.getLanguage(lang)) {
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
try {
|
try {
|
||||||
@@ -33,6 +42,18 @@ const md = new MarkdownIt({
|
|||||||
return hljs.highlightAuto(str).value;
|
return hljs.highlightAuto(str).value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const compiledMarkdown = computed(() => md.render(msg.messageContent))
|
const compiledMarkdown = computed(() => md.render(msg.messageContent))
|
||||||
|
|
||||||
|
const compiledList = computed(() => {
|
||||||
|
return (msg.messageContentList || []).map((m: string) => md.render(m || ''))
|
||||||
|
})
|
||||||
|
|
||||||
|
const compiledAt = (index: number): string => {
|
||||||
|
const list: string[] = (compiledList as any).value || []
|
||||||
|
if (list[index]) return list[index]
|
||||||
|
const raw = msg?.messageContentList?.[index] || ''
|
||||||
|
return md.render(raw || '')
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -16,6 +16,8 @@ export class ChatMessage {
|
|||||||
messageRole: MessageRole;
|
messageRole: MessageRole;
|
||||||
// 消息内容
|
// 消息内容
|
||||||
messageContent: string;
|
messageContent: string;
|
||||||
|
// 消息内容列表(用于流式更新)
|
||||||
|
messageContentList: string[];
|
||||||
// 是否加载中
|
// 是否加载中
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
// 是否完成
|
// 是否完成
|
||||||
@@ -31,6 +33,7 @@ export class ChatMessage {
|
|||||||
messageId: string,
|
messageId: string,
|
||||||
messageRole: MessageRole,
|
messageRole: MessageRole,
|
||||||
messageContent: string,
|
messageContent: string,
|
||||||
|
messageContentList: string[] = [],
|
||||||
isLoading: boolean = false,
|
isLoading: boolean = false,
|
||||||
finished: boolean = false,
|
finished: boolean = false,
|
||||||
toolCall?: any,
|
toolCall?: any,
|
||||||
@@ -40,6 +43,7 @@ export class ChatMessage {
|
|||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.messageRole = messageRole;
|
this.messageRole = messageRole;
|
||||||
this.messageContent = messageContent;
|
this.messageContent = messageContent;
|
||||||
|
this.messageContentList = messageContentList;
|
||||||
this.isLoading = isLoading;
|
this.isLoading = isLoading;
|
||||||
this.finished = finished;
|
this.finished = finished;
|
||||||
this.toolCall = toolCall;
|
this.toolCall = toolCall;
|
||||||
|
|||||||
Reference in New Issue
Block a user