60 lines
1.7 KiB
Vue
60 lines
1.7 KiB
Vue
<template>
|
|
<div class="max-w-[75%] flex flex-col">
|
|
<slot name="header"></slot>
|
|
<div v-if="!msg.messageContentList || msg.messageContentList.length === 0"
|
|
class="flex flex-row text-sm text-gray-700">
|
|
<div v-html="compiledMarkdown"></div>
|
|
<ChatLoading v-if="msg.isLoading" />
|
|
</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>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ChatMessage } from '../model/ChatModel';
|
|
import { computed } from 'vue'
|
|
import MarkdownIt from 'markdown-it'
|
|
import hljs from 'highlight.js'
|
|
import 'highlight.js/styles/github.css'
|
|
import ChatLoading from './ChatLoading.vue';
|
|
|
|
interface Props {
|
|
msg: ChatMessage
|
|
}
|
|
|
|
const { msg } = defineProps<Props>()
|
|
const md = new MarkdownIt({
|
|
html: true,
|
|
linkify: true,
|
|
typographer: true,
|
|
highlight: function (str: string, lang: string) {
|
|
if (lang && hljs.getLanguage(lang)) {
|
|
try {
|
|
return hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
|
|
} catch (__) { }
|
|
}
|
|
// 自动检测
|
|
return hljs.highlightAuto(str).value;
|
|
}
|
|
});
|
|
|
|
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> |