feat(agent-panel): 添加可调整宽度的agent面板

- 为 AgentPanel 组件添加拖拽调整宽度功能
- 引入 resize-handle 组件处理拖拽交互
- 设置面板宽度范围限制(280px-600px)
This commit is contained in:
Wenjie Zhang 2026-01-31 17:04:30 +08:00
parent f31705d58c
commit cfb0ed7609
2 changed files with 82 additions and 10 deletions

View File

@ -167,12 +167,18 @@
<!-- Agent Panel Area -->
<transition name="panel-slide">
<div class="agent-panel-wrapper" v-if="isAgentPanelOpen && hasAgentStateContent">
<div
class="agent-panel-wrapper"
v-if="isAgentPanelOpen && hasAgentStateContent"
:style="{ width: `${panelWidth}px` }"
>
<AgentPanel
:agent-state="currentAgentState"
:thread-id="currentChatId"
:panel-width="panelWidth"
@refresh="handleAgentStateRefresh"
@close="toggleAgentPanel"
@resize="handlePanelResize"
/>
</div>
</transition>
@ -257,6 +263,9 @@ const localUIState = reactive({
// Agent Panel State
const isAgentPanelOpen = ref(false)
const panelWidth = ref(360)
const minPanelWidth = 280
const maxPanelWidth = 600
// ==================== COMPUTED PROPERTIES ====================
const currentAgentId = computed(() => {
@ -973,6 +982,12 @@ const toggleAgentPanel = () => {
isAgentPanelOpen.value = !isAgentPanelOpen.value
}
//
// deltaX
const handlePanelResize = (deltaX) => {
panelWidth.value = Math.min(maxPanelWidth, Math.max(minPanelWidth, panelWidth.value - deltaX))
}
// ==================== HELPER FUNCTIONS ====================
const getLastMessage = (conv) => {
if (!conv?.messages?.length) return null
@ -1153,7 +1168,7 @@ watch(
}
.agent-panel-wrapper {
flex: 3; /* 4:3 ratio with chat-main */
flex: 0 0 auto;
height: calc(100% - 32px);
overflow: hidden;
z-index: 20;
@ -1163,7 +1178,7 @@ watch(
border-radius: 12px;
box-shadow: 0 4px 20px var(--shadow-1);
border: 1px solid var(--gray-200);
min-width: 0; /* Prevent flex item from overflowing */
min-width: 0;
}
/* Workbench transition animations */

View File

@ -1,5 +1,7 @@
<template>
<div class="agent-panel">
<div class="agent-panel" :class="{ resizing: isResizing }">
<!-- 拖拽手柄 -->
<div class="resize-handle" @mousedown="startResize"></div>
<div class="panel-header">
<div class="panel-title">
<FolderCode :size="16" class="header-icon" />
@ -238,7 +240,7 @@ const props = defineProps({
}
})
const emit = defineEmits(['refresh', 'close'])
const emit = defineEmits(['refresh', 'close', 'resize'])
const activeTab = ref('todos')
const modalVisible = ref(false)
@ -396,14 +398,68 @@ const handleFileChange = async (event) => {
const emitRefresh = () => {
emit('refresh')
}
//
const isResizing = ref(false)
const startX = ref(0)
const startResize = (e) => {
isResizing.value = true
startX.value = e.clientX
document.body.style.cursor = 'col-resize'
document.body.style.userSelect = 'none'
//
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', stopResize)
}
const onMouseMove = (e) => {
if (!isResizing.value) return
const deltaX = e.clientX - startX.value
startX.value = e.clientX
emit('resize', deltaX)
}
const stopResize = () => {
if (isResizing.value) {
isResizing.value = false
document.body.style.cursor = ''
document.body.style.userSelect = ''
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', stopResize)
}
}
</script>
<style scoped lang="less">
.resize-handle {
position: absolute;
left: -2px;
top: 50%;
transform: translateY(-50%);
height: 32px;
width: 4px;
cursor: col-resize;
background: var(--gray-300);
border-radius: 2px;
z-index: 10;
transition: background 0.2s;
&:hover {
background: var(--main-400);
}
}
.agent-panel {
height: 100%;
display: flex;
flex-direction: column;
background: var(--gray-0);
transition: none;
&.resizing {
transition: none;
}
}
.panel-header {
@ -412,7 +468,7 @@ const emitRefresh = () => {
justify-content: space-between;
padding: 0 12px;
height: 40px;
border-bottom: 1px solid var(--gray-200);
background: var(--gray-25);
flex-shrink: 0;
}
@ -464,10 +520,11 @@ const emitRefresh = () => {
.tabs {
display: flex;
border-bottom: 1px solid var(--gray-100);
background: var(--gray-25);
position: relative;
align-items: center;
padding: 4px 6px;
padding: 8px 6px;
padding-top: 0px;
gap: 4px;
flex-shrink: 0;
}
@ -484,12 +541,12 @@ const emitRefresh = () => {
border-radius: 999px;
&:hover {
background: var(--gray-100);
background: var(--gray-150);
color: var(--gray-900);
}
&.active {
background: var(--gray-100);
background: var(--gray-150);
color: var(--gray-900);
}
}