package containers import ( "joybuywork/internal/consts" "joybuywork/internal/consts/ckey" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/dbcheck" "joybuywork/internal/repository/finder" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/service/provider/cachecurd" "joybuywork/internal/utils" "joybuywork/internal/utils/logic" pb "joybuywork/proto/go_proto/w_library" "fmt" "gorm.io/gen" ) type LibraryQaRand struct { logic.Logic Req *pb.QaRandReq Res *pb.QaRandRes } func (s *LibraryQaRand) Run() error { return logic.Run(s) } func (s *LibraryQaRand) Exec() (err error) { cpn, group, err := s.campaign() if err != nil || group == nil { return } return s.rand(cpn, group) } func (s *LibraryQaRand) campaign() (cpn *model.FissionCampaign, group *model.LibraryQaGroup, err error) { cpn, err = finder.Campaign(s.Ctx, s.Req.GetCampaignId()) if err != nil { err = s.BE().MysqlError(err) return } if cpn == nil { err = s.BE().VerifyError("not a qa campaign") return } groupM := s.GetDao().LibraryQaGroup group, err = groupM.WithContext(s.Ctx).Where(groupM.HashID.Eq(s.Req.GetGroupHashId()), groupM.DelTime.Eq(0)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } return } func (s *LibraryQaRand) rand(cpn *model.FissionCampaign, group *model.LibraryQaGroup) (err error) { m := s.GetDao().LibraryQa var cond = []gen.Condition{ m.IsDel.Eq(mtype.No), m.GroupID.Eq(group.ID), } switch cpn.FissionID { case consts.IdQaAudio: cond = append(cond, m.Mark.Eq(mtype.LibraryQaMarkAudio)) case consts.IdQaVideo: cond = append(cond, m.Mark.Eq(mtype.LibraryQaMarkVideo)) } list, err := m.WithContext(s.Ctx).Where(cond...).Find() if err != nil { return s.BE().MysqlError(err) } if len(list) == 0 { return } s.Res.List = make([]*pb.QaRandRes_One, 0, len(list)) var qaMap = make(map[int64]*model.LibraryQa, len(list)) for _, v := range list { qaMap[v.ID] = v } chooseIds, err := s._filter(cpn, qaMap) if err != nil { return } optionM := s.GetDao().LibraryQaOption options, err := optionM.WithContext(s.Ctx).Where(optionM.QaID.In(chooseIds...), optionM.IsDel.Eq(mtype.No)).Find() if err != nil { err = s.BE().MysqlError(err) return } var opMap = make(map[int64][]*model.LibraryQaOption) for _, v := range options { opMap[v.QaID] = append(opMap[v.QaID], v) } for _, id := range chooseIds { v := qaMap[id] one := &pb.QaRandRes_One{ Id: v.ID, HashId: v.HashID, Mark: v.Mark, Title: v.Title, CoverUrl: v.CoverURL, LinkUrl: v.LinkURL, ExplainText: v.ExplainText, ExplainImg: v.ExplainImg, Options: make([]*pb.QaRandRes_Option, 0, len(opMap[v.ID])), CreatedAt: v.CreatedAt, AnswerMark: v.AnswerMark, } for _, option := range opMap[v.ID] { one.Options = append(one.Options, &pb.QaRandRes_Option{ Id: option.ID, Title: option.Title, ImgUrl: option.ImgURL, IsRight: int32(option.IsRight), }) } s.Res.List = append(s.Res.List, one) } return } func (s *LibraryQaRand) _qaNum(cpn *model.FissionCampaign) (qaNum int32, err error) { langMark := utils.NotExistGetFirst(s.Req.GetLangMark(), cpn.GetLangMarks()) if langMark == cpn.GetLangMarks()[0] { qam := s.GetDao().FissionCampaignQa var conf *model.FissionCampaignQa conf, err = qam.WithContext(s.Ctx).Where(qam.CampaignID.Eq(cpn.ID)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if conf == nil { return } qaNum = conf.QaNum return } lang, err := cache.NewCampaignLang(s.Ctx).FindByCampaignId(cpn.ID, langMark) if err != nil { err = s.BE().CacheError(err) return } if lang == nil { return } qaNum = lang.GetQaGroup().QaNum return } func (s *LibraryQaRand) _filter(cpn *model.FissionCampaign, qaMap map[int64]*model.LibraryQa) (chooseIds []int64, err error) { key := ckey.FissionUserQaSelect(s.Req.GetUserId()) choose, err := cachecurd.NewHMap(s.Ctx, key) if err != nil { return } selectMap, err := choose.Int64ToInt64() if err != nil { return } qaNum, err := s._qaNum(cpn) if err != nil { return } var maxNum int64 for _, num := range selectMap { if maxNum < num { maxNum = num } } var idx int32 var selected = make(map[int64]struct{}) for id := range qaMap { num, ok := selectMap[id] if ok && num >= maxNum { continue } chooseIds = append(chooseIds, id) selected[id] = struct{}{} idx++ if idx == qaNum { break } } if idx < qaNum { for id := range qaMap { if _, ok := selected[id]; ok { continue } chooseIds = append(chooseIds, id) idx++ if idx == qaNum { break } } } for _, id := range chooseIds { _, err = choose.Incr(fmt.Sprint(id), 1) if err != nil { return } } return }