fix(realname): DTO 更新 expiry_base 替换 enable_realname_activation REALNAME-05

- package_dto.go: CreatePackageRequest/UpdatePackageRequest/PackageResponse 三处替换
- service.go: 同步更新 DTO 映射逻辑使用 ExpiryBase
This commit is contained in:
2026-03-28 10:37:51 +08:00
parent 8f62496250
commit 244a2742c1
2 changed files with 98 additions and 98 deletions

View File

@@ -2,37 +2,37 @@ package dto
// CreatePackageRequest 创建套餐请求 // CreatePackageRequest 创建套餐请求
type CreatePackageRequest struct { type CreatePackageRequest struct {
PackageCode string `json:"package_code" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"套餐编码"` PackageCode string `json:"package_code" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"套餐编码"`
PackageName string `json:"package_name" validate:"required,min=1,max=255" required:"true" minLength:"1" maxLength:"255" description:"套餐名称"` PackageName string `json:"package_name" validate:"required,min=1,max=255" required:"true" minLength:"1" maxLength:"255" description:"套餐名称"`
SeriesID *uint `json:"series_id" validate:"omitempty" description:"套餐系列ID"` SeriesID *uint `json:"series_id" validate:"omitempty" description:"套餐系列ID"`
PackageType string `json:"package_type" validate:"required,oneof=formal addon" required:"true" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"` PackageType string `json:"package_type" validate:"required,oneof=formal addon" required:"true" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"`
DurationMonths int `json:"duration_months" validate:"required,min=1,max=120" required:"true" minimum:"1" maximum:"120" description:"套餐时长(月数)"` DurationMonths int `json:"duration_months" validate:"required,min=1,max=120" required:"true" minimum:"1" maximum:"120" description:"套餐时长(月数)"`
RealDataMB *int64 `json:"real_data_mb" validate:"omitempty,min=0" minimum:"0" description:"真流量额度(MB)"` RealDataMB *int64 `json:"real_data_mb" validate:"omitempty,min=0" minimum:"0" description:"真流量额度(MB)"`
VirtualDataMB *int64 `json:"virtual_data_mb" validate:"omitempty,min=0" minimum:"0" description:"虚流量额度(MB)"` VirtualDataMB *int64 `json:"virtual_data_mb" validate:"omitempty,min=0" minimum:"0" description:"虚流量额度(MB)"`
EnableVirtualData bool `json:"enable_virtual_data" description:"是否启用虚流量"` EnableVirtualData bool `json:"enable_virtual_data" description:"是否启用虚流量"`
SuggestedRetailPrice *int64 `json:"suggested_retail_price" validate:"omitempty,min=0" minimum:"0" description:"建议售价(分)"` SuggestedRetailPrice *int64 `json:"suggested_retail_price" validate:"omitempty,min=0" minimum:"0" description:"建议售价(分)"`
CostPrice int64 `json:"cost_price" validate:"required,min=0" required:"true" minimum:"0" description:"成本价(分)"` CostPrice int64 `json:"cost_price" validate:"required,min=0" required:"true" minimum:"0" description:"成本价(分)"`
CalendarType *string `json:"calendar_type" validate:"omitempty,oneof=natural_month by_day" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"` CalendarType *string `json:"calendar_type" validate:"omitempty,oneof=natural_month by_day" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"`
DurationDays *int `json:"duration_days" validate:"omitempty,min=1,max=3650" minimum:"1" maximum:"3650" description:"套餐天数(calendar_type=by_day时必填)"` DurationDays *int `json:"duration_days" validate:"omitempty,min=1,max=3650" minimum:"1" maximum:"3650" description:"套餐天数(calendar_type=by_day时必填)"`
DataResetCycle *string `json:"data_reset_cycle" validate:"omitempty,oneof=daily monthly yearly none" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"` DataResetCycle *string `json:"data_reset_cycle" validate:"omitempty,oneof=daily monthly yearly none" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"`
EnableRealnameActivation *bool `json:"enable_realname_activation" description:"是否启用实名激活 (true:需实名激活, false:立即激活)"` ExpiryBase string `json:"expiry_base" validate:"omitempty,oneof=from_activation from_purchase" description:"到期时间基准 (from_activation:实名激活时起算, from_purchase:购买时起算)" example:"from_activation"`
} }
// UpdatePackageRequest 更新套餐请求 // UpdatePackageRequest 更新套餐请求
type UpdatePackageRequest struct { type UpdatePackageRequest struct {
PackageName *string `json:"package_name" validate:"omitempty,min=1,max=255" minLength:"1" maxLength:"255" description:"套餐名称"` PackageName *string `json:"package_name" validate:"omitempty,min=1,max=255" minLength:"1" maxLength:"255" description:"套餐名称"`
SeriesID *uint `json:"series_id" validate:"omitempty" description:"套餐系列ID"` SeriesID *uint `json:"series_id" validate:"omitempty" description:"套餐系列ID"`
PackageType *string `json:"package_type" validate:"omitempty,oneof=formal addon" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"` PackageType *string `json:"package_type" validate:"omitempty,oneof=formal addon" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"`
DurationMonths *int `json:"duration_months" validate:"omitempty,min=1,max=120" minimum:"1" maximum:"120" description:"套餐时长(月数)"` DurationMonths *int `json:"duration_months" validate:"omitempty,min=1,max=120" minimum:"1" maximum:"120" description:"套餐时长(月数)"`
RealDataMB *int64 `json:"real_data_mb" validate:"omitempty,min=0" minimum:"0" description:"真流量额度(MB)"` RealDataMB *int64 `json:"real_data_mb" validate:"omitempty,min=0" minimum:"0" description:"真流量额度(MB)"`
VirtualDataMB *int64 `json:"virtual_data_mb" validate:"omitempty,min=0" minimum:"0" description:"虚流量额度(MB)"` VirtualDataMB *int64 `json:"virtual_data_mb" validate:"omitempty,min=0" minimum:"0" description:"虚流量额度(MB)"`
EnableVirtualData *bool `json:"enable_virtual_data" description:"是否启用虚流量"` EnableVirtualData *bool `json:"enable_virtual_data" description:"是否启用虚流量"`
SuggestedRetailPrice *int64 `json:"suggested_retail_price" validate:"omitempty,min=0" minimum:"0" description:"建议售价(分)"` SuggestedRetailPrice *int64 `json:"suggested_retail_price" validate:"omitempty,min=0" minimum:"0" description:"建议售价(分)"`
CostPrice *int64 `json:"cost_price" validate:"omitempty,min=0" minimum:"0" description:"成本价(分)"` CostPrice *int64 `json:"cost_price" validate:"omitempty,min=0" minimum:"0" description:"成本价(分)"`
CalendarType *string `json:"calendar_type" validate:"omitempty,oneof=natural_month by_day" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"` CalendarType *string `json:"calendar_type" validate:"omitempty,oneof=natural_month by_day" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"`
DurationDays *int `json:"duration_days" validate:"omitempty,min=1,max=3650" minimum:"1" maximum:"3650" description:"套餐天数(calendar_type=by_day时必填)"` DurationDays *int `json:"duration_days" validate:"omitempty,min=1,max=3650" minimum:"1" maximum:"3650" description:"套餐天数(calendar_type=by_day时必填)"`
DataResetCycle *string `json:"data_reset_cycle" validate:"omitempty,oneof=daily monthly yearly none" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"` DataResetCycle *string `json:"data_reset_cycle" validate:"omitempty,oneof=daily monthly yearly none" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"`
EnableRealnameActivation *bool `json:"enable_realname_activation" description:"是否启用实名激活 (true:需实名激活, false:立即激活)"` ExpiryBase *string `json:"expiry_base" validate:"omitempty,oneof=from_activation from_purchase" description:"到期时间基准 (from_activation:实名激活时起算, from_purchase:购买时起算)"`
} }
// PackageListRequest 套餐列表请求 // PackageListRequest 套餐列表请求
@@ -70,32 +70,32 @@ type CommissionTierInfo struct {
// PackageResponse 套餐响应 // PackageResponse 套餐响应
type PackageResponse struct { type PackageResponse struct {
ID uint `json:"id" description:"套餐ID"` ID uint `json:"id" description:"套餐ID"`
PackageCode string `json:"package_code" description:"套餐编码"` PackageCode string `json:"package_code" description:"套餐编码"`
PackageName string `json:"package_name" description:"套餐名称"` PackageName string `json:"package_name" description:"套餐名称"`
SeriesID *uint `json:"series_id" description:"套餐系列ID"` SeriesID *uint `json:"series_id" description:"套餐系列ID"`
SeriesName *string `json:"series_name" description:"套餐系列名称"` SeriesName *string `json:"series_name" description:"套餐系列名称"`
PackageType string `json:"package_type" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"` PackageType string `json:"package_type" description:"套餐类型 (formal:正式套餐, addon:附加套餐)"`
DurationMonths int `json:"duration_months" description:"套餐时长(月数)"` DurationMonths int `json:"duration_months" description:"套餐时长(月数)"`
RealDataMB int64 `json:"real_data_mb" description:"真流量额度(MB)"` RealDataMB int64 `json:"real_data_mb" description:"真流量额度(MB)"`
VirtualDataMB int64 `json:"virtual_data_mb" description:"虚流量额度(MB)"` VirtualDataMB int64 `json:"virtual_data_mb" description:"虚流量额度(MB)"`
EnableVirtualData bool `json:"enable_virtual_data" description:"是否启用虚流量"` EnableVirtualData bool `json:"enable_virtual_data" description:"是否启用虚流量"`
VirtualRatio float64 `json:"virtual_ratio" description:"虚流量比例(real_data_mb/virtual_data_mb)启用虚流量时计算否则为1.0"` VirtualRatio float64 `json:"virtual_ratio" description:"虚流量比例(real_data_mb/virtual_data_mb)启用虚流量时计算否则为1.0"`
SuggestedRetailPrice int64 `json:"suggested_retail_price" description:"建议售价(分)"` SuggestedRetailPrice int64 `json:"suggested_retail_price" description:"建议售价(分)"`
CostPrice int64 `json:"cost_price" description:"成本价(分)"` CostPrice int64 `json:"cost_price" description:"成本价(分)"`
OneTimeCommissionAmount *int64 `json:"one_time_commission_amount,omitempty" description:"一次性佣金金额(分,代理视角)"` OneTimeCommissionAmount *int64 `json:"one_time_commission_amount,omitempty" description:"一次性佣金金额(分,代理视角)"`
Status int `json:"status" description:"状态 (1:启用, 2:禁用)"` Status int `json:"status" description:"状态 (1:启用, 2:禁用)"`
ShelfStatus int `json:"shelf_status" description:"上架状态 (1:上架, 2:下架)"` ShelfStatus int `json:"shelf_status" description:"上架状态 (1:上架, 2:下架)"`
CreatedAt string `json:"created_at" description:"创建时间"` CreatedAt string `json:"created_at" description:"创建时间"`
UpdatedAt string `json:"updated_at" description:"更新时间"` UpdatedAt string `json:"updated_at" description:"更新时间"`
RetailPrice *int64 `json:"retail_price,omitempty" description:"代理零售价(分),仅代理用户可见"` RetailPrice *int64 `json:"retail_price,omitempty" description:"代理零售价(分),仅代理用户可见"`
ProfitMargin *int64 `json:"profit_margin,omitempty" description:"利润空间(分,仅代理用户可见)"` ProfitMargin *int64 `json:"profit_margin,omitempty" description:"利润空间(分,仅代理用户可见)"`
CurrentCommissionRate string `json:"current_commission_rate,omitempty" description:"当前返佣比例(仅代理用户可见)"` CurrentCommissionRate string `json:"current_commission_rate,omitempty" description:"当前返佣比例(仅代理用户可见)"`
TierInfo *CommissionTierInfo `json:"tier_info,omitempty" description:"梯度返佣信息(仅代理用户可见)"` TierInfo *CommissionTierInfo `json:"tier_info,omitempty" description:"梯度返佣信息(仅代理用户可见)"`
CalendarType string `json:"calendar_type" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"` CalendarType string `json:"calendar_type" description:"套餐周期类型 (natural_month:自然月, by_day:按天)"`
DurationDays *int `json:"duration_days,omitempty" description:"套餐天数(calendar_type=by_day时有值)"` DurationDays *int `json:"duration_days,omitempty" description:"套餐天数(calendar_type=by_day时有值)"`
DataResetCycle string `json:"data_reset_cycle" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"` DataResetCycle string `json:"data_reset_cycle" description:"流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)"`
EnableRealnameActivation bool `json:"enable_realname_activation" description:"是否启用实名激活 (true:需实名激活, false:立即激活)"` ExpiryBase string `json:"expiry_base" description:"到期时间基准 (from_activation:实名激活时起算, from_purchase:购买时起算)"`
} }
// UpdatePackageParams 更新套餐聚合参数 // UpdatePackageParams 更新套餐聚合参数

View File

@@ -123,10 +123,10 @@ func (s *Service) Create(ctx context.Context, req *dto.CreatePackageRequest) (*d
// 默认月重置 // 默认月重置
pkg.DataResetCycle = constants.PackageDataResetMonthly pkg.DataResetCycle = constants.PackageDataResetMonthly
} }
if req.EnableRealnameActivation != nil { if req.ExpiryBase != "" {
pkg.EnableRealnameActivation = *req.EnableRealnameActivation pkg.ExpiryBase = req.ExpiryBase
} else { } else {
pkg.EnableRealnameActivation = true pkg.ExpiryBase = "from_activation"
} }
pkg.VirtualRatio = calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB) pkg.VirtualRatio = calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB)
pkg.Creator = currentUserID pkg.Creator = currentUserID
@@ -225,8 +225,8 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdatePackageReq
if req.DataResetCycle != nil { if req.DataResetCycle != nil {
pkg.DataResetCycle = *req.DataResetCycle pkg.DataResetCycle = *req.DataResetCycle
} }
if req.EnableRealnameActivation != nil { if req.ExpiryBase != nil {
pkg.EnableRealnameActivation = *req.EnableRealnameActivation pkg.ExpiryBase = *req.ExpiryBase
} }
// 校验套餐周期类型和时长配置 // 校验套餐周期类型和时长配置
@@ -541,26 +541,26 @@ func (s *Service) toResponse(ctx context.Context, pkg *model.Package) *dto.Packa
} }
resp := &dto.PackageResponse{ resp := &dto.PackageResponse{
ID: pkg.ID, ID: pkg.ID,
PackageCode: pkg.PackageCode, PackageCode: pkg.PackageCode,
PackageName: pkg.PackageName, PackageName: pkg.PackageName,
SeriesID: seriesID, SeriesID: seriesID,
PackageType: pkg.PackageType, PackageType: pkg.PackageType,
DurationMonths: pkg.DurationMonths, DurationMonths: pkg.DurationMonths,
RealDataMB: pkg.RealDataMB, RealDataMB: pkg.RealDataMB,
VirtualDataMB: pkg.VirtualDataMB, VirtualDataMB: pkg.VirtualDataMB,
EnableVirtualData: pkg.EnableVirtualData, EnableVirtualData: pkg.EnableVirtualData,
VirtualRatio: calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB), VirtualRatio: calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB),
CostPrice: pkg.CostPrice, CostPrice: pkg.CostPrice,
SuggestedRetailPrice: pkg.SuggestedRetailPrice, SuggestedRetailPrice: pkg.SuggestedRetailPrice,
CalendarType: pkg.CalendarType, CalendarType: pkg.CalendarType,
DurationDays: durationDays, DurationDays: durationDays,
DataResetCycle: pkg.DataResetCycle, DataResetCycle: pkg.DataResetCycle,
EnableRealnameActivation: pkg.EnableRealnameActivation, ExpiryBase: pkg.ExpiryBase,
Status: pkg.Status, Status: pkg.Status,
ShelfStatus: pkg.ShelfStatus, ShelfStatus: pkg.ShelfStatus,
CreatedAt: pkg.CreatedAt.Format(time.RFC3339), CreatedAt: pkg.CreatedAt.Format(time.RFC3339),
UpdatedAt: pkg.UpdatedAt.Format(time.RFC3339), UpdatedAt: pkg.UpdatedAt.Format(time.RFC3339),
} }
userType := middleware.GetUserTypeFromContext(ctx) userType := middleware.GetUserTypeFromContext(ctx)
@@ -606,26 +606,26 @@ func (s *Service) toResponseWithAllocation(_ context.Context, pkg *model.Package
} }
resp := &dto.PackageResponse{ resp := &dto.PackageResponse{
ID: pkg.ID, ID: pkg.ID,
PackageCode: pkg.PackageCode, PackageCode: pkg.PackageCode,
PackageName: pkg.PackageName, PackageName: pkg.PackageName,
SeriesID: seriesID, SeriesID: seriesID,
PackageType: pkg.PackageType, PackageType: pkg.PackageType,
DurationMonths: pkg.DurationMonths, DurationMonths: pkg.DurationMonths,
RealDataMB: pkg.RealDataMB, RealDataMB: pkg.RealDataMB,
VirtualDataMB: pkg.VirtualDataMB, VirtualDataMB: pkg.VirtualDataMB,
EnableVirtualData: pkg.EnableVirtualData, EnableVirtualData: pkg.EnableVirtualData,
VirtualRatio: calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB), VirtualRatio: calculateVirtualRatio(pkg.EnableVirtualData, pkg.RealDataMB, pkg.VirtualDataMB),
CostPrice: pkg.CostPrice, CostPrice: pkg.CostPrice,
SuggestedRetailPrice: pkg.SuggestedRetailPrice, SuggestedRetailPrice: pkg.SuggestedRetailPrice,
CalendarType: pkg.CalendarType, CalendarType: pkg.CalendarType,
DurationDays: durationDays, DurationDays: durationDays,
DataResetCycle: pkg.DataResetCycle, DataResetCycle: pkg.DataResetCycle,
EnableRealnameActivation: pkg.EnableRealnameActivation, ExpiryBase: pkg.ExpiryBase,
Status: pkg.Status, Status: pkg.Status,
ShelfStatus: pkg.ShelfStatus, ShelfStatus: pkg.ShelfStatus,
CreatedAt: pkg.CreatedAt.Format(time.RFC3339), CreatedAt: pkg.CreatedAt.Format(time.RFC3339),
UpdatedAt: pkg.UpdatedAt.Format(time.RFC3339), UpdatedAt: pkg.UpdatedAt.Format(time.RFC3339),
} }
if allocationMap != nil { if allocationMap != nil {