Files
tools-show/design/plans/2026-04-11-tool-manual-detail-page-plan.md
2026-04-11 20:46:55 +08:00

12 KiB
Raw Blame History

用户手册详情页实施计划

目标:将访客端原有详情弹窗替换为基于 slug 的独立详情页,使 description 可以长期作为 Markdown 用户手册展示并补齐直达访问、空内容、404 和长文阅读体验。

架构:本次为单一功能子系统改造,不创建纲领文件。后端先补齐按 slug 查询已发布工具的公开详情能力,再由前端新增公开详情页路由和页面组件,最后替换首页详情入口并完善长文阅读样式与测试。前端测试基建当前缺失,因此计划第一步先补齐 Vitest + Vue Test Utils + jsdom,确保后续页面改造遵循测试优先。

技术栈Vue 3、vue-router、Vite、Vitest、Vue Test Utils、NestJS、Prisma、Jest、Supertest、marked、DOMPurify


文件结构

新建文件

  • client/vitest.config.js - 前端测试配置,提供 Vue SFC 和 jsdom 运行环境
    注释需求:低优先级,配置项仅在非直观处补简短说明
    复杂度:低

  • client/src/test/setup.js - 前端测试初始化,挂载全局匹配器、滚动和路由相关基础 mock
    注释需求:中优先级,需要说明全局 mock 的用途
    复杂度:中

  • client/src/utils/markdown-outline.js - 提取 Markdown 标题、生成稳定锚点和目录结构
    注释需求:高优先级,需要为重复标题去重和锚点规范化逻辑添加说明
    复杂度:中

  • client/src/utils/markdown-outline.spec.js - 验证目录提取、标题去重和无标题场景
    注释需求:低优先级
    复杂度:中

  • client/src/pages/ToolDetailPage.vue - 公开详情页,负责按 slug 拉取详情、渲染摘要和 Markdown 手册、处理空状态/404/返回入口
    注释需求:高优先级,需要在状态流转和 launch 复用入口处补说明
    复杂度:高

  • client/src/pages/ToolDetailPage.spec.js - 详情页组件测试覆盖加载态、404、空内容、目录和主操作按钮
    注释需求:低优先级
    复杂度:高

  • client/src/App.spec.js - 首页交互测试,覆盖详情按钮跳转和旧弹窗移除
    注释需求:低优先级
    复杂度:中

  • server/src/modules/tools/tools.service.spec.ts - 后端服务单测,覆盖按 slug 查询详情的业务规则
    注释需求:低优先级
    复杂度:中

  • server/test/tools-detail.e2e-spec.ts - 公开详情接口 e2e覆盖成功命中和 404
    注释需求:中优先级,需要说明测试数据准备和清理
    复杂度:中

修改文件

  • client/package.json - 增加前端测试脚本和测试依赖声明
    注释需求:低优先级
    复杂度:低

  • client/package-lock.json - 锁定前端测试依赖版本
    注释需求:无
    复杂度:低

  • client/src/api.js - 新增按 slug 获取详情的方法,复用现有错误和 launch 行为
    注释需求:中优先级,需要说明新接口和旧按 id 接口的职责差异
    复杂度:中

  • client/src/admin/router.js - 增加公开详情页路由 /tools/:slug
    注释需求:低优先级
    复杂度:低

  • client/src/App.vue - 移除详情弹窗状态和模板,将详情入口改为路由跳转
    注释需求:中优先级,需要说明首页仅负责列表和跳转,不再持有详情状态
    复杂度:高

  • client/src/style.scss - 增加详情页布局、目录、空状态、404 和长文阅读样式
    注释需求:低优先级
    复杂度:高

  • client/src/admin/components/ToolFormDialog.vue - 微调“工具简介”提示文案,明确其可承载 Markdown 手册内容
    注释需求:低优先级
    复杂度:低

  • server/src/modules/tools/tools.service.ts - 抽出详情映射逻辑,新增按 slug 查询已发布工具详情的方法
    注释需求:高优先级,需要说明 idslug 两套公开查询入口的职责分层
    复杂度:中

  • server/src/modules/tools/tools.controller.ts - 新增按 slug 获取公开详情的接口
    注释需求:低优先级
    复杂度:低

