Browse Source

11.12

所有接口的基本功能都已实现
wangguixi/feature-20251107144650-股票知识测评
wangguixi 2 months ago
parent
commit
4ef48d2d72
  1. 40
      Knowledge_Test_Go/api/v1/questionBank.go
  2. 15
      Knowledge_Test_Go/go.mod
  3. 29
      Knowledge_Test_Go/go.sum
  4. 16
      Knowledge_Test_Go/internal/cmd/cmd.go
  5. 45
      Knowledge_Test_Go/internal/controller/questionBank.go
  6. 10
      Knowledge_Test_Go/internal/logic/knowledge/knowledge.go
  7. 152
      Knowledge_Test_Go/internal/logic/questionBank/questionBank.go
  8. 1
      Knowledge_Test_Go/internal/service/knowledge.go
  9. 8
      Knowledge_Test_Go/internal/service/question_bank.go

40
Knowledge_Test_Go/api/v1/questionBank.go

@ -58,14 +58,6 @@ type GetWrongQuestionsRes struct {
CorrectAnswer string `json:"correctAnswer" dc:"正确答案"`
}
// TotalScoreOutput 成绩输出
type TotalScoreOutput struct {
Id int `json:"id"`
Jwcode int `json:"jwcode"`
Score int `json:"score"`
CreatedAt string `json:"createdAt"`
}
//------------------------------------------------------------------------------------------------------------
// QuestionOutputReq 获取题目列表请求
@ -93,6 +85,7 @@ type QuestionOutputRes struct {
ErrorRate int `json:"errorRate"`
}
// QuestionUpdateReq 修改题目请求
type QuestionUpdateReq struct {
Id int `json:"id"`
Stem string `json:"stem"`
@ -104,6 +97,37 @@ type QuestionUpdateReq struct {
QuestionTypeId string `json:"question_type_id"`
CourseRecommendationId string `json:"course+recommendation_id"`
}
// QuestionDelReq 删除题目请求
type QuestionDelReq struct {
Id int `json:"id"`
}
// UserScoreOutput 用户成绩输出
type UserScoreOutput 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 int `json:"jwcode"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// 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"`
}

15
Knowledge_Test_Go/go.mod

@ -1,11 +1,12 @@
module Knowledge_Test_Go
go 1.23.0
go 1.24.0
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 (
@ -30,14 +31,20 @@ require (
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/net v0.43.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.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
)

29
Knowledge_Test_Go/go.sum

@ -61,6 +61,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
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=
@ -68,6 +73,14 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
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=
@ -82,13 +95,17 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr
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/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
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=

16
Knowledge_Test_Go/internal/cmd/cmd.go

@ -34,16 +34,12 @@ var (
group.Middleware(
ghttp.MiddlewareHandlerResponse,
)
group.POST("/questions/get", controller.NewQuestionBank().GetQuestions)
group.POST("/questions/update", controller.NewQuestionBank().QuestionUpdate)
group.POST("/questions/del", controller.NewQuestionBank().QuestionDel)
//kt := controller.NewKnowledgeTest()
//qb := controller.NewQuestionBank()
//group.GET("/users", kt.AdminUserList)
//group.GET("/wrong-statistics", kt.AdminWrongStatistics)
//group.GET("/questions", qb.AdminQuestionList)
//group.POST("/questions/update", qb.UpdateQuestion)
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
})
s.Run()

45
Knowledge_Test_Go/internal/controller/questionBank.go

