diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue index 49e5d12..4a7c983 100644 --- a/src/components/layout/AppHeader.vue +++ b/src/components/layout/AppHeader.vue @@ -42,9 +42,24 @@
- @@ -136,6 +151,7 @@ import { NDropdown, NIcon } from 'naive-ui' import LoginModal from '@/components/auth/LoginModal.vue' import RegisterModal from '@/components/auth/RegisterModal.vue' import SafeAvatar from '@/components/common/SafeAvatar.vue' +import SearchDropdown from '@/components/search/SearchDropdown.vue' const router = useRouter() const route = useRoute() @@ -200,6 +216,12 @@ const registerModalVisible = ref(false) const showLanguageDropdown = ref(false) const languageSwitcherRef = ref(null) +// 搜索相关 +const searchKeyword = ref('') +const showSearchDropdown = ref(false) +const searchBoxRef = ref(null) +const searchDropdownRef = ref | null>(null) + // 语言选项配置 const languageOptions = computed(() => [ { @@ -278,6 +300,36 @@ const getLanguageName = (lang: string): string => { return languageMap[lang] || '中文' } +// 搜索相关方法 +const handleSearch = () => { + if (searchKeyword.value.trim()) { + performSearch(searchKeyword.value.trim()) + } +} + +const handleSearchFromDropdown = (keyword: string) => { + searchKeyword.value = keyword + performSearch(keyword) +} + +const performSearch = (keyword: string) => { + console.log('🔍 执行搜索:', keyword) + + // 保存搜索记录到最近搜索 + if (searchDropdownRef.value) { + searchDropdownRef.value.saveRecentSearch(keyword) + } + + // 跳转到搜索结果页面 + router.push({ + path: '/search', + query: { q: keyword } + }) + + // 关闭搜索下拉框 + showSearchDropdown.value = false +} + const handleLearningCenter = () => { @@ -634,10 +686,15 @@ const handleAuthSuccess = () => { // 修复未定义的handleClickOutside const handleClickOutside = (event: MouseEvent) => { - // 这里只处理语言下拉的关闭,其他弹窗由自身控制 + // 处理语言下拉的关闭 if (languageSwitcherRef.value && !languageSwitcherRef.value.contains(event.target as Node)) { showLanguageDropdown.value = false } + + // 处理搜索下拉的关闭 + if (searchBoxRef.value && !searchBoxRef.value.contains(event.target as Node)) { + showSearchDropdown.value = false + } } // 生命周期钩子 @@ -863,6 +920,7 @@ watch(() => route.path, () => { .search-box { /* border-left: 1px solid #ececec; border-right: 1px solid #ececec; */ + position: relative; display: flex; align-items: center; padding: 22px 16px; diff --git a/src/components/search/SearchDropdown.vue b/src/components/search/SearchDropdown.vue new file mode 100644 index 0000000..2abc815 --- /dev/null +++ b/src/components/search/SearchDropdown.vue @@ -0,0 +1,384 @@ + + + + + diff --git a/src/views/Login.vue b/src/views/Login.vue index d93ed5a..4a59465 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -114,7 +114,7 @@
@@ -336,6 +336,11 @@ const handleSubmit = async () => { userStore.isLoading = false } } + +// 跳转到服务协议页面 +const goToServiceAgreement = () => { + router.push('/service-agreement') +}