测试文件

  • client/src/utils/markdown-outline.spec.js - 验证 Markdown 目录提取和锚点生成规则
  • client/src/pages/ToolDetailPage.spec.js - 验证详情页数据状态和长文阅读体验
  • client/src/App.spec.js - 验证首页详情入口从弹窗切为路由跳转
  • server/src/modules/tools/tools.service.spec.ts - 验证按 slug 查询的业务规则
  • server/test/tools-detail.e2e-spec.ts - 验证公开详情接口路由行为

任务列表

任务 1建立前端测试基建和 Markdown 目录工具

文件

  • 创建:client/vitest.config.js

  • 创建:client/src/test/setup.js

  • 创建:client/src/utils/markdown-outline.js

  • 测试:client/src/utils/markdown-outline.spec.js

  • 修改:client/package.json

  • 修改:client/package-lock.json

  • 步骤 1:在 client/package.json 中增加 testtest:run 脚本和 vitest@vue/test-utilsjsdom 等依赖声明;创建 client/vitest.config.jsclient/src/test/setup.js;编写 client/src/utils/markdown-outline.spec.js,先描述标题提取、重复标题去重、无标题返回空目录的失败用例。

  • 步骤 2:运行 npm --prefix client install;随后运行 npm --prefix client run test:run -- client/src/utils/markdown-outline.spec.js,预期输出为测试失败,原因是 markdown-outline.js 尚未实现或断言不满足。

  • 步骤 3:创建 client/src/utils/markdown-outline.js,实现 extractMarkdownOutline 和稳定锚点生成逻辑,保证只提取正文标题并对重复标题追加序号。

  • 步骤 4:再次运行 npm --prefix client run test:run -- client/src/utils/markdown-outline.spec.js,预期输出 1 passed,前端测试基建可用。

任务 2实现后端按 slug 查询详情的服务层能力

文件

  • 创建:server/src/modules/tools/tools.service.spec.ts

  • 修改:server/src/modules/tools/tools.service.ts

  • 步骤 1:编写 server/src/modules/tools/tools.service.spec.ts,覆盖已发布工具可按 slug 查询、未发布工具不可见、缺失工具抛出 404、详情映射字段与现有按 id 详情保持一致的失败测试。

  • 步骤 2:运行 npm --prefix server test -- --runTestsByPath src/modules/tools/tools.service.spec.ts,预期输出为编译失败或测试失败,因为 getToolDetailBySlug 及共享映射尚未存在。

  • 步骤 3:在 server/src/modules/tools/tools.service.ts 中抽出详情映射方法,新增 getToolDetailBySlug(slug: string),查询条件限定为 status=publishedisDeleted=false,并复用现有详情返回结构。

  • 步骤 4:再次运行 npm --prefix server test -- --runTestsByPath src/modules/tools/tools.service.spec.ts,预期输出 Test Suites: 1 passed

任务 3补齐公开详情 slug 接口和后端 e2e

文件

  • 创建:server/test/tools-detail.e2e-spec.ts

  • 修改:server/src/modules/tools/tools.controller.ts

  • 步骤 1:编写 server/test/tools-detail.e2e-spec.ts,准备一条已发布工具测试数据,定义 GET /tools/slug/:slug 成功返回详情和未知 slug 返回 404 的失败测试。

  • 步骤 2:运行 npm --prefix server run test:e2e -- --runTestsByPath test/tools-detail.e2e-spec.ts,预期输出为 404 或断言失败,因为控制器路由尚未暴露该接口。

  • 步骤 3:在 server/src/modules/tools/tools.controller.ts 中新增 GET /tools/slug/:slug 路由,调用 toolsService.getToolDetailBySlug;按需要调整 e2e 中的测试数据清理,避免污染现有数据。

  • 步骤 4:再次运行 npm --prefix server run test:e2e -- --runTestsByPath test/tools-detail.e2e-spec.ts,预期输出 1 passed2 passed,接口直达行为稳定。

任务 4新增公开详情页路由、API 接入和页面状态

