feat(street): 公开 API 详情新增主副图分组字段

This commit is contained in:
toom1996
2026-09-21 22:35:28 +08:00
parent ed92b475d1
commit be73e595ca
3 changed files with 139 additions and 6 deletions

View File

@ -134,14 +134,72 @@ func (s *streetSnapService) Detail(ctx context.Context, id string) (*dto.PublicS
return nil, internalErr(err.Error())
}
flat, groups := s.groupSnapImages(imgs)
return &dto.PublicStreetSnapDetail{
UID: hashid.EncodeWithType(snap.ID, hashid.TypeSnap),
Title: snap.Title,
Cover: s.img.Compose(snap.Cover),
Images: s.toPublicSnapImages(imgs),
Images: flat,
Groups: groups,
}, nil
}
// groupSnapImages 把街拍图片按主副图分组:主图各成一组,副图归入其(存活)主图组。
// 父引用指向「副图」时沿链向上归并到该副图所在组的主图;父行缺失(被软删)则把该图按主图渲染(不丢图)。
// 返回的 flat(扁平)与 groups 同源同序:groups 中每张主图对应的 Details 顺序,等于 flat 中该主图之后的副图出现顺序。
func (s *streetSnapService) groupSnapImages(imgs []model.StreetSnapImage) ([]dto.PublicArticleImage, []dto.PublicStreetSnapGroup) {
if len(imgs) == 0 {
return nil, nil
}
flat := s.toPublicSnapImages(imgs)
byID := make(map[uint32]*model.StreetSnapImage, len(imgs))
for i := range imgs {
byID[imgs[i].ID] = &imgs[i]
}
// resolveRoot 返回 img 所属主图的行 id;自身是主图则返回自身;父行缺失 / 成环则按主图渲染(返回自身)。
resolveRoot := func(start uint32) uint32 {
cur := start
seen := map[uint32]bool{}
for {
n, ok := byID[cur]
if !ok {
return start // 父行不存在 → 按主图渲染(返回自身)
}
if n.IsDetail == 0 {
return n.ID
}
if seen[cur] {
return start // 环 → 容错,自成主图
}
seen[cur] = true
cur = n.ParentImageID
}
}
groups := make([]dto.PublicStreetSnapGroup, 0, len(imgs))
index := make(map[uint32]int, len(imgs))
for i, im := range imgs {
root := resolveRoot(im.ID)
isDetail := root != im.ID
ref := flat[i]
if !isDetail {
groups = append(groups, dto.PublicStreetSnapGroup{Image: ref})
index[im.ID] = len(groups) - 1
continue
}
if gi, ok := index[root]; ok {
groups[gi].Details = append(groups[gi].Details, ref)
} else {
// 兜底(理论不发生):主图未先出现,自成一组
groups = append(groups, dto.PublicStreetSnapGroup{Image: ref})
index[im.ID] = len(groups) - 1
}
}
return flat, groups
}
// IDs 返回全部街拍的编码 uid(供 SSG 枚举详情页路径使用,对外暴露的即编码串)。
// Popular 返回热度前 N 个街拍(按图片数降序),供 SSG 首页热门街拍展示。
func (s *streetSnapService) Popular(ctx context.Context, limit int) ([]dto.PublicStreetSnap, error) {