feat: 实现企业设备授权功能并归档 OpenSpec 变更
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m39s

- 新增企业设备授权模块(Model、DTO、Service、Handler、Store)
- 实现设备授权的创建、查询、更新、删除等完整业务逻辑
- 添加企业卡授权与设备授权的关联关系
- 新增 2 个数据库迁移脚本
- 同步 OpenSpec delta specs 到 main specs
- 归档 add-enterprise-device-authorization 变更
- 更新 API 文档和路由配置
- 新增完整的集成测试和单元测试覆盖
This commit is contained in:
2026-01-29 13:18:49 +08:00
parent e87513541b
commit b02175271a
118 changed files with 14306 additions and 472 deletions

View File

@@ -13,6 +13,7 @@ type StandaloneCard struct {
StatusName string `json:"status_name" description:"状态名称"`
}
// Deprecated: 已废弃,不再支持通过单卡授权接口授权设备卡,请使用设备授权接口
type DeviceBundle struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
@@ -20,12 +21,21 @@ type DeviceBundle struct {
BundleCards []DeviceBundleCard `json:"bundle_cards" description:"连带卡(同设备的其他卡)"`
}
// Deprecated: 已废弃,不再支持通过单卡授权接口授权设备卡,请使用设备授权接口
type DeviceBundleCard struct {
ICCID string `json:"iccid" description:"ICCID"`
IotCardID uint `json:"iot_card_id" description:"卡ID"`
MSISDN string `json:"msisdn" description:"手机号"`
}
// Deprecated: 已废弃,不再支持通过单卡授权接口授权设备卡,请使用设备授权接口
type AllocatedDevice struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
CardCount int `json:"card_count" description:"卡数量"`
ICCIDs []string `json:"iccids" description:"卡ICCID列表"`
}
type FailedItem struct {
ICCID string `json:"iccid" description:"ICCID"`
Reason string `json:"reason" description:"失败原因"`
@@ -41,29 +51,20 @@ type AllocatePreviewSummary struct {
type AllocateCardsPreviewResp struct {
StandaloneCards []StandaloneCard `json:"standalone_cards" description:"可直接授权的卡(未绑定设备)"`
DeviceBundles []DeviceBundle `json:"device_bundles" description:"需要整体授权的设备包"`
FailedItems []FailedItem `json:"failed_items" description:"失败的卡"`
Summary AllocatePreviewSummary `json:"summary" description:"汇总信息"`
}
type AllocateCardsReq struct {
ID uint `json:"-" params:"id" path:"id" validate:"required" required:"true" description:"企业ID"`
ICCIDs []string `json:"iccids" validate:"required,min=1,max=1000,dive,required" required:"true" description:"需要授权的 ICCID 列表"`
ConfirmDeviceBundles bool `json:"confirm_device_bundles" description:"确认整体授权设备下所有卡"`
}
type AllocatedDevice struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
CardCount int `json:"card_count" description:"卡数量"`
ICCIDs []string `json:"iccids" description:"卡ICCID列表"`
ID uint `json:"-" params:"id" path:"id" validate:"required" required:"true" description:"企业ID"`
ICCIDs []string `json:"iccids" validate:"required,min=1,max=1000,dive,required" required:"true" description:"需要授权的 ICCID 列表"`
Remark string `json:"remark" validate:"max=500" description:"授权备注"`
}
type AllocateCardsResp struct {
SuccessCount int `json:"success_count" description:"成功数量"`
FailCount int `json:"fail_count" description:"失败数量"`
FailedItems []FailedItem `json:"failed_items" description:"失败详情"`
AllocatedDevices []AllocatedDevice `json:"allocated_devices" description:"连带授权的设备列表"`
SuccessCount int `json:"success_count" description:"成功数量"`
FailCount int `json:"fail_count" description:"失败数量"`
FailedItems []FailedItem `json:"failed_items" description:"失败详情"`
}
type RecallCardsReq struct {

View File

@@ -0,0 +1,103 @@
package dto
import "time"
type AllocateDevicesReq struct {
ID uint `json:"-" params:"id" path:"id" validate:"required" required:"true" description:"企业ID"`
DeviceNos []string `json:"device_nos" validate:"required,min=1,max=100" description:"设备号列表最多100个"`
Remark string `json:"remark" validate:"max=500" description:"授权备注"`
}
type AllocateDevicesResp struct {
SuccessCount int `json:"success_count" description:"成功数量"`
FailCount int `json:"fail_count" description:"失败数量"`
FailedItems []FailedDeviceItem `json:"failed_items" description:"失败项列表"`
AuthorizedDevices []AuthorizedDeviceItem `json:"authorized_devices" description:"已授权设备列表"`
}
type FailedDeviceItem struct {
DeviceNo string `json:"device_no" description:"设备号"`
Reason string `json:"reason" description:"失败原因"`
}
type AuthorizedDeviceItem struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
CardCount int `json:"card_count" description:"绑定卡数量"`
}
type RecallDevicesReq struct {
ID uint `json:"-" params:"id" path:"id" validate:"required" required:"true" description:"企业ID"`
DeviceNos []string `json:"device_nos" validate:"required,min=1,max=100" description:"设备号列表最多100个"`
}
type RecallDevicesResp struct {
SuccessCount int `json:"success_count" description:"成功数量"`
FailCount int `json:"fail_count" description:"失败数量"`
FailedItems []FailedDeviceItem `json:"failed_items" description:"失败项列表"`
}
type EnterpriseDeviceListReq struct {
ID uint `json:"-" params:"id" path:"id" validate:"required" required:"true" description:"企业ID"`
Page int `json:"page" query:"page" validate:"required,min=1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"required,min=1,max=100" description:"每页数量"`
DeviceNo string `json:"device_no" query:"device_no" description:"设备号(模糊搜索)"`
}
type H5EnterpriseDeviceListReq struct {
Page int `json:"page" query:"page" validate:"required,min=1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"required,min=1,max=100" description:"每页数量"`
DeviceNo string `json:"device_no" query:"device_no" description:"设备号(模糊搜索)"`
}
type EnterpriseDeviceListResp struct {
List []EnterpriseDeviceItem `json:"list" description:"设备列表"`
Total int64 `json:"total" description:"总数"`
}
type EnterpriseDeviceItem struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
DeviceName string `json:"device_name" description:"设备名称"`
DeviceModel string `json:"device_model" description:"设备型号"`
CardCount int `json:"card_count" description:"绑定卡数量"`
AuthorizedAt time.Time `json:"authorized_at" description:"授权时间"`
}
type EnterpriseDeviceDetailResp struct {
Device EnterpriseDeviceInfo `json:"device" description:"设备信息"`
Cards []DeviceCardInfo `json:"cards" description:"绑定卡列表"`
}
type EnterpriseDeviceInfo struct {
DeviceID uint `json:"device_id" description:"设备ID"`
DeviceNo string `json:"device_no" description:"设备号"`
DeviceName string `json:"device_name" description:"设备名称"`
DeviceModel string `json:"device_model" description:"设备型号"`
DeviceType string `json:"device_type" description:"设备类型"`
AuthorizedAt time.Time `json:"authorized_at" description:"授权时间"`
}
type DeviceCardInfo struct {
CardID uint `json:"card_id" description:"卡ID"`
ICCID string `json:"iccid" description:"ICCID"`
MSISDN string `json:"msisdn" description:"手机号"`
CarrierName string `json:"carrier_name" description:"运营商名称"`
NetworkStatus int `json:"network_status" description:"网络状态0=停机 1=开机"`
NetworkStatusName string `json:"network_status_name" description:"网络状态名称"`
}
type DeviceDetailReq struct {
DeviceID uint `json:"-" params:"device_id" path:"device_id" validate:"required" required:"true" description:"设备ID"`
}
type DeviceCardOperationReq struct {
DeviceID uint `json:"-" params:"device_id" path:"device_id" validate:"required" required:"true" description:"设备ID"`
CardID uint `json:"-" params:"card_id" path:"card_id" validate:"required" required:"true" description:"卡ID"`
Reason string `json:"reason" validate:"max=200" description:"操作原因"`
}
type DeviceCardOperationResp struct {
Success bool `json:"success" description:"操作是否成功"`
Message string `json:"message" description:"操作结果消息"`
}

