# 下载跳转 URL 修复设计 ## 概述 当前访客端在触发下载型工具时,会沿用网页型工具的 `same_tab` 导航分支。若后台将下载工具配置为非新标签页,前端会直接执行 `window.location.assign(actionUrl)`,导致当前 SPA 页面 URL 被改写成下载地址,破坏返回和继续浏览体验。 本次修复目标是保证下载行为不会修改当前访客页的 URL。下载应在新标签页或浏览器新窗口中完成;当前页继续停留在工具列表页或详情页。 ## 目标定位 主要用户为访客端普通用户,在浏览工具列表或详情页时点击下载操作。 ## 约束条件 - 保持现有网页模式 `web` 的同标签/新标签配置能力不变。 - 保持已有下载埋点与下载票据逻辑不变。 - 变更范围尽量小,优先修复公开访客端入口,不扩展后台交互。 ## 成功标准 - 下载型工具触发后,当前页 URL 保持不变。 - 首页和详情页的下载按钮行为一致。 - 网页型工具仍按现有 `openIn` 配置运行。 - 新增自动化测试能覆盖下载模式不走当前页跳转。 ## 架构设计 - 后端 `AccessService.launchTool`: - 对下载模式统一返回 `openIn: 'new_tab'`。 - 包括外部下载地址和票据下载两种分支。 - 前端 `App.vue` 与 `ToolDetailPage.vue`: - 仅网页模式 `web + same_tab` 执行 `window.location.assign(...)`。 - 下载模式始终使用 `window.open(...)`,不再降级到当前页跳转。 - 若浏览器阻止弹窗,则提示用户允许新窗口,而不是改写当前页 URL。 ## 数据流 1. 用户点击下载按钮。 2. 前端调用 `/tools/:id/launch`。 3. 后端返回 `mode: download` 且 `openIn: new_tab`。 4. 前端使用 `window.open(actionUrl, '_blank', 'noopener,noreferrer')` 发起下载。 5. 当前 SPA 路由保持原状。 ## 错误处理 - 若 `actionUrl` 为空,维持现有错误提示。 - 若浏览器拦截新窗口,显示明确提示,不执行 `location.assign`。 ## 测试策略 - 前端单测覆盖首页下载按钮: - `download + same_tab` 输入场景下,断言不会调用 `window.location.assign`。 - 断言 `window.open` 被调用并保持当前路由不变。 - 前端单测覆盖详情页下载按钮: - 断言下载模式不会调用 `window.location.assign`。 - 服务端单测如已有 launch 行为覆盖,则补充下载模式 `openIn` 断言;若当前模块无单测,则至少保证前端回归测试覆盖核心用户路径。