|
@@ -1,12 +1,16 @@
|
|
|
package learning
|
|
package learning
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
|
+ "bytes"
|
|
|
"context"
|
|
"context"
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
|
|
+ "io/ioutil"
|
|
|
"lims_adapter/dao/learning"
|
|
"lims_adapter/dao/learning"
|
|
|
"lims_adapter/model/learning"
|
|
"lims_adapter/model/learning"
|
|
|
|
|
+ "net/http"
|
|
|
"strconv"
|
|
"strconv"
|
|
|
|
|
+ "strings"
|
|
|
|
|
|
|
|
"dashoo.cn/micro_libary/micro_srv"
|
|
"dashoo.cn/micro_libary/micro_srv"
|
|
|
"dashoo.cn/micro_libary/myerrors"
|
|
"dashoo.cn/micro_libary/myerrors"
|
|
@@ -245,6 +249,146 @@ func (s LearningQuestionService) Delete(ctx context.Context, id []int) error {
|
|
|
return err
|
|
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) {
|
|
func QuestionTemplate() (*excelize.File, error) {
|
|
|
f := excelize.NewFile()
|
|
f := excelize.NewFile()
|
|
|
sheet := "Sheet1"
|
|
sheet := "Sheet1"
|