版本管理,优化
This commit is contained in:
@@ -247,7 +247,8 @@ export const useAppStore = defineStore('app', () => {
|
||||
moduleId,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
keywords: item.keywords
|
||||
keywords: item.keywords,
|
||||
tab: item.tab
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,6 +28,27 @@ export const useModuleTabsStore = defineStore('moduleTabs', () => {
|
||||
/** 是否显示浮动切换器(TabsList 滚出可视区时为 true) */
|
||||
const floatingVisible = ref<boolean>(false)
|
||||
|
||||
/** 待跳转 tab(搜索导航设置):{ moduleId, tab },模块挂载/已挂载时消费 */
|
||||
const pendingTab = ref<{ moduleId: string; tab: string } | null>(null)
|
||||
|
||||
/** 设置待跳转 tab(搜索结果点击时调用) */
|
||||
const setPendingTab = (moduleId: string, tab: string) => {
|
||||
pendingTab.value = { moduleId, tab }
|
||||
}
|
||||
|
||||
/**
|
||||
* 消费指定模块的待跳转 tab(返回 tab 值并清除)。
|
||||
* 仅在 moduleId 匹配时消费,避免误切当前已挂载模块的 tab。
|
||||
*/
|
||||
const consumePendingTab = (moduleId: string): string | null => {
|
||||
if (pendingTab.value && pendingTab.value.moduleId === moduleId) {
|
||||
const tab = pendingTab.value.tab
|
||||
pendingTab.value = null
|
||||
return tab
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** 当前模块注册的保存处理函数(null 表示无保存按钮,如自动保存模块) */
|
||||
const saveHandler = ref<(() => unknown) | null>(null)
|
||||
/** 保存中状态(驱动按钮 disabled + loading 图标) */
|
||||
@@ -93,6 +114,7 @@ export const useModuleTabsStore = defineStore('moduleTabs', () => {
|
||||
tabs,
|
||||
activeTab,
|
||||
floatingVisible,
|
||||
pendingTab,
|
||||
saveHandler,
|
||||
saving,
|
||||
saveVisible,
|
||||
@@ -100,6 +122,8 @@ export const useModuleTabsStore = defineStore('moduleTabs', () => {
|
||||
unregisterTabs,
|
||||
setFloatingVisible,
|
||||
setActiveTab,
|
||||
setPendingTab,
|
||||
consumePendingTab,
|
||||
registerSave,
|
||||
runSave
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ export interface SearchIndexItem {
|
||||
title: string
|
||||
description?: string
|
||||
keywords: string[]
|
||||
/** 跳转目标:模块内部 tab(如 proxy 的 'settings'),无 tab 则只切换模块 */
|
||||
tab?: string
|
||||
}
|
||||
|
||||
export interface SearchIndexConfig {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { moduleRegistry } from '@/modules/registry'
|
||||
import { getTextForms, bestScore } from '@/modules/quickpanel/engine'
|
||||
|
||||
export interface SearchItem {
|
||||
id: string
|
||||
@@ -8,6 +9,8 @@ export interface SearchItem {
|
||||
title: string
|
||||
description?: string
|
||||
keywords: string[]
|
||||
/** 跳转目标:模块内部 tab(无则只切换模块) */
|
||||
tab?: string
|
||||
action?: () => void
|
||||
}
|
||||
|
||||
@@ -29,7 +32,8 @@ export const useSearchStore = defineStore('search', () => {
|
||||
moduleId,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
keywords: item.keywords
|
||||
keywords: item.keywords,
|
||||
tab: item.tab
|
||||
}
|
||||
if (!items.value.find(i => i.id === searchItem.id)) {
|
||||
items.value.push(searchItem)
|
||||
@@ -76,14 +80,21 @@ export const useSearchStore = defineStore('search', () => {
|
||||
|
||||
const search = (query: string) => {
|
||||
if (!query.trim()) return []
|
||||
const lowerQuery = query.toLowerCase()
|
||||
return items.value.filter(item => {
|
||||
const titleMatch = item.title.toLowerCase().includes(lowerQuery)
|
||||
const descMatch = item.description ? item.description.toLowerCase().includes(lowerQuery) : false
|
||||
const keywordMatch = item.keywords.some(k => k.toLowerCase().includes(lowerQuery))
|
||||
const moduleIdMatch = item.moduleId.toLowerCase().includes(lowerQuery)
|
||||
return titleMatch || descMatch || keywordMatch || moduleIdMatch
|
||||
})
|
||||
// 复用快速面板匹配引擎:标题/描述/关键词/模块名 多形态模糊匹配(支持拼音、子序列)
|
||||
const scored = items.value
|
||||
.map(item => {
|
||||
let score = Math.max(
|
||||
bestScore(query, getTextForms(item.title)),
|
||||
bestScore(query, getTextForms(item.description ?? '')),
|
||||
bestScore(query, getTextForms(item.keywords.join(' ')))
|
||||
)
|
||||
const moduleName = moduleRegistry.getConfig(item.moduleId)?.name ?? item.moduleId
|
||||
score = Math.max(score, bestScore(query, getTextForms(moduleName)) * 0.9)
|
||||
return { item, score }
|
||||
})
|
||||
.filter(e => e.score > 0)
|
||||
.sort((a, b) => b.score - a.score)
|
||||
return scored.map(e => e.item)
|
||||
}
|
||||
|
||||
const getItemsByModule = (moduleId: string) => {
|
||||
|
||||
Reference in New Issue
Block a user