feat: 实现卡和设备的套餐系列绑定功能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m37s

- 添加 Device 和 IotCard 模型的 SeriesID 字段
- 实现 DeviceService 和 IotCardService 的套餐系列绑定逻辑
- 添加 DeviceStore 和 IotCardStore 的数据库操作方法
- 更新 API 接口和路由支持套餐系列绑定
- 创建数据库迁移脚本(000027_add_series_binding_fields)
- 添加完整的单元测试和集成测试
- 更新 OpenAPI 文档
- 归档 OpenSpec 变更文档

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-01-28 19:49:45 +08:00
parent 1da680a790
commit a945a4f554
38 changed files with 2906 additions and 318 deletions

View File

@@ -538,6 +538,73 @@ components:
- mode
- value
type: object
DtoBatchSetCardSeriesBindngRequest:
properties:
iccids:
description: ICCID列表
items:
type: string
maxItems: 500
minItems: 1
nullable: true
type: array
series_allocation_id:
description: 套餐系列分配ID0表示清除关联
minimum: 0
type: integer
required:
- iccids
- series_allocation_id
type: object
DtoBatchSetCardSeriesBindngResponse:
properties:
fail_count:
description: 失败数量
type: integer
failed_items:
description: 失败详情列表
items:
$ref: '#/components/schemas/DtoCardSeriesBindngFailedItem'
nullable: true
type: array
success_count:
description: 成功数量
type: integer
type: object
DtoBatchSetDeviceSeriesBindngRequest:
properties:
device_ids:
description: 设备ID列表
items:
minimum: 0
type: integer
maxItems: 500
minItems: 1
nullable: true
type: array
series_allocation_id:
description: 套餐系列分配ID0表示清除关联
minimum: 0
type: integer
required:
- device_ids
- series_allocation_id
type: object
DtoBatchSetDeviceSeriesBindngResponse:
properties:
fail_count:
description: 失败数量
type: integer
failed_items:
description: 失败详情列表
items:
$ref: '#/components/schemas/DtoDeviceSeriesBindngFailedItem'
nullable: true
type: array
success_count:
description: 成功数量
type: integer
type: object
DtoBindCardToDeviceRequest:
properties:
iot_card_id:
@@ -563,6 +630,15 @@ components:
description: 提示信息
type: string
type: object
DtoCardSeriesBindngFailedItem:
properties:
iccid:
description: ICCID
type: string
reason:
description: 失败原因
type: string
type: object
DtoCarrierPageResult:
properties:
list:
@@ -1376,6 +1452,9 @@ components:
type: object
DtoDeviceResponse:
properties:
accumulated_recharge:
description: 累计充值金额(分)
type: integer
activated_at:
description: 激活时间
format: date-time
@@ -1403,6 +1482,9 @@ components:
device_type:
description: 设备类型
type: string
first_commission_paid:
description: 一次性佣金是否已发放
type: boolean
id:
description: 设备ID
minimum: 0
@@ -1413,6 +1495,11 @@ components:
max_sim_slots:
description: 最大插槽数
type: integer
series_allocation_id:
description: 套餐系列分配ID
minimum: 0
nullable: true
type: integer
shop_id:
description: 店铺ID
minimum: 0
@@ -1432,6 +1519,19 @@ components:
format: date-time
type: string
type: object
DtoDeviceSeriesBindngFailedItem:
properties:
device_id:
description: 设备ID
minimum: 0
type: integer
device_no:
description: 设备号
type: string
reason:
description: 失败原因
type: string
type: object
DtoEnterpriseCardItem:
properties:
carrier_id:
@@ -1822,6 +1922,9 @@ components:
type: object
DtoIotCardDetailResponse:
properties:
accumulated_recharge:
description: 累计充值金额(分)
type: integer
activated_at:
description: 激活时间
format: date-time
@@ -1862,6 +1965,9 @@ components:
distribute_price:
description: 分销价(分)
type: integer
first_commission_paid:
description: 一次性佣金是否已发放
type: boolean
iccid:
description: ICCID
type: string
@@ -1881,6 +1987,11 @@ components:
real_name_status:
description: 实名状态 (0:未实名, 1:已实名)
type: integer
series_allocation_id:
description: 套餐系列分配ID
minimum: 0
nullable: true
type: integer
shop_id:
description: 店铺ID
minimum: 0
@@ -3041,6 +3152,9 @@ components:
type: object
DtoStandaloneIotCardResponse:
properties:
accumulated_recharge:
description: 累计充值金额(分)
type: integer
activated_at:
description: 激活时间
format: date-time
@@ -3081,6 +3195,9 @@ components:
distribute_price:
description: 分销价(分)
type: integer
first_commission_paid:
description: 一次性佣金是否已发放
type: boolean
iccid:
description: ICCID
type: string
@@ -3100,6 +3217,11 @@ components:
real_name_status:
description: 实名状态 (0:未实名, 1:已实名)
type: integer
series_allocation_id:
description: 套餐系列分配ID
minimum: 0
nullable: true
type: integer
shop_id:
description: 店铺ID
minimum: 0
@@ -5614,6 +5736,14 @@ paths:
minimum: 0
nullable: true
type: integer
- description: 套餐系列分配ID
in: query
name: series_allocation_id
schema:
description: 套餐系列分配ID
minimum: 0
nullable: true
type: integer
- description: 批次号
in: query
name: batch_no
@@ -6261,6 +6391,50 @@ paths:
summary: 批量回收设备
tags:
- 设备管理
/api/admin/devices/series-binding:
patch:
description: 批量设置或清除设备与套餐系列分配的关联关系。series_allocation_id 为 0 时表示清除关联。
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/DtoBatchSetDeviceSeriesBindngRequest'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/DtoBatchSetDeviceSeriesBindngResponse'
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 请求参数错误
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 未认证或认证已过期
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 无权访问
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 服务器内部错误
security:
- BearerAuth: []
summary: 批量设置设备的套餐系列绑定
tags:
- 设备管理
/api/admin/enterprises:
get:
parameters:
@@ -7081,6 +7255,50 @@ paths:
summary: 导入任务详情
tags:
- IoT卡管理
/api/admin/iot-cards/series-binding:
patch:
description: 批量设置或清除卡与套餐系列分配的关联关系。series_allocation_id 为 0 时表示清除关联。
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/DtoBatchSetCardSeriesBindngRequest'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/DtoBatchSetCardSeriesBindngResponse'
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 请求参数错误
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 未认证或认证已过期
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 无权访问
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 服务器内部错误
security:
- BearerAuth: []
summary: 批量设置卡的套餐系列绑定
tags:
- IoT卡管理
/api/admin/iot-cards/standalone:
get:
parameters:
@@ -7124,6 +7342,14 @@ paths:
minimum: 0
nullable: true
type: integer
- description: 套餐系列分配ID
in: query
name: series_allocation_id
schema:
description: 套餐系列分配ID
minimum: 0
nullable: true
type: integer
- description: ICCID(模糊查询)
in: query
name: iccid