by Robin at 20241206

This commit is contained in:
Robin 2024-12-06 17:41:45 +08:00
parent 30f874af1f
commit 289b4616ad
10 changed files with 289 additions and 5 deletions

View File

@ -100,3 +100,5 @@ const (
)
const ZoneAdmissionPrice_NoZone = int64(-999999)
const ActivityHot_QueryLimit = 20

View File

@ -340,3 +340,15 @@ const (
RavenIQTest_VType_Visit = 0 // 访问
RavenIQTest_VType_Paid = 1 // 付款
)
// 热榜状态
const (
ActivityHotStatus_Normal = 0 // 已生效
ActivityHotStatus_Paused = 1 // 已暂停
)
// 活动Banner状态
const (
ActivityBannerStatus_Normal = 0 // 已生效
ActivityBannerStatus_Paused = 1 // 已暂停
)

View File

@ -0,0 +1,23 @@
package proto
import "service/dbstruct"
type ActivityBannerApiVO struct {
Image *dbstruct.MediaComponent `json:"image" bson:"image"` // 主图
Title string `json:"title" bson:"title"` // 标题
Hyperlinks []*dbstruct.Hyperlink `json:"hyperlinks" bson:"hyperlinks"` // 跳转链接
}
func NewActivityBannerApiVO() *ActivityBannerApiVO {
return &ActivityBannerApiVO{}
}
func (vo *ActivityBannerApiVO) CopyActivityBanner(activityBanner *dbstruct.ActivityBanner) *ActivityBannerApiVO {
if activityBanner == nil {
return vo
}
vo.Image = activityBanner.Image
vo.Title = activityBanner.GetTitle()
vo.Hyperlinks = activityBanner.Hyperlinks
return vo
}

View File

@ -0,0 +1,54 @@
package proto
import (
"service/dbstruct"
)
type ActivityHotApiVO struct {
Mid int64 `json:"mid" bson:"mid"` // 主播mid
Image *dbstruct.MediaComponent `json:"image" bson:"image"` // 主图
Title string `json:"title" bson:"title"` // 标题
Text string `json:"text" bson:"text"` // 文字内容
Hyperlinks []*dbstruct.Hyperlink `json:"hyperlinks" bson:"hyperlinks"` // 跳转链接
}
func NewActivityHotApiVO() *ActivityHotApiVO {
return &ActivityHotApiVO{}
}
func (vo *ActivityHotApiVO) CopyActivityHot(activityHot *dbstruct.ActivityHot) *ActivityHotApiVO {
if activityHot == nil {
return vo
}
vo.Mid = activityHot.GetMid()
vo.Image = activityHot.Image
vo.Title = activityHot.GetTitle()
vo.Text = activityHot.GetText()
vo.Hyperlinks = activityHot.Hyperlinks
return vo
}
func (vo *ActivityHotApiVO) CopyZone(zone *dbstruct.Zone) *ActivityHotApiVO {
if zone == nil {
return vo
}
vo.Text = zone.GetProfile()
return vo
}
func (vo *ActivityHotApiVO) CopyAccount(account *dbstruct.Account) *ActivityHotApiVO {
if account == nil {
return vo
}
vo.Image = account.Avatar
vo.Title = account.GetName()
return vo
}
func (vo *ActivityHotApiVO) CopyHyperlinks(getFunc func(mid int64) []*dbstruct.Hyperlink) *ActivityHotApiVO {
if getFunc == nil {
return vo
}
vo.Hyperlinks = getFunc(vo.Mid)
return vo
}

View File

