feat:修改展示收益
This commit is contained in:
parent
2a0faeb835
commit
3ef3510303
@ -2,7 +2,9 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Skill(superpowers:subagent-driven-development)",
|
||||
"Skill(superpowers:subagent-driven-development:*)"
|
||||
"Skill(superpowers:subagent-driven-development:*)",
|
||||
"Bash(go build:*)",
|
||||
"Bash(go vet:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,13 +32,13 @@ type ServerConfig struct {
|
||||
|
||||
// DubboConfig Dubbo 服务配置
|
||||
type DubboConfig struct {
|
||||
UserServiceURL string
|
||||
SocialServiceURL string
|
||||
AssetServiceURL string
|
||||
GalleryServiceURL string
|
||||
ActivityServiceURL string
|
||||
TaskServiceURL string
|
||||
StarbookServiceURL string
|
||||
UserServiceURL string
|
||||
SocialServiceURL string
|
||||
AssetServiceURL string
|
||||
GalleryServiceURL string
|
||||
ActivityServiceURL string
|
||||
TaskServiceURL string
|
||||
StarbookServiceURL string
|
||||
}
|
||||
|
||||
// JWTConfig JWT 配置
|
||||
@ -104,7 +104,7 @@ func Load() *Config {
|
||||
Redis: RedisConfig{
|
||||
Host: getEnv("REDIS_HOST", "127.0.0.1"),
|
||||
Port: getEnvInt("REDIS_PORT", 6379),
|
||||
Password: getEnv("REDIS_PASSWORD", ""),
|
||||
Password: getEnv("REDIS_PASSWORD", "123456"),
|
||||
DB: getEnvInt("REDIS_DB", 0),
|
||||
},
|
||||
}
|
||||
|
||||
@ -48,6 +48,8 @@ github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||
github.com/bketelsen/crypt v0.0.4 h1:w/jqZtC9YD4DS/Vp9GhWfWcCpuAL58oTnLoI8vE9YHU=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/casbin/casbin/v2 v2.1.2 h1:bTwon/ECRx9dwBy2ewRVr5OiqjeXSGiTUY74sDPQi/g=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
@ -289,6 +291,7 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts=
|
||||
|
||||
@ -1748,6 +1748,7 @@ type AddExhibitionHoursRequest struct {
|
||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // 用户ID
|
||||
StarId int64 `protobuf:"varint,2,opt,name=star_id,json=starId,proto3" json:"star_id,omitempty"` // 明星ID
|
||||
ExhibitionHours int64 `protobuf:"varint,3,opt,name=exhibition_hours,json=exhibitionHours,proto3" json:"exhibition_hours,omitempty"` // 本次展出的时长(小时)
|
||||
SourceId string `protobuf:"bytes,4,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` // 关联业务ID,用于升级奖励流水的溯源
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -1803,6 +1804,13 @@ func (x *AddExhibitionHoursRequest) GetExhibitionHours() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *AddExhibitionHoursRequest) GetSourceId() string {
|
||||
if x != nil {
|
||||
return x.SourceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 增加累计上架时长响应
|
||||
type AddExhibitionHoursResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -2987,11 +2995,12 @@ const file_user_proto_rawDesc = "" +
|
||||
"\x05delta\x18\x03 \x01(\x05R\x05delta\"j\n" +
|
||||
"\x19UpdateAssetsCountResponse\x120\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12\x1b\n" +
|
||||
"\tnew_count\x18\x02 \x01(\x05R\bnewCount\"x\n" +
|
||||
"\tnew_count\x18\x02 \x01(\x05R\bnewCount\"\x95\x01\n" +
|
||||
"\x19AddExhibitionHoursRequest\x12\x17\n" +
|
||||
"\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x17\n" +
|
||||
"\astar_id\x18\x02 \x01(\x03R\x06starId\x12)\n" +
|
||||
"\x10exhibition_hours\x18\x03 \x01(\x03R\x0fexhibitionHours\"\xb3\x01\n" +
|
||||
"\x10exhibition_hours\x18\x03 \x01(\x03R\x0fexhibitionHours\x12\x1b\n" +
|
||||
"\tsource_id\x18\x04 \x01(\tR\bsourceId\"\xb3\x01\n" +
|
||||
"\x1aAddExhibitionHoursResponse\x120\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12\x1b\n" +
|
||||
"\tnew_level\x18\x02 \x01(\x05R\bnewLevel\x12\x1f\n" +
|
||||
|
||||
@ -218,6 +218,7 @@ message AddExhibitionHoursRequest {
|
||||
int64 user_id = 1; // 用户ID
|
||||
int64 star_id = 2; // 明星ID
|
||||
int64 exhibition_hours = 3; // 本次展出的时长(小时)
|
||||
string source_id = 4; // 关联业务ID,用于升级奖励流水的溯源
|
||||
}
|
||||
|
||||
// 增加累计上架时长响应
|
||||
|
||||
@ -27,11 +27,15 @@ type UserRPCClient interface {
|
||||
GetFanProfile(userID, starID int64) (*FanProfile, error)
|
||||
|
||||
// UpdateCrystalBalance 更新水晶余额(返回更新后的余额)
|
||||
UpdateCrystalBalance(userID, starID int64, delta int64) (int64, error)
|
||||
// changeType: 变化类型,如 task_reward/mint_cost/mint_reward/exhibition_revenue/level_up_bonus/manual_adjust
|
||||
// sourceID: 关联业务ID
|
||||
// description: 可读描述
|
||||
UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error)
|
||||
|
||||
// AddExhibitionHours 增加用户累计上架时长
|
||||
// sourceID: 关联业务ID,用于升级奖励流水的溯源
|
||||
// 返回: newLevel, levelDelta, crystalReward, error
|
||||
AddExhibitionHours(userID, starID int64, hours int64) (int32, int32, int64, error)
|
||||
AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error)
|
||||
}
|
||||
|
||||
// userRPCClient User Service RPC客户端实现
|
||||
@ -101,18 +105,22 @@ func (c *userRPCClient) GetFanProfile(userID, starID int64) (*FanProfile, error)
|
||||
}
|
||||
|
||||
// UpdateCrystalBalance 更新水晶余额(返回更新后的余额)
|
||||
func (c *userRPCClient) UpdateCrystalBalance(userID, starID int64, delta int64) (int64, error) {
|
||||
func (c *userRPCClient) UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error) {
|
||||
logger.Logger.Debug("Calling UserService.UpdateCrystalBalance",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.Int64("star_id", starID),
|
||||
zap.Int64("delta", delta),
|
||||
zap.String("change_type", changeType),
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
resp, err := c.client.UpdateCrystalBalance(ctx, &pbUser.UpdateCrystalBalanceRequest{
|
||||
UserId: userID,
|
||||
StarId: starID,
|
||||
Delta: delta,
|
||||
UserId: userID,
|
||||
StarId: starID,
|
||||
Delta: delta,
|
||||
ChangeType: changeType,
|
||||
SourceId: sourceID,
|
||||
Description: description,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -150,7 +158,8 @@ func (c *userRPCClient) UpdateCrystalBalance(userID, starID int64, delta int64)
|
||||
}
|
||||
|
||||
// AddExhibitionHours 增加用户累计上架时长
|
||||
func (c *userRPCClient) AddExhibitionHours(userID, starID int64, hours int64) (int32, int32, int64, error) {
|
||||
// sourceID: 关联业务ID,用于升级奖励流水的溯源(本参数暂未透传到RPC,仅Go层保留)
|
||||
func (c *userRPCClient) AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) {
|
||||
logger.Logger.Debug("Calling UserService.AddExhibitionHours",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.Int64("star_id", starID),
|
||||
@ -162,6 +171,7 @@ func (c *userRPCClient) AddExhibitionHours(userID, starID int64, hours int64) (i
|
||||
UserId: userID,
|
||||
StarId: starID,
|
||||
ExhibitionHours: hours,
|
||||
SourceId: sourceID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@ -385,15 +385,12 @@ func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pag
|
||||
err = r.db.Model(&models.Exhibition{}).
|
||||
Raw(`
|
||||
SELECT exhibitions.asset_id, a.name, a.cover_url, a.like_count,
|
||||
exhibitions.start_time as exhibited_at, exhibitions.expire_at, bs.slot_index,
|
||||
COALESCE(CAST(SUM(err.crystal_amount) / 10 AS bigint), 0) as earnings
|
||||
exhibitions.start_time as exhibited_at, exhibitions.expire_at, bs.slot_index
|
||||
FROM exhibitions
|
||||
JOIN assets a ON a.id = exhibitions.asset_id
|
||||
JOIN booth_slots bs ON bs.slot_id = exhibitions.slot_id
|
||||
LEFT JOIN exhibition_revenue_records err ON err.asset_id = a.id AND err.status = 'claimable'
|
||||
WHERE exhibitions.occupier_uid = ? AND exhibitions.occupier_star_id = ?
|
||||
AND exhibitions.deleted_at IS NULL AND exhibitions.expire_at > ?
|
||||
GROUP BY exhibitions.asset_id, a.name, a.cover_url, a.like_count, exhibitions.start_time, exhibitions.expire_at, bs.slot_index
|
||||
ORDER BY bs.slot_index ASC
|
||||
LIMIT ? OFFSET ?
|
||||
`, userID, starID, now, pageSize, offset).Scan(&items).Error
|
||||
@ -402,6 +399,12 @@ func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pag
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 实时计算展示收益:R1 = R0 × T × [100% + Buff(n)]
|
||||
// R0 = 5 水晶/小时
|
||||
for _, item := range items {
|
||||
item.Earnings = calculateRealtimeEarnings(item.LikeCount, item.ExhibitedAt, now)
|
||||
}
|
||||
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
@ -576,3 +579,37 @@ func generateHostProfileID(userID, starID int64) int64 {
|
||||
// 实际项目中应该使用与 User Service 一致的逻辑
|
||||
return userID*1000000 + starID
|
||||
}
|
||||
|
||||
// calculateRealtimeEarnings 实时计算展示收益
|
||||
// 公式:R1 = R0 × T × [100% + Buff(n)]
|
||||
// R0 = 5 水晶/小时,T = 上架时长(小时),Buff(n) 根据点赞数计算
|
||||
func calculateRealtimeEarnings(likeCount int32, startTime, now int64) int64 {
|
||||
R0 := int64(5) // 水晶/小时
|
||||
|
||||
// 计算上架时长(毫秒转小时)
|
||||
T := (now - startTime) / 3600000
|
||||
if T <= 0 {
|
||||
T = 1 // 最少1小时
|
||||
}
|
||||
|
||||
// 计算Buff
|
||||
var buff int
|
||||
switch {
|
||||
case likeCount >= 30:
|
||||
buff = 30
|
||||
case likeCount >= 10:
|
||||
buff = 20
|
||||
case likeCount >= 5:
|
||||
buff = 10
|
||||
default:
|
||||
buff = 0
|
||||
}
|
||||
|
||||
// 基础收益
|
||||
baseRevenue := R0 * T
|
||||
|
||||
// 应用Buff加成:R1 = R0 × T × (100% + Buff)
|
||||
buffedRevenue := baseRevenue * (100 + int64(buff)) / 100
|
||||
|
||||
return buffedRevenue
|
||||
}
|
||||
|
||||
@ -12,6 +12,10 @@ import (
|
||||
type UserServiceClient interface {
|
||||
UpdateCrystalBalance(ctx context.Context, userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error)
|
||||
GetFanProfile(ctx context.Context, userID, starID int64) (*pbUser.FanProfile, error)
|
||||
// AddExhibitionHours 增加用户累计上架时长
|
||||
// sourceID: 关联业务ID,用于升级奖励流水的溯源
|
||||
// 返回: newLevel, levelDelta, crystalReward, error
|
||||
AddExhibitionHours(ctx context.Context, userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error)
|
||||
}
|
||||
|
||||
type userServiceClient struct {
|
||||
@ -56,3 +60,24 @@ func (c *userServiceClient) GetFanProfile(ctx context.Context, userID, starID in
|
||||
}
|
||||
return resp.Profile, nil
|
||||
}
|
||||
|
||||
// AddExhibitionHours 增加用户累计上架时长
|
||||
func (c *userServiceClient) AddExhibitionHours(ctx context.Context, userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) {
|
||||
logger.Logger.Debug("Calling UserService.AddExhibitionHours",
|
||||
zap.Int64("user_id", userID), zap.Int64("star_id", starID), zap.Int64("hours", hours))
|
||||
resp, err := c.client.AddExhibitionHours(ctx, &pbUser.AddExhibitionHoursRequest{
|
||||
UserId: userID,
|
||||
StarId: starID,
|
||||
ExhibitionHours: hours,
|
||||
SourceId: sourceID,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Logger.Error("UserService.AddExhibitionHours failed", zap.Error(err))
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
if resp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||||
logger.Logger.Warn("AddExhibitionHours non-zero code", zap.Int32("code", int32(resp.Base.Code)))
|
||||
return 0, 0, 0, fmt.Errorf("AddExhibitionHours failed with code: %d", resp.Base.Code)
|
||||
}
|
||||
return resp.NewLevel, resp.LevelDelta, resp.CrystalReward, nil
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package repository
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -21,31 +20,6 @@ func contains(s, substr string) bool {
|
||||
return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
|
||||
}
|
||||
|
||||
// CalculateLevel 根据经验值计算等级
|
||||
// 公式: 升级到等级L需要的累计经验 = (L-1) * L * 50
|
||||
// Level 1: 0经验, Level 2: 100经验, Level 3: 300经验, Level 4: 600经验...
|
||||
func CalculateLevel(experience int64) int32 {
|
||||
if experience < 0 {
|
||||
return 1
|
||||
}
|
||||
// 使用公式: (L-1) * L * 50 <= experience
|
||||
// 解方程: L^2 - L - experience/50 <= 0
|
||||
// L = (1 + sqrt(1 + 4*experience/50)) / 2
|
||||
level := int32((1 + math.Sqrt(1+4*float64(experience)/50)) / 2)
|
||||
if level < 1 {
|
||||
level = 1
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
// GetExperienceForLevel 获取指定等级需要的经验值
|
||||
func GetExperienceForLevel(level int32) int64 {
|
||||
if level <= 1 {
|
||||
return 0
|
||||
}
|
||||
return int64((level-1) * level * 50)
|
||||
}
|
||||
|
||||
// FanProfileRepository 粉丝档案Repository接口
|
||||
type FanProfileRepository interface {
|
||||
// Create 创建粉丝档案
|
||||
@ -72,9 +46,6 @@ type FanProfileRepository interface {
|
||||
// IncrementAssetsCount 增加资产计数
|
||||
IncrementAssetsCount(userID, starID int64, delta int32) error
|
||||
|
||||
// SyncLevelFromExperience 根据经验值同步等级(只升级不降级)
|
||||
SyncLevelFromExperience(userID, starID int64) (int32, error)
|
||||
|
||||
// DecrementAssetsCount 减少资产计数
|
||||
DecrementAssetsCount(userID, starID int64, delta int32) error
|
||||
|
||||
@ -91,11 +62,9 @@ type FanProfileRepository interface {
|
||||
UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error)
|
||||
|
||||
// AddExhibitionHours 增加用户累计上架时长并同步等级(事务性)
|
||||
// sourceID: 关联业务ID,用于升级奖励流水的溯源
|
||||
// 返回: newLevel, levelDelta, crystalReward, error
|
||||
AddExhibitionHours(userID, starID int64, hours int64) (int32, int32, int64, error)
|
||||
|
||||
// UpdateExperience 更新经验值
|
||||
UpdateExperience(userID, starID int64, delta int64) (int64, error)
|
||||
AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error)
|
||||
|
||||
// UpdateAvatar 更新头像
|
||||
UpdateAvatar(userID, starID int64, avatarURL string) error
|
||||
@ -517,8 +486,9 @@ func GetLevelCap() int32 {
|
||||
}
|
||||
|
||||
// AddExhibitionHours 增加用户累计上架时长并同步等级(事务性)
|
||||
// sourceID: 关联业务ID,用于升级奖励流水的溯源
|
||||
// 返回: newLevel, levelDelta, crystalReward, error
|
||||
func (r *fanProfileRepository) AddExhibitionHours(userID, starID int64, hours int64) (int32, int32, int64, error) {
|
||||
func (r *fanProfileRepository) AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) {
|
||||
var result struct {
|
||||
OldLevel int32
|
||||
NewLevel int32
|
||||
@ -607,7 +577,7 @@ func (r *fanProfileRepository) AddExhibitionHours(userID, starID int64, hours in
|
||||
Delta: crystalReward,
|
||||
BalanceBefore: balanceBefore,
|
||||
BalanceAfter: balanceAfter,
|
||||
SourceID: "",
|
||||
SourceID: sourceID,
|
||||
Description: fmt.Sprintf("升级到%d级奖励", newLevel),
|
||||
CreatedAt: time.Now().UnixMilli(),
|
||||
}
|
||||
@ -664,63 +634,6 @@ func (r *fanProfileRepository) getLevelUpRewards(tx *gorm.DB, level int32) ([]*m
|
||||
return rewards, err
|
||||
}
|
||||
|
||||
// UpdateExperience 更新经验值(同时自动更新等级)
|
||||
// UpdateExperience 更新经验值(同时自动更新等级)
|
||||
// delta: 变化量,正数表示增加,负数表示减少
|
||||
// 返回: 更新后的经验值
|
||||
func (r *fanProfileRepository) UpdateExperience(userID, starID int64, delta int64) (int64, error) {
|
||||
if userID <= 0 {
|
||||
return 0, errors.New("user_id must be greater than 0")
|
||||
}
|
||||
|
||||
if starID <= 0 {
|
||||
return 0, errors.New("star_id must be greater than 0")
|
||||
}
|
||||
|
||||
// 使用事务确保原子性
|
||||
var newExperience int64
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
// 先查询当前的 experience 值
|
||||
var profile models.FanProfile
|
||||
if err := tx.Where("user_id = ? AND star_id = ?", userID, starID).
|
||||
First(&profile).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return appErrors.ErrFanProfileNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 计算新经验值
|
||||
newExperience = profile.Experience + delta
|
||||
|
||||
// 确保不会小于 0
|
||||
if newExperience < 0 {
|
||||
newExperience = 0
|
||||
}
|
||||
|
||||
// 根据新经验值计算新等级
|
||||
newLevel := CalculateLevel(newExperience)
|
||||
|
||||
// 更新 experience 和 level 字段
|
||||
if err := tx.Model(&models.FanProfile{}).
|
||||
Where("user_id = ? AND star_id = ?", userID, starID).
|
||||
Updates(map[string]interface{}{
|
||||
"experience": newExperience,
|
||||
"level": newLevel,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return newExperience, nil
|
||||
}
|
||||
|
||||
// UpdateAvatar 更新头像
|
||||
func (r *fanProfileRepository) UpdateAvatar(userID, starID int64, avatarURL string) error {
|
||||
if userID <= 0 {
|
||||
@ -750,23 +663,4 @@ func (r *fanProfileRepository) UpdateAvatar(userID, starID int64, avatarURL stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncLevelFromExperience 根据经验值同步等级(只升级不降级)
|
||||
// 在获取用户信息时调用,确保等级与经验值匹配
|
||||
func (r *fanProfileRepository) SyncLevelFromExperience(userID, starID int64) (int32, error) {
|
||||
var profile models.FanProfile
|
||||
if err := r.db.Where("user_id = ? AND star_id = ?", userID, starID).First(&profile).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
newLevel := CalculateLevel(profile.Experience)
|
||||
|
||||
// 只升级,不降级
|
||||
if newLevel > profile.Level {
|
||||
if err := r.db.Model(&profile).Update("level", newLevel).Error; err != nil {
|
||||
return profile.Level, err
|
||||
}
|
||||
return newLevel, nil
|
||||
}
|
||||
|
||||
return profile.Level, nil
|
||||
}
|
||||
// UpdateAvatar 更新头像
|
||||
|
||||
@ -353,7 +353,6 @@ func TestFanProfileRepository_Update(t *testing.T) {
|
||||
|
||||
// 更新粉丝档案
|
||||
profile.Level = 2
|
||||
profile.Experience = 100
|
||||
err := repo.Update(profile)
|
||||
if err != nil {
|
||||
t.Fatalf("Update failed: %v", err)
|
||||
@ -368,10 +367,6 @@ func TestFanProfileRepository_Update(t *testing.T) {
|
||||
if retrieved.Level != 2 {
|
||||
t.Errorf("Level mismatch: expected 2, got %d", retrieved.Level)
|
||||
}
|
||||
|
||||
if retrieved.Experience != 100 {
|
||||
t.Errorf("Experience mismatch: expected 100, got %d", retrieved.Experience)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanProfileRepository_UpdateNickname(t *testing.T) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user