Files
pit-router/frontend/src/components/chat/ChatWindow.vue
feifei.xu dcf8494db7 feat: 功能3 - Markdown 渲染和代码高亮 (v0.9.8)
- 添加 MarkdownMessage.vue 组件
- 集成 markdown-it 库
- 集成 highlight.js 代码高亮
- 支持标题/列表/代码块/表格等
- ChatWindow 使用 Markdown 渲染
- 添加 .gitignore 忽略 node_modules
2026-03-15 12:13:06 +08:00

211 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { useChatStore } from '@/stores/chat'
import MarkdownMessage from '@/components/chat/MarkdownMessage.vue'
const chatStore = useChatStore()
const messagesContainer = ref<HTMLElement | null>(null)
const messages = computed(() => chatStore.messages)
watch(messages, () => {
nextTick(() => {
scrollToBottom()
})
}, { deep: true })
function scrollToBottom() {
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
}
}
function formatTime(dateStr: string): string {
return new Date(dateStr).toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
})
}
function isOwnMessage(msg: any): boolean {
return msg.sender_type === 'user'
}
</script>
<template>
<div class="chat-window">
<div class="chat-header">
<div class="chat-info">
<div class="bot-avatar">
{{ chatStore.currentSession?.bot?.avatar || '🤖' }}
</div>
<div class="chat-title">
<h3>{{ chatStore.currentSession?.title }}</h3>
<span class="status" :class="chatStore.currentSession?.bot?.status">
{{ chatStore.currentSession?.bot?.status === 'online' ? '在线' : '离线' }}
</span>
</div>
</div>
</div>
<div class="messages-container" ref="messagesContainer">
<div class="messages-list">
<div
v-for="message in messages"
:key="message.id"
class="message"
:class="{ own: isOwnMessage(message) }"
>
<div class="message-avatar">
{{ message.sender_type === 'user' ? '👤' : (chatStore.currentSession?.bot?.avatar || '🤖') }}
</div>
<div class="message-content">
<div class="message-header">
<span class="sender-name">{{ message.sender_name }}</span>
<span class="message-time">{{ formatTime(message.created_at) }}</span>
</div>
<div class="message-bubble">
<MarkdownMessage :content="message.content" />
</div>
</div>
</div>
<div class="empty-messages" v-if="messages.length === 0">
<p>暂无消息开始对话吧</p>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.chat-window {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
background: var(--bg-primary);
border-bottom: 1px solid var(--border-color);
padding: var(--spacing-md);
}
.chat-info {
display: flex;
align-items: center;
gap: var(--spacing-md);
}
.bot-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--bg-secondary);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
.chat-title h3 {
font-size: var(--font-size-md);
font-weight: 600;
margin-bottom: 2px;
}
.chat-title .status {
font-size: var(--font-size-xs);
color: var(--text-secondary);
}
.chat-title .status.online {
color: var(--success-color);
}
.messages-container {
flex: 1;
overflow-y: auto;
padding: var(--spacing-md);
}
.messages-list {
max-width: 900px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: var(--spacing-md);
}
.message {
display: flex;
gap: var(--spacing-sm);
max-width: 80%;
}
.message.own {
flex-direction: row-reverse;
margin-left: auto;
}
.message-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--bg-tertiary);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.message-content {
display: flex;
flex-direction: column;
gap: 4px;
}
.message-header {
display: flex;
gap: var(--spacing-sm);
align-items: center;
font-size: var(--font-size-xs);
}
.message.own .message-header {
flex-direction: row-reverse;
}
.sender-name {
font-weight: 500;
color: var(--text-secondary);
}
.message-time {
color: var(--text-tertiary);
}
.message-bubble {
padding: var(--spacing-sm) var(--spacing-md);
background: var(--bg-primary);
border-radius: var(--border-radius-lg);
color: var(--text-primary);
line-height: 1.5;
white-space: pre-wrap;
word-break: break-word;
}
.message.own .message-bubble {
background: var(--primary-color);
color: white;
}
.empty-messages {
text-align: center;
color: var(--text-tertiary);
padding: var(--spacing-xl);
}
</style>