diff --git a/auto/api/v1/rank.go b/auto/api/v1/rank.go new file mode 100644 index 00000000..cf6bf9a2 --- /dev/null +++ b/auto/api/v1/rank.go @@ -0,0 +1,69 @@ +package v1 + +import ( + "github.com/alimy/mir/v4" + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/model/web" + "net/http" +) + +type Rank interface { + _default_ + + GetHighQuality() ([]*web.GetHighQualityRankingResp, mir.Error) + + mustEmbedUnimplementedRankServant() + //GetRankList(req *web.GetRankListReq) (interface{}, interface{}) + //Chain() gin.HandlersChain +} + +// RegisterRankServant 注册路由 +func RegisterRankServant(e *gin.Engine, s Rank) { + router := e.Group("v1") + // use chain for router + //middlewares := s.Chain() + //router.Use(middlewares...) + + //注册路由 + router.Handle("GET", "/rank/highquality", func(c *gin.Context) { + select { + case <-c.Request.Context().Done(): + return + default: + } + //获取GetHighQuality完成后的数据,然后将其放到GetHighQualityResp中,并返回 + resp := new(web.GetHighQualityResp) + highQualityRanking, err := s.GetHighQuality() + resp.List = highQualityRanking + s.Render(c, resp, err) + }) + + //获取所有的rank + //router.Handle("GET", "/rank/list", func(c *gin.Context) { + // select { + // case <-c.Request.Context().Done(): + // return + // default: + // } + // req := new(web.GetRankListReq) + // var bv _binding_ = req + // if err := bv.Bind(c); err != nil { + // s.Render(c, nil, err) + // return + // } + // //返回值 + // resp, err := s.GetRankList(req) + // s.Render(c, resp, err) + //} + +} + +// UnimplementedRankServant can be embedded to have forward compatible implementations. +type UnimplementedRankServant struct{} + +// GetHighQuality 设置RegisterRankServant的默认实现 +func (UnimplementedRankServant) GetHighQuality() (*web.GetHighQualityRankingResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +} + +func (UnimplementedRankServant) mustEmbedUnimplementedRankServant() {} diff --git a/auto/api/v1/share_key.go b/auto/api/v1/share_key.go index e7f38795..3cf8d72b 100644 --- a/auto/api/v1/share_key.go +++ b/auto/api/v1/share_key.go @@ -57,7 +57,6 @@ func RegisterKeyQueryServant(e *gin.Engine, s KeyQuery) { resp, err := s.DeleteKeyDetail(req) s.Render(c, resp, err) }) - } type UnimplementedShareKeyServant struct{} diff --git a/internal/core/core.go b/internal/core/core.go index 1f51b02b..f3d48932 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -37,6 +37,9 @@ type DataService interface { // share_key服务 ShareKeyService + + //排行榜服务 + RankService } // WebDataServantA Web数据服务集成(版本A) diff --git a/internal/core/rank.go b/internal/core/rank.go new file mode 100644 index 00000000..5300880f --- /dev/null +++ b/internal/core/rank.go @@ -0,0 +1,13 @@ +package core + +import ( + "github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr" +) + +type ( + GetHighQualityRankingResp = dbr.GetHighQualityRankingResp +) + +type RankService interface { + GetHighQualityRanking() ([]*GetHighQualityRankingResp, error) +} diff --git a/internal/dao/jinzhu/dbr/rank.go b/internal/dao/jinzhu/dbr/rank.go new file mode 100644 index 00000000..410d7d95 --- /dev/null +++ b/internal/dao/jinzhu/dbr/rank.go @@ -0,0 +1,24 @@ +package dbr + +type Rank struct { + UserName string `json:"user_name"` + ShareKey string `json:"share_key"` + AllDownLoadCount int `json:"all_download_count"` + DownloadCountPerWeek int `json:"download_count_per_week"` + DownloadCountPerMonth int `json:"download_count_per_month"` +} + +type HighQualityRanking struct { + UserName string `json:"user_name"` + UserId int `json:"user_id"` + Avatar string `json:"avatar"` +} + +// GetHighQualityRankingResp 优质榜单返回数据 +type GetHighQualityRankingResp struct { + UserName string `json:"name"` + Avatar string `json:"avatar"` + PostCount int64 `json:"post_count"` + LikesCount int64 `json:"likes"` + ComprehensiveScore int64 `json:"comprehensive_score"` +} diff --git a/internal/dao/jinzhu/jinzhu.go b/internal/dao/jinzhu/jinzhu.go index 55055f63..1554f331 100644 --- a/internal/dao/jinzhu/jinzhu.go +++ b/internal/dao/jinzhu/jinzhu.go @@ -45,6 +45,7 @@ type dataSrv struct { core.SecurityService core.AttachmentCheckService core.ShareKeyService + core.RankService } type webDataSrvA struct { @@ -114,6 +115,7 @@ func NewDataService() (core.DataService, core.VersionInfo) { SecurityService: newSecurityService(db, pvs), AttachmentCheckService: security.NewAttachmentCheckService(), ShareKeyService: NewShareKeyService(db), + RankService: NewRankService(db), } return ds, ds } diff --git a/internal/dao/jinzhu/rank.go b/internal/dao/jinzhu/rank.go new file mode 100644 index 00000000..4cc3104c --- /dev/null +++ b/internal/dao/jinzhu/rank.go @@ -0,0 +1,143 @@ +package jinzhu + +import ( + "fmt" + "github.com/rocboss/paopao-ce/internal/core" + "github.com/rocboss/paopao-ce/internal/core/ms" + "gorm.io/gorm" + "sort" + "strconv" + "strings" +) + +type RankService struct { + db *gorm.DB +} + +func NewRankService(db *gorm.DB) *RankService { + return &RankService{db: db} +} + +type UserPosts struct { + UserId int64 + PostId []int64 +} + +type UserScore struct { + //用户id + UserId int64 + //用户名 + Username string + //用户头像 + Avatar string + //帖子数量&得分,一个帖子是1分 + PostCount int64 + //图像得分,一个图像加2分 + ImageCount int64 + //视频得分,一个视频加2分 + VideoCount int64 + //点赞总数 + LikeCount int64 + //评论总数 + CommentCount int64 + //分享码得分 + ShareCodeCount int64 + //总分 + Score int64 +} + +// GetHighQualityRanking 优质榜单函数 +func (s RankService) GetHighQualityRanking() ([]*core.GetHighQualityRankingResp, error) { + //获取p_post表的所有数据 + var posts []*ms.Post + err := s.db.Table("p_post").Find(&posts).Error + //一个用户对应一个总分,建立一个map + var userScores = make(map[int64]*UserScore) + //判断posts是否为空 + if len(posts) == 0 { + fmt.Print("posts is empty") + return nil, nil + } + for _, post := range posts { + //根据user_id获取用户信息,其中包括用户名,用户头像 + var user ms.User + //如果userScores中没有该用户的信息,则新建一个用户信息 + if _, ok := userScores[post.UserID]; !ok { + userScores[post.UserID] = &UserScore{} + err = s.db.Table("p_user").Select("id,username,avatar").Where("id = ?", post.UserID).Find(&user).Error + if err != nil { + fmt.Print("get user info error") + return nil, err + } + userScores[post.UserID].Username = user.Username + userScores[post.UserID].Avatar = user.Avatar + } + + var userPostContent []*ms.PostContent + userScores[post.UserID].LikeCount += post.UpvoteCount + userScores[post.UserID].CommentCount += post.CommentCount + //根据post_id查询p_post_content表,获取type + err = s.db.Table("p_post_content").Select("post_id,type,content").Where("post_id = ?", post.ID).Find(&userPostContent).Error + if err != nil { + return nil, err + } + //userPostCount[post.UserId] = userPostCount[post.UserId] + 1 + //计算每个用户发帖是否存在正文、图像、视频,即查询p_post_content表,若帖子id对应的type存在3或4,则存在图像或视频 + for _, postContent := range userPostContent { + //有正文内容的帖子加1分 + if postContent.Type == 2 { + userScores[post.UserID].PostCount = userScores[post.UserID].PostCount + 1 + //判断正文字符串中是否包含其用户名,若存在,则加5分 + var userNameStr = userScores[post.UserID].Username + "-" + if strings.Index(postContent.Content, userNameStr) != -1 { + userScores[post.UserID].ShareCodeCount = userScores[post.UserID].ShareCodeCount + 5 + } + } + if postContent.Type == 3 { + //总分加2 + userScores[post.UserID].ImageCount = userScores[post.UserID].ImageCount + 2 + } else if postContent.Type == 4 { + //总分加2 + userScores[post.UserID].VideoCount = userScores[post.UserID].VideoCount + 2 + } + } + } + //计算每个用户的总分 + for _, userScore := range userScores { + userScore.Score = (userScore.PostCount + userScore.ImageCount + userScore.VideoCount + userScore.ShareCodeCount) * ((userScore.LikeCount*3 + userScore.CommentCount) / 10) + } + + // 对userScore排序 + var userScoreSlice []*UserScore + for _, userScore := range userScores { + userScoreSlice = append(userScoreSlice, userScore) + } + sort.Slice(userScoreSlice, func(i, j int) bool { + return userScoreSlice[i].Score > userScoreSlice[j].Score + }) + var rank []*core.GetHighQualityRankingResp + var i = 0 + //将userScoreSlice中的数据放到rank中 + for _, userScore := range userScoreSlice { + if i >= 5 { + break + } + i++ + fmt.Print(userScore.Username + " " + strconv.FormatInt(userScore.CommentCount, 10) + + " " + strconv.FormatInt(userScore.LikeCount, 10) + + " " + strconv.FormatInt(userScore.ImageCount, 10) + + " " + strconv.FormatInt(userScore.PostCount, 10) + + " " + strconv.FormatInt(userScore.VideoCount, 10) + + " " + strconv.FormatInt(userScore.ShareCodeCount, 10) + + " " + strconv.FormatInt(userScore.Score, 10) + + "\n") + rank = append(rank, &core.GetHighQualityRankingResp{ + UserName: userScore.Username, + Avatar: userScore.Avatar, + PostCount: userScore.PostCount, + LikesCount: userScore.LikeCount, + ComprehensiveScore: userScore.Score, + }) + } + return rank, nil +} diff --git a/internal/model/web/rank.go b/internal/model/web/rank.go new file mode 100644 index 00000000..52499d3a --- /dev/null +++ b/internal/model/web/rank.go @@ -0,0 +1,37 @@ +package web + +import ( + "github.com/alimy/mir/v4" + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/pkg/convert" +) + +// GetHighQualityResp 构造相应参数,包含一个GetHighQualityRankingResp数组 +type GetHighQualityResp struct { + List any `json:"list"` +} + +type GetHighQualityRankingResp struct { + UserName string `json:"name"` + Avatar string `json:"avatar"` + PostCount int64 `json:"post_count"` + LikesCount int64 `json:"likes"` + ComprehensiveScore int64 `json:"comprehensive_score"` +} + +type GetRankListReq struct { + ListType string `json:"list_type"` +} + +type GetRankListResp struct { + UserName string `json:"name"` + Avatar string `json:"avatar"` + PostCount int64 `json:"post_count"` + LikesCount int64 `json:"likes"` + ComprehensiveScore int64 `json:"comprehensive_score"` +} + +func (g *GetRankListReq) Bind(c *gin.Context) mir.Error { + g.ListType = convert.StrTo(c.Query("list_type")).String() + return nil +} diff --git a/internal/model/web/share_key.go b/internal/model/web/share_key.go index e4dc66bd..a1f9c79c 100644 --- a/internal/model/web/share_key.go +++ b/internal/model/web/share_key.go @@ -36,7 +36,7 @@ type KeyInfo struct { type GetUserKeysResp base.PageResp -// 逻辑删除服务 +// DeleteKeyReq 逻辑删除服务 type DeleteKeyReq struct { ShareKey string `json:"share_key"` UserId int64 diff --git a/internal/model/web/xerror.go b/internal/model/web/xerror.go index 4f4bde57..5d935bdb 100644 --- a/internal/model/web/xerror.go +++ b/internal/model/web/xerror.go @@ -97,5 +97,7 @@ var ( ErrDeleteUserKeyFailed = xerror.NewError(11004, "删除用户Share Key失败") ErrGetUserShareKeyCountFailed = xerror.NewError(11005, "获取用户Share Key数量失败") + ErrGetHighQualityRankingFailed = xerror.NewError(12001, "获取优质帖子排行榜失败") + ErrNotImplemented = xerror.NewError(10501, "功能未实现") ) diff --git a/internal/servants/web/rank.go b/internal/servants/web/rank.go new file mode 100644 index 00000000..14d4b728 --- /dev/null +++ b/internal/servants/web/rank.go @@ -0,0 +1,57 @@ +package web + +import ( + "github.com/alimy/mir/v4" + "github.com/gin-gonic/gin" + api "github.com/rocboss/paopao-ce/auto/api/v1" + "github.com/rocboss/paopao-ce/internal/model/web" + "github.com/rocboss/paopao-ce/internal/servants/base" + "github.com/rocboss/paopao-ce/internal/servants/chain" + "github.com/sirupsen/logrus" +) + +var ( + _ api.Rank = (*rankSrv)(nil) +) + +type rankSrv struct { + api.UnimplementedRankServant + *base.DaoServant +} + +func (s *rankSrv) Chain() gin.HandlersChain { + return gin.HandlersChain{chain.JWT()} +} + +func (s *rankSrv) GetHighQuality() ([]*web.GetHighQualityRankingResp, mir.Error) { + if s.Ds == nil { + logrus.Errorf("GetKeyDetail err: %s", web.ErrDsNil) + return nil, web.ErrDsNil + } else { + logrus.Info("GetKeyDetail success") + } + //调用数据源的方式查询所有的rank信息 + ranks, err := s.Ds.GetHighQualityRanking() + if err != nil { + return nil, web.ErrGetHighQualityRankingFailed + } + + //将查询到的rank信息转换为GetHighQualityRankingResp结构体 + var rankInfos []*web.GetHighQualityRankingResp + for _, rank := range ranks { + rankInfos = append(rankInfos, &web.GetHighQualityRankingResp{ + UserName: rank.UserName, + Avatar: rank.Avatar, + PostCount: rank.PostCount, + LikesCount: rank.LikesCount, + ComprehensiveScore: rank.ComprehensiveScore, + }) + } + return rankInfos, nil +} + +func NewRankServant(ds *base.DaoServant) api.Rank { + return &rankSrv{ + DaoServant: ds, + } +} diff --git a/internal/servants/web/web.go b/internal/servants/web/web.go index f034a26e..b82d4f53 100644 --- a/internal/servants/web/web.go +++ b/internal/servants/web/web.go @@ -33,6 +33,7 @@ func RouteWeb(e *gin.Engine) { api.RegisterPrivServant(e, newPrivSrv(ds, oss)) api.RegisterPubServant(e, newPubSrv(ds)) api.RegisterKeyQueryServant(e, NewShareKeyServant(ds)) + api.RegisterRankServant(e, NewRankServant(ds)) // regster servants if needed by configure cfg.In(cfg.Actions{ "Alipay": func() { diff --git a/web/src/api/post.ts b/web/src/api/post.ts index a4df3979..250cd56c 100644 --- a/web/src/api/post.ts +++ b/web/src/api/post.ts @@ -22,6 +22,14 @@ export const getTags = ( }); }; +/** 获取优质帖榜 */ +export const getHighQuailty = (): Promise => { + return request({ + method: "get", + url: "/v1/rank/highquality", + }); +} + /** 获取动态详情 */ export const getPost = ( params: NetParams.PostGetPost diff --git a/web/src/components/rightbar.vue b/web/src/components/rightbar.vue index 028759d3..9e1f4a87 100644 --- a/web/src/components/rightbar.vue +++ b/web/src/components/rightbar.vue @@ -1,222 +1,366 @@ \ No newline at end of file diff --git a/web/src/types/Item.d.ts b/web/src/types/Item.d.ts index df3b13ef..8d54e849 100644 --- a/web/src/types/Item.d.ts +++ b/web/src/types/Item.d.ts @@ -334,4 +334,18 @@ declare module Item { //描述 description: string; } + + //优质榜参数 + interface highqualityProps { + //用户名 + name: string; + //头像 + avatar: string; + //发帖数量 + post_count: number; + //被赞数量 + likes: number; + //总得分 + comprehensive_score: number; + } } diff --git a/web/src/types/NetReq.d.ts b/web/src/types/NetReq.d.ts index 280eff54..183b69be 100644 --- a/web/src/types/NetReq.d.ts +++ b/web/src/types/NetReq.d.ts @@ -168,6 +168,11 @@ declare module NetReq { pager: Item.PagerProps; } + interface PostGetHighQuailty { + /** 帖子列表 */ + list: Item.highqualityProps[]; + } + type PostCreatePost = Item.PostProps; interface PostDeletePost {}