新增状态筛选条件,同时修复价格未正常写入的情况
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m35s

This commit is contained in:
2026-04-23 09:57:39 +08:00
parent a207c51bfb
commit 10a35625a5
7 changed files with 35 additions and 16 deletions

View File

@@ -1,6 +1,8 @@
package admin
import (
"strconv"
"github.com/gofiber/fiber/v2"
dto "github.com/break/junhong_cmp_fiber/internal/model/dto"
@@ -119,8 +121,17 @@ func (h *AssetHandler) Packages(c *fiber.Ctx) error {
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 50)
statusRaw := c.Query("status")
var status *int
if statusRaw != "" {
parsedStatus, parseErr := strconv.Atoi(statusRaw)
if parseErr != nil || parsedStatus < constants.PackageUsageStatusPending || parsedStatus > constants.PackageUsageStatusInvalidated {
return errors.New(errors.CodeInvalidParam)
}
status = &parsedStatus
}
result, err := h.assetService.GetPackages(c.UserContext(), asset.AssetType, asset.AssetID, page, pageSize)
result, err := h.assetService.GetPackages(c.UserContext(), asset.AssetType, asset.AssetID, page, pageSize, status)
if err != nil {
return err
}

View File

@@ -223,7 +223,7 @@ func (h *ClientAssetHandler) GetAvailablePackages(c *fiber.Ctx) error {
return errors.New(errors.CodeNoAvailablePackage, "当前无可购买套餐")
}
packagesResult, err := h.assetService.GetPackages(resolved.SkipPermissionCtx, resolved.Asset.AssetType, resolved.Asset.AssetID, 1, 50)
packagesResult, err := h.assetService.GetPackages(resolved.SkipPermissionCtx, resolved.Asset.AssetType, resolved.Asset.AssetID, 1, 50, nil)
if err != nil {
return err
}

View File

@@ -140,12 +140,12 @@ type AssetTypeIDRequest struct {
ID uint `path:"id" description:"资产ID" required:"true"`
}
// AssetPackagesRequest 资产套餐列表请求(路径参数 + 分页)
// AssetPackagesRequest 资产套餐列表请求(路径参数 + 分页 + 状态筛选
type AssetPackagesRequest struct {
AssetType string `path:"asset_type" description:"资产类型card 或 device" required:"true"`
ID uint `path:"id" description:"资产ID" required:"true"`
Page int `query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码默认1"`
PageSize int `query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页条数默认50最大100"`
Identifier string `path:"identifier" description:"资产标识符(虚拟号/ICCID/IMEI/SN/MSISDN" required:"true"`
Page int `query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码默认1"`
PageSize int `query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页条数默认50最大100"`
Status *int `query:"status" validate:"omitempty,min=0,max=4" minimum:"0" maximum:"4" description:"套餐状态 (0:待生效, 1:生效中, 2:已用完, 3:已过期, 4:已失效)"`
}
// DeviceIDRequest 设备ID请求路径参数

View File

@@ -41,9 +41,9 @@ func registerAssetRoutes(router fiber.Router, handler *admin.AssetHandler, walle
Register(assets, doc, groupPath, "GET", "/:identifier/packages", handler.Packages, RouteSpec{
Summary: "资产套餐列表",
Description: "查询该资产所有套餐记录,含虚流量换算结果。支持分页。",
Description: "查询该资产所有套餐记录,含虚流量换算结果。支持分页与 status 状态筛选。",
Tags: []string{"资产管理"},
Input: new(dto.AssetIdentifierRequest),
Input: new(dto.AssetPackagesRequest),
Output: new(dto.AssetPackagesResult),
Auth: true,
})

View File

@@ -648,9 +648,9 @@ func parseGatewayTime(raw gateway.FlexString) *time.Time {
return &t
}
// GetPackages 获取资产的所有套餐列表(支持分页)
// GetPackages 获取资产的所有套餐列表(支持分页和状态筛选
// page 默认 1pageSize 默认 50pageSize 最大 100
func (s *Service) GetPackages(ctx context.Context, assetType string, id uint, page, pageSize int) (*dto.AssetPackagesResult, error) {
func (s *Service) GetPackages(ctx context.Context, assetType string, id uint, page, pageSize int, status *int) (*dto.AssetPackagesResult, error) {
// 分页参数边界处理
if page < 1 {
page = 1
@@ -661,6 +661,9 @@ func (s *Service) GetPackages(ctx context.Context, assetType string, id uint, pa
if pageSize > 100 {
pageSize = 100
}
if status != nil && (*status < constants.PackageUsageStatusPending || *status > constants.PackageUsageStatusInvalidated) {
return nil, errors.New(errors.CodeInvalidParam, "套餐状态非法")
}
// assetType 对应 Store 中的 carrierTypecard→iot_card, device→device
carrierType := assetType
@@ -668,7 +671,7 @@ func (s *Service) GetPackages(ctx context.Context, assetType string, id uint, pa
carrierType = "iot_card"
}
usages, err := s.packageUsageStore.ListByCarrier(ctx, carrierType, id)
usages, err := s.packageUsageStore.ListByCarrier(ctx, carrierType, id, status)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询套餐使用记录失败")
}
@@ -706,7 +709,6 @@ func (s *Service) GetPackages(ctx context.Context, assetType string, id uint, pa
pkgType = pkg.PackageType
enableVirtualData = pkg.EnableVirtualData
}
item := &dto.AssetPackageResponse{
PackageUsageID: u.ID,
PackageID: u.PackageID,
@@ -784,7 +786,6 @@ func (s *Service) GetCurrentPackage(ctx context.Context, assetType string, id ui
pkgType = pkg.PackageType
enableVirtualData = pkg.EnableVirtualData
}
return &dto.AssetPackageResponse{
PackageUsageID: usage.ID,
PackageID: usage.PackageID,

View File

@@ -1452,6 +1452,10 @@ func (s *Service) HandlePaymentCallback(ctx context.Context, orderNo string, pay
}
}
// 回调更新成功后,同步内存对象,确保激活套餐时写入 paid_amount 快照
actualPaidAmountSnapshot := actualPaidAmount
order.ActualPaidAmount = &actualPaidAmountSnapshot
return s.activatePackage(ctx, tx, order)
})

View File

@@ -212,8 +212,8 @@ func (s *PackageUsageStore) GetActiveOrDepletedByCarrier(ctx context.Context, ca
return &pkg, nil
}
// ListByCarrier 查询载体的所有套餐使用记录(包括所有状态
func (s *PackageUsageStore) ListByCarrier(ctx context.Context, carrierType string, carrierID uint) ([]*model.PackageUsage, error) {
// ListByCarrier 查询载体的套餐使用记录(可按状态筛选
func (s *PackageUsageStore) ListByCarrier(ctx context.Context, carrierType string, carrierID uint, status *int) ([]*model.PackageUsage, error) {
var usages []*model.PackageUsage
query := s.db.WithContext(ctx).Order("priority ASC, created_at DESC")
@@ -222,6 +222,9 @@ func (s *PackageUsageStore) ListByCarrier(ctx context.Context, carrierType strin
} else if carrierType == "device" {
query = query.Where("device_id = ?", carrierID)
}
if status != nil {
query = query.Where("status = ?", *status)
}
if err := query.Find(&usages).Error; err != nil {
return nil, err