文件

  • 创建:client/src/pages/ToolDetailPage.vue

  • 测试:client/src/pages/ToolDetailPage.spec.js

  • 修改:client/src/api.js

  • 修改:client/src/admin/router.js

  • 步骤 1:编写 client/src/pages/ToolDetailPage.spec.js,覆盖按路由 slug 拉取详情、加载态、404 提示、空内容提示、返回首页入口以及主操作按钮展示的失败测试。

  • 步骤 2:运行 npm --prefix client run test:run -- client/src/pages/ToolDetailPage.spec.js,预期输出为模块不存在或多个断言失败,因为详情页组件、路由和新 API 方法尚未实现。

  • 步骤 3:在 client/src/api.js 中新增 fetchToolDetailBySlug(slug);在 client/src/admin/router.js 中增加公开路由 /tools/:slug;创建 client/src/pages/ToolDetailPage.vue,完成按 slug 加载数据、页面级加载/错误/404/空内容状态和返回入口,并复用现有 launch 行为。

  • 步骤 4:再次运行 npm --prefix client run test:run -- client/src/pages/ToolDetailPage.spec.js,预期输出 1 passed,详情页基础行为成立。

任务 5替换首页详情弹窗为路由跳转

文件

  • 创建:client/src/App.spec.js

  • 修改:client/src/App.vue

  • 步骤 1:编写 client/src/App.spec.js,覆盖“详情”按钮改为跳转到 /tools/:slug、旧详情弹窗 DOM 不再渲染、首页仍保留概览弹窗的失败测试。

  • 步骤 2:运行 npm --prefix client run test:run -- client/src/App.spec.js,预期输出为断言失败,因为首页仍然保留 openDetailModal 流程和旧弹窗模板。

  • 步骤 3:修改 client/src/App.vue,移除 detailModalOpen/detailLoading/detailError/detail 等状态及弹窗模板,将详情按钮改为 router.pushRouterLink 跳转,并保留列表、筛选和概览弹窗逻辑不变。

  • 步骤 4:再次运行 npm --prefix client run test:run -- client/src/App.spec.js client/src/pages/ToolDetailPage.spec.js,预期输出全部通过,首页到详情页的主链路打通。

任务 6完善长文阅读体验、后台提示文案和整体验证

文件

  • 修改:client/src/style.scss

  • 修改:client/src/pages/ToolDetailPage.vue

  • 修改:client/src/pages/ToolDetailPage.spec.js

  • 修改:client/src/admin/components/ToolFormDialog.vue

  • 步骤 1:扩展 client/src/pages/ToolDetailPage.spec.js,新增目录渲染、无标题时不显示目录、长文时保留清晰段落层级和返回入口的失败测试。

  • 步骤 2:运行 npm --prefix client run test:run -- client/src/pages/ToolDetailPage.spec.js,预期输出为目录相关断言失败,因为页面尚未接入目录工具和阅读态样式。

  • 步骤 3:修改 client/src/pages/ToolDetailPage.vueclient/src/style.scss,接入 extractMarkdownOutline、渲染目录导航、优化正文宽度/标题层级/锚点区块;同步修改 client/src/admin/components/ToolFormDialog.vue 的简介提示文案,明确其支持 Markdown 手册内容。

  • 步骤 4:依次运行 npm --prefix client run test:run -- client/src/utils/markdown-outline.spec.js client/src/pages/ToolDetailPage.spec.js client/src/App.spec.jsnpm --prefix client run buildnpm --prefix server test -- --runTestsByPath src/modules/tools/tools.service.spec.tsnpm --prefix server run test:e2e -- --runTestsByPath test/tools-detail.e2e-spec.ts,预期输出均为通过,且客户端构建成功无报错。


执行顺序说明

  1. 先补前端测试基建,否则后续页面任务无法按 TDD 执行。
  2. 后端先做服务层,再做控制器和 e2e可减少路由级调试成本。
  3. 前端先完成详情页自身状态,再替换首页入口,避免“按钮先改了但页面未就绪”。
  4. 长文阅读体验放在最后收口,避免样式和目录逻辑反复返工。

风险提示

  • 前端当前没有测试依赖,任务 1 会同时引入测试脚手架和锁文件变更。
  • App.vue 体量较大,任务 5 需要谨慎删除旧弹窗状态,避免误伤概览弹窗和列表筛选逻辑。
  • slug 接口与按 id 接口将同时存在,任务 2 和任务 3 需要确保两者返回结构一致,避免前端出现双标准。
  • e2e 测试需要自行准备和清理工具数据,避免依赖现有 seed 内容导致测试不稳定。