ForcePilot/web/src/components/ViewSwitchHeader.vue
Wenjie Zhang a7d3c0ba2e refactor(chat): 重构聊天侧边栏为 ConversationNavSection
- 删除 ChatSidebarComponent.vue (627行)
- 新增 ConversationNavSection.vue (316行) 实现对话历史导航
- 新增 chatThreads store 管理对话线程状态
- 重构 AppLayout.vue 使用新的侧边栏架构
- 优化 UserInfoComponent 头像加载逻辑与降级处理
- 更新 AgentArtifactsCard 移除未使用的 Eye 图标
2026-04-24 22:44:37 +08:00

121 lines
2.6 KiB
Vue

<template>
<HeaderComponent :title="title" :loading="loading">
<template #behind-title>
<nav class="view-switcher" :aria-label="ariaLabel">
<slot name="options" :items="items" :active-key="activeKey" :select="selectItem">
<template v-for="item in items" :key="item.key">
<RouterLink
v-if="item.path"
:to="item.path"
class="switcher-item"
:class="{ active: activeKey === item.key }"
@click="selectItem(item)"
>
{{ item.label }}
</RouterLink>
<button
v-else
type="button"
class="switcher-item"
:class="{ active: activeKey === item.key }"
@click="selectItem(item)"
>
{{ item.label }}
</button>
</template>
</slot>
</nav>
</template>
<template #actions v-if="$slots.actions">
<slot name="actions"></slot>
</template>
</HeaderComponent>
</template>
<script setup>
import { RouterLink } from 'vue-router'
import HeaderComponent from '@/components/HeaderComponent.vue'
defineProps({
title: {
type: String,
required: true
},
loading: {
type: Boolean,
default: false
},
activeKey: {
type: String,
required: true
},
items: {
type: Array,
required: true
},
ariaLabel: {
type: String,
default: '视图切换'
}
})
const emit = defineEmits(['update:activeKey', 'change'])
const selectItem = (item) => {
emit('update:activeKey', item.key)
emit('change', item)
}
</script>
<style scoped lang="less">
.view-switcher {
display: inline-flex;
align-items: center;
gap: 2px;
padding-left: 12px;
margin-left: 2px;
border-left: 1px solid var(--gray-200);
height: 16px;
line-height: 16px;
}
.switcher-item {
display: inline-flex;
align-items: center;
height: 28px;
padding: 0 10px;
border: 1px solid transparent;
border-radius: 6px;
background: transparent;
color: var(--gray-600);
font-size: 15px;
font-weight: 500;
line-height: 1;
text-decoration: none;
cursor: pointer;
transition:
background-color 0.2s ease,
color 0.2s ease,
border-color 0.2s ease,
box-shadow 0.2s ease;
&:hover {
color: var(--gray-900);
background-color: var(--gray-50);
}
&:focus-visible {
outline: 2px solid var(--main-200);
outline-offset: 2px;
}
&.active {
color: var(--main-color);
background-color: color-mix(in srgb, var(--main-color) 6%, var(--gray-0));
border-color: transparent;
position: relative;
}
}
</style>