feat(agent-sidebar): 独立问答智能体列表栏顶部增加智能体名称模糊搜索
下拉来源切换下面加搜索框:防抖 300ms 走服务端 search(按原始名 + 内置缩写 脱敏映射匹配,与智能体管理页一致),在当前来源(我的/某广场)内搜全量; 带清除按钮、无结果显示「未找到匹配的智能体」、搜索中复用 isFetching 半透明指示。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
0bd4524334
commit
13ef1942f2
1 file changed
+36
-4
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { Bot, Loader2 } from "lucide-react";
|
||||
import { Bot, Loader2, Search, X } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { agentColor } from "@/components/workspace/agent-icon-color";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -52,6 +53,15 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string })
|
||||
// 作用域:MINE_SCOPE 或某个广场 id。默认「我的」。
|
||||
const [scope, setScope] = useState<string>(MINE_SCOPE);
|
||||
|
||||
// 模糊搜索智能体名称:防抖 300ms 后走服务端 search(后端按原始名 / 脱敏名匹配),
|
||||
// 在当前来源(我的 / 某广场)内过滤,能搜全量而非仅当前 50 条。
|
||||
const [searchInput, setSearchInput] = useState("");
|
||||
const [search, setSearch] = useState("");
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => setSearch(searchInput.trim()), 300);
|
||||
return () => clearTimeout(timer);
|
||||
}, [searchInput]);
|
||||
|
||||
// 若所选广场被管理员删除,回退到「我的」,避免指向不存在的广场。
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -70,13 +80,14 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string })
|
||||
page: 1,
|
||||
pageSize: LIST_PAGE_SIZE,
|
||||
square: isMine ? undefined : scope,
|
||||
search: search || undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
// 配色与 AgentModuleSidebar 一致:浅色白底,深蓝主题半透明深蓝玻璃面板。
|
||||
<aside className="flex h-full w-(--sidebar-width) shrink-0 flex-col overflow-hidden border-r border-border/70 bg-white text-foreground backdrop-blur-md dark:border-[#2b8ffe]/45 dark:bg-[#032650]/80">
|
||||
{/* 顶部:作用域下拉(我的 / 各广场) */}
|
||||
<div className="shrink-0 border-b border-border/60 px-3 py-2.5">
|
||||
{/* 顶部:作用域下拉(我的 / 各广场)+ 智能体名称模糊搜索 */}
|
||||
<div className="shrink-0 space-y-2 border-b border-border/60 px-3 py-2.5">
|
||||
<Select value={scope} onValueChange={setScope}>
|
||||
<SelectTrigger className="h-9 w-full text-sm" title="切换智能体来源">
|
||||
<SelectValue />
|
||||
@@ -90,6 +101,27 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string })
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="relative">
|
||||
<Search className="text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2" />
|
||||
<Input
|
||||
value={searchInput}
|
||||
onChange={(e) => setSearchInput(e.target.value)}
|
||||
placeholder="搜索智能体名称"
|
||||
className="h-9 pl-8 pr-8 text-sm"
|
||||
aria-label="搜索智能体名称"
|
||||
/>
|
||||
{searchInput && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSearchInput("")}
|
||||
className="text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2"
|
||||
title="清除"
|
||||
aria-label="清除搜索"
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 智能体列表 */}
|
||||
@@ -101,7 +133,7 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string })
|
||||
</div>
|
||||
) : agents.length === 0 ? (
|
||||
<p className="px-3 py-1.5 text-xs text-muted-foreground/70">
|
||||
{isMine ? "暂无智能体" : "该广场暂无智能体"}
|
||||
{search ? "未找到匹配的智能体" : isMine ? "暂无智能体" : "该广场暂无智能体"}
|
||||
</p>
|
||||
) : (
|
||||
<div
|
||||
|
||||
Reference in new issue
Block a user