View File

@@ -21,6 +21,7 @@ type EnterpriseCardAuthorization struct {
RevokedBy *uint `gorm:"column:revoked_by;comment:回收人账号ID" json:"revoked_by"`
RevokedAt *time.Time `gorm:"column:revoked_at;comment:回收时间" json:"revoked_at"`
Remark string `gorm:"column:remark;type:varchar(500);default:'';comment:授权备注" json:"remark"`
DeviceAuthID *uint `gorm:"column:device_auth_id;comment:关联的设备授权ID" json:"device_auth_id"`
}
func (EnterpriseCardAuthorization) TableName() string {

View File

@@ -0,0 +1,26 @@
package model
import (
"time"
"gorm.io/gorm"
)
type EnterpriseDeviceAuthorization struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"deleted_at,omitempty"`
EnterpriseID uint `gorm:"column:enterprise_id;not null;comment:被授权企业ID" json:"enterprise_id"`
DeviceID uint `gorm:"column:device_id;not null;comment:被授权设备ID" json:"device_id"`
AuthorizedBy uint `gorm:"column:authorized_by;not null;comment:授权人账号ID" json:"authorized_by"`
AuthorizedAt time.Time `gorm:"column:authorized_at;not null;default:CURRENT_TIMESTAMP;comment:授权时间" json:"authorized_at"`
AuthorizerType int `gorm:"column:authorizer_type;not null;comment:授权人类型2=平台用户 3=代理账号" json:"authorizer_type"`
RevokedBy *uint `gorm:"column:revoked_by;comment:回收人账号ID" json:"revoked_by"`
RevokedAt *time.Time `gorm:"column:revoked_at;comment:回收时间" json:"revoked_at"`
Remark string `gorm:"column:remark;type:varchar(500);default:'';comment:授权备注" json:"remark"`
}
func (EnterpriseDeviceAuthorization) TableName() string {
return "tb_enterprise_device_authorization"
}