refactor: space页面改为卡片式关注列表布局

- 重写 space/index.html:左右分栏,左侧导航栏 + 右侧卡片网格
- 自己空间:显示全部关注用户卡片(头像/用户名/简介/已关注标签)+ 设置入口
- 他人空间:简化侧栏(Ta的关注/粉丝),隐私关闭时显示空状态插图
- Model UserFollow 新增头像/简介联表字段
- Repository ListFollowing/ListFollowers SELECT 增加 avatar/bio
- Controller ShowSpace 注入 FollowService,获取关注列表数据
- space.css 完全重写为卡片网格布局 + 响应式适配
- follow.css 清理旧 .follow-btn/.follow-links 无用样式
This commit is contained in:
2026-06-01 21:18:04 +08:00
parent db2f9206be
commit 797e9c15f4
7 changed files with 509 additions and 379 deletions

View File

@ -5,6 +5,8 @@ import (
"strconv"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
"metazone.cc/metalab/internal/service"
"github.com/gin-gonic/gin"
)
@ -12,6 +14,7 @@ import (
// SpaceController 用户空间控制器
type SpaceController struct {
spaceService spaceUseCase
followSvc followUseCase
}
// NewSpaceController 构造函数
@ -19,6 +22,11 @@ func NewSpaceController(spaceService spaceUseCase) *SpaceController {
return &SpaceController{spaceService: spaceService}
}
// WithFollowService 注入关注服务(可选依赖)
func (ctrl *SpaceController) WithFollowService(svc followUseCase) {
ctrl.followSvc = svc
}
// MySpace 自己的空间(/space— 需登录,重定向到 /space/{uid}
func (ctrl *SpaceController) MySpace(c *gin.Context) {
uid, _, ok := common.GetGinUser(c)
@ -83,22 +91,30 @@ func (ctrl *SpaceController) ShowSpace(c *gin.Context) {
}
// 检查是否是自己的空间
isOwnSpace := false
if currentUID, _, ok := common.GetGinUser(c); ok {
isOwnSpace = currentUID == uint(uid)
currentUID, _, _ := common.GetGinUser(c)
isOwnSpace := currentUID == uint(uid)
// 获取关注列表数据
var followingResult *service.FollowListResult
if ctrl.followSvc != nil {
res, err := ctrl.followSvc.ListFollowing(uint(uid), currentUID, 1, 24)
if err != nil || res == nil {
res = &service.FollowListResult{Items: []model.UserFollow{}, Total: 0, Accessible: true}
}
followingResult = res
}
c.HTML(http.StatusOK, "space/index.html", common.BuildPageData(c, gin.H{
"Title": spaceUser.Username + " 的空间",
"SpaceUser": spaceUser,
"Posts": posts,
"Total": total,
"Page": page,
"TotalPages": totalPages,
"PrevPage": prevPage,
"NextPage": nextPage,
"IsOwnSpace": isOwnSpace,
"ExtraCSS": "/static/css/space.css",
"ExtraCSS2": "/static/css/follow.css",
"Title": spaceUser.Username + " 的空间",
"SpaceUser": spaceUser,
"Posts": posts,
"Total": total,
"Page": page,
"TotalPages": totalPages,
"PrevPage": prevPage,
"NextPage": nextPage,
"IsOwnSpace": isOwnSpace,
"FollowingResult": followingResult,
"ExtraCSS": "/static/css/space.css",
}))
}

View File

@ -11,4 +11,8 @@ type UserFollow struct {
// 联表查询填充(非数据库字段)
FollowerUsername string `gorm:"-:migration;<-:false;column:follower_username" json:"follower_username,omitempty"`
FolloweeUsername string `gorm:"-:migration;<-:false;column:followee_username" json:"followee_username,omitempty"`
FollowerAvatar string `gorm:"-:migration;<-:false;column:follower_avatar" json:"follower_avatar,omitempty"`
FolloweeAvatar string `gorm:"-:migration;<-:false;column:followee_avatar" json:"followee_avatar,omitempty"`
FollowerBio string `gorm:"-:migration;<-:false;column:follower_bio" json:"follower_bio,omitempty"`
FolloweeBio string `gorm:"-:migration;<-:false;column:followee_bio" json:"followee_bio,omitempty"`
}

View File

@ -56,7 +56,7 @@ func (r *FollowRepo) CountFollowing(userID uint) (int64, error) {
return count, err
}
// ListFollowers 粉丝列表分页JOIN users 获取用户名)
// ListFollowers 粉丝列表分页JOIN users 获取用户名、头像、简介
func (r *FollowRepo) ListFollowers(userID uint, offset, limit int) ([]model.UserFollow, int64, error) {
var total int64
if err := r.db.Model(&model.UserFollow{}).Where("followee_id = ?", userID).Count(&total).Error; err != nil {
@ -64,7 +64,7 @@ func (r *FollowRepo) ListFollowers(userID uint, offset, limit int) ([]model.User
}
var items []model.UserFollow
err := r.db.Table("user_follows").
Select("user_follows.*, u.username AS follower_username").
Select("user_follows.*, u.username AS follower_username, u.avatar AS follower_avatar, u.bio AS follower_bio").
Joins("INNER JOIN users u ON u.uid = user_follows.follower_id").
Where("user_follows.followee_id = ?", userID).
Order("user_follows.created_at DESC").
@ -73,7 +73,7 @@ func (r *FollowRepo) ListFollowers(userID uint, offset, limit int) ([]model.User
return items, total, err
}
// ListFollowing 关注列表分页JOIN users 获取用户名)
// ListFollowing 关注列表分页JOIN users 获取用户名、头像、简介
func (r *FollowRepo) ListFollowing(userID uint, offset, limit int) ([]model.UserFollow, int64, error) {
var total int64
if err := r.db.Model(&model.UserFollow{}).Where("follower_id = ?", userID).Count(&total).Error; err != nil {
@ -81,7 +81,7 @@ func (r *FollowRepo) ListFollowing(userID uint, offset, limit int) ([]model.User
}
var items []model.UserFollow
err := r.db.Table("user_follows").
Select("user_follows.*, u.username AS followee_username").
Select("user_follows.*, u.username AS followee_username, u.avatar AS followee_avatar, u.bio AS followee_bio").
Joins("INNER JOIN users u ON u.uid = user_follows.followee_id").
Where("user_follows.follower_id = ?", userID).
Order("user_follows.created_at DESC").

View File

@ -85,6 +85,7 @@ func buildDeps(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSetting
// 用户空间
spaceService := service.NewSpaceService(userRepo, postRepo)
spaceCtrl := controller.NewSpaceController(spaceService)
spaceCtrl.WithFollowService(followService)
// 收藏夹系统
favoriteRepo := repository.NewFavoriteRepo(db)