diff --git a/frontend-web/src/pages/SkillAddressesPage.tsx b/frontend-web/src/pages/SkillAddressesPage.tsx index 4fefa80e..3fa96662 100644 --- a/frontend-web/src/pages/SkillAddressesPage.tsx +++ b/frontend-web/src/pages/SkillAddressesPage.tsx @@ -17,6 +17,7 @@ import { Search, Undo2, Wand2, + X, } from "lucide-react"; import { toast } from "sonner"; @@ -231,11 +232,19 @@ export function SkillAddressesPanel() { } }; - const q = query.trim().toLowerCase(); - const visible = useMemo( - () => (!q ? groups : groups.filter((g) => g.address.toLowerCase().includes(q) || g.occurrences.some((o) => o.skill.toLowerCase().includes(q)))), - [groups, q], + // 多关键词检索:空格分隔,每个关键词都要命中(地址或技能名任一包含)才显示。 + // 这样「uat 4.cn」能同时收窄到既含 uat 又含 4.cn 的地址,应对地址过多的场景。 + const tokens = useMemo( + () => query.trim().toLowerCase().split(/\s+/).filter(Boolean), + [query], ); + const visible = useMemo(() => { + if (tokens.length === 0) return groups; + return groups.filter((g) => { + const haystack = `${g.address} ${g.occurrences.map((o) => o.skill).join(" ")}`.toLowerCase(); + return tokens.every((t) => haystack.includes(t)); + }); + }, [groups, tokens]); const totalOccurrences = useMemo(() => groups.reduce((s, g) => s + g.count, 0), [groups]); const canRollback = !!(lastBackupId || backups.length > 0); @@ -332,15 +341,25 @@ export function SkillAddressesPanel() { ))} -