diff --git a/.gitignore b/.gitignore index f76055c4..9ac27937 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ go.work /go.work.sum /internal/user/internal/integration/logs/ config/local.yaml +config/.DS_Store logs/ /internal/baguwen/internal/integration/logs/ /**/**/logs diff --git a/.run/local.run.xml b/.run/local.run.xml deleted file mode 100644 index 640d9846..00000000 --- a/.run/local.run.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/.DS_Store b/config/.DS_Store deleted file mode 100644 index 7ca0c8fa..00000000 Binary files a/config/.DS_Store and /dev/null differ diff --git a/internal/question/internal/integration/examine_handler_test.go b/internal/question/internal/integration/examine_handler_test.go index 0f6e0ae5..aa36d6f4 100644 --- a/internal/question/internal/integration/examine_handler_test.go +++ b/internal/question/internal/integration/examine_handler_test.go @@ -259,6 +259,81 @@ func (s *ExamineHandlerTest) TestExamine() { } } +func (s *ExamineHandlerTest) TestCorrect() { + testCases := []struct { + name string + before func(t *testing.T) + after func(t *testing.T) + + req web.CorrectReq + + wantCode int + wantResp test.Result[web.ExamineResult] + }{ + { + name: "修改成通过", + before: func(t *testing.T) { + err := s.db.Create(&dao.QuestionResult{ + Id: 2, + Uid: uid, + Qid: 1, + Result: domain.ResultFailed.ToUint8(), + Ctime: 123, + Utime: 123, + }).Error + require.NoError(t, err) + }, + after: func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + var record dao.QuestionResult + err := s.db.WithContext(ctx).Where("uid = ? AND qid = ?", uid, 1).First(&record).Error + + require.NoError(t, err) + assert.True(t, record.Utime > 0) + record.Utime = 0 + assert.True(t, record.Ctime > 0) + record.Ctime = 0 + assert.True(t, record.Id > 0) + record.Id = 0 + + assert.Equal(t, dao.QuestionResult{ + Uid: uid, + Qid: 1, + Result: domain.ResultBasic.ToUint8(), + }, record) + + }, + req: web.CorrectReq{ + Qid: 1, + Result: domain.ResultBasic.ToUint8(), + }, + wantCode: 200, + wantResp: test.Result[web.ExamineResult]{ + Data: web.ExamineResult{ + Qid: 1, + Result: domain.ResultBasic.ToUint8(), + }, + }, + }, + } + + for _, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + tc.before(t) + req, err := http.NewRequest(http.MethodPost, + "/question/examine/correct", iox.NewJSONReader(tc.req)) + req.Header.Set("content-type", "application/json") + require.NoError(t, err) + recorder := test.NewJSONResponseRecorder[web.ExamineResult]() + s.server.ServeHTTP(recorder, req) + require.Equal(t, tc.wantCode, recorder.Code) + assert.Equal(t, tc.wantResp, recorder.MustScan()) + tc.after(t) + }) + } +} + func TestExamineHandler(t *testing.T) { suite.Run(t, new(ExamineHandlerTest)) } diff --git a/internal/question/internal/repository/dao/examine.go b/internal/question/internal/repository/dao/examine.go index 878e53c8..d5c14325 100644 --- a/internal/question/internal/repository/dao/examine.go +++ b/internal/question/internal/repository/dao/examine.go @@ -29,6 +29,7 @@ type ExamineDAO interface { SaveResult(ctx context.Context, record ExamineRecord) error GetResultByUidAndQid(ctx context.Context, uid int64, qid int64) (QuestionResult, error) GetResultByUidAndQids(ctx context.Context, uid int64, ids []int64) ([]QuestionResult, error) + UpdateQuestionResult(ctx context.Context, result QuestionResult) error } var _ ExamineDAO = &GORMExamineDAO{} @@ -73,6 +74,19 @@ func (dao *GORMExamineDAO) SaveResult(ctx context.Context, record ExamineRecord) }) } +func (dao *GORMExamineDAO) UpdateQuestionResult(ctx context.Context, result QuestionResult) error { + now := time.Now().UnixMilli() + return dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + res := tx.Model(&result).Where("uid = ? and qid = ?", result.Uid, result.Qid).Updates(map[string]any{ + "uid": result.Uid, + "qid": result.Qid, + "result": result.Result, + "utime": now, + }) + return res.Error + }) +} + func NewGORMExamineDAO(db *egorm.Component) ExamineDAO { return &GORMExamineDAO{db: db} } diff --git a/internal/question/internal/repository/examine.go b/internal/question/internal/repository/examine.go index cafacc91..210fbd08 100644 --- a/internal/question/internal/repository/examine.go +++ b/internal/question/internal/repository/examine.go @@ -27,6 +27,7 @@ type ExamineRepository interface { SaveResult(ctx context.Context, uid, qid int64, result domain.ExamineResult) error GetResultByUidAndQid(ctx context.Context, uid int64, qid int64) (domain.Result, error) GetResultsByIds(ctx context.Context, uid int64, ids []int64) ([]domain.ExamineResult, error) + UpdateQuestionResult(ctx context.Context, uid int64, qid int64, result domain.Result) error } var _ ExamineRepository = &CachedExamineRepository{} @@ -67,6 +68,15 @@ func (repo *CachedExamineRepository) SaveResult(ctx context.Context, uid, qid in return err } +func (repo *CachedExamineRepository) UpdateQuestionResult(ctx context.Context, uid int64, qid int64, result domain.Result) error { + err := repo.dao.UpdateQuestionResult(ctx, dao.QuestionResult{ + Uid: uid, + Qid: qid, + Result: result.ToUint8(), + }) + return err +} + func NewCachedExamineRepository(dao dao.ExamineDAO) ExamineRepository { return &CachedExamineRepository{dao: dao} } diff --git a/internal/question/internal/service/examine.go b/internal/question/internal/service/examine.go index 703454cf..62948095 100644 --- a/internal/question/internal/service/examine.go +++ b/internal/question/internal/service/examine.go @@ -36,6 +36,7 @@ type ExamineService interface { Examine(ctx context.Context, uid, qid int64, input string) (domain.ExamineResult, error) QuestionResult(ctx context.Context, uid, qid int64) (domain.Result, error) GetResults(ctx context.Context, uid int64, ids []int64) (map[int64]domain.ExamineResult, error) + Correct(ctx context.Context, uid int64, qid int64, questionResult domain.Result) error } var _ ExamineService = &LLMExamineService{} @@ -92,6 +93,12 @@ func (svc *LLMExamineService) Examine(ctx context.Context, return result, err } +func (svc *LLMExamineService) Correct(ctx context.Context, uid int64, + qid int64, questionResult domain.Result) error { + // 更新结果 + return svc.repo.UpdateQuestionResult(ctx, uid, qid, questionResult) +} + func (svc *LLMExamineService) parseExamineResult(answer string) domain.Result { answer = strings.TrimSpace(answer) // 获取第一行 diff --git a/internal/question/internal/web/examine_hander.go b/internal/question/internal/web/examine_hander.go index 4c147d36..2c10f0c5 100644 --- a/internal/question/internal/web/examine_hander.go +++ b/internal/question/internal/web/examine_hander.go @@ -19,6 +19,7 @@ import ( "github.com/ecodeclub/ginx" "github.com/ecodeclub/ginx/session" + "github.com/ecodeclub/webook/internal/question/internal/domain" "github.com/ecodeclub/webook/internal/question/internal/errs" "github.com/ecodeclub/webook/internal/question/internal/service" "github.com/gin-gonic/gin" @@ -59,7 +60,18 @@ func (h *ExamineHandler) Examine(ctx *ginx.Context, req ExamineReq, sess session } } +// 修改题目的结果 func (h *ExamineHandler) Correct(ctx *ginx.Context, req CorrectReq, sess session.Session) (ginx.Result, error) { // 实现这个接口 - panic("implement me") + err := h.svc.Correct(ctx, sess.Claims().Uid, req.Qid, domain.Result(req.Result)) + if err != nil { + return systemErrorResult, err + } + return ginx.Result{ + Data: newExamineResult(domain.ExamineResult{ + Qid: req.Qid, + Result: domain.Result(req.Result), + }), + }, nil + } diff --git a/internal/question/internal/web/examine_vo.go b/internal/question/internal/web/examine_vo.go index 65938feb..5ae141af 100644 --- a/internal/question/internal/web/examine_vo.go +++ b/internal/question/internal/web/examine_vo.go @@ -41,3 +41,9 @@ func newExamineResult(r domain.ExamineResult) ExamineResult { Amount: r.Amount, } } + +type CorrectReq struct { + Qid int64 `json:"qid"` + // 修正结果,对应 domain.Result + Result uint8 `json:"result"` +} diff --git a/internal/question/internal/web/vo.go b/internal/question/internal/web/vo.go index b933c35b..e86bf255 100644 --- a/internal/question/internal/web/vo.go +++ b/internal/question/internal/web/vo.go @@ -200,9 +200,3 @@ type BizReq struct { Biz string `json:"biz"` BizId int64 `json:"bizId"` } - -type CorrectReq struct { - Qid int64 `json:"qid"` - // 修正结果,对应 domain.Result - Result uint8 `json:"result"` -} diff --git a/internal/question/mocks/examine.mock.go b/internal/question/mocks/examine.mock.go index 6f3be52c..0f5c897d 100644 --- a/internal/question/mocks/examine.mock.go +++ b/internal/question/mocks/examine.mock.go @@ -156,3 +156,41 @@ func (c *MockExamineServiceQuestionResultCall) DoAndReturn(f func(context.Contex c.Call = c.Call.DoAndReturn(f) return c } + +// Correct mocks base method. +func (m *MockExamineService) Correct(ctx context.Context, uid, qid int64, questionResult domain.Result) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Correct", ctx, uid, qid, questionResult) + ret0, _ := ret[0].(error) + return ret0 +} + +// Correct indicates an expected call of Correct. +func (mr *MockExamineServiceMockRecorder) Correct(ctx, uid, qid, questionResult any) *MockExamineServiceCorrectCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Correct", reflect.TypeOf((*MockExamineService)(nil).Correct), ctx, uid, qid, questionResult) + return &MockExamineServiceCorrectCall{Call: call} +} + +// MockExamineServiceCorrectCall wraps *gomock.Call. +type MockExamineServiceCorrectCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return for Correct. +func (c *MockExamineServiceCorrectCall) Return(arg0 error) *MockExamineServiceCorrectCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do for Correct. +func (c *MockExamineServiceCorrectCall) Do(f func(context.Context, int64, int64, domain.Result) error) *MockExamineServiceCorrectCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn for Correct. +func (c *MockExamineServiceCorrectCall) DoAndReturn(f func(context.Context, int64, int64, domain.Result) error) *MockExamineServiceCorrectCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/internal/skill/internal/domain/skill.go b/internal/skill/internal/domain/skill.go index 2e32d328..956cb229 100644 --- a/internal/skill/internal/domain/skill.go +++ b/internal/skill/internal/domain/skill.go @@ -34,6 +34,18 @@ func (s Skill) questionSetLen() int { return len(s.Basic.QuestionSets) + len(s.Intermediate.QuestionSets) + len(s.Advanced.QuestionSets) } +func (s Skill) CaseSets() []int64 { + res := make([]int64, 0, s.caseSetLen()) + res = append(res, s.Basic.CaseSets...) + res = append(res, s.Intermediate.CaseSets...) + res = append(res, s.Advanced.CaseSets...) + return res +} + +func (s Skill) caseSetLen() int { + return len(s.Basic.CaseSets) + len(s.Intermediate.CaseSets) + len(s.Advanced.CaseSets) +} + func (s Skill) caseLen() int { return len(s.Basic.Cases) + len(s.Intermediate.Cases) + len(s.Advanced.Cases) } @@ -58,4 +70,5 @@ type SkillLevel struct { Questions []int64 Cases []int64 QuestionSets []int64 + CaseSets []int64 } diff --git a/internal/skill/internal/integration/handler_test.go b/internal/skill/internal/integration/handler_test.go index 75f7d544..98a6681b 100644 --- a/internal/skill/internal/integration/handler_test.go +++ b/internal/skill/internal/integration/handler_test.go @@ -116,11 +116,31 @@ func (s *HandlerTestSuite) SetupSuite() { } }), nil }).AnyTimes() + + caseSetSvc := casemocks.NewMockCaseSetService(ctrl) + caseSetSvc.EXPECT().GetByIds(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, ids []int64) ([]cases.CaseSet, error) { + return slice.Map(ids, func(idx int, src int64) cases.CaseSet { + return cases.CaseSet{ + ID: src, + Title: fmt.Sprintf("这是案例集%d", src), + Cases: []cases.Case{ + { + Id: src*10 + src, + Title: fmt.Sprintf("这是案例%d", src*10+src), + }, + { + Id: src*11 + src, + Title: fmt.Sprintf("这是案例%d", src*11+src), + }, + }, + } + }), nil + }).AnyTimes() s.ctrl = ctrl s.producer = evemocks.NewMockSyncEventProducer(s.ctrl) handler, err := startup.InitHandler( &baguwen.Module{Svc: queSvc, SetSvc: queSetSvc, ExamSvc: examSvc}, - &cases.Module{Svc: caseSvc}, + &cases.Module{Svc: caseSvc, SetSvc: caseSetSvc}, s.producer, ) require.NoError(s.T(), err) @@ -405,6 +425,12 @@ func (s *HandlerTestSuite) TestSaveRefs() { Rid: 67, Rtype: "case", }, + { + Sid: 1, + Slid: 3, + Rid: 78, + Rtype: "caseSet", + }, } for idx := range refs { ref := &(refs[idx]) @@ -447,6 +473,9 @@ func (s *HandlerTestSuite) TestSaveRefs() { Cases: []web.Case{ {Id: 67}, }, + CaseSets: []web.CaseSet{ + {ID: 78}, + }, }, }, }, @@ -509,6 +538,12 @@ func (s *HandlerTestSuite) TestSaveRefs() { Rid: 67, Rtype: "case", }, + { + Sid: 1, + Slid: 3, + Rid: 78, + Rtype: "caseSet", + }, } for idx := range refs { ref := &(refs[idx]) @@ -546,6 +581,9 @@ func (s *HandlerTestSuite) TestSaveRefs() { Cases: []web.Case{ {Id: 67}, }, + CaseSets: []web.CaseSet{ + {ID: 78}, + }, }, }, }, @@ -636,6 +674,26 @@ func (s *HandlerTestSuite) TestDetailRef() { Ctime: time.Now().UnixMilli(), Utime: time.Now().UnixMilli(), }, + + { + Id: 4, + Slid: 2, + Sid: 2, + Rtype: "questionSet", + Rid: 1, + Ctime: time.Now().UnixMilli(), + Utime: time.Now().UnixMilli(), + }, + + { + Id: 5, + Slid: 2, + Sid: 2, + Rtype: "caseSet", + Rid: 1, + Ctime: time.Now().UnixMilli(), + Utime: time.Now().UnixMilli(), + }, }) sid := web.Sid{ Sid: 2, @@ -667,6 +725,7 @@ func (s *HandlerTestSuite) TestDetailRef() { {Id: 1, Title: "这是案例1"}, }, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Intermediate: web.SkillLevel{ Id: 2, @@ -674,13 +733,25 @@ func (s *HandlerTestSuite) TestDetailRef() { Questions: []web.Question{ {Id: 1, Title: "这是问题1"}, }, - QuestionSets: []web.QuestionSet{}, - Cases: []web.Case{}, + QuestionSets: []web.QuestionSet{ + {ID: 1, Title: "这是题集1", Questions: []web.Question{ + {Id: 11, Title: "这是题目11"}, + {Id: 12, Title: "这是题目12"}, + }}, + }, + Cases: []web.Case{}, + CaseSets: []web.CaseSet{ + {ID: 1, Title: "这是案例集1", Cases: []web.Case{ + {Id: 11, Title: "这是案例11"}, + {Id: 12, Title: "这是案例12"}, + }}, + }, }, Advanced: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, }, resp) } @@ -732,16 +803,19 @@ func (s *HandlerTestSuite) TestList() { Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Intermediate: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Advanced: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, }, { @@ -756,16 +830,19 @@ func (s *HandlerTestSuite) TestList() { Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Intermediate: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Advanced: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, }, }, @@ -795,16 +872,19 @@ func (s *HandlerTestSuite) TestList() { Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Intermediate: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, Advanced: web.SkillLevel{ Questions: []web.Question{}, Cases: []web.Case{}, QuestionSets: []web.QuestionSet{}, + CaseSets: []web.CaseSet{}, }, }, }, @@ -876,6 +956,15 @@ func (s *HandlerTestSuite) TestRefsByLevelIDs() { Ctime: time.Now().UnixMilli(), Utime: time.Now().UnixMilli(), }, + { + Id: 6, + Slid: 2, + Sid: 2, + Rtype: "caseSet", + Rid: 6, + Ctime: time.Now().UnixMilli(), + Utime: time.Now().UnixMilli(), + }, }).Error require.NoError(s.T(), err) testCases := []struct { @@ -919,6 +1008,7 @@ func (s *HandlerTestSuite) TestRefsByLevelIDs() { }, }, }, + CaseSets: []web.CaseSet{}, }, { Id: 2, @@ -944,6 +1034,22 @@ func (s *HandlerTestSuite) TestRefsByLevelIDs() { }, }, }, + CaseSets: []web.CaseSet{ + { + ID: 6, + Title: "这是案例集6", + Cases: []web.Case{ + { + Id: 66, + Title: "这是案例66", + }, + { + Id: 72, + Title: "这是案例72", + }, + }, + }, + }, }, }, }, diff --git a/internal/skill/internal/integration/startup/wire.go b/internal/skill/internal/integration/startup/wire.go index b16d788d..c486e1b6 100644 --- a/internal/skill/internal/integration/startup/wire.go +++ b/internal/skill/internal/integration/startup/wire.go @@ -33,9 +33,8 @@ func initHandler( p event.SyncEventProducer) (*web.Handler, error) { wire.Build( InitSkillDAO, - wire.FieldsOf(new(*baguwen.Module), "Svc"), - wire.FieldsOf(new(*cases.Module), "Svc"), - wire.FieldsOf(new(*baguwen.Module), "SetSvc"), + wire.FieldsOf(new(*baguwen.Module), "Svc", "SetSvc"), + wire.FieldsOf(new(*cases.Module), "Svc", "SetSvc"), wire.FieldsOf(new(*baguwen.Module), "ExamSvc"), cache.NewSkillCache, repository.NewSkillRepo, diff --git a/internal/skill/internal/integration/startup/wire_gen.go b/internal/skill/internal/integration/startup/wire_gen.go index 13a2303a..42c7c233 100644 --- a/internal/skill/internal/integration/startup/wire_gen.go +++ b/internal/skill/internal/integration/startup/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject @@ -42,9 +42,10 @@ func initHandler(db *gorm.DB, ec ecache.Cache, queModule *baguwen.Module, caseMo skillService := service.NewSkillService(skillRepo, p) serviceService := queModule.Svc service2 := caseModule.Svc + caseSetService := caseModule.SetSvc questionSetService := queModule.SetSvc examineService := queModule.ExamSvc - handler := web.NewHandler(skillService, serviceService, service2, questionSetService, examineService) + handler := web.NewHandler(skillService, serviceService, service2, caseSetService, questionSetService, examineService) return handler, nil } diff --git a/internal/skill/internal/repository/dao/type.go b/internal/skill/internal/repository/dao/type.go index 3172de74..a5ba1080 100644 --- a/internal/skill/internal/repository/dao/type.go +++ b/internal/skill/internal/repository/dao/type.go @@ -57,6 +57,7 @@ const ( LevelAdvanced = "advanced" RTypeQuestion = "question" RTypeCase = "case" + RTypeCaseSet = "caseSet" RTypeQuestionSet = "questionSet" ) diff --git a/internal/skill/internal/repository/skill.go b/internal/skill/internal/repository/skill.go index 2cb2033d..445b07e1 100644 --- a/internal/skill/internal/repository/skill.go +++ b/internal/skill/internal/repository/skill.go @@ -53,6 +53,7 @@ func (s *skillRepo) LevelInfo(ctx context.Context, id int64) (domain.SkillLevel, level.Cases = levels[0].Cases level.Questions = levels[0].Questions level.QuestionSets = levels[0].QuestionSets + level.CaseSets = levels[0].CaseSets } return level, nil } @@ -71,11 +72,13 @@ func (s *skillRepo) RefsByLevelIDs(ctx context.Context, ids []int64) ([]domain.S ques, _ := m.Get(fmt.Sprintf(keyPattern, dao.RTypeQuestion, src)) cs, _ := m.Get(fmt.Sprintf(keyPattern, dao.RTypeCase, src)) questionSets, _ := m.Get(fmt.Sprintf(keyPattern, dao.RTypeQuestionSet, src)) + caseSets, _ := m.Get(fmt.Sprintf(keyPattern, dao.RTypeCaseSet, src)) return domain.SkillLevel{ Id: src, Questions: ques, Cases: cs, QuestionSets: questionSets, + CaseSets: caseSets, } }), nil } @@ -143,6 +146,17 @@ func (s *skillRepo) toRef(sid int64, level domain.SkillLevel) []dao.SkillRef { }) } + for i := 0; i < len(level.CaseSets); i++ { + res = append(res, dao.SkillRef{ + Rid: level.CaseSets[i], + Rtype: dao.RTypeCaseSet, + Sid: sid, + Slid: level.Id, + Ctime: now, + Utime: now, + }) + } + return res } @@ -233,6 +247,7 @@ func (s *skillRepo) skillToInfoDomain(skill dao.Skill, slQues, _ := reqsMap.Get(fmt.Sprintf("%d_%s", sl.Id, dao.RTypeQuestion)) slCases, _ := reqsMap.Get(fmt.Sprintf("%d_%s", sl.Id, dao.RTypeCase)) slQueSets, _ := reqsMap.Get(fmt.Sprintf("%d_%s", sl.Id, dao.RTypeQuestionSet)) + slCaseSets, _ := reqsMap.Get(fmt.Sprintf("%d_%s", sl.Id, dao.RTypeCaseSet)) dsl.Questions = slice.Map(slQues, func(idx int, src dao.SkillRef) int64 { return src.Rid }) @@ -242,6 +257,9 @@ func (s *skillRepo) skillToInfoDomain(skill dao.Skill, dsl.QuestionSets = slice.Map(slQueSets, func(idx int, src dao.SkillRef) int64 { return src.Rid }) + dsl.CaseSets = slice.Map(slCaseSets, func(idx int, src dao.SkillRef) int64 { + return src.Rid + }) switch sl.Level { case dao.LevelBasic: res.Basic = dsl diff --git a/internal/skill/internal/web/handler.go b/internal/skill/internal/web/handler.go index d7fa486f..a9a39b35 100644 --- a/internal/skill/internal/web/handler.go +++ b/internal/skill/internal/web/handler.go @@ -19,26 +19,29 @@ import ( ) type Handler struct { - svc service.SkillService - queSvc baguwen.Service - caseSvc cases.Service - queSetSvc baguwen.QuestionSetService - examSvc baguwen.ExamService - logger *elog.Component + svc service.SkillService + queSvc baguwen.Service + caseSvc cases.Service + caseSetSvc cases.SetService + queSetSvc baguwen.QuestionSetService + examSvc baguwen.ExamService + logger *elog.Component } func NewHandler(svc service.SkillService, queSvc baguwen.Service, caseSvc cases.Service, + caseSetSvc cases.SetService, queSetSvc baguwen.QuestionSetService, examSvc baguwen.ExamService) *Handler { return &Handler{ - svc: svc, - logger: elog.DefaultLogger, - queSvc: queSvc, - queSetSvc: queSetSvc, - examSvc: examSvc, - caseSvc: caseSvc, + svc: svc, + logger: elog.DefaultLogger, + queSvc: queSvc, + queSetSvc: queSetSvc, + examSvc: examSvc, + caseSvc: caseSvc, + caseSetSvc: caseSetSvc, } } @@ -157,6 +160,22 @@ func (h *Handler) DetailRefs(ctx *ginx.Context, req Sid) (ginx.Result, error) { res.setQuestionSets(cms) return nil }) + + eg.Go(func() error { + cids := skill.CaseSets() + if len(cids) == 0 { + return nil + } + cs, err1 := h.caseSetSvc.GetByIds(ctx, cids) + if err1 != nil { + return err1 + } + cms := slice.ToMap(cs, func(ele cases.CaseSet) int64 { + return ele.ID + }) + res.setCaseSets(cms) + return nil + }) return ginx.Result{ Data: res, }, eg.Wait() @@ -171,7 +190,7 @@ func (h *Handler) RefsByLevelIDs(ctx *ginx.Context, req IDs, sess session.Sessio if err != nil { return systemErrorResult, err } - csm, qsm, qssmap, examResMap, err := h.skillLevels(ctx, uid, res) + csm, cssm, qsm, qssmap, examResMap, err := h.skillLevels(ctx, uid, res) if err != nil { return systemErrorResult, err } @@ -182,35 +201,41 @@ func (h *Handler) RefsByLevelIDs(ctx *ginx.Context, req IDs, sess session.Sessio sl.setCases(csm) sl.setQuestionsWithExam(qsm, examResMap) sl.setQuestionSet(qssmap, examResMap) + sl.setCaseSet(cssm) return sl }), }, nil } -func (h *Handler) skillLevels(ctx context.Context, uid int64, levels []domain.SkillLevel) (map[int64]cases.Case, +func (h *Handler) skillLevels(ctx context.Context, uid int64, levels []domain.SkillLevel) ( + map[int64]cases.Case, + map[int64]cases.CaseSet, map[int64]baguwen.Question, map[int64]baguwen.QuestionSet, map[int64]baguwen.ExamResult, error, ) { var ( - err error eg errgroup.Group csm map[int64]cases.Case + cssm map[int64]cases.CaseSet qsm map[int64]baguwen.Question qssmap map[int64]baguwen.QuestionSet examResMap map[int64]baguwen.ExamResult ) qids := make([]int64, 0, 32) cids := make([]int64, 0, 16) + csids := make([]int64, 0, 16) qsids := make([]int64, 0, 16) for _, sl := range levels { qids = append(qids, sl.Questions...) cids = append(cids, sl.Cases...) + csids = append(csids, sl.CaseSets...) qsids = append(qsids, sl.QuestionSets...) } var qid2s []int64 qid2s = append(qid2s, qids...) + // 获取case eg.Go(func() error { cs, err1 := h.caseSvc.GetPubByIDs(ctx, cids) @@ -219,6 +244,15 @@ func (h *Handler) skillLevels(ctx context.Context, uid int64, levels []domain.Sk }) return err1 }) + + // 获取 caseSet + eg.Go(func() error { + sets, err := h.caseSetSvc.GetByIds(ctx, csids) + cssm = slice.ToMap(sets, func(element cases.CaseSet) int64 { + return element.ID + }) + return err + }) // 获取问题 eg.Go(func() error { qs, err1 := h.queSvc.GetPubByIDs(ctx, qids) @@ -241,14 +275,14 @@ func (h *Handler) skillLevels(ctx context.Context, uid int64, levels []domain.Sk } return nil }) - if err = eg.Wait(); err != nil { - return nil, nil, nil, nil, err + if err := eg.Wait(); err != nil { + return nil, nil, nil, nil, nil, err } // 获取进度 - examResMap, err = h.examSvc.GetResults(ctx, uid, qid2s) + examResMap, err := h.examSvc.GetResults(ctx, uid, qid2s) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, err } - return csm, qsm, qssmap, examResMap, nil + return csm, cssm, qsm, qssmap, examResMap, nil } diff --git a/internal/skill/internal/web/vo.go b/internal/skill/internal/web/vo.go index d34cd38b..b715a15d 100644 --- a/internal/skill/internal/web/vo.go +++ b/internal/skill/internal/web/vo.go @@ -31,12 +31,19 @@ type QuestionSet struct { Questions []Question `json:"questions"` } +type CaseSet struct { + ID int64 `json:"id"` + Title string `json:"title"` + Cases []Case `json:"cases"` +} + type SkillLevel struct { Id int64 `json:"id,omitempty"` Desc string `json:"desc,omitempty"` Questions []Question `json:"questions"` Cases []Case `json:"cases"` QuestionSets []QuestionSet `json:"questionSets"` + CaseSets []CaseSet `json:"caseSets"` } func (s SkillLevel) toDomain() domain.SkillLevel { @@ -52,6 +59,9 @@ func (s SkillLevel) toDomain() domain.SkillLevel { QuestionSets: slice.Map(s.QuestionSets, func(idx int, src QuestionSet) int64 { return src.ID }), + CaseSets: slice.Map(s.CaseSets, func(idx int, src CaseSet) int64 { + return src.ID + }), } } @@ -95,6 +105,22 @@ func (s *SkillLevel) setQuestionSet(qsm map[int64]baguwen.QuestionSet, resultMap }) } +func (s *SkillLevel) setCaseSet(csm map[int64]cases.CaseSet) { + s.CaseSets = slice.Map(s.CaseSets, func(idx int, src CaseSet) CaseSet { + cs := csm[src.ID] + src.Title = cs.Title + res := make([]Case, 0, len(src.Cases)) + for _, q := range cs.Cases { + res = append(res, Case{ + Id: q.Id, + Title: q.Title, + }) + } + src.Cases = res + return src + }) +} + type LevelInfoReq struct { ID int64 `json:"id"` } @@ -145,6 +171,13 @@ func (s *Skill) setQuestionSets(qm map[int64]baguwen.QuestionSet) { s.Intermediate.setQuestionSet(qm, res) s.Advanced.setQuestionSet(qm, res) } + +func (s *Skill) setCaseSets(qm map[int64]cases.CaseSet) { + s.Basic.setCaseSet(qm) + s.Intermediate.setCaseSet(qm) + s.Advanced.setCaseSet(qm) +} + func (s *Skill) setQuestions(qm map[int64]baguwen.Question) { s.Basic.setQuestions(qm) s.Intermediate.setQuestions(qm) @@ -176,6 +209,11 @@ func newSkillLevel(s domain.SkillLevel) SkillLevel { ID: src, } }), + CaseSets: slice.Map(s.CaseSets, func(idx int, src int64) CaseSet { + return CaseSet{ + ID: src, + } + }), } } diff --git a/internal/skill/wire.go b/internal/skill/wire.go index dc55a54e..af5ec5bd 100644 --- a/internal/skill/wire.go +++ b/internal/skill/wire.go @@ -49,7 +49,7 @@ func InitHandler( wire.FieldsOf(new(*baguwen.Module), "Svc"), wire.FieldsOf(new(*baguwen.Module), "SetSvc"), wire.FieldsOf(new(*baguwen.Module), "ExamSvc"), - wire.FieldsOf(new(*cases.Module), "Svc"), + wire.FieldsOf(new(*cases.Module), "Svc", "SetSvc"), cache.NewSkillCache, repository.NewSkillRepo, event.NewSyncEventProducer, diff --git a/internal/skill/wire_gen.go b/internal/skill/wire_gen.go index 827435a3..4215704c 100644 --- a/internal/skill/wire_gen.go +++ b/internal/skill/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject @@ -36,9 +36,10 @@ func InitHandler(db *gorm.DB, ec ecache.Cache, queModule *baguwen.Module, caseMo skillService := service.NewSkillService(skillRepo, syncEventProducer) serviceService := queModule.Svc service2 := caseModule.Svc + caseSetService := caseModule.SetSvc questionSetService := queModule.SetSvc examineService := queModule.ExamSvc - handler := web.NewHandler(skillService, serviceService, service2, questionSetService, examineService) + handler := web.NewHandler(skillService, serviceService, service2, caseSetService, questionSetService, examineService) return handler, nil }