From 45ebef4a88bdb5142f4778daa44e943fab283944 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 28 Sep 2026 13:45:47 +0800 Subject: [PATCH] fix(web): settings deep links use section hash; agent report links to download detail settingsPath() now builds /console/settings#section[/anchor] directly. Smoke covers the old ?tab= redirects and every settings section hash (hash-only URLs load from about:blank first). Agent report download links go to /console/downloads/:id without the /tasks 404 probe. Co-Authored-By: Claude Opus 5.5 --- .../components/agent/agent-conversation.tsx | 2 +- apps/web/app/components/console/nav.test.ts | 4 ++-- apps/web/app/components/console/nav.ts | 18 ++------------ apps/web/scripts/smoke.mjs | 24 +++++++++++++++++-- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/apps/web/app/components/agent/agent-conversation.tsx b/apps/web/app/components/agent/agent-conversation.tsx index c2936383..86ca9bd3 100644 --- a/apps/web/app/components/agent/agent-conversation.tsx +++ b/apps/web/app/components/agent/agent-conversation.tsx @@ -710,7 +710,7 @@ export function FinalReport({ title: d.name ?? `下载任务 ${d.downloadTaskId.slice(0, 8)}`, domain: "下载任务", meta: {d.status}, - to: `/console/tasks/${d.downloadTaskId}`, + to: `/console/downloads/${d.downloadTaskId}`, })), ...report.organization.map((o) => ({ id: `o${o.recordId}`, diff --git a/apps/web/app/components/console/nav.test.ts b/apps/web/app/components/console/nav.test.ts index 8294545e..0b3bc848 100644 --- a/apps/web/app/components/console/nav.test.ts +++ b/apps/web/app/components/console/nav.test.ts @@ -49,8 +49,8 @@ describe("控制台导航", () => { }); it("settingsPath 只认新分区名", () => { - expect(settingsPath("automation", "cache").startsWith("/console/settings")).toBe(true); - expect(settingsPath("agent").startsWith("/console/settings")).toBe(true); + expect(settingsPath("automation", "cache")).toBe("/console/settings#automation/cache"); + expect(settingsPath("agent")).toBe("/console/settings#agent"); }); }); diff --git a/apps/web/app/components/console/nav.ts b/apps/web/app/components/console/nav.ts index 830125e1..f98c0329 100644 --- a/apps/web/app/components/console/nav.ts +++ b/apps/web/app/components/console/nav.ts @@ -194,10 +194,7 @@ export const NAV_GROUPS: NavGroup[] = [ export const NAV_ITEMS = NAV_GROUPS.flatMap((g) => g.items); -/** - * 设置页深链。IA-2 把设置改为 /console/settings/:section 之前,先落到现有 ?tab=; - * 调用方只认新分区名,切换时只改这里。 - */ +/** 设置页深链(IA-2):`/console/settings#分区[/节]`。调用方只认新分区名 */ export type SettingsSection = | "automation" | "sites" @@ -208,19 +205,8 @@ export type SettingsSection = | "agent" | "api-keys" | "account"; -const SETTINGS_LEGACY_TAB: Partial> = { - automation: "automation", - sites: "site-credentials", - downloaders: "downloaders", - library: "library-roots", - "media-servers": "media-servers", - agent: "pi", - "api-keys": "api-keys", -}; export function settingsPath(section: SettingsSection, anchor?: string): string { - // 缓存阈值现在在"缓存与入库"页签,IA-2 后归到 automation#cache - const tab = section === "automation" && anchor === "cache" ? "storage" : SETTINGS_LEGACY_TAB[section]; - return tab ? `${CONSOLE_BASE}/settings?tab=${tab}` : `${CONSOLE_BASE}/settings`; + return `${CONSOLE_BASE}/settings#${section}${anchor ? `/${anchor}` : ""}`; } /** 按路径找当前导航项(最长前缀匹配) */ diff --git a/apps/web/scripts/smoke.mjs b/apps/web/scripts/smoke.mjs index 389a47ed..244bac3c 100644 --- a/apps/web/scripts/smoke.mjs +++ b/apps/web/scripts/smoke.mjs @@ -44,6 +44,15 @@ const STATIC_ROUTES = [ "/console/schedules", "/console/settings", "/console/settings?tab=pi", + // 设置各分区(hash 定位,IA-2) + "/console/settings#sites", + "/console/settings#downloaders", + "/console/settings#library", + "/console/settings#media-servers", + "/console/settings#metadata", + "/console/settings#agent", + "/console/settings#api-keys", + "/console/settings#account", ]; const DETAIL_ROUTES = [ @@ -72,6 +81,11 @@ const REDIRECT_ROUTES = [ { from: "/console/sources?tab=snapshots&siteId=:id", to: "/console/sites/:id?tab=snapshots", list: "/api/v1/sites" }, // 旧的下载详情地址:先查业务任务(404 属预期),再跳到下载详情 { from: "/console/tasks/:id", to: "/console/downloads/:id", list: "/api/v1/download-tasks", expect404: true }, + // 设置旧页签 ?tab= → 分区 hash(IA-2) + { from: "/console/settings?tab=pi", to: "/console/settings#agent" }, + { from: "/console/settings?tab=storage", to: "/console/settings#automation/cache" }, + { from: "/console/settings?tab=path-mappings", to: "/console/settings#downloaders" }, + { from: "/console/settings?tab=site-credentials", to: "/console/settings#sites" }, ]; /** 允许的控制台噪音(React Router 开发模式提示等,不算错误) */ @@ -154,6 +168,8 @@ async function main() { const t0 = Date.now(); let status = 0; try { + // 只差 hash 的地址是同文档跳转(没有响应);先离开,保证整页加载 + if (path.includes("#")) await page.goto("about:blank"); const res = await page.goto(`${BASE}${path}`, { waitUntil: "networkidle", timeout: 30_000 }); status = res?.status() ?? 0; // SPA 外壳已渲染(主内容区出现),不是登录页 / 404 页 @@ -190,11 +206,15 @@ async function main() { try { const res = await page.goto(`${BASE}${from}`, { waitUntil: "networkidle", timeout: 30_000 }); status = res?.status() ?? 0; - await page.waitForURL((u) => `${u.pathname}${u.search}` === to, { timeout: 10_000 }); + await page.waitForURL((u) => `${u.pathname}${u.search}${to.includes("#") ? u.hash : ""}` === to, { + timeout: 10_000, + }); await page.waitForSelector("main", { timeout: 10_000 }); } catch (err) { const u = new URL(page.url()); - problems.push(`没有跳到 ${to}(停在 ${u.pathname}${u.search}):${String(err?.message ?? err).split("\n")[0]}`); + problems.push( + `没有跳到 ${to}(停在 ${u.pathname}${u.search}${u.hash}):${String(err?.message ?? err).split("\n")[0]}`, + ); } if (status !== 200) problems.push(`HTTP ${status}`); // 旧下载详情先探测业务任务,那次 404 与浏览器随之打印的资源错误是预期内的