10 Commits

Author SHA1 Message Date
wangguixi 68702e8af7 11.17 2 months ago
wangguixi ae17259454 11.17 2 months ago
wangguixi 1283fd1747 11.17 2 months ago
wangguixi f88b3e27e6 11.14 2 months ago
wangguixi 7f7c2a6df9 11.13 2 months ago
wangguixi 4ef48d2d72 11.12 2 months ago
wangguixi 7a22dd79e2 后台题目查询,更新,修改,删除接口 2 months ago
wangguixi a1b0b17c11 后台题目查询,更新,修改,删除接口 2 months ago
wangguixi ad4fef81da 前台接口基本功能完成 2 months ago
wangguixi c50c45d74b 测试远程仓库连接 2 months ago
  1. 15
      Knowledge_Test_Go/api/hello/hello.go
  2. 12
      Knowledge_Test_Go/api/hello/v1/hello.go
  3. 149
      Knowledge_Test_Go/api/v1/questionBank.go
  4. 56
      Knowledge_Test_Go/go.mod
  5. 135
      Knowledge_Test_Go/go.sum
  6. 21
      Knowledge_Test_Go/hack/config.yaml
  7. 34
      Knowledge_Test_Go/internal/cmd/cmd.go
  8. 5
      Knowledge_Test_Go/internal/controller/hello/hello.go
  9. 13
      Knowledge_Test_Go/internal/controller/hello/hello_v1_hello.go
  10. 94
      Knowledge_Test_Go/internal/controller/knowledge.go
  11. 122
      Knowledge_Test_Go/internal/controller/questionBank.go
  12. 27
      Knowledge_Test_Go/internal/dao/course_recommend.go
  13. 75
      Knowledge_Test_Go/internal/dao/internal/course_recommend.go
  14. 99
      Knowledge_Test_Go/internal/dao/internal/question_bank.go
  15. 83
      Knowledge_Test_Go/internal/dao/internal/question_record.go
  16. 75
      Knowledge_Test_Go/internal/dao/internal/question_type.go
  17. 79
      Knowledge_Test_Go/internal/dao/internal/total_score.go
  18. 81
      Knowledge_Test_Go/internal/dao/internal/user.go
  19. 27
      Knowledge_Test_Go/internal/dao/question_bank.go
  20. 27
      Knowledge_Test_Go/internal/dao/question_record.go
  21. 27
      Knowledge_Test_Go/internal/dao/question_type.go
  22. 27
      Knowledge_Test_Go/internal/dao/total_score.go
  23. 27
      Knowledge_Test_Go/internal/dao/user.go
  24. 233
      Knowledge_Test_Go/internal/logic/knowledge/knowledge.go
  25. 15
      Knowledge_Test_Go/internal/logic/logic.go
  26. 471
      Knowledge_Test_Go/internal/logic/questionBank/questionBank.go
  27. 16
      Knowledge_Test_Go/internal/model/do/course_recommend.go
  28. 29
      Knowledge_Test_Go/internal/model/do/question_bank.go
  29. 21
      Knowledge_Test_Go/internal/model/do/question_record.go
  30. 16
      Knowledge_Test_Go/internal/model/do/question_type.go
  31. 19
      Knowledge_Test_Go/internal/model/do/total_score.go
  32. 20
      Knowledge_Test_Go/internal/model/do/user.go
  33. 11
      Knowledge_Test_Go/internal/model/entity/course_recommend.go
  34. 27
      Knowledge_Test_Go/internal/model/entity/question_bank.go
  35. 19
      Knowledge_Test_Go/internal/model/entity/question_record.go
  36. 11
      Knowledge_Test_Go/internal/model/entity/question_type.go
  37. 17
      Knowledge_Test_Go/internal/model/entity/total_score.go
  38. 18
      Knowledge_Test_Go/internal/model/entity/user.go
  39. 41
      Knowledge_Test_Go/internal/service/knowledge.go
  40. 47
      Knowledge_Test_Go/internal/service/question_bank.go
  41. 6
      Knowledge_Test_Go/main.go
  42. 128
      Knowledge_Test_Go/utility/response/response.go

15
Knowledge_Test_Go/api/hello/hello.go

@ -1,15 +0,0 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package hello
import (
"context"
"Knowledge_Test_Go/api/hello/v1"
)
type IHelloV1 interface {
Hello(ctx context.Context, req *v1.HelloReq) (res *v1.HelloRes, err error)
}

12
Knowledge_Test_Go/api/hello/v1/hello.go

@ -1,12 +0,0 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
type HelloReq struct {
g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"`
}
type HelloRes struct {
g.Meta `mime:"text/html" example:"string"`
}

149
Knowledge_Test_Go/api/v1/questionBank.go

