Files
vue-task01/app.vue
2026-01-22 12:15:38 +08:00

211 lines
4.1 KiB
Vue
Raw Permalink 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 } from 'vue'
// --- 类型定义 ---
interface Message {
id: number
role: 'user' | 'ai'
content: string
timestamp: string
}
// --- 状态管理 ---
const messages = ref<Message[]>([
{
id: 1,
role: 'ai',
content: '你好!我是你的 AI 助手,有什么可以帮你的吗?',
timestamp: new Date().toLocaleTimeString()
}
])
const inputVal = ref('')
const chatContainerRef = ref<HTMLElement | null>(null)
// --- 模拟 API 调用 ---
const mockAiResponse = async () => {
// 模拟网络延迟
setTimeout(() => {
messages.value.push({
id: Date.now(),
role: 'ai',
content: '这是一个模拟的 AI 回复。它可以是很长很长很长很长很长很长很长很长很长很长很长很长的一段话,用来测试滚动条是否能正常工作。Vue 3 的性能非常棒!',
timestamp: new Date().toLocaleTimeString()
})
// 尝试滚动 task2
scrollToBottom()
}, 1500)
}
// --- 事件处理 ---
const sendMessage = () => {
if (!inputVal.value.trim()) return
// 添加用户消息
messages.value.push({
id: Date.now(),
role: 'user',
content: inputVal.value,
timestamp: new Date().toLocaleTimeString()
})
// 3. 清空输入
inputVal.value = ''
// task2
//
scrollToBottom()
// 4. 请求 AI
mockAiResponse()
}
// 滚动到底部
const scrollToBottom = () => {
if (chatContainerRef.value) {
// 滚动
chatContainerRef.value.scrollTop = chatContainerRef.value.scrollHeight
}
}
</script>
<template>
<div class="chat-wrapper">
<header class="header">
<h1>🤖 AI Chat Lite</h1>
</header>
<div class="chat-container" ref="chatContainerRef">
<div
v-for="msg in messages"
:key="msg.id"
class="message-row"
:class="msg.role === 'user' ? 'row-user' : 'row-ai'"
>
<div class="avatar">
{{ msg.role === 'ai' ? '🤖' : '👤' }}
</div>
<div class="bubble">
<div class="text">{{ msg.content }}</div>
<div class="time">{{ msg.timestamp }}</div>
</div>
</div>
</div>
<div class="input-area">
<input
v-model="inputVal"
@keyup.enter="sendMessage"
type="text"
placeholder="输入你的问题..."
/>
<button @click="sendMessage" >
发送
</button>
</div>
</div>
</template>
<style scoped>
/* 基础样式,无需修改 */
.chat-wrapper {
max-width: 600px;
margin: 40px auto;
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
font-family: sans-serif;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.header {
background: #f3f4f6;
padding: 16px;
border-bottom: 1px solid #e5e7eb;
}
.header h1 { margin: 0; font-size: 1.25rem; color: #1f2937; }
.chat-container {
height: 400px;
overflow-y: auto;
padding: 20px;
background: #fff;
/* scroll-behavior: smooth; */
/* 平滑滚动 */
}
/* 消息行样式 */
.message-row {
display: flex;
align-items: flex-start;
margin-bottom: 16px;
gap: 10px;
}
.row-user { flex-direction: row-reverse; }
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #eee;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.bubble {
max-width: 70%;
padding: 10px 14px;
border-radius: 10px;
position: relative;
}
.row-ai .bubble { background: #f3f4f6; color: #1f2937; border-top-left-radius: 2px; }
.row-user .bubble { background: #3b82f6; color: white; border-top-right-radius: 2px; }
.time {
font-size: 10px;
opacity: 0.7;
margin-top: 4px;
text-align: right;
}
.input-area {
padding: 16px;
background: #f9fafb;
border-top: 1px solid #e5e7eb;
display: flex;
gap: 10px;
}
input {
flex: 1;
padding: 10px;
border: 1px solid #d1d5db;
border-radius: 6px;
outline: none;
}
input:focus { border-color: #3b82f6; }
button {
padding: 0 20px;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: opacity 0.2s;
}
button:disabled {
background: #9ca3af;
cursor: not-allowed;
}
</style>