All checks were successful
deploy to server / build-and-deploy (push) Successful in 3m7s
- 将meilisearch搜索服务移至Server端
117 lines
2.4 KiB
Vue
117 lines
2.4 KiB
Vue
<template>
|
|
<div class="search-page">
|
|
<search-header v-model="keyword" />
|
|
<div v-if="loading" class="search-state">
|
|
<el-skeleton :rows="4" animated />
|
|
</div>
|
|
<search-tabs v-else-if="hasResults" :search-items="searchItems" />
|
|
<div v-else class="search-state">
|
|
<el-empty
|
|
:description="
|
|
route.query.query
|
|
? $t('search.no-results', { query: route.query?.query })
|
|
: $t('search.no-query')
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
// i18n相关
|
|
const { t } = useI18n();
|
|
const { getDirectusLocale } = useLocalizations();
|
|
const locale = getDirectusLocale();
|
|
|
|
// 路由相关
|
|
const route = useRoute();
|
|
|
|
// 搜索相关
|
|
const keyword = ref('');
|
|
|
|
if (typeof route.query.query === 'string' && route.query.query.trim()) {
|
|
keyword.value = route.query.query;
|
|
}
|
|
|
|
const {
|
|
data: searchItems,
|
|
pending: loading,
|
|
error,
|
|
refresh,
|
|
} = useAsyncData(`meilisearch-${keyword.value}-${locale}`, async () => {
|
|
try {
|
|
const data = await $fetch(`/api/search?query=${keyword.value}`, {
|
|
headers: { 'x-locale': locale },
|
|
});
|
|
return data;
|
|
} catch (error) {
|
|
logger.error('Error fetching search results: ', error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
const hasResults = computed(() => searchItems.value.length > 0);
|
|
|
|
watch(
|
|
() => route.query.query,
|
|
async (newQuery) => {
|
|
if (typeof newQuery === 'string' && newQuery.trim()) {
|
|
keyword.value = newQuery;
|
|
await refresh();
|
|
}
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => locale,
|
|
async () => {
|
|
await refresh();
|
|
}
|
|
);
|
|
|
|
watch(error, (value) => {
|
|
if (value) {
|
|
logger.error('数据获取失败: ', value);
|
|
}
|
|
});
|
|
|
|
onMounted(() => {
|
|
if (typeof route.query.query === 'string' && route.query.query.trim())
|
|
keyword.value = route.query.query;
|
|
});
|
|
|
|
useHead(() => ({
|
|
title: t('search.head-title'),
|
|
}));
|
|
</script>
|
|
|
|
<style scoped>
|
|
.search-page {
|
|
margin: 0 auto;
|
|
max-width: 960px;
|
|
padding: 2.5rem 1.5rem 3rem;
|
|
min-height: 70vh;
|
|
}
|
|
|
|
.search-state {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 3rem 0;
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
.search-page {
|
|
padding: 2rem 1rem;
|
|
}
|
|
|
|
.search-bar {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.search-input {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|