refactor(chat): 重构聊天输入
This commit is contained in:
parent
c22eaf781c
commit
2616b53858
|
@ -72,27 +72,10 @@
|
|||
<el-tag size="large" type="info" class="end-tag">会话已结束</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-area">
|
||||
<el-input
|
||||
v-model="messageInput"
|
||||
type="textarea"
|
||||
:rows="1"
|
||||
:autosize="{ minRows: 1, maxRows: 6 }"
|
||||
placeholder="请输入消息..."
|
||||
@keyup.enter.exact.prevent="sendMessage"
|
||||
resize="none"
|
||||
ref="messageInputRef"
|
||||
:disabled="isInputDisabled"
|
||||
/>
|
||||
<el-button
|
||||
class="send-btn"
|
||||
@click="sendMessage"
|
||||
:disabled="isInputDisabled || !messageInput.trim()"
|
||||
type="primary"
|
||||
>
|
||||
发送
|
||||
</el-button>
|
||||
</div>
|
||||
<ChatInput
|
||||
:is-input-disabled="isInputDisabled"
|
||||
@send="sendMessage"
|
||||
/>
|
||||
<!-- 总结弹窗 -->
|
||||
<div v-if="lastMessageWithDafen" class="summary-panel" :class="{ 'summary-panel-collapsed': isSummaryCollapsed }">
|
||||
<div class="summary-header" @click="toggleSummary">
|
||||
|
@ -112,7 +95,8 @@ import { ref, onMounted, onUnmounted, nextTick, watch, computed, defineOptions }
|
|||
import { marked } from 'marked'
|
||||
import * as echarts from 'echarts'
|
||||
import { useChatStore } from '@/store/chat'
|
||||
import ChatHeader from '@/views/chat/ChatHeader.vue'
|
||||
import ChatHeader from '@/views/chat/components/ChatHeader.vue'
|
||||
import ChatInput from '@/views/chat/components/ChatInput.vue'
|
||||
import { ElTag, ElButton, ElInput, ElAvatar } from 'element-plus'
|
||||
import { Plus, CaretBottom, CaretRight } from '@element-plus/icons-vue'
|
||||
import userAvatarUrl from '@/assets/user.png';
|
||||
|
@ -241,11 +225,9 @@ watch(() => currentMessages.value?.map(msg => msg.respondingType), (newTypes, ol
|
|||
}, { deep: true })
|
||||
|
||||
// 发送消息时滚动到底部
|
||||
const sendMessage = () => {
|
||||
if (!messageInput.value.trim() && !sendButtonsDisabled.value) return
|
||||
chatStore.sendMessage(messageInput.value)
|
||||
messageInput.value = ''
|
||||
messageInputRef.value.style.height = 'auto'
|
||||
const sendMessage = (message) => {
|
||||
if (!message.trim() && !sendButtonsDisabled.value) return
|
||||
chatStore.sendMessage(message)
|
||||
shouldAutoScroll.value = true // 发送消息时恢复自动滚动
|
||||
scrollToBottom(true)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
|
||||
</el-menu>
|
||||
<HistoryList />
|
||||
<ChatHistoryList />
|
||||
<!-- Settings Button Popover -->
|
||||
<el-popover
|
||||
placement="top-end"
|
||||
|
@ -65,7 +65,7 @@ import { computed, ref, onMounted, onUnmounted } from 'vue'
|
|||
import { ChatDotRound, ChatLineRound, ChatRound, Service, Setting, Clock, Delete, Plus } from '@element-plus/icons-vue'
|
||||
import { ElMenu, ElMenuItem, ElIcon, ElPopover, ElMessageBox } from 'element-plus'
|
||||
import SettingsPanel from '@/components/settings/SettingsPanel.vue'
|
||||
import HistoryList from '@/components/chat/HistoryList.vue'
|
||||
import ChatHistoryList from '@/views/chat/components/ChatHistoryList.vue'
|
||||
|
||||
const chatStore = useChatStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div class="input-area">
|
||||
<el-input
|
||||
v-model="messageInput"
|
||||
type="textarea"
|
||||
:rows="1"
|
||||
:autosize="{ minRows: 1, maxRows: 6 }"
|
||||
placeholder="请输入消息..."
|
||||
@keyup.enter.exact.prevent="handleSend"
|
||||
resize="none"
|
||||
ref="messageInputRef"
|
||||
:disabled="isInputDisabled"
|
||||
/>
|
||||
<el-button
|
||||
class="send-btn"
|
||||
@click="handleSend"
|
||||
:disabled="isInputDisabled || !messageInput.trim()"
|
||||
type="primary"
|
||||
>
|
||||
发送
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ElInput, ElButton } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
isInputDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['send'])
|
||||
|
||||
const messageInput = ref('')
|
||||
const messageInputRef = ref(null)
|
||||
const maxRows = 6
|
||||
|
||||
const handleSend = () => {
|
||||
if (!messageInput.value.trim() && !props.isInputDisabled) return
|
||||
emit('send', messageInput.value)
|
||||
messageInput.value = ''
|
||||
messageInputRef.value.style.height = 'auto'
|
||||
}
|
||||
|
||||
const adjustTextareaHeight = () => {
|
||||
const textarea = messageInputRef.value
|
||||
textarea.style.height = 'auto'
|
||||
const newHeight = Math.min(textarea.scrollHeight, maxRows * 24)
|
||||
textarea.style.height = newHeight + 'px'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.input-area {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid var(--el-border-color-light);
|
||||
background-color: var(--el-bg-color);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.el-textarea {
|
||||
flex: 1;
|
||||
|
||||
:deep(.el-textarea__inner) {
|
||||
border-radius: 8px;
|
||||
resize: none;
|
||||
padding: 8px 12px;
|
||||
min-height: 40px !important;
|
||||
max-height: 120px;
|
||||
line-height: 24px;
|
||||
font-size: 14px;
|
||||
|
||||
&:disabled {
|
||||
background-color: var(--el-input-disabled-bg);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
height: 40px;
|
||||
padding: 0 20px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
// Dark mode override for input area
|
||||
html.dark .input-area {
|
||||
background: var(--el-color-primary-dark-1);
|
||||
border-top-color: var(--el-border-color-dark);
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.input-area {
|
||||
padding: 12px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
min-width: 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue