package mysqldao import ( "context" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/global" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/mysqlmodel" "gorm.io/gorm" "gorm.io/gorm/clause" ) // CollectDao 收藏数据访问 type CollectDao struct { db *gorm.DB } // NewCollectDao 创建收藏 DAO func NewCollectDao() *CollectDao { return &CollectDao{db: global.MysqlEngine} } // CollectCreate 创建收藏记录 func (d *CollectDao) CollectCreate(ctx context.Context, collect *mysqlmodel.Collect) error { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectCreate") defer span.End() if err := d.db.WithContext(ctx).Create(collect).Error; err != nil { span.RecordError(err) return err } return nil } // CollectUpsertOn 收藏幂等写入:唯一索引冲突时仅置 status=1,防并发重复插入。 func (d *CollectDao) CollectUpsertOn(ctx context.Context, collect *mysqlmodel.Collect) error { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectUpsertOn") defer span.End() if err := d.db.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "collect_type"}, {Name: "target_id"}, {Name: "user_id"}}, DoUpdates: clause.AssignmentColumns([]string{"status"}), }).Create(collect).Error; err != nil { span.RecordError(err) return err } return nil } // CollectUpdateStatus 更新收藏状态(1=已收藏 0=已取消) func (d *CollectDao) CollectUpdateStatus(ctx context.Context, id int64, status int8) error { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectUpdateStatus") defer span.End() if err := d.db.WithContext(ctx).Model(&mysqlmodel.Collect{}).Where("id = ?", id).UpdateColumn("status", status).Error; err != nil { span.RecordError(err) return err } return nil } // CollectGetByTargetAndUser 查询用户在目标上的收藏记录 func (d *CollectDao) CollectGetByTargetAndUser(ctx context.Context, collectType int8, targetID, userID int64) (*mysqlmodel.Collect, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectGetByTargetAndUser") defer span.End() var collect mysqlmodel.Collect if err := d.db.WithContext(ctx).Where("collect_type = ? AND target_id = ? AND user_id = ?", collectType, targetID, userID).First(&collect).Error; err != nil { span.RecordError(err) return nil, err } return &collect, nil } // CollectCountByTarget 统计目标收藏数(仅 status=1) func (d *CollectDao) CollectCountByTarget(ctx context.Context, collectType int8, targetID int64) (int64, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectCountByTarget") defer span.End() var count int64 if err := d.db.WithContext(ctx).Model(&mysqlmodel.Collect{}). Where("collect_type = ? AND target_id = ? AND status = ?", collectType, targetID, int8(1)). Count(&count).Error; err != nil { span.RecordError(err) return 0, err } return count, nil } // CollectCountByTargets 批量统计多个目标的收藏数(仅 status=1),返回 targetID -> count;空入参短路。 func (d *CollectDao) CollectCountByTargets(ctx context.Context, collectType int8, targetIDs []int64) (map[int64]int64, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectCountByTargets") defer span.End() counts := make(map[int64]int64, len(targetIDs)) if len(targetIDs) == 0 { return counts, nil } var rows []struct { TargetID int64 `gorm:"column:target_id"` Cnt int64 `gorm:"column:cnt"` } if err := d.db.WithContext(ctx).Model(&mysqlmodel.Collect{}). Select("target_id, COUNT(*) AS cnt"). Where("collect_type = ? AND target_id IN ? AND status = ?", collectType, targetIDs, int8(1)). Group("target_id"). Scan(&rows).Error; err != nil { span.RecordError(err) return nil, err } for _, r := range rows { counts[r.TargetID] = r.Cnt } return counts, nil } // CollectListTargetIDsByUserPage 分页查询用户收藏的目标ID列表(仅 status=1,且目标穿搭对本人可见),返回 ids 与总数。 // // 可见性口径与 service.isOutfitPublicVisible 保持一致:本人收藏自己的穿搭始终可见; // 收藏他人穿搭要求「公开(2) + 审核通过(2) + 状态正常(1)」。 // 联表过滤而非服务层过滤,是为了让 total 与实际返回条数口径一致 //(此前只按 collects 计数,穿搭转私/删除后会返回 total 虚高、页内条数偏少的空洞页)。 func (d *CollectDao) CollectListTargetIDsByUserPage(ctx context.Context, collectType int8, userID int64, page, pageSize int) ([]int64, int64, error) { ctx, span := global.Tracer.Start(ctx, "mysqldao.CollectListTargetIDsByUserPage") defer span.End() q := d.db.WithContext(ctx).Model(&mysqlmodel.Collect{}). Joins("JOIN outfits o ON o.id = collects.target_id AND o.deleted_at = 0"). Where("collects.collect_type = ? AND collects.user_id = ? AND collects.status = ?", collectType, userID, int8(1)). Where("o.user_id = ? OR (o.is_public = ? AND o.audit_status = ? AND o.status = ?)", userID, 2, 2, 1) var total int64 if err := q.Count(&total).Error; err != nil { span.RecordError(err) return nil, 0, err } var ids []int64 if err := q.Order("collects.id DESC").Offset((page-1)*pageSize).Limit(pageSize). Pluck("collects.target_id", &ids).Error; err != nil { span.RecordError(err) return nil, 0, err } return ids, total, nil }