feat: 文件下载
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m54s

This commit is contained in:
sexygoat
2026-04-30 18:04:01 +08:00
parent 81155fd8e4
commit 950520635d
19 changed files with 438 additions and 44 deletions

View File

@@ -0,0 +1,92 @@
# Design: 后台任务页与操作审计日志文件下载入口
## Context
当前项目已经具备对象存储上传与下载地址获取能力:
- `StorageService.getUploadUrl()` 已用于上传导入文件
- `StorageService.batchDownloadUrls()` 已封装 `POST /api/admin/storage/batch-download-urls`
但在后台实际业务入口上,下载链路还没有被接起来:
- IoT 卡任务页和设备任务页只有“失败数据”等操作,没有“下载原始导入文件”
- 共享的资产操作审计日志组件虽然会显示 `文件存储键`,但只能看见 `file_key` 字符串,不能直接下载
此外,操作审计日志组件是共享组件,同时用于:
- 资产详情页
- IoT 卡列表中的操作审计日志弹窗
- 设备列表中的操作审计日志弹窗
这意味着“下载文件”能力既要复用统一实现,又要允许三个入口使用不同权限编码。
## Goals / Non-Goals
- Goals:
- 为 IoT 卡任务页增加原始导入文件下载入口
- 为设备任务页增加原始导入文件下载入口
- 为三个后台审计日志入口增加基于 `file_key` 的内联下载入口
- 为以上 5 个入口分别施加独立权限控制
- 复用现有 `batch-download-urls` 接口完成下载
- Non-Goals:
- 不改造对象存储上传流程
- 不增加批量下载多个文件的 UI
- 不扩展到 C 端页面
- 不在本次提案中统一所有历史权限命名差异
## Decisions
- Decision: 所有“下载文件”入口统一通过 `POST /api/admin/storage/batch-download-urls` 获取下载 URL
- Rationale: 现有基础设施已经覆盖私有文件下载,不需要新增独立接口;单文件下载可直接以 `file_keys: [file_key]` 方式复用批量接口。
- Decision: 任务页“下载文件”继续放在现有操作列中,而不是新增文件列
- Rationale: IoT 卡任务页和设备任务页已经有行级操作模式;把下载文件放入操作列,和“失败数据”等现有动作一致,改动面更小。
- Decision: 审计日志中的“下载文件”必须紧跟在 `文件存储键` / `file_key` 值后,而不是放到日志行外层操作区
- Rationale: 需求明确指出“如果变更内容出现了文件存储键,后面也要跟上下载文件”,因此入口应与该字段形成强绑定。
- Decision: 共享 `OperationLogsCard` 作为唯一实现,但下载权限由调用入口传入
- Rationale: 三个审计日志入口复用同一组件如果把权限写死在组件内部就无法满足“3 个不同权限编码”的要求。
- Decision: 本提案默认新增权限编码建议如下
- 任务页:
- `iot_card_task:download_file`
- `device_task:download_file`
- 审计日志入口:
- `asset_info:download_log_file`
- `iot_card:download_log_file`
- `device:download_log_file`
- Rationale: 任务页下载权限与现有同页行级动作前缀保持一致;日志下载权限与各自入口页面前缀保持一致,便于角色配置时理解来源。
- Decision: 不在本次变更中顺带统一 IoT 卡任务页历史上的 `lot_task:*` / `iot_card_task:*` 前缀差异
- Rationale: 当前需求只要求增加下载文件权限入口;若同时做权限前缀清理,会把提案扩大为权限命名治理,超出本次范围。
- Decision: 当 `file_key` 缺失、为空或下载 URL 获取失败时,页面只提示失败,不影响列表或日志正常渲染
- Rationale: 下载属于增强能力,不应把原有任务列表和审计日志变成硬依赖下载服务的阻塞页面。
## Risks / Trade-offs
- 任务列表前端类型当前未显式声明 `file_key`,实施时若接口已返回但类型未补齐,容易出现“功能依赖字段存在但类型缺口”的问题。
- `OperationLogsCard` 的 props 和渲染逻辑一旦调整会同时影响资产详情页、IoT 卡列表弹窗和设备列表弹窗,需要联动验证。
- IoT 卡任务页现存 `lot_task:bulk_import``iot_card_task:*` 并存,新增权限虽可落地,但会继续保留命名历史包袱。
## Migration Plan
1. 明确导入任务记录的 `file_key` 契约,并补齐前端类型。
2. 在 IoT 卡任务页和设备任务页的操作列增加“下载文件”。
3. 为两个任务页接入各自独立的下载权限编码。
4. 扩展共享 `OperationLogsCard`,在 `file_key` 场景渲染内联“下载文件”入口。
5. 由资产详情页、IoT 卡列表、设备列表分别传入对应的日志下载权限编码。
6. 联调验证 5 个入口的权限隔离与下载行为。
## Open Questions
- IoT 卡任务新增下载权限默认建议使用 `iot_card_task:download_file`。如果后端权限树仍希望完全沿用 `lot_task:*` 前缀,需要在评审阶段确认是否改为 `lot_task:download_file`
- 当前导入任务列表接口是否已经返回 `file_key` 需要评审确认;若未返回,则实施范围需要同步包含接口契约补齐。