@ -48,6 +48,7 @@ func (c *cQuestionBank) QuestionUpdate(r *ghttp.Request) {
})
}
// QuestionDel 删除题目
func (c *cQuestionBank) QuestionDel(r *ghttp.Request) {
ctx := r.GetCtx()
var req *v1.QuestionDelReq
@ -62,3 +63,47 @@ func (c *cQuestionBank) QuestionDel(r *ghttp.Request) {
"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)
}

10
Knowledge_Test_Go/internal/logic/knowledge/knowledge.go

@ -21,12 +21,13 @@ func init() {
// GetQuestions 获取题目列表
func (s *sKnowledgeTest) GetQuestions(ctx context.Context, req *v1.GetQuestionsReq) (res []*v1.GetQuestionsRes, total int, err error) {
db := g.Model("question_bank a").Fields("a.id", "a.stem", "a.a", "a.b", "a.c", "a.d")
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)
@ -36,6 +37,8 @@ func (s *sKnowledgeTest) GetUserScores(ctx context.Context, req *v1.GetUserScore
return res, nil
}
// -----------------------------------------------------------------------------------------------------------------------------------------------
// SubmitAnswers 提交答案并计算分数
func (s *sKnowledgeTest) SubmitAnswers(ctx context.Context, req *v1.SubmitAnswersReq) (*v1.SubmitAnswersRes, error) {
if len(req.Answers) == 0 {
@ -47,7 +50,6 @@ func (s *sKnowledgeTest) SubmitAnswers(ctx context.Context, req *v1.SubmitAnswer
for i, answer := range req.Answers {
questionIds[i] = answer.QuestionId
}
// 批量查询题目
var questions []*do.QuestionBank
err := dao.QuestionBank.Ctx(ctx).
@ -150,10 +152,12 @@ func (s *sKnowledgeTest) SubmitAnswers(ctx context.Context, req *v1.SubmitAnswer
}, 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").
LeftJoin("question_bank a", "a.id=b.question_bank_id").
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

152
Knowledge_Test_Go/internal/logic/questionBank/questionBank.go

@ -3,10 +3,16 @@ package questionBank
import (
v1 "Knowledge_Test_Go/api/v1"
"Knowledge_Test_Go/internal/service"
"Knowledge_Test_Go/utility/response"
"context"
"fmt"
"strconv"
"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{}
@ -19,7 +25,7 @@ func init() {
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").
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")
@ -115,3 +121,147 @@ func (s *sQuestionBank) QuestionDel(ctx context.Context, req *v1.QuestionDelReq)
}
//-------------------------------------------------------------------------------------------------------------------------------
// UserScoreOutput 获取用户成绩列表
func (s *sQuestionBank) UserScoreOutput(ctx context.Context, req *v1.UserScoreOutputReq) (res []*v1.UserScoreOutput, 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")
err = db.Page(req.Page, req.PageSize).ScanAndCount(&res, &total, false)
return
}
//-------------------------------------------------------------------------------------------------------------------------------
// 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).
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{"ID", "题干", "选项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.Id)
excelFile.SetCellValue(sheetName, "C"+strconv.Itoa(rowIndex), question.Stem)
excelFile.SetCellValue(sheetName, "D"+strconv.Itoa(rowIndex), question.A)
excelFile.SetCellValue(sheetName, "E"+strconv.Itoa(rowIndex), question.B)
excelFile.SetCellValue(sheetName, "F"+strconv.Itoa(rowIndex), question.C)
excelFile.SetCellValue(sheetName, "G"+strconv.Itoa(rowIndex), question.D)
excelFile.SetCellValue(sheetName, "H"+strconv.Itoa(rowIndex), question.CorrectAnswer)
excelFile.SetCellValue(sheetName, "I"+strconv.Itoa(rowIndex), question.QuestionTypeName)
excelFile.SetCellValue(sheetName, "J"+strconv.Itoa(rowIndex), question.CrName)
excelFile.SetCellValue(sheetName, "K"+strconv.Itoa(rowIndex), question.CitationCount)
excelFile.SetCellValue(sheetName, "L"+strconv.Itoa(rowIndex), question.ErrorCount)
excelFile.SetCellValue(sheetName, "M"+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, "A", "A", 10) // ID
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())
}

1
Knowledge_Test_Go/internal/service/knowledge.go

@ -14,7 +14,6 @@ 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)
// SubmitAnswers 提交答案并计算分数

8
Knowledge_Test_Go/internal/service/question_bank.go

@ -8,6 +8,8 @@ package service
import (
v1 "Knowledge_Test_Go/api/v1"
"context"
"github.com/gogf/gf/v2/net/ghttp"
)
type (
@ -18,6 +20,12 @@ type (
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.UserScoreOutput, 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)
}
)

Loading…
Cancel
Save