Browse Source

feature:培训考试题库批量上传

liuyaqi 3 năm trước cách đây
mục cha
commit
5fe2684057

+ 16 - 0
handler/learning/question.go

@@ -118,3 +118,19 @@ func (c *LearningQuestion) Template(ctx context.Context, req *model.EmptyArgs, r
 	rsp.Data = base64.StdEncoding.EncodeToString(buf.Bytes())
 	return nil
 }
+
+func (c *LearningQuestion) BatchUpload(ctx context.Context, req *learning.LearningQuestionBatchUploadReq, rsp *comm_def.CommonMsg) error {
+	g.Log().Infof("LearningQuestion.Delete request %#v ", *req)
+	s, err := learningSrv.NewLearningQuestionService(ctx)
+	if err != nil {
+		return err
+	}
+	err = s.BatchUpload(ctx, req)
+	_, err, code, msg := myerrors.CheckError(err)
+	if err != nil {
+		return err
+	}
+	rsp.Code = code
+	rsp.Msg = msg
+	return nil
+}

+ 5 - 0
model/learning/learning_question.go

@@ -62,3 +62,8 @@ type LearningQuestionUpdateReq struct {
 type LearningQuestionDeleteReq struct {
 	Id []int `json:"id" v:"required#请输入题目Id"`
 }
+
+type LearningQuestionBatchUploadReq struct {
+	SkillId  int    `json:"skillId"`                          // 技能 Id
+	ExcelUrl string `json:"excelUrl" v:"required#请输入excel地址"` // excel 文件地址
+}

+ 144 - 0
service/learning/question.go

@@ -1,12 +1,16 @@
 package learning
 
 import (
+	"bytes"
 	"context"
 	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"lims_adapter/dao/learning"
 	"lims_adapter/model/learning"
+	"net/http"
 	"strconv"
+	"strings"
 
 	"dashoo.cn/micro_libary/micro_srv"
 	"dashoo.cn/micro_libary/myerrors"
@@ -245,6 +249,146 @@ func (s LearningQuestionService) Delete(ctx context.Context, id []int) error {
 	return err
 }
 
+func (s LearningQuestionService) BatchUpload(ctx context.Context, req *learning.LearningQuestionBatchUploadReq) error {
+	r, err := s.Dao.DB.Table("learning_skill").Where("Id", req.SkillId).One()
+	if err != nil {
+		return err
+	}
+	if r.IsEmpty() {
+		return myerrors.NewMsgError(nil, fmt.Sprintf("技能不存在: %d", req.SkillId))
+	}
+
+	b, err := DownFile(req.ExcelUrl)
+	if err != nil {
+		return myerrors.NewMsgError(nil, fmt.Sprintf("下载 excel 异常 %s", err.Error()))
+	}
+	question, err := ParseQuestionExcel(req.SkillId, s.userInfo.RealName, b)
+	if err != nil {
+		return myerrors.NewMsgError(nil, fmt.Sprintf("解析 excel 异常 %s", err.Error()))
+	}
+	_, err = s.Dao.Insert(question)
+	return err
+}
+
+func DownFile(url string) ([]byte, error) {
+	r, err := http.Get(url)
+	if err != nil {
+		return nil, err
+	}
+	if r.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("DownFile from %s StatusCode %d", url, r.StatusCode)
+	}
+	defer r.Body.Close()
+	return ioutil.ReadAll(r.Body)
+}
+
+var allowAnswer = []string{"A", "B", "C", "D"}
+
+func ParseQuestionExcel(skillId int, operateBy string, b []byte) ([]learning.LearningQuestion, error) {
+	f, err := excelize.OpenReader(bytes.NewBuffer(b))
+	if err != nil {
+		return nil, err
+	}
+	sheet := "Sheet1"
+	rows, err := f.GetRows(sheet)
+	if err != nil {
+		return nil, err
+	}
+
+	questions := []learning.LearningQuestion{}
+	for rown, row := range rows[1:] {
+		rown += 1
+		if len(row) < 9 {
+			return nil, fmt.Errorf("excel 格式错误:列数小于9列")
+		}
+
+		name := strings.TrimSpace(row[2])
+		typeStr := strings.TrimSpace(row[1])
+		explanation := strings.TrimSpace(row[8])
+		a := strings.TrimSpace(row[3])
+		b := strings.TrimSpace(row[4])
+		c := strings.TrimSpace(row[5])
+		d := strings.TrimSpace(row[6])
+
+		var qtype int
+		switch typeStr {
+		case "单选题":
+			qtype = 1
+		case "多选题":
+			qtype = 2
+		case "判断题":
+			qtype = 3
+		default:
+			return nil, fmt.Errorf("excel 格式错误:不合法的题型 '%s' %d", typeStr, rown)
+		}
+
+		answerStr := strings.TrimSpace(row[7])
+		answer := strings.Split(answerStr, " ")
+		for i := range answer {
+			pass := false
+			for _, allow := range allowAnswer {
+				if answer[i] == allow {
+					pass = true
+					break
+				}
+			}
+			if !pass {
+				return nil, fmt.Errorf("excel 格式错误:不合法的答案:'%s' %d", answer[i], rown)
+			}
+		}
+
+		options := []learning.LearningQuestionOption{
+			{
+				Name:      "A",
+				Content:   a,
+				IsCorrect: strings.Contains(answerStr, "A"),
+			},
+			{
+				Name:      "B",
+				Content:   b,
+				IsCorrect: strings.Contains(answerStr, "B"),
+			},
+			{
+				Name:      "C",
+				Content:   c,
+				IsCorrect: strings.Contains(answerStr, "C"),
+			},
+			{
+				Name:      "D",
+				Content:   d,
+				IsCorrect: strings.Contains(answerStr, "D"),
+			},
+		}
+		correctCount := 0
+		for _, o := range options {
+			if o.IsCorrect {
+				correctCount += 1
+			}
+		}
+		if correctCount < 1 {
+			return nil, fmt.Errorf("excel 格式错误:含有未设置正确答案的题目 %d", rown)
+		}
+		if (qtype == 1 || qtype == 3) && correctCount != 1 {
+			return nil, fmt.Errorf("excel 格式错误:含有设置正确答案和题型不符的题目 %d", rown)
+		}
+		content, _ := json.Marshal(options)
+
+		q := learning.LearningQuestion{
+			SkillId:     skillId,
+			Name:        name,
+			Type:        qtype,
+			Enable:      1,
+			Content:     string(content),
+			Explanation: explanation,
+			OperateBy:   operateBy,
+			CreatedAt:   gtime.New(),
+			UpdatedAt:   gtime.New(),
+		}
+		questions = append(questions, q)
+	}
+	return questions, nil
+}
+
 func QuestionTemplate() (*excelize.File, error) {
 	f := excelize.NewFile()
 	sheet := "Sheet1"

+ 41 - 0
swaggerui/swagger.yml

@@ -430,6 +430,31 @@ paths:
                   success:
                     $ref: "#/components/examples/success"
 
+    /LearningQuestion.BatchUpload:
+      post:
+        tags:
+          - 考试培训-题库
+        operationId: LearningQuestionBatchUpload
+        summary: 批量上传题库
+        requestBody:
+          required: true
+          content:
+            application/json:
+              schema:
+                oneOf:
+                  - $ref: '#/components/schemas/LearningQuestionBatchUpload'
+              examples:
+                LearningQuestionBatchUpload:
+                  $ref: '#/components/examples/LearningQuestionBatchUpload'
+        responses:
+          200:
+            description: 请求成功
+            content:
+              application/json:
+                examples:
+                  success:
+                    $ref: "#/components/examples/success"
+
     /LearningExamRecord.AddToMy:
       post:
         tags:
@@ -1042,6 +1067,18 @@ components:
         explanationImage:
           type: string
           description: 题目解析图片
+    LearningQuestionBatchUpload:
+      type: object
+      required:
+        - skillId
+        - excelUrl
+      properties:
+        skillId:
+          type: integer
+          description: 技能 Id
+        excelUrl:
+          type: string
+          description: excel 地址
     LearningExamRecordAddToMy:
       type: object
       required:
@@ -1487,3 +1524,7 @@ components:
     LearningTestpaperDelete:
       value:
         id: [1]
+    LearningQuestionBatchUpload:
+      value:
+        skillId: 5
+        excelUrl: http://192.168.0.252:9390/9,21086966c07b68