package service import ( "errors" "fmt" "github.com/goccy/go-json" "gorm.io/gorm" "knowledge/api/dao" "knowledge/api/dto" "knowledge/api/model" "knowledge/api/requests" "knowledge/global" "knowledge/utils" "strconv" "time" ) type QuestionQaService struct { } // 题库-飞花令题目数量规则 type tokenQuestionContent struct { QuestionType int `json:"question_type"` // 题目类型(1:单选 2:多选 3:问答 4:判断) Quantity int `json:"quantity"` // 数量 } // AddQuestionQa 新增问答题库 func (r *QuestionQaService) AddQuestionQa(req requests.AddQuestionQa) (bool, error) { // 处理图片 if req.Image != "" { req.Image = utils.RemoveOssDomain(req.Image) } // 验证过期时间 now := time.Now() // 1:绝对时效 // 获取本地时区 location, err := time.LoadLocation("Local") if err != nil { return false, errors.New("新增失败") } qaExpireTime, err := time.ParseInLocation("2006-01-02 15:04", req.QaExpireTime, location) if err != nil { return false, errors.New("过期时间错误") } if qaExpireTime.Before(now) { return false, errors.New("过期时间需大于当前时间") } // 处理明细选题规则 questionQaItemContent, err := json.Marshal(req.QuestionQaItem) if err != nil { return false, errors.New("明细题目错误") } // 获取并检测题库题目数量 qaQuantity, err := r.CheckAddQaQuestionQuantity(req) if err != nil { return false, err } // 检测题目明细重复问题 var items []*requests.QuestionQaItem for _, v := range req.QuestionQaItem { if r.CheckQuestionQaItemRepeat(items, v) { items = append(items, v) } else { return false, errors.New(utils.QuestionType(v.QuestionType) + "选题存在冲突") } } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 新增题目 questionQa := &model.QuestionQa{ QaName: req.QaName, QaType: req.QaType, QaQuantity: qaQuantity, QaStatus: 1, QaRuleContent: req.QaRuleContent, TokenNum: nil, RoundNum: nil, QaDisplayType: req.QaDisplayType, IsTurnTimer: req.IsTurnTimer, QaExpireTime: model.LocalTime(qaExpireTime), QaPassword: req.QaPassword, OpenNumber: 0, Image: req.Image, ItemContent: string(questionQaItemContent), } // 固定套题模式-飞花令数量 if req.QaType == 2 { questionQa.TokenNum = req.TokenNum } // 多轮固定题型模式-飞花令数量、轮次数量 if req.QaType == 3 { questionQa.TokenNum = req.TokenNum questionQa.RoundNum = req.RoundNum } if req.QaType == 2 || req.QaType == 3 { // 处理飞花令题目数量规则 tokenQuestionContent, err := json.Marshal(req.TokenQuestionContent) if err != nil { return false, errors.New("飞花令题目数量错误") } questionQa.TokenQuestionContent = string(tokenQuestionContent) } questionQaDao := dao.QuestionQaDao{} questionQa, err = questionQaDao.AddQuestionQa(tx, questionQa) if err != nil { tx.Rollback() return false, errors.New("新增失败") } // 新增飞花令标签数据 if req.QaDisplayType == 2 { questionQaTokenDao := dao.QuestionQaTokenDao{} baseTokenDao := dao.BaseTokenDao{} baseTokenItemDao := dao.BaseTokenItemDao{} // 飞花令明细总数 tokenItemQuantity := 0 for i, item := range req.BaseTokenItem { tokenId, err := strconv.ParseInt(item.TokenId, 10, 64) if err != nil { tx.Rollback() return false, err } // 检测飞花令基础数据 _, err = baseTokenDao.GetBaseTokenById(tokenId) if err != nil { tx.Rollback() return false, err } // 获取飞花令明细数据 baseTokenItem, err := baseTokenItemDao.GetBaseTokenItemListByTokenId(tokenId) if err != nil { tx.Rollback() return false, err } // 飞花令明细总数 tokenItemQuantity = tokenItemQuantity + len(baseTokenItem) questionQaToken := &model.QuestionQaToken{ QaId: questionQa.QaId, TokenId: tokenId, Sort: i + 1, } questionQaToken, err = questionQaTokenDao.AddQuestionQaToken(tx, questionQaToken) if err != nil { tx.Rollback() return false, err } } // 检测飞花令数量 if req.QaType == 1 { // 所需飞花令数量 = 题目总数 if tokenItemQuantity < qaQuantity { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", qaQuantity)) } } if req.QaType == 2 { // 所需飞花令数量 = TokenNum if tokenItemQuantity < *req.TokenNum { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", *req.TokenNum)) } } if req.QaType == 3 { //// 轮次 * 最大值 = 所需飞花令数量 //maxTokenQuestionQuantity := 0 //for _, content := range req.TokenQuestionContent { // if content.Quantity > maxTokenQuestionQuantity { // maxTokenQuestionQuantity = content.Quantity // } //} if tokenItemQuantity < *req.TokenNum { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", *req.TokenNum)) } } } // 生成分享链接 questionQaData := make(map[string]interface{}) questionQaData["qa_share_id"] = utils.GenerateUniqueCode() err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) if err != nil { tx.Rollback() return false, errors.New("新增失败") } // 新增问答题库题目列表 questionDao := dao.QuestionDao{} questionQaItemDao := dao.QuestionQaItemDao{} for _, item := range req.QuestionQaItem { // 验证数量 maps := make(map[string]interface{}) maps["question_type"] = item.QuestionType maps["question_status"] = 1 maps["is_delete"] = 0 maps["question_source"] = 1 if item.Difficulty != nil { maps["difficulty"] = item.Difficulty } maps["first_label_id"] = item.FirstLabelId if item.SecondLabelId != "" { maps["second_label_id"] = item.SecondLabelId } // 获取随机明细题目 questions, err := questionDao.GetQuestionListRand(maps, item.Quantity) if err != nil { tx.Rollback() return false, err } if len(questions) < item.Quantity { tx.Rollback() return false, errors.New(utils.QuestionType(item.QuestionType) + "数量不足") } // 新增明细题目 for _, question := range questions { questionQaItem := &model.QuestionQaItem{ QaId: questionQa.QaId, QuestionId: question.QuestionId, } questionQaItem, err := questionQaItemDao.AddQuestionQaItem(tx, questionQaItem) if err != nil { tx.Rollback() return false, errors.New("新增失败") } } } // 新增计时设置 if req.IsTurnTimer == 1 { questionQaTimerDao := dao.QuestionQaTimerDao{} for _, timer := range req.QuestionQaTimer { QuestionQaTimer := &model.QuestionQaTimer{ QaId: questionQa.QaId, QuestionType: timer.QuestionType, TimerRule: timer.TimerRule, Duration: timer.Duration, } QuestionQaTimer, err := questionQaTimerDao.AddQuestionQaTimer(tx, QuestionQaTimer) if err != nil { tx.Rollback() return false, errors.New("新增失败") } } } tx.Commit() return true, nil } // PutQuestionQa 修改题目题库 func (r *QuestionQaService) PutQuestionQa(qaId int64, req requests.PutQuestionQa) (bool, error) { questionQaDao := dao.QuestionQaDao{} questionDao := dao.QuestionDao{} questionQa, err := questionQaDao.GetQuestionQaById(qaId) if err != nil { return false, errors.New("题库不存在") } if questionQa.QaStatus == 2 { return false, errors.New("题库已失效,请重新创建") } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() questionQaData := make(map[string]interface{}) // 名称 if req.QaName != questionQa.QaName { questionQaData["qa_name"] = req.QaName } // 规则解释 if req.QaRuleContent != questionQa.QaRuleContent { questionQaData["qa_rule_content"] = req.QaRuleContent } // 展示类型 if req.QaDisplayType != questionQa.QaDisplayType { questionQaData["qa_display_type"] = req.QaDisplayType } // 验证过期时间 now := time.Now() // 1:绝对时效 // 获取本地时区 location, err := time.LoadLocation("Local") if err != nil { tx.Rollback() return false, errors.New("新增失败") } qaExpireTime, err := time.ParseInLocation("2006-01-02 15:04", req.QaExpireTime, location) if err != nil { tx.Rollback() return false, errors.New("过期时间错误") } if qaExpireTime.Before(now) { tx.Rollback() return false, errors.New("过期时间需大于当前时间") } // 分享密码 if req.QaPassword != questionQa.QaPassword { questionQaData["qa_password"] = req.QaPassword } // 背景图 image := utils.RemoveOssDomain(req.Image) if image != questionQa.Image { questionQaData["image"] = image } // 处理飞花令题目数量规则 tokenQuestionContent, _ := json.Marshal(req.TokenQuestionContent) if string(tokenQuestionContent) != questionQa.TokenQuestionContent { questionQaData["token_question_content"] = string(tokenQuestionContent) } // 获取并检测题库题目数量 qaQuantity, err := r.CheckPutQaQuestionQuantity(req) if err != nil { tx.Rollback() return false, err } // 题目数量 if qaQuantity != questionQa.QaQuantity { if req.Action == 1 { tx.Rollback() return false, errors.New("您修改了题目数量,无法正常修改该题库,请重新生成") } questionQaData["qa_quantity"] = qaQuantity if req.QaType == 2 { questionQaData["token_num"] = req.TokenNum } if req.QaType == 3 { questionQaData["token_num"] = req.TokenNum questionQaData["round_num"] = req.RoundNum } } // 处理题库明细-需重新生成时才会检测明细 if req.Action == 2 { // 检测题目明细重复问题 var items []*requests.QuestionQaItem for _, v := range req.QuestionQaItem { if r.CheckQuestionQaItemRepeat(items, v) { items = append(items, v) } else { return false, errors.New(utils.QuestionType(v.QuestionType) + ":选题存在冲突") } } // 删除所有明细 questionQaItemDao := dao.QuestionQaItemDao{} err := questionQaItemDao.DeleteQuestionQaItemByQaId(tx, questionQa.QaId) if err != nil { tx.Rollback() return false, err } for _, item := range req.QuestionQaItem { // 验证数量 maps := make(map[string]interface{}) maps["question_type"] = item.QuestionType maps["question_status"] = 1 maps["is_delete"] = 0 maps["question_source"] = 1 if item.Difficulty != nil { maps["difficulty"] = item.Difficulty } maps["first_label_id"] = item.FirstLabelId if item.SecondLabelId != "" { maps["second_label_id"] = item.SecondLabelId } // 获取随机明细题目 questions, err := questionDao.GetQuestionListRand(maps, item.Quantity) if err != nil { tx.Rollback() return false, err } if len(questions) < item.Quantity { tx.Rollback() return false, errors.New("选题超出现有题目数量") } for _, question := range questions { questionQaItem := &model.QuestionQaItem{ QaId: questionQa.QaId, QuestionId: question.QuestionId, } questionQaItem, err := questionQaItemDao.AddQuestionQaItem(tx, questionQaItem) if err != nil { tx.Rollback() return false, errors.New("新增失败") } } } // 处理明细选题规则 questionQaItemContent, err := json.Marshal(req.QuestionQaItem) if err != nil { tx.Rollback() return false, err } if string(questionQaItemContent) != questionQa.ItemContent { questionQaData["item_content"] = string(questionQaItemContent) } } // 计时开关 if req.IsTurnTimer != questionQa.IsTurnTimer { questionQaData["is_turn_timer"] = req.IsTurnTimer } if len(questionQaData) > 0 { err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } } // 删除飞花令 questionQaTokenDao := dao.QuestionQaTokenDao{} maps := make(map[string]interface{}) maps["qa_id"] = questionQa.QaId err = questionQaTokenDao.DeleteQuestionQaToken(tx, maps) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } // 新增飞花令 if req.QaDisplayType == 2 { baseTokenDao := dao.BaseTokenDao{} baseTokenItemDao := dao.BaseTokenItemDao{} // 飞花令明细总数 tokenItemQuantity := 0 for i, item := range req.BaseTokenItem { tokenId, err := strconv.ParseInt(item.TokenId, 10, 64) if err != nil { tx.Rollback() return false, err } // 检测飞花令基础数据 _, err = baseTokenDao.GetBaseTokenById(tokenId) if err != nil { tx.Rollback() return false, err } // 获取飞花令明细数据 baseTokenItem, err := baseTokenItemDao.GetBaseTokenItemListByTokenId(tokenId) if err != nil { tx.Rollback() return false, err } // 飞花令明细总数 tokenItemQuantity = tokenItemQuantity + len(baseTokenItem) questionQaToken := &model.QuestionQaToken{ QaId: questionQa.QaId, TokenId: tokenId, Sort: i + 1, } questionQaToken, err = questionQaTokenDao.AddQuestionQaToken(tx, questionQaToken) if err != nil { tx.Rollback() return false, err } } // 检测飞花令数量 if req.QaType == 1 { // 所需飞花令数量 = 题目总数 if tokenItemQuantity < qaQuantity { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", qaQuantity)) } } if req.QaType == 2 { // 所需飞花令数量 = TokenNum if tokenItemQuantity < *req.TokenNum { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", *req.TokenNum)) } } if req.QaType == 3 { //// 轮次 * 最大值 = 所需飞花令数量 //maxTokenQuestionQuantity := 0 //for _, content := range req.TokenQuestionContent { // if content.Quantity > maxTokenQuestionQuantity { // maxTokenQuestionQuantity = content.Quantity // } //} if tokenItemQuantity < *req.TokenNum { tx.Rollback() return false, errors.New("选择的飞花令的数量需大于:" + fmt.Sprintf("%d", *req.TokenNum)) } } } // 删除计时规则 questionQaTimerDao := dao.QuestionQaTimerDao{} err = questionQaTimerDao.DeleteQuestionQaTimerByQaId(tx, questionQa.QaId) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } // 新增计时规则 if req.IsTurnTimer == 1 { for _, timer := range req.QuestionQaTimer { QuestionQaTimer := &model.QuestionQaTimer{ QaId: questionQa.QaId, QuestionType: timer.QuestionType, TimerRule: timer.TimerRule, Duration: timer.Duration, } QuestionQaTimer, err := questionQaTimerDao.AddQuestionQaTimer(tx, QuestionQaTimer) if err != nil { tx.Rollback() return false, errors.New("修改失败") } } } tx.Commit() return true, nil } // PutQuestionQaPassword 修改题目题库密码 func (r *QuestionQaService) PutQuestionQaPassword(qaId int64, req requests.PutQuestionQaPassword) (bool, error) { questionQaDao := dao.QuestionQaDao{} questionQa, err := questionQaDao.GetQuestionQaById(qaId) if err != nil { return false, errors.New("题库不存在") } if questionQa.QaStatus == 2 { return false, errors.New("题库已失效") } // 分享密码 if req.QaPassword == questionQa.QaPassword { return true, nil } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() questionQaData := make(map[string]interface{}) questionQaData["qa_password"] = req.QaPassword err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } tx.Commit() return true, nil } // PutQuestionQaExpire 修改问答题库有效期 func (r *QuestionQaService) PutQuestionQaExpire(qaId int64, req requests.PutQuestionQaExpire) (bool, error) { questionQaDao := dao.QuestionQaDao{} questionQa, err := questionQaDao.GetQuestionQaById(qaId) if err != nil { return false, errors.New("题库不存在") } if questionQa.QaStatus == 2 { return false, errors.New("题库已失效") } // 验证过期时间 now := time.Now() // 获取本地时区 location, err := time.LoadLocation("Local") if err != nil { return false, errors.New("修改失败") } qaExpireTime, err := time.ParseInLocation("2006-01-02 15:04", req.QaExpireTime, location) if err != nil { return false, errors.New("过期时间错误") } if qaExpireTime.Before(now) { return false, errors.New("过期时间需大于当前时间") } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() questionQaData := make(map[string]interface{}) questionQaData["qa_expire_time"] = qaExpireTime err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } tx.Commit() return true, nil } // PutQuestionQaRule 修改问答题库规则解释 func (r *QuestionQaService) PutQuestionQaRule(qaId int64, req requests.PutQuestionQaRule) (bool, error) { questionQaDao := dao.QuestionQaDao{} questionQa, err := questionQaDao.GetQuestionQaById(qaId) if err != nil { return false, errors.New("题库不存在") } if questionQa.QaStatus == 2 { return false, errors.New("题库已失效") } // 分享密码 if req.QaRuleContent == questionQa.QaRuleContent { return true, nil } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() questionQaData := make(map[string]interface{}) questionQaData["qa_rule_content"] = req.QaRuleContent err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) if err != nil { tx.Rollback() return false, errors.New(err.Error()) } tx.Commit() return true, nil } // RecordQuestionQaOpenNum 记录问答题库打开次数 func (r *QuestionQaService) RecordQuestionQaOpenNum(tx *gorm.DB, qaId int64) error { questionQaDao := dao.QuestionQaDao{} err := questionQaDao.Inc(tx, qaId, "open_number", 1) if err != nil { return err } return nil } // CheckAddQaQuestionQuantity 检测题库题目数量-新增 func (r *QuestionQaService) CheckAddQaQuestionQuantity(req requests.AddQuestionQa) (qaQuantity int, err error) { // 题目总数量 qaQuantity = req.QaQuantity // 选择的明细总数量 += QuestionQaItem.Quantity itemQuantity := 0 for _, item := range req.QuestionQaItem { itemQuantity = itemQuantity + item.Quantity } // 常规模式 if req.QaType == 1 { // 总数量 需大于 选择的明细数量 if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } } // 固定套题模式 if req.QaType == 2 { // 计算飞花令题目数量 tokenQuestionQuantity := 0 for _, content := range req.TokenQuestionContent { tokenQuestionQuantity = tokenQuestionQuantity + content.Quantity } // 总数量 = 飞花令题目数量 * 飞花令数量 qaQuantity = tokenQuestionQuantity * *req.TokenNum if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } // 单个类型总数量 = 单一题目类型数量 * 飞花令数量 for _, content := range req.TokenQuestionContent { itemQuantity = 0 for _, item := range req.QuestionQaItem { if content.QuestionType == item.QuestionType { itemQuantity = itemQuantity + item.Quantity } } quantity := content.Quantity * *req.TokenNum if quantity > itemQuantity { return qaQuantity, errors.New(utils.QuestionType(content.QuestionType) + "数量不足") } } } // 多轮固定题型模式 if req.QaType == 3 { // 计算飞花令题目数量 tokenQuestionQuantity := 0 for _, content := range req.TokenQuestionContent { tokenQuestionQuantity = tokenQuestionQuantity + content.Quantity } // 总数量 = 飞花令题目数量 * 飞花令数量 * 轮次 qaQuantity = tokenQuestionQuantity * *req.TokenNum * *req.RoundNum if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } // 单个类型总数量 = 单一题目类型数量 * 飞花令数量 * 轮次 for _, content := range req.TokenQuestionContent { itemQuantity = 0 for _, item := range req.QuestionQaItem { if content.QuestionType == item.QuestionType { itemQuantity = itemQuantity + item.Quantity } } quantity := content.Quantity * *req.TokenNum * *req.RoundNum if quantity > itemQuantity { return qaQuantity, errors.New(utils.QuestionType(content.QuestionType) + "数量不足") } } } return qaQuantity, nil } // CheckPutQaQuestionQuantity 检测题库题目数量-修改 func (r *QuestionQaService) CheckPutQaQuestionQuantity(req requests.PutQuestionQa) (qaQuantity int, err error) { // 题目总数量 qaQuantity = req.QaQuantity // 选择的明细总数量 += QuestionQaItem.Quantity itemQuantity := 0 for _, item := range req.QuestionQaItem { itemQuantity = itemQuantity + item.Quantity } // 常规模式 if req.QaType == 1 { // 总数量 需大于 选择的明细数量 if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } } // 固定套题模式 if req.QaType == 2 { // 计算飞花令题目数量 tokenQuestionQuantity := 0 for _, content := range req.TokenQuestionContent { tokenQuestionQuantity = tokenQuestionQuantity + content.Quantity } // 总数量 = 飞花令题目数量 * 飞花令数量 qaQuantity = tokenQuestionQuantity * *req.TokenNum if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } // 单个类型总数量 = 单一题目类型数量 * 飞花令数量 for _, content := range req.TokenQuestionContent { itemQuantity = 0 for _, item := range req.QuestionQaItem { if content.QuestionType == item.QuestionType { itemQuantity = itemQuantity + item.Quantity } } quantity := content.Quantity * *req.TokenNum if quantity > itemQuantity { return qaQuantity, errors.New(utils.QuestionType(content.QuestionType) + "数量不足") } } } // 多轮固定题型模式 if req.QaType == 3 { // 计算飞花令题目数量 tokenQuestionQuantity := 0 for _, content := range req.TokenQuestionContent { tokenQuestionQuantity = tokenQuestionQuantity + content.Quantity } // 总数量 = 飞花令题目数量 * 飞花令数量 * 轮次 qaQuantity = tokenQuestionQuantity * *req.TokenNum * *req.RoundNum if qaQuantity > itemQuantity { return qaQuantity, errors.New("明细题目数量需超过题库所需题目总数量") } // 单个类型总数量 = 单一题目类型数量 * 飞花令数量 * 轮次 for _, content := range req.TokenQuestionContent { itemQuantity = 0 for _, item := range req.QuestionQaItem { if content.QuestionType == item.QuestionType { itemQuantity = itemQuantity + item.Quantity } } quantity := content.Quantity * *req.TokenNum * *req.RoundNum if quantity > itemQuantity { return qaQuantity, errors.New(utils.QuestionType(content.QuestionType) + "数量不足") } } } return qaQuantity, nil } // GetQuestionQaBaseTokenItemList 获取题库飞花令数据-列表 func (r *QuestionQaService) GetQuestionQaBaseTokenItemList(qaDisplayType int, qaId int64, quantity int) ([]*model.BaseTokenItem, error) { // 定义返回值 var g []*model.BaseTokenItem // 判断展示类型 if qaDisplayType != 2 { return g, nil } questionQaTokenDao := dao.QuestionQaTokenDao{} maps := make(map[string]interface{}) maps["qa_id"] = qaId questionQaToken, err := questionQaTokenDao.GetQuestionQaTokenPreloadList(maps) if err != nil { return g, errors.New("内部错误") } for _, v := range questionQaToken { // 处理返回值 for _, item := range v.BaseTokenItem { if len(g) < quantity { // 将转换后的结构体添加到新切片中 g = append(g, item) } } } return g, nil } // GetShareQuestionQaForTypeOne 获取题库数据-常规模式 func (r *QuestionQaService) GetShareQuestionQaForTypeOne(questionQa *model.QuestionQa) (*dto.ShareDto, error) { // 初始化返回值 g := &dto.ShareDto{} if questionQa.QaType != 1 { return g, errors.New("题库类型错误") } questionQaItemDao := dao.QuestionQaItemDao{} // 题目数据 var questions []*model.Question // 题目数据-必备选中 maps := make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 1 questionQaItems, err := questionQaItemDao.GetQuestionQaItemWhereList(maps) if err == nil && len(questionQaItems) > 0 { for _, item := range questionQaItems { questions = append(questions, item.Question) } } // 题目数据-剩余随机数量 remainingQuantity := questionQa.QaQuantity - len(questionQaItems) if remainingQuantity > 0 { // 随机获取剩余题目 maps = make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 0 questionQaItems, err = questionQaItemDao.GetQuestionQaItemWhereListRandLimit(maps, remainingQuantity) if err == nil && len(questionQaItems) > 0 { for _, item := range questionQaItems { questions = append(questions, item.Question) } } } for _, v := range questions { // 处理返回值 questionDto := dto.GetShareQuestionDto(v) // 加载选项 questionDto.LoadQuestionOptionSimplify(v.QuestionOption) // 加载图片 questionDto.LoadQuestionImage(v.QuestionImage) // 加载答案 questionDto.LoadQuestionAnswer(v) // 将转换后的结构体添加到新切片中 g.Question = append(g.Question, questionDto) } // 按照难度重新排序题目顺序 //sort.SliceStable(g.Question, func(i, j int) bool { // return g.Question[i].Difficulty < g.Question[j].Difficulty //}) // 获取题库飞花令数据 baseTokenItems, err := r.GetQuestionQaBaseTokenItemList(questionQa.QaDisplayType, questionQa.QaId, questionQa.QaQuantity) if err != nil { return g, errors.New(err.Error()) } g.BaseTokenItem = dto.GetBaseTokenItemListDto(baseTokenItems) return g, nil } // GetShareQuestionQaForTypeTwo 获取题库数据-固定套题模式 func (r *QuestionQaService) GetShareQuestionQaForTypeTwo(questionQa *model.QuestionQa) (*dto.ShareDtoForTwo, error) { // 初始化返回值 g := &dto.ShareDtoForTwo{} if questionQa.QaType != 2 { return g, errors.New("题库类型错误") } questionQaItemDao := dao.QuestionQaItemDao{} // 题目数据-必备选中 maps := make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 1 mustQuestions, err := questionQaItemDao.GetQuestionQaItemWhereList(maps) // 题目数据-未比被选中 maps = make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 0 notMustQuestions, err := questionQaItemDao.GetQuestionQaItemWhereListRand(maps) // json转结构体-飞花令题目数量规则 var tokenQuestionContents []tokenQuestionContent err = json.Unmarshal([]byte(questionQa.TokenQuestionContent), &tokenQuestionContents) if err != nil { return g, errors.New(err.Error()) } // 获取题库飞花令数据-列表 baseTokenItems, err := r.GetQuestionQaBaseTokenItemList(questionQa.QaDisplayType, questionQa.QaId, *questionQa.TokenNum) if err != nil { return g, errors.New(err.Error()) } g.BaseTokenItem = dto.GetBaseTokenItemListDto(baseTokenItems) // 已被使用id集合 var isUseQuestionId []int64 // 飞花令数量 for i := 0; i < *questionQa.TokenNum; i++ { // 题目数据 var tokenQuestions []*model.Question // 套题规则 [{"question_type":1,"quantity":10},{"question_type":2,"quantity":0},{"question_type":3,"quantity":0},{"question_type":4,"quantity":0}] for _, v2 := range tokenQuestionContents { var questions []*model.Question // 必选数据 for _, v3 := range mustQuestions { // 判断此题目是否已被选中 if utils.IsInSlice(v3.QuestionId, isUseQuestionId) { continue } // 类型相同,加入该组数据中 if v2.QuestionType == v3.Question.QuestionType { // 当数量超出时,跳出 if len(questions) >= v2.Quantity { continue } questions = append(questions, v3.Question) // 标记已被使用 isUseQuestionId = append(isUseQuestionId, v3.QuestionId) } } // 题目数据-剩余随机数量 remainingQuantity := v2.Quantity - len(questions) if remainingQuantity > 0 { // 非必选数据 for _, v3 := range notMustQuestions { // 判断此题目是否已被选中 if utils.IsInSlice(v3.QuestionId, isUseQuestionId) { continue } // 类型相同,加入该组数据中 if v2.QuestionType == v3.Question.QuestionType { // 当数量超出时,跳出 if len(questions) >= v2.Quantity { continue } questions = append(questions, v3.Question) // 标记已被使用 isUseQuestionId = append(isUseQuestionId, v3.QuestionId) } } } if len(questions) > 0 { for _, v3 := range questions { tokenQuestions = append(tokenQuestions, v3) } } } // 处理返回值 questionDtoList := make([]*dto.QuestionDto, len(tokenQuestions)) // 处理数据 for i2, v2 := range tokenQuestions { // 处理返回值 questionDto := dto.GetShareQuestionDto(v2) // 加载选项 questionDto.LoadQuestionOptionSimplify(v2.QuestionOption) // 加载图片 questionDto.LoadQuestionImage(v2.QuestionImage) // 加载答案 questionDto.LoadQuestionAnswer(v2) questionDtoList[i2] = questionDto } g.Question = append(g.Question, questionDtoList) } return g, nil } // GetShareQuestionQaForTypeThree 获取题库数据-多轮固定题型模式 func (r *QuestionQaService) GetShareQuestionQaForTypeThree(questionQa *model.QuestionQa) ([]*dto.ShareDtoForThree, error) { // 初始化返回值 var g []*dto.ShareDtoForThree if questionQa.QaType != 3 { return g, errors.New("题库类型错误") } questionQaItemDao := dao.QuestionQaItemDao{} // 题目数据-必备选中 maps := make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 1 mustQuestions, err := questionQaItemDao.GetQuestionQaItemWhereList(maps) // 题目数据-未比被选中 maps = make(map[string]interface{}) maps["qa_id"] = questionQa.QaId maps["is_must_select"] = 0 notMustQuestions, err := questionQaItemDao.GetQuestionQaItemWhereListRand(maps) // json转结构体-飞花令题目数量规则 var tokenQuestionContents []tokenQuestionContent err = json.Unmarshal([]byte(questionQa.TokenQuestionContent), &tokenQuestionContents) if err != nil { return g, errors.New(err.Error()) } // 获取题库飞花令数据-列表 maxTokenQuestionQuantity := 0 for _, content := range tokenQuestionContents { if content.Quantity > maxTokenQuestionQuantity { maxTokenQuestionQuantity = content.Quantity } } baseTokenItemQuantity := maxTokenQuestionQuantity * *questionQa.TokenNum baseTokenItems, err := r.GetQuestionQaBaseTokenItemList(questionQa.QaDisplayType, questionQa.QaId, baseTokenItemQuantity) if err != nil { return g, errors.New(err.Error()) } // 已被使用id集合 var isUseQuestionId []int64 for i := 0; i < *questionQa.RoundNum; i++ { // 单轮次返回值 shareDtoForThree := &dto.ShareDtoForThree{ Single: nil, Multiple: nil, Judge: nil, Qa: nil, } // 套题规则 [{"question_type":1,"quantity":10},{"question_type":2,"quantity":0},{"question_type":3,"quantity":0},{"question_type":4,"quantity":0}] for _, v2 := range tokenQuestionContents { if v2.Quantity == 0 { continue } shareDtoForTwo := &dto.ShareDtoForTwo{} // 处理对应飞花令数据 for _, item := range baseTokenItems { if len(shareDtoForTwo.BaseTokenItem) < *questionQa.TokenNum { questionDto := dto.GetBaseTokenItemDto(item) shareDtoForTwo.BaseTokenItem = append(shareDtoForTwo.BaseTokenItem, questionDto) } } // 飞花令数量 for i3 := 0; i3 < *questionQa.TokenNum; i3++ { // 题目数据 var questions []*model.Question // 必选数据 for _, v3 := range mustQuestions { // 判断此题目是否已被选中 if utils.IsInSlice(v3.QuestionId, isUseQuestionId) { continue } // 类型相同,加入该组数据中 if v2.QuestionType == v3.Question.QuestionType { // 当数量超出时,跳出 if len(questions) >= v2.Quantity { continue } questions = append(questions, v3.Question) // 标记已被使用 isUseQuestionId = append(isUseQuestionId, v3.QuestionId) } } // 题目数据-剩余随机数量 remainingQuantity := v2.Quantity - len(questions) if remainingQuantity > 0 { // 非必选数据 for _, v3 := range notMustQuestions { // 判断此题目是否已被选中 if utils.IsInSlice(v3.QuestionId, isUseQuestionId) { continue } // 类型相同,加入该组数据中 if v2.QuestionType == v3.Question.QuestionType { // 当数量超出时,跳出 if len(questions) >= v2.Quantity { continue } questions = append(questions, v3.Question) // 标记已被使用 isUseQuestionId = append(isUseQuestionId, v3.QuestionId) } } } // 处理返回值 var questionDtoList []*dto.QuestionDto // 处理数据 for _, v3 := range questions { // 处理返回值 questionDto := dto.GetShareQuestionDto(v3) // 加载选项 questionDto.LoadQuestionOptionSimplify(v3.QuestionOption) // 加载图片 questionDto.LoadQuestionImage(v3.QuestionImage) // 加载答案 questionDto.LoadQuestionAnswer(v3) questionDtoList = append(questionDtoList, questionDto) } shareDtoForTwo.Question = append(shareDtoForTwo.Question, questionDtoList) } // 填入对应类别 if v2.QuestionType == 1 { shareDtoForThree.Single = shareDtoForTwo } else if v2.QuestionType == 2 { shareDtoForThree.Multiple = shareDtoForTwo } else if v2.QuestionType == 4 { shareDtoForThree.Judge = shareDtoForTwo } else if v2.QuestionType == 3 { shareDtoForThree.Qa = shareDtoForTwo } else { return g, errors.New("内部错误") } } // 添加如总数据 g = append(g, shareDtoForThree) } return g, nil } // CheckQuestionQaItemRepeat 检测题目明细重复 func (r *QuestionQaService) CheckQuestionQaItemRepeat(items []*requests.QuestionQaItem, newItem *requests.QuestionQaItem) bool { for _, item := range items { // 检查必填项 if item.QuestionType == newItem.QuestionType && item.FirstLabelId == newItem.FirstLabelId { // 如果所有字段相同(包括选填项),不能添加 if item.SecondLabelId == newItem.SecondLabelId && ((item.Difficulty == nil && newItem.Difficulty == nil) || (item.Difficulty != nil && newItem.Difficulty != nil && *item.Difficulty == *newItem.Difficulty)) { return false } // 如果新增项选填项为空,但已有项选填项不为空,则冲突 if newItem.SecondLabelId == "" && item.SecondLabelId != "" { return false } // 如果新增项选填项不为空,但已有项选填项为空,则冲突 if newItem.SecondLabelId != "" && item.SecondLabelId == "" { return false } // 如果新增项选填项为空,但已有项选填项不为空,则冲突 if newItem.Difficulty == nil && item.Difficulty != nil { return false } // 如果新增项选填项不为空,但已有项选填项为空,则冲突 if newItem.Difficulty != nil && item.Difficulty == nil { return false } } } return true } // CheckQuestionRelationQaQuantitySub 检测题目关联的题库数量是否充足-减去对应数量后 func (r *QuestionQaService) CheckQuestionRelationQaQuantitySub(questionId int64, num int) (bool, error) { // 获取关联题库id questionQaItemDao := dao.QuestionQaItemDao{} questionQaItems, err := questionQaItemDao.GetQuestionQaItemListByQuestionIdDistinctQaId(questionId) if err != nil { return false, err } questionQaDao := dao.QuestionQaDao{} for _, item := range questionQaItems { // 获取题库数据 questionQa, err := questionQaDao.GetQuestionQaById(item.QaId) if err != nil { return false, err } // 获取明细数据 questionQaItems, err = questionQaItemDao.GetQuestionQaItemListByQaId(item.QaId) if err != nil { return false, err } if (len(questionQaItems) - num) < questionQa.QaQuantity { return false, errors.New("操作后会导致关联题库:" + questionQa.QaName + " 题目数量不足") } } return true, nil }