feat: 点赞列表修改,增加光栅卡字段
This commit is contained in:
parent
9ac75d034b
commit
94b9271184
@ -894,6 +894,7 @@ func (ctrl *SocialController) UnlikeAsset(c *gin.Context) {
|
||||
// @Security BearerAuth
|
||||
// @Param page query int false "页码,默认1"
|
||||
// @Param page_size query int false "每页数量,默认20,最大100"
|
||||
// @Param order_by query string false "排序字段:liked_at(默认), like_count(按点赞数)"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/v1/me/liked-assets [get]
|
||||
func (ctrl *SocialController) GetMyLikedAssets(c *gin.Context) {
|
||||
@ -938,6 +939,7 @@ func (ctrl *SocialController) GetMyLikedAssets(c *gin.Context) {
|
||||
"liked_at": item.LikedAt,
|
||||
"earnings": item.Earnings,
|
||||
"hourly_earnings": item.HourlyEarnings,
|
||||
"is_lenticular": item.IsLenticular,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ type Exhibition struct {
|
||||
CreatedAt int64 `gorm:"column:created_at;not null"`
|
||||
UpdatedAt int64 `gorm:"column:updated_at;not null"`
|
||||
DeletedAt *int64 `gorm:"column:deleted_at"`
|
||||
IsProcessed bool `gorm:"column:is_processed;default:false"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
|
||||
@ -2349,6 +2349,7 @@ type LikedAssetItem struct {
|
||||
LikedAt int64 `protobuf:"varint,5,opt,name=liked_at,json=likedAt,proto3" json:"liked_at,omitempty"` // 点赞时间(毫秒时间戳)
|
||||
Earnings int64 `protobuf:"varint,6,opt,name=earnings,proto3" json:"earnings,omitempty"` // 当前可领取收益
|
||||
HourlyEarnings float64 `protobuf:"fixed64,7,opt,name=hourly_earnings,json=hourlyEarnings,proto3" json:"hourly_earnings,omitempty"` // 每小时收益
|
||||
IsLenticular bool `protobuf:"varint,8,opt,name=is_lenticular,json=isLenticular,proto3" json:"is_lenticular,omitempty"` // 是否为光栅卡
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -2432,6 +2433,13 @@ func (x *LikedAssetItem) GetHourlyEarnings() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *LikedAssetItem) GetIsLenticular() bool {
|
||||
if x != nil {
|
||||
return x.IsLenticular
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取我今日点赞的作品列表请求(暂不实现)
|
||||
type GetMyTodayLikedAssetsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -2936,7 +2944,7 @@ const file_social_proto_rawDesc = "" +
|
||||
"\x04page\x18\x02 \x01(\x05R\x04page\x12\x1b\n" +
|
||||
"\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x14\n" +
|
||||
"\x05total\x18\x04 \x01(\x03R\x05total\x12\x19\n" +
|
||||
"\bhas_more\x18\x05 \x01(\bR\ahasMore\"\xdb\x01\n" +
|
||||
"\bhas_more\x18\x05 \x01(\bR\ahasMore\"\x80\x02\n" +
|
||||
"\x0eLikedAssetItem\x12\x19\n" +
|
||||
"\basset_id\x18\x01 \x01(\x03R\aassetId\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x1b\n" +
|
||||
@ -2945,7 +2953,8 @@ const file_social_proto_rawDesc = "" +
|
||||
"like_count\x18\x04 \x01(\x05R\tlikeCount\x12\x19\n" +
|
||||
"\bliked_at\x18\x05 \x01(\x03R\alikedAt\x12\x1a\n" +
|
||||
"\bearnings\x18\x06 \x01(\x03R\bearnings\x12'\n" +
|
||||
"\x0fhourly_earnings\x18\a \x01(\x01R\x0ehourlyEarnings\"O\n" +
|
||||
"\x0fhourly_earnings\x18\a \x01(\x01R\x0ehourlyEarnings\x12#\n" +
|
||||
"\ris_lenticular\x18\b \x01(\bR\fisLenticular\"O\n" +
|
||||
"\x1cGetMyTodayLikedAssetsRequest\x12\x12\n" +
|
||||
"\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" +
|
||||
"\tpage_size\x18\x02 \x01(\x05R\bpageSize\"\x86\x01\n" +
|
||||
|
||||
@ -293,6 +293,7 @@ message LikedAssetItem {
|
||||
int64 liked_at = 5; // 点赞时间(毫秒时间戳)
|
||||
int64 earnings = 6; // 当前可领取收益
|
||||
double hourly_earnings = 7; // 每小时收益
|
||||
bool is_lenticular = 8; // 是否为光栅卡
|
||||
}
|
||||
|
||||
// 获取我今日点赞的作品列表请求(暂不实现)
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
-- Migration: Add is_processed field to exhibitions table
|
||||
-- Description: Mark exhibitions as processed to prevent duplicate revenue record generation
|
||||
-- Date: 2026-05-19
|
||||
|
||||
ALTER TABLE exhibitions ADD COLUMN IF NOT EXISTS is_processed BOOLEAN DEFAULT false;
|
||||
|
||||
-- Create index for faster queries on unprocessed expired exhibitions
|
||||
CREATE INDEX IF NOT EXISTS idx_exhibitions_unprocessed ON exhibitions(expire_at) WHERE is_processed = false AND deleted_at IS NULL;
|
||||
@ -40,6 +40,8 @@ type GalleryRepository interface {
|
||||
RemoveExhibitionTx(exhibitionID int64, assetID int64) error
|
||||
// 更新展览过期时间(用于清理后防止重复处理)
|
||||
UpdateExhibitionExpireAt(exhibitionID int64, expireAt int64) error
|
||||
// 设置展品已处理(用于清理后标记已处理,防止重复生成收益记录)
|
||||
SetExhibitionProcessed(exhibitionID int64, processed bool) error
|
||||
|
||||
// ========== 我的作品相关 ==========
|
||||
|
||||
@ -299,10 +301,10 @@ func (r *galleryRepository) DeleteExhibitionByAsset(assetID int64) error {
|
||||
}).Error
|
||||
}
|
||||
|
||||
// GetExpiredExhibitions 获取过期的展品展示记录(不含已删除)
|
||||
// GetExpiredExhibitions 获取过期的展品展示记录(不含已删除且未处理)
|
||||
func (r *galleryRepository) GetExpiredExhibitions(beforeTime int64) ([]*models.Exhibition, error) {
|
||||
var exhibitions []*models.Exhibition
|
||||
err := r.db.Where("expire_at <= ? AND deleted_at IS NULL", beforeTime).Find(&exhibitions).Error
|
||||
err := r.db.Where("expire_at <= ? AND deleted_at IS NULL AND is_processed = false", beforeTime).Find(&exhibitions).Error
|
||||
return exhibitions, err
|
||||
}
|
||||
|
||||
@ -399,6 +401,13 @@ func (r *galleryRepository) UpdateExhibitionExpireAt(exhibitionID int64, expireA
|
||||
Update("expire_at", expireAt).Error
|
||||
}
|
||||
|
||||
// SetExhibitionProcessed 设置展品已处理标记(用于清理后标记已处理,防止重复生成收益记录)
|
||||
func (r *galleryRepository) SetExhibitionProcessed(exhibitionID int64, processed bool) error {
|
||||
return r.db.Model(&models.Exhibition{}).
|
||||
Where("id = ?", exhibitionID).
|
||||
Update("is_processed", processed).Error
|
||||
}
|
||||
|
||||
// ========== 我的作品相关实现 ==========
|
||||
|
||||
// GetMyExhibitedAssets 获取我展出的作品列表(返回展出中且未下架的,含收益)
|
||||
|
||||
@ -146,9 +146,9 @@ func (w *CleanupWorker) cleanupExpiredExhibitions(now int64) {
|
||||
|
||||
successCount++
|
||||
|
||||
// 4.5 更新展览过期时间为历史值,防止重复处理(领取收益时才会真正下架)
|
||||
if err := w.repo.UpdateExhibitionExpireAt(e.ID, now-3600000); err != nil {
|
||||
logger.Logger.Error("更新展览过期时间失败",
|
||||
// 4.5 标记展品已处理,防止重复生成收益记录
|
||||
if err := w.repo.SetExhibitionProcessed(e.ID, true); err != nil {
|
||||
logger.Logger.Error("标记展品已处理失败",
|
||||
zap.Int64("exhibition_id", e.ID),
|
||||
zap.Error(err))
|
||||
}
|
||||
|
||||
@ -147,6 +147,7 @@ type LikedAssetInfo struct {
|
||||
LikedAt int64
|
||||
Earnings int64
|
||||
HourlyEarnings float64
|
||||
IsLenticular bool // 是否为光栅卡
|
||||
}
|
||||
|
||||
// RandomUserInfo 随机用户信息
|
||||
@ -590,29 +591,29 @@ func (r *socialRepositoryImpl) GetMyLikedAssets(userID, starID int64, page, page
|
||||
}
|
||||
|
||||
// 计数查询(使用 DISTINCT 因为一个资产可能在多个展位展出)
|
||||
// 只要资产未删除且未下架就显示,包含已过期的(用户可继续查看点赞记录)
|
||||
// 显示:展品存在且未领取(is_processed=false),无论是否过期
|
||||
// 不显示:已领取的(is_processed=true)或从未展出过的
|
||||
countQuery := r.db.Model(&models.AssetLike{}).
|
||||
Joins("JOIN assets a ON a.id = asset_likes.asset_id").
|
||||
Joins("JOIN exhibitions e ON e.asset_id = a.id").
|
||||
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL AND e.is_processed = false").
|
||||
Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID).
|
||||
Where("a.deleted_at IS NULL AND a.is_active = ?", true).
|
||||
Where("e.deleted_at IS NULL")
|
||||
Where("a.deleted_at IS NULL AND a.is_active = ?", true)
|
||||
|
||||
if err := countQuery.Distinct("asset_likes.asset_id").Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 数据查询:只过滤已下架的,不过滤过期
|
||||
// 数据查询:只过滤已下架的,不过滤过期(已过期但未领取的仍显示)
|
||||
offset := (page - 1) * pageSize
|
||||
err := r.db.Model(&models.AssetLike{}).
|
||||
Select(`asset_likes.asset_id, a.name, a.cover_url, a.like_count,
|
||||
asset_likes.created_at as liked_at`).
|
||||
asset_likes.created_at as liked_at,
|
||||
(a.tags @> '["craft:lenticular"]') as is_lenticular`).
|
||||
Joins("JOIN assets a ON a.id = asset_likes.asset_id").
|
||||
Joins("JOIN exhibitions e ON e.asset_id = a.id").
|
||||
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL AND e.is_processed = false").
|
||||
Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID).
|
||||
Where("a.deleted_at IS NULL AND a.is_active = ?", true).
|
||||
Where("e.deleted_at IS NULL").
|
||||
Group("asset_likes.asset_id, a.name, a.cover_url, a.like_count, asset_likes.created_at").
|
||||
Group("asset_likes.asset_id, a.name, a.cover_url, a.like_count, asset_likes.created_at, is_lenticular").
|
||||
Order(orderClause).
|
||||
Limit(pageSize).
|
||||
Offset(offset).
|
||||
|
||||
@ -278,6 +278,7 @@ func (s *AssetLikeService) GetMyLikedAssets(ctx context.Context, req *pb.GetMyLi
|
||||
LikedAt: item.LikedAt,
|
||||
Earnings: item.Earnings,
|
||||
HourlyEarnings: item.HourlyEarnings,
|
||||
IsLenticular: item.IsLenticular,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -217,7 +217,7 @@
|
||||
.level-badge {
|
||||
position: absolute;
|
||||
background: linear-gradient(165deg, #F0E4B1 0%, #F08399 50%, #B94E73 90%, #834B9E 100%);
|
||||
width: 88rpx;
|
||||
width: 112rpx;
|
||||
height: 24rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@ -393,7 +393,7 @@ const handleExhibitionCardTap = (item, index) => {
|
||||
// exhibitionWorks.value[index].earnings = data.earnings;
|
||||
// } else {
|
||||
// 如果没有返回收益数据,刷新列表获取最新收益
|
||||
await loadExhibitedAssets();
|
||||
await loadLikedAssets();
|
||||
// }
|
||||
|
||||
uni.showToast({ title: '点赞成功', icon: 'success' });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user