From 10a35625a569453dfb0149ce0591b24ad5afbc19 Mon Sep 17 00:00:00 2001 From: huang Date: Thu, 23 Apr 2026 09:57:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=8A=B6=E6=80=81=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E6=9D=A1=E4=BB=B6,=E5=90=8C=E6=97=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BB=B7=E6=A0=BC=E6=9C=AA=E6=AD=A3=E5=B8=B8=E5=86=99?= =?UTF-8?q?=E5=85=A5=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/handler/admin/asset.go | 13 ++++++++++++- internal/handler/app/client_asset.go | 2 +- internal/model/dto/asset_dto.go | 10 +++++----- internal/routes/asset.go | 4 ++-- internal/service/asset/service.go | 11 ++++++----- internal/service/order/service.go | 4 ++++ internal/store/postgres/package_usage_store.go | 7 +++++-- 7 files changed, 35 insertions(+), 16 deletions(-) diff --git a/internal/handler/admin/asset.go b/internal/handler/admin/asset.go index 790fef2..35ce3eb 100644 --- a/internal/handler/admin/asset.go +++ b/internal/handler/admin/asset.go @@ -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 } diff --git a/internal/handler/app/client_asset.go b/internal/handler/app/client_asset.go index 3f61fe2..52cf6e0 100644 --- a/internal/handler/app/client_asset.go +++ b/internal/handler/app/client_asset.go @@ -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 } diff --git a/internal/model/dto/asset_dto.go b/internal/model/dto/asset_dto.go index 9bd47b0..291413e 100644 --- a/internal/model/dto/asset_dto.go +++ b/internal/model/dto/asset_dto.go @@ -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请求(路径参数) diff --git a/internal/routes/asset.go b/internal/routes/asset.go index 653c363..50afbb3 100644 --- a/internal/routes/asset.go +++ b/internal/routes/asset.go @@ -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, }) diff --git a/internal/service/asset/service.go b/internal/service/asset/service.go index 295edd8..924c61a 100644 --- a/internal/service/asset/service.go +++ b/internal/service/asset/service.go @@ -648,9 +648,9 @@ func parseGatewayTime(raw gateway.FlexString) *time.Time { return &t } -// GetPackages 获取资产的所有套餐列表(支持分页) +// GetPackages 获取资产的所有套餐列表(支持分页和状态筛选) // page 默认 1,pageSize 默认 50,pageSize 最大 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 中的 carrierType:card→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, diff --git a/internal/service/order/service.go b/internal/service/order/service.go index 0c25fbd..c3256f8 100644 --- a/internal/service/order/service.go +++ b/internal/service/order/service.go @@ -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) }) diff --git a/internal/store/postgres/package_usage_store.go b/internal/store/postgres/package_usage_store.go index 47dd859..eb36a97 100644 --- a/internal/store/postgres/package_usage_store.go +++ b/internal/store/postgres/package_usage_store.go @@ -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