wx/src/views/chat/ChatHeader.vue

302 lines
6.5 KiB
Vue

<template>
<div class="chat-header">
<div class="header-content">
<div class="title">
<el-button
class="mobile-sidebar-toggle"
:icon="Expand"
@click="settingsStore.toggleSidebar"
text
v-if="isMobile"
/>
<span class="title-text">{{ title }}</span>
<el-tag v-if="chatStore.currentConversation?.conversationStatus === 'typing'"
size="small"
class="status-tag"
type="warning"
>
对话中
</el-tag>
<HistoryButton v-if="settingsStore.sidebarCollapsed" :icon-only="false" class="title-history-btn" />
</div>
<div class="actions">
<el-tooltip content="删除会话" placement="bottom" v-if="chatStore.conversationId">
<el-button
class="action-btn delete-btn"
:icon="Delete"
@click="handleDelete"
text
>
</el-button>
</el-tooltip>
<el-tooltip content="设置" placement="bottom">
<el-button
class="action-btn"
:icon="Setting"
@click="handleSettings"
text
>
</el-button>
</el-tooltip>
<el-tooltip :content="hasBackground ? '客户背景' : '暂无客户背景信息'" placement="bottom" v-if="hasBackground">
<el-button
class="action-btn"
:icon="User"
@click="showUserInfo = true"
text
>
</el-button>
</el-tooltip>
</div>
</div>
<CustomerBackground v-model="showUserInfo" ref="customerBackgroundRef" />
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useChatStore } from '@/store/chat'
import { useSettingsStore } from '@/store/settings'
import { Delete, Setting, User, Expand } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus'
import HistoryButton from '@/components/chat/HistoryButton.vue'
import CustomerBackground from '@/components/chat/CustomerBackground.vue'
const chatStore = useChatStore()
const settingsStore = useSettingsStore()
const showUserInfo = ref(false)
const customerBackgroundRef = ref(null)
const isMobile = ref(false)
const title = computed(() => {
const conversation = chatStore.currentConversation
if (!conversation) return '新会话'
// 使用第一条消息作为标题
if (conversation.chatMessages && conversation.chatMessages.length > 0) {
return conversation.chatMessages[0].question
}
return '新会话'
})
const hasBackground = computed(() => {
return customerBackgroundRef.value?.hasBackground ?? false
})
const handleDelete = async () => {
console.log(chatStore.conversationId)
if (!chatStore.conversationId) return
try {
await ElMessageBox.confirm(
'确定要删除当前会话吗?删除后无法恢复。',
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
confirmButtonClass: 'el-button--danger'
}
)
chatStore.deleteConversation(chatStore.conversationId)
} catch {
// 用户取消操作
}
}
const handleSettings = () => {
// TODO: 实现设置功能
console.log('打开设置')
}
const checkMobile = () => {
isMobile.value = window.innerWidth <= 768
}
onMounted(() => {
checkMobile()
window.addEventListener('resize', checkMobile)
})
onUnmounted(() => {
window.removeEventListener('resize', checkMobile)
})
</script>
<style lang="scss" scoped>
.chat-header {
height: 60px;
border-bottom: 1px solid #e5e5e5;
background: #fff;
padding: 0 20px;
flex-shrink: 0;
.header-content {
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.title {
display: flex;
align-items: center;
gap: 4px;
height: 100%;
.mobile-sidebar-toggle {
height: 24px;
width: 24px;
padding: 0;
color: #666;
transition: all 0.3s ease;
border: none;
background: transparent !important;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
margin-left: -4px;
&:hover {
color: #07c160;
background: transparent !important;
}
&:focus {
outline: none;
box-shadow: none;
}
:deep(.el-icon) {
font-size: 18px;
margin-top: 1px;
}
}
.title-text {
font-size: 16px;
font-weight: 500;
color: #333;
max-width: 500px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 24px;
padding-top: 1px;
}
.status-tag {
font-weight: normal;
flex-shrink: 0;
}
.title-history-btn {
:deep(.history-btn) {
height: 32px;
padding: 0 12px;
color: #666;
transition: all 0.3s ease;
font-size: 14px;
&:hover {
color: #07c160 !important;
}
:deep(.el-icon) {
font-size: 16px;
margin-right: 4px;
}
}
}
}
.actions {
display: flex;
align-items: center;
gap: 4px;
.action-btn {
height: 32px;
width: 32px;
padding: 0;
color: #666;
transition: all 0.3s ease;
border: none;
background: transparent !important;
font-size: 14px;
&:hover {
color: #07c160;
background: transparent !important;
}
&.delete-btn {
&:hover {
color: var(--el-color-danger) !important;
}
}
&:focus {
outline: none;
box-shadow: none;
}
:deep(.el-icon) {
font-size: 16px;
}
}
}
}
.user-info-content {
padding: 20px;
.info-section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
h3 {
font-size: 16px;
font-weight: 500;
color: #333;
margin: 0 0 12px 0;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
}
.info-item {
display: flex;
margin-bottom: 8px;
line-height: 1.6;
&:last-child {
margin-bottom: 0;
}
&.description {
flex-direction: column;
gap: 8px;
}
.label {
color: #666;
min-width: 80px;
flex-shrink: 0;
}
.value {
color: #333;
flex: 1;
}
}
}
}
.dialog-footer {
padding-top: 20px;
}
</style>