@ -0,0 +1,149 @@
package v1
// GetQuestionsReq 获取题目请求
type GetQuestionsReq struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// GetQuestionsRes 获取题目响应
type GetQuestionsRes struct {
Id int `json:"id"`
Stem string `json:"stem"`
A string `json:"A"`
B string `json:"B"`
C string `json:"C"`
D string `json:"D"`
}
// SubmitAnswersReq 提交答案请求
type SubmitAnswersReq struct {
Jwcode int `v:"required" dc:"精网号"`
Answers []*AnswerItem `v:"required" dc:"答案列表"`
}
// AnswerItem 答案项
type AnswerItem struct {
QuestionId int `json:"questionId" dc:"题目ID"`
UserAnswer string `json:"userAnswer" dc:"用户答案"`
}
// SubmitAnswersRes 提交答案响应
type SubmitAnswersRes struct {
Score int `json:"score" dc:"得分"`
Total int `json:"total" dc:"总分"`
}
// GetWrongQuestionsReq 获取错题请求
type GetWrongQuestionsReq struct {
Jwcode int `v:"required" dc:"精网号(查询参数传递)"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// GetUserScoresReq 获取用户成绩请求
type GetUserScoresReq struct {
Jwcode int `v:"required" dc:"精网号"`
}
// GetUserScoresRes 获取用户成绩响应
type GetUserScoresRes struct {
Score int `json:"score"`
}
// GetCourseReq 获取用户课程请求
type GetCourseReq struct {
Jwcode int `v:"required" dc:"精网号"`
}
// GetCourseRes 获取用户课程响应
type GetCourseRes struct {
CrName []string `json:"cr_name"`
}
// GetWrongQuestionsRes 错题详情
type GetWrongQuestionsRes struct {
GetQuestionsRes `json:"question"`
UserAnswer string `json:"userAnswer" dc:"用户答案"`
CorrectAnswer string `json:"correctAnswer" dc:"正确答案"`
}
//------------------------------------------------------------------------------------------------------------
// QuestionOutputReq 获取题目列表请求
type QuestionOutputReq struct {
Stem string `json:"stem"`
QuestionTypeId string `json:"question_type_id"`
CourseRecommendationId string `json:"course+recommendation_id"`
Page int `json:"page"`
PageSize int `json:"page_size"`
SortField string `json:"sort_field"` // 排序字段:error_count, error_rate, id
SortOrder string `json:"sort_order"` // 排序方向:asc, desc
}
// QuestionOutputRes 题目输出
type QuestionOutputRes struct {
Id int `json:"id"`
Stem string `json:"stem"`
A string `json:"A"`
B string `json:"B"`
C string `json:"C"`
D string `json:"D"`
CorrectAnswer string `json:"correctAnswer"`
QuestionTypeName string `json:"questionTypeName"`
CrName string `json:"CrName"`
CitationCount int `json:"citationCount"`
ErrorCount int `json:"errorCount"`
ErrorRate int `json:"errorRate"`
}
// QuestionUpdateReq 修改题目请求
type QuestionUpdateReq struct {
Id int `json:"id"`
Stem string `json:"stem"`
A string `json:"A"`
B string `json:"B"`
C string `json:"C"`
D string `json:"D"`
CorrectAnswer string `json:"correct_answer"`
QuestionTypeId string `json:"question_type_id"`
CourseRecommendationId string `json:"course+recommendation_id"`
}
// QuestionDelReq 删除题目请求
type QuestionDelReq struct {
Id int `json:"id"`
}
// UserScoreOutputRes 获取用户成绩列表响应
type UserScoreOutputRes struct {
Id int `json:"id"`
UserName string `json:"user_name"`
UserIdentity string `json:"user_identity"`
Jwcode int `json:"jwcode"`
Score int `json:"score"`
CreatedAt string `json:"createdAt"`
}
// UserScoreOutputReq 获取用户成绩列表请求
type UserScoreOutputReq struct {
UserName string `json:"user_name"` // 用户名(精准查询)
UserIdentity string `json:"user_identity"` // 用户身份(过滤)
Jwcode string `json:"jwcode"` // 精网号(精准查询)
StartTime string `json:"start_time"` // 开始时间(提交时间范围)
EndTime string `json:"end_time"` // 结束时间(提交时间范围)
Page int `json:"page"`
PageSize int `json:"page_size"`
SortField string `json:"sort_field"` // 排序字段:score, created_at
SortOrder string `json:"sort_order"` // 排序方向:asc, desc
}
// ErrorOutPutUserReq 获取错题用户列表请求
type ErrorOutPutUserReq struct {
Id int `json:"id"`
}
type ErrorOutPutUserRes struct {
UserName string `json:"user_name"`
UserIdentity string `json:"user_identity"`
ErrorCount int `json:"error_count"`
}

56
Knowledge_Test_Go/go.mod

@ -1,28 +1,50 @@
module Knowledge_Test_Go
go 1.18
go 1.24.0
require github.com/gogf/gf/v2 v2.7.1
require (
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.4
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.4
github.com/gogf/gf/v2 v2.9.4
github.com/xuri/excelize/v2 v2.10.0
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect
github.com/olekukonko/tablewriter v1.1.0 // indirect
github.com/redis/go-redis/v9 v9.12.1 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/tiendc/go-deepcopy v1.7.1 // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

135
Knowledge_Test_Go/go.sum

@ -1,52 +1,113 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gogf/gf/v2 v2.7.1 h1:Ukp7vzwh6VKnivEEx/xiMc61dL1HVZqCCHl//3GBRxc=
github.com/gogf/gf/v2 v2.7.1/go.mod h1:3oyGjyLHtSSo8kQ57Nj1TPdUNc0e2HS0A2J+KkXoW+I=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.4 h1:ntAPahCjQwQ79CC6tI67QDgj17NTWp+lMd1SaL2jJhs=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.4/go.mod h1:/350+9clTW5ktUvF+hePMN9yDknB2ipslqcx3Y2rLDQ=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.4 h1:iKXUQ+8TklSriAqOQjfwioI36zlByqrDqz4ISaRFvm8=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.4/go.mod h1:PYVwyQ0gN+w3wL7zKAoeUpy2WFs4/V8+Ls+eNsy7Uo0=
github.com/gogf/gf/v2 v2.9.4 h1:6vleEWypot9WBPncP2GjbpgAUeG6Mzb1YESb9nPMkjY=
github.com/gogf/gf/v2 v2.9.4/go.mod h1:Ukl+5HUH9S7puBmNLR4L1zUqeRwi0nrW4OigOknEztU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tiendc/go-deepcopy v1.7.1 h1:LnubftI6nYaaMOcaz0LphzwraqN8jiWTwm416sitff4=
github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstfW4=
github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

21
Knowledge_Test_Go/hack/config.yaml

@ -1,13 +1,16 @@
# CLI tool, only in development environment.
# https://goframe.org/docs/cli
# https://goframe.org/pages/viewpage.action?pageId=3673173
gfcli:
# 工具编译配置
build:
name: "Knowledge_Test_Go"
path: "./bin"
arch: "amd64"
system: "linux"
packSrc: "manifest/i18n"
# dao生成
gen:
dao:
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
descriptionTag: true
docker:
build: "-a amd64 -s linux -p temp -ew"
tagPrefixes:
- my.image.pub/my-app
- link: "mysql:root:123456@tcp(127.0.0.1:3306)/knowledge_test?loc=Local&parseTime=true"
tables: ""

34
Knowledge_Test_Go/internal/cmd/cmd.go

@ -1,13 +1,12 @@
package cmd
import (
"Knowledge_Test_Go/internal/controller"
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcmd"
"Knowledge_Test_Go/internal/controller/hello"
)
var (
@ -17,12 +16,35 @@ var (
Brief: "start http server",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(
hello.NewV1(),
// 前台路由组 - 知识测评
s.Group("/api", func(group *ghttp.RouterGroup) {
group.Middleware(
ghttp.MiddlewareHandlerResponse,
ghttp.MiddlewareCORS,
)
group.POST("/knowledge/questions", controller.NewKnowledgeTest().GetQuestions) // 获取题目列表
group.POST("/knowledge/submit", controller.NewKnowledgeTest().SubmitAnswers) // 提交答案
group.POST("/knowledge/scores", controller.NewKnowledgeTest().GetUserScores) // 获取用户成绩
group.POST("/knowledge/wrong-questions", controller.NewKnowledgeTest().GetWrongQuestions) // 获取错题列表
group.POST("/knowledge/course", controller.NewKnowledgeTest().GetCourse) // 获取课程
})
// 后台路由组
s.Group("/admin", func(group *ghttp.RouterGroup) {
group.Middleware(
ghttp.MiddlewareHandlerResponse,
ghttp.MiddlewareCORS,
)
group.POST("/questions/get", controller.NewQuestionBank().GetQuestions) // 获取题目列表
group.POST("/questions/update", controller.NewQuestionBank().QuestionUpdate) // 新增修改题目
group.POST("/questions/del", controller.NewQuestionBank().QuestionDel) // 删除题目
group.POST("/user/score", controller.NewQuestionBank().UserScoreOutput) // 获取用户成绩
group.POST("/questions/user", controller.NewQuestionBank().ErrorOutPutUser) // 获取错题用户列表
group.POST("/questions/export", controller.NewQuestionBank().ExportQuestion) // 导出题目数据到 Excel
group.POST("/user/export", controller.NewQuestionBank().ExportUserScore) //导出用户成绩到 Excel
})
s.Run()
return nil
},

5
Knowledge_Test_Go/internal/controller/hello/hello.go

@ -1,5 +0,0 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package hello

13
Knowledge_Test_Go/internal/controller/hello/hello_v1_hello.go

@ -1,13 +0,0 @@
package hello
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"Knowledge_Test_Go/api/hello/v1"
)
func (c *ControllerV1) Hello(ctx context.Context, req *v1.HelloReq) (res *v1.HelloRes, err error) {
g.RequestFromCtx(ctx).Response.Writeln("Hello World!")
return
}

94
Knowledge_Test_Go/internal/controller/knowledge.go

@ -0,0 +1,94 @@
package controller
import (
"Knowledge_Test_Go/api/v1"
"Knowledge_Test_Go/internal/service"
"Knowledge_Test_Go/utility/response"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type CKnowledgeTest struct{}
func NewKnowledgeTest() *CKnowledgeTest {
return &CKnowledgeTest{}
}
// GetQuestions 获取题目列表
func (c *CKnowledgeTest) GetQuestions(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.GetQuestionsReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, total, err := service.KnowledgeTest().GetQuestions(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
"total": total,
})
}
// GetUserScores 获取用户成绩
func (c *CKnowledgeTest) GetUserScores(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.GetUserScoresReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, err := service.KnowledgeTest().GetUserScores(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", res)
}
// GetCourse 获取用户课程
func (c *CKnowledgeTest) GetCourse(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.GetCourseReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, err := service.KnowledgeTest().GetCourse(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", res)
}
// SubmitAnswers 提交答案
func (c *CKnowledgeTest) SubmitAnswers(r *ghttp.Request) {
ctx := r.GetCtx()
var req v1.SubmitAnswersReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, err := service.KnowledgeTest().SubmitAnswers(ctx, &req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"data": res,
})
}
// GetWrongQuestions 获取错题列表
func (c *CKnowledgeTest) GetWrongQuestions(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.GetWrongQuestionsReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, total, err := service.KnowledgeTest().GetWrongQuestions(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
"total": total,
})
}

122
Knowledge_Test_Go/internal/controller/questionBank.go

@ -0,0 +1,122 @@
package controller
import (
"Knowledge_Test_Go/api/v1"
"Knowledge_Test_Go/internal/service"
"Knowledge_Test_Go/utility/response"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type CQuestionBank struct{}
func NewQuestionBank() *CQuestionBank {
return &CQuestionBank{}
}
// GetQuestions 获取题目列表
func (c *CQuestionBank) GetQuestions(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.QuestionOutputReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, total, err := service.QuestionBank().GetQuestions(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
"total": total,
})
}
// QuestionUpdate 获取题目列表
func (c *CQuestionBank) QuestionUpdate(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.QuestionUpdateReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, err := service.QuestionBank().QuestionUpdate(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
})
}
// QuestionDel 删除题目
func (c *CQuestionBank) QuestionDel(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.QuestionDelReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, err := service.QuestionBank().QuestionDel(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
})
}
// UserScoreOutput 获取用户成绩列表
func (c *CQuestionBank) UserScoreOutput(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.UserScoreOutputReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, total, err := service.QuestionBank().UserScoreOutput(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
"total": total,
})
}
// ErrorOutPutUser 错题统计出错用户
func (c *CQuestionBank) ErrorOutPutUser(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.ErrorOutPutUserReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
res, total, err := service.QuestionBank().ErrorOutPutUser(ctx, req)
if err != nil {
response.JsonExit(r, 400, err.Error())
}
response.JsonExit(r, 200, "success", g.Map{
"list": res,
"total": total,
})
}
// ExportQuestion 导出题目数据到 Excel
func (c *CQuestionBank) ExportQuestion(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.QuestionOutputReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
}
service.QuestionBank().ExportQuestion(r, ctx, req)
}
// ExportUserScore 导出用户成绩到 Excel
func (c *CQuestionBank) ExportUserScore(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.UserScoreOutputReq
if err := r.Parse(&req); err != nil {
response.JsonExit(r, 400, err.Error())
return
}
// 调用服务层的导出方法
service.QuestionBank().ExportUserScore(r, ctx, req)
}

27
Knowledge_Test_Go/internal/dao/course_recommend.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalCourseRecommendDao is internal type for wrapping internal DAO implements.
type internalCourseRecommendDao = *internal.CourseRecommendDao
// courseRecommendDao is the data access object for table course_recommend.
// You can define custom methods on it to extend its functionality as you wish.
type courseRecommendDao struct {
internalCourseRecommendDao
}
var (
// CourseRecommend is globally public accessible object for table course_recommend operations.
CourseRecommend = courseRecommendDao{
internal.NewCourseRecommendDao(),
}
)
// Fill with you ideas below.

75
Knowledge_Test_Go/internal/dao/internal/course_recommend.go

@ -0,0 +1,75 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// CourseRecommendDao is the data access object for table course_recommend.
type CourseRecommendDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns CourseRecommendColumns // columns contains all the column names of Table for convenient usage.
}
// CourseRecommendColumns defines and stores column names for table course_recommend.
type CourseRecommendColumns struct {
Id string // 课程推荐主键
CrName string // 课程推荐名称
}
// courseRecommendColumns holds the columns for table course_recommend.
var courseRecommendColumns = CourseRecommendColumns{
Id: "id",
CrName: "cr_name",
}
// NewCourseRecommendDao creates and returns a new DAO object for table data access.
func NewCourseRecommendDao() *CourseRecommendDao {
return &CourseRecommendDao{
group: "default",
table: "course_recommend",
columns: courseRecommendColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *CourseRecommendDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *CourseRecommendDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *CourseRecommendDao) Columns() CourseRecommendColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *CourseRecommendDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *CourseRecommendDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *CourseRecommendDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

99
Knowledge_Test_Go/internal/dao/internal/question_bank.go

@ -0,0 +1,99 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// QuestionBankDao is the data access object for table question_bank.
type QuestionBankDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns QuestionBankColumns // columns contains all the column names of Table for convenient usage.
}
// QuestionBankColumns defines and stores column names for table question_bank.
type QuestionBankColumns struct {
Id string // 题库主键
Stem string // 题干
A string // A选项
B string // B选项
C string // C选项
D string // D选项
CorrectAnswer string // 正确答案
QuestionTypeId string // 题目类型
CourseRecommendationId string // 课程推荐
CitationCount string // 引用次数
ErrorCount string // 错误次数
CreatedAt string // 创建时间
UpdatedAt string // 修改时间
Isdel string // 逻辑删(1为删除)
}
// questionBankColumns holds the columns for table question_bank.
var questionBankColumns = QuestionBankColumns{
Id: "id",
Stem: "stem",
A: "A",
B: "B",
C: "C",
D: "D",
CorrectAnswer: "correct_answer",
QuestionTypeId: "question_type_id",
CourseRecommendationId: "course_recommendation_id",
CitationCount: "citation_count",
ErrorCount: "error_count",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
Isdel: "isdel",
}
// NewQuestionBankDao creates and returns a new DAO object for table data access.
func NewQuestionBankDao() *QuestionBankDao {
return &QuestionBankDao{
group: "default",
table: "question_bank",
columns: questionBankColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *QuestionBankDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *QuestionBankDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *QuestionBankDao) Columns() QuestionBankColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *QuestionBankDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *QuestionBankDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *QuestionBankDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

83
Knowledge_Test_Go/internal/dao/internal/question_record.go

@ -0,0 +1,83 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// QuestionRecordDao is the data access object for table question_record.
type QuestionRecordDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns QuestionRecordColumns // columns contains all the column names of Table for convenient usage.
}
// QuestionRecordColumns defines and stores column names for table question_record.
type QuestionRecordColumns struct {
Id string // 题目记录主键
Jwcode string // 精网号
QuestionBankId string // 题目id
UserAnswer string // 用户答案
IsCorrect string // 是否正确(0为正确)
CreatedAt string // 提交时间
}
// questionRecordColumns holds the columns for table question_record.
var questionRecordColumns = QuestionRecordColumns{
Id: "id",
Jwcode: "jwcode",
QuestionBankId: "question_bank_id",
UserAnswer: "user_answer",
IsCorrect: "is_correct",
CreatedAt: "created_at",
}
// NewQuestionRecordDao creates and returns a new DAO object for table data access.
func NewQuestionRecordDao() *QuestionRecordDao {
return &QuestionRecordDao{
group: "default",
table: "question_record",
columns: questionRecordColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *QuestionRecordDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *QuestionRecordDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *QuestionRecordDao) Columns() QuestionRecordColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *QuestionRecordDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *QuestionRecordDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *QuestionRecordDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

75
Knowledge_Test_Go/internal/dao/internal/question_type.go

@ -0,0 +1,75 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// QuestionTypeDao is the data access object for table question_type.
type QuestionTypeDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns QuestionTypeColumns // columns contains all the column names of Table for convenient usage.
}
// QuestionTypeColumns defines and stores column names for table question_type.
type QuestionTypeColumns struct {
Id string // 题库类型主键
QuestionTypeName string // 题目类型名称
}
// questionTypeColumns holds the columns for table question_type.
var questionTypeColumns = QuestionTypeColumns{
Id: "id",
QuestionTypeName: "question_type_name",
}
// NewQuestionTypeDao creates and returns a new DAO object for table data access.
func NewQuestionTypeDao() *QuestionTypeDao {
return &QuestionTypeDao{
group: "default",
table: "question_type",
columns: questionTypeColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *QuestionTypeDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *QuestionTypeDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *QuestionTypeDao) Columns() QuestionTypeColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *QuestionTypeDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *QuestionTypeDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *QuestionTypeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

79
Knowledge_Test_Go/internal/dao/internal/total_score.go

@ -0,0 +1,79 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// TotalScoreDao is the data access object for table total_score.
type TotalScoreDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns TotalScoreColumns // columns contains all the column names of Table for convenient usage.
}
// TotalScoreColumns defines and stores column names for table total_score.
type TotalScoreColumns struct {
Id string // 总成绩主键
Jwcode string // 精网号
Score string // 成绩
CreatedAt string // 提交时间
}
// totalScoreColumns holds the columns for table total_score.
var totalScoreColumns = TotalScoreColumns{
Id: "id",
Jwcode: "jwcode",
Score: "score",
CreatedAt: "created_at",
}
// NewTotalScoreDao creates and returns a new DAO object for table data access.
func NewTotalScoreDao() *TotalScoreDao {
return &TotalScoreDao{
group: "default",
table: "total_score",
columns: totalScoreColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *TotalScoreDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *TotalScoreDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *TotalScoreDao) Columns() TotalScoreColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *TotalScoreDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *TotalScoreDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *TotalScoreDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

81
Knowledge_Test_Go/internal/dao/internal/user.go

@ -0,0 +1,81 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// UserDao is the data access object for table user.
type UserDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns UserColumns // columns contains all the column names of Table for convenient usage.
}
// UserColumns defines and stores column names for table user.
type UserColumns struct {
Id string // 用户主键
UserName string // 用户名称
Jwcode string // 精网号
UserIdentity string // 用户身份
CreatedAt string // 创建时间
}
// userColumns holds the columns for table user.
var userColumns = UserColumns{
Id: "id",
UserName: "user_name",
Jwcode: "jwcode",
UserIdentity: "user_identity",
CreatedAt: "created_at",
}
// NewUserDao creates and returns a new DAO object for table data access.
func NewUserDao() *UserDao {
return &UserDao{
group: "default",
table: "user",
columns: userColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *UserDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *UserDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *UserDao) Columns() UserColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *UserDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *UserDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *UserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

27
Knowledge_Test_Go/internal/dao/question_bank.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalQuestionBankDao is internal type for wrapping internal DAO implements.
type internalQuestionBankDao = *internal.QuestionBankDao
// questionBankDao is the data access object for table question_bank.
// You can define custom methods on it to extend its functionality as you wish.
type questionBankDao struct {
internalQuestionBankDao
}
var (
// QuestionBank is globally public accessible object for table question_bank operations.
QuestionBank = questionBankDao{
internal.NewQuestionBankDao(),
}
)
// Fill with you ideas below.

27
Knowledge_Test_Go/internal/dao/question_record.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalQuestionRecordDao is internal type for wrapping internal DAO implements.
type internalQuestionRecordDao = *internal.QuestionRecordDao
// questionRecordDao is the data access object for table question_record.
// You can define custom methods on it to extend its functionality as you wish.
type questionRecordDao struct {
internalQuestionRecordDao
}
var (
// QuestionRecord is globally public accessible object for table question_record operations.
QuestionRecord = questionRecordDao{
internal.NewQuestionRecordDao(),
}
)
// Fill with you ideas below.

27
Knowledge_Test_Go/internal/dao/question_type.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalQuestionTypeDao is internal type for wrapping internal DAO implements.
type internalQuestionTypeDao = *internal.QuestionTypeDao
// questionTypeDao is the data access object for table question_type.
// You can define custom methods on it to extend its functionality as you wish.
type questionTypeDao struct {
internalQuestionTypeDao
}
var (
// QuestionType is globally public accessible object for table question_type operations.
QuestionType = questionTypeDao{
internal.NewQuestionTypeDao(),
}
)
// Fill with you ideas below.

27
Knowledge_Test_Go/internal/dao/total_score.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalTotalScoreDao is internal type for wrapping internal DAO implements.
type internalTotalScoreDao = *internal.TotalScoreDao
// totalScoreDao is the data access object for table total_score.
// You can define custom methods on it to extend its functionality as you wish.
type totalScoreDao struct {
internalTotalScoreDao
}
var (
// TotalScore is globally public accessible object for table total_score operations.
TotalScore = totalScoreDao{
internal.NewTotalScoreDao(),
}
)
// Fill with you ideas below.

27
Knowledge_Test_Go/internal/dao/user.go

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"Knowledge_Test_Go/internal/dao/internal"
)
// internalUserDao is internal type for wrapping internal DAO implements.
type internalUserDao = *internal.UserDao
// userDao is the data access object for table user.
// You can define custom methods on it to extend its functionality as you wish.
type userDao struct {
internalUserDao
}
var (
// User is globally public accessible object for table user operations.
User = userDao{
internal.NewUserDao(),
}
)
// Fill with you ideas below.

233
Knowledge_Test_Go/internal/logic/knowledge/knowledge.go

@ -0,0 +1,233 @@
package knowledge
import (
v1 "Knowledge_Test_Go/api/v1"
"Knowledge_Test_Go/internal/dao"
"Knowledge_Test_Go/internal/model/do"
"Knowledge_Test_Go/internal/service"
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
type sKnowledgeTest struct{}
func init() {
service.RegisterKnowledgeTest(&sKnowledgeTest{})
}
// GetQuestions 获取题目列表
func (s *sKnowledgeTest) GetQuestions(ctx context.Context, req *v1.GetQuestionsReq) (res []*v1.GetQuestionsRes, total int, err error) {
db := g.Model("question_bank a").Where("isdel=0").Fields("a.id", "a.stem", "a.a", "a.b", "a.c", "a.d")
err = db.Page(req.Page, req.PageSize).ScanAndCount(&res, &total, false)
return
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
// GetUserScores 获取用户成绩
func (s *sKnowledgeTest) GetUserScores(ctx context.Context, req *v1.GetUserScoresReq) (res []*v1.GetUserScoresRes, err error) {
err = g.Model("total_score").Fields("score").Where("jwcode=?", req.Jwcode).Ctx(ctx).Scan(&res)
if err != nil {
return nil, fmt.Errorf("获取用户成绩失败: %w", err)
}
return res, nil
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
// GetCourse 获取用户课程
func (s *sKnowledgeTest) GetCourse(ctx context.Context, req *v1.GetCourseReq) (res []*v1.GetCourseRes, err error) {
// 使用临时结构体接收数据
type Course struct {
CrName string `json:"cr_name"`
}
var courses []Course
// 查询数据
err = g.Model("question_record a").
LeftJoin("question_bank b", "a.question_bank_id = b.id").
LeftJoin("course_recommend c", "b.course_recommendation_id = c.id").
Where("a.jwcode = ?", req.Jwcode).
Where("c.cr_name IS NOT NULL").
Where("c.cr_name != ''").
Fields("DISTINCT c.cr_name"). // DISTINCT去重
Ctx(ctx).
Scan(&courses)
if err != nil {
return nil, fmt.Errorf("查询课程名称失败: %w", err)
}
// 提取纯字符串
courseNames := make([]string, 0, len(courses))
for _, course := range courses {
courseNames = append(courseNames, course.CrName)
}
// 创建响应
res = append(res, &v1.GetCourseRes{
CrName: courseNames,
})
return res, nil
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
// SubmitAnswers 提交答案并计算分数
func (s *sKnowledgeTest) SubmitAnswers(ctx context.Context, req *v1.SubmitAnswersReq) (*v1.SubmitAnswersRes, error) {
if len(req.Answers) == 0 {
return nil, fmt.Errorf("答案列表不能为空")
}
// 获取所有题目ID
questionIds := make([]interface{}, len(req.Answers))
for i, answer := range req.Answers {
questionIds[i] = answer.QuestionId
}
// 批量查询题目
var questions []*do.QuestionBank
err := dao.QuestionBank.Ctx(ctx).
Where(dao.QuestionBank.Columns().Id, questionIds).
Where(dao.QuestionBank.Columns().Isdel, 0).
Scan(&questions)
if err != nil {
return nil, err
}
// 构建题目ID到正确答案的映射
questionMap := make(map[int]string)
for _, q := range questions {
questionMap[gconv.Int(q.Id)] = gconv.String(q.CorrectAnswer)
}
// 计算分数并准备记录数据
score := 0
total := len(req.Answers) * 2 // 每题2分
records := make([]*do.QuestionRecord, 0, len(req.Answers))
// 收集所有被回答的题目ID(用于更新引用次数)
allAnsweredQuestionIds := make([]int, 0, len(req.Answers))
// 收集错误题目的ID(用于更新错误次数)
errorQuestionIds := make([]int, 0)
for _, answer := range req.Answers {
correctAnswer, exists := questionMap[answer.QuestionId]
if !exists {
continue
}
// 记录所有被回答的题目
allAnsweredQuestionIds = append(allAnsweredQuestionIds, answer.QuestionId)
isCorrect := 0 // 0为正确
if answer.UserAnswer == correctAnswer {
score += 2
} else {
isCorrect = 1 // 1为错误
errorQuestionIds = append(errorQuestionIds, answer.QuestionId)
}
records = append(records, &do.QuestionRecord{
Jwcode: req.Jwcode,
QuestionBankId: answer.QuestionId,
UserAnswer: answer.UserAnswer,
IsCorrect: isCorrect,
})
}
// 批量保存记录(使用事务确保原子性)
err = dao.QuestionRecord.Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 批量插入答题记录
if len(records) > 0 {
_, err := tx.Model(dao.QuestionRecord.Table()).Data(records).Insert()
if err != nil {
return err
}
}
// 更新所有被回答题目的引用次数
if len(allAnsweredQuestionIds) > 0 {
_, err := tx.Model(dao.QuestionBank.Table()).
Where(dao.QuestionBank.Columns().Id, allAnsweredQuestionIds).
Increment(dao.QuestionBank.Columns().CitationCount, 1)
if err != nil {
return err
}
}
// 更新错误题目的错误次数
if len(errorQuestionIds) > 0 {
_, err := tx.Model(dao.QuestionBank.Table()).
Where(dao.QuestionBank.Columns().Id, errorQuestionIds).
Increment(dao.QuestionBank.Columns().ErrorCount, 1)
if err != nil {
return err
}
}
// 计算并更新所有被回答题目的错误率
if len(allAnsweredQuestionIds) > 0 {
err := s.updateErrorRatesInTransaction(ctx, tx, allAnsweredQuestionIds)
if err != nil {
return err
}
}
// 插入总成绩记录
_, err = tx.Model(dao.TotalScore.Table()).Data(&do.TotalScore{
Jwcode: req.Jwcode,
Score: score,
}).Insert()
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return &v1.SubmitAnswersRes{
Score: score,
Total: total,
}, nil
}
// updateErrorRatesInTransaction 在事务中更新错误率(简化版)
func (s *sKnowledgeTest) updateErrorRatesInTransaction(ctx context.Context, tx gdb.TX, questionIds []int) error {
if len(questionIds) == 0 {
return nil
}
// 使用GF的Raw方法
_, err := tx.Model(dao.QuestionBank.Table()).
Where(dao.QuestionBank.Columns().Id, questionIds).
Data(g.Map{
"error_rate": gdb.Raw("CASE WHEN citation_count = 0 THEN 0 ELSE ROUND((error_count * 100.0) / citation_count) END"),
}).
Update()
if err != nil {
return fmt.Errorf("更新错误率失败: %w", err)
}
return nil
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
// GetWrongQuestions 获取错题列表
func (s *sKnowledgeTest) GetWrongQuestions(ctx context.Context, req *v1.GetWrongQuestionsReq) (res []*v1.GetWrongQuestionsRes, total int, err error) {
db := g.Model("question_record b").
RightJoin("question_bank a", "a.id=b.question_bank_id").
Where("b.jwcode=?", req.Jwcode).Fields("a.id", "a.stem", "a.a", "a.b", "a.c", "a.d", "a.correct_answer", "b.user_answer")
err = db.Page(req.Page, req.PageSize).ScanAndCount(&res, &total, false)
return
}

15
Knowledge_Test_Go/internal/controller/hello/hello_new.go → Knowledge_Test_Go/internal/logic/logic.go

@ -1,15 +1,10 @@
// =================================================================================
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
// ==========================================================================
package hello
package logic
import (
"Knowledge_Test_Go/api/hello"
_ "Knowledge_Test_Go/internal/logic/knowledge"
_ "Knowledge_Test_Go/internal/logic/questionBank"
)
type ControllerV1 struct{}
func NewV1() hello.IHelloV1 {
return &ControllerV1{}
}

471
Knowledge_Test_Go/internal/logic/questionBank/questionBank.go

@ -0,0 +1,471 @@
package questionBank
import (
v1 "Knowledge_Test_Go/api/v1"
"Knowledge_Test_Go/internal/service"
"Knowledge_Test_Go/utility/response"
"context"
"fmt"
"regexp"
"strconv"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/xuri/excelize/v2"
)
type sQuestionBank struct{}
func init() {
service.RegisterQuestionBank(&sQuestionBank{})
}
// GetQuestions 获取题目列表
func (s *sQuestionBank) GetQuestions(ctx context.Context, req *v1.QuestionOutputReq) (res []*v1.QuestionOutputRes, total int, err error) {
db := g.Model("question_bank a").
LeftJoin("question_type b", "a.question_type_id = b.id").
LeftJoin("course_recommend c", "a.course_recommendation_id = c.id").
Where("a.isdel = 0").
Fields("a.id", "a.stem", "a.a", "a.b", "a.c", "a.d", "a.correct_answer",
"b.question_type_name", "c.cr_name", "a.error_count", "a.citation_count", "a.error_rate") // 添加 error_rate 字段
// 添加查询条件
if req.Stem != "" {
// 对题干进行模糊查询
db = db.Where("a.stem LIKE ?", "%"+req.Stem+"%")
}
if req.QuestionTypeId != "" {
// 对题目类型ID进行精准查询
db = db.Where("a.question_type_id = ?", req.QuestionTypeId)
}
if req.CourseRecommendationId != "" {
// 对课程推荐ID进行精准查询
db = db.Where("a.course_recommendation_id = ?", req.CourseRecommendationId)
}
// 添加排序逻辑
db = s.buildSortCondition(db, req)
err = db.Page(req.Page, req.PageSize).ScanAndCount(&res, &total, false)
return
}
// buildSortCondition 构建排序条件
func (s *sQuestionBank) buildSortCondition(db *gdb.Model, req *v1.QuestionOutputReq) *gdb.Model {
// 默认排序(按ID倒序)
if req.SortField == "" {
return db.OrderDesc("a.id")
}
// 确定排序方向
order := "DESC"
if req.SortOrder == "asc" {
order = "ASC"
}
// 根据排序字段构建排序条件
switch req.SortField {
case "error_count":
return db.Order("a.error_count " + order)
case "error_rate":
return db.Order("a.error_rate " + order)
case "id":
return db.Order("a.id " + order)
default:
// 默认按ID倒序
return db.OrderDesc("a.id")
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// QuestionUpdate 修改题目
func (s *sQuestionBank) QuestionUpdate(ctx context.Context, req *v1.QuestionUpdateReq) (res string, err error) {
// 准备数据
data := g.Map{
"stem": req.Stem,
"a": req.A,
"b": req.B,
"c": req.C,
"d": req.D,
"correct_answer": req.CorrectAnswer,
"question_type_id": req.QuestionTypeId,
"course_recommendation_id": req.CourseRecommendationId,
}
if req.Id == 0 {
// 新增记录
result, err := g.Model("question_bank").Data(data).Insert()
if err != nil {
return "新增失败", err
}
// 获取新增的ID
id, _ := result.LastInsertId()
return fmt.Sprintf("新增成功,ID: %d", id), nil
} else {
// 更新记录
_, err := g.Model("question_bank").Where("id = ?", req.Id).Data(data).Update()
if err != nil {
return "更新失败", err
}
// 检查是否真的更新了记录
count, _ := g.Model("question_bank").Where("id = ?", req.Id).Count()
if count == 0 {
return "更新失败,记录不存在", nil
}
return fmt.Sprintf("更新成功,ID: %d", req.Id), nil
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// QuestionDel 删除题目
func (s *sQuestionBank) QuestionDel(ctx context.Context, req *v1.QuestionDelReq) (res string, err error) {
_, err = g.Model("question_bank").Where("id = ?", req.Id).Data("isdel", 1).Update()
if err != nil {
return "删除失败", err
}
return "删除成功", err
}
//-------------------------------------------------------------------------------------------------------------------------------
// UserScoreOutput 获取用户成绩列表
func (s *sQuestionBank) UserScoreOutput(ctx context.Context, req *v1.UserScoreOutputReq) (res []*v1.UserScoreOutputRes, total int, err error) {
db := g.Model("user a").
RightJoin("total_score b", "a.jwcode = b.jwcode").
Fields("a.id", "a.user_name", "a.user_identity", "a.jwcode", "b.created_at", "b.score")
// 添加查询条件
if req.UserName != "" {
db = db.Where("a.user_name LIKE ?", "%"+req.UserName+"%")
}
if req.UserIdentity != "" {
db = db.Where("a.user_identity = ?", req.UserIdentity)
}
// 预编译正则:匹配8位数字(^表示开头,$表示结尾,\d{8}表示8位数字)
var jwcodeRegex = regexp.MustCompile(`^\d{8}$`)
if req.Jwcode != "" { // 假设字符串类型的默认值是空串
// 校验:长度8位且全为数字
if !jwcodeRegex.MatchString(req.Jwcode) {
return nil, 0, fmt.Errorf("Jwcode必须是8位数字")
}
// 校验通过,添加查询条件
db = db.Where("a.jwcode = ?", req.Jwcode)
}
//// 1. 定义时间格式(根据业务实际格式调整)
//const timeLayout = "2006-01-02 15:04:05"
//// 2. 解析开始时间和结束时间(校验格式)
//var startTime, endTime time.Time
//
//if req.StartTime != "" {
// if startTime, err = time.Parse(timeLayout, req.StartTime); err != nil {
// return nil, 0, fmt.Errorf("开始时间格式错误,需为 %s", timeLayout)
// }
//}
//if req.EndTime != "" {
// if endTime, err = time.Parse(timeLayout, req.EndTime); err != nil {
// return nil, 0, fmt.Errorf("结束时间格式错误,需为 %s", timeLayout)
// }
//}
//// 3. 校验结束时间不能早于开始时间(两者都存在时)
//if req.StartTime != "" && req.EndTime != "" {
// if endTime.Before(startTime) { // 用time.Before()判断时间顺序
// return nil, 0, fmt.Errorf("结束时间不能早于开始时间")
// }
//}
if req.StartTime != "" && req.EndTime != "" {
if req.StartTime > req.EndTime {
return nil, 0, fmt.Errorf("结束时间不能早于开始时间")
}
}
// 4.时间范围查询
if req.StartTime != "" && req.EndTime != "" {
db = db.Where("b.created_at BETWEEN ? AND ?", req.StartTime, req.EndTime)
} else if req.StartTime != "" {
db = db.Where("b.created_at >= ?", req.StartTime)
} else if req.EndTime != "" {
db = db.Where("b.created_at <= ?", req.EndTime)
}
// 添加排序逻辑
db = s.buildUserScoreSortCondition(db, req)
err = db.Page(req.Page, req.PageSize).ScanAndCount(&res, &total, false)
return
}
// buildUserScoreSortCondition 构建用户成绩排序条件
func (s *sQuestionBank) buildUserScoreSortCondition(db *gdb.Model, req *v1.UserScoreOutputReq) *gdb.Model {
// 默认排序(按创建时间倒序)
if req.SortField == "" {
return db.OrderDesc("b.created_at")
}
// 确定排序方向
order := "DESC"
if req.SortOrder == "asc" {
order = "ASC"
}
// 根据排序字段构建排序条件
switch req.SortField {
case "score":
return db.Order("b.score " + order)
case "created_at":
return db.Order("b.created_at " + order)
default:
// 默认按创建时间倒序
return db.OrderDesc("b.created_at")
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// ErrorOutPutUser 错题统计出错用户
func (s *sQuestionBank) ErrorOutPutUser(ctx context.Context, req *v1.ErrorOutPutUserReq) (res []*v1.ErrorOutPutUserRes, total int, err error) {
// 参数验证
if req.Id == 0 {
return nil, 0, gerror.New("题目ID不能为空")
}
// 直接在数据库层面按 jwcode 分组统计
err = g.Model("question_record r").
LeftJoin("user u", "r.jwcode = u.jwcode").
Where("r.question_bank_id = ?", req.Id).
Where("r.is_correct = 1").
Fields("r.jwcode", "u.user_name", "u.user_identity", "COUNT(*) as error_count").
Group("r.jwcode", "u.user_name", "u.user_identity").
OrderDesc("error_count").
Scan(&res)
if err != nil {
return nil, 0, gerror.Wrap(err, "查询错题用户统计失败")
}
total = len(res)
return res, total, nil
}
// -------------------------------------------------------------------------------------------------------------------------------
// ExportQuestion 导出题目数据到 Excel
func (s *sQuestionBank) ExportQuestion(r *ghttp.Request, ctx context.Context, req *v1.QuestionOutputReq) {
// === 1. 数据查询和验证 ===
var result []*v1.QuestionOutputRes
// 查询总数
_, total, err := service.QuestionBank().GetQuestions(ctx, req)
if err != nil {
response.JsonExit(r, 400, "查询失败", err.Error())
return
}
// 数据量验证
if total == 0 {
response.JsonExit(r, 400, "查询结果为空")
return
}
if total > 20000 {
response.JsonExit(r, 400, "导出数据过多,请添加筛选条件后再导出")
return
}
// === 2. 分批查询数据 ===
var num int
req.PageSize = 1000
for {
res, total, _ := s.GetQuestions(ctx, req)
result = append(result, res[:]...)
num += 1000
if num > total {
break
}
req.Page++
}
// === 3. 创建 Excel 文件 ===
excelFile := excelize.NewFile()
sheetName := "Sheet1"
fileName := "题目数据导出.xlsx"
// === 4. 设置表头 ===
headers := []string{"序号", "题干", "选项A", "选项B", "选项C", "选项D", "正确答案", "题目类型", "推荐课程", "引用次数", "错误次数", "错误率"}
for i, header := range headers {
col := string('A' + i)
excelFile.SetCellValue(sheetName, col+"1", header)
}
// === 5. 写入数据 ===
rowIndex := 2
for _, question := range result {
excelFile.SetCellValue(sheetName, "A"+strconv.Itoa(rowIndex), rowIndex-1)
excelFile.SetCellValue(sheetName, "B"+strconv.Itoa(rowIndex), question.Stem)
excelFile.SetCellValue(sheetName, "C"+strconv.Itoa(rowIndex), question.A)
excelFile.SetCellValue(sheetName, "D"+strconv.Itoa(rowIndex), question.B)
excelFile.SetCellValue(sheetName, "E"+strconv.Itoa(rowIndex), question.C)
excelFile.SetCellValue(sheetName, "F"+strconv.Itoa(rowIndex), question.D)
excelFile.SetCellValue(sheetName, "G"+strconv.Itoa(rowIndex), question.CorrectAnswer)
excelFile.SetCellValue(sheetName, "H"+strconv.Itoa(rowIndex), question.QuestionTypeName)
excelFile.SetCellValue(sheetName, "I"+strconv.Itoa(rowIndex), question.CrName)
excelFile.SetCellValue(sheetName, "J"+strconv.Itoa(rowIndex), question.CitationCount)
excelFile.SetCellValue(sheetName, "K"+strconv.Itoa(rowIndex), question.ErrorCount)
excelFile.SetCellValue(sheetName, "L"+strconv.Itoa(rowIndex), strconv.Itoa(question.ErrorRate)+"%")
rowIndex++
}
// === 6. 样式设置 ===
lastRow := rowIndex - 1
// 创建样式
style, err := excelFile.NewStyle(&excelize.Style{
Alignment: &excelize.Alignment{
Horizontal: "center",
Vertical: "center",
},
})
if err != nil {
response.JsonExit(r, 400, "创建样式失败", err.Error())
return
}
// 应用样式
excelFile.SetCellStyle(sheetName, "A1", "L"+strconv.Itoa(lastRow), style)
// 设置列宽
excelFile.SetColWidth(sheetName, "B", "B", 40) // 题干
excelFile.SetColWidth(sheetName, "C", "F", 20) // 选项A-D
excelFile.SetColWidth(sheetName, "G", "G", 12) // 正确答案
excelFile.SetColWidth(sheetName, "H", "H", 15) // 题目类型
excelFile.SetColWidth(sheetName, "I", "I", 20) // 推荐课程
excelFile.SetColWidth(sheetName, "J", "L", 12) // 统计信息
// === 7. 输出 Excel 文件 ===
buffer, err := excelFile.WriteToBuffer()
if err != nil {
response.JsonExit(r, 400, "生成Excel文件失败", err.Error())
return
}
// 设置响应头
r.Response.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
r.Response.Header().Set("Content-Disposition", "attachment; filename="+fileName)
r.Response.Write(buffer.Bytes())
}
//-------------------------------------------------------------------------------------------------------------------------------
// ExportUserScore 导出用户成绩数据到 Excel
func (s *sQuestionBank) ExportUserScore(r *ghttp.Request, ctx context.Context, req *v1.UserScoreOutputReq) {
// === 1. 数据查询和验证 ===
var result []*v1.UserScoreOutputRes
// 查询总数
_, total, err := service.QuestionBank().UserScoreOutput(ctx, req)
if err != nil {
response.JsonExit(r, 400, "查询失败", err.Error())
return
}
// 数据量验证
if total == 0 {
response.JsonExit(r, 400, "查询结果为空")
return
}
if total > 20000 {
response.JsonExit(r, 400, "导出数据过多,请添加筛选条件后再导出")
return
}
// === 2. 分批查询数据 ===
var num int
req.PageSize = 1000
for {
res, total, err := service.QuestionBank().UserScoreOutput(ctx, req)
if err != nil {
response.JsonExit(r, 400, "分批查询失败", err.Error())
return
}
result = append(result, res...)
num += req.PageSize
if num >= total {
break
}
req.Page++
}
// === 3. 创建 Excel 文件 ===
excelFile := excelize.NewFile()
sheetName := "Sheet1"
fileName := "用户成绩导出.xlsx"
// === 4. 设置表头 ===
headers := []string{"序号", "用户名", "用户身份", "精网号", "成绩", "提交时间"}
for i, header := range headers {
col := string('A' + i)
excelFile.SetCellValue(sheetName, col+"1", header)
}
// === 5. 写入数据 ===
rowIndex := 2
for _, userScore := range result {
excelFile.SetCellValue(sheetName, "A"+strconv.Itoa(rowIndex), rowIndex-1)
excelFile.SetCellValue(sheetName, "B"+strconv.Itoa(rowIndex), userScore.UserName)
excelFile.SetCellValue(sheetName, "C"+strconv.Itoa(rowIndex), userScore.UserIdentity)
excelFile.SetCellValue(sheetName, "D"+strconv.Itoa(rowIndex), userScore.Jwcode)
excelFile.SetCellValue(sheetName, "E"+strconv.Itoa(rowIndex), userScore.Score)
excelFile.SetCellValue(sheetName, "F"+strconv.Itoa(rowIndex), userScore.CreatedAt)
rowIndex++
}
// === 6. 样式设置 ===
lastRow := rowIndex - 1
// 创建样式
style, err := excelFile.NewStyle(&excelize.Style{
Alignment: &excelize.Alignment{
Horizontal: "center",
Vertical: "center",
},
})
if err != nil {
response.JsonExit(r, 400, "创建样式失败", err.Error())
return
}
// 应用样式
excelFile.SetCellStyle(sheetName, "A1", "F"+strconv.Itoa(lastRow), style)
// 设置列宽
excelFile.SetColWidth(sheetName, "B", "B", 20) // 用户名
excelFile.SetColWidth(sheetName, "C", "C", 15) // 用户身份
excelFile.SetColWidth(sheetName, "D", "D", 15) // 精网号
excelFile.SetColWidth(sheetName, "E", "E", 10) // 成绩
excelFile.SetColWidth(sheetName, "F", "F", 20) // 创建时间
// === 7. 输出 Excel 文件 ===
buffer, err := excelFile.WriteToBuffer()
if err != nil {
response.JsonExit(r, 400, "生成Excel文件失败", err.Error())
return
}
// 设置响应头
r.Response.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
r.Response.Header().Set("Content-Disposition", "attachment; filename="+fileName)
r.Response.Write(buffer.Bytes())
}

16
Knowledge_Test_Go/internal/model/do/course_recommend.go

@ -0,0 +1,16 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
)
// CourseRecommend is the golang structure of table course_recommend for DAO operations like Where/Data.
type CourseRecommend struct {
g.Meta `orm:"table:course_recommend, do:true"`
Id interface{} // 课程推荐主键
CrName interface{} // 课程推荐名称
}

29
Knowledge_Test_Go/internal/model/do/question_bank.go

@ -0,0 +1,29 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// QuestionBank is the golang structure of table question_bank for DAO operations like Where/Data.
type QuestionBank struct {
g.Meta `orm:"table:question_bank, do:true"`
Id interface{} // 题库主键
Stem interface{} // 题干
A interface{} // A选项
B interface{} // B选项
C interface{} // C选项
D interface{} // D选项
CorrectAnswer interface{} // 正确答案
QuestionTypeId interface{} // 题目类型
CourseRecommendationId interface{} // 课程推荐
CitationCount interface{} // 引用次数
ErrorCount interface{} // 错误次数
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 修改时间
Isdel interface{} // 逻辑删(1为删除)
}

21
Knowledge_Test_Go/internal/model/do/question_record.go

@ -0,0 +1,21 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// QuestionRecord is the golang structure of table question_record for DAO operations like Where/Data.
type QuestionRecord struct {
g.Meta `orm:"table:question_record, do:true"`
Id interface{} // 题目记录主键
Jwcode interface{} // 精网号
QuestionBankId interface{} // 题目id
UserAnswer interface{} // 用户答案
IsCorrect interface{} // 是否正确(0为正确)
CreatedAt *gtime.Time // 提交时间
}

16
Knowledge_Test_Go/internal/model/do/question_type.go

@ -0,0 +1,16 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
)
// QuestionType is the golang structure of table question_type for DAO operations like Where/Data.
type QuestionType struct {
g.Meta `orm:"table:question_type, do:true"`
Id interface{} // 题库类型主键
QuestionTypeName interface{} // 题目类型名称
}

19
Knowledge_Test_Go/internal/model/do/total_score.go

@ -0,0 +1,19 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// TotalScore is the golang structure of table total_score for DAO operations like Where/Data.
type TotalScore struct {
g.Meta `orm:"table:total_score, do:true"`
Id interface{} // 总成绩主键
Jwcode interface{} // 精网号
Score interface{} // 成绩
CreatedAt *gtime.Time // 提交时间
}

20
Knowledge_Test_Go/internal/model/do/user.go

@ -0,0 +1,20 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// User is the golang structure of table user for DAO operations like Where/Data.
type User struct {
g.Meta `orm:"table:user, do:true"`
Id interface{} // 用户主键
UserName interface{} // 用户名称
Jwcode interface{} // 精网号
UserIdentity interface{} // 用户身份
CreatedAt *gtime.Time // 创建时间
}

11
Knowledge_Test_Go/internal/model/entity/course_recommend.go

@ -0,0 +1,11 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// CourseRecommend is the golang structure for table course_recommend.
type CourseRecommend struct {
Id int `json:"id" orm:"id" ` // 课程推荐主键
CrName string `json:"crName" orm:"cr_name" ` // 课程推荐名称
}

27
Knowledge_Test_Go/internal/model/entity/question_bank.go

@ -0,0 +1,27 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// QuestionBank is the golang structure for table question_bank.
type QuestionBank struct {
Id int `json:"id" orm:"id" ` // 题库主键
Stem string `json:"stem" orm:"stem" ` // 题干
A string `json:"a" orm:"A" ` // A选项
B string `json:"b" orm:"B" ` // B选项
C string `json:"c" orm:"C" ` // C选项
D string `json:"d" orm:"D" ` // D选项
CorrectAnswer string `json:"correctAnswer" orm:"correct_answer" ` // 正确答案
QuestionTypeId int `json:"questionTypeId" orm:"question_type_id" ` // 题目类型
CourseRecommendationId int `json:"courseRecommendationId" orm:"course_recommendation_id" ` // 课程推荐
CitationCount int `json:"citationCount" orm:"citation_count" ` // 引用次数
ErrorCount int `json:"errorCount" orm:"error_count" ` // 错误次数
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" ` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" ` // 修改时间
Isdel int `json:"isdel" orm:"isdel" ` // 逻辑删(1为删除)
}

