feat:修改类型为复合类型
This commit is contained in:
parent
0852f96436
commit
e545f41c3b
@ -408,6 +408,7 @@ start_watcher "gateway" "gateway:pkg/proto" "gateway/gateway
|
||||
start_watcher "userService" "services/userService" "services/userService/userService" 20000 1
|
||||
start_watcher "assetService" "services/assetService:pkg/proto/asset" "services/assetService/assetService" 20003 1
|
||||
start_watcher "socialService" "services/socialService" "services/socialService/socialService" 20002 1
|
||||
start_watcher "galleryService" "services/galleryService" "services/galleryService/galleryService" 20004 1
|
||||
start_watcher "activityService" "services/activityService" "services/activityService/activityService" 20005 1
|
||||
start_watcher "taskService" "services/taskService" "services/taskService/taskService" 20006 1
|
||||
start_watcher "starbookService" "services/starbookService" "services/starbookService/starbookService" 20007 1
|
||||
|
||||
@ -121,7 +121,7 @@ type MintOrder struct {
|
||||
MaterialURL *string `gorm:"type:varchar(500);column:material_url"` // 用户上传的素材URL(阶段一写入)
|
||||
Name *string `gorm:"type:varchar(100);column:name"` // 藏品名称(阶段一写入,可选)
|
||||
Description *string `gorm:"type:text;column:description"` // 藏品描述(阶段一写入,可选)
|
||||
MaterialType *string `gorm:"type:varchar(50);column:material_type"` // 素材类型(可选)
|
||||
MaterialType *string `gorm:"type:varchar(100);column:material_type"` // 素材类型(可选,多个用逗号分隔)
|
||||
Event *string `gorm:"type:varchar(100);column:event"` // 藏品事件(可选)
|
||||
Info *string `gorm:"type:text;column:info"` // 藏品信息(必填)
|
||||
CreatedAt int64 `gorm:"not null;index:idx_mint_orders_created_at,sort:desc;column:created_at"`
|
||||
|
||||
@ -74,37 +74,18 @@ func shouldUpdateMaterialType(oldLikes, newLikes int32, createdAt int64, isIncre
|
||||
|
||||
// 点赞增加时的临界点
|
||||
if isIncrement {
|
||||
// new → hot (超过20)
|
||||
if oldLikes <= 20 && newLikes > 20 {
|
||||
// 超过20 → 添加 hot
|
||||
if newLikes > 20 {
|
||||
return true, "hot"
|
||||
}
|
||||
// new → potential (达到10且在1小时内)
|
||||
if oldLikes < 10 && newLikes >= 10 && isWithin1Hour {
|
||||
return true, "potential"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 点赞减少时的临界点(降级检测)
|
||||
if !isIncrement {
|
||||
// hot → new/potential (降到20以下)
|
||||
if oldLikes > 20 && newLikes <= 20 {
|
||||
// 重新计算
|
||||
// 1小时内达到10 → 添加 potential
|
||||
if newLikes >= 10 && isWithin1Hour {
|
||||
return true, "potential"
|
||||
}
|
||||
return true, "new"
|
||||
}
|
||||
// potential → new (降到10以下)
|
||||
if oldLikes >= 10 && newLikes < 10 {
|
||||
return true, "new"
|
||||
}
|
||||
// hot 降到 21-20 区间
|
||||
if oldLikes > 20 && newLikes > 20 {
|
||||
return false, "" // 仍在 hot 区间
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 点赞减少时不降级(保留原类型)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
@ -191,15 +172,13 @@ func (s *AssetLikeService) LikeAsset(ctx context.Context, assetID, userID, starI
|
||||
return fmt.Errorf("failed to increment like count: %w", err)
|
||||
}
|
||||
|
||||
// 3.3 更新素材类型(只在临界点更新)
|
||||
// 3.3 更新素材类型(追加类型,不重复)
|
||||
oldLikes := asset.LikeCount
|
||||
newLikes := oldLikes + 1
|
||||
shouldUpdate, newMaterialType := shouldUpdateMaterialType(oldLikes, newLikes, asset.CreatedAt, true)
|
||||
if shouldUpdate {
|
||||
if err := tx.Model(&models.Asset{}).
|
||||
Where("id = ?", assetID).
|
||||
UpdateColumn("material_type", newMaterialType).
|
||||
Error; err != nil {
|
||||
if shouldUpdate && newMaterialType != "" {
|
||||
// 使用 PostgreSQL CONCAT 函数追加类型
|
||||
if err := tx.Raw("UPDATE assets SET material_type = CONCAT(COALESCE(material_type, ''), ',', ?) WHERE id = ?", newMaterialType, assetID).Error; err != nil {
|
||||
logger.Logger.Warn("Failed to update material type",
|
||||
zap.Error(err),
|
||||
zap.Int64("asset_id", assetID),
|
||||
|
||||
@ -441,13 +441,13 @@ func (s *assetService) GetAsset(req *pb.GetAssetRequest, userID, starID int64) (
|
||||
var ownerNickname string
|
||||
profile, err := s.userClient.GetFanProfile(context.Background(), asset.OwnerUID, asset.StarID)
|
||||
if err != nil {
|
||||
logger.Logger.Warn("Failed to get owner fan profile, will return without nickname",
|
||||
logger.Logger.Warn("Failed to get owner fan profile, using fallback nickname",
|
||||
zap.Int64("owner_uid", asset.OwnerUID),
|
||||
zap.Int64("star_id", asset.StarID),
|
||||
zap.Error(err),
|
||||
)
|
||||
// 获取失败时,使用空字符串
|
||||
ownerNickname = ""
|
||||
// 获取失败时,使用 User{uid} 作为 fallback
|
||||
ownerNickname = fmt.Sprintf("User%d", asset.OwnerUID)
|
||||
} else {
|
||||
ownerNickname = profile.Nickname
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/topfans/backend/pkg/models"
|
||||
@ -514,7 +515,7 @@ func (r *galleryRepository) CountValidExhibitions(starID int64, materialType str
|
||||
|
||||
if materialType != "" && materialType != "all" && materialType != "random" {
|
||||
query = query.Joins("JOIN assets a ON a.id = exhibitions.asset_id").
|
||||
Where("a.material_type = ?", materialType)
|
||||
Where("a.material_type LIKE ?", "%"+materialType+"%")
|
||||
}
|
||||
|
||||
err := query.Count(&count).Error
|
||||
@ -532,7 +533,7 @@ func (r *galleryRepository) GetRandomExhibitions(starID int64, materialType stri
|
||||
|
||||
if materialType != "" && materialType != "all" && materialType != "random" {
|
||||
baseQuery = baseQuery.Joins("JOIN assets a ON a.id = exhibitions.asset_id").
|
||||
Where("a.material_type = ?", materialType)
|
||||
Where("a.material_type LIKE ?", "%"+materialType+"%")
|
||||
}
|
||||
|
||||
// 排除已展示的ID
|
||||
@ -568,26 +569,42 @@ func (r *galleryRepository) GetRandomExhibitions(starID int64, materialType stri
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read-repair: 检查并修正 material_type(查询时自动修正数据不一致)
|
||||
// Read-repair: 检查并补充 material_type(多类型共存,不降级)
|
||||
for _, item := range items {
|
||||
item.Span = calcSpanByLikes(item.LikeCount)
|
||||
correctType := calcMaterialType(item.LikeCount, item.CreatedAt)
|
||||
if item.MaterialType != correctType {
|
||||
// 异步修正,不阻塞返回(使用 goroutine 避免影响响应时间)
|
||||
go func(assetID int64, correct string) {
|
||||
correctTypes := calcMaterialTypes(item.LikeCount, item.CreatedAt)
|
||||
|
||||
// 如果缺少任何类型,追加(不覆盖原有类型)
|
||||
missingTypes := []string{}
|
||||
for _, ct := range strings.Split(correctTypes, ",") {
|
||||
ct = strings.TrimSpace(ct)
|
||||
if ct != "" && !strings.Contains(item.MaterialType, ct) {
|
||||
missingTypes = append(missingTypes, ct)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingTypes) > 0 {
|
||||
newType := strings.Join(missingTypes, ",")
|
||||
// 异步修正
|
||||
go func(assetID int64, newType string) {
|
||||
r.db.Model(&models.Asset{}).
|
||||
Where("id = ?", assetID).
|
||||
Update("material_type", correct)
|
||||
}(item.AssetID, correctType)
|
||||
// 同时修正当前对象的值,保证返回给前端的是正确的
|
||||
item.MaterialType = correctType
|
||||
Update("material_type", gorm.Expr("CONCAT(COALESCE(material_type, ''), ',', ?)", newType))
|
||||
}(item.AssetID, newType)
|
||||
|
||||
// 修正当前返回对象
|
||||
if item.MaterialType == "" {
|
||||
item.MaterialType = correctTypes
|
||||
} else {
|
||||
item.MaterialType = item.MaterialType + "," + strings.Join(missingTypes, ",")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// calcMaterialType 根据点赞数计算素材类型
|
||||
// calcMaterialType 根据点赞数计算素材类型(单类型,互斥)
|
||||
func calcMaterialType(likes int32, createdAt int64) string {
|
||||
now := time.Now().UnixMilli()
|
||||
isWithin1Hour := createdAt > 0 && now-createdAt < 3600*1000
|
||||
@ -602,6 +619,27 @@ func calcMaterialType(likes int32, createdAt int64) string {
|
||||
return "new"
|
||||
}
|
||||
|
||||
// calcMaterialTypes 根据点赞数计算素材类型(多类型共存)
|
||||
func calcMaterialTypes(likes int32, createdAt int64) string {
|
||||
now := time.Now().UnixMilli()
|
||||
isWithin1Hour := createdAt > 0 && now-createdAt < 3600*1000
|
||||
|
||||
types := []string{}
|
||||
|
||||
// 超过20 → hot
|
||||
if likes > 20 {
|
||||
types = append(types, "hot")
|
||||
}
|
||||
// 1小时内达到10 → potential
|
||||
if isWithin1Hour && likes >= 10 {
|
||||
types = append(types, "potential")
|
||||
}
|
||||
// new 默认存在
|
||||
types = append(types, "new")
|
||||
|
||||
return strings.Join(types, ",")
|
||||
}
|
||||
|
||||
// calcSpanByLikes 根据点赞数计算卡片大小
|
||||
// 0-30 → span 1, 31-100 → span 2, 101-200 → span 3, 200+ → span 4
|
||||
func calcSpanByLikes(likes int32) int32 {
|
||||
|
||||
@ -1012,7 +1012,7 @@ onUnmounted(() => {
|
||||
width: 352rpx;
|
||||
height: 520rpx;
|
||||
margin-bottom: 32rpx;
|
||||
/* animation: card-3d-flip 15s ease-in-out infinite; */
|
||||
animation: card-3d-flip 15s ease-in-out infinite;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user