mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-07-27 04:20:43 +08:00
feat: 新增全局搜索功能,优化页面默认跳转逻辑
1. 新增全局搜索弹窗组件及相关事件常量 2. 修复首页默认跳转路径,改回首页而非动态页 3. 注释无用的单例运行代码 4. 添加背景模糊样式类 5. 更新搜索API类型定义 6. 底部导航栏搜索按钮触发全局搜索弹窗
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
<script setup lang="ts">
|
||||
import { indicesSearch } from '@/api/halo-base/common'
|
||||
import { timeFormat } from '@/utils/base/timeFormat'
|
||||
import { debounce } from '@/utils/base/debounce'
|
||||
import { GLOBAL_SEARCH_EVENT_NAME } from '@/constants/events'
|
||||
import type { HaloDocument, SearchOption, SearchResult } from '@halo-dev/api-client'
|
||||
|
||||
const { loading, error, data, run } = useRequest<SearchResult, SearchOption>(indicesSearch, { loadingToast: false, loadingToastContent: '加载中...', loadingToastMask: true })
|
||||
|
||||
const scroll = reactive({
|
||||
top: 0,
|
||||
})
|
||||
|
||||
const searchParams = ref<SearchOption>({
|
||||
keyword: undefined,
|
||||
limit: 50,
|
||||
})
|
||||
|
||||
const searchResultTypeMap = {
|
||||
'moment.moment.halo.run': 'moment',
|
||||
'post.content.halo.run': 'post',
|
||||
'doc.halo.run': 'doc',
|
||||
}
|
||||
const searchResultTypeCN = {
|
||||
'moment.moment.halo.run': '瞬间',
|
||||
'post.content.halo.run': '文章',
|
||||
'doc.halo.run': '文档',
|
||||
}
|
||||
|
||||
interface SearchResultItem extends HaloDocument {
|
||||
releaseTime: string
|
||||
typeCN: string
|
||||
}
|
||||
|
||||
const searchResult = computed<Array<SearchResultItem>>(() => {
|
||||
if (!data.value || data.value?.hits?.length === 0) {
|
||||
return []
|
||||
}
|
||||
return data.value.hits.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
type: searchResultTypeMap[item.type],
|
||||
typeCN: searchResultTypeCN[item.type],
|
||||
releaseTime: timeFormat(item.updateTimestamp ?? item.creationTimestamp),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function handleSearch() {
|
||||
if (!searchParams.value.keyword) {
|
||||
uni.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
scroll.top = 0
|
||||
run(searchParams.value)
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
setTimeout(() => {
|
||||
uni.$emit(GLOBAL_SEARCH_EVENT_NAME)
|
||||
}, 30)
|
||||
}
|
||||
|
||||
const onViewScroll = debounce((e: any) => {
|
||||
scroll.top = e.detail.scrollTop
|
||||
}, 150)
|
||||
|
||||
onMounted(() => {
|
||||
handleSearch()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view
|
||||
class="uh-backdrop-blur fixed inset-0 z-110 flex items-center justify-center bg-black/20"
|
||||
@click.stop="handleClose"
|
||||
>
|
||||
<!-- 内容区 -->
|
||||
<view class="box-border h-[65vh] w-[80vw] flex flex-col overflow-hidden rounded-2xl bg-page2 p-2" @click.stop>
|
||||
<view class="box-border w-full flex shrink-0 items-center justify-between gap-x-4 p-2">
|
||||
<view class="flex flex-1 items-center gap-x-2">
|
||||
<input
|
||||
v-model="searchParams.keyword" :auto-focus="true" type="text" placeholder="请输入搜索内容"
|
||||
class="flex-1 border-2 border-gray-900 rounded-md border-solid px-2 py-1 text-xs text-gray-900 placeholder:text-xs"
|
||||
>
|
||||
<view
|
||||
class="flex items-center justify-center rounded-lg bg-gray-900 px-3 py-2"
|
||||
@click="handleSearch()"
|
||||
>
|
||||
<wd-icon name="search-line" color="#ffffff" :size="16" />
|
||||
<text class="text-xs text-white">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="shrink-0">
|
||||
<wd-icon name="close-circle" size="24px" color="#1A1A1A" @click="handleClose" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果区 -->
|
||||
<view class="mb-2 box-border flex items-center justify-between px-2">
|
||||
<text class="text-xs text-gray-900 font-bold">搜索结果</text>
|
||||
<text class="text-xs text-gray-600">共 {{ searchResult.length }} 条</text>
|
||||
</view>
|
||||
<scroll-view
|
||||
v-if="searchResult.length !== 0" class="h-[53vh] w-full" :scroll-y="true"
|
||||
:scroll-top="scroll.top" @scroll="onViewScroll"
|
||||
>
|
||||
<view class="box-border flex flex-col gap-y-3 px-2">
|
||||
<!-- 卡片 -->
|
||||
<view
|
||||
v-for="(item, index) in searchResult" :key="item.metadataName"
|
||||
class="uh-shadow-xs box-border w-full flex flex-col gap-y-2 rounded-lg bg-white p-3"
|
||||
>
|
||||
<view class="flex items-center gap-x-2">
|
||||
<view
|
||||
class="flex items-center rounded-md bg-gray-900 px-1.5 py-0.5 text-xs text-white font-bold"
|
||||
>
|
||||
# <text class="pl-0.5 text-[12px]">{{ index + 1 }}</text>
|
||||
</view>
|
||||
<rich-text :nodes="item.title" class="line-clamp-1 text-sm text-gray-900 font-bold" />
|
||||
</view>
|
||||
<view class="line-clamp-2 w-full text-xs text-gray-600 leading-relaxed">
|
||||
<rich-text :nodes="item.description ?? item.content" />
|
||||
</view>
|
||||
<view class="h-1px w-full bg-gray-50" />
|
||||
<view class="flex items-center justify-between gap-x-4">
|
||||
<view class="rounded-md bg-gray-900 px-2 py-1 text-[11px] text-white">
|
||||
来自{{ item.typeCN }}
|
||||
</view>
|
||||
<text class="text-xs text-gray-600">{{ item.releaseTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view v-else-if="loading" class="flex flex-1 items-center justify-center">
|
||||
<wd-loading text="搜索中..." color="#1A1A1A" :size="52" />
|
||||
</view>
|
||||
<view v-else-if="error" class="flex flex-1 items-center justify-center">
|
||||
<wd-empty tip="搜索失败">
|
||||
<template #image>
|
||||
<wd-icon name="close-circle" color="#1A1A1A" :size="52" />
|
||||
</template>
|
||||
<template #bottom>
|
||||
<view
|
||||
class="flex items-center justify-center rounded-lg bg-gray-900 px-3 py-2"
|
||||
@click="handleSearch()"
|
||||
>
|
||||
<wd-icon name="search-line" color="#ffffff" :size="16" />
|
||||
<text class="pl-1 text-xs text-white">点击重试</text>
|
||||
</view>
|
||||
</template>
|
||||
</wd-empty>
|
||||
</view>
|
||||
<view v-else class="flex flex-1 items-center justify-center">
|
||||
<wd-empty tip="暂无搜索结果">
|
||||
<template #image>
|
||||
<wd-icon name="empty" color="#1A1A1A" :size="52" />
|
||||
</template>
|
||||
</wd-empty>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
Reference in New Issue
Block a user