19
Knowledge_Test_Go/internal/model/entity/question_record.go

@ -0,0 +1,19 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// QuestionRecord is the golang structure for table question_record.
type QuestionRecord struct {
Id int `json:"id" orm:"id" ` // 题目记录主键
Jwcode int `json:"jwcode" orm:"jwcode" ` // 精网号
QuestionBankId int `json:"questionBankId" orm:"question_bank_id" ` // 题目id
UserAnswer string `json:"userAnswer" orm:"user_answer" ` // 用户答案
IsCorrect int `json:"isCorrect" orm:"is_correct" ` // 是否正确(0为正确)
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" ` // 提交时间
}

11
Knowledge_Test_Go/internal/model/entity/question_type.go

@ -0,0 +1,11 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
// QuestionType is the golang structure for table question_type.
type QuestionType struct {
Id int `json:"id" orm:"id" ` // 题库类型主键
QuestionTypeName string `json:"questionTypeName" orm:"question_type_name" ` // 题目类型名称
}

17
Knowledge_Test_Go/internal/model/entity/total_score.go

@ -0,0 +1,17 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// TotalScore is the golang structure for table total_score.
type TotalScore struct {
Id int `json:"id" orm:"id" ` // 总成绩主键
Jwcode int `json:"jwcode" orm:"jwcode" ` // 精网号
Score int `json:"score" orm:"score" ` // 成绩
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" ` // 提交时间
}

