feat: 资产套餐历史增加主子层级查询

This commit is contained in:
2026-09-07 17:17:15 +08:00
parent c7c2b17d78
commit 696120ab38
18 changed files with 1030 additions and 236 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/break/junhong_cmp_fiber/internal/middleware"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
assetquery "github.com/break/junhong_cmp_fiber/internal/query/asset"
asset "github.com/break/junhong_cmp_fiber/internal/service/asset"
customerBinding "github.com/break/junhong_cmp_fiber/internal/service/customer_binding"
packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
@@ -462,7 +463,7 @@ func (h *ClientAssetHandler) GetAvailablePackages(c *fiber.Ctx) error {
return response.Success(c, &dto.AssetPackageListResponse{Packages: items})
}
// GetPackageHistory B3 资产套餐历史
// GetPackageHistory B3 资产套餐历史
// GET /api/c/v1/asset/package-history
func (h *ClientAssetHandler) GetPackageHistory(c *fiber.Ctx) error {
var req dto.AssetPackageHistoryRequest
@@ -485,73 +486,93 @@ func (h *ClientAssetHandler) GetPackageHistory(c *fiber.Ctx) error {
return err
}
query := h.db.WithContext(resolved.SkipPermissionCtx).Model(&model.PackageUsage{}).
Where("generation = ?", resolved.Generation)
if resolved.Asset.AssetType == "card" {
query = query.Where("iot_card_id = ?", resolved.Asset.AssetID)
} else {
query = query.Where("device_id = ?", resolved.Asset.AssetID)
}
if req.Status != nil {
query = query.Where("status = ?", *req.Status)
}
if req.PackageType != nil {
query = query.Where("package_id IN (?)",
h.db.Model(&model.Package{}).Select("id").Where("package_type = ?", *req.PackageType))
}
var total int64
if err := query.Count(&total).Error; err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "查询套餐历史总数失败")
}
var usages []*model.PackageUsage
offset := (req.Page - 1) * req.PageSize
if err := query.Order("created_at DESC").Offset(offset).Limit(req.PageSize).Find(&usages).Error; err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "查询套餐历史失败")
}
packageMap, err := h.loadPackageMap(resolved.SkipPermissionCtx, usages)
history, err := assetquery.NewPackageHistoryQuery(h.db).List(resolved.SkipPermissionCtx, assetquery.PackageHistoryInput{
AssetType: resolved.Asset.AssetType,
AssetID: resolved.Asset.AssetID,
Generation: &resolved.Generation,
Status: req.Status,
PackageType: req.PackageType,
Page: req.Page,
PageSize: req.PageSize,
})
if err != nil {
return err
}
list := make([]dto.AssetPackageResponse, 0, len(usages))
for _, usage := range usages {
pkg := packageMap[usage.PackageID]
metrics := usage.BuildTrafficMetrics()
pkgName := usage.PackageName
pkgType := ""
if pkg != nil {
if pkgName == "" {
pkgName = pkg.PackageName
}
pkgType = pkg.PackageType
}
list = append(list, dto.AssetPackageResponse{
PackageUsageID: usage.ID,
PackageID: usage.PackageID,
PackageName: pkgName,
PackageType: pkgType,
UsageType: usage.UsageType,
Status: usage.Status,
StatusName: packageStatusName(usage.Status),
RealTotalMB: metrics.RealTotalMB,
RealUsedMB: metrics.RealUsedMB,
VirtualTotalMB: metrics.VirtualTotalMB,
VirtualUsedMB: metrics.VirtualUsedMB,
ReductionPct: metrics.ReductionPct,
EnableVirtualData: usage.EnableVirtualDataSnapshot,
ActivatedAt: usage.ActivatedAt,
ExpiresAt: usage.ExpiresAt,
MasterUsageID: usage.MasterUsageID,
Priority: usage.Priority,
CreatedAt: usage.CreatedAt,
})
packageMap, err := h.loadPackageMap(resolved.SkipPermissionCtx, collectPackageHistoryUsages(history.Items))
if err != nil {
return err
}
return response.SuccessWithPagination(c, list, total, req.Page, req.PageSize)
items := make([]*dto.ClientAssetPackageHistoryNode, 0, len(history.Items))
for _, node := range history.Items {
items = append(items, buildClientPackageHistoryNode(node, packageMap))
}
return response.SuccessWithPagination(c, items, history.Total, req.Page, req.PageSize)
}
func collectPackageHistoryUsages(items []*assetquery.PackageHistoryNode) []*model.PackageUsage {
usages := make([]*model.PackageUsage, 0)
var collect func(*assetquery.PackageHistoryNode)
collect = func(node *assetquery.PackageHistoryNode) {
if node == nil || node.Usage == nil {
return
}
usages = append(usages, node.Usage)
for _, child := range node.Children {
collect(child)
}
}
for _, item := range items {
collect(item)
}
return usages
}
func buildClientPackageHistoryNode(node *assetquery.PackageHistoryNode, packageMap map[uint]*model.Package) *dto.ClientAssetPackageHistoryNode {
usage := node.Usage
pkg := packageMap[usage.PackageID]
metrics := usage.BuildTrafficMetrics()
packageName := usage.PackageName
packageType := ""
if pkg != nil {
if packageName == "" {
packageName = pkg.PackageName
}
packageType = pkg.PackageType
}
item := &dto.ClientAssetPackageHistoryNode{
PackageUsageID: usage.ID,
PackageID: usage.PackageID,
PackageName: packageName,
PackageType: packageType,
UsageType: usage.UsageType,
Status: usage.Status,
StatusName: packageStatusName(usage.Status),
RealTotalMB: metrics.RealTotalMB,
RealUsedMB: metrics.RealUsedMB,
VirtualTotalMB: metrics.VirtualTotalMB,
VirtualUsedMB: metrics.VirtualUsedMB,
ReductionPct: metrics.ReductionPct,
EnableVirtualData: usage.EnableVirtualDataSnapshot,
ActivatedAt: usage.ActivatedAt,
ExpiresAt: usage.ExpiresAt,
MasterUsageID: usage.MasterUsageID,
Priority: usage.Priority,
CreatedAt: usage.CreatedAt,
Children: make([]*dto.ClientAssetPackageHistoryNode, 0, len(node.Children)),
}
if node.RelationshipStatus != "" {
item.RelationshipStatus = node.RelationshipStatus
item.RelationshipStatusName = "关联主套餐缺失"
}
for _, child := range node.Children {
item.Children = append(item.Children, buildClientPackageHistoryNode(child, packageMap))
}
item.ExpandByDefault = len(item.Children) > 0
return item
}
// RefreshAsset B4 资产刷新