import { MeiliSearch } from 'meilisearch'; import type { SearchParams } from 'meilisearch'; 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()}${suffix}`).filter(Boolean); } return indexes .split(',') .map((item) => `${item.trim()}${suffix}`) .filter(Boolean); }; export const useMeilisearch = () => { const runtimeConfig = useRuntimeConfig(); const indexes = computed(() => parseIndexes(runtimeConfig.public?.meili?.indexes) ); let meiliClient: MeiliSearch | null = null; const ensureClient = () => { if (meiliClient) return meiliClient; const host = runtimeConfig.public?.meili?.host; if (!host) { console.warn('Meilisearch host is not configured.'); return null; } const apiKey = runtimeConfig.public?.meili?.searchKey; meiliClient = new MeiliSearch({ host, apiKey: apiKey || undefined, }); return meiliClient; }; /** * 泛型搜索函数 * @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 = {}, searchLocale?: string ): Promise[]> { const trimmedQuery = query.trim(); if (!trimmedQuery) { return []; } const client = ensureClient(); if (!client) { return []; } 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}` : '') ); console.log(indexesWithLocale); const requests = indexesWithLocale.map(async (indexUid) => { const response = await client.index(indexUid).search(trimmedQuery, { limit: params.limit ?? 10, ...params, }); return { indexUid, response, } satisfies RawSearchSection; }); const settled = await Promise.allSettled(requests); console.log('Meilisearch settled results:', settled); settled .filter( (result): result is PromiseRejectedResult => result.status === 'rejected' ) .forEach((result) => { console.error('Meilisearch query failed', result.reason); }); return settled .filter( (result): result is PromiseFulfilledResult> => result.status === 'fulfilled' ) .map((result) => { const { indexUid, response } = result.value; return { indexUid: indexUid, rawIndex: rawIndexMap[indexUid], hits: response.hits, estimatedTotalHits: response.estimatedTotalHits ?? response.hits.length, processingTimeMs: response.processingTimeMs ?? 0, }; }); } return { search, indexes, }; };