diff --git a/api/controller/base.go b/api/controller/base.go index eedaa8f..be8f066 100644 --- a/api/controller/base.go +++ b/api/controller/base.go @@ -3,8 +3,12 @@ package controller // Api api接口 type Api struct { Migrate - Public // 公共方法-不验证权限 - AdminUser // 后台用户 - Question // 题目 - QuestionQa // 问答题库 + Public // 公共方法-不验证权限 + AdminUser // 后台用户 + Question // 题目 + QuestionQa // 问答题库 + QuestionQaItem // 问答题库明细 + Label // 标签 + Static // 统计 + Share // 分享 } diff --git a/api/controller/label.go b/api/controller/label.go new file mode 100644 index 0000000..315cfbe --- /dev/null +++ b/api/controller/label.go @@ -0,0 +1,112 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "knowledge/api/dao" + "knowledge/api/dto" + "knowledge/api/requests" + "knowledge/api/responses" + "knowledge/api/service" + "knowledge/global" + "knowledge/utils" + "strconv" +) + +type Label struct{} + +// GetLabelList 获取标签列表 +func (r *Label) GetLabelList(c *gin.Context) { + labelRequest := requests.LabelRequest{} + req := labelRequest.GetLabelList + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + labelDao := dao.LabelDao{} + label, err := labelDao.GetLabelListSearch(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + GetLabelListResponses := dto.GetLabelListDto(label) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(GetLabelListResponses, c) +} + +// AddLabel 新增标签 +func (r *Label) AddLabel(c *gin.Context) { + labelRequest := requests.LabelRequest{} + req := labelRequest.AddLabel + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 业务处理 + labelService := service.LabelService{} + _, err := labelService.AddLabel(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} + +// PutLabel 修改标签 +func (r *Label) PutLabel(c *gin.Context) { + labelRequest := requests.LabelRequest{} + req := labelRequest.PutLabel + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + id := c.Param("label_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + labelId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + labelService := service.LabelService{} + _, err = labelService.PutLabel(labelId, req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} diff --git a/api/controller/question.go b/api/controller/question.go index d7b5449..5d14f96 100644 --- a/api/controller/question.go +++ b/api/controller/question.go @@ -59,6 +59,32 @@ func (r *Question) GetQuestionPage(c *gin.Context) { responses.OkWithData(result, c) } +// GetQuestion 获取题目详情 +func (r *Question) GetQuestion(c *gin.Context) { + id := c.Param("question_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + questionId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + questionService := service.QuestionService{} + getQuestionResponses, err := questionService.GetQuestion(questionId) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(getQuestionResponses, c) +} + // AddQuestion 新增题目 func (r *Question) AddQuestion(c *gin.Context) { questionRequest := requests.QuestionRequest{} @@ -191,8 +217,8 @@ func (r *Question) PutQuestionTest(c *gin.Context) { // DeleteQuestion 删除题目 func (r *Question) DeleteQuestion(c *gin.Context) { - couponRequest := requests.QuestionRequest{} - req := couponRequest.DeleteQuestion + questionRequest := requests.QuestionRequest{} + req := questionRequest.DeleteQuestion if err := c.ShouldBindJSON(&req); err != nil { responses.FailWithMessage(err.Error(), c) return @@ -214,3 +240,28 @@ func (r *Question) DeleteQuestion(c *gin.Context) { responses.Ok(c) } + +// GetQuestionCount 获取题目数量 +func (r *Question) GetQuestionCount(c *gin.Context) { + questionRequest := requests.QuestionRequest{} + req := questionRequest.GetQuestionCount + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + questionDao := dao.QuestionDao{} + total, err := questionDao.GetQuestionCountSearch(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(total, c) +} diff --git a/api/controller/questionQa.go b/api/controller/questionQa.go index 24842ec..9e51798 100644 --- a/api/controller/questionQa.go +++ b/api/controller/questionQa.go @@ -94,7 +94,7 @@ func (r *QuestionQa) AddQuestionQa(c *gin.Context) { } // PutQuestionQa 修改问答题库 -func (r *Question) PutQuestionQa(c *gin.Context) { +func (r *QuestionQa) PutQuestionQa(c *gin.Context) { questionQaRequest := requests.QuestionQaRequest{} req := questionQaRequest.PutQuestionQa if err := c.ShouldBindJSON(&req); err != nil { @@ -141,7 +141,7 @@ func (r *Question) PutQuestionQa(c *gin.Context) { } // PutQuestionQaPassword 修改问答题库密码 -func (r *Question) PutQuestionQaPassword(c *gin.Context) { +func (r *QuestionQa) PutQuestionQaPassword(c *gin.Context) { questionQaRequest := requests.QuestionQaRequest{} req := questionQaRequest.PutQuestionQaPassword if err := c.ShouldBindJSON(&req); err != nil { @@ -180,7 +180,7 @@ func (r *Question) PutQuestionQaPassword(c *gin.Context) { } // PutQuestionQaExpire 修改问答题库有效期 -func (r *Question) PutQuestionQaExpire(c *gin.Context) { +func (r *QuestionQa) PutQuestionQaExpire(c *gin.Context) { questionQaRequest := requests.QuestionQaRequest{} req := questionQaRequest.PutQuestionQaExpire if err := c.ShouldBindJSON(&req); err != nil { @@ -217,3 +217,68 @@ func (r *Question) PutQuestionQaExpire(c *gin.Context) { responses.Ok(c) } + +// PutQuestionQaRule 修改问答题库规则解释 +func (r *QuestionQa) PutQuestionQaRule(c *gin.Context) { + questionQaRequest := requests.QuestionQaRequest{} + req := questionQaRequest.PutQuestionQaRule + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + id := c.Param("qa_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + qaId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + questionQaService := service.QuestionQaService{} + _, err = questionQaService.PutQuestionQaRule(qaId, req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} + +// GetQuestionQa 获取问答题库详情 +func (r *QuestionQa) GetQuestionQa(c *gin.Context) { + id := c.Param("qa_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + qaId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + questionQaService := service.QuestionQaService{} + getQuestionQaResponses, err := questionQaService.GetQuestionQa(qaId) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(getQuestionQaResponses, c) +} diff --git a/api/controller/questionQaItem.go b/api/controller/questionQaItem.go new file mode 100644 index 0000000..222b7ff --- /dev/null +++ b/api/controller/questionQaItem.go @@ -0,0 +1,125 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "knowledge/api/dao" + "knowledge/api/dto" + "knowledge/api/requests" + "knowledge/api/responses" + "knowledge/api/service" + "knowledge/global" + "knowledge/utils" + "strconv" +) + +type QuestionQaItem struct{} + +// GetQuestionQaItemPage 获取问答题库明细列表-分页 +func (r *QuestionQaItem) GetQuestionQaItemPage(c *gin.Context) { + questionQaItemRequest := requests.QuestionQaItemRequest{} + req := questionQaItemRequest.GetQuestionQaItemPage + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + questionQaItemDao := dao.QuestionQaItemDao{} + questionQaItem, total, err := questionQaItemDao.GetQuestionQaItemPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + questionQaItemPageResponses := dto.GetQuestionQaItemListDto(questionQaItem) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = questionQaItemPageResponses + responses.OkWithData(result, c) +} + +// DeleteQuestionQaItem 删除问答题库明细 +func (r *QuestionQaItem) DeleteQuestionQaItem(c *gin.Context) { + questionQaItemRequest := requests.QuestionQaItemRequest{} + req := questionQaItemRequest.DeleteQuestionQaItem + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 业务处理 + questionQaItemService := service.QuestionQaItemService{} + _, err := questionQaItemService.DeleteQuestionQaItem(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} + +// PutQuestionQaItemMust 修改必选 +func (r *QuestionQaItem) PutQuestionQaItemMust(c *gin.Context) { + questionQaItemRequest := requests.QuestionQaItemRequest{} + req := questionQaItemRequest.PutQuestionQaItemMust + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + id := c.Param("item_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + itemId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 业务处理 + questionQaItemService := service.QuestionQaItemService{} + _, err = questionQaItemService.PutQuestionQaItemMust(itemId, req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} diff --git a/api/controller/share.go b/api/controller/share.go new file mode 100644 index 0000000..691daa8 --- /dev/null +++ b/api/controller/share.go @@ -0,0 +1,38 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "knowledge/api/requests" + "knowledge/api/responses" + "knowledge/api/service" + "knowledge/global" + "knowledge/utils" +) + +type Share struct{} + +// GetShare 获取分享数据 +func (r *Share) GetShare(c *gin.Context) { + shareRequest := requests.ShareRequest{} + req := shareRequest.GetShare + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 业务处理 + shareService := service.ShareService{} + getShareResponses, err := shareService.GetShare(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(getShareResponses, c) +} diff --git a/api/controller/static.go b/api/controller/static.go new file mode 100644 index 0000000..100585b --- /dev/null +++ b/api/controller/static.go @@ -0,0 +1,22 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "knowledge/api/responses" + "knowledge/api/service" +) + +type Static struct{} + +// GetStatic 获取统计数据 +func (r *Static) GetStatic(c *gin.Context) { + // 业务处理 + staticService := service.StaticService{} + getStaticResponses, err := staticService.GetStatic() + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(getStaticResponses, c) +} diff --git a/api/dao/Label.go b/api/dao/Label.go index a237a2f..c2684da 100644 --- a/api/dao/Label.go +++ b/api/dao/Label.go @@ -3,6 +3,7 @@ package dao import ( "gorm.io/gorm" "knowledge/api/model" + "knowledge/api/requests" "knowledge/global" ) @@ -63,6 +64,17 @@ func (r *LabelDao) GetLabelList(maps interface{}) (m []*model.Label, err error) return m, nil } +// GetLabelCount 获取数量 +func (r *LabelDao) GetLabelCount(maps interface{}) (total int64, err error) { + var totalRecords int64 + err = global.Db.Model(&model.Label{}).Where(maps).Count(&totalRecords).Error + + if err != nil { + return 0, err + } + return totalRecords, nil +} + // AddLabel 新增 func (r *LabelDao) AddLabel(tx *gorm.DB, model *model.Label) (*model.Label, error) { if err := tx.Create(model).Error; err != nil { @@ -79,3 +91,38 @@ func (r *LabelDao) GetLabel(maps interface{}) (m *model.Label, err error) { } return m, nil } + +// GetLabelListSearch 获取列表 +func (r *LabelDao) GetLabelListSearch(req requests.GetLabelList) (m []*model.Label, err error) { + // 构建查询条件 + query := global.Db.Model(&model.Label{}) + + // 主键id + if req.LabelId != "" { + query = query.Where("label_id = ?", req.LabelId) + } + + // 标签名称 + if req.LabelName != "" { + query = query.Where("label_name LIKE ?", "%"+req.LabelName+"%") + } + + // 父级ID + if req.ParentId != "" { + query = query.Where("parent_id = ?", req.ParentId) + } + + // 级别 + if req.LabelLevel != nil { + query = query.Where("label_level = ?", req.LabelLevel) + } + + // 排序 + query = query.Order("created_at desc") + + err = query.Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} diff --git a/api/dao/Question.go b/api/dao/Question.go index ce65ea7..544dd64 100644 --- a/api/dao/Question.go +++ b/api/dao/Question.go @@ -3,6 +3,7 @@ package dao import ( "errors" "gorm.io/gorm" + "gorm.io/gorm/clause" "knowledge/api/model" "knowledge/api/requests" "knowledge/global" @@ -22,6 +23,15 @@ func (r *QuestionDao) GetQuestionById(questionId int64) (m *model.Question, err return m, nil } +// GetQuestionPreloadById 获取数据-加载全部关联-id +func (r *QuestionDao) GetQuestionPreloadById(questionId int64) (m *model.Question, err error) { + err = global.Db.Preload(clause.Associations).First(&m, questionId).Error + if err != nil { + return nil, err + } + return m, nil +} + // DeleteQuestion 删除 func (r *QuestionDao) DeleteQuestion(tx *gorm.DB, maps interface{}) error { err := tx.Where(maps).Delete(&model.Question{}).Error @@ -77,7 +87,7 @@ func (r *QuestionDao) GetQuestionCount(maps interface{}) (total int64, err error // GetQuestionListRand 获取列表-随机 func (r *QuestionDao) GetQuestionListRand(maps interface{}, limit int) (m []*model.Question, err error) { - err = global.Db.Where(maps).Find(&m).Order(gorm.Expr("RAND()")).Limit(limit).Error + err = global.Db.Where(maps).Order("rand()").Limit(limit).Find(&m).Error if err != nil { return nil, err } @@ -205,3 +215,49 @@ func (r *QuestionDao) GetQuestionPageSearch(req requests.GetQuestionPage, page, } return m, totalRecords, nil } + +// GetQuestionCountSearch 获取题目数量 +func (r *QuestionDao) GetQuestionCountSearch(req requests.GetQuestionCount) (total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.Question{}) + + // 题目类型 + query = query.Where("question_type = ?", req.QuestionType) + + // 状态 + if req.QuestionStatus != nil { + query = query.Where("question_status = ?", req.QuestionStatus) + } + + // 难度 + if req.Difficulty != nil { + query = query.Where("difficulty = ?", req.Difficulty) + } + + // 题目来源 + if req.QuestionSource != nil { + query = query.Where("question_source = ?", req.QuestionSource) + } + + // 一级标签id + if req.FirstLabelId != nil { + query = query.Where("first_label_id = ?", req.FirstLabelId) + } + + // 二级标签id + if req.SecondLabelId != nil { + query = query.Where("second_label_id = ?", req.SecondLabelId) + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return 0, err + } + + return totalRecords, nil +} diff --git a/api/dao/QuestionQaItem.go b/api/dao/QuestionQaItem.go index 8ec57ff..12aea3f 100644 --- a/api/dao/QuestionQaItem.go +++ b/api/dao/QuestionQaItem.go @@ -1,8 +1,10 @@ package dao import ( + "errors" "gorm.io/gorm" "knowledge/api/model" + "knowledge/api/requests" "knowledge/global" ) @@ -10,8 +12,17 @@ type QuestionQaItemDao struct { } // GetQuestionQaItemById 获取数据-id -func (r *QuestionQaItemDao) GetQuestionQaItemById(qaId int64) (m *model.QuestionQaItem, err error) { - err = global.Db.First(&m, qaId).Error +func (r *QuestionQaItemDao) GetQuestionQaItemById(itemId int64) (m *model.QuestionQaItem, err error) { + err = global.Db.First(&m, itemId).Error + if err != nil { + return nil, err + } + return m, nil +} + +// GetQuestionQaItemListByQaId 获取数据-QaId +func (r *QuestionQaItemDao) GetQuestionQaItemListByQaId(qaId int64) (m []*model.QuestionQaItem, err error) { + err = global.Db.Where("qa_id = ?", qaId).Find(&m).Error if err != nil { return nil, err } @@ -27,6 +38,14 @@ func (r *QuestionQaItemDao) DeleteQuestionQaItem(tx *gorm.DB, maps interface{}) return nil } +// DeleteQuestionQaItemById 删除-Id +func (r *QuestionQaItemDao) DeleteQuestionQaItemById(tx *gorm.DB, itemId int64) error { + if err := tx.Delete(&model.QuestionQaItem{}, itemId).Error; err != nil { + return err + } + return nil +} + // DeleteQuestionQaItemByQaId 删除-QaId func (r *QuestionQaItemDao) DeleteQuestionQaItemByQaId(tx *gorm.DB, qaId int64) error { if err := tx.Where("qa_id = ?", qaId).Delete(&model.QuestionQaItem{}).Error; err != nil { @@ -44,6 +63,15 @@ func (r *QuestionQaItemDao) EditQuestionQaItem(tx *gorm.DB, maps interface{}, da return nil } +// EditQuestionQaItemById 修改-id +func (r *QuestionQaItemDao) EditQuestionQaItemById(tx *gorm.DB, itemId int64, data interface{}) error { + err := tx.Model(&model.QuestionQaItem{}).Where("item_id = ?", itemId).Updates(data).Error + if err != nil { + return err + } + return nil +} + // GetQuestionQaItemList 获取列表 func (r *QuestionQaItemDao) GetQuestionQaItemList(maps interface{}) (m []*model.QuestionQaItem, err error) { err = global.Db.Where(maps).Find(&m).Error @@ -53,6 +81,15 @@ func (r *QuestionQaItemDao) GetQuestionQaItemList(maps interface{}) (m []*model. return m, nil } +// GetQuestionQaItemListRand 获取列表-随机 +func (r *QuestionQaItemDao) GetQuestionQaItemListRand(maps interface{}, limit int) (m []*model.QuestionQaItem, err error) { + err = global.Db.Where(maps).Limit(limit).Order("rand()").Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + // AddQuestionQaItem 新增 func (r *QuestionQaItemDao) AddQuestionQaItem(tx *gorm.DB, model *model.QuestionQaItem) (*model.QuestionQaItem, error) { if err := tx.Create(model).Error; err != nil { @@ -69,3 +106,118 @@ func (r *QuestionQaItemDao) GetQuestionQaItem(maps interface{}) (m *model.Questi } return m, nil } + +// GetQuestionQaItemPageSearch 获取列表-分页 +func (r *QuestionQaItemDao) GetQuestionQaItemPageSearch(req requests.GetQuestionQaItemPage, page, pageSize int) (m []*model.QuestionQaItem, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.QuestionQaItem{}) + + // 题目表 + query = query.Preload("Question", func(db *gorm.DB) *gorm.DB { + return db.Select("question_id", "question_name", "question_type", "question_source", "difficulty", "first_label_id", "second_label_id") + }) + + // 一级标签 + query = query.Preload("Question.FirstLabel", func(db *gorm.DB) *gorm.DB { + return db.Select("label_id", "label_name") + }) + + // 二级标签 + query = query.Preload("Question.SecondLabel", func(db *gorm.DB) *gorm.DB { + return db.Select("label_id", "label_name") + }) + + // 题库id + query = query.Where("qa_id = ?", req.QaId) + + // 题目id + if req.QuestionId != "" { + query = query.Where("question_id = ?", req.QuestionId) + } + + // 是否必被选中 + if req.IsMustSelect != nil { + query = query.Where("is_must_select = ?", req.IsMustSelect) + } + + // 题目名称 + if req.QuestionName != "" { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("question_name LIKE ?", "%"+req.QuestionName+"%") + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 题目类型 + if req.QuestionType != nil { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("question_type = ?", req.QuestionType) + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 题目来源 + if req.QuestionSource != nil { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("question_source = ?", req.QuestionSource) + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 难度 + if req.Difficulty != nil { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("difficulty = ?", req.Difficulty) + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 一级标签id + if req.FirstLabelId != nil { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("first_label_id = ?", req.FirstLabelId) + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 二级标签id + if req.SecondLabelId != nil { + subQuery := global.Db.Model(&model.Question{}). + Select("question_id"). + Where("second_label_id = ?", req.SecondLabelId) + + query = query.Where(gorm.Expr("question_id IN (?)", subQuery)) + } + + // 排序 + if req.Order != nil { + if req.Order.UpdatedAt != "" { + if req.Order.UpdatedAt != "desc" && req.Order.UpdatedAt != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("updated_at " + req.Order.UpdatedAt) + } + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} diff --git a/api/dto/Question.go b/api/dto/Question.go index aa99429..7f9493d 100644 --- a/api/dto/Question.go +++ b/api/dto/Question.go @@ -3,30 +3,44 @@ package dto import ( "fmt" "knowledge/api/model" + "knowledge/utils" + "strings" ) // QuestionDto 题目表(单选-多选-问答-判断) type QuestionDto struct { - QuestionId string `json:"question_id"` // 主键id - QuestionName string `json:"question_name"` // 题目名称 - QuestionType int `json:"question_type"` // 题目类型(1:单选 2:多选 3:问答 4:判断) - QuestionStatus int `json:"question_status"` // 状态(1:正常 2:禁用) - IsDelete int `json:"is_delete"` // 是否删除(0:否 1:是) - QuestionSource int `json:"question_source"` // 题目来源(1:本题库 2:外部数据) - QuestionImage []string `json:"question_image"` // 题目图片(逗号分隔) - QuestionAnswer string `json:"question_answer"` // 答案 - QuestionAnalysis string `json:"question_analysis"` // 解析 - Difficulty int `json:"difficulty"` // 难度(0:未知 1:低 2:中 3:高) - FirstLabelId string `json:"first_label_id"` // 一级标签id - SecondLabelId string `json:"second_label_id"` // 二级标签id - CreatedAt model.LocalTime `json:"created_at"` // 创建时间 - UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 - FirstLabel *LabelDto `json:"first_label"` // 一级标签 - SecondLabel *LabelDto `json:"second_label"` // 二级标签 + QuestionId string `json:"question_id"` // 主键id + QuestionName string `json:"question_name"` // 题目名称 + QuestionType int `json:"question_type"` // 题目类型(1:单选 2:多选 3:问答 4:判断) + QuestionStatus int `json:"question_status"` // 状态(1:正常 2:禁用) + IsDelete int `json:"is_delete"` // 是否删除(0:否 1:是) + QuestionSource int `json:"question_source"` // 题目来源(1:本题库 2:外部数据) + QuestionImage []string `json:"question_image"` // 题目图片(逗号分隔) + QuestionAnswer string `json:"question_answer"` // 答案 + QuestionAnalysis string `json:"question_analysis"` // 解析 + Difficulty int `json:"difficulty"` // 难度(0:未知 1:低 2:中 3:高) + FirstLabelId string `json:"first_label_id"` // 一级标签id + SecondLabelId string `json:"second_label_id"` // 二级标签id + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + FirstLabel *LabelDto `json:"first_label"` // 一级标签 + SecondLabel *LabelDto `json:"second_label"` // 二级标签 + QuestionOption []*QuestionOptionDto `json:"question_option"` // 选项 } // GetQuestionDto 题目详情 func GetQuestionDto(m *model.Question) *QuestionDto { + var questionImage []string + if m.QuestionImage != "" { + result := strings.Split(m.QuestionImage, ",") + if len(result) > 0 { + for _, v := range result { + v = utils.AddOssDomain(v) + questionImage = append(questionImage, v) + } + } + } + return &QuestionDto{ QuestionId: fmt.Sprintf("%d", m.QuestionId), QuestionName: m.QuestionName, @@ -34,6 +48,7 @@ func GetQuestionDto(m *model.Question) *QuestionDto { QuestionStatus: m.QuestionStatus, IsDelete: m.IsDelete, QuestionSource: m.QuestionSource, + QuestionImage: questionImage, QuestionAnswer: m.QuestionAnswer, QuestionAnalysis: m.QuestionAnalysis, Difficulty: m.Difficulty, @@ -51,6 +66,17 @@ func GetQuestionListDto(m []*model.Question) []*QuestionDto { if len(m) > 0 { for i, v := range m { + var questionImage []string + if v.QuestionImage != "" { + result := strings.Split(v.QuestionImage, ",") + if len(result) > 0 { + for _, v := range result { + v = utils.AddOssDomain(v) + questionImage = append(questionImage, v) + } + } + } + response := &QuestionDto{ QuestionId: fmt.Sprintf("%d", v.QuestionId), QuestionName: v.QuestionName, @@ -58,6 +84,7 @@ func GetQuestionListDto(m []*model.Question) []*QuestionDto { QuestionStatus: v.QuestionStatus, IsDelete: v.IsDelete, QuestionSource: v.QuestionSource, + QuestionImage: questionImage, QuestionAnswer: v.QuestionAnswer, QuestionAnalysis: v.QuestionAnalysis, Difficulty: v.Difficulty, @@ -100,3 +127,11 @@ func (r *QuestionDto) LoadSecondLabel(m *model.Label) *QuestionDto { } return r } + +// LoadQuestionOption 加载选项 +func (r *QuestionDto) LoadQuestionOption(m []*model.QuestionOption) *QuestionDto { + if len(m) > 0 { + r.QuestionOption = GetQuestionOptionListDto(m) + } + return r +} diff --git a/api/dto/QuestionOption.go b/api/dto/QuestionOption.go new file mode 100644 index 0000000..287f6a9 --- /dev/null +++ b/api/dto/QuestionOption.go @@ -0,0 +1,51 @@ +package dto + +import ( + "fmt" + "knowledge/api/model" +) + +// QuestionOptionDto 题目选项表 +type QuestionOptionDto struct { + OptionId string `json:"option_id"` // 主键id + QuestionId string `json:"question_id"` // 题目id + OptionValue string `json:"option_value"` // 选项内容 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + +} + +// GetQuestionOptionDto 题目选项详情 +func GetQuestionOptionDto(m *model.QuestionOption) *QuestionOptionDto { + + return &QuestionOptionDto{ + OptionId: fmt.Sprintf("%d", m.OptionId), + QuestionId: fmt.Sprintf("%d", m.QuestionId), + OptionValue: m.OptionValue, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetQuestionOptionListDto 题目选项列表 +func GetQuestionOptionListDto(m []*model.QuestionOption) []*QuestionOptionDto { + // 处理返回值 + responses := make([]*QuestionOptionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionOptionDto{ + OptionId: fmt.Sprintf("%d", v.OptionId), + QuestionId: fmt.Sprintf("%d", v.QuestionId), + OptionValue: v.OptionValue, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} diff --git a/api/dto/QuestionQa.go b/api/dto/QuestionQa.go index 2e51108..4435adc 100644 --- a/api/dto/QuestionQa.go +++ b/api/dto/QuestionQa.go @@ -1,25 +1,37 @@ package dto import ( + "encoding/json" "fmt" "knowledge/api/model" + "knowledge/utils" ) // QuestionQaDto 问答题库 type QuestionQaDto struct { - QaId string `json:"qa_id"` // 主键id - QaName string `json:"qa_name"` // 名称 - QaQuantity int `json:"qa_quantity"` // 题目数量 - QaStatus int `json:"qa_status"` // 状态(1:正常 2:无效) - QaRuleContent string `json:"qa_rule_content"` // 规则解释 - QaDisplayType int `json:"qa_display_type"` // 展示类型(1:常规 2:飞花令) - QaExpireTime model.LocalTime `json:"qa_expire_time"` // 过期时间 - QaLink string `json:"qa_link"` // 分享链接 - QaPassword string `json:"qa_password"` // 分享密码 - OpenNumber int `json:"open_number"` // 打开的次数 - Image string `json:"image"` // 背景图 - CreatedAt model.LocalTime `json:"created_at"` // 创建时间 - UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + QaId string `json:"qa_id"` // 主键id + QaName string `json:"qa_name"` // 名称 + QaQuantity int `json:"qa_quantity"` // 题目数量 + QaStatus int `json:"qa_status"` // 状态(1:正常 2:无效) + QaRuleContent string `json:"qa_rule_content"` // 规则解释 + QaDisplayType int `json:"qa_display_type"` // 展示类型(1:常规 2:飞花令) + QaExpireTime model.LocalTime `json:"qa_expire_time"` // 过期时间 + QaShareId string `json:"qa_share_id"` // 分享标识 + QaPassword string `json:"qa_password"` // 分享密码 + OpenNumber int `json:"open_number"` // 打开的次数 + Image string `json:"image"` // 背景图 + ItemContent []ItemContentDto `json:"item_content"` // 明细选题规则(json) + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 +} + +// ItemContentDto 问答题库-明细选题规则 +type ItemContentDto struct { + QuestionType int `json:"question_type"` // 题目类型(1:单选 2:多选 3:问答 4:判断) + FirstLabelId string `json:"first_label_id"` // 一级标签id + SecondLabelId string `json:"second_label_id"` // 二级标签id + Difficulty int `json:"difficulty"` // 难度(0:未知 1:低 2:中 3:高) + Quantity int `json:"quantity"` // 数量 } // GetQuestionQaListDto 问答题库列表 @@ -37,7 +49,8 @@ func GetQuestionQaListDto(m []*model.QuestionQa) []*QuestionQaDto { QaRuleContent: v.QaRuleContent, QaDisplayType: v.QaDisplayType, QaExpireTime: v.QaExpireTime, - QaLink: v.QaLink, + QaShareId: utils.AddDomain(v.QaShareId), + Image: utils.AddOssDomain(v.Image), OpenNumber: v.OpenNumber, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, @@ -50,3 +63,34 @@ func GetQuestionQaListDto(m []*model.QuestionQa) []*QuestionQaDto { return responses } + +// GetQuestionQaDto 问答题库详情 +func GetQuestionQaDto(m *model.QuestionQa) *QuestionQaDto { + return &QuestionQaDto{ + QaId: fmt.Sprintf("%d", m.QaId), + QaName: m.QaName, + QaQuantity: m.QaQuantity, + QaStatus: m.QaStatus, + QaRuleContent: m.QaRuleContent, + QaDisplayType: m.QaDisplayType, + QaExpireTime: m.QaExpireTime, + QaShareId: utils.AddDomain(m.QaShareId), + OpenNumber: m.OpenNumber, + Image: utils.AddOssDomain(m.Image), + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// LoadItemContent 加载明细选题规则 +func (r *QuestionQaDto) LoadItemContent(s string) *QuestionQaDto { + if s != "" { + var itemContentDto []ItemContentDto + + err := json.Unmarshal([]byte(s), &itemContentDto) + if err == nil { + r.ItemContent = itemContentDto + } + } + return r +} diff --git a/api/dto/QuestionQaItem.go b/api/dto/QuestionQaItem.go new file mode 100644 index 0000000..c8356df --- /dev/null +++ b/api/dto/QuestionQaItem.go @@ -0,0 +1,94 @@ +package dto + +import ( + "fmt" + "knowledge/api/model" +) + +// QuestionQaItemDto 知识问答-明细 +type QuestionQaItemDto struct { + ItemId string `json:"item_id"` // 主键id + QaId string `json:"qa_id"` // 知识问答id + QuestionId string `json:"question_id"` // 题目id + IsMustSelect int `json:"is_must_select"` // 是否必被选中(0:否 1:是) + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + FirstLabel *LabelDto `json:"first_label"` // 一级标签 + SecondLabel *LabelDto `json:"second_label"` // 二级标签 + Question *QuestionDto `json:"question"` // 题目 +} + +// GetQuestionQaItemDto 题库明细详情 +func GetQuestionQaItemDto(m *model.QuestionQaItem) *QuestionQaItemDto { + return &QuestionQaItemDto{ + ItemId: fmt.Sprintf("%d", m.ItemId), + QaId: fmt.Sprintf("%d", m.QaId), + QuestionId: fmt.Sprintf("%d", m.QuestionId), + IsMustSelect: m.IsMustSelect, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetQuestionQaItemListDto 题目列表 +func GetQuestionQaItemListDto(m []*model.QuestionQaItem) []*QuestionQaItemDto { + // 处理返回值 + responses := make([]*QuestionQaItemDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionQaItemDto{ + ItemId: fmt.Sprintf("%d", v.ItemId), + QaId: fmt.Sprintf("%d", v.QaId), + QuestionId: fmt.Sprintf("%d", v.QuestionId), + IsMustSelect: v.IsMustSelect, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 加载题目 + if v.Question != nil { + response = response.LoadQuestion(v.Question) + } + + // 加载一级标签 + if v.Question.FirstLabel != nil { + response = response.LoadFirstLabel(v.Question.FirstLabel) + } + + // 加载二级标签 + if v.Question.SecondLabel != nil { + response = response.LoadSecondLabel(v.Question.SecondLabel) + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadFirstLabel 加载一级标签 +func (r *QuestionQaItemDto) LoadFirstLabel(m *model.Label) *QuestionQaItemDto { + if m != nil { + r.FirstLabel = GetLabelDto(m) + } + return r +} + +// LoadSecondLabel 加载二级标签 +func (r *QuestionQaItemDto) LoadSecondLabel(m *model.Label) *QuestionQaItemDto { + if m != nil { + r.SecondLabel = GetLabelDto(m) + } + return r +} + +// LoadQuestion 加载题目 +func (r *QuestionQaItemDto) LoadQuestion(m *model.Question) *QuestionQaItemDto { + if m != nil { + r.Question = GetQuestionDto(m) + } + return r +} diff --git a/api/dto/Share.go b/api/dto/Share.go new file mode 100644 index 0000000..a3fe72f --- /dev/null +++ b/api/dto/Share.go @@ -0,0 +1,56 @@ +package dto + +import ( + "knowledge/api/model" + "knowledge/utils" + "strings" +) + +type ShareDto struct { + QuestionQa *QuestionQaDto `json:"question_qa"` // 题库数据 + Question []*ShareQuestionDto `json:"question"` // 题目数据 +} + +// ShareQuestionDto 题目数据 +type ShareQuestionDto struct { + QuestionName string `json:"question_name"` // 题目名称 + QuestionType int `json:"question_type"` // 题目类型(1:单选 2:多选 3:问答 4:判断) + QuestionSource int `json:"question_source"` // 题目来源(1:本题库 2:外部数据) + QuestionImage []string `json:"question_image"` // 题目图片(逗号分隔) + QuestionAnswer string `json:"question_answer"` // 答案 + QuestionAnalysis string `json:"question_analysis"` // 解析 + Difficulty int `json:"difficulty"` // 难度(0:未知 1:低 2:中 3:高) + IsMustSelect int `json:"is_must_select"` +} + +// GetShareQuestionDto 分享题目详情 +func GetShareQuestionDto(m *model.Question) *ShareQuestionDto { + var questionImage []string + if m.QuestionImage != "" { + result := strings.Split(m.QuestionImage, ",") + if len(result) > 0 { + for _, v := range result { + v = utils.AddOssDomain(v) + questionImage = append(questionImage, v) + } + } + } + + return &ShareQuestionDto{ + QuestionName: m.QuestionName, + QuestionType: m.QuestionType, + QuestionSource: m.QuestionSource, + QuestionImage: questionImage, + QuestionAnswer: m.QuestionAnswer, + QuestionAnalysis: m.QuestionAnalysis, + Difficulty: m.Difficulty, + } +} + +// LoadQuestionQa 加载题库数据 +func (r *ShareDto) LoadQuestionQa(m *model.QuestionQa) *ShareDto { + if m != nil { + r.QuestionQa = GetQuestionQaDto(m) + } + return r +} diff --git a/api/dto/Static.go b/api/dto/Static.go new file mode 100644 index 0000000..5ce55f2 --- /dev/null +++ b/api/dto/Static.go @@ -0,0 +1,42 @@ +package dto + +import ( + "fmt" + "knowledge/api/model" + "knowledge/utils" +) + +type StaticDto struct { + Name string `json:"name"` // 名称 + Total int `json:"total"` // 数量 +} + +// GetStaticListDto 问答题库列表 +func GetStaticListDto(m []*model.QuestionQa) []*QuestionQaDto { + // 处理返回值 + responses := make([]*QuestionQaDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionQaDto{ + QaId: fmt.Sprintf("%d", v.QaId), + QaName: v.QaName, + QaQuantity: v.QaQuantity, + QaStatus: v.QaStatus, + QaRuleContent: v.QaRuleContent, + QaDisplayType: v.QaDisplayType, + QaExpireTime: v.QaExpireTime, + QaShareId: utils.AddDomain(v.QaShareId), + Image: utils.AddOssDomain(v.Image), + OpenNumber: v.OpenNumber, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} diff --git a/api/model/Question.go b/api/model/Question.go index a38e2ee..8234c2d 100644 --- a/api/model/Question.go +++ b/api/model/Question.go @@ -21,8 +21,9 @@ type Question struct { FirstLabelId *int64 `gorm:"column:first_label_id;type:bigint(19);comment:一级标签id" json:"first_label_id"` SecondLabelId *int64 `gorm:"column:second_label_id;type:bigint(19);comment:二级标签id" json:"second_label_id"` Model - FirstLabel *Label `gorm:"foreignKey:FirstLabelId;references:label_id" json:"first_label"` - SecondLabel *Label `gorm:"foreignKey:SecondLabelId;references:label_id" json:"second_label"` + FirstLabel *Label `gorm:"foreignKey:FirstLabelId;references:label_id" json:"first_label"` + SecondLabel *Label `gorm:"foreignKey:SecondLabelId;references:label_id" json:"second_label"` + QuestionOption []*QuestionOption `gorm:"foreignKey:QuestionId;references:question_id" json:"question_option"` } func (m *Question) TableName() string { diff --git a/api/model/QuestionQa.go b/api/model/QuestionQa.go index 0678f31..9c7beee 100644 --- a/api/model/QuestionQa.go +++ b/api/model/QuestionQa.go @@ -15,10 +15,11 @@ type QuestionQa struct { QaRuleContent string `gorm:"column:qa_rule_content;type:text;comment:规则解释" json:"qa_rule_content"` QaDisplayType int `gorm:"column:qa_display_type;type:tinyint(1);default:1;comment:展示类型(1:常规 2:飞花令)" json:"qa_display_type"` QaExpireTime LocalTime `gorm:"column:qa_expire_time;type:datetime;comment:过期时间" json:"qa_expire_time"` - QaLink string `gorm:"column:qa_link;type:varchar(255);comment:分享链接" json:"qa_link"` + QaShareId string `gorm:"column:qa_share_id;type:varchar(255);comment:分享标识" json:"qa_share_id"` QaPassword string `gorm:"column:qa_password;type:varchar(255);comment:分享密码" json:"qa_password"` OpenNumber int `gorm:"column:open_number;type:int(1);default:0;comment:打开的次数" json:"open_number"` Image string `gorm:"column:image;type:varchar(255);comment:背景图" json:"image"` + ItemContent string `gorm:"column:item_content;type:text;comment:明细选题规则(json)" json:"item_content"` Model } diff --git a/api/model/QuestionQaItem.go b/api/model/QuestionQaItem.go index bd48b50..25e6c72 100644 --- a/api/model/QuestionQaItem.go +++ b/api/model/QuestionQaItem.go @@ -13,6 +13,8 @@ type QuestionQaItem struct { QuestionId int64 `gorm:"column:question_id;type:bigint(19);comment:题目id;NOT NULL" json:"question_id"` IsMustSelect int `gorm:"column:is_must_select;type:tinyint(1);default:0;comment:是否必被选中(0:否 1:是)" json:"is_must_select"` Model + Question *Question `gorm:"foreignKey:QuestionId;references:question_id" json:"question"` + QuestionQa *QuestionQa `gorm:"foreignKey:QaId;references:qa_id" json:"question_qa"` } func (m *QuestionQaItem) TableName() string { diff --git a/api/requests/Label.go b/api/requests/Label.go new file mode 100644 index 0000000..bbbf983 --- /dev/null +++ b/api/requests/Label.go @@ -0,0 +1,27 @@ +package requests + +type LabelRequest struct { + GetLabelList // 获取标签列表 + AddLabel // 新增标签 + PutLabel // 修改标签 +} + +// GetLabelList 获取标签列表 +type GetLabelList struct { + LabelId string `json:"label_id" form:"label_id" label:"主键id"` + LabelName string `json:"label_name" form:"label_name" label:"标签名称"` + ParentId string `json:"parent_id" form:"parent_id" label:"父级ID"` + LabelLevel *int `json:"label_level" form:"label_level" label:"级别"` +} + +// AddLabel 新增标签 +type AddLabel struct { + LabelName string `json:"label_name" form:"label_name" label:"标签名称" validate:"required" ` + ParentId string `json:"parent_id" form:"parent_id" label:"父级ID" ` + LabelLevel int `json:"label_level" form:"label_level" label:"级别" validate:"required,number,min=1" ` +} + +// PutLabel 修改标签 +type PutLabel struct { + LabelName string `json:"label_name" form:"label_name" label:"标签名称" validate:"required" ` +} diff --git a/api/requests/Question.go b/api/requests/Question.go index 403409e..e5d9d68 100644 --- a/api/requests/Question.go +++ b/api/requests/Question.go @@ -1,12 +1,13 @@ package requests type QuestionRequest struct { - GetQuestionPage // 获取题目列表-分页 - AddQuestion // 新增题目 - AddQuestionTest // 新增题目 - PutQuestion // 修改题目 - PutQuestionTest // 修改题目 - DeleteQuestion // 修改题目 + GetQuestionPage // 获取题目列表-分页 + AddQuestion // 新增题目 + AddQuestionTest // 新增题目 + PutQuestion // 修改题目 + PutQuestionTest // 修改题目 + DeleteQuestion // 修改题目 + GetQuestionCount // 获取题目数量 } // GetQuestionPage 获取题目列表-分页 @@ -44,6 +45,7 @@ type AddQuestion struct { SecondLabelId string `json:"second_label_id" form:"second_label_id" label:"二级标签id"` QuestionImage []string `json:"question_image" form:"question_image" label:"图片"` QuestionOption []string `json:"question_option" form:"question_option" label:"选项"` + QaId string `json:"qa_id" form:"qa_id" label:"题库id"` } // AddQuestionTest 新增题目 @@ -102,3 +104,13 @@ type PutQuestionTest struct { type DeleteQuestion struct { QuestionId []string `json:"question_id" form:"question_id" validate:"required" label:"题目id"` } + +// GetQuestionCount 获取题目数量 +type GetQuestionCount struct { + QuestionType *int `json:"question_type" form:"question_type" validate:"omitempty,oneof=1 2 3 4" label:"题目类型"` // 题目类型(1:单选 2:多选 3:问答 4:判断) + QuestionStatus *int `json:"question_status" form:"question_status" label:"状态"` + QuestionSource *int `json:"question_source" form:"question_source" validate:"omitempty,oneof=1 2" label:"题目来源"` // 题目来源(1:本题库 2:外部数据) + Difficulty *int `json:"difficulty" form:"difficulty" label:"难度"` + FirstLabelId *string `json:"first_label_id" form:"first_label_id" label:"一级标签id"` + SecondLabelId *string `json:"second_label_id" form:"second_label_id" label:"二级标签id"` +} diff --git a/api/requests/QuestionQa.go b/api/requests/QuestionQa.go index 8d6e18c..ce82f1e 100644 --- a/api/requests/QuestionQa.go +++ b/api/requests/QuestionQa.go @@ -6,6 +6,7 @@ type QuestionQaRequest struct { PutQuestionQa // 修改问答题库 PutQuestionQaPassword // 修改问答题库密码 PutQuestionQaExpire // 修改问答题库有效期 + PutQuestionQaRule // 修改问答题库规则解释 } // GetQuestionQaPage 获取问答题库列表-分页 @@ -19,7 +20,7 @@ type GetQuestionQaPage struct { QaDisplayType *int `json:"qa_display_type" form:"qa_display_type" label:"展示类型"` // (1:常规 2:飞花令) QaExpireTime string `json:"qa_expire_time" form:"qa_expire_time" label:"过期时间"` // 注意:这里假设LocalTime转换为字符串格式处理 CreatedAt string `json:"created_at" form:"created_at" label:"创建时间"` // 注意:这里假设LocalTime转换为字符串格式处理 - UpdatedAt string `json:"updated_at" form:"updated_at" label:"过期时间"` // 注意:这里假设LocalTime转换为字符串格式处理 + UpdatedAt string `json:"updated_at" form:"updated_at" label:"修改时间"` // 注意:这里假设LocalTime转换为字符串格式处理 Order *GetQuestionQaPageOrder `json:"order" form:"order" label:"排序"` } @@ -80,3 +81,8 @@ type PutQuestionQaPassword struct { type PutQuestionQaExpire struct { QaExpireTime string `json:"qa_expire_time" form:"qa_expire_time" label:"过期时间" validate:"required"` // 注意:这里假设LocalTime转换为字符串格式处理 } + +// PutQuestionQaRule 修改问答题库规则解释 +type PutQuestionQaRule struct { + QaRuleContent string `json:"qa_rule_content" form:"qa_rule_content" label:"规则解释" validate:"required"` +} diff --git a/api/requests/QuestionQaItem.go b/api/requests/QuestionQaItem.go new file mode 100644 index 0000000..5dd4966 --- /dev/null +++ b/api/requests/QuestionQaItem.go @@ -0,0 +1,38 @@ +package requests + +type QuestionQaItemRequest struct { + GetQuestionQaItemPage // 获取问答题库明细列表-分页 + DeleteQuestionQaItem // 删除问答题库明细 + PutQuestionQaItemMust // 修改必选 +} + +// GetQuestionQaItemPage 获取问答题库明细列表-分页 +type GetQuestionQaItemPage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + QaId string `json:"qa_id" form:"qa_id" label:"题库id" validate:"required"` + QuestionId string `json:"question_id" form:"question_id" label:"题目id"` + IsMustSelect *int `json:"is_must_select" form:"is_must_select" label:"是否必被选中"` + QuestionName string `json:"question_name" form:"question_name" label:"题目名称"` + QuestionType *int `json:"question_type" form:"question_type" validate:"omitempty,oneof=1 2 3 4" label:"题目类型"` // 题目类型(1:单选 2:多选 3:问答 4:判断) + QuestionSource *int `json:"question_source" form:"question_source" validate:"omitempty,oneof=1 2" label:"题目来源"` // 题目来源(1:本题库 2:外部数据) + Difficulty *int `json:"difficulty" form:"difficulty" label:"难度"` + FirstLabelId *string `json:"first_label_id" form:"first_label_id" label:"一级标签id"` + SecondLabelId *string `json:"second_label_id" form:"second_label_id" label:"二级标签id"` + Order *GetQuestionQaItemPageOrder `json:"order" form:"order" label:"排序"` +} + +// GetQuestionQaItemPageOrder 获取题目明细列表-分页-排序条件 +type GetQuestionQaItemPageOrder struct { + UpdatedAt string `json:"updated_at" form:"updated_at" label:"排序"` +} + +// DeleteQuestionQaItem 删除问答题库明细 +type DeleteQuestionQaItem struct { + ItemId []string `json:"item_id" form:"item_id" validate:"required" label:"明细id"` +} + +// PutQuestionQaItemMust 修改必选 +type PutQuestionQaItemMust struct { + IsMustSelect int `json:"is_must_select" form:"is_must_select" label:"是否必被选中"` +} diff --git a/api/requests/Share.go b/api/requests/Share.go new file mode 100644 index 0000000..20c61c8 --- /dev/null +++ b/api/requests/Share.go @@ -0,0 +1,10 @@ +package requests + +type ShareRequest struct { + GetShare // 获取分享数据 +} + +type GetShare struct { + QaShareId string `json:"qa_share_id" form:"qa_share_id" label:"分享标识" validate:"required"` + QaPassword string `json:"qa_password" form:"qa_password" label:"密码" validate:"required"` +} diff --git a/api/router/router.go b/api/router/router.go index 7d52aad..9ba5e69 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -90,6 +90,13 @@ func publicRouter(r *gin.Engine, api controller.Api) { // 修改题目 adminGroup.PUT("/question/test/:question_id", api.Question.PutQuestionTest) + + // 分享 + shareGroup := r.Group("/share") + { + // 获取分享数据 + shareGroup.GET("", api.Share.GetShare) + } } // adminRouter 公共路由-验证权限 @@ -112,6 +119,9 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 获取题目列表-分页 questionGroup.POST("/page", api.Question.GetQuestionPage) + // 获取题目详情 + questionGroup.GET("/:question_id", api.Question.GetQuestion) + // 新增题目 questionGroup.POST("", api.Question.AddQuestion) @@ -120,6 +130,9 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 删除题目 questionGroup.DELETE("", api.Question.DeleteQuestion) + + // 获取题目数量 + questionGroup.GET("/count", api.Question.GetQuestionCount) } // 问答 @@ -132,13 +145,52 @@ func privateRouter(r *gin.Engine, api controller.Api) { qaGroup.POST("", api.QuestionQa.AddQuestionQa) // 修改问答题库 - qaGroup.PUT("/:qa_id", api.Question.PutQuestionQa) + qaGroup.PUT("/:qa_id", api.QuestionQa.PutQuestionQa) // 修改问答题库密码 - qaGroup.PUT("/password/:qa_id", api.Question.PutQuestionQaPassword) + qaGroup.PUT("/password/:qa_id", api.QuestionQa.PutQuestionQaPassword) // 修改问答题库有效期 - qaGroup.PUT("/expire/:qa_id", api.Question.PutQuestionQaExpire) + qaGroup.PUT("/expire/:qa_id", api.QuestionQa.PutQuestionQaExpire) + + // 修改问答题库规则解释 + qaGroup.PUT("/rule/:qa_id", api.QuestionQa.PutQuestionQaRule) + + // 获取问答题库详情 + qaGroup.GET("/:qa_id", api.QuestionQa.GetQuestionQa) + + // 题库明细 + itemGroup := qaGroup.Group("/item") + { + // 获取问答题库明细列表-分页 + itemGroup.POST("/page", api.QuestionQaItem.GetQuestionQaItemPage) + + // 删除问答题库明细 + itemGroup.DELETE("", api.QuestionQaItem.DeleteQuestionQaItem) + + // 修改必选 + itemGroup.PUT("/must/:item_id", api.QuestionQaItem.PutQuestionQaItemMust) + } + } + + // 标签 + labelGroup := adminGroup.Group("/label") + { + // 获取标签列表 + labelGroup.GET("/list", api.Label.GetLabelList) + + // 新增标签 + labelGroup.POST("", api.Label.AddLabel) + + // 修改标签 + labelGroup.PUT("/:label_id", api.Label.PutLabel) + } + + // 统计 + staticGroup := adminGroup.Group("/static") + { + // 获取统计数据 + staticGroup.GET("", api.Static.GetStatic) } } diff --git a/api/service/Label.go b/api/service/Label.go new file mode 100644 index 0000000..f5b39d8 --- /dev/null +++ b/api/service/Label.go @@ -0,0 +1,88 @@ +package service + +import ( + "errors" + "knowledge/api/dao" + "knowledge/api/model" + "knowledge/api/requests" + "knowledge/global" + "strconv" +) + +type LabelService struct { +} + +// AddLabel 新增标签 +func (r *LabelService) AddLabel(req requests.AddLabel) (bool, error) { + labelDao := dao.LabelDao{} + + var parentId int64 + if req.LabelLevel != 1 { + if req.ParentId == "" || req.ParentId == "0" { + return false, errors.New("请填写父级标签") + } + + parentId, err := strconv.ParseInt(req.ParentId, 10, 64) + if err != nil { + return false, err + } + + _, err = labelDao.GetLabelFirstById(parentId) + if err != nil { + return false, errors.New("父级标签错误") + } + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + // 新增题目 + label := &model.Label{ + LabelName: req.LabelName, + ParentId: parentId, + LabelLevel: req.LabelLevel, + } + + label, err := labelDao.AddLabel(tx, label) + if err != nil { + tx.Rollback() + return false, errors.New("新增失败") + } + + tx.Commit() + return true, nil +} + +// PutLabel 修改标签 +func (r *LabelService) PutLabel(labelId int64, req requests.PutLabel) (bool, error) { + labelDao := dao.LabelDao{} + _, err := labelDao.GetLabelFirstById(labelId) + if err != nil { + return false, errors.New("标签不存在") + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + labelData := make(map[string]interface{}) + labelData["label_name"] = req.LabelName + + err = labelDao.EditLabelById(tx, labelId, labelData) + if err != nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + tx.Commit() + return true, nil +} diff --git a/api/service/Question.go b/api/service/Question.go index 2647072..2449f24 100644 --- a/api/service/Question.go +++ b/api/service/Question.go @@ -5,6 +5,7 @@ import ( "fmt" "gorm.io/gorm" "knowledge/api/dao" + "knowledge/api/dto" "knowledge/api/model" "knowledge/api/requests" "knowledge/global" @@ -119,6 +120,29 @@ func (r *QuestionService) AddQuestion(req requests.AddQuestion) (bool, error) { } } + // 处理题库数据 + if req.QaId != "" { + qaId, err := strconv.ParseInt(req.QaId, 10, 64) + if err != nil { + tx.Rollback() + return false, err + } + + // 新增题库明细 + questionQaItemDao := dao.QuestionQaItemDao{} + questionQaItem := &model.QuestionQaItem{ + QaId: qaId, + QuestionId: question.QuestionId, + IsMustSelect: 0, + } + + _, err = questionQaItemDao.AddQuestionQaItem(tx, questionQaItem) + if err != nil { + tx.Rollback() + return false, err + } + } + tx.Commit() return true, nil } @@ -746,3 +770,34 @@ func (r *QuestionService) DeleteQuestion(req requests.DeleteQuestion) (bool, err return true, nil } + +// GetQuestion 获取题目详情 +func (r *QuestionService) GetQuestion(questionId int64) (g *dto.QuestionDto, err error) { + questionDao := dao.QuestionDao{} + question, err := questionDao.GetQuestionPreloadById(questionId) + if err != nil { + return nil, errors.New("题目不存在") + } + + if question.QuestionStatus == 2 { + return nil, errors.New("题目已禁用") + } + + if question.IsDelete == 1 { + return nil, errors.New("题目已删除") + } + + // 处理返回值 + g = dto.GetQuestionDto(question) + + // 加载一级标签 + g.LoadFirstLabel(question.FirstLabel) + + // 加载二级标签 + g.LoadSecondLabel(question.SecondLabel) + + // 加载选项 + g.LoadQuestionOption(question.QuestionOption) + + return g, nil +} diff --git a/api/service/QuestionQa.go b/api/service/QuestionQa.go index 030888e..4e8b5f3 100644 --- a/api/service/QuestionQa.go +++ b/api/service/QuestionQa.go @@ -2,7 +2,10 @@ package service import ( "errors" + "fmt" + "github.com/goccy/go-json" "knowledge/api/dao" + "knowledge/api/dto" "knowledge/api/model" "knowledge/api/requests" "knowledge/global" @@ -39,8 +42,8 @@ func (r *QuestionQaService) AddQuestionQa(req requests.AddQuestionQa) (bool, err return false, errors.New("过期时间需大于当前时间") } - // 生成分享链接 - qaLink := "" + // 处理明细选题规则 + itemContent, _ := json.Marshal(req.Item) // 开始事务 tx := global.Db.Begin() @@ -58,10 +61,10 @@ func (r *QuestionQaService) AddQuestionQa(req requests.AddQuestionQa) (bool, err QaRuleContent: req.QaRuleContent, QaDisplayType: req.QaDisplayType, QaExpireTime: model.LocalTime(qaExpireTime), - QaLink: qaLink, QaPassword: req.QaPassword, OpenNumber: 0, Image: req.Image, + ItemContent: string(itemContent), } questionQaDao := dao.QuestionQaDao{} @@ -71,6 +74,21 @@ func (r *QuestionQaService) AddQuestionQa(req requests.AddQuestionQa) (bool, err return false, errors.New("新增失败") } + // 生成分享链接 + qaShareId := utils.HashString(fmt.Sprintf("%d", questionQa.QaId)) + if err != nil { + tx.Rollback() + return false, err + } + + questionQaData := make(map[string]interface{}) + questionQaData["qa_share_id"] = qaShareId + err = questionQaDao.EditQuestionQaById(tx, questionQa.QaId, questionQaData) + if err != nil { + tx.Rollback() + return false, errors.New("新增失败") + } + // 新增问答题库题目列表 questionDao := dao.QuestionDao{} questionQaItemDao := dao.QuestionQaItemDao{} @@ -129,7 +147,7 @@ func (r *QuestionQaService) AddQuestionQa(req requests.AddQuestionQa) (bool, err } // 获取随机明细题目 - questions, err := questionDao.GetQuestionListRand(maps, req.QaQuantity) + questions, err := questionDao.GetQuestionListRand(maps, item.Quantity*3) if err != nil { tx.Rollback() return false, err @@ -223,6 +241,12 @@ func (r *QuestionQaService) PutQuestionQa(qaId int64, req requests.PutQuestionQa questionQaData["image"] = image } + // 处理明细选题规则 + itemContent, _ := json.Marshal(req.Item) + if string(itemContent) != questionQa.ItemContent { + questionQaData["item_content"] = string(itemContent) + } + // 题目数量 if req.QaQuantity != questionQa.QaQuantity { if req.Action == 1 { @@ -298,7 +322,7 @@ func (r *QuestionQaService) PutQuestionQa(qaId int64, req requests.PutQuestionQa } // 获取随机明细题目 - questions, err := questionDao.GetQuestionListRand(maps, req.QaQuantity) + questions, err := questionDao.GetQuestionListRand(maps, req.QaQuantity*3) if err != nil { tx.Rollback() return false, err @@ -418,3 +442,62 @@ func (r *QuestionQaService) PutQuestionQaExpire(qaId int64, req requests.PutQues 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 +} + +// GetQuestionQa 获取问答题库详情 +func (r *QuestionQaService) GetQuestionQa(qaId int64) (g *dto.QuestionQaDto, err error) { + questionQaDao := dao.QuestionQaDao{} + questionQa, err := questionQaDao.GetQuestionQaById(qaId) + if err != nil { + return nil, errors.New("题库不存在") + } + + if questionQa.QaStatus == 2 { + return nil, errors.New("题库已失效") + } + + // 处理返回值 + g = dto.GetQuestionQaDto(questionQa) + + // 加载明细选题规则 + g = g.LoadItemContent(questionQa.ItemContent) + + return g, nil +} diff --git a/api/service/QuestionQaItem.go b/api/service/QuestionQaItem.go new file mode 100644 index 0000000..49d9644 --- /dev/null +++ b/api/service/QuestionQaItem.go @@ -0,0 +1,84 @@ +package service + +import ( + "errors" + "knowledge/api/dao" + "knowledge/api/requests" + "knowledge/global" + "strconv" +) + +type QuestionQaItemService struct { +} + +// DeleteQuestionQaItem 删除问答题库明细 +func (r *QuestionQaItemService) DeleteQuestionQaItem(req requests.DeleteQuestionQaItem) (bool, error) { + questionQaItemDao := dao.QuestionQaItemDao{} + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + for _, itemId := range req.ItemId { + // 将字符串转换为int64类型 + itemId, err := strconv.ParseInt(itemId, 10, 64) + if err != nil { + tx.Rollback() + return false, errors.New("删除失败") + } + + _, err = questionQaItemDao.GetQuestionQaItemById(itemId) + if err != nil { + tx.Rollback() + return false, errors.New("明细不存在") + } + + err = questionQaItemDao.DeleteQuestionQaItemById(tx, itemId) + if err != nil { + tx.Rollback() + return false, errors.New("删除失败") + } + } + + tx.Commit() + + return true, nil +} + +// PutQuestionQaItemMust 修改必选 +func (r *QuestionQaItemService) PutQuestionQaItemMust(itemId int64, req requests.PutQuestionQaItemMust) (bool, error) { + questionQaItemDao := dao.QuestionQaItemDao{} + questionQaItem, err := questionQaItemDao.GetQuestionQaItemById(itemId) + if err != nil { + return false, errors.New("题目不存在") + } + + // 分享密码 + if req.IsMustSelect == questionQaItem.IsMustSelect { + return true, nil + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + questionQaItemData := make(map[string]interface{}) + questionQaItemData["is_must_select"] = req.IsMustSelect + + err = questionQaItemDao.EditQuestionQaItemById(tx, itemId, questionQaItemData) + if err != nil { + tx.Rollback() + return false, errors.New(err.Error()) + } + + tx.Commit() + return true, nil +} diff --git a/api/service/Share.go b/api/service/Share.go new file mode 100644 index 0000000..4c2d730 --- /dev/null +++ b/api/service/Share.go @@ -0,0 +1,106 @@ +package service + +import ( + "errors" + "knowledge/api/dao" + "knowledge/api/dto" + "knowledge/api/requests" + "sort" + "time" +) + +type ShareService struct { +} + +func (r *ShareService) GetShare(req requests.GetShare) (g *dto.ShareDto, err error) { + questionQaDao := dao.QuestionQaDao{} + questionQaItemDao := dao.QuestionQaItemDao{} + questionDao := dao.QuestionDao{} + + // 获取题库数据 + maps := make(map[string]interface{}) + maps["qa_share_id"] = req.QaShareId + questionQa, err := questionQaDao.GetQuestionQa(maps) + if err != nil || questionQa == nil { + return nil, errors.New("题库不存在") + } + + if questionQa.QaStatus == 2 { + return nil, errors.New("题库已失效") + } + + if questionQa.QaPassword != req.QaPassword { + return nil, errors.New("密码错误") + } + + // 检测过期时间 + now := time.Now() + qaExpireTime := time.Time(questionQa.QaExpireTime) + if qaExpireTime.Before(now) { + return nil, errors.New("题库已失效") + } + + // 加载题库数据 + g = &dto.ShareDto{} + g.QuestionQa = dto.GetQuestionQaDto(questionQa) + + // 获取题库明细数据-必备选中 + maps = make(map[string]interface{}) + maps["qa_id"] = questionQa.QaId + maps["is_must_select"] = 1 + questionQaItems, err := questionQaItemDao.GetQuestionQaItemList(maps) + if err == nil && len(questionQaItems) > 0 { + shareQuestionDtos := make([]*dto.ShareQuestionDto, len(questionQaItems)) + + for i, item := range questionQaItems { + // 获取题目数据 + question, err := questionDao.GetQuestionById(item.QuestionId) + if err != nil { + return nil, errors.New("题目错误") + } + + shareQuestionDto := dto.GetShareQuestionDto(question) + + shareQuestionDto.IsMustSelect = item.IsMustSelect + + // 将转换后的结构体添加到新切片中 + shareQuestionDtos[i] = shareQuestionDto + } + + g.Question = shareQuestionDtos + } + + // 计算剩余题目数量 + 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.GetQuestionQaItemListRand(maps, 1) + if err == nil && len(questionQaItems) > 0 { + for _, item := range questionQaItems { + // 获取题目数据 + question, err := questionDao.GetQuestionById(item.QuestionId) + if err != nil { + return nil, errors.New("题目错误") + } + + shareQuestionDto := dto.GetShareQuestionDto(question) + + shareQuestionDto.IsMustSelect = item.IsMustSelect + + // 将转换后的结构体添加到新切片中 + g.Question = append(g.Question, shareQuestionDto) + } + } + } + + // 按照难度重新排序题目顺序 + sort.SliceStable(g.Question, func(i, j int) bool { + return g.Question[i].Difficulty < g.Question[j].Difficulty + }) + + return g, nil +} diff --git a/api/service/Static.go b/api/service/Static.go new file mode 100644 index 0000000..5fc6367 --- /dev/null +++ b/api/service/Static.go @@ -0,0 +1,93 @@ +package service + +import ( + "knowledge/api/dao" + "knowledge/api/dto" +) + +type StaticService struct { +} + +func (r *StaticService) GetStatic() (g []*dto.StaticDto, err error) { + questionDao := dao.QuestionDao{} + // 处理返回值 + var responses []*dto.StaticDto + + // 获取每个题目类型题目数量 + maps := make(map[string]interface{}) + maps["question_type"] = 1 + maps["question_status"] = 1 + maps["question_source"] = 1 + total, err := questionDao.GetQuestionCount(maps) + response := &dto.StaticDto{ + Name: "单选题", + Total: int(total), + } + + responses = append(responses, response) + + // 获取每个题目类型题目数量 + maps = make(map[string]interface{}) + maps["question_type"] = 2 + maps["question_status"] = 1 + maps["question_source"] = 1 + total, err = questionDao.GetQuestionCount(maps) + response = &dto.StaticDto{ + Name: "多选题", + Total: int(total), + } + + responses = append(responses, response) + + // 获取每个题目类型题目数量 + maps = make(map[string]interface{}) + maps["question_type"] = 3 + maps["question_status"] = 1 + maps["question_source"] = 1 + total, err = questionDao.GetQuestionCount(maps) + response = &dto.StaticDto{ + Name: "问答题", + Total: int(total), + } + + responses = append(responses, response) + + // 获取每个题目类型题目数量 + maps = make(map[string]interface{}) + maps["question_type"] = 4 + maps["question_status"] = 1 + maps["question_source"] = 1 + total, err = questionDao.GetQuestionCount(maps) + response = &dto.StaticDto{ + Name: "判断题", + Total: int(total), + } + + responses = append(responses, response) + + // 获取每个一级标签题目数量 + labelDao := dao.LabelDao{} + maps = make(map[string]interface{}) + maps["parent_id"] = 0 + maps["label_level"] = 1 + labels, err := labelDao.GetLabelList(maps) + if err != nil { + return nil, err + } + + for _, label := range labels { + maps = make(map[string]interface{}) + maps["question_status"] = 1 + maps["question_source"] = 1 + maps["first_label_id"] = label.LabelId + total, err = questionDao.GetQuestionCount(maps) + response = &dto.StaticDto{ + Name: label.LabelName, + Total: int(total), + } + + responses = append(responses, response) + } + + return responses, nil +} diff --git a/config.yaml b/config.yaml index 59848c7..ac78272 100644 --- a/config.yaml +++ b/config.yaml @@ -4,6 +4,8 @@ env: dev # 环境配置 snowflake: 1 # 雪花算法机器id +domain: http://dev-knowledge.com + # [数据库配置] mysql: host: '42.193.16.243' diff --git a/config/config.go b/config/config.go index 24c7043..e60f0a0 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ var C Config type Config struct { Port int `mapstructure:"port" json:"port" yaml:"port"` Env string `mapstructure:"env" json:"Env" yaml:"Env"` + Domain string `mapstructure:"domain" json:"domain" yaml:"domain"` Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"` Log Log `mapstructure:"log" json:"log" yaml:"log"` Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"` diff --git a/utils/aes.go b/utils/aes.go new file mode 100644 index 0000000..ba70469 --- /dev/null +++ b/utils/aes.go @@ -0,0 +1,90 @@ +package utils + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "io" +) + +// Encrypt 加密函数 +func Encrypt(text, key string) (string, error) { + plaintext := []byte(text) + hashedKey := hashKey(key) + + // 创建一个新的 AES cipher.Block + block, err := aes.NewCipher(hashedKey) + if err != nil { + return "", err + } + + // 使用 GCM 模式加密 + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonce := make([]byte, aesGCM.NonceSize()) + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return "", err + } + + // 加密数据 + ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil) + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + +// Decrypt 解密函数 +func Decrypt(cryptoText, key string) (string, error) { + ciphertext, _ := base64.StdEncoding.DecodeString(cryptoText) + hashedKey := hashKey(key) + + // 创建一个新的 AES cipher.Block + block, err := aes.NewCipher(hashedKey) + if err != nil { + return "", err + } + + // 使用 GCM 模式解密 + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonceSize := aesGCM.NonceSize() + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + + // 解密数据 + plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil) + if err != nil { + return "", err + } + + return string(plaintext), nil +} + +// HashString 使用SHA256算法对字符串进行哈希加密 +func HashString(s string) string { + // 创建一个新的SHA256哈希实例 + hasher := sha256.New() + + // 写入要哈希的字符串的字节 + hasher.Write([]byte(s)) + + // 获取哈希结果的字节切片 + hashBytes := hasher.Sum(nil) + + // 将字节切片转换成十六进制字符串表示 + s = hex.EncodeToString(hashBytes) + + return s +} + +// 将任意长度的密钥转换为适合 AES 的长度(32 字节) +func hashKey(key string) []byte { + hash := sha256.Sum256([]byte(key)) + return hash[:] +} diff --git a/utils/replace.go b/utils/replace.go index 12c804c..d0da92f 100644 --- a/utils/replace.go +++ b/utils/replace.go @@ -20,3 +20,11 @@ func AddOssDomain(url string) string { } return config.C.Oss.OssCustomDomainName + url } + +// AddDomain 增加地址中的前缀 +func AddDomain(url string) string { + if url == "" { + return "" + } + return config.C.Domain + "/share/" + url +}