View File

@@ -0,0 +1,54 @@
# Change: 为后台任务页与操作审计日志补充文件下载入口
## Why
当前后台已经具备对象存储上传能力和下载 URL 获取接口,但与“下载文件”相关的运营入口仍然缺失两块关键能力:
- IoT 卡任务页和设备任务页虽然展示了导入任务记录,但操作列里没有“下载文件”入口,运营无法直接回看任务原始导入文件。
- 资产操作审计日志已经会显示 `文件存储键` / `file_key`,但仍然只是纯文本,无法直接从日志里发起下载。
同时,本次需求明确要求这些下载入口按页面上下文拆分权限,不允许任务页和三个审计日志入口共用同一个按钮权限编码。
如果不补齐这些入口,后台用户仍然需要依赖复制 `file_key`、跳外部系统或人工排查对象存储文件,审计与任务追溯链路会继续断裂。
本提案仅覆盖后台管理端admin能力不包含 C 端页面和 C 端接口消费逻辑。
## What Changes
- 为后台任务管理增加原始导入文件下载入口:
- 在 IoT 卡任务列表操作列增加“下载文件”
- 在设备任务列表操作列增加“下载文件”
- 两个任务页分别使用独立按钮权限编码
- 为后台资产操作审计日志增加基于 `file_key` 的下载入口:
- 当日志变更内容包含 `文件存储键` / `file_key` 时,在对应值后追加“下载文件”
- 资产详情页、IoT 卡列表审计日志弹窗、设备列表审计日志弹窗分别使用独立按钮权限编码
- 共享日志组件需要支持由不同入口传入对应的下载权限上下文
- 明确复用现有下载接口:
- 所有下载入口统一通过 `POST /api/admin/storage/batch-download-urls` 获取预签名下载 URL
- 本次不新增新的对象存储下载 API
- 范围约束:
- 不改造上传流程
- 不扩展为“文件中心”或批量多文件下载能力
- 不顺带统一现有全部权限命名历史差异,仅为本次新增入口定义可审查的权限编码
## Impact
- Affected specs:
- `admin-file-download`
- Affected code:
- `src/api/modules/storage.ts`
- `src/views/asset-management/task-management/iot-card-task/index.vue`
- `src/views/asset-management/task-management/device-task/index.vue`
- `src/views/asset-management/asset-information/components/OperationLogsCard.vue`
- `src/components/business/OperationLogsDialog.vue`
- `src/views/asset-management/asset-information/index.vue`
- `src/views/asset-management/iot-card-management/index.vue`
- `src/views/asset-management/device-list/index.vue`
- `src/types/api/card.ts`
- `src/types/api/device.ts`
- Dependencies:
- 依赖现有 `POST /api/admin/storage/batch-download-urls` 可为单个 `file_key` 返回可直接下载的预签名 URL
- 与活跃变更 `update-admin-asset-device-signal-and-audit-logs` 存在 `OperationLogsCard.vue` 共享组件交集,实施前需要基于其最新状态合并
- 导入任务列表/详情接口需要提供可下载所需的 `file_key`;如果当前接口尚未返回,实施阶段需要同步补齐契约
- Breaking changes:
- 无外部接口路径和 HTTP 方法层面的破坏性变更;主要是后台入口、权限和前端类型契约的增量扩展

View File