18
Knowledge_Test_Go/internal/model/entity/user.go

@ -0,0 +1,18 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// User is the golang structure for table user.
type User struct {
Id int `json:"id" orm:"id" ` // 用户主键
UserName string `json:"userName" orm:"user_name" ` // 用户名称
Jwcode string `json:"jwcode" orm:"jwcode" ` // 精网号
UserIdentity string `json:"userIdentity" orm:"user_identity" ` // 用户身份
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" ` // 创建时间
}

41
Knowledge_Test_Go/internal/service/knowledge.go

@ -0,0 +1,41 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
v1 "Knowledge_Test_Go/api/v1"
"context"
)
type (
IKnowledgeTest interface {
// GetQuestions 获取题目列表
GetQuestions(ctx context.Context, req *v1.GetQuestionsReq) (res []*v1.GetQuestionsRes, total int, err error)
// GetUserScores 获取用户成绩
GetUserScores(ctx context.Context, req *v1.GetUserScoresReq) (res []*v1.GetUserScoresRes, err error)
// GetCourse 获取用户课程
GetCourse(ctx context.Context, req *v1.GetCourseReq) (res []*v1.GetCourseRes, err error)
// SubmitAnswers 提交答案并计算分数
SubmitAnswers(ctx context.Context, req *v1.SubmitAnswersReq) (*v1.SubmitAnswersRes, error)
// GetWrongQuestions 获取错题列表
GetWrongQuestions(ctx context.Context, req *v1.GetWrongQuestionsReq) (res []*v1.GetWrongQuestionsRes, total int, err error)
}
)
var (
localKnowledgeTest IKnowledgeTest
)
func KnowledgeTest() IKnowledgeTest {
if localKnowledgeTest == nil {
panic("implement not found for interface IKnowledgeTest, forgot register?")
}
return localKnowledgeTest
}
func RegisterKnowledgeTest(i IKnowledgeTest) {
localKnowledgeTest = i
}

