Initial commit: Update project structure and add new features
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="flex flex-col w-full h-full bg-base-200 overflow-hidden">
|
||||
<!-- 消息气泡列表 -->
|
||||
<div ref="bubbleListRef" class="flex-1 overflow-y-auto p-4 ">
|
||||
<!-- 空状态 -->
|
||||
<div v-if="bubbles.length === 0" class="flex items-center justify-center h-full">
|
||||
<p class="text-base-content opacity-50">暂无消息,发送第一条消息开始对话吧~</p>
|
||||
</div>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<template v-else>
|
||||
<ChatBubble v-for="bubble in bubbles" :key="bubble.id" :content="bubble.content" :is-self="bubble.isSelf"
|
||||
:time="bubble.time" :avatar="getAvatar(bubble.isSelf)" />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 输入框区域 -->
|
||||
<ChatInput @send="handleSend" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import ChatBubble from './ChatBubble.vue'
|
||||
import ChatInput from './ChatInput.vue'
|
||||
import type { ChatBubble as ChatBubbleType } from '@/composables/useChat'
|
||||
|
||||
const props = defineProps<{
|
||||
// 消息气泡列表
|
||||
bubbles: ChatBubbleType[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
send: [content: string]
|
||||
}>()
|
||||
|
||||
const bubbleListRef = ref<HTMLDivElement | null>(null)
|
||||
|
||||
// 获取头像(根据是否为自己发送的消息)
|
||||
const getAvatar = (isSelf: boolean): string => {
|
||||
return isSelf
|
||||
? 'https://api.dicebear.com/7.x/avataaars/svg?seed=User'
|
||||
: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Assistant'
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
const scrollToBottom = () => {
|
||||
const el = bubbleListRef.value
|
||||
if (el) {
|
||||
// 使用平滑滚动
|
||||
el.scrollTo({
|
||||
top: el.scrollHeight,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 监听消息变化,自动滚动到底部
|
||||
watch(
|
||||
() => props.bubbles.length,
|
||||
() => {
|
||||
// 下一帧滚动,确保 DOM 已更新
|
||||
setTimeout(() => {
|
||||
scrollToBottom()
|
||||
}, 0)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 处理发送消息
|
||||
const handleSend = (content: string) => {
|
||||
emit('send', content)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义滚动条样式 */
|
||||
.overflow-y-auto::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user