@@ -0,0 +1,80 @@
## ADDED Requirements
### Requirement: Admin Import Tasks Provide Source File Download Actions
The admin import task pages SHALL provide a source-file download action for eligible task rows and SHALL gate the action with page-specific permissions.
#### Scenario: Show download action on IoT card task rows
- **GIVEN** 后台 IoT 卡任务列表中的某条任务记录包含可下载的原始文件标识
- **AND** 当前用户具备该页面的下载文件权限
- **WHEN** 任务列表渲染该条记录
- **THEN** 该条记录的操作列 MUST 显示“下载文件”
- **AND** 用户点击后,页面 MUST 通过 `POST /api/admin/storage/batch-download-urls` 获取该文件的下载地址并发起下载
#### Scenario: Show download action on device task rows
- **GIVEN** 后台设备任务列表中的某条任务记录包含可下载的原始文件标识
- **AND** 当前用户具备该页面的下载文件权限
- **WHEN** 任务列表渲染该条记录
- **THEN** 该条记录的操作列 MUST 显示“下载文件”
- **AND** 用户点击后,页面 MUST 通过 `POST /api/admin/storage/batch-download-urls` 获取该文件的下载地址并发起下载
#### Scenario: Hide task download action when permission or file key is missing
- **GIVEN** 某条任务记录缺少可下载文件标识,或当前用户不具备该页面的下载文件权限
- **WHEN** 任务列表渲染该条记录
- **THEN** 页面 MUST NOT 显示“下载文件”入口
### Requirement: Admin Operation Logs Provide Inline File Download Actions
The admin asset operation log views SHALL append an inline download action next to `文件存储键` / `file_key` values when a downloadable file exists.
#### Scenario: Asset detail operation log shows inline download action
- **GIVEN** 用户在资产详情页查看操作审计日志
- **AND** 某条日志变更内容包含 `文件存储键``file_key`
- **AND** 当前用户具备资产详情页日志下载权限
- **WHEN** 该日志内容被渲染
- **THEN** 页面 MUST 在对应文件键值后显示“下载文件”
- **AND** 用户点击后,页面 MUST 通过 `POST /api/admin/storage/batch-download-urls` 获取该文件的下载地址并发起下载
#### Scenario: IoT card list log dialog shows inline download action
- **GIVEN** 用户从 IoT 卡列表打开操作审计日志弹窗
- **AND** 某条日志变更内容包含 `文件存储键``file_key`
- **AND** 当前用户具备 IoT 卡列表日志下载权限
- **WHEN** 该日志内容被渲染
- **THEN** 页面 MUST 在对应文件键值后显示“下载文件”
#### Scenario: Device list log dialog shows inline download action
- **GIVEN** 用户从设备列表打开操作审计日志弹窗
- **AND** 某条日志变更内容包含 `文件存储键``file_key`
- **AND** 当前用户具备设备列表日志下载权限
- **WHEN** 该日志内容被渲染
- **THEN** 页面 MUST 在对应文件键值后显示“下载文件”
#### Scenario: Hide inline log download action without permission or file key
- **GIVEN** 某条日志不包含可下载文件键值,或当前用户不具备当前入口的日志下载权限
- **WHEN** 该日志内容被渲染
- **THEN** 页面 MUST NOT 显示“下载文件”入口
### Requirement: Admin File Download Permissions Remain Entry-Specific
The admin file-download entry points MUST use distinct permission checks per page context instead of sharing one global download permission.
#### Scenario: Task page permissions are isolated
- **GIVEN** 某用户具备设备任务页的下载文件权限,但不具备 IoT 卡任务页的下载文件权限
- **WHEN** 用户分别访问两个任务页
- **THEN** 设备任务页 MAY 显示“下载文件”
- **AND** IoT 卡任务页 MUST NOT 因设备任务权限而显示该入口
#### Scenario: Shared log component respects caller-specific permissions
- **GIVEN** 某用户具备 IoT 卡列表日志下载权限,但不具备设备列表日志下载权限
- **WHEN** 同一共享日志组件分别在两个入口渲染包含 `file_key` 的日志
- **THEN** IoT 卡列表入口 MAY 显示“下载文件”
- **AND** 设备列表入口 MUST NOT 因共享组件复用而错误显示该入口

View File

@@ -0,0 +1,25 @@
## 1. Proposal Review
- [x] 1.1 确认本提案仅覆盖后台管理端,不包含 C 端页面与 C 端接口消费逻辑。
- [x] 1.2 确认 5 个新增下载入口需要使用彼此独立的权限编码。
- [x] 1.3 确认 IoT 卡任务下载权限是否沿用提案建议 `iot_card_task:download_file`,还是改为 `lot_task:download_file`
- [ ] 1.4 确认导入任务列表/详情接口是否已经提供原始文件下载所需的 `file_key`
## 2. Implementation
- [x] 2.1 补齐 IoT 卡导入任务与设备导入任务的前端类型契约,接收原始文件下载所需字段。
- [x] 2.2 在 IoT 卡任务列表操作列增加“下载文件”,并接入独立权限编码。
- [x] 2.3 在设备任务列表操作列增加“下载文件”,并接入独立权限编码。
- [x] 2.4 复用 `POST /api/admin/storage/batch-download-urls` 实现单文件下载流程。
- [x] 2.5 扩展共享操作审计日志组件,在 `文件存储键` / `file_key` 后增加“下载文件”入口。
- [x] 2.6 让资产详情页、IoT 卡列表日志弹窗、设备列表日志弹窗分别传入各自的日志下载权限编码。
- [x] 2.7 确保无权限或无 `file_key` 时不显示下载入口,且下载失败不影响原有内容渲染。
## 3. Verification
- [ ] 3.1 验证 IoT 卡任务页仅在具备对应权限且记录存在可下载文件时显示“下载文件”。
- [ ] 3.2 验证设备任务页仅在具备对应权限且记录存在可下载文件时显示“下载文件”。
- [ ] 3.3 验证资产详情页操作审计日志中,`文件存储键` 后可按权限显示“下载文件”。
- [ ] 3.4 验证 IoT 卡列表操作审计日志弹窗中,`文件存储键` 后可按权限显示“下载文件”。
- [ ] 3.5 验证设备列表操作审计日志弹窗中,`文件存储键` 后可按权限显示“下载文件”。
- [ ] 3.6 验证 5 个下载入口均通过 `batch-download-urls` 正常发起下载。