From 950520635da9d3c5ab6da97ca2184291d67811b4 Mon Sep 17 00:00:00 2001 From: sexygoat <1538832180@qq.com> Date: Thu, 30 Apr 2026 18:04:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design.md | 92 +++++++++++++++++++ .../proposal.md | 54 +++++++++++ .../specs/admin-file-download/spec.md | 80 ++++++++++++++++ .../tasks.md | 25 +++++ src/api/modules/card.ts | 10 +- src/api/modules/storage.ts | 47 ++++++++++ .../business/OperationLogsDialog.vue | 3 +- src/types/api/asset.ts | 3 + src/types/api/card.ts | 9 ++ src/types/api/device.ts | 1 + .../components/CurrentPackageCard.vue | 6 +- .../components/OperationLogsCard.vue | 32 ++++++- .../components/WalletTransactionCard.vue | 23 ++--- .../composables/useAssetFormatters.ts | 8 +- .../asset-information/index.vue | 12 +-- .../asset-management/device-list/index.vue | 16 +++- .../iot-card-management/index.vue | 2 +- .../task-management/device-task/index.vue | 27 +++++- .../task-management/iot-card-task/index.vue | 32 ++++++- 19 files changed, 438 insertions(+), 44 deletions(-) create mode 100644 openspec/changes/add-admin-task-and-audit-log-file-download/design.md create mode 100644 openspec/changes/add-admin-task-and-audit-log-file-download/proposal.md create mode 100644 openspec/changes/add-admin-task-and-audit-log-file-download/specs/admin-file-download/spec.md create mode 100644 openspec/changes/add-admin-task-and-audit-log-file-download/tasks.md diff --git a/openspec/changes/add-admin-task-and-audit-log-file-download/design.md b/openspec/changes/add-admin-task-and-audit-log-file-download/design.md new file mode 100644 index 0000000..f687e84 --- /dev/null +++ b/openspec/changes/add-admin-task-and-audit-log-file-download/design.md @@ -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` 需要评审确认;若未返回,则实施范围需要同步包含接口契约补齐。 diff --git a/openspec/changes/add-admin-task-and-audit-log-file-download/proposal.md b/openspec/changes/add-admin-task-and-audit-log-file-download/proposal.md new file mode 100644 index 0000000..ba3d607 --- /dev/null +++ b/openspec/changes/add-admin-task-and-audit-log-file-download/proposal.md @@ -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 方法层面的破坏性变更;主要是后台入口、权限和前端类型契约的增量扩展 diff --git a/openspec/changes/add-admin-task-and-audit-log-file-download/specs/admin-file-download/spec.md b/openspec/changes/add-admin-task-and-audit-log-file-download/specs/admin-file-download/spec.md new file mode 100644 index 0000000..be67989 --- /dev/null +++ b/openspec/changes/add-admin-task-and-audit-log-file-download/specs/admin-file-download/spec.md @@ -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 因共享组件复用而错误显示该入口 diff --git a/openspec/changes/add-admin-task-and-audit-log-file-download/tasks.md b/openspec/changes/add-admin-task-and-audit-log-file-download/tasks.md new file mode 100644 index 0000000..cacc415 --- /dev/null +++ b/openspec/changes/add-admin-task-and-audit-log-file-download/tasks.md @@ -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` 正常发起下载。 diff --git a/src/api/modules/card.ts b/src/api/modules/card.ts index 241b707..3b4426b 100644 --- a/src/api/modules/card.ts +++ b/src/api/modules/card.ts @@ -21,7 +21,9 @@ import type { ListResponse, GatewayRealnameLinkResponse, ImportIotCardRequest, - ImportIotCardResponse + ImportIotCardResponse, + IotCardImportTask, + IotCardImportTaskDetail } from '@/types/api' export class CardService extends BaseService { @@ -296,7 +298,7 @@ export class CardService extends BaseService { * 获取导入任务列表 * @param params 查询参数 */ - static getIotCardImportTasks(params?: any): Promise> { + static getIotCardImportTasks(params?: any): Promise> { return this.getPage('/api/admin/iot-cards/import-tasks', params) } @@ -304,8 +306,8 @@ export class CardService extends BaseService { * 获取导入任务详情 * @param id 任务ID */ - static getIotCardImportTaskDetail(id: number): Promise> { - return this.getOne(`/api/admin/iot-cards/import-tasks/${id}`) + static getIotCardImportTaskDetail(id: number): Promise> { + return this.getOne(`/api/admin/iot-cards/import-tasks/${id}`) } // ========== 单卡列表(未绑定设备)相关 ========== diff --git a/src/api/modules/storage.ts b/src/api/modules/storage.ts index 055d295..077ee8a 100644 --- a/src/api/modules/storage.ts +++ b/src/api/modules/storage.ts @@ -5,6 +5,21 @@ import { BaseService } from '../BaseService' import type { BaseResponse } from '@/types/api' +const inferFileNameFromKey = (fileKey: string) => { + return fileKey.split('/').pop() || 'download' +} + +const triggerBrowserDownload = (downloadUrl: string, fileName: string) => { + const link = document.createElement('a') + link.href = downloadUrl + link.download = fileName + link.target = '_blank' + link.rel = 'noopener noreferrer' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) +} + /** * 文件用途枚举 */ @@ -132,4 +147,36 @@ export class StorageService extends BaseService { data ) } + + /** + * 获取单文件下载 URL + * @param fileKey 文件路径标识 + */ + static async getDownloadUrl(fileKey: string): Promise { + const normalizedFileKey = fileKey.trim() + const res = await this.batchDownloadUrls({ + file_keys: [normalizedFileKey] + }) + + if (res.code !== 0 || !res.data?.urls?.[normalizedFileKey]) { + throw new Error(res.msg || '获取下载地址失败') + } + + return res.data.urls[normalizedFileKey] + } + + /** + * 按文件标识直接触发浏览器下载 + * @param fileKey 文件路径标识 + * @param fileName 可选文件名 + */ + static async downloadFileByKey(fileKey: string, fileName?: string): Promise { + const normalizedFileKey = fileKey.trim() + if (!normalizedFileKey) { + throw new Error('文件标识不能为空') + } + + const downloadUrl = await this.getDownloadUrl(normalizedFileKey) + triggerBrowserDownload(downloadUrl, fileName || inferFileNameFromKey(normalizedFileKey)) + } } diff --git a/src/components/business/OperationLogsDialog.vue b/src/components/business/OperationLogsDialog.vue index eaa10c2..0fca9a8 100644 --- a/src/components/business/OperationLogsDialog.vue +++ b/src/components/business/OperationLogsDialog.vue @@ -6,7 +6,7 @@ size="70%" :before-close="handleClose" > - + @@ -18,6 +18,7 @@ interface Props { modelValue: boolean identifier?: string + downloadPermission?: string } const props = defineProps() diff --git a/src/types/api/asset.ts b/src/types/api/asset.ts index a231b64..2de65ea 100644 --- a/src/types/api/asset.ts +++ b/src/types/api/asset.ts @@ -216,6 +216,9 @@ export interface AssetPackageUsageRecord { enable_virtual_data?: boolean // 是否启用虚流量 paid_amount?: number // 实际支付金额(分) package_price?: number // 套餐价格(分) + start_time?: string // 开始时间(兼容前端现有映射字段) + expire_time?: string // 到期时间(兼容前端现有映射字段) + duration_days?: number // 套餐时长(兼容前端现有映射字段) activated_at?: string // 激活时间 expires_at?: string // 到期时间 master_usage_id?: number | null // 主套餐 ID(加油包时有值) diff --git a/src/types/api/card.ts b/src/types/api/card.ts index 681f185..70a8e7e 100644 --- a/src/types/api/card.ts +++ b/src/types/api/card.ts @@ -119,6 +119,7 @@ export interface ImportIotCardRequest { file_key: string // 对象存储文件路径 batch_no?: string // 批次号 card_category?: CardCategory // 卡业务类型(新增,可选,默认 normal) + realname_policy?: 'none' | 'before_order' | 'after_order' // 实名认证策略 } // IoT 卡导入响应 @@ -283,6 +284,8 @@ export interface IotCardImportTask { carrier_type: string // 运营商类型 (CMCC:中国移动, CUCC:中国联通, CTCC:中国电信) carrier_name: string // 运营商名称 file_name: string // 文件名 + file_key?: string // 原始导入文件存储键 + card_category?: CardCategory // 卡业务类型 status: IotCardImportTaskStatus // 任务状态 status_text: string // 任务状态文本 total_count: number // 总数 @@ -369,6 +372,12 @@ export interface StandaloneIotCard { cost_price: number // 成本价(分) distribute_price: number // 分销价(分) data_usage_mb: number // 累计流量使用(MB) + current_month_usage_mb?: number // 自然月累计流量(MB) + current_month_start_date?: string | null // 本月开始日期 + last_month_total_mb?: number // 上月流量总量(MB) + last_data_check_at?: string | null // 最后流量检查时间 + last_real_name_check_at?: string | null // 最后实名检查时间 + enable_polling?: boolean // 是否启用轮询 first_commission_paid: boolean // 是否已支付首次佣金 accumulated_recharge: number // 累计充值金额(分) activated_at?: string | null // 激活时间 (可选) diff --git a/src/types/api/device.ts b/src/types/api/device.ts index 3409bf8..5ae5468 100644 --- a/src/types/api/device.ts +++ b/src/types/api/device.ts @@ -200,6 +200,7 @@ export interface DeviceImportTask { task_no: string // 任务编号 batch_no: string // 批次号 file_name: string // 文件名 + file_key?: string // 原始导入文件存储键 status: DeviceImportTaskStatus // 任务状态 status_text: string // 任务状态文本 total_count: number // 总数 diff --git a/src/views/asset-management/asset-information/components/CurrentPackageCard.vue b/src/views/asset-management/asset-information/components/CurrentPackageCard.vue index 44b6e31..642cf2e 100644 --- a/src/views/asset-management/asset-information/components/CurrentPackageCard.vue +++ b/src/views/asset-management/asset-information/components/CurrentPackageCard.vue @@ -246,8 +246,8 @@ import { useAssetFormatters } from '../composables/useAssetFormatters' import { useUserStore } from '@/store/modules/user' import { storeToRefs } from 'pinia' + import type { AssetPackageUsageRecord } from '@/types/api' import { formatDateTime } from '@/utils/business/format' - import type { PackageInfo } from '../types' const { formatAmount, @@ -265,10 +265,10 @@ ) interface Props { - currentPackage: PackageInfo | null + currentPackage: AssetPackageUsageRecord | null loading?: boolean errorMsg?: string - boundDeviceId?: number + boundDeviceId?: number | null boundDeviceNo?: string boundDeviceName?: string } diff --git a/src/views/asset-management/asset-information/components/OperationLogsCard.vue b/src/views/asset-management/asset-information/components/OperationLogsCard.vue index 215e886..47d0045 100644 --- a/src/views/asset-management/asset-information/components/OperationLogsCard.vue +++ b/src/views/asset-management/asset-information/components/OperationLogsCard.vue @@ -79,6 +79,14 @@ {{ item.message }} @@ -106,7 +114,7 @@