feat:修改藏品等级硬编码改为根据数据库的配置来定义
This commit is contained in:
parent
8dce6ae11a
commit
7c5d5a7275
@ -119,3 +119,20 @@ var LevelOrderMap = map[string]int{
|
|||||||
LevelSSR: 4,
|
LevelSSR: 4,
|
||||||
LevelUR: 5,
|
LevelUR: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LevelToGradeMap 等级字符串到前端Grade的映射(1-5)
|
||||||
|
var LevelToGradeMap = map[string]int{
|
||||||
|
LevelN: 1,
|
||||||
|
LevelR: 2,
|
||||||
|
LevelSR: 3,
|
||||||
|
LevelSSR: 4,
|
||||||
|
LevelUR: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// LevelToGrade 将等级字符串转换为前端Grade
|
||||||
|
func LevelToGrade(level string) int {
|
||||||
|
if grade, ok := LevelToGradeMap[level]; ok {
|
||||||
|
return grade
|
||||||
|
}
|
||||||
|
return 1 // 默认返回1
|
||||||
|
}
|
||||||
|
|||||||
@ -1726,6 +1726,7 @@ type OnExhibitionCompletedRequest struct {
|
|||||||
CrystalAmount int64 `protobuf:"varint,7,opt,name=crystal_amount,json=crystalAmount,proto3" json:"crystal_amount,omitempty"`
|
CrystalAmount int64 `protobuf:"varint,7,opt,name=crystal_amount,json=crystalAmount,proto3" json:"crystal_amount,omitempty"`
|
||||||
StartTime int64 `protobuf:"varint,8,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
|
StartTime int64 `protobuf:"varint,8,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
|
||||||
ExpireAt int64 `protobuf:"varint,9,opt,name=expire_at,json=expireAt,proto3" json:"expire_at,omitempty"`
|
ExpireAt int64 `protobuf:"varint,9,opt,name=expire_at,json=expireAt,proto3" json:"expire_at,omitempty"`
|
||||||
|
LikeCount int32 `protobuf:"varint,10,opt,name=like_count,json=likeCount,proto3" json:"like_count,omitempty"` // 点赞数,用于在taskService中根据资产等级重新计算收益
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@ -1823,6 +1824,13 @@ func (x *OnExhibitionCompletedRequest) GetExpireAt() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *OnExhibitionCompletedRequest) GetLikeCount() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.LikeCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type OnExhibitionCompletedResponse struct {
|
type OnExhibitionCompletedResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||||
@ -2001,7 +2009,7 @@ const file_task_proto_rawDesc = "" +
|
|||||||
"\astar_id\x18\x02 \x01(\x03R\x06starId\"c\n" +
|
"\astar_id\x18\x02 \x01(\x03R\x06starId\"c\n" +
|
||||||
"\x15InitUserTasksResponse\x120\n" +
|
"\x15InitUserTasksResponse\x120\n" +
|
||||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12\x18\n" +
|
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12\x18\n" +
|
||||||
"\asuccess\x18\x02 \x01(\bR\asuccess\"\xcd\x02\n" +
|
"\asuccess\x18\x02 \x01(\bR\asuccess\"\xec\x02\n" +
|
||||||
"\x1cOnExhibitionCompletedRequest\x12#\n" +
|
"\x1cOnExhibitionCompletedRequest\x12#\n" +
|
||||||
"\rexhibition_id\x18\x01 \x01(\x03R\fexhibitionId\x12\x19\n" +
|
"\rexhibition_id\x18\x01 \x01(\x03R\fexhibitionId\x12\x19\n" +
|
||||||
"\basset_id\x18\x02 \x01(\x03R\aassetId\x12\x17\n" +
|
"\basset_id\x18\x02 \x01(\x03R\aassetId\x12\x17\n" +
|
||||||
@ -2012,7 +2020,10 @@ const file_task_proto_rawDesc = "" +
|
|||||||
"\x0ecrystal_amount\x18\a \x01(\x03R\rcrystalAmount\x12\x1d\n" +
|
"\x0ecrystal_amount\x18\a \x01(\x03R\rcrystalAmount\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"start_time\x18\b \x01(\x03R\tstartTime\x12\x1b\n" +
|
"start_time\x18\b \x01(\x03R\tstartTime\x12\x1b\n" +
|
||||||
"\texpire_at\x18\t \x01(\x03R\bexpireAt\"}\n" +
|
"\texpire_at\x18\t \x01(\x03R\bexpireAt\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"like_count\x18\n" +
|
||||||
|
" \x01(\x05R\tlikeCount\"}\n" +
|
||||||
"\x1dOnExhibitionCompletedResponse\x120\n" +
|
"\x1dOnExhibitionCompletedResponse\x120\n" +
|
||||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12*\n" +
|
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12*\n" +
|
||||||
"\x11revenue_record_id\x18\x02 \x01(\x03R\x0frevenueRecordId2\xc6\f\n" +
|
"\x11revenue_record_id\x18\x02 \x01(\x03R\x0frevenueRecordId2\xc6\f\n" +
|
||||||
|
|||||||
@ -195,6 +195,7 @@ message OnExhibitionCompletedRequest {
|
|||||||
int64 crystal_amount = 7;
|
int64 crystal_amount = 7;
|
||||||
int64 start_time = 8;
|
int64 start_time = 8;
|
||||||
int64 expire_at = 9;
|
int64 expire_at = 9;
|
||||||
|
int32 like_count = 10; // 点赞数,用于在taskService中根据资产等级重新计算收益
|
||||||
}
|
}
|
||||||
|
|
||||||
message OnExhibitionCompletedResponse {
|
message OnExhibitionCompletedResponse {
|
||||||
|
|||||||
@ -55,6 +55,10 @@ func (r *AssetLevelRepository) CreateChangeLog(log *models.AssetLevelChangeLog)
|
|||||||
return r.db.Create(log).Error
|
return r.db.Create(log).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AssetLevelRepository) GetDB() *gorm.DB {
|
||||||
|
return r.db
|
||||||
|
}
|
||||||
|
|
||||||
func (r *AssetLevelRepository) GetChangeLogs(assetID int64, limit, offset int) ([]*models.AssetLevelChangeLog, error) {
|
func (r *AssetLevelRepository) GetChangeLogs(assetID int64, limit, offset int) ([]*models.AssetLevelChangeLog, error) {
|
||||||
var logs []*models.AssetLevelChangeLog
|
var logs []*models.AssetLevelChangeLog
|
||||||
err := r.db.Where("asset_id = ?", assetID).
|
err := r.db.Where("asset_id = ?", assetID).
|
||||||
|
|||||||
@ -48,6 +48,9 @@ type AssetRepository interface {
|
|||||||
// DecrementLikeCount 减少点赞数
|
// DecrementLikeCount 减少点赞数
|
||||||
DecrementLikeCount(assetID int64) error
|
DecrementLikeCount(assetID int64) error
|
||||||
|
|
||||||
|
// UpdateGradeByAssetID 根据asset_id更新藏品等级(用于同步AssetLevelRecord.CurrentLevel到AssetRegistry.Grade)
|
||||||
|
UpdateGradeByAssetID(assetID int64, grade int32) error
|
||||||
|
|
||||||
// UpdateMaterialTypeByLikes 根据点赞数和创建时间更新素材类型
|
// UpdateMaterialTypeByLikes 根据点赞数和创建时间更新素材类型
|
||||||
UpdateMaterialTypeByLikes(assetID int64, likes int32, createdAt int64) error
|
UpdateMaterialTypeByLikes(assetID int64, likes int32, createdAt int64) error
|
||||||
|
|
||||||
@ -154,6 +157,17 @@ func (r *assetRepository) GetGradeByAssetID(assetID int64) (int32, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateGradeByAssetID 根据asset_id更新藏品等级(用于同步AssetLevelRecord.CurrentLevel到AssetRegistry.Grade)
|
||||||
|
func (r *assetRepository) UpdateGradeByAssetID(assetID int64, grade int32) error {
|
||||||
|
if assetID <= 0 {
|
||||||
|
return errors.New("asset_id must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.db.Table("public.asset_registry").
|
||||||
|
Where("asset_id = ?", assetID).
|
||||||
|
Update("grade", grade).Error
|
||||||
|
}
|
||||||
|
|
||||||
// GetByIDs 批量查询资产
|
// GetByIDs 批量查询资产
|
||||||
func (r *assetRepository) GetByIDs(assetIDs []int64) ([]*models.Asset, error) {
|
func (r *assetRepository) GetByIDs(assetIDs []int64) ([]*models.Asset, error) {
|
||||||
if len(assetIDs) == 0 {
|
if len(assetIDs) == 0 {
|
||||||
|
|||||||
@ -29,6 +29,7 @@ type assetLevelService struct {
|
|||||||
levelRepo *repository.AssetLevelRepository
|
levelRepo *repository.AssetLevelRepository
|
||||||
seasonRepo *repository.SeasonRepository
|
seasonRepo *repository.SeasonRepository
|
||||||
decayConfigRepo *repository.SeasonDecayConfigRepository
|
decayConfigRepo *repository.SeasonDecayConfigRepository
|
||||||
|
assetRepo repository.AssetRepository // 用于同步等级到AssetRegistry.Grade(可选)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAssetLevelService(
|
func NewAssetLevelService(
|
||||||
@ -173,6 +174,8 @@ func (s *assetLevelService) AddExhibitionHours(assetID int64, hours int) (string
|
|||||||
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
||||||
"exhibition_complete", record.SeasonExhibitionHours, record.SeasonLikes,
|
"exhibition_complete", record.SeasonExhibitionHours, record.SeasonLikes,
|
||||||
fmt.Sprintf("展出完成,时长+%d小时", hours))
|
fmt.Sprintf("展出完成,时长+%d小时", hours))
|
||||||
|
// 同步等级到AssetRegistry.Grade
|
||||||
|
s.syncGradeToAssetRegistry(record.AssetID, newLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLevel, upgraded, nil
|
return newLevel, upgraded, nil
|
||||||
@ -210,6 +213,8 @@ func (s *assetLevelService) AddLikes(assetID int64, count int) (string, bool, er
|
|||||||
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
||||||
"like_update", record.SeasonExhibitionHours, record.SeasonLikes,
|
"like_update", record.SeasonExhibitionHours, record.SeasonLikes,
|
||||||
fmt.Sprintf("点赞数达到%d触发升级", record.SeasonLikes))
|
fmt.Sprintf("点赞数达到%d触发升级", record.SeasonLikes))
|
||||||
|
// 同步等级到AssetRegistry.Grade
|
||||||
|
s.syncGradeToAssetRegistry(record.AssetID, newLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLevel, upgraded, nil
|
return newLevel, upgraded, nil
|
||||||
@ -245,11 +250,53 @@ func (s *assetLevelService) RemoveLikes(assetID int64, count int) (string, bool,
|
|||||||
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
||||||
"like_remove", record.SeasonExhibitionHours, record.SeasonLikes,
|
"like_remove", record.SeasonExhibitionHours, record.SeasonLikes,
|
||||||
fmt.Sprintf("取消点赞,点赞数降至%d触发降级", record.SeasonLikes))
|
fmt.Sprintf("取消点赞,点赞数降至%d触发降级", record.SeasonLikes))
|
||||||
|
// 同步等级到AssetRegistry.Grade
|
||||||
|
s.syncGradeToAssetRegistry(record.AssetID, newLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLevel, downgraded, nil
|
return newLevel, downgraded, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syncGradeToAssetRegistry 将等级同步到AssetRegistry.Grade
|
||||||
|
// 直接使用gorm.DB更新,不依赖repository层
|
||||||
|
func (s *assetLevelService) syncGradeToAssetRegistry(assetID int64, level string) {
|
||||||
|
if s.assetRepo == nil {
|
||||||
|
// 直接使用levelRepo的db进行更新
|
||||||
|
grade := models.LevelToGrade(level)
|
||||||
|
db := s.levelRepo.GetDB()
|
||||||
|
if db != nil {
|
||||||
|
if err := db.Table("public.asset_registry").
|
||||||
|
Where("asset_id = ?", assetID).
|
||||||
|
Update("grade", grade).Error; err != nil {
|
||||||
|
logger.Logger.Warn("syncGradeToAssetRegistry failed",
|
||||||
|
zap.Int64("asset_id", assetID),
|
||||||
|
zap.String("level", level),
|
||||||
|
zap.Int("grade", grade),
|
||||||
|
zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Logger.Info("syncGradeToAssetRegistry success",
|
||||||
|
zap.Int64("asset_id", assetID),
|
||||||
|
zap.String("level", level),
|
||||||
|
zap.Int("grade", grade))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
grade := models.LevelToGrade(level)
|
||||||
|
if err := s.assetRepo.UpdateGradeByAssetID(assetID, int32(grade)); err != nil {
|
||||||
|
logger.Logger.Warn("syncGradeToAssetRegistry failed",
|
||||||
|
zap.Int64("asset_id", assetID),
|
||||||
|
zap.String("level", level),
|
||||||
|
zap.Int("grade", grade),
|
||||||
|
zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Logger.Info("syncGradeToAssetRegistry success",
|
||||||
|
zap.Int64("asset_id", assetID),
|
||||||
|
zap.String("level", level),
|
||||||
|
zap.Int("grade", grade))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *assetLevelService) CalculateRevenue(assetID int64, likeCount int, startTime, endTime int64, revenueBoostBps int) (int64, error) {
|
func (s *assetLevelService) CalculateRevenue(assetID int64, likeCount int, startTime, endTime int64, revenueBoostBps int) (int64, error) {
|
||||||
record, err := s.GetRecordByAssetID(assetID)
|
record, err := s.GetRecordByAssetID(assetID)
|
||||||
if err != nil || record == nil {
|
if err != nil || record == nil {
|
||||||
@ -372,6 +419,8 @@ func (s *assetLevelService) SeasonReset(seasonID string) error {
|
|||||||
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
s.logLevelChange(record.AssetID, oldLevel, newLevel,
|
||||||
"season_decay", record.SeasonExhibitionHours, record.SeasonLikes,
|
"season_decay", record.SeasonExhibitionHours, record.SeasonLikes,
|
||||||
fmt.Sprintf("赛季%s降序,保留%d%%", seasonID, preservePercent))
|
fmt.Sprintf("赛季%s降序,保留%d%%", seasonID, preservePercent))
|
||||||
|
// 同步等级到AssetRegistry.Grade
|
||||||
|
s.syncGradeToAssetRegistry(record.AssetID, newLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ type OnExhibitionCompletedRequest struct {
|
|||||||
StartTime int64
|
StartTime int64
|
||||||
ExpireAt int64
|
ExpireAt int64
|
||||||
CrystalAmount int64
|
CrystalAmount int64
|
||||||
|
LikeCount int32 // 点赞数,用于taskService根据资产等级重新计算收益
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnExhibitionCompletedResponse 展位完成响应
|
// OnExhibitionCompletedResponse 展位完成响应
|
||||||
@ -72,6 +73,7 @@ func (c *taskRPCClient) OnExhibitionCompleted(ctx context.Context, req *OnExhibi
|
|||||||
StartTime: req.StartTime,
|
StartTime: req.StartTime,
|
||||||
ExpireAt: req.ExpireAt,
|
ExpireAt: req.ExpireAt,
|
||||||
CrystalAmount: req.CrystalAmount,
|
CrystalAmount: req.CrystalAmount,
|
||||||
|
LikeCount: req.LikeCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.client.OnExhibitionCompleted(ctx, pbReq)
|
resp, err := c.client.OnExhibitionCompleted(ctx, pbReq)
|
||||||
|
|||||||
@ -132,6 +132,7 @@ func (w *CleanupWorker) cleanupExpiredExhibitions(now int64) {
|
|||||||
StartTime: e.StartTime,
|
StartTime: e.StartTime,
|
||||||
ExpireAt: now,
|
ExpireAt: now,
|
||||||
CrystalAmount: revenue,
|
CrystalAmount: revenue,
|
||||||
|
LikeCount: int32(likeCount),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Error("调用TaskService记录收益失败,跳过标记已处理以便重试",
|
logger.Logger.Error("调用TaskService记录收益失败,跳过标记已处理以便重试",
|
||||||
|
|||||||
@ -28,6 +28,7 @@ type RevenueService interface {
|
|||||||
type AssetLevelService interface {
|
type AssetLevelService interface {
|
||||||
GetOrCreateRecord(assetID int64) (*models.AssetLevelRecord, error)
|
GetOrCreateRecord(assetID int64) (*models.AssetLevelRecord, error)
|
||||||
AddExhibitionHours(assetID int64, hours int) (string, bool, error)
|
AddExhibitionHours(assetID int64, hours int) (string, bool, error)
|
||||||
|
CalculateRevenue(assetID int64, likeCount int, startTime, endTime int64, revenueBoostBps int) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// revenueService 展示收益Service实现
|
// revenueService 展示收益Service实现
|
||||||
@ -322,7 +323,33 @@ func (s *revenueService) OnExhibitionCompleted(ctx context.Context, req *pb.OnEx
|
|||||||
zap.Int64("slot_id", req.SlotId),
|
zap.Int64("slot_id", req.SlotId),
|
||||||
zap.Int64("occupier_uid", req.OccupierUid),
|
zap.Int64("occupier_uid", req.OccupierUid),
|
||||||
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
||||||
zap.Int64("crystal_amount", req.CrystalAmount))
|
zap.Int64("crystal_amount", req.CrystalAmount),
|
||||||
|
zap.Int32("like_count", req.LikeCount))
|
||||||
|
|
||||||
|
// 计算实际上架时长(毫秒转小时)
|
||||||
|
startTime := req.StartTime
|
||||||
|
expireAt := req.ExpireAt
|
||||||
|
actualHours := (expireAt - startTime) / 3600000
|
||||||
|
|
||||||
|
// 重新计算收益(使用资产等级对应的R0值,而非galleryService传来的硬编码R0=5)
|
||||||
|
var finalRevenue int64
|
||||||
|
if s.assetLevelService != nil && req.AssetId > 0 {
|
||||||
|
if calculatedRevenue, err := s.assetLevelService.CalculateRevenue(req.AssetId, int(req.LikeCount), startTime, expireAt, 0); err == nil {
|
||||||
|
finalRevenue = calculatedRevenue
|
||||||
|
logger.Logger.Info("OnExhibitionCompleted: recalculated revenue using asset level",
|
||||||
|
zap.Int64("asset_id", req.AssetId),
|
||||||
|
zap.Int64("original_revenue", req.CrystalAmount),
|
||||||
|
zap.Int64("recalculated_revenue", finalRevenue))
|
||||||
|
} else {
|
||||||
|
// 计算失败,使用传来的值
|
||||||
|
finalRevenue = req.CrystalAmount
|
||||||
|
logger.Logger.Warn("OnExhibitionCompleted: failed to calculate revenue with asset level, using original",
|
||||||
|
zap.Int64("asset_id", req.AssetId),
|
||||||
|
zap.Error(err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalRevenue = req.CrystalAmount
|
||||||
|
}
|
||||||
|
|
||||||
// 收益归属资产主人(铸爱用户),无论展位是否为自己
|
// 收益归属资产主人(铸爱用户),无论展位是否为自己
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
@ -334,7 +361,7 @@ func (s *revenueService) OnExhibitionCompleted(ctx context.Context, req *pb.OnEx
|
|||||||
SlotID: req.SlotId,
|
SlotID: req.SlotId,
|
||||||
SlotOwnerUID: req.SlotOwnerUid, // 记录展位所有者信息(仅供参考)
|
SlotOwnerUID: req.SlotOwnerUid, // 记录展位所有者信息(仅供参考)
|
||||||
SlotType: "exhibition", // 上架展示收益
|
SlotType: "exhibition", // 上架展示收益
|
||||||
CrystalAmount: req.CrystalAmount,
|
CrystalAmount: finalRevenue, // 使用重新计算的收益
|
||||||
CycleStartTime: req.StartTime,
|
CycleStartTime: req.StartTime,
|
||||||
CycleEndTime: req.ExpireAt,
|
CycleEndTime: req.ExpireAt,
|
||||||
Status: "claimable",
|
Status: "claimable",
|
||||||
@ -349,12 +376,6 @@ func (s *revenueService) OnExhibitionCompleted(ctx context.Context, req *pb.OnEx
|
|||||||
return &pb.OnExhibitionCompletedResponse{Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR}}, err
|
return &pb.OnExhibitionCompletedResponse{Base: &pbCommon.BaseResponse{Code: pbCommon.StatusCode_STATUS_INTERNAL_ERROR}}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加用户累计上架时长(展位主人获得上架时长累计)
|
|
||||||
// 计算实际上架时长(毫秒转小时)
|
|
||||||
startTime := req.StartTime
|
|
||||||
expireAt := req.ExpireAt
|
|
||||||
actualHours := (expireAt - startTime) / 3600000
|
|
||||||
|
|
||||||
// sourceID 用于去重,避免重复累计
|
// sourceID 用于去重,避免重复累计
|
||||||
sourceID := fmt.Sprintf("exhibition_%d", req.ExhibitionId)
|
sourceID := fmt.Sprintf("exhibition_%d", req.ExhibitionId)
|
||||||
|
|
||||||
@ -423,15 +444,17 @@ func CalculateBuff(likeCount int) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateExhibitionRevenue 计算单次上架收益
|
// CalculateExhibitionRevenue 计算单次上架收益(参考实现,未被调用)
|
||||||
|
// 注意:实际收益计算在 OnExhibitionCompleted 中通过 AssetLevelService.CalculateRevenue 实现
|
||||||
|
// 此函数保留用于参考和测试场景
|
||||||
// 设计文档公式:
|
// 设计文档公式:
|
||||||
// R1 = R0 × T × [100% + Buff(n)]
|
// R1 = R0 × T × [100% + Buff(n)]
|
||||||
// R0 = 5 水晶/小时
|
// R0 = 5 水晶/小时(默认,仅作参考)
|
||||||
// T = 上架时长(小时)
|
// T = 上架时长(小时)
|
||||||
// Buff(n) 根据点赞数计算
|
// Buff(n) 根据点赞数计算
|
||||||
// 应用永久收益提升:revenueBoostBps (bps),如 500 = +5%
|
// 应用永久收益提升:revenueBoostBps (bps),如 500 = +5%
|
||||||
func CalculateExhibitionRevenue(likeCount int, startTime, endTime int64, revenueBoostBps int) int64 {
|
func CalculateExhibitionRevenue(likeCount int, startTime, endTime int64, revenueBoostBps int) int64 {
|
||||||
R0 := int64(5) // 水晶/小时
|
R0 := int64(5) // 水晶/小时(默认参考值)
|
||||||
|
|
||||||
// 计算上架时长(毫秒转小时)
|
// 计算上架时长(毫秒转小时)
|
||||||
T := (endTime - startTime) / 3600000
|
T := (endTime - startTime) / 3600000
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user