性能优化
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Provider 注册与聚合搜索。
|
||||
* 并行调用各 Provider 合并结果、打分排序、应用去重。
|
||||
*/
|
||||
import type { QPItem, QPProvider } from './types'
|
||||
import { appRankFromPath } from './utils'
|
||||
import { HistoryProvider } from './history'
|
||||
import { CommandProvider } from './command'
|
||||
import { CustomCommandProvider } from './customCommand'
|
||||
import { AppProvider } from './app'
|
||||
import { FileProvider } from './file'
|
||||
import { ClipboardProvider } from './clipboard'
|
||||
import { CalcProvider } from './calc'
|
||||
import { UnitProvider } from './unit'
|
||||
import { SpecialProvider } from './special'
|
||||
import { SystemProvider } from './system'
|
||||
import { WebProvider } from './web'
|
||||
|
||||
let providers: QPProvider[] | null = null
|
||||
|
||||
export function getProviders(): QPProvider[] {
|
||||
if (!providers) {
|
||||
providers = [
|
||||
new HistoryProvider(),
|
||||
new CommandProvider(),
|
||||
new CustomCommandProvider(),
|
||||
new AppProvider(),
|
||||
new FileProvider(),
|
||||
new ClipboardProvider(),
|
||||
new CalcProvider(),
|
||||
new UnitProvider(),
|
||||
new SpecialProvider(),
|
||||
new SystemProvider(),
|
||||
new WebProvider(),
|
||||
]
|
||||
}
|
||||
return providers
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚合搜索:并行调用各 Provider,合并结果,按 score 降序排序。
|
||||
* 空查询时返回 command Provider 的快捷入口 + system Provider 的固定项。
|
||||
*/
|
||||
export async function aggregateSearch(query: string): Promise<QPItem[]> {
|
||||
const all = getProviders()
|
||||
const results = await Promise.all(all.map(p => Promise.resolve(p.search(query))))
|
||||
const merged: QPItem[] = []
|
||||
results.forEach((items, idx) => {
|
||||
items.forEach(item => {
|
||||
// 未打分的项赋予基础分(按 provider 优先级递减)
|
||||
if (item.score === undefined) {
|
||||
item.score = (10 - idx) * 0.01
|
||||
}
|
||||
merged.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
// 去重:所有来源的「应用」(含文件索引中的 .lnk)按名称归并,保留可靠性最高的来源
|
||||
// 可靠性:开始菜单(appRank 0) > 桌面(1) > 其他位置(2);同可靠性时保留分数更高的
|
||||
// (如 "TRAE Work CN" 在开始菜单 + 桌面 + 某索引目录都有 .lnk,只留开始菜单那条)
|
||||
const appKey = (title: string): string => {
|
||||
let t = title.trim().toLowerCase()
|
||||
if (t.endsWith('.lnk')) t = t.slice(0, -4).trim()
|
||||
return t
|
||||
}
|
||||
// 应用候选:应用分组,以及文件分组中的 .lnk 快捷方式
|
||||
const isAppLike = (item: QPItem): boolean => {
|
||||
if (item.group === '应用') return true
|
||||
if (item.group === '文件' && item.title && item.title.toLowerCase().endsWith('.lnk')) return true
|
||||
return false
|
||||
}
|
||||
const bestAppByKey = new Map<string, QPItem>()
|
||||
for (const item of merged) {
|
||||
if (!isAppLike(item) || !item.title) continue
|
||||
const key = appKey(item.title)
|
||||
const prev = bestAppByKey.get(key)
|
||||
if (!prev) {
|
||||
bestAppByKey.set(key, item)
|
||||
continue
|
||||
}
|
||||
// 比较可靠性:appRank 越小越可靠;文件分组 .lnk 无 appRank 时按路径推断
|
||||
const rankOf = (i: QPItem): number => {
|
||||
if (i.appRank !== undefined) return i.appRank
|
||||
if (i.group === '文件') return appRankFromPath(i.subtitle ?? '')
|
||||
return 2
|
||||
}
|
||||
const rankA = rankOf(item)
|
||||
const rankB = rankOf(prev)
|
||||
if (rankA < rankB || (rankA === rankB && (item.score ?? 0) > (prev.score ?? 0))) {
|
||||
bestAppByKey.set(key, item)
|
||||
}
|
||||
}
|
||||
const keptAppIds = new Set(Array.from(bestAppByKey.values()).map(i => i.id))
|
||||
const deduped = merged.filter(item => {
|
||||
if (!isAppLike(item)) return true
|
||||
return keptAppIds.has(item.id)
|
||||
})
|
||||
|
||||
deduped.sort((a, b) => (b.score ?? 0) - (a.score ?? 0))
|
||||
return deduped
|
||||
}
|
||||
Reference in New Issue
Block a user