feat: 将搜索页面由Strapi迁移至Direcuts

- 路由页面相关源码修改
- 类型标注与组合式API
- 相关工具函数
This commit is contained in:
2025-10-24 16:18:26 +08:00
parent 05938550e6
commit f62c4a3987
11 changed files with 309 additions and 151 deletions

View File

@ -2,14 +2,14 @@
<div v-if="hasResults">
<div class="search-results">
<NuxtLink
v-for="(hit, hitIndex) in paginatedHits"
:key="`${getHitIdentifier(hit.content, hitIndex)}`"
:to="localePath(resolveHitLink(hit.content))"
v-for="hit in paginatedHits"
:key="`${hit.type}-${hit.id}`"
:to="localePath(resolveHitLink(hit))"
>
<el-card class="result-card">
<h3 class="result-title">{{ getHitTitle(hit.content) }}</h3>
<p v-if="getHitSummary(hit.content)" class="result-summary">
{{ getHitSummary(hit.content) }}
<h3 class="result-title">{{ hit.title }}</h3>
<p v-if="hit.summary" class="result-summary">
{{ hit.summary }}
</p>
<p v-if="hit.type" class="result-type">
<span>内容类型: </span>
@ -44,13 +44,8 @@
</template>
<script setup lang="ts">
interface HitItem {
content: SearchHit;
type: string;
}
const props = defineProps<{
hitItems: HitItem[];
searchItems: SearchItemView[];
currentPage: number;
category?: string;
}>();
@ -74,12 +69,12 @@
const pageSize = ref(5);
// 搜索相关
const hits = props.hitItems;
const items = props.searchItems;
const filteredHits = computed(() => {
if (props.category) {
return hits.filter((hit) => hit.type === props.category);
return items.filter((item) => item.type === props.category);
} else {
return hits;
return items;
}
});
const paginatedHits = computed(() => {
@ -106,64 +101,13 @@
return filteredHits.value.length > 0;
});
/**
* 获取搜索条目的唯一标识符
* 尝试根据搜索条目的相关词条获取唯一标识符
* 若未找到则fallback至给定的index
* @param hit 搜索条目
* @param index 条目索引
*/
const getHitIdentifier = (hit: SearchHit, index: number) => {
const candidate = [hit.objectID, hit.documentId, hit.id, hit.slug].find(
(value) =>
['string', 'number'].includes(typeof value) && String(value).length > 0
);
return candidate != null ? String(candidate) : String(index);
};
/**
* 获取搜索条目的标题
* @param hit 搜索条目
*/
const getHitTitle = (hit: SearchHit) => {
const candidate = [
hit.title,
hit.name,
hit.heading,
hit.documentTitle,
].find((value) => typeof value === 'string' && value.trim().length > 0);
return candidate ? String(candidate) : t('search.untitled');
};
/**
* 获取搜索条目的摘要
* @param hit 搜索条目
*/
const getHitSummary = (hit: SearchHit) => {
const candidate = [
hit.summary,
hit.description,
hit.snippet,
hit.content,
hit.text,
].find((value) => typeof value === 'string' && value.trim().length > 0);
return candidate ? String(candidate) : '';
};
/**
* 解析条目链接
* 根据条目类型返回正确的跳转链接
* @param hit 搜索条目
* @param item 搜索条目
*/
const resolveHitLink = (hit: SearchHit) => {
if (typeof hit.route === 'string' && hit.route.trim().length > 0) {
return localePath(hit.route);
}
const slugCandidate = [hit.slug, hit.documentId, hit.id, hit.objectID].find(
(value) =>
['string', 'number'].includes(typeof value) && String(value).length > 0
);
const resolveHitLink = (item: SearchItemView) => {
const slugCandidate = item.id;
if (!slugCandidate) {
return null;
@ -171,11 +115,11 @@
const slug = String(slugCandidate);
if (hit.indexUid === 'production') {
if (item.type === 'product') {
return localePath({ path: `/productions/${slug}` });
}
if (hit.indexUid === 'solution') {
if (item.type === 'solution') {
return localePath({ path: `/solutions/${slug}` });
}