47
Knowledge_Test_Go/internal/service/question_bank.go

@ -0,0 +1,47 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
v1 "Knowledge_Test_Go/api/v1"
"context"
"github.com/gogf/gf/v2/net/ghttp"
)
type (
IQuestionBank interface {
// GetQuestions 获取题目列表
GetQuestions(ctx context.Context, req *v1.QuestionOutputReq) (res []*v1.QuestionOutputRes, total int, err error)
// QuestionUpdate 修改题目
QuestionUpdate(ctx context.Context, req *v1.QuestionUpdateReq) (res string, err error)
// QuestionDel 删除题目
QuestionDel(ctx context.Context, req *v1.QuestionDelReq) (res string, err error)
// UserScoreOutput 获取用户成绩列表
UserScoreOutput(ctx context.Context, req *v1.UserScoreOutputReq) (res []*v1.UserScoreOutputRes, total int, err error)
// ErrorOutPutUser 错题统计出错用户
ErrorOutPutUser(ctx context.Context, req *v1.ErrorOutPutUserReq) (res []*v1.ErrorOutPutUserRes, total int, err error)
// ExportQuestion 导出题目数据到 Excel
ExportQuestion(r *ghttp.Request, ctx context.Context, req *v1.QuestionOutputReq)
// ExportUserScore 导出用户成绩数据到 Excel
ExportUserScore(r *ghttp.Request, ctx context.Context, req *v1.UserScoreOutputReq)
}
)
var (
localQuestionBank IQuestionBank
)
func QuestionBank() IQuestionBank {
if localQuestionBank == nil {
panic("implement not found for interface IQuestionBank, forgot register?")
}
return localQuestionBank
}
func RegisterQuestionBank(i IQuestionBank) {
localQuestionBank = i
}

