Files
junhong_cmp_fiber/internal/handler/admin/asset.go
huang 2a92ab64af fix(perm): 修复企业账号资产权限边界 PERM-01/02
- PERM-01: 删除 Resolve 接口对企业账号的错误拦截(企业账号应可查询资产)
- PERM-02: 在 Refresh 接口开头新增企业账号拦截(企业账号只读,不允许主动触发运营商刷新)
2026-03-28 10:36:17 +08:00

187 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package admin
import (
"strconv"
"github.com/gofiber/fiber/v2"
assetService "github.com/break/junhong_cmp_fiber/internal/service/asset"
deviceService "github.com/break/junhong_cmp_fiber/internal/service/device"
iotCardService "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"github.com/break/junhong_cmp_fiber/pkg/response"
)
// AssetHandler 资产管理处理器
// 提供统一的资产解析、实时状态、套餐查询、停复机等接口
type AssetHandler struct {
assetService *assetService.Service
deviceService *deviceService.Service
iotCardStopResume *iotCardService.StopResumeService
}
// NewAssetHandler 创建资产管理处理器
func NewAssetHandler(
assetSvc *assetService.Service,
deviceSvc *deviceService.Service,
iotCardStopResume *iotCardService.StopResumeService,
) *AssetHandler {
return &AssetHandler{
assetService: assetSvc,
deviceService: deviceSvc,
iotCardStopResume: iotCardStopResume,
}
}
// Resolve 通过任意标识符解析资产(设备或卡)
// GET /api/admin/assets/resolve/:identifier
func (h *AssetHandler) Resolve(c *fiber.Ctx) error {
identifier := c.Params("identifier")
if identifier == "" {
return errors.New(errors.CodeInvalidParam, "标识符不能为空")
}
result, err := h.assetService.Resolve(c.UserContext(), identifier)
if err != nil {
return err
}
return response.Success(c, result)
}
// RealtimeStatus 获取资产实时状态
// GET /api/admin/assets/:asset_type/:id/realtime-status
func (h *AssetHandler) RealtimeStatus(c *fiber.Ctx) error {
assetType := c.Params("asset_type")
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
}
result, err := h.assetService.GetRealtimeStatus(c.UserContext(), assetType, uint(id))
if err != nil {
return err
}
return response.Success(c, result)
}
// Refresh 刷新资产状态(调网关同步)
// POST /api/admin/assets/:asset_type/:id/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)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
}
result, err := h.assetService.Refresh(c.UserContext(), assetType, uint(id))
if err != nil {
return err
}
return response.Success(c, result)
}
// Packages 获取资产所有套餐列表
// GET /api/admin/assets/:asset_type/:id/packages
func (h *AssetHandler) Packages(c *fiber.Ctx) error {
assetType := c.Params("asset_type")
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
}
result, err := h.assetService.GetPackages(c.UserContext(), assetType, uint(id))
if err != nil {
return err
}
return response.Success(c, result)
}
// CurrentPackage 获取资产当前生效套餐
// GET /api/admin/assets/:asset_type/:id/current-package
func (h *AssetHandler) CurrentPackage(c *fiber.Ctx) error {
assetType := c.Params("asset_type")
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的资产ID")
}
result, err := h.assetService.GetCurrentPackage(c.UserContext(), assetType, uint(id))
if err != nil {
return err
}
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)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的设备ID")
}
result, err := h.deviceService.StopDevice(c.UserContext(), uint(deviceID))
if err != nil {
return err
}
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)
}