package service import ( "joybuywork/internal/repository/cache" "joybuywork/internal/repository/dbcheck" "joybuywork/internal/repository/finder" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/repository/withdefault" "joybuywork/internal/service/containers" "joybuywork/internal/utils" pb "joybuywork/proto/go_proto/w_library" "joybuywork/proto/go_proto/workerr" "time" "gorm.io/gen" ) type WLibrary struct { Service } // QaGroup 题库列表 func (s *WLibrary) QaGroup(req *pb.QaGroupReq, res *pb.QaGroupRes) (err error) { defer s.checkErr() project, err := finder.Project(s.ctx, req.GetProjectHashId()) if err != nil { err = s.BE().CacheError(err) return } if project == nil || project.IsDel == mtype.Yes { return } m := s.GetDao().LibraryQaGroup var cond = []gen.Condition{ m.DelTime.Eq(0), m.ProjectID.Eq(project.ID), } if req.GetTitle() != "" { cond = append(cond, m.Title.Like(utils.DbAllLike(req.GetTitle()))) } offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage()) list, total, err := m.WithContext(s.ctx).Where(cond...).Order(m.ID.Desc()).FindByPage(offset, limit) if err != nil { return s.BE().MysqlError(err) } *res = pb.QaGroupRes{ List: make([]*pb.QaGroupRes_One, 0, len(list)), Total: total, } if total == 0 { return } var ids []int64 for _, item := range list { ids = append(ids, item.ID) } type num struct { GroupID int64 `json:"group_id"` Num int64 `json:"num"` } var nums []*num qaM := s.GetDao().LibraryQa err = qaM.WithContext(s.ctx).Select(qaM.GroupID, qaM.ID.Count().As("num")).Where(qaM.GroupID.In(ids...)).Group(qaM.GroupID).Scan(&nums) if err != nil { return s.BE().MysqlError(err) } var numMap = make(map[int64]int64, len(list)) for _, v := range nums { numMap[v.GroupID] = v.Num } for _, v := range list { res.List = append(res.List, &pb.QaGroupRes_One{ Id: v.ID, HashId: v.HashID, Title: v.Title, CreatedAt: v.CreatedAt, QaCount: numMap[v.ID], }) } return } // StoreQaGroup 创建题库 func (s *WLibrary) StoreQaGroup(req *pb.StoreQaGroupReq, res *pb.StoreQaGroupRes) (err error) { defer s.checkErr() project, err := finder.Project(s.ctx, req.GetProjectHashId()) if err != nil { err = s.BE().CacheError(err) return } if project == nil || project.IsDel == mtype.Yes { err = workerr.NotFound("not found project") return } m := s.GetDao().LibraryQaGroup exist, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(project.ID), m.Title.Eq(req.GetTitle()), m.DelTime.Eq(0)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if exist != nil { err = workerr.VerifyError("title exist") return } err = m.WithContext(s.ctx).Create(withdefault.LibraryQaGroup(&model.LibraryQaGroup{ ProjectID: project.ID, Title: req.GetTitle(), DelTime: 0, })) if err != nil { err = s.BE().MysqlError(err) return } *res = pb.StoreQaGroupRes{} return } // UpdateQaGroup 更新题库 func (s *WLibrary) UpdateQaGroup(req *pb.UpdateQaGroupReq, res *pb.UpdateQaGroupRes) (err error) { defer s.checkErr() project, err := finder.Project(s.ctx, req.GetProjectHashId()) if err != nil { err = s.BE().CacheError(err) return } if project == nil || project.IsDel == mtype.Yes { err = workerr.NotFound("not found project") return } group, err := cache.NewLibraryQaGroup(s.ctx).FindByHashId(req.GetHashId()) if err != nil { err = s.BE().MysqlError(err) return } if group == nil || group.DelTime > 0 || group.ProjectID != project.ID { err = workerr.NotFound("not found qa group") return } m := s.GetDao().LibraryQaGroup exist, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(project.ID), m.Title.Eq(req.GetTitle()), m.ID.Neq(group.ID), m.DelTime.Eq(0)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if exist != nil { err = workerr.VerifyError("title exist") return } _, err = m.WithContext(s.ctx).Where(m.ID.Eq(group.ID)).UpdateSimple(m.Title.Value(req.GetTitle())) if err != nil { err = s.BE().MysqlError(err) return } _ = cache.NewLibraryQaGroup(s.ctx).Clear(group) *res = pb.UpdateQaGroupRes{} return } // DestroyQaGroup 删除题库 func (s *WLibrary) DestroyQaGroup(req *pb.DestroyQaGroupReq, res *pb.DestroyQaGroupRes) (err error) { defer s.checkErr() project, err := finder.Project(s.ctx, req.GetProjectHashId()) if err != nil { err = s.BE().CacheError(err) return } if project == nil || project.IsDel == mtype.Yes { err = workerr.NotFound("not found project") return } group, err := cache.NewLibraryQaGroup(s.ctx).FindByHashId(req.GetHashId()) if err != nil { err = s.BE().MysqlError(err) return } if group == nil || group.DelTime > 0 || group.ProjectID != project.ID { return } m := s.GetDao().LibraryQaGroup _, err = m.WithContext(s.ctx).Where(m.ID.Eq(group.ID)).UpdateSimple(m.DelTime.Value(time.Now().Unix())) if err != nil { err = s.BE().MysqlError(err) return } _ = cache.NewLibraryQaGroup(s.ctx).Clear(group) *res = pb.DestroyQaGroupRes{} return } // QaList 问题列表 func (s *WLibrary) QaList(req *pb.QaListReq, res *pb.QaListRes) (err error) { defer s.checkErr() groupM := s.GetDao().LibraryQaGroup group, err := groupM.WithContext(s.ctx).Where(groupM.HashID.Eq(req.GetGroupHashId()), groupM.DelTime.Eq(0)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if group == nil { return } m := s.GetDao().LibraryQa var cond = []gen.Condition{ m.IsDel.Eq(mtype.No), m.GroupID.Eq(group.ID), } if req.GetTitle() != "" { cond = append(cond, m.Title.Like(utils.DbAllLike(req.GetTitle()))) } if req.GetMark() != "" { cond = append(cond, m.Mark.Eq(req.GetMark())) } offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage()) list, total, err := m.WithContext(s.ctx).Where(cond...).Order(m.ID.Desc()).FindByPage(offset, limit) if err != nil { return s.BE().MysqlError(err) } *res = pb.QaListRes{ List: make([]*pb.QaListRes_One, 0, len(list)), Total: total, } if total == 0 { return } var ids []int64 for _, v := range list { ids = append(ids, v.ID) } optionM := s.GetDao().LibraryQaOption options, err := optionM.WithContext(s.ctx).Where(optionM.QaID.In(ids...), 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 _, v := range list { one := &pb.QaListRes_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.QaListRes_Option, 0, len(opMap[v.ID])), CreatedAt: v.CreatedAt, AnswerMark: v.AnswerMark, } for _, option := range opMap[v.ID] { one.Options = append(one.Options, &pb.QaListRes_Option{ Id: option.ID, Title: option.Title, ImgUrl: option.ImgURL, IsRight: int32(option.IsRight), }) } res.List = append(res.List, one) } return } // StoreQa 创建题目 func (s *WLibrary) StoreQa(req *pb.StoreQaReq, res *pb.StoreQaRes) (err error) { defer s.checkErr() groupM := s.GetDao().LibraryQaGroup group, err := groupM.WithContext(s.ctx).Where(groupM.HashID.Eq(req.GetGroupHashId()), groupM.DelTime.Eq(0)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if group == nil { err = workerr.NotFound("not found qa group") return } tx := s.GetDao().Begin() defer func() { if err != nil { _ = tx.Rollback() return } _ = tx.Commit() }() m := tx.LibraryQa qa := withdefault.LibraryQa(&model.LibraryQa{ ProjectID: group.ProjectID, GroupID: group.ID, Mark: req.GetMark(), Title: req.GetTitle(), LinkURL: req.GetLinkUrl(), CoverURL: req.GetCoverUrl(), ExplainText: req.GetExplainText(), ExplainImg: req.GetExplainImg(), AnswerMark: req.GetAnswerMark(), }) if err = m.WithContext(s.ctx).Create(qa); err != nil { err = s.BE().MysqlError(err) return } var options []*model.LibraryQaOption optionM := tx.LibraryQaOption for _, v := range req.GetOptions() { options = append(options, withdefault.LibraryQaOption(&model.LibraryQaOption{ QaID: qa.ID, Title: v.GetTitle(), ImgURL: v.GetImgUrl(), IsRight: int8(v.GetIsRight()), })) } if len(options) > 0 { if err = optionM.WithContext(s.ctx).Create(options...); err != nil { err = s.BE().MysqlError(err) return } } *res = pb.StoreQaRes{} return } // UpdateQa 更新题目 func (s *WLibrary) UpdateQa(req *pb.UpdateQaReq, res *pb.UpdateQaRes) (err error) { defer s.checkErr() m := s.GetDao().LibraryQa qa, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetHashId()), m.IsDel.Eq(mtype.No)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if qa == nil { err = workerr.NotFound("not found question") return } tx := s.GetDao().Begin() defer func() { if err != nil { _ = tx.Rollback() return } _ = tx.Commit() }() mtx := tx.LibraryQa _, err = mtx.WithContext(s.ctx).Where(mtx.ID.Eq(qa.ID)).UpdateSimple( mtx.Mark.Value(req.GetMark()), mtx.Title.Value(req.GetTitle()), mtx.LinkURL.Value(req.GetLinkUrl()), mtx.CoverURL.Value(req.GetCoverUrl()), mtx.ExplainText.Value(req.GetExplainText()), mtx.ExplainImg.Value(req.GetExplainImg()), mtx.AnswerMark.Value(req.GetAnswerMark()), ) if err != nil { err = s.BE().MysqlError(err) return } optionTx := tx.LibraryQaOption old, err := optionTx.WithContext(s.ctx).Where(optionTx.QaID.Eq(qa.ID), optionTx.IsDel.Eq(mtype.No)).Find() if err != nil { err = s.BE().MysqlError(err) return } var oldMap = make(map[int64]struct{}, len(old)) for _, v := range old { oldMap[v.ID] = struct{}{} } var newMap = make(map[int64]struct{}) var add []*model.LibraryQaOption for _, v := range req.GetOptions() { _, ok := oldMap[v.GetId()] if !ok { add = append(add, withdefault.LibraryQaOption(&model.LibraryQaOption{ QaID: qa.ID, Title: v.GetTitle(), ImgURL: v.GetImgUrl(), IsRight: int8(v.GetIsRight()), })) continue } newMap[v.GetId()] = struct{}{} _, err = optionTx.WithContext(s.ctx).Where(optionTx.ID.Eq(v.GetId())).UpdateSimple( optionTx.Title.Value(v.GetTitle()), optionTx.ImgURL.Value(v.GetImgUrl()), optionTx.IsRight.Value(int8(v.GetIsRight())), ) if err != nil { err = s.BE().MysqlError(err) return } } var delIds []int64 for _, v := range old { if _, ok := newMap[v.ID]; !ok { delIds = append(delIds, v.ID) } } if len(add) > 0 { if err = optionTx.WithContext(s.ctx).Create(add...); err != nil { err = s.BE().MysqlError(err) return } } if len(delIds) > 0 { _, err = optionTx.WithContext(s.ctx).Where(optionTx.ID.In(delIds...), optionTx.QaID.Eq(qa.ID)).UpdateSimple(optionTx.IsDel.Value(mtype.Yes)) if err != nil { err = s.BE().MysqlError(err) return } } *res = pb.UpdateQaRes{} return } // DestroyQa 删除题目 func (s *WLibrary) DestroyQa(req *pb.DestroyQaReq, res *pb.DestroyQaRes) (err error) { defer s.checkErr() m := s.GetDao().LibraryQa qa, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetHashId()), m.IsDel.Eq(mtype.No)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if qa == nil { return } _, err = m.WithContext(s.ctx).Where(m.ID.Eq(qa.ID)).UpdateSimple(m.IsDel.Value(mtype.Yes)) if err != nil { err = s.BE().MysqlError(err) return } *res = pb.DestroyQaRes{} return } // QaGroupSelect 题库选项 func (s *WLibrary) QaGroupSelect(req *pb.QaGroupSelectReq, res *pb.QaGroupSelectRes) (err error) { defer s.checkErr() project, err := finder.Project(s.ctx, req.GetProjectHashId()) if err != nil { err = s.BE().CacheError(err) return } if project == nil || project.IsDel == mtype.Yes { return } groupM := s.GetDao().LibraryQaGroup list, err := groupM.WithContext(s.ctx).Where(groupM.ProjectID.Eq(project.ID), groupM.DelTime.Eq(0)).Find() if err != nil { err = s.BE().MysqlError(err) return } if len(list) == 0 { return } var ids = make([]int64, 0, len(list)) for _, v := range list { ids = append(ids, v.ID) } var total []struct { GroupId int64 `json:"group_id"` Num int64 `json:"num"` } m := s.GetDao().LibraryQa var cond = []gen.Condition{ m.IsDel.Eq(mtype.No), m.GroupID.In(ids...), } if req.GetMark() != "" { cond = append(cond, m.Mark.Eq(req.GetMark())) } err = m.WithContext(s.ctx). Select(m.GroupID, m.ID.Count().As("num")). Where(cond...). Group(m.GroupID). Scan(&total) if err != nil { err = s.BE().MysqlError(err) return } var totalMap = make(map[int64]int64, len(total)) for _, v := range total { totalMap[v.GroupId] = v.Num } *res = pb.QaGroupSelectRes{ List: make([]*pb.QaGroupSelectRes_One, 0), } for _, v := range list { res.List = append(res.List, &pb.QaGroupSelectRes_One{ Id: v.ID, HashId: v.HashID, Title: v.Title, QaNum: totalMap[v.ID], }) } return } // QaRand 随机问题 func (s *WLibrary) QaRand(req *pb.QaRandReq, res *pb.QaRandRes) (err error) { defer s.checkErr() container := new(containers.LibraryQaRand) { container.Init(s.ctx) container.Req = req container.Res = res } return container.Run() } // QaShow 问题详情 func (s *WLibrary) QaShow(req *pb.QaShowReq, res *pb.QaShowRes) (err error) { defer s.checkErr() m := s.GetDao().LibraryQa qa, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetHashId())).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if qa == nil { err = workerr.NotFound("not found qa") return } optionM := s.GetDao().LibraryQaOption options, err := optionM.WithContext(s.ctx).Where(optionM.QaID.Eq(qa.ID), optionM.IsDel.Eq(mtype.No)).Find() if err != nil { err = s.BE().MysqlError(err) return } *res = pb.QaShowRes{ Id: qa.ID, HashId: qa.HashID, Mark: qa.Mark, Title: qa.Title, CoverUrl: qa.CoverURL, LinkUrl: qa.LinkURL, ExplainText: qa.ExplainText, ExplainImg: qa.ExplainImg, Options: make([]*pb.QaShowRes_Option, 0, len(options)), CreatedAt: qa.CreatedAt, AnswerMark: qa.AnswerMark, } for _, v := range options { res.Options = append(res.Options, &pb.QaShowRes_Option{ Id: v.ID, Title: v.Title, ImgUrl: v.ImgURL, IsRight: int32(v.IsRight), }) } return }