6
Knowledge_Test_Go/main.go

@ -3,9 +3,15 @@ package main
import (
_ "Knowledge_Test_Go/internal/packed"
_ "Knowledge_Test_Go/internal/logic"
"github.com/gogf/gf/v2/os/gctx"
"Knowledge_Test_Go/internal/cmd"
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
)
func main() {

128
Knowledge_Test_Go/utility/response/response.go

@ -0,0 +1,128 @@
package response
import (
"net/http"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/gconv"
)
// JsonRes 数据返回通用JSON数据结构
type JsonRes struct {
Code int `json:"code"` // 错误码((0:成功, 1:失败, >1:错误码))
Message string `json:"msg"` // 提示信息
Data interface{} `json:"data"` // 返回数据(业务接口定义具体数据结构)
// Redirect string `json:"redirect"` // 引导客户端跳转到指定路由
}
// Json 返回标准JSON数据。
func Json(r *ghttp.Request, code int, message string, data ...interface{}) {
var responseData interface{}
if len(data) > 0 {
responseData = data[0]
} else {
responseData = g.Map{}
}
r.Response.WriteJson(JsonRes{
Code: code,
Message: message,
Data: responseData,
})
}
// JsonExit 返回标准JSON数据并退出当前HTTP执行函数。
func JsonExit(r *ghttp.Request, code int, message string, data ...interface{}) {
if code == http.StatusBadRequest {
g.Log().Error(r.Context(), code, message)
}
Json(r, code, message, data...)
r.Exit()
}
func dataReturn(r *ghttp.Request, code int, req ...interface{}) *JsonRes {
var msg string
var data interface{}
if len(req) > 0 {
msg = gconv.String(req[0])
}
if len(req) > 1 {
data = req[1]
}
// msg = GetCodeMsg(code, msg)
if code != 1 && !gconv.Bool(r.GetCtxVar("api_code")) {
code = 0
}
response := &JsonRes{
// ID: r.GetCtxVar("RequestId").String(),
Code: code,
Message: msg,
Data: data,
}
r.SetParam("apiReturnRes", response)
return response
}
// Auth 认证失败
func Auth(r *ghttp.Request) {
res := dataReturn(r, 999, "请登录")
r.Response.WriteJsonExit(res)
}
// AuthBlack Auth 认证失败 被冻结拉黑
func AuthBlack(r *ghttp.Request) {
res := dataReturn(r, 888, "您的账号被冻结拉黑,请联系管理员")
r.Response.WriteJsonExit(res)
}
// JsonRedirect 返回标准JSON数据引导客户端跳转。
func JsonRedirect(r *ghttp.Request, code int, message, redirect string, data ...interface{}) {
responseData := interface{}(nil)
if len(data) > 0 {
responseData = data[0]
}
r.Response.WriteJson(JsonRes{
Code: code,
Message: message,
Data: responseData,
// Redirect: redirect,
})
}
// JsonRedirectExit 返回标准JSON数据引导客户端跳转,并退出当前HTTP执行函数。
func JsonRedirectExit(r *ghttp.Request, code int, message, redirect string, data ...interface{}) {
JsonRedirect(r, code, message, redirect, data...)
r.Exit()
}
func SuccessWithData(r *ghttp.Request, data interface{}) {
res := dataReturn(r, 1, "ok", data)
r.Response.WriteJsonExit(res)
}
// JsonResponse 数据返回通用JSON数据结构
type JsonResponse struct {
// ID string `json:"id"` //
Code int `json:"code"` // 错误码((1:成功, 0:失败, >1:错误码))
Message string `json:"message"` // 提示信息
Data interface{} `json:"data,omitempty"` // 返回数据(业务接口定义具体数据结构)
Redirect string `json:"redirect,omitempty"` // 引导客户端跳转到指定路由
}
/*错误,只有错误信息,错误码0*/
func Error(msg string) *JsonRes {
return &JsonRes{
Code: 400, // 错误码
Message: msg, // 错误信息
Data: nil,
}
}
/*成功,有数据*/
func SuccessWithDataNoReq(data interface{}) *JsonRes {
return &JsonRes{
Code: 200,
Message: "success",
Data: data,
}
}
Loading…
Cancel
Save