feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
主要变更: - 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等) - 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束 - 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析 - 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合 - 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝 - Excel 工具函数优化,前端导入指引文档同步更新 - 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no - 更新 OpenAPI 文档及相关 DTO Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
dto "github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
@@ -17,12 +15,13 @@ import (
|
||||
)
|
||||
|
||||
// AssetHandler 资产管理处理器
|
||||
// 提供统一的资产解析、实时状态、套餐查询、停复机、轮询管控等接口
|
||||
// 提供统一的资产解析、实时状态、套餐查询、停复机、停用、轮询管控等接口
|
||||
type AssetHandler struct {
|
||||
assetService *assetService.Service
|
||||
deviceService *deviceService.Service
|
||||
iotCardStopResume *iotCardService.StopResumeService
|
||||
assetPolling *pollingSvc.AssetPollingService
|
||||
assetService *assetService.Service
|
||||
deviceService *deviceService.Service
|
||||
iotCardStopResume *iotCardService.StopResumeService
|
||||
assetPolling *pollingSvc.AssetPollingService
|
||||
assetLifecycleService AssetLifecycleService
|
||||
}
|
||||
|
||||
// NewAssetHandler 创建资产管理处理器
|
||||
@@ -40,6 +39,20 @@ func NewAssetHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// SetLifecycleService 注入生命周期服务(用于 Deactivate 接口)
|
||||
func (h *AssetHandler) SetLifecycleService(svc AssetLifecycleService) {
|
||||
h.assetLifecycleService = svc
|
||||
}
|
||||
|
||||
// resolveByIdentifier 通过标识符解析资产,用于各处理器的公共逻辑
|
||||
func (h *AssetHandler) resolveByIdentifier(c *fiber.Ctx) (*dto.AssetResolveResponse, error) {
|
||||
identifier := c.Params("identifier")
|
||||
if identifier == "" {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "标识符不能为空")
|
||||
}
|
||||
return h.assetService.Resolve(c.UserContext(), identifier)
|
||||
}
|
||||
|
||||
// Resolve 通过任意标识符解析资产(设备或卡)
|
||||
// GET /api/admin/assets/resolve/:identifier
|
||||
func (h *AssetHandler) Resolve(c *fiber.Ctx) error {
|
||||
@@ -57,15 +70,14 @@ func (h *AssetHandler) Resolve(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// RealtimeStatus 获取资产实时状态
|
||||
// GET /api/admin/assets/:asset_type/:id/realtime-status
|
||||
// GET /api/admin/assets/:identifier/realtime-status
|
||||
func (h *AssetHandler) RealtimeStatus(c *fiber.Ctx) error {
|
||||
assetType := c.Params("asset_type")
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.assetService.GetRealtimeStatus(c.UserContext(), assetType, uint(id))
|
||||
result, err := h.assetService.GetRealtimeStatus(c.UserContext(), asset.AssetType, asset.AssetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -74,20 +86,19 @@ func (h *AssetHandler) RealtimeStatus(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// Refresh 刷新资产状态(调网关同步)
|
||||
// POST /api/admin/assets/:asset_type/:id/refresh
|
||||
// POST /api/admin/assets/:identifier/refresh
|
||||
func (h *AssetHandler) Refresh(c *fiber.Ctx) error {
|
||||
// 企业账号只读,不允许主动触发运营商刷新
|
||||
userType := middleware.GetUserTypeFromContext(c.UserContext())
|
||||
if userType == constants.UserTypeEnterprise {
|
||||
return errors.New(errors.CodeForbidden, "企业账号无权主动刷新资产状态")
|
||||
}
|
||||
assetType := c.Params("asset_type")
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.assetService.Refresh(c.UserContext(), assetType, uint(id))
|
||||
result, err := h.assetService.Refresh(c.UserContext(), asset.AssetType, asset.AssetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -96,18 +107,17 @@ func (h *AssetHandler) Refresh(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// Packages 获取资产所有套餐列表(支持分页,默认 page=1 pageSize=50)
|
||||
// GET /api/admin/assets/:asset_type/:id/packages
|
||||
// GET /api/admin/assets/:identifier/packages
|
||||
func (h *AssetHandler) Packages(c *fiber.Ctx) error {
|
||||
assetType := c.Params("asset_type")
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
return err
|
||||
}
|
||||
|
||||
page := c.QueryInt("page", 1)
|
||||
pageSize := c.QueryInt("page_size", 50)
|
||||
|
||||
result, err := h.assetService.GetPackages(c.UserContext(), assetType, uint(id), page, pageSize)
|
||||
result, err := h.assetService.GetPackages(c.UserContext(), asset.AssetType, asset.AssetID, page, pageSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,15 +126,14 @@ func (h *AssetHandler) Packages(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// CurrentPackage 获取资产当前生效套餐
|
||||
// GET /api/admin/assets/:asset_type/:id/current-package
|
||||
// GET /api/admin/assets/:identifier/current-package
|
||||
func (h *AssetHandler) CurrentPackage(c *fiber.Ctx) error {
|
||||
assetType := c.Params("asset_type")
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.assetService.GetCurrentPackage(c.UserContext(), assetType, uint(id))
|
||||
result, err := h.assetService.GetCurrentPackage(c.UserContext(), asset.AssetType, asset.AssetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -132,15 +141,102 @@ func (h *AssetHandler) CurrentPackage(c *fiber.Ctx) error {
|
||||
return response.Success(c, result)
|
||||
}
|
||||
|
||||
// StopDevice 设备停机(批量停机设备下所有已实名卡)
|
||||
// POST /api/admin/assets/device/:device_id/stop
|
||||
func (h *AssetHandler) StopDevice(c *fiber.Ctx) error {
|
||||
deviceID, err := strconv.ParseUint(c.Params("device_id"), 10, 64)
|
||||
// Stop 停机(设备批量停机,单卡停机)
|
||||
// POST /api/admin/assets/:identifier/stop
|
||||
func (h *AssetHandler) Stop(c *fiber.Ctx) error {
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.deviceService.StopDevice(c.UserContext(), uint(deviceID))
|
||||
switch asset.AssetType {
|
||||
case "device":
|
||||
result, devErr := h.deviceService.StopDevice(c.UserContext(), asset.AssetID)
|
||||
if devErr != nil {
|
||||
return devErr
|
||||
}
|
||||
return response.Success(c, result)
|
||||
case "card":
|
||||
if asset.ICCID == "" {
|
||||
return errors.New(errors.CodeInternalError, "卡 ICCID 为空,无法停机")
|
||||
}
|
||||
if cardErr := h.iotCardStopResume.ManualStopCard(c.UserContext(), asset.ICCID); cardErr != nil {
|
||||
return cardErr
|
||||
}
|
||||
return response.Success(c, nil)
|
||||
default:
|
||||
return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
|
||||
}
|
||||
}
|
||||
|
||||
// Start 复机(设备批量复机,单卡复机)
|
||||
// POST /api/admin/assets/:identifier/start
|
||||
func (h *AssetHandler) Start(c *fiber.Ctx) error {
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch asset.AssetType {
|
||||
case "device":
|
||||
if devErr := h.deviceService.StartDevice(c.UserContext(), asset.AssetID); devErr != nil {
|
||||
return devErr
|
||||
}
|
||||
return response.Success(c, nil)
|
||||
case "card":
|
||||
if asset.ICCID == "" {
|
||||
return errors.New(errors.CodeInternalError, "卡 ICCID 为空,无法复机")
|
||||
}
|
||||
if cardErr := h.iotCardStopResume.ManualStartCard(c.UserContext(), asset.ICCID); cardErr != nil {
|
||||
return cardErr
|
||||
}
|
||||
return response.Success(c, nil)
|
||||
default:
|
||||
return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
|
||||
}
|
||||
}
|
||||
|
||||
// Deactivate 停用资产
|
||||
// PATCH /api/admin/assets/:identifier/deactivate
|
||||
func (h *AssetHandler) Deactivate(c *fiber.Ctx) error {
|
||||
if h.assetLifecycleService == nil {
|
||||
return errors.New(errors.CodeInternalError, "资产生命周期服务未配置")
|
||||
}
|
||||
|
||||
asset, err := h.resolveByIdentifier(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch asset.AssetType {
|
||||
case "device":
|
||||
if devErr := h.assetLifecycleService.DeactivateDevice(c.UserContext(), asset.AssetID); devErr != nil {
|
||||
return devErr
|
||||
}
|
||||
case "card":
|
||||
if cardErr := h.assetLifecycleService.DeactivateIotCard(c.UserContext(), asset.AssetID); cardErr != nil {
|
||||
return cardErr
|
||||
}
|
||||
default:
|
||||
return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
|
||||
}
|
||||
|
||||
return response.Success(c, nil)
|
||||
}
|
||||
|
||||
// Orders 查询资产历史订单(支持跨代追溯)
|
||||
// GET /api/admin/assets/:identifier/orders
|
||||
func (h *AssetHandler) Orders(c *fiber.Ctx) error {
|
||||
identifier := c.Params("identifier")
|
||||
if identifier == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "标识符不能为空")
|
||||
}
|
||||
|
||||
page := c.QueryInt("page", 1)
|
||||
pageSize := c.QueryInt("page_size", 20)
|
||||
includePrevious := c.QueryBool("include_previous", false)
|
||||
|
||||
result, err := h.assetService.GetOrders(c.UserContext(), identifier, page, pageSize, includePrevious)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -148,63 +244,11 @@ func (h *AssetHandler) StopDevice(c *fiber.Ctx) error {
|
||||
return response.Success(c, result)
|
||||
}
|
||||
|
||||
// StartDevice 设备复机(批量复机设备下所有已实名卡)
|
||||
// POST /api/admin/assets/device/:device_id/start
|
||||
func (h *AssetHandler) StartDevice(c *fiber.Ctx) error {
|
||||
deviceID, err := strconv.ParseUint(c.Params("device_id"), 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
}
|
||||
|
||||
if err := h.deviceService.StartDevice(c.UserContext(), uint(deviceID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, nil)
|
||||
}
|
||||
|
||||
// StopCard 单卡停机(通过ICCID)
|
||||
// POST /api/admin/assets/card/:iccid/stop
|
||||
func (h *AssetHandler) StopCard(c *fiber.Ctx) error {
|
||||
iccid := c.Params("iccid")
|
||||
if iccid == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "ICCID不能为空")
|
||||
}
|
||||
|
||||
if err := h.iotCardStopResume.ManualStopCard(c.UserContext(), iccid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, nil)
|
||||
}
|
||||
|
||||
// StartCard 单卡复机(通过ICCID)
|
||||
// POST /api/admin/assets/card/:iccid/start
|
||||
func (h *AssetHandler) StartCard(c *fiber.Ctx) error {
|
||||
iccid := c.Params("iccid")
|
||||
if iccid == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "ICCID不能为空")
|
||||
}
|
||||
|
||||
if err := h.iotCardStopResume.ManualStartCard(c.UserContext(), iccid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, nil)
|
||||
}
|
||||
|
||||
// UpdatePollingStatus 更新资产轮询状态
|
||||
// PATCH /api/admin/assets/:asset_type/:id/polling-status
|
||||
// PATCH /api/admin/assets/:identifier/polling-status
|
||||
func (h *AssetHandler) UpdatePollingStatus(c *fiber.Ctx) error {
|
||||
assetType := c.Params("asset_type")
|
||||
idStr := c.Params("id")
|
||||
|
||||
if assetType == "" || idStr == "" {
|
||||
return errors.New(errors.CodeInvalidParam)
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
identifier := c.Params("identifier")
|
||||
if identifier == "" {
|
||||
return errors.New(errors.CodeInvalidParam)
|
||||
}
|
||||
|
||||
@@ -213,19 +257,29 @@ func (h *AssetHandler) UpdatePollingStatus(c *fiber.Ctx) error {
|
||||
return errors.New(errors.CodeInvalidParam)
|
||||
}
|
||||
|
||||
asset, err := h.assetService.Resolve(c.UserContext(), identifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = middleware.GetUserIDFromContext(c.UserContext())
|
||||
|
||||
if h.assetPolling == nil {
|
||||
return errors.New(errors.CodeInternalError, "轮询管控服务未配置")
|
||||
}
|
||||
|
||||
if err := h.assetPolling.UpdatePollingStatus(c.UserContext(), assetType, uint(id), req.EnablePolling); err != nil {
|
||||
pollingAssetType := asset.AssetType
|
||||
if pollingAssetType == "card" {
|
||||
pollingAssetType = "iot_card"
|
||||
}
|
||||
|
||||
if err := h.assetPolling.UpdatePollingStatus(c.UserContext(), pollingAssetType, asset.AssetID, req.EnablePolling); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, &dto.UpdateAssetPollingStatusResponse{
|
||||
AssetType: assetType,
|
||||
AssetID: uint(id),
|
||||
AssetType: asset.AssetType,
|
||||
AssetID: asset.AssetID,
|
||||
EnablePolling: req.EnablePolling,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
assetSvc "github.com/break/junhong_cmp_fiber/internal/service/asset"
|
||||
assetWalletSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_wallet"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
@@ -16,7 +15,8 @@ import (
|
||||
// AssetWalletHandler 资产钱包处理器
|
||||
// 提供管理端资产(卡/设备)钱包概况和流水查询接口
|
||||
type AssetWalletHandler struct {
|
||||
service *assetWalletSvc.Service
|
||||
service *assetWalletSvc.Service
|
||||
assetService *assetSvc.Service
|
||||
}
|
||||
|
||||
// NewAssetWalletHandler 创建资产钱包处理器
|
||||
@@ -24,26 +24,34 @@ func NewAssetWalletHandler(svc *assetWalletSvc.Service) *AssetWalletHandler {
|
||||
return &AssetWalletHandler{service: svc}
|
||||
}
|
||||
|
||||
// SetAssetService 注入资产解析服务(用于通过标识符解析资产类型和ID)
|
||||
func (h *AssetWalletHandler) SetAssetService(svc *assetSvc.Service) {
|
||||
h.assetService = svc
|
||||
}
|
||||
|
||||
// GetWallet 查询资产钱包概况
|
||||
// GET /api/admin/assets/:asset_type/:id/wallet
|
||||
// GET /api/admin/assets/:identifier/wallet
|
||||
func (h *AssetWalletHandler) GetWallet(c *fiber.Ctx) error {
|
||||
userType := middleware.GetUserTypeFromContext(c.UserContext())
|
||||
if userType == constants.UserTypeEnterprise {
|
||||
return errors.New(errors.CodeForbidden, "企业账号无权查看钱包信息")
|
||||
}
|
||||
|
||||
assetType := c.Params("asset_type")
|
||||
if assetType != "card" && assetType != "device" {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产类型")
|
||||
identifier := c.Params("identifier")
|
||||
if identifier == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "标识符不能为空")
|
||||
}
|
||||
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
if h.assetService == nil {
|
||||
return errors.New(errors.CodeInternalError, "资产服务未配置")
|
||||
}
|
||||
|
||||
result, err := h.service.GetWallet(c.UserContext(), assetType, uint(id))
|
||||
asset, err := h.assetService.Resolve(c.UserContext(), identifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.service.GetWallet(c.UserContext(), asset.AssetType, asset.AssetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -52,22 +60,25 @@ func (h *AssetWalletHandler) GetWallet(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// ListTransactions 查询资产钱包流水列表
|
||||
// GET /api/admin/assets/:asset_type/:id/wallet/transactions
|
||||
// GET /api/admin/assets/:identifier/wallet/transactions
|
||||
func (h *AssetWalletHandler) ListTransactions(c *fiber.Ctx) error {
|
||||
userType := middleware.GetUserTypeFromContext(c.UserContext())
|
||||
if userType == constants.UserTypeEnterprise {
|
||||
return errors.New(errors.CodeForbidden, "企业账号无权查看钱包信息")
|
||||
}
|
||||
|
||||
assetType := c.Params("asset_type")
|
||||
if assetType != "card" && assetType != "device" {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产类型")
|
||||
identifier := c.Params("identifier")
|
||||
if identifier == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "标识符不能为空")
|
||||
}
|
||||
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
|
||||
if h.assetService == nil {
|
||||
return errors.New(errors.CodeInternalError, "资产服务未配置")
|
||||
}
|
||||
|
||||
asset, err := h.assetService.Resolve(c.UserContext(), identifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req dto.AssetWalletTransactionListRequest
|
||||
@@ -79,7 +90,7 @@ func (h *AssetWalletHandler) ListTransactions(c *fiber.Ctx) error {
|
||||
return errors.New(errors.CodeInvalidParam, "每页数量不能超过100")
|
||||
}
|
||||
|
||||
result, err := h.service.ListTransactions(c.UserContext(), assetType, uint(id), &req)
|
||||
result, err := h.service.ListTransactions(c.UserContext(), asset.AssetType, asset.AssetID, &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
@@ -43,13 +41,17 @@ func (h *DeviceHandler) Delete(c *fiber.Ctx) error {
|
||||
return errors.New(errors.CodeForbidden, "仅平台用户可删除设备")
|
||||
}
|
||||
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
virtualNo := c.Params("virtual_no")
|
||||
if virtualNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "虚拟号不能为空")
|
||||
}
|
||||
|
||||
if err := h.service.Delete(c.UserContext(), uint(id)); err != nil {
|
||||
device, err := h.service.GetByVirtualNo(c.UserContext(), virtualNo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.service.Delete(c.UserContext(), device.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -57,13 +59,17 @@ func (h *DeviceHandler) Delete(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func (h *DeviceHandler) ListCards(c *fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
virtualNo := c.Params("virtual_no")
|
||||
if virtualNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "虚拟号不能为空")
|
||||
}
|
||||
|
||||
result, err := h.service.ListBindings(c.UserContext(), uint(id))
|
||||
device, err := h.service.GetByVirtualNo(c.UserContext(), virtualNo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.service.ListBindings(c.UserContext(), device.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -77,19 +83,23 @@ func (h *DeviceHandler) BindCard(c *fiber.Ctx) error {
|
||||
return errors.New(errors.CodeForbidden, "仅平台用户可绑定卡到设备")
|
||||
}
|
||||
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
virtualNo := c.Params("virtual_no")
|
||||
if virtualNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "虚拟号不能为空")
|
||||
}
|
||||
|
||||
device, err := h.service.GetByVirtualNo(c.UserContext(), virtualNo)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
return err
|
||||
}
|
||||
|
||||
var req dto.BindCardToDeviceRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
req.ID = uint(id)
|
||||
req.ID = device.ID
|
||||
|
||||
result, err := h.service.BindCard(c.UserContext(), uint(id), &req)
|
||||
result, err := h.service.BindCard(c.UserContext(), device.ID, &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -103,19 +113,27 @@ func (h *DeviceHandler) UnbindCard(c *fiber.Ctx) error {
|
||||
return errors.New(errors.CodeForbidden, "仅平台用户可解绑设备的卡")
|
||||
}
|
||||
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
|
||||
virtualNo := c.Params("virtual_no")
|
||||
if virtualNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "虚拟号不能为空")
|
||||
}
|
||||
|
||||
cardIdStr := c.Params("cardId")
|
||||
cardId, err := strconv.ParseUint(cardIdStr, 10, 64)
|
||||
device, err := h.service.GetByVirtualNo(c.UserContext(), virtualNo)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的卡ID")
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := h.service.UnbindCard(c.UserContext(), uint(id), uint(cardId))
|
||||
iccid := c.Params("iccid")
|
||||
if iccid == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "ICCID 不能为空")
|
||||
}
|
||||
|
||||
card, cardErr := h.service.GetCardByICCID(c.UserContext(), iccid)
|
||||
if cardErr != nil {
|
||||
return cardErr
|
||||
}
|
||||
|
||||
result, err := h.service.UnbindCard(c.UserContext(), device.ID, card.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user