update:增加文档模式
This commit is contained in:
152
design/specs/2026-04-14-tool-display-version-none-mode-design.md
Normal file
152
design/specs/2026-04-14-tool-display-version-none-mode-design.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# 工具展示版本与无访问模式设计规格
|
||||
|
||||
## 概述
|
||||
|
||||
当前工具站只区分 `web` 和 `download` 两种访问方式。下载工具的版本来源于 `ToolArtifact.version`,因此访客端首页和详情页中的“版本”信息只对下载工具有效,网页工具长期显示“暂无版本”。与此同时,当前系统没有“仅展示详情、不提供打开或下载入口”的访问模式,无法承载预告型、资料型或人工分发型工具。
|
||||
|
||||
本次设计目标是在现有 `Tool` 模型上补齐“展示版本”和“无访问模式”能力,保持下载包管理逻辑不变,同时让前台和后台统一拿到一个稳定的展示版本字段。具体策略为:数据库新增 `Tool.versionOverride` 作为人工维护的展示版本覆盖值;服务端统一计算 `displayVersion`;访问方式新增 `none`,用于“只展示详情,不执行 launch”的工具。
|
||||
|
||||
## 目标定位
|
||||
|
||||
- **主要用户**:后台管理员、公开站访客
|
||||
- **使用场景**:管理员在新增或编辑工具时维护展示版本,并可将工具设置为 `download`、`web` 或 `none`;访客在首页和详情页查看统一的版本信息,其中 `none` 模式工具只提供“查看详情”入口,不提供打开网页或下载操作
|
||||
|
||||
## 约束条件
|
||||
|
||||
- **技术限制**:前端基于 Vue 3 + Element Plus,服务端基于 NestJS + Prisma + SQLite;本次只做现有模型上的增量改造,不引入新的依赖或新的版本历史表
|
||||
- **时间限制**:本轮只实现版本展示和 `none` 访问模式,不扩展版本历史、发布日期、版本说明等二级能力
|
||||
- **资源限制**:继续复用现有下载包模型、公开列表/详情接口和后台工具管理流程;版本字段仅用于展示,不参与发布校验、不新增额外审核流程
|
||||
|
||||
## 成功标准
|
||||
|
||||
- [ ] Prisma 数据模型支持 `AccessMode.none` 和 `Tool.versionOverride`
|
||||
- [ ] 后台新增/编辑工具表单可以维护“展示版本”,访问方式下拉可选择“无”
|
||||
- [ ] 后台工具列表接口和公开工具列表/详情接口统一返回 `displayVersion`
|
||||
- [ ] 下载工具的 `displayVersion` 计算规则为 `versionOverride || latestArtifact.version || null`
|
||||
- [ ] 网页工具和无访问模式工具的 `displayVersion` 计算规则为 `versionOverride || null`
|
||||
- [ ] 访客端首页和详情页统一展示 `displayVersion`,不再依赖下载模式专属的 `latestVersion`
|
||||
- [ ] `none` 模式在首页主按钮显示“查看详情”,详情页不展示打开/下载主按钮
|
||||
- [ ] 直接调用 `launch` 接口访问 `none` 模式工具时返回明确错误,且不会产生打开/下载计数
|
||||
- [ ] 现有发布约束保持不变:`web` 仍要求 `openUrl`,`download` 仍要求安装包或下载地址,`none` 不因为缺少版本而被阻止发布
|
||||
- [ ] 后台概览和模式标签不再把 `none` 模式误显示为“下载模式”
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 系统结构
|
||||
|
||||
本次改造分为四层:
|
||||
|
||||
1. **数据层**:在 `Tool` 模型中新增 `versionOverride` 字段;在 `AccessMode` 枚举中新增 `none`
|
||||
2. **映射层**:在后台服务和公开服务中统一计算 `displayVersion`,将“原始覆盖值”和“最终展示值”分离
|
||||
3. **行为层**:在 `AccessService` 中显式拒绝 `none` 模式的 launch 行为,保证服务端语义闭合
|
||||
4. **展示层**:后台编辑页维护 `versionOverride`,后台列表和访客端页面统一展示 `displayVersion`
|
||||
|
||||
版本数据的核心原则如下:
|
||||
|
||||
1. `versionOverride` 是管理员手工维护的原始字段,允许为空
|
||||
2. `displayVersion` 是接口返回给前端的最终展示值,不直接持久化
|
||||
3. 对下载工具,若 `versionOverride` 为空,则自动回退到当前 `latestArtifact.version`
|
||||
4. 对网页工具和无访问模式工具,`displayVersion` 只来自 `versionOverride`
|
||||
5. `latestArtifact.version` 继续用于安装包管理;`displayVersion` 用于页面展示
|
||||
|
||||
访问模式的核心原则如下:
|
||||
|
||||
1. 新增枚举值 `none`,内部值固定为 `none`,后台展示文案为“无”
|
||||
2. `none` 模式工具允许存在详情页和展示版本,但不允许执行 launch
|
||||
3. 访客端列表页对 `none` 模式的主按钮改为“查看详情”
|
||||
4. 访客端详情页对 `none` 模式不渲染打开/下载按钮
|
||||
5. 服务端若收到对 `none` 模式的 launch 请求,返回 `409 Conflict`
|
||||
|
||||
### 组件划分
|
||||
|
||||
| 组件 | 职责 | 依赖 |
|
||||
|------|------|------|
|
||||
| `server/prisma/schema.prisma` | 为 `AccessMode` 增加 `none`;为 `Tool` 增加 `versionOverride` 字段 | Prisma |
|
||||
| `server/prisma/seed.ts` | 补齐种子数据中的访问方式和展示版本样例,避免本地初始化后看不到新行为 | Prisma Seed |
|
||||
| `server/src/modules/admin-tools/dto/create-tool.dto.ts` | 接收 `versionOverride`,并允许 `accessMode=none` | `class-validator` |
|
||||
| `server/src/modules/admin-tools/dto/update-tool.dto.ts` | 继承新增字段,支持后台更新展示版本 | `CreateToolDto` |
|
||||
| `server/src/modules/admin-tools/dto/update-access-mode.dto.ts` | 接收 `none` 枚举值,兼容访问方式切换 | `class-validator` |
|
||||
| `server/src/modules/admin-tools/admin-tools.service.ts` | 规范化 `versionOverride`;列表和详情返回 `displayVersion` 与 `versionOverride`;保持发布校验逻辑不因版本字段变化 | Prisma |
|
||||
| `server/src/modules/tools/tools.service.ts` | 公开列表和详情统一返回 `displayVersion`;保留下载工具的 `latestVersion` 作为兼容字段 | Prisma |
|
||||
| `server/src/modules/access/access.service.ts` | 对 `none` 模式返回明确错误,禁止生成 launch 地址或下载票据 | Prisma, ConfigService |
|
||||
| `server/src/modules/admin-overview/admin-overview.service.ts` | 访问方式统计兼容 `none`,避免概览数据遗漏或模式显示错误 | Prisma |
|
||||
| `client/src/admin/components/ToolFormDialog.vue` | 新增“展示版本”输入项;访问方式下拉新增“无”;根据模式调整提示文案 | Element Plus |
|
||||
| `client/src/admin/components/AdminToolsSection.vue` | 列表增加版本列,访问方式标签兼容 `none` 文案 | Element Plus |
|
||||
| `client/src/admin/components/AccessModeDialog.vue` | 快速修改访问方式时允许选择“无”,并在 `none` 模式下隐藏 URL 输入项 | Element Plus |
|
||||
| `client/src/admin/AdminApp.vue` | 表单数据结构新增 `versionOverride`;构造创建/更新 payload;访问模式、标签颜色和模式文案兼容 `none` | Vue 3 |
|
||||
| `client/src/App.vue` | 工具卡片统一显示 `displayVersion`;`none` 模式主按钮改为“查看详情”并直接路由跳转 | `vue-router`, `client/src/api.js` |
|
||||
| `client/src/pages/ToolDetailPage.vue` | 摘要区展示 `displayVersion`;`none` 模式不显示主操作按钮 | `vue-router`, `client/src/api.js` |
|
||||
| `client/src/admin/components/AdminOverviewSection.vue` | 模式统计与 Top 工具模式文案兼容 `none` | Element Plus |
|
||||
|
||||
## 数据流
|
||||
|
||||
### 版本字段维护流
|
||||
|
||||
1. 管理员在新增或编辑工具时填写“展示版本”
|
||||
2. 前端将该值作为 `versionOverride` 提交给后台;空字符串在提交前或服务端落库前统一归一化为 `null`
|
||||
3. 服务端保存 `Tool.versionOverride`
|
||||
4. 当后台列表、后台详情、公开列表或公开详情查询工具时,服务端统一计算 `displayVersion`
|
||||
5. 前端页面一律渲染 `displayVersion`,不再直接依赖下载工具专属的 `latestVersion`
|
||||
|
||||
`displayVersion` 计算规则如下:
|
||||
|
||||
1. 当 `tool.accessMode === 'download'` 时:`displayVersion = tool.versionOverride || tool.latestArtifact?.version || null`
|
||||
2. 当 `tool.accessMode === 'web'` 或 `tool.accessMode === 'none'` 时:`displayVersion = tool.versionOverride || null`
|
||||
|
||||
为降低回归风险,下载工具响应中的 `latestVersion` 字段继续保留,其语义保持为“当前最新安装包版本”;页面展示逻辑统一切换为 `displayVersion`。
|
||||
|
||||
### 访问模式切换流
|
||||
|
||||
1. 管理员在新增/编辑表单或访问方式对话框中选择 `download`、`web` 或 `none`
|
||||
2. 当模式为 `web` 时,沿用现有规则,发布时仍要求 `openUrl`
|
||||
3. 当模式为 `download` 时,沿用现有规则,发布时仍要求活动安装包或外部下载地址
|
||||
4. 当模式为 `none` 时,不生成 launch 目标,不要求 `openUrl`,前端不展示打开/下载按钮
|
||||
5. 当公开站列表遇到 `none` 模式工具时,主按钮直接路由到详情页
|
||||
6. 当公开站详情页遇到 `none` 模式工具时,仅展示内容和版本,不发起 launch 请求
|
||||
7. 若外部调用者直接请求 `POST /api/v1/tools/:id/launch` 且目标工具为 `none` 模式,服务端返回 `409`
|
||||
|
||||
### 前后台显示流
|
||||
|
||||
1. 后台工具列表新增版本列,显示 `row.displayVersion || '-'`
|
||||
2. 公开首页卡片“版本”行显示 `tool.displayVersion || '暂无版本'`
|
||||
3. 公开详情页摘要区显示 `detail.displayVersion || '暂无版本'`
|
||||
4. `none` 模式的卡片副文案和详情摘要不再显示“下载/访问”动词,统一显示“仅详情”
|
||||
5. 概览和模式标签遇到 `none` 时显示“无”,不将其归并到下载模式
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 错误类型 | 处理方式 |
|
||||
|----------|----------|
|
||||
| `versionOverride` 为空字符串 | 前端提交前或服务端保存前统一归一化为 `null`,避免空串污染数据 |
|
||||
| 下载工具没有覆盖版本且没有最新安装包版本 | `displayVersion` 返回 `null`,前端显示“暂无版本”,但不阻止发布之外的页面展示 |
|
||||
| `none` 模式被直接调用 launch 接口 | 服务端返回 `409 Conflict`,建议复用 `TOOL_ACCESS_MODE_MISMATCH` 并提供明确消息,如“tool is not launchable in none mode” |
|
||||
| 访问方式统计遇到 `none` | 后台概览必须显式处理该值,避免统计遗漏或错误文案 |
|
||||
| 旧前端代码仍读取 `latestVersion` | 下载工具继续保留该字段,版本展示迁移到 `displayVersion` 后逐步收敛消费端 |
|
||||
| 管理员把工具切换为 `none` | 页面行为以模式为准,版本仍可展示,但公开站不再允许打开/下载 |
|
||||
|
||||
## 风险评估
|
||||
|
||||
| 风险描述 | 类别 | 影响 | 概率 | 缓解策略 |
|
||||
|----------|------|------|------|----------|
|
||||
| 新增 `none` 枚举后,现有前端分支把未知模式错误地当成下载模式处理 | 集成风险 | 高 | 中 | 全量检查 `accessMode` 条件分支,补齐 `none` 的按钮文案、标签颜色和统计展示 |
|
||||
| 下载工具同时存在 `latestArtifact.version` 和 `versionOverride`,容易出现展示口径不一致 | 技术风险 | 中 | 中 | 服务端统一生成 `displayVersion`,前端禁止自行拼接版本来源 |
|
||||
| 旧接口调用方继续消费 `latestVersion`,导致 web/none 工具仍显示“暂无版本” | 范围风险 | 中 | 中 | 在页面和后台列表统一切到 `displayVersion`,同时短期保留 `latestVersion` 兼容下载工具 |
|
||||
| 增加 `none` 模式后,后台概览和模式统计遗漏该值 | 集成风险 | 中 | 中 | 同步更新概览服务、模式标签和概览页面文案,避免出现统计不闭合 |
|
||||
|
||||
## 测试策略
|
||||
|
||||
- **单元测试**:为服务端新增版本解析逻辑编写测试,覆盖三种场景:下载工具无覆盖值时回退安装包版本、下载工具有覆盖值时优先显示覆盖值、`web/none` 工具只使用覆盖值
|
||||
- **集成测试**:覆盖后台创建/更新工具时提交 `versionOverride` 和 `accessMode=none`;覆盖公开列表和详情接口返回 `displayVersion`;覆盖 `none` 模式 launch 接口返回 `409`
|
||||
- **前端组件测试**:覆盖首页卡片在 `none` 模式下显示“查看详情”;覆盖详情页在 `none` 模式下不渲染主操作按钮;覆盖版本展示优先使用 `displayVersion`
|
||||
- **验收标准**:管理员可维护展示版本;后台工具列表可看到版本;访客端列表与详情都能看到统一版本;下载工具默认继承安装包版本;`none` 模式只可查看详情、不可 launch;后台概览与模式文案不出现错误映射
|
||||
|
||||
## 决策记录
|
||||
|
||||
| 决策 | 理由 | 影响 |
|
||||
|------|------|------|
|
||||
| 使用 `Tool.versionOverride + displayVersion`,而不是为所有工具新建统一版本表 | 当前需求只需要单值展示和少量覆盖能力,不需要版本历史,增量成本最低 | 需要在服务端增加统一映射逻辑 |
|
||||
| `displayVersion` 由服务端计算,不在数据库落地 | 避免前端自行拼接版本来源,减少 download/web/none 三种模式的歧义 | 后台和公开接口都要增加该字段 |
|
||||
| 下载工具保留 `latestVersion`,但页面展示切到 `displayVersion` | 降低旧代码回归风险,同时给新页面一个统一字段 | 服务端响应短期内会同时存在两个版本相关字段 |
|
||||
| 访问方式新增 `none`,而不是用布尔开关控制是否可 launch | 与现有 `AccessMode` 模型保持一致,语义清晰,便于后台筛选和统计 | Prisma 枚举、前后端条件分支和概览统计都需要更新 |
|
||||
| `none` 模式首页主按钮跳详情页,详情页不展示主操作按钮 | 用户已明确选择详情引导型行为,比“禁用按钮”更可用 | 公开站首页和详情页都需增加 `none` 分支 |
|
||||
| 版本字段不参与发布校验 | 用户明确要求版本只作展示,不希望改变当前发布约束 | `assertPublishInput` 和状态流保持现状,只需兼容 `none` 模式 |
|
||||
Reference in New Issue
Block a user