This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Change: 新增资产钱包自动续费配置(后台查询/保存 + 自动续费失败通知适配)
|
||||
|
||||
## Why
|
||||
|
||||
根据 `docs/产品迭代8月份/资产钱包.md`。后端测试环境(`https://cmp-api.boss160.cn`,`Authorization: Bearer <token>`)已提供资产钱包自动续费全局配置能力,仅有 2 个后台接口,H5 侧零新增:
|
||||
|
||||
- 查询资产钱包自动续费配置:`GET /api/admin/asset-auto-renewal-config`
|
||||
- 保存资产钱包自动续费配置:`PUT /api/admin/asset-auto-renewal-config`
|
||||
|
||||
后台需要提供配置页面承载总开关、适用范围、指定主套餐、到期前天数等配置;同时新增通知类型 `asset.auto_renewal.failed` 会复用既有通知接口产生新数据,需要适配展示与跳转。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 新增能力 `asset-wallet-auto-renewal`:
|
||||
- 配置读取:`GET /api/admin/asset-auto-renewal-config`,返回唯一一份全局配置的 `enabled`+`enabled_name`、`scope`+`scope_name`、`package_ids`、`days_before_expiry`、`config_version`、`updater`、`updated_at`。
|
||||
- 配置保存:`PUT /api/admin/asset-auto-renewal-config`:
|
||||
- 请求体 `{ enabled(0/1,必填), scope(all|specified,必填), package_ids(uint[],仅 specified 时非空且只能选当前可售主套餐), days_before_expiry(1–90,必填) }`。
|
||||
- 语义:单行配置、无新增/删除;保存即递增 `config_version`,记录操作者与前后值快照;配置变更只影响后续扫描,历史记录不重算。
|
||||
- 权限:仅超级管理员与平台账号可访问;其他身份(代理/企业/个人客户)`403`,提示「无权限操作该资源或资源不存在」,无权限与不存在不区分。
|
||||
- 通知适配(复用既有接口,不算新接口):
|
||||
- 后台站内通知:新增通知类型 `asset.auto_renewal.failed`(类别 `expiry`、级别 `warning`),接收人是业务员/店铺账号。走既有 `GET /api/admin/notifications` + `GET /api/admin/notifications/{id}/target`;确认 `target_type` 的 `iot_card` / `device` 在导航白名单;`available=false` 时只显示正文不跳转;计入未读数。
|
||||
- H5 个人客户通知:同一类型已由后端加入客户可见白名单,出现在既有 `GET /api/c/v1/notifications` 与 `unread-count`,客户侧只有文案(资产标识、套餐、原因、到期日),无跳转接口、无需新页面,本仓库无需改动。该类型属 `expiry` 类别,展示期以业务到期时间为准,套餐到期后从列表消失(既有类别行为)。
|
||||
- 明确不做(避免前端空等):无自动续费记录页/异常记录页接口、无尝试记录查询接口、无「有余额就不停机」开关、无 H5 客户侧新接口。
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs:
|
||||
- `asset-wallet-auto-renewal` — 新增能力
|
||||
- Affected code:
|
||||
- `src/types/api/assetWallet.ts`(新增)
|
||||
- `src/types/api/index.ts`
|
||||
- `src/api/modules/assetWallet.ts`(新增)
|
||||
- `src/api/modules/index.ts`
|
||||
- `src/views/settings/asset-wallet-auto-renewal/index.vue`(新增)
|
||||
- `src/router/routesAlias.ts`
|
||||
- `src/router/routes/asyncRoutes.ts`
|
||||
- `src/utils/business/notificationNavigation.ts`(确认/补充 `iot_card`、`device` 白名单)
|
||||
- `src/components/core/layouts/art-notification/index.vue`(确认 `expiry` 分类覆盖新类型)
|
||||
- `src/locales/langs/zh.json`、`src/locales/langs/en.json`
|
||||
@@ -0,0 +1,94 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 自动续费配置查询
|
||||
|
||||
The admin frontend SHALL load the single global asset wallet auto-renewal configuration through `GET /api/admin/asset-auto-renewal-config`. 响应字段 SHALL 包含并展示 `enabled`+`enabled_name`、`scope`+`scope_name`、`package_ids`、`days_before_expiry`、`config_version`、`updater`、`updated_at`。
|
||||
|
||||
#### Scenario: 读取全局自动续费配置
|
||||
|
||||
- **WHEN** 用户进入资产钱包自动续费配置页面
|
||||
- **THEN** 前端 MUST 调用 `GET /api/admin/asset-auto-renewal-config`
|
||||
- **AND** 页面 MUST 展示总开关及中文名称、适用范围及中文名称、指定主套餐集合、统一到期前天数、配置版本、最近保存操作者与最近保存时间
|
||||
|
||||
### Requirement: 自动续费配置保存
|
||||
|
||||
The admin frontend SHALL save the configuration through `PUT /api/admin/asset-auto-renewal-config` with request body `{ enabled, scope, package_ids, days_before_expiry }`。`enabled` SHALL 取值 0/1 且必填;`scope` SHALL 取值 `all`(全部主套餐)或 `specified`(指定主套餐)且必填;`package_ids` 仅在 `scope=specified` 时必填非空且只能选择当前可售主套餐;`days_before_expiry` SHALL 取值 1 至 90 且必填。配置为单行、无新增/删除;保存 SHALL 递增 `config_version` 并记录操作者与前后值快照;配置变更 SHALL 只影响后续扫描,历史记录不重算。
|
||||
|
||||
#### Scenario: 保存全部主套餐范围配置
|
||||
|
||||
- **WHEN** 用户设置适用范围为「全部主套餐」并提交
|
||||
- **THEN** 前端 MUST 调用 `PUT /api/admin/asset-auto-renewal-config`
|
||||
- **AND** 请求体携带 `enabled`、`scope=all`、`days_before_expiry`
|
||||
- **AND** `package_ids` 以空数组提交
|
||||
- **AND** 保存成功后页面 MUST 以响应中的 `config_version`、`updater`、`updated_at` 刷新展示
|
||||
|
||||
#### Scenario: 保存指定主套餐范围配置
|
||||
|
||||
- **WHEN** 用户设置适用范围为「指定主套餐」并选择若干当前可售主套餐后提交
|
||||
- **THEN** `package_ids` MUST 非空且只包含当前可售主套餐
|
||||
- **AND** 前端 MUST 携带 `scope=specified` 与非空 `package_ids` 提交
|
||||
|
||||
#### Scenario: 参数校验
|
||||
|
||||
- **WHEN** `enabled` 缺失、`scope` 非法、`scope=specified` 时 `package_ids` 为空或包含不可售套餐,或 `days_before_expiry` 超出 1–90
|
||||
- **THEN** 前端 MUST 阻止提交并给出校验提示
|
||||
|
||||
#### Scenario: 仅影响后续扫描
|
||||
|
||||
- **WHEN** 用户修改并保存配置
|
||||
- **THEN** 历史自动续费记录 MUST NOT 被重算
|
||||
- **AND** 新配置 MUST 只对保存后的扫描生效
|
||||
|
||||
### Requirement: 自动续费配置访问权限
|
||||
|
||||
Only super admin and platform accounts SHALL be allowed to query or save the asset wallet auto-renewal configuration. 代理、企业与个人客户等身份访问时 SHALL 返回 `403` 并提示「无权限操作该资源或资源不存在」;无权限与不存在的表现 MUST NOT 可区分。
|
||||
|
||||
#### Scenario: 授权访问
|
||||
|
||||
- **WHEN** 超级管理员或平台账号访问配置接口
|
||||
- **THEN** 页面 MUST 正常查询与保存配置
|
||||
|
||||
#### Scenario: 无权限访问
|
||||
|
||||
- **WHEN** 代理、企业或个人客户账号访问配置接口
|
||||
- **THEN** 页面 MUST 按 `403` 无权限处理并展示统一提示
|
||||
- **AND** 前端 MUST NOT 通过响应区分无权限与资源不存在
|
||||
|
||||
### Requirement: 自动续费失败后台通知
|
||||
|
||||
The admin notification center SHALL display the new notification type `asset.auto_renewal.failed`(类别 `expiry`、级别 `warning`)through the existing notification APIs,接收人为业务员/店铺账号。目标 `target_type` 的 `iot_card` 与 `device` SHALL 位于通知导航白名单;当目标 `available=false` 时页面 SHALL 只展示正文且不跳转;该类型通知 SHALL 计入未读数。
|
||||
|
||||
#### Scenario: 展示并跳转自动续费失败通知
|
||||
|
||||
- **WHEN** 通知列表返回 `asset.auto_renewal.failed` 类型且目标可用
|
||||
- **THEN** 通知中心 MUST 将该通知归入 `expiry` 类别展示
|
||||
- **AND** 用户点击后 MUST 通过既有目标接口按 `iot_card` / `device` 跳转到对应资产详情
|
||||
|
||||
#### Scenario: 目标不可用
|
||||
|
||||
- **WHEN** 目标接口返回 `available=false`
|
||||
- **THEN** 页面 MUST 只展示通知正文且不发起跳转
|
||||
|
||||
### Requirement: H5 客户侧通知边界
|
||||
|
||||
This capability SHALL NOT 新增或修改 H5 客户侧接口与页面。`asset.auto_renewal.failed` 类型已由后端加入客户可见白名单,通过既有 `GET /api/c/v1/notifications` 与 `unread-count` 返回;客户侧仅展示文案(资产标识、套餐、原因、到期日),无跳转接口、无需新页面。该类型属 `expiry` 类别,展示期以业务到期时间为准,套餐到期后从列表消失(既有类别行为)。
|
||||
|
||||
#### Scenario: H5 复用既有接口
|
||||
|
||||
- **WHEN** 客户侧通知接口返回该类型
|
||||
- **THEN** 客户侧 MUST 仅展示文案且不提供跳转
|
||||
- **AND** 本次变更 MUST NOT 新增 H5 客户侧接口或页面
|
||||
|
||||
#### Scenario: 到期展示期
|
||||
|
||||
- **WHEN** 对应套餐业务到期
|
||||
- **THEN** 该通知按 `expiry` 类别既有行为从客户侧列表消失
|
||||
|
||||
### Requirement: 功能范围边界
|
||||
|
||||
This capability SHALL NOT 包含以下内容:自动续费记录页/异常记录页、尝试记录查询、「有余额就不停机」开关、H5 客户侧新接口。
|
||||
|
||||
#### Scenario: 明确不提供的功能
|
||||
|
||||
- **WHEN** 前端对接本次资产钱包自动续费能力
|
||||
- **THEN** 页面 MUST NOT 提供或依赖自动续费记录页、异常记录页、尝试记录查询接口与「有余额就不停机」开关
|
||||
@@ -0,0 +1,27 @@
|
||||
# Tasks: 资产钱包自动续费配置
|
||||
|
||||
## 1. 类型与 API
|
||||
- [ ] 1.1 新增 `src/types/api/assetWallet.ts`:`AssetAutoRenewalConfig`(`enabled`/`enabled_name`/`scope`/`scope_name`/`package_ids`/`days_before_expiry`/`config_version`/`updater`/`updated_at`)、`UpdateAssetAutoRenewalConfigRequest`(`enabled`/`scope`/`package_ids`/`days_before_expiry`)等类型
|
||||
- [ ] 1.2 `src/types/api/index.ts` 导出新类型
|
||||
- [ ] 1.3 新增 `src/api/modules/assetWallet.ts`:
|
||||
- `getAutoRenewalConfig`:`GET /api/admin/asset-auto-renewal-config`
|
||||
- `saveAutoRenewalConfig`:`PUT /api/admin/asset-auto-renewal-config`
|
||||
- [ ] 1.4 `src/api/modules/index.ts` 导出新服务
|
||||
|
||||
## 2. 配置页面
|
||||
- [ ] 2.1 `src/router/routesAlias.ts` 新增资产钱包自动续费配置路由别名,`src/router/routes/asyncRoutes.ts` 在设置下注册路由与菜单(仅超级管理员与平台账号可见)
|
||||
- [ ] 2.2 新增 `src/views/settings/asset-wallet-auto-renewal/index.vue`:读取配置并展示总开关、适用范围、指定主套餐、统一到期前天数、配置版本、最近保存操作者与时间
|
||||
- [ ] 2.3 实现保存表单:总开关(0/1)、适用范围(all/specified)、到期前天数(1–90 校验);指定范围时主套餐多选仅支持当前可售主套餐且非空
|
||||
- [ ] 2.4 保存成功后使用响应刷新 `config_version`、`updater`、`updated_at`,不做新增/删除记录操作
|
||||
|
||||
## 3. 通知适配
|
||||
- [ ] 3.1 确认 `src/utils/business/notificationNavigation.ts` 白名单包含 `iot_card` 与 `device`,目标可用时跳转资产详情
|
||||
- [ ] 3.2 确认 `src/components/core/layouts/art-notification/index.vue` 的 `expiry` 分类可展示 `asset.auto_renewal.failed`,`available=false` 时只显示正文不跳转
|
||||
- [ ] 3.3 确认该类型通知计入未读数与分类汇总
|
||||
|
||||
## 4. Verification
|
||||
- [ ] 4.1 验证 GET/PUT 字段传递与参数校验(enabled、scope、package_ids、days_before_expiry)
|
||||
- [ ] 4.2 验证指定范围时 package_ids 非空且仅可售主套餐
|
||||
- [ ] 4.3 验证通知类型展示、目标跳转与不可用目标处理
|
||||
- [ ] 4.4 验证非超级管理员/平台账号访问的 403 处理
|
||||
- [ ] 4.5 运行 lint、类型检查与构建
|
||||
Reference in New Issue
Block a user