fix: 修复发现返回导航(#34)与情报内容搜索及查看对话(#38)

- #34: 任务发现页进入漏洞报告详情后,「←返回」回到该任务的发现页
  (/function/tasks/detail?id=<task>&tab=findings),而非全局发现列表。
  任务自身的 FindingCaseList 与原始上报列表「详情」链接均携带 context_task。
- #38: 情报搜索除标题/上报者外,同时匹配内容(content)与来源证据(evidence)。
- #38: 修复「查看对话」点击无反应:任务详情页标签切换同步写入 URL 的 tab 参数,
  使跳转 tab=sessions&session=... 时能正确切换到会话并打开对应会话。

Closes #34
Closes #38
This commit is contained in:
RuoJi6 committed 2026-10-23 18:09:55 +08:00
1 parent 620ca5d96c
commit 0a327328f3
5 files changed
+20 -13

No files matched your search

+2 -2
View File
@@ -260,8 +260,8 @@ func (d *DB) ListIntelligence(ctx context.Context, f IntelligenceFilter) (*Intel
if err != nil {
return nil, err
}
// Search titles and reporters; return the recorded content directly in each row.
where := scope + ` AND ($3='' OR kind=$3) AND ($4='' OR i.status=$4) AND ($5='' OR i.title ILIKE '%'||$5||'%' OR i.worker ILIKE '%'||$5||'%')`
// Search titles, content, evidence, and reporters; return the recorded content directly in each row.
where := scope + ` AND ($3='' OR kind=$3) AND ($4='' OR i.status=$4) AND ($5='' OR i.title ILIKE '%'||$5||'%' OR i.content ILIKE '%'||$5||'%' OR i.evidence ILIKE '%'||$5||'%' OR i.worker ILIKE '%'||$5||'%')`
args = append(args, f.Kind, f.Status, f.Query)
if err = d.QueryRowContext(ctx, `SELECT count(*)`+where, args...).Scan(&page.Total); err != nil {
return nil, err
@@ -58,6 +58,7 @@ function FindingDetailInner() {
const searchParams = useSearchParams();
const id = searchParams.get("id") ?? "";
const contextTaskId = searchParams.get("context_task") ?? "";
const backHref = contextTaskId ? `/function/tasks/detail?id=${contextTaskId}&tab=findings` : "/function/findings";
const [finding, setFinding] = React.useState<Finding | null>(null);
const [loaded, setLoaded] = React.useState(false);
const [tab, setTab] = React.useState("overview");
@@ -117,7 +118,7 @@ function FindingDetailInner() {
<p className="text-muted-foreground">{loaded ? `未找到发现 ${id}` : "加载中…"}</p>
{loaded && (
<Button asChild variant="outline">
<Link href="/function/findings">
<Link href={backHref}>
<ArrowLeftIcon /> 返回发现列表
</Link>
</Button>
@@ -135,7 +136,7 @@ function FindingDetailInner() {
<div className="flex flex-wrap items-center gap-2">
<SidebarTrigger className="-ml-1" />
<Button asChild variant="ghost" size="icon" className="size-7">
<Link href="/function/findings">
<Link href={backHref}>
<ArrowLeftIcon />
</Link>
</Button>
@@ -113,11 +113,7 @@ function Row({
</span>
{f.finding_id && (
<Link
href={
f.inherited
? `/function/findings/detail?id=${f.finding_id}&context_task=${contextTaskId}`
: `/function/findings/detail?id=${f.finding_id}`
}
href={`/function/findings/detail?id=${f.finding_id}&context_task=${contextTaskId}`}
className="text-muted-foreground hover:text-primary inline-flex shrink-0 items-center gap-0.5 text-xs"
title="查看漏洞详情"
>
@@ -190,7 +186,7 @@ export function FindingsTab({ taskId }: { taskId: string }) {
return (
<div className="flex flex-col gap-4">
<FindingCaseList query={{ task: taskId, sort: "time" }} />
<FindingCaseList query={{ task: taskId, sort: "time" }} contextTask={taskId} />
{[
...new Set(
items
@@ -354,7 +354,17 @@ function TaskDetailInner() {
);
return (
<Tabs value={tab} onValueChange={setTab} className="flex flex-1 flex-col gap-0">
<Tabs
value={tab}
onValueChange={(value) => {
setTab(value);
const params = new URLSearchParams(searchParams.toString());
params.set("tab", value);
params.delete("session");
router.replace(`/function/tasks/detail?${params.toString()}`, { scroll: false });
}}
className="flex flex-1 flex-col gap-0"
>
{/* Top fixed area */}
<header className="sticky top-0 z-10 flex flex-col gap-2 border-b bg-background/95 px-4 py-2.5 backdrop-blur lg:px-6">
<div className="flex items-center gap-2">
+2 -2
View File
@@ -193,8 +193,8 @@ export function IntelligencePanel({
</Tabs>
<div className="flex flex-wrap items-center gap-2">
<Input
aria-label="搜索情报标题或上报者"
placeholder="搜索标题或上报者"
aria-label="搜索情报标题、内容或上报者"
placeholder="搜索标题、内容或上报者"
value={search}
maxLength={200}
onChange={(e) => setSearch(e.target.value)}