feat: 优化
This commit is contained in:
@@ -70,8 +70,8 @@
|
||||
<!-- 加载中 -->
|
||||
<div v-if="loading" class="message-item message-item--assistant">
|
||||
<div class="agent-avatar-small msg-avatar">
|
||||
<RobotOutlined v-if="!agent?.avatar" class="avatar-icon" />
|
||||
<img v-else :src="agent?.avatar" :alt="agent?.name" />
|
||||
<img v-if="agent?.avatar" :src="agent?.avatar" :alt="agent?.name" />
|
||||
<RobotOutlined v-else class="avatar-icon" />
|
||||
</div>
|
||||
<div class="message-bubble message-bubble--assistant">
|
||||
<div class="typing-indicator">
|
||||
@@ -135,6 +135,7 @@ import {
|
||||
ThunderboltFilled
|
||||
} from '@ant-design/icons-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { sendChatStream } from '@/api/agent'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@@ -156,9 +157,16 @@ const loading = ref(false)
|
||||
const messages = ref([])
|
||||
const messagesRef = ref(null)
|
||||
const userAvatar = ref('王')
|
||||
const conversationId = ref(null) // 会话ID,用于连续对话
|
||||
const abortController = ref(null) // 用于取消请求
|
||||
|
||||
// 方法
|
||||
const handleClose = () => {
|
||||
// 取消正在进行的请求
|
||||
if (abortController.value) {
|
||||
abortController.value.abort()
|
||||
abortController.value = null
|
||||
}
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
@@ -181,24 +189,74 @@ const handleSend = async () => {
|
||||
|
||||
await scrollToBottom()
|
||||
|
||||
// 模拟 AI 响应
|
||||
setTimeout(() => {
|
||||
const assistantMessage = {
|
||||
role: 'assistant',
|
||||
content: generateMockResponse(question),
|
||||
isPro: modelMode.value === 'pro',
|
||||
actions: true
|
||||
}
|
||||
messages.value.push(assistantMessage)
|
||||
loading.value = false
|
||||
nextTick(() => scrollToBottom())
|
||||
}, 1500)
|
||||
// 创建 AI 消息占位
|
||||
const assistantMessage = {
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
isPro: modelMode.value === 'pro',
|
||||
actions: false
|
||||
}
|
||||
messages.value.push(assistantMessage)
|
||||
|
||||
emit('send', {
|
||||
agentId: props.agent?.id,
|
||||
content: question,
|
||||
modelMode: modelMode.value
|
||||
})
|
||||
// 创建取消控制器
|
||||
abortController.value = new AbortController()
|
||||
|
||||
// 调用流式对话 API
|
||||
try {
|
||||
await sendChatStream({
|
||||
agentId: props.agent?.id,
|
||||
content: question,
|
||||
conversationId: conversationId.value,
|
||||
ctrl: abortController.value,
|
||||
onMessage: (result) => {
|
||||
if (result.event === 'message' && result.content) {
|
||||
// 追加消息内容
|
||||
assistantMessage.content += result.content
|
||||
scrollToBottom()
|
||||
} else if (result.event === 'done') {
|
||||
// 对话完成
|
||||
conversationId.value = result.conversationId
|
||||
assistantMessage.actions = true
|
||||
} else if (result.event === 'error') {
|
||||
// 错误处理
|
||||
message.error(result.errorMessage || '对话出错')
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('发送消息失败:', error)
|
||||
message.error('发送消息失败,请重试')
|
||||
// 移除失败的 AI 消息
|
||||
const lastMsg = messages.value[messages.value.length - 1]
|
||||
if (lastMsg?.role === 'assistant' && !lastMsg.content) {
|
||||
messages.value.pop()
|
||||
}
|
||||
},
|
||||
onClose: () => {
|
||||
loading.value = false
|
||||
abortController.value = null
|
||||
nextTick(() => scrollToBottom())
|
||||
}
|
||||
})
|
||||
|
||||
emit('send', {
|
||||
agentId: props.agent?.id,
|
||||
content: question,
|
||||
modelMode: modelMode.value
|
||||
})
|
||||
} catch (error) {
|
||||
// 用户取消不需要提示
|
||||
if (error.name !== 'AbortError') {
|
||||
console.error('发送消息失败:', error)
|
||||
message.error('发送消息失败,请重试')
|
||||
// 移除失败的 AI 消息
|
||||
const lastMsg = messages.value[messages.value.length - 1]
|
||||
if (lastMsg?.role === 'assistant' && !lastMsg.content) {
|
||||
messages.value.pop()
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
@@ -213,9 +271,14 @@ const handleCopy = (content) => {
|
||||
message.success('已复制到剪贴板')
|
||||
}
|
||||
|
||||
const handleRegenerate = (index) => {
|
||||
// TODO: 重新生成消息
|
||||
message.info('重新生成中...')
|
||||
const handleRegenerate = async (index) => {
|
||||
// 重新生成:移除当前消息,重新发送上一条用户消息
|
||||
if (index > 0 && messages.value[index - 1]?.role === 'user') {
|
||||
const userMsg = messages.value[index - 1]
|
||||
messages.value.splice(index - 1, 2) // 移除用户消息和 AI 回复
|
||||
inputText.value = userMsg.content
|
||||
await handleSend()
|
||||
}
|
||||
}
|
||||
|
||||
const scrollToBottom = async () => {
|
||||
@@ -225,20 +288,13 @@ const scrollToBottom = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateMockResponse = (question) => {
|
||||
const responses = [
|
||||
'当夜深人静的时候,我们卸下了一天的铠甲,那才是真实的自己。成年人的世界里,连崩溃都要调成静音模式。',
|
||||
'根据您的需求,我为您生成以下内容:这是一个经过精心设计的文案,结合了情感共鸣和产品卖点。',
|
||||
'让我帮您分析一下这个问题。首先,我们需要考虑目标受众的需求和痛点...'
|
||||
]
|
||||
return responses[Math.floor(Math.random() * responses.length)]
|
||||
}
|
||||
|
||||
// 监听 visible 变化,重置状态
|
||||
watch(() => props.visible, (newVal) => {
|
||||
if (newVal) {
|
||||
messages.value = []
|
||||
inputText.value = ''
|
||||
conversationId.value = null // 重置会话ID
|
||||
abortController.value = null
|
||||
nextTick(() => scrollToBottom())
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user