From 9a6761e01de6db77f7e6b3e003776ce8d054c4f8 Mon Sep 17 00:00:00 2001 From: luo Date: Sun, 20 Sep 2026 17:29:09 +0800 Subject: [PATCH] fix: some --- .../design.md | 38 ++++++ .../proposal.md | 39 ++++++ .../specs/asset-information/spec.md | 13 ++ .../specs/device-management/spec.md | 19 +++ .../specs/employee-collection/spec.md | 12 ++ .../h5-popup-configuration-management/spec.md | 18 +++ .../specs/iot-card-management/spec.md | 19 +++ .../spec.md | 19 +++ .../tasks.md | 27 ++++ src/types/api/asset.ts | 2 +- src/types/api/card.ts | 2 +- src/types/api/device.ts | 2 +- src/types/api/employeeCollection.ts | 2 +- .../components/BasicInfoCard.vue | 4 + .../dialogs/PackageRechargeDialog.vue | 1 - .../asset-information/index.vue | 1 - .../asset-information/types.ts | 2 +- .../phone-asset-association/index.vue | 124 +++++++----------- .../device-batch-allocation/index.vue | 3 - .../task-management/device-task/index.vue | 2 - .../detail.vue | 6 - .../phone-asset-unbind-import-tasks/index.vue | 1 - .../employeeCollectionDisplay.ts | 4 +- .../traffic-alert-rules/index.vue | 12 +- .../traffic-alerts/index.vue | 2 - .../settings/h5-popup-configuration/index.vue | 5 - 26 files changed, 268 insertions(+), 111 deletions(-) create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/design.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/proposal.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/asset-information/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/device-management/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/employee-collection/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/h5-popup-configuration-management/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/iot-card-management/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/specs/phone-asset-association-management/spec.md create mode 100644 openspec/changes/update-asset-import-popup-and-phone-display/tasks.md diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/design.md b/openspec/changes/update-asset-import-popup-and-phone-display/design.md new file mode 100644 index 0000000..c98afd6 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/design.md @@ -0,0 +1,38 @@ +## Context + +本次变更同时涉及任务导入弹窗、配置管理表单、公共错误处理约定和三类资产展示面。已有解绑导入 API、`VoucherUpload` 组件及 H5 配置页面能力,不新增后端接口或新的上传基础设施。 + +## Goals / Non-Goals + +- Goals: + - 让 CSV 解绑导入沿用已有批量导入的交互模式和共享上传能力。 + - 让页面错误提示遵循“公共请求层统一提示、页面不重复提示”的约定。 + - 让关联手机号在列表和详情的字段、空值、图标和展示格式一致。 +- Non-Goals: + - 不改变解绑导入 API、权限模型、任务处理逻辑或后端手机号数据范围。 + - 不删除或迁移历史 H5 运营弹窗配置。 + - 不修改其他业务页面中与本次列表加载无关的错误提示。 + +## Decisions + +- Decision: 复用 `VoucherUpload` 作为 CSV 解绑导入的文件入口;通过 `purpose` 和 CSV 校验参数表达业务约束,提交前只使用组件产出的对象存储 key。 +- Decision: `asset_detail` 仅从新增/编辑的页面选择项隐藏,历史配置的 `PAGE_NAMES`/回显映射继续保留,避免历史数据无法查看或保存时被静默改写。 +- Decision: 关联手机号直接消费 `associated_phones`,使用统一的“、”拼接和 `-` 空值占位,不在前端二次脱敏,以符合接口“按资产数据范围返回完整手机号”的契约。 +- Decision: 资产详情图标沿用 `BasicInfoCard` 现有 `asset-label--*` iconfont 伪元素机制,新增关联手机号对应的 class/glyph,不引入新的图标库。 + +## Risks / Trade-offs + +- 共享上传组件的默认文件数量、大小或校验提示可能与旧弹窗不同,需要在弹窗层明确传入参数并回归关闭/重选行为。 +- 隐藏 `asset_detail` 后,已存在该值的编辑表单必须允许回显,否则会造成用户误以为配置被清空;实现时需区分“历史值回显”和“新选项列表”。 +- 完整手机号展示属于敏感信息,必须保持现有权限和后端资产数据范围,不得通过前端扩大查询范围。 + +## Migration Plan + +1. 先完成组件和页面改造并通过静态检查。 +2. 在测试环境验证上传任务、历史弹窗配置回显和关联手机号字段兼容性。 +3. 发布前确认公共请求层已覆盖列表接口错误提示;如未覆盖,先补齐公共层再移除页面提示。 + +## Open Questions + +- 无。上传大小上限沿用 `VoucherUpload`/现有解绑导入接口约束,若后端另有上限以接口契约为准。 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/proposal.md b/openspec/changes/update-asset-import-popup-and-phone-display/proposal.md new file mode 100644 index 0000000..2701622 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/proposal.md @@ -0,0 +1,39 @@ +# Change: 统一资产导入交互并补充关联手机号展示 + +## Why + +当前 CSV 解绑导入使用独立的弹窗和原生上传实现,与批量导入 IoT 卡的导入体验不一致,也没有复用项目已有的上传组件。H5 运营弹窗配置仍把“资产详情”作为新增配置的可选页面,列表请求失败时还会重复弹出错误提示;核销申请状态文案、设备/IoT 卡列表及资产详情中的关联手机号展示也需要与后端返回契约和现有视觉规范保持一致。 + +## What Changes + +- 将 CSV 解绑导入弹窗调整为与“批量导入 IoT 卡”一致的导入说明、模板入口、表单布局、提交状态和底部操作区。 +- CSV 文件上传改用现有通用上传组件,限定单个 `.csv` 文件并沿用 `phone_unbind_import` 上传用途;上传中禁止重复提交,上传结果和校验错误在弹窗内可见。 +- 在新增/编辑运营弹窗配置的 `PAGE_OPTIONS` 中隐藏“资产详情”选项;历史配置若已命中 `asset_detail` 仍可正常展示,不因隐藏选项而丢失或改写历史数据。 +- 移除 H5 运营弹窗配置列表加载 `try/catch` 中的本地 `ElMessage.error(normalizeApiError(error).message || '获取运营弹窗配置列表失败')`,由公共请求层统一负责错误提示,页面保留必要的日志和加载状态收尾。 +- 将核销申请的“已撤销或已关闭”统一改为“已关闭”,同步状态选项、映射和类型注释中的用户可见文案。 +- 设备管理和 IoT 卡管理列表消费并展示接口返回的 `associated_phones`,多个手机号使用统一分隔符,无关联时显示稳定占位符;按后端资产数据范围展示完整手机号,不在前端脱敏或截断。 +- 在资产信息基础信息区域的“关联手机号”标签前补充与其他字段一致的图标样式,并保持空数组的占位展示。 + +## Impact + +- Affected specs: + - `phone-asset-association-management` + - `h5-popup-configuration-management` + - `employee-collection` + - `device-management` + - `iot-card-management` + - `asset-information` +- Affected code: + - `src/views/asset-management/phone-asset-association/index.vue` + - `src/components/business/VoucherUpload.vue`(仅在需要扩展 CSV 上传参数时调整) + - `src/views/settings/h5-popup-configuration/index.vue` + - `src/views/finance/employee-collection/employeeCollectionDisplay.ts` + - `src/views/asset-management/device-list/index.vue` + - `src/views/asset-management/iot-card-management/index.vue` + - `src/types/api/device.ts`、`src/types/api/card.ts`、相关列表列配置 + - `src/views/asset-management/asset-information/components/BasicInfoCard.vue` +- Related changes: + - 衔接已有 `add-phone-asset-unbind-management` 的解绑导入 API 和权限约束。 + - 衔接已有 `add-h5-popup-configuration-management` 的页面枚举、历史配置展示和权限约束。 +- Breaking changes: 无后端 API 破坏性变更;新增配置页面选项对运营人员的可选范围有意收窄。 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/asset-information/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/asset-information/spec.md new file mode 100644 index 0000000..613ee91 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/asset-information/spec.md @@ -0,0 +1,13 @@ +## ADDED Requirements + +### Requirement: 资产详情关联手机号标签图标 + +资产信息基础信息区域展示 `associated_phones` 时,关联手机号标签 MUST 使用与其他资产字段一致的图标前缀样式。 + +#### Scenario: 展示关联手机号字段 + +- **WHEN** 资产详情渲染关联手机号字段 +- **THEN** “关联手机号”标签前 MUST 显示现有 iconfont 图标 +- **AND** 图标样式 MUST 与基础信息区域其他带图标标签的颜色、间距和对齐方式一致 +- **AND** 手机号内容 MUST 保持现有完整值拼接和空值占位规则 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/device-management/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/device-management/spec.md new file mode 100644 index 0000000..d12c335 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/device-management/spec.md @@ -0,0 +1,19 @@ +## ADDED Requirements + +### Requirement: 设备列表展示关联手机号 + +设备管理列表 MUST 消费接口返回的 `associated_phones` 当前关联手机号列表,并按后端资产数据范围展示完整手机号。 + +#### Scenario: 设备存在关联手机号 + +- **GIVEN** 设备列表项包含一个或多个 `associated_phones` +- **WHEN** 设备管理列表渲染 +- **THEN** 页面 MUST 展示“关联手机号”列 +- **AND** 多个手机号 MUST 使用统一分隔符连接,且 MUST 不在前端脱敏或截断 + +#### Scenario: 设备没有关联手机号 + +- **GIVEN** `associated_phones` 为空数组或缺失 +- **WHEN** 设备管理列表渲染 +- **THEN** “关联手机号”列 MUST 显示稳定的空值占位符 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/employee-collection/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/employee-collection/spec.md new file mode 100644 index 0000000..801fcff --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/employee-collection/spec.md @@ -0,0 +1,12 @@ +## ADDED Requirements + +### Requirement: 核销申请关闭状态文案 + +核销申请状态值为关闭/撤销兼容状态时,前端用户可见文案 MUST 统一显示为“已关闭”。 + +#### Scenario: 显示关闭状态 + +- **WHEN** 核销申请列表、筛选项或详情返回兼容的关闭状态值 +- **THEN** 页面 MUST 显示“已关闭” +- **AND** 页面 MUST NOT 显示“已撤销或已关闭” + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/h5-popup-configuration-management/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/h5-popup-configuration-management/spec.md new file mode 100644 index 0000000..d6c5e14 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/h5-popup-configuration-management/spec.md @@ -0,0 +1,18 @@ +## ADDED Requirements + +### Requirement: 运营弹窗新增页面选项与列表错误提示 + +运营弹窗配置页面 MUST 在新增/编辑表单的 `PAGE_OPTIONS` 中隐藏“资产详情”页面,同时 MUST 由公共请求层统一处理列表接口异常,页面不得重复弹出同一错误提示。 + +#### Scenario: 新增配置不提供资产详情选项 + +- **WHEN** 用户打开新增或编辑运营弹窗配置表单 +- **THEN** 页面 MUST NOT 在可选页面列表中展示“资产详情” +- **AND** 页面 MUST 继续保留已有配置中 `asset_detail` 的名称映射和历史值回显能力 + +#### Scenario: 列表请求失败 + +- **WHEN** 运营弹窗配置列表请求在网络层或接口层失败 +- **THEN** 页面 MUST 不再调用 `ElMessage.error(normalizeApiError(error).message || '获取运营弹窗配置列表失败')` +- **AND** 公共请求层 MUST 负责用户可见的错误提示,页面 MUST 仅保留日志记录及 loading 状态收尾 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/iot-card-management/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/iot-card-management/spec.md new file mode 100644 index 0000000..a96a6cc --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/iot-card-management/spec.md @@ -0,0 +1,19 @@ +## ADDED Requirements + +### Requirement: IoT 卡列表展示关联手机号 + +IoT 卡管理列表 MUST 消费接口返回的 `associated_phones` 当前关联手机号列表,并按后端资产数据范围展示完整手机号。 + +#### Scenario: IoT 卡存在关联手机号 + +- **GIVEN** IoT 卡列表项包含一个或多个 `associated_phones` +- **WHEN** IoT 卡管理列表渲染 +- **THEN** 页面 MUST 展示“关联手机号”列 +- **AND** 多个手机号 MUST 使用统一分隔符连接,且 MUST 不在前端脱敏或截断 + +#### Scenario: IoT 卡没有关联手机号 + +- **GIVEN** `associated_phones` 为空数组或缺失 +- **WHEN** IoT 卡管理列表渲染 +- **THEN** “关联手机号”列 MUST 显示稳定的空值占位符 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/specs/phone-asset-association-management/spec.md b/openspec/changes/update-asset-import-popup-and-phone-display/specs/phone-asset-association-management/spec.md new file mode 100644 index 0000000..0678721 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/specs/phone-asset-association-management/spec.md @@ -0,0 +1,19 @@ +## ADDED Requirements + +### Requirement: CSV 解绑导入弹窗复用批量导入交互 + +CSV 解绑导入入口 MUST 使用与批量导入 IoT 卡一致的导入说明、模板入口、表单确认和底部操作布局,并复用项目通用上传组件完成文件选择与上传。 + +#### Scenario: 打开解绑导入弹窗 + +- **WHEN** 具备权限的用户打开 CSV 解绑导入 +- **THEN** 页面 MUST 展示导入说明、模板下载、解绑原因、二次确认和明确的创建任务操作 +- **AND** 弹窗 MUST 提供与批量导入 IoT 卡一致的抽屉/弹窗层次和提交状态反馈 + +#### Scenario: 使用共享组件上传 CSV + +- **WHEN** 用户选择解绑 CSV 文件 +- **THEN** 页面 MUST 使用通用上传组件,并限制为单个 `.csv` 文件 +- **AND** 上传 MUST 使用 `phone_unbind_import` 用途并产出后续任务接口所需的 `file_key` +- **AND** 文件上传中 MUST 禁止重复创建任务,上传失败 MUST 在弹窗内给出可理解的校验或错误反馈 + diff --git a/openspec/changes/update-asset-import-popup-and-phone-display/tasks.md b/openspec/changes/update-asset-import-popup-and-phone-display/tasks.md new file mode 100644 index 0000000..3a798f8 --- /dev/null +++ b/openspec/changes/update-asset-import-popup-and-phone-display/tasks.md @@ -0,0 +1,27 @@ +# Tasks: 统一资产导入交互并补充关联手机号展示 + +## 1. CSV 解绑导入 + +- [x] 1.1 对照批量导入 IoT 卡抽屉,重排 CSV 解绑导入说明、模板下载、原因/确认表单和底部操作区。 +- [x] 1.2 将 CSV 文件选择替换为通用上传组件,配置单文件、`.csv`、`phone_unbind_import` 用途及文件类型/编码提示。 +- [x] 1.3 接入上传中状态、移除/重选文件和提交前校验,确保创建解绑任务仍发送 `file_key`、`reason`、`confirmed`。 +- [x] 1.4 验证上传失败、重复选择文件、取消关闭和任务创建成功后的清理行为。 + +## 2. H5 运营弹窗配置 + +- [x] 2.1 从新增/编辑表单的 `PAGE_OPTIONS` 隐藏 `asset_detail`,保留历史值的名称映射和只读回显能力。 +- [x] 2.2 删除列表加载 `catch` 中重复的运营弹窗配置失败 `ElMessage.error`,保留日志与 loading 状态收尾。 +- [x] 2.3 验证全局请求错误提示只出现一次,且成功响应中的业务错误仍按现有响应约定处理。 + +## 3. 状态文案与关联手机号 + +- [x] 3.1 将核销申请状态“已撤销或已关闭”改为“已关闭”,同步选项、映射、注释和相关页面筛选显示。 +- [x] 3.2 确认设备与 IoT 卡列表类型保留 `associated_phones: string[]`,并在默认列/列管理配置中展示“关联手机号”。 +- [x] 3.3 统一多手机号拼接和空数组占位符,确认不做前端脱敏、截断或超出后端数据范围的补查。 +- [x] 3.4 为资产详情“关联手机号”标签补充现有 iconfont 图标,并检查卡资产、设备资产及空值场景。 + +## 4. Verification + +- [x] 4.1 运行相关 TypeScript/Vue 检查、编码检查和变更页面 lint。 +- [x] 4.2 手工验证 CSV 导入、运营弹窗配置、核销申请、设备列表、IoT 卡列表和资产详情的关键场景。 +- [x] 4.3 使用 `openspec validate update-asset-import-popup-and-phone-display --strict` 校验提案格式。 diff --git a/src/types/api/asset.ts b/src/types/api/asset.ts index ad8ca40..27bec30 100644 --- a/src/types/api/asset.ts +++ b/src/types/api/asset.ts @@ -159,7 +159,7 @@ export interface AssetExchangeTrace { export interface AssetResolveResponse { asset_type: AssetType // 资产类型:card 或 device asset_id: number // 数据库 ID - associated_phones?: string[] // 当前关联手机号列表(完整手机号,无关联时为空数组) + associated_phones?: string[] // 当前关联手机号列表(按资产数据范围返回完整手机号,无关联时为空数组) identifier?: string // 原样回传本次查询所用的标识符 virtual_no: string // 虚拟号 status: number // 资产状态 diff --git a/src/types/api/card.ts b/src/types/api/card.ts index 81f1b62..2dda939 100644 --- a/src/types/api/card.ts +++ b/src/types/api/card.ts @@ -384,7 +384,7 @@ export interface StandaloneIotCard { gateway_card_imei?: string // 网关侧返回的卡 IMEI(可空) id: number // 卡ID iccid: string // ICCID - associated_phones?: string[] // 当前关联手机号列表(完整手机号,无关联时为空数组) + associated_phones?: string[] // 当前关联手机号列表(按资产数据范围返回完整手机号,无关联时为空数组) imsi?: string // IMSI (可选) msisdn?: string // 卡接入号 (可选) virtual_no?: string // 卡虚拟号(可空) diff --git a/src/types/api/device.ts b/src/types/api/device.ts index 4fdf69f..6b8f963 100644 --- a/src/types/api/device.ts +++ b/src/types/api/device.ts @@ -39,7 +39,7 @@ export type SwitchMode = '0' | '1' // 0=自动, 1=手动 export interface Device { id: number // 设备ID virtual_no: string // 虚拟号(原 device_no) - associated_phones?: string[] // 当前关联手机号列表(完整手机号,无关联时为空数组) + associated_phones?: string[] // 当前关联手机号列表(按资产数据范围返回完整手机号,无关联时为空数组) device_name: string // 设备名称 device_model: string // 设备型号 device_type: string // 设备类型 diff --git a/src/types/api/employeeCollection.ts b/src/types/api/employeeCollection.ts index b539fdd..aa19046 100644 --- a/src/types/api/employeeCollection.ts +++ b/src/types/api/employeeCollection.ts @@ -183,7 +183,7 @@ export type CloseEmployeeCollectionBillResult = EmployeeCollectionBill // ========== 核销申请 ========== -/** 申请状态:0 审批中 / 1 已通过 / 2 已驳回 / 3 已撤销或已关闭 */ +/** 申请状态:0 审批中 / 1 已通过 / 2 已驳回 / 3 已关闭 */ export type EmployeeCollectionApplicationStatus = number /** 审批尝试记录(历史材料不被覆盖) */ diff --git a/src/views/asset-management/asset-information/components/BasicInfoCard.vue b/src/views/asset-management/asset-information/components/BasicInfoCard.vue index 7a27e03..a5ee1a4 100644 --- a/src/views/asset-management/asset-information/components/BasicInfoCard.vue +++ b/src/views/asset-management/asset-information/components/BasicInfoCard.vue @@ -1413,6 +1413,10 @@ content: '\e776'; } + :deep(.asset-label--associated-phones::before) { + content: '\e776'; + } + :deep(.asset-label--operator-account::before) { content: '\e70d'; } diff --git a/src/views/asset-management/asset-information/components/dialogs/PackageRechargeDialog.vue b/src/views/asset-management/asset-information/components/dialogs/PackageRechargeDialog.vue index e7a8537..89bf7f6 100644 --- a/src/views/asset-management/asset-information/components/dialogs/PackageRechargeDialog.vue +++ b/src/views/asset-management/asset-information/components/dialogs/PackageRechargeDialog.vue @@ -365,7 +365,6 @@ return } console.error('创建订单失败:', error) - ElMessage.error(normalizeApiError(error).message) } finally { loading.value = false } diff --git a/src/views/asset-management/asset-information/index.vue b/src/views/asset-management/asset-information/index.vue index ca8e75a..e9bee92 100644 --- a/src/views/asset-management/asset-information/index.vue +++ b/src/views/asset-management/asset-information/index.vue @@ -836,7 +836,6 @@ console.error('设置限速失败:', error) speedLimitDialogVisible.value = false await nextTick() - ElMessage.error(normalizeApiError(error).message) } finally { speedTierSubmitting.value = false } diff --git a/src/views/asset-management/asset-information/types.ts b/src/views/asset-management/asset-information/types.ts index 1976e4e..8811eaa 100644 --- a/src/views/asset-management/asset-information/types.ts +++ b/src/views/asset-management/asset-information/types.ts @@ -16,7 +16,7 @@ export interface AssetInfo { iccid?: string imei?: string msisdn?: string - associated_phones?: string[] // 当前关联手机号(完整值) + associated_phones?: string[] // 当前关联手机号(按资产数据范围返回完整值) carrier_type?: string carrier_name?: string real_name_status?: number diff --git a/src/views/asset-management/phone-asset-association/index.vue b/src/views/asset-management/phone-asset-association/index.vue index 606134e..89fc619 100644 --- a/src/views/asset-management/phone-asset-association/index.vue +++ b/src/views/asset-management/phone-asset-association/index.vue @@ -142,34 +142,41 @@ - -
- 模板表头: - 下载模板 -
- 资产标识,备注(备注可选);支持 UTF-8(可带 BOM),非 UTF-8 按 GBK 解码;无行数上限。 -
-
+ + + - - -
拖拽文件到此处,或点击选择 .csv 文件
-
+ v-model="importFileKeys" + voucher-name="CSV 文件" + :max-count="1" + purpose="phone_unbind_import" + content-type="text/csv" + accept=".csv,text/csv" + tip="仅支持 UTF-8 CSV(可带 BOM),大小限制以服务端校验为准" + @uploading-change="importUploading = $event" + />
-
+