@ -4818,6 +4818,20 @@ func (m *Mongo) GetMidsByZids(ctx *gin.Context, zids []int64) ([]int64, error) {
return mids, err
}
func (m *Mongo) GetMids(ctx *gin.Context) ([]int64, error) {
col := m.getColZone()
query := qmgo.M{
"del_flag": 0,
}
mids := make([]int64, 0)
err := col.Find(ctx, query).Distinct("mid", &mids)
if err == qmgo.ErrNoSuchDocuments {
err = nil
return make([]int64, 0), err
}
return mids, err
}
func (m *Mongo) RecordZoneStatisticsById(ctx *gin.Context, id int64, zoneMomentCount int64, imageCount int64, videoCount int64) error {
col := m.getColZone()
up := qmgo.M{
@ -6574,7 +6588,7 @@ func (m *Mongo) GetActivityHotList(ctx *gin.Context, req *activity_hot_proto.OpL
}
}
err := col.Find(ctx, query).Sort("-ct").Skip(int64(req.Offset)).Limit(int64(req.Limit)).All(&list)
err := col.Find(ctx, query).Sort("-priority").Skip(int64(req.Offset)).Limit(int64(req.Limit)).All(&list)
if err == qmgo.ErrNoSuchDocuments {
err = nil
return list, err

View File

@ -4465,23 +4465,63 @@ func (s *Service) ApiGetRavenIQTestVisitCount(ctx *gin.Context, req *Raven_IQ_te
return
}
func (s *Service) ApiGetActivityHotList(ctx *gin.Context, req *activity_hot_proto.ApiListReq) (list []*dbstruct.ActivityHot, ec errcode.ErrCode) {
func (s *Service) ApiGetActivityHotList(ctx *gin.Context, req *activity_hot_proto.ApiListReq) (volist []*activity_hot_proto.ActivityHotApiVO, ec errcode.ErrCode) {
ec = errcode.ErrCodeActivityHotSrvOk
volist = make([]*activity_hot_proto.ActivityHotApiVO, 0)
// 先尝试从编推里拿出指定数量的主播
list, err := _DefaultActivityHot.OpList(ctx, &activity_hot_proto.OpListReq{
BaseRequest: req.BaseRequest,
Offset: req.Offset,
Limit: req.Limit,
Status: goproto.Int64(consts.ActivityHotStatus_Normal),
Offset: 0,
Limit: consts.ActivityHot_QueryLimit,
})
if err != nil {
logger.Error("OpGetActivityHotList fail, req: %v, err: %v", util.ToJson(req), err)
ec = errcode.ErrCodeActivityHotSrvFail
return
}
// 做map和mids
activityHotMp := make(map[int64]*dbstruct.ActivityHot)
mids := make([]int64, 0)
for _, v := range list {
activityHotMp[v.GetMid()] = v
mids = append(mids, v.GetMid())
}
// 填充信息
if len(list) > 0 {
vl, err := s.utilFillActivityHotVO(ctx, activityHotMp, mids)
if err != nil {
logger.Error("utilFillActivityHotVO fail, req: %v, err: %v", util.ToJson(req), err)
ec = errcode.ErrCodeActivityHotSrvFail
return
}
volist = append(volist, vl...)
}
// 再补足剩余的主播
remLength := consts.ActivityHot_QueryLimit - len(list)
if remLength > 0 {
vl, err := s.utilCompleteActivityHotList(ctx, activityHotMp, remLength)
if err != nil {
logger.Error("utilCompleteActivityHotList fail, req: %v, err: %v", util.ToJson(req), err)
ec = errcode.ErrCodeActivityHotSrvFail
return
}
volist = append(volist, vl...)
}
return
}
func (s *Service) ApiGetActivityBannerList(ctx *gin.Context, req *activity_banner_proto.ApiListReq) (list []*dbstruct.ActivityBanner, ec errcode.ErrCode) {
func (s *Service) ApiGetActivityBannerList(ctx *gin.Context, req *activity_banner_proto.ApiListReq) (volist []*activity_banner_proto.ActivityBannerApiVO, ec errcode.ErrCode) {
ec = errcode.ErrCodeActivityBannerSrvOk
volist = make([]*activity_banner_proto.ActivityBannerApiVO, 0)
list, err := _DefaultActivityBanner.OpList(ctx, &activity_banner_proto.OpListReq{
BaseRequest: req.BaseRequest,
DeviceType: req.DeviceType,
@ -4493,5 +4533,10 @@ func (s *Service) ApiGetActivityBannerList(ctx *gin.Context, req *activity_banne
ec = errcode.ErrCodeActivityBannerSrvFail
return
}
for _, activityBanner := range list {
volist = append(volist, activity_banner_proto.NewActivityBannerApiVO().CopyActivityBanner(activityBanner))
}
return
}

View File

@ -5061,6 +5061,8 @@ func (s *Service) OpCreateActivityHot(ctx *gin.Context, req *activity_hot_proto.
return
}
// 新创建的活动默认直接生效
req.ActivityHot.Status = goproto.Int64(consts.ActivityHotStatus_Normal)
err := _DefaultActivityHot.OpCreate(ctx, req)
if err != nil {
logger.Error("OpCreate fail, req: %v, err: %v", util.ToJson(req), err)
@ -5111,6 +5113,9 @@ func (s *Service) OpGetActivityHotList(ctx *gin.Context, req *activity_hot_proto
// ActivityBanner
func (s *Service) OpCreateActivityBanner(ctx *gin.Context, req *activity_banner_proto.OpCreateReq) (ec errcode.ErrCode) {
ec = errcode.ErrCodeActivityBannerSrvOk
// 新创建的活动默认直接生效
req.ActivityBanner.Status = goproto.Int64(consts.ActivityBannerStatus_Normal)
err := _DefaultActivityBanner.OpCreate(ctx, req)
if err != nil {
logger.Error("OpCreate fail, req: %v, err: %v", util.ToJson(req), err)

View File

@ -10,6 +10,7 @@ import (
"service/api/message/request"
accountproto "service/api/proto/account/proto"
accountrelationproto "service/api/proto/accountrelation/proto"
activity_hot_proto "service/api/proto/activity_hot/proto"
contact_customer_service_sessionproto "service/api/proto/contact_customer_service_session/proto"
imageauditproto "service/api/proto/imageaudit/proto"
imageaudittaskproto "service/api/proto/imageaudittask/proto"
@ -2208,3 +2209,111 @@ func (s *Service) UtilEncryptVideosForZoneMomentVOs(ctx *gin.Context, list []*zo
}
}
}
func (s *Service) utilFillActivityHotVO(ctx *gin.Context, activityHotMp map[int64]*dbstruct.ActivityHot, mids []int64) ([]*activity_hot_proto.ActivityHotApiVO, error) {
volist := make([]*activity_hot_proto.ActivityHotApiVO, 0)
acctMp, err := _DefaultAccount.GetAccountMapByMids(ctx, mids)
if err != nil {
logger.Error("GetAccountMapByMids failed, err: %v", err)
return make([]*activity_hot_proto.ActivityHotApiVO, 0), err
}
zoneMp, err := _DefaultZone.GetZoneMapByMids(ctx, mids)
if err != nil {
logger.Error("GetZoneMapByMids failed, err: %v", err)
return make([]*activity_hot_proto.ActivityHotApiVO, 0), err
}
for mid, activityHot := range activityHotMp {
vo := activity_hot_proto.NewActivityHotApiVO().CopyActivityHot(activityHot)
if activityHot.Image == nil { // 主图为空,填充头像
vo.Image = acctMp[mid].Avatar
}
if activityHot.Title == nil { // 标题为空,填充昵称
vo.Title = acctMp[mid].GetName()
}
if activityHot.Text == nil { // 文字内容为空,填充空间简介
vo.Text = zoneMp[mid][0].GetProfile()
}
if len(activityHot.Hyperlinks) == 0 { // 超链接为空,填充空间链接
vo.CopyHyperlinks(s.utilGetZoneHyperlinks)
}
volist = append(volist, vo)
}
return volist, nil
}
func (s *Service) utilCompleteActivityHotList(ctx *gin.Context, existedMp map[int64]*dbstruct.ActivityHot, remLength int) ([]*activity_hot_proto.ActivityHotApiVO, error) {
volist := make([]*activity_hot_proto.ActivityHotApiVO, 0)
voMap := make(map[int64]*activity_hot_proto.ActivityHotApiVO)
selectedMids := make([]int64, 0)
// 从redis中获取主播推荐列表
recommlist := make([]int64, 0)
err := redis.GetRedisClient().GetObject(consts.RedisStreamerPrefix+"recomm_list", &recommlist)
if err != nil {
logger.Error("Redis read failed : %v", err)
return make([]*activity_hot_proto.ActivityHotApiVO, 0), err
}
// 存量主播基本一定有空间且排位越靠前的主播拥有空间的概率越大一次性查询100个出来基本能保证命中未全命中则继续查询
for offset, count := 0, 0; offset < len(recommlist) && count < remLength; offset += 100 {
// 取切片
end := offset + 100
if end > len(recommlist) {
end = len(recommlist)
}
mids := recommlist[offset:end]
// 取空间
zoneMp, err := _DefaultZone.GetZoneMapByMids(ctx, mids)
if err != nil {
logger.Error("GetZoneMapByMids failed, err: %v", err)
return make([]*activity_hot_proto.ActivityHotApiVO, 0), err
}
for _, mid := range mids {
if _, ok := existedMp[mid]; ok { // 已经存在的编推不再补足进去
continue
}
if len(zoneMp[mid]) > 0 { // 该mid有空间进行补足
vo := activity_hot_proto.NewActivityHotApiVO().CopyZone(zoneMp[mid][0])
volist = append(volist, vo)
voMap[mid] = vo
selectedMids = append(selectedMids, mid)
count++
}
if count == remLength {
break
}
}
}
// 补足account表信息
acctMp, err := _DefaultAccount.GetAccountMapByMids(ctx, selectedMids)
if err != nil {
logger.Error("GetAccountMapByMids failed, err: %v", err)
return make([]*activity_hot_proto.ActivityHotApiVO, 0), err
}
for mid, vo := range voMap {
vo.CopyAccount(acctMp[mid]).CopyHyperlinks(s.utilGetZoneHyperlinks)
}
return volist, nil
}
func (s *Service) utilGetZoneHyperlinks(mid int64) []*dbstruct.Hyperlink {
list := make([]*dbstruct.Hyperlink, 0)
list = append(list, &dbstruct.Hyperlink{
Action: "app",
Url: fmt.Sprintf("StreamerSpace?mid=%d", mid),
})
list = append(list, &dbstruct.Hyperlink{
Action: "h5",
Url: fmt.Sprintf("space/%v", mid),
})
return list
}

View File

@ -12,7 +12,13 @@ type ActivityBanner struct {
Ct *int64 `json:"ct" bson:"ct"` // 创建时间
Ut *int64 `json:"ut" bson:"ut"` // 更新时间
DelFlag *int64 `json:"del_flag" bson:"del_flag"` // 删除标记
}
func (p *ActivityBanner) GetTitle() string {
if p == nil || p.Title == nil {
return ""
}
return *p.Title
}
func (p *ActivityBanner) GetSt() int64 {

View File

@ -23,6 +23,20 @@ func (p *ActivityHot) GetMid() int64 {
return *p.Mid
}
func (p *ActivityHot) GetTitle() string {
if p == nil || p.Title == nil {
return ""
}
return *p.Title
}
func (p *ActivityHot) GetText() string {
if p == nil || p.Text == nil {
return ""
}
return *p.Text
}
func (p *ActivityHot) GetSt() int64 {
if p == nil || p.St == nil {
return -1