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

@ -87,5 +87,10 @@ export const useLocalizations = () => {
* @returns 语言映射对象
*/
getLocaleMapping: getMapping,
/** 所有可用的Directus语言代码列表(只读) **/
availableDirectusLocales: readonly(
Object.values(localeMap).map((item) => item.directus)
),
};
};

View File

@ -1,33 +1,25 @@
import { MeiliSearch } from 'meilisearch';
import type { SearchParams, SearchResponse } from 'meilisearch';
import type { SearchParams } from 'meilisearch';
interface RawSearchSection {
indexUid: string;
response: SearchResponse<Record<string, unknown>>;
}
export interface SearchHit extends Record<string, unknown> {
indexUid: string;
objectID?: string | number;
}
export interface SearchSection {
indexUid: string;
hits: SearchHit[];
estimatedTotalHits: number;
processingTimeMs: number;
}
const parseIndexes = (indexes: string | string[] | undefined): string[] => {
const parseIndexes = (
indexes: string | string[] | undefined,
locale?: string
): string[] => {
if (!indexes) {
return [];
}
let suffix = '';
if (locale) {
suffix = `_${locale}`;
}
if (Array.isArray(indexes)) {
return indexes.map((item) => item.trim()).filter(Boolean);
return indexes.map((item) => `${item.trim()}${suffix}`).filter(Boolean);
}
return indexes
.split(',')
.map((item) => item.trim())
.map((item) => `${item.trim()}${suffix}`)
.filter(Boolean);
};
@ -56,10 +48,22 @@ export const useMeilisearch = () => {
return meiliClient;
};
const search = async (
/**
* 泛型搜索函数
* @template T 文档类型, 如 MeiliProductIndex
* ---
* @param query 搜索关键词
* @param params 其他搜索参数
* @returns 搜索结果数组
*/
async function search<
K extends MeiliSearchItemType = MeiliSearchItemType,
T extends MeiliIndexMap[K] = MeiliIndexMap[K],
>(
query: string,
params: SearchParams = {}
): Promise<SearchSection[]> => {
params: SearchParams = {},
searchLocale?: string
): Promise<SearchSection<T>[]> {
const trimmedQuery = query.trim();
if (!trimmedQuery) {
return [];
@ -70,34 +74,35 @@ export const useMeilisearch = () => {
return [];
}
const activeIndexes = indexes.value;
const activeIndexes = indexes.value as K[];
if (!activeIndexes.length) {
console.warn('No Meilisearch indexes configured.');
return [];
}
const rawIndexMap = Object.fromEntries(
activeIndexes.map((index) => [`${index}_${searchLocale}`, index])
);
const indexesWithLocale = activeIndexes.map(
(index) => index + (searchLocale ? `_${searchLocale}` : '')
);
const requests = activeIndexes.map(async (indexUid) => {
const response = await client.index(indexUid).search(trimmedQuery, {
console.log(indexesWithLocale);
const requests = indexesWithLocale.map(async (indexUid) => {
const response = await client.index(indexUid).search<T>(trimmedQuery, {
limit: params.limit ?? 10,
...params,
});
const safeResponse = JSON.parse(JSON.stringify(response));
return {
indexUid,
response: {
hits: safeResponse.hits,
estimatedTotalHits:
safeResponse.estimatedTotalHits ?? safeResponse.hits.length,
processingTimeMs: safeResponse.processingTimeMs ?? 0,
query: safeResponse.query,
},
} satisfies RawSearchSection;
response,
} satisfies RawSearchSection<T>;
});
console.log((await requests[0])?.response.hits[0]?.locale);
const settled = await Promise.allSettled(requests);
console.log('Meilisearch settled results:', settled);
settled
.filter(
(result): result is PromiseRejectedResult =>
@ -108,22 +113,22 @@ export const useMeilisearch = () => {
});
return settled
.filter((result) => result.status === 'fulfilled')
.filter(
(result): result is PromiseFulfilledResult<RawSearchSection<T>> =>
result.status === 'fulfilled'
)
.map((result) => {
const fulfilled = result as PromiseFulfilledResult<RawSearchSection>;
const { indexUid, response } = result.value;
return {
indexUid: fulfilled.value.indexUid,
hits: fulfilled.value.response.hits.map((hit) => ({
...hit,
indexUid: fulfilled.value.indexUid,
})),
indexUid: indexUid,
rawIndex: rawIndexMap[indexUid],
hits: response.hits,
estimatedTotalHits:
fulfilled.value.response.estimatedTotalHits ??
fulfilled.value.response.hits.length,
processingTimeMs: fulfilled.value.response.processingTimeMs ?? 0,
response.estimatedTotalHits ?? response.hits.length,
processingTimeMs: response.processingTimeMs ?? 0,
};
});
};
}
return {
search,