This commit is contained in:
@@ -70,9 +70,16 @@ func (c *Client) RebootDevice(ctx context.Context, req *DeviceOperationReq) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SwitchMode 设置设备切卡模式
|
// SwitchMode 设置设备切卡模式
|
||||||
|
// Gateway 实际要求 cardNo 传设备 IMEI,switch_mode 传字符串,并且必须指定目标 ICCID
|
||||||
// 切换设备卡槽的自动/手动模式,0=自动切卡,1=手动切卡
|
// 切换设备卡槽的自动/手动模式,0=自动切卡,1=手动切卡
|
||||||
// POST /device/SwitchMode
|
// POST /device/SwitchMode
|
||||||
func (c *Client) SwitchMode(ctx context.Context, req *SwitchModeReq) error {
|
func (c *Client) SwitchMode(ctx context.Context, req *SwitchModeReq) error {
|
||||||
|
if req.CardNo == "" {
|
||||||
|
return errors.New(errors.CodeInvalidParam, "cardNo 不能为空")
|
||||||
|
}
|
||||||
|
if req.ICCID == "" {
|
||||||
|
return errors.New(errors.CodeInvalidParam, "iccid 不能为空")
|
||||||
|
}
|
||||||
_, err := c.doRequest(ctx, "/device/SwitchMode", req)
|
_, err := c.doRequest(ctx, "/device/SwitchMode", req)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,7 +193,8 @@ type DeviceOperationReq struct {
|
|||||||
// SwitchModeReq 是设置设备切卡模式的请求
|
// SwitchModeReq 是设置设备切卡模式的请求
|
||||||
type SwitchModeReq struct {
|
type SwitchModeReq struct {
|
||||||
CardNo string `json:"cardNo" validate:"required" required:"true" description:"设备编号(IMEI)"`
|
CardNo string `json:"cardNo" validate:"required" required:"true" description:"设备编号(IMEI)"`
|
||||||
SwitchMode int `json:"switch_mode" description:"切卡模式(0:自动切卡, 1:手动切卡)"`
|
SwitchMode string `json:"switch_mode" description:"切卡模式(0:自动切卡, 1:手动切卡)"`
|
||||||
|
ICCID string `json:"iccid" validate:"required" required:"true" description:"目标卡 ICCID"`
|
||||||
CallbackURL string `json:"callbackUrl,omitempty" description:"异步回调通知地址"`
|
CallbackURL string `json:"callbackUrl,omitempty" description:"异步回调通知地址"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,15 @@ func (h *DeviceHandler) SetSwitchMode(c *fiber.Ctx) error {
|
|||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||||
}
|
}
|
||||||
|
if req.SwitchMode == nil {
|
||||||
|
return errors.New(errors.CodeInvalidParam, "切卡模式不能为空")
|
||||||
|
}
|
||||||
|
if *req.SwitchMode != 0 && *req.SwitchMode != 1 {
|
||||||
|
return errors.New(errors.CodeInvalidParam, "切卡模式仅支持0或1")
|
||||||
|
}
|
||||||
|
if req.IotCardID == 0 {
|
||||||
|
return errors.New(errors.CodeInvalidParam, "目标卡资产ID不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.service.GatewaySwitchMode(c.UserContext(), identifier, &req); err != nil {
|
if err := h.service.GatewaySwitchMode(c.UserContext(), identifier, &req); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -183,7 +183,8 @@ type SwitchCardRequest struct {
|
|||||||
// SetSwitchModeRequest 设置切卡模式请求
|
// SetSwitchModeRequest 设置切卡模式请求
|
||||||
type SetSwitchModeRequest struct {
|
type SetSwitchModeRequest struct {
|
||||||
Identifier string `path:"identifier" description:"设备标识符(支持虚拟号/IMEI/SN)" required:"true"`
|
Identifier string `path:"identifier" description:"设备标识符(支持虚拟号/IMEI/SN)" required:"true"`
|
||||||
SwitchMode int `json:"switch_mode" validate:"oneof=0 1" required:"true" description:"切卡模式 (0:自动切卡, 1:手动切卡)"`
|
SwitchMode *int `json:"switch_mode" validate:"required,oneof=0 1" required:"true" description:"切卡模式 (0:自动切卡, 1:手动切卡)"`
|
||||||
|
IotCardID uint `json:"iot_card_id" validate:"required,min=1" required:"true" minimum:"1" description:"目标卡资产ID(必须是系统内状态正常且已实名的卡)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmptyResponse struct {
|
type EmptyResponse struct {
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ func registerDeviceRoutes(router fiber.Router, handler *admin.DeviceHandler, imp
|
|||||||
|
|
||||||
Register(devices, doc, groupPath, "POST", "/by-identifier/:identifier/switch-mode", handler.SetSwitchMode, RouteSpec{
|
Register(devices, doc, groupPath, "POST", "/by-identifier/:identifier/switch-mode", handler.SetSwitchMode, RouteSpec{
|
||||||
Summary: "设置切卡模式",
|
Summary: "设置切卡模式",
|
||||||
Description: "通过虚拟号/IMEI/SN 设置设备切卡模式(0:自动切卡, 1:手动切卡)。设备必须已配置 IMEI。",
|
Description: "通过虚拟号/IMEI/SN 设置设备切卡模式(0:自动切卡, 1:手动切卡)。设备必须已配置 IMEI,且必须指定一张系统内状态正常并已实名的目标卡资产ID。",
|
||||||
Tags: []string{"设备管理"},
|
Tags: []string{"设备管理"},
|
||||||
Input: new(dto.SetSwitchModeRequest),
|
Input: new(dto.SetSwitchModeRequest),
|
||||||
Output: new(dto.EmptyResponse),
|
Output: new(dto.EmptyResponse),
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package device
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/break/junhong_cmp_fiber/internal/gateway"
|
"github.com/break/junhong_cmp_fiber/internal/gateway"
|
||||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getGatewayDevice 通过标识符获取设备并验证 IMEI 存在
|
// getGatewayDevice 通过标识符获取设备并验证 IMEI 存在
|
||||||
@@ -344,6 +346,11 @@ func (s *Service) GatewayResetDevice(ctx context.Context, identifier string) err
|
|||||||
|
|
||||||
// GatewaySwitchMode 通过标识符设置设备切卡模式
|
// GatewaySwitchMode 通过标识符设置设备切卡模式
|
||||||
func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req *dto.SetSwitchModeRequest) error {
|
func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req *dto.SetSwitchModeRequest) error {
|
||||||
|
switchMode := 0
|
||||||
|
if req.SwitchMode != nil {
|
||||||
|
switchMode = *req.SwitchMode
|
||||||
|
}
|
||||||
|
|
||||||
device, imei, err := s.getGatewayDevice(ctx, identifier)
|
device, imei, err := s.getGatewayDevice(ctx, identifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logDeviceOperation(
|
s.logDeviceOperation(
|
||||||
@@ -355,7 +362,8 @@ func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req
|
|||||||
nil,
|
nil,
|
||||||
map[string]any{
|
map[string]any{
|
||||||
"identifier": identifier,
|
"identifier": identifier,
|
||||||
"switch_mode": req.SwitchMode,
|
"switch_mode": switchMode,
|
||||||
|
"iot_card_id": req.IotCardID,
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -364,9 +372,194 @@ func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req
|
|||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if req.SwitchMode == nil {
|
||||||
|
appErr := errors.New(errors.CodeInvalidParam, "切卡模式不能为空")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if switchMode != 0 && switchMode != 1 {
|
||||||
|
appErr := errors.New(errors.CodeInvalidParam, "切卡模式仅支持0或1")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if req.IotCardID == 0 {
|
||||||
|
appErr := errors.New(errors.CodeInvalidParam, "目标卡资产ID不能为空")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
|
||||||
|
targetCard, err := s.iotCardStore.GetByID(ctx, req.IotCardID)
|
||||||
|
if err != nil {
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
appErr := errors.New(errors.CodeNotFound, "目标卡资产不存在或无权限访问")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询目标卡资产失败")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换失败",
|
||||||
|
constants.AssetAuditResultFailed,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if _, err = s.deviceSimBindingStore.GetByDeviceAndCard(ctx, device.ID, targetCard.ID); err != nil {
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
appErr := errors.New(errors.CodeForbidden, "目标卡未绑定到当前设备,禁止设置切卡模式")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询设备卡绑定关系失败")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换失败",
|
||||||
|
constants.AssetAuditResultFailed,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if targetCard.ICCID == "" {
|
||||||
|
appErr := errors.New(errors.CodeConflict, "目标卡资产缺少ICCID,无法设置切卡模式")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if targetCard.NetworkStatus != constants.NetworkStatusOnline {
|
||||||
|
appErr := errors.New(errors.CodeForbidden, "目标卡状态异常,仅正常状态的卡允许设置切卡模式")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{
|
||||||
|
"switch_mode": switchMode,
|
||||||
|
"iot_card_id": req.IotCardID,
|
||||||
|
"iccid": targetCard.ICCID,
|
||||||
|
"network_status": targetCard.NetworkStatus,
|
||||||
|
"real_name_status": targetCard.RealNameStatus,
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if targetCard.RealNameStatus != constants.RealNameStatusVerified {
|
||||||
|
appErr := errors.New(errors.CodeForbidden, "目标卡未实名,禁止设置切卡模式")
|
||||||
|
s.logDeviceOperation(
|
||||||
|
ctx,
|
||||||
|
constants.AssetAuditOpDeviceSwitchMode,
|
||||||
|
"设备切卡模式切换被拒绝",
|
||||||
|
constants.AssetAuditResultDenied,
|
||||||
|
device,
|
||||||
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
|
map[string]any{
|
||||||
|
"switch_mode": switchMode,
|
||||||
|
"iot_card_id": req.IotCardID,
|
||||||
|
"iccid": targetCard.ICCID,
|
||||||
|
"network_status": targetCard.NetworkStatus,
|
||||||
|
"real_name_status": targetCard.RealNameStatus,
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
appErr,
|
||||||
|
)
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
if err = s.gatewayClient.SwitchMode(ctx, &gateway.SwitchModeReq{
|
if err = s.gatewayClient.SwitchMode(ctx, &gateway.SwitchModeReq{
|
||||||
CardNo: imei,
|
CardNo: imei,
|
||||||
SwitchMode: req.SwitchMode,
|
SwitchMode: strconv.Itoa(switchMode),
|
||||||
|
ICCID: targetCard.ICCID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
s.logDeviceOperation(
|
s.logDeviceOperation(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -375,7 +568,7 @@ func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req
|
|||||||
constants.AssetAuditResultFailed,
|
constants.AssetAuditResultFailed,
|
||||||
device,
|
device,
|
||||||
map[string]any{"device": deviceSnapshot(device)},
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
map[string]any{"switch_mode": req.SwitchMode},
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -391,7 +584,7 @@ func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req
|
|||||||
constants.AssetAuditResultSuccess,
|
constants.AssetAuditResultSuccess,
|
||||||
device,
|
device,
|
||||||
map[string]any{"device": deviceSnapshot(device)},
|
map[string]any{"device": deviceSnapshot(device)},
|
||||||
map[string]any{"switch_mode": req.SwitchMode},
|
map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|||||||
Reference in New Issue
Block a user