1
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/api/requests"
|
||||
"knowledge/api/responses"
|
||||
"knowledge/api/service"
|
||||
"knowledge/config"
|
||||
"knowledge/global"
|
||||
"knowledge/utils"
|
||||
)
|
||||
|
||||
type AdminUser struct{}
|
||||
|
||||
func (r *AdminUser) Login(c *gin.Context) {
|
||||
adminUserRequest := requests.AdminUserRequest{}
|
||||
req := adminUserRequest.Login
|
||||
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
|
||||
}
|
||||
|
||||
// 验证验证码
|
||||
if config.C.Env == "prod" {
|
||||
isValid := utils.VerifyCaptcha(req.CaptchaId, req.Captcha)
|
||||
if !isValid {
|
||||
// 验证码错误
|
||||
responses.FailWithMessage("验证码错误", c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 登陆
|
||||
adminUserService := service.AdminUserService{}
|
||||
token, err := adminUserService.Login(req)
|
||||
if err != nil {
|
||||
responses.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
responses.OkWithData(token, c)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package controller
|
||||
|
||||
// Api api接口
|
||||
type Api struct {
|
||||
Migrate
|
||||
Public // 公共方法-不验证权限
|
||||
AdminUser // 后台用户
|
||||
Question // 题目
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/api/dao"
|
||||
"knowledge/api/model"
|
||||
"knowledge/api/responses"
|
||||
"knowledge/global"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Migrate struct{}
|
||||
|
||||
var (
|
||||
concurrency = 50 // 最大并发协程的数量
|
||||
running int32 // 当前运行的协程数量
|
||||
wg sync.WaitGroup
|
||||
limiter = make(chan struct{}, concurrency) // 通道作为限流器
|
||||
)
|
||||
|
||||
// Migrate 迁移数据
|
||||
func (r *Migrate) Migrate(c *gin.Context) {
|
||||
// 获取全部数据
|
||||
Testpaper12Dao := dao.Testpaper12Dao{}
|
||||
|
||||
maps := make(map[string]interface{})
|
||||
//maps["id"] = 51134
|
||||
maps["is_migrate"] = 0
|
||||
Testpaper12s, err := Testpaper12Dao.GetTestpaper12List(maps)
|
||||
if err != nil {
|
||||
panic("数据迁移失败! " + err.Error())
|
||||
}
|
||||
|
||||
if len(Testpaper12s) <= 0 {
|
||||
fmt.Println("已全部处理结束")
|
||||
}
|
||||
|
||||
for i, v := range Testpaper12s {
|
||||
wg.Add(1)
|
||||
go doWork(i, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
responses.Ok(c)
|
||||
}
|
||||
|
||||
func doWork(i int, v *model.Testpaper12) {
|
||||
defer wg.Done() // goroutine结束就登记-1
|
||||
|
||||
limiter <- struct{}{} // 获取一个令牌
|
||||
atomic.AddInt32(&running, 1)
|
||||
time.Sleep(100 * time.Millisecond) // 模拟工作
|
||||
<-limiter // 释放一个令牌
|
||||
atomic.AddInt32(&running, -1)
|
||||
|
||||
questionDao := dao.QuestionDao{}
|
||||
|
||||
// 开始事务
|
||||
tx := global.Db.Begin()
|
||||
|
||||
// 处理题目名称
|
||||
if v.Name == "" {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 题目名称去除前面标点符号
|
||||
re := regexp.MustCompile(`^\d+\.`)
|
||||
questionName := re.ReplaceAllString(v.Name, "")
|
||||
|
||||
re = regexp.MustCompile(`^\d+、`)
|
||||
questionName = re.ReplaceAllString(questionName, "")
|
||||
|
||||
re = regexp.MustCompile(`^\(\d+分\)\d+\.`)
|
||||
questionName = re.ReplaceAllString(questionName, "")
|
||||
|
||||
// 处理答案 【答案】D
|
||||
if v.Answer == "" {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
re = regexp.MustCompile(`[A-Z]+$`)
|
||||
questionAnswer := re.FindString(v.Answer)
|
||||
if questionAnswer == "" {
|
||||
// 未匹配到
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
if questionAnswer == "" {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理解析
|
||||
questionAnalysis := ""
|
||||
if v.Explain != "" {
|
||||
questionAnalysis = strings.Replace(v.Explain, "【解析】", "", 1)
|
||||
|
||||
questionAnalysis = strings.Replace(questionAnalysis, "【答案解析】", "", 1)
|
||||
}
|
||||
|
||||
// 添加题库表
|
||||
question := &model.Question{
|
||||
QuestionName: questionName,
|
||||
QuestionType: 1, // 题目类型
|
||||
QuestionSource: 1, // 题目来源(1:本题库 2:外部数据)
|
||||
QuestionAnswer: questionAnswer,
|
||||
QuestionAnalysis: questionAnalysis,
|
||||
FirstLabelId: nil,
|
||||
SecondLabelId: nil,
|
||||
}
|
||||
|
||||
question, err := questionDao.AddQuestion(tx, question)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理选项
|
||||
questionOptions := strings.Split(v.Item, "★")
|
||||
if len(questionOptions) > 0 {
|
||||
questionOptionDao := dao.QuestionOptionDao{}
|
||||
|
||||
s := false
|
||||
for _, option := range questionOptions {
|
||||
questionOption := &model.QuestionOption{
|
||||
QuestionId: question.QuestionId,
|
||||
OptionValue: option,
|
||||
}
|
||||
|
||||
questionOption, err := questionOptionDao.AddQuestionOption(tx, questionOption)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
s = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if s {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 修改为已迁移
|
||||
testpaper12Data := make(map[string]interface{})
|
||||
testpaper12Data["is_migrate"] = 1
|
||||
|
||||
Testpaper12Dao := dao.Testpaper12Dao{}
|
||||
err = Testpaper12Dao.EditTestpaper12ById(tx, int64(v.Id), testpaper12Data)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/api/responses"
|
||||
"knowledge/utils"
|
||||
)
|
||||
|
||||
type Public struct{}
|
||||
|
||||
// GetCaptcha 获取验证码
|
||||
func (b *Public) GetCaptcha(c *gin.Context) {
|
||||
id, b64s, err := utils.GenerateCaptcha()
|
||||
if err != nil {
|
||||
responses.FailWithMessage("验证码获取失败", c)
|
||||
}
|
||||
|
||||
responses.OkWithData(gin.H{
|
||||
"id": id,
|
||||
"b64s": b64s,
|
||||
}, c)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type Question struct{}
|
||||
|
||||
// GetQuestionPage 获取题目列表-分页
|
||||
func (r *Question) GetQuestionPage(c *gin.Context) {
|
||||
questionRequest := requests.QuestionRequest{}
|
||||
req := questionRequest.GetQuestionPage
|
||||
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
|
||||
}
|
||||
|
||||
questionDao := dao.QuestionDao{}
|
||||
question, total, err := questionDao.GetQuestionPageSearch(req, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
responses.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 处理返回值
|
||||
GetQuestionPageResponses := dto.GetQuestionListDto(question)
|
||||
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"] = GetQuestionPageResponses
|
||||
responses.OkWithData(result, c)
|
||||
}
|
||||
|
||||
// AddQuestion 新增题目
|
||||
func (r *Question) AddQuestion(c *gin.Context) {
|
||||
questionRequest := requests.QuestionRequest{}
|
||||
req := questionRequest.AddQuestion
|
||||
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
|
||||
}
|
||||
|
||||
// 业务处理
|
||||
questionService := service.QuestionService{}
|
||||
_, err := questionService.AddQuestion(req)
|
||||
if err != nil {
|
||||
responses.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
responses.Ok(c)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/api/model"
|
||||
"knowledge/global"
|
||||
)
|
||||
|
||||
type AdminUserDao struct {
|
||||
}
|
||||
|
||||
// GetAdminUserFirstById 获取用户数据-用户id
|
||||
// roleId 用户id
|
||||
func (r *AdminUserDao) GetAdminUserFirstById(userId int64) (m *model.AdminUser, err error) {
|
||||
err = global.Db.First(&m, userId).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetAdminUserFirstByAccess 获取用户数据-用户账号
|
||||
func (r *AdminUserDao) GetAdminUserFirstByAccess(access string) (m *model.AdminUser, err error) {
|
||||
err = global.Db.Where("access = ?", access).First(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetAdminUserFirstByPhone 获取用户数据-手机号
|
||||
func (r *AdminUserDao) GetAdminUserFirstByPhone(phone string) (m *model.AdminUser, err error) {
|
||||
err = global.Db.Where("phone = ?", phone).First(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DeleteAdminUser 删除用户
|
||||
func (r *AdminUserDao) DeleteAdminUser(tx *gorm.DB, maps interface{}) error {
|
||||
err := tx.Where(maps).Delete(&model.AdminUser{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAdminUserById 删除用户-用户id
|
||||
func (r *AdminUserDao) DeleteAdminUserById(tx *gorm.DB, userId int64) error {
|
||||
if err := tx.Delete(&model.AdminUser{}, userId).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditAdminUser 修改用户
|
||||
func (r *AdminUserDao) EditAdminUser(tx *gorm.DB, maps interface{}, data interface{}) error {
|
||||
err := tx.Model(&model.AdminUser{}).Where(maps).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditAdminUserById 修改角色-用户id
|
||||
func (r *AdminUserDao) EditAdminUserById(tx *gorm.DB, userId int64, data interface{}) error {
|
||||
err := tx.Model(&model.AdminUser{}).Where("user_id = ?", userId).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAdminUserList 获取用户列表
|
||||
func (r *AdminUserDao) GetAdminUserList(maps interface{}) (m []*model.AdminUser, err error) {
|
||||
err = global.Db.Where(maps).Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// AddAdminUser 新增用户
|
||||
func (r *AdminUserDao) AddAdminUser(tx *gorm.DB, model *model.AdminUser) (*model.AdminUser, error) {
|
||||
if err := tx.Create(model).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/api/model"
|
||||
"knowledge/global"
|
||||
)
|
||||
|
||||
type LabelDao struct {
|
||||
}
|
||||
|
||||
// GetLabelFirstById 获取数据-id
|
||||
// roleId 用户id
|
||||
func (r *LabelDao) GetLabelFirstById(LabelId int64) (m *model.Label, err error) {
|
||||
err = global.Db.First(&m, LabelId).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DeleteLabel 删除
|
||||
func (r *LabelDao) DeleteLabel(tx *gorm.DB, maps interface{}) error {
|
||||
err := tx.Where(maps).Delete(&model.Label{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteLabelById 删除-id
|
||||
func (r *LabelDao) DeleteLabelById(tx *gorm.DB, LabelId int64) error {
|
||||
if err := tx.Delete(&model.Label{}, LabelId).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditLabel 修改
|
||||
func (r *LabelDao) EditLabel(tx *gorm.DB, maps interface{}, data interface{}) error {
|
||||
err := tx.Model(&model.Label{}).Where(maps).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditLabelById 修改-id
|
||||
func (r *LabelDao) EditLabelById(tx *gorm.DB, LabelId int64, data interface{}) error {
|
||||
err := tx.Model(&model.Label{}).Where("label_id = ?", LabelId).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLabelList 获取列表
|
||||
func (r *LabelDao) GetLabelList(maps interface{}) (m []*model.Label, err error) {
|
||||
err = global.Db.Where(maps).Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// AddLabel 新增
|
||||
func (r *LabelDao) AddLabel(tx *gorm.DB, model *model.Label) (*model.Label, error) {
|
||||
if err := tx.Create(model).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
// GetLabel 获取
|
||||
func (r *LabelDao) GetLabel(maps interface{}) (m *model.Label, err error) {
|
||||
err = global.Db.Where(maps).First(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/api/model"
|
||||
"knowledge/api/requests"
|
||||
"knowledge/global"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type QuestionDao struct {
|
||||
}
|
||||
|
||||
// GetQuestionFirstById 获取数据-id
|
||||
// roleId 用户id
|
||||
func (r *QuestionDao) GetQuestionFirstById(questionId int64) (m *model.Question, err error) {
|
||||
err = global.Db.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
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteQuestionById 删除-id
|
||||
func (r *QuestionDao) DeleteQuestionById(tx *gorm.DB, questionId int64) error {
|
||||
if err := tx.Delete(&model.Question{}, questionId).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditQuestion 修改
|
||||
func (r *QuestionDao) EditQuestion(tx *gorm.DB, maps interface{}, data interface{}) error {
|
||||
err := tx.Model(&model.Question{}).Where(maps).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditQuestionById 修改-id
|
||||
func (r *QuestionDao) EditQuestionById(tx *gorm.DB, questionId int64, data interface{}) error {
|
||||
err := tx.Model(&model.Question{}).Where("question_id = ?", questionId).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetQuestionList 获取列表
|
||||
func (r *QuestionDao) GetQuestionList(maps interface{}) (m []*model.Question, err error) {
|
||||
err = global.Db.Where(maps).Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// AddQuestion 新增
|
||||
func (r *QuestionDao) AddQuestion(tx *gorm.DB, model *model.Question) (*model.Question, error) {
|
||||
if err := tx.Create(model).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
// GetQuestion 获取
|
||||
func (r *QuestionDao) GetQuestion(maps interface{}) (m *model.Question, err error) {
|
||||
err = global.Db.Where(maps).First(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetQuestionPageSearch 获取题目列表-分页
|
||||
func (r *QuestionDao) GetQuestionPageSearch(req requests.GetQuestionPage, page, pageSize int) (m []*model.Question, total int64, err error) {
|
||||
var totalRecords int64
|
||||
|
||||
// 构建查询条件
|
||||
query := global.Db.Model(&model.Question{})
|
||||
|
||||
// 一级标签
|
||||
query = query.Preload("FirstLabel", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("label_id", "label_name")
|
||||
})
|
||||
|
||||
// 二级标签
|
||||
query = query.Preload("SecondLabel", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("label_id", "label_name")
|
||||
})
|
||||
|
||||
// 主键id
|
||||
if req.QuestionId != "" {
|
||||
query = query.Where("question_id = ?", req.QuestionId)
|
||||
}
|
||||
|
||||
// 题目名称
|
||||
if req.QuestionName != "" {
|
||||
query = query.Where("question_name LIKE ?", "%"+req.QuestionName+"%")
|
||||
}
|
||||
|
||||
// 题目类型
|
||||
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)
|
||||
}
|
||||
|
||||
// 题目来源
|
||||
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)
|
||||
}
|
||||
|
||||
// 创建时间
|
||||
if req.CreatedAt != "" {
|
||||
createdAt := strings.Split(req.CreatedAt, "&")
|
||||
if len(createdAt) == 2 {
|
||||
startTime, _ := time.Parse("2006-01-02", createdAt[0])
|
||||
endTime, _ := time.Parse("2006-01-02", createdAt[1])
|
||||
|
||||
endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||
|
||||
query = query.Where("created_at BETWEEN ? AND ?", startTime, endTime)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改时间
|
||||
if req.UpdatedAt != "" {
|
||||
updatedAt := strings.Split(req.UpdatedAt, "&")
|
||||
if len(updatedAt) == 2 {
|
||||
startTime, _ := time.Parse("2006-01-02", updatedAt[0])
|
||||
endTime, _ := time.Parse("2006-01-02", updatedAt[1])
|
||||
|
||||
endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||
|
||||
query = query.Where("updated_at BETWEEN ? AND ?", startTime, endTime)
|
||||
}
|
||||
}
|
||||
|
||||
// 排序
|
||||
if req.Order != nil {
|
||||
if req.Order.UpdatedAt != "" {
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/api/model"
|
||||
"knowledge/global"
|
||||
)
|
||||
|
||||
type QuestionOptionDao struct {
|
||||
}
|
||||
|
||||
// GetQuestionOptionFirstById 获取数据-id
|
||||
// roleId 用户id
|
||||
func (r *QuestionOptionDao) GetQuestionOptionFirstById(OptionId int64) (m *model.QuestionOption, err error) {
|
||||
err = global.Db.First(&m, OptionId).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DeleteQuestionOption 删除
|
||||
func (r *QuestionOptionDao) DeleteQuestionOption(tx *gorm.DB, maps interface{}) error {
|
||||
err := tx.Where(maps).Delete(&model.QuestionOption{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteQuestionOptionById 删除-id
|
||||
func (r *QuestionOptionDao) DeleteQuestionOptionById(tx *gorm.DB, OptionId int64) error {
|
||||
if err := tx.Delete(&model.QuestionOption{}, OptionId).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditQuestionOption 修改
|
||||
func (r *QuestionOptionDao) EditQuestionOption(tx *gorm.DB, maps interface{}, data interface{}) error {
|
||||
err := tx.Model(&model.QuestionOption{}).Where(maps).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditQuestionOptionById 修改-id
|
||||
func (r *QuestionOptionDao) EditQuestionOptionById(tx *gorm.DB, OptionId int64, data interface{}) error {
|
||||
err := tx.Model(&model.QuestionOption{}).Where("option_id = ?", OptionId).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetQuestionOptionList 获取列表
|
||||
func (r *QuestionOptionDao) GetQuestionOptionList(maps interface{}) (m []*model.QuestionOption, err error) {
|
||||
err = global.Db.Where(maps).Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// AddQuestionOption 新增
|
||||
func (r *QuestionOptionDao) AddQuestionOption(tx *gorm.DB, model *model.QuestionOption) (*model.QuestionOption, error) {
|
||||
if err := tx.Create(model).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/api/model"
|
||||
"knowledge/global"
|
||||
)
|
||||
|
||||
type Testpaper12Dao struct {
|
||||
}
|
||||
|
||||
// GetTestpaper12FirstById 获取数据-id
|
||||
// roleId 用户id
|
||||
func (r *Testpaper12Dao) GetTestpaper12FirstById(Id int64) (m *model.Testpaper12, err error) {
|
||||
err = global.Db.First(&m, Id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetTestpaper12List 获取列表
|
||||
func (r *Testpaper12Dao) GetTestpaper12List(maps interface{}) (m []*model.Testpaper12, err error) {
|
||||
err = global.Db.Where(maps).Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// EditTestpaper12ById 修改-id
|
||||
func (r *Testpaper12Dao) EditTestpaper12ById(tx *gorm.DB, id int64, data interface{}) error {
|
||||
err := tx.Model(&model.Testpaper12{}).Where("id = ?", id).Updates(data).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"knowledge/api/model"
|
||||
"knowledge/utils"
|
||||
)
|
||||
|
||||
// AdminUserDto 后台-用户表
|
||||
type AdminUserDto struct {
|
||||
UserId string `json:"user_id"` // 主键id
|
||||
Access string `json:"access"` // 账号
|
||||
Password string `json:"password"` // 密码
|
||||
Salt string `json:"salt"` // 密码掩码
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
Status int `json:"status"` // 状态(1:正常 2:审核中 3:审核失败)
|
||||
IsDeleted int `json:"is_deleted"` // 是否被删除(0:否 1:是)
|
||||
IsDisabled int `json:"is_disabled"` // 是否被禁用(0:否 1:是)
|
||||
Phone string `json:"phone"` // 手机号
|
||||
Avatar string `json:"avatar"` // 头像
|
||||
Sex int `json:"sex"` // 性别(1:男 2:女)
|
||||
Email string `json:"email"` // 邮箱
|
||||
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
||||
UpdatedAt model.LocalTime `json:"updated_at"` // 修改时间
|
||||
Token string `json:"token"` // token
|
||||
}
|
||||
|
||||
func LoginDto(m *model.AdminUser) *AdminUserDto {
|
||||
return &AdminUserDto{
|
||||
UserId: fmt.Sprintf("%d", m.UserId),
|
||||
Access: m.Access,
|
||||
Status: m.Status,
|
||||
NickName: m.NickName,
|
||||
Avatar: utils.AddOssDomain(m.Avatar),
|
||||
Sex: m.Sex,
|
||||
Email: m.Email,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadUserDoctor 加载token
|
||||
func (r *AdminUserDto) LoadUserDoctor(t string) *AdminUserDto {
|
||||
if t != "" {
|
||||
r.Token = t
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"knowledge/api/model"
|
||||
)
|
||||
|
||||
// LabelDto 标签表
|
||||
type LabelDto struct {
|
||||
LabelId string `json:"label_id"` // 主键id
|
||||
LabelName string `json:"label_name"` // 标签名称
|
||||
ParentId string `json:"parent_id"` // 父级ID(0表示一级)
|
||||
LabelLevel int `json:"label_level"` // 级别(1:1级 2:2级 3:3级)
|
||||
CreatedAt model.LocalTime `json:"created_at"` // 创建时间
|
||||
UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间
|
||||
}
|
||||
|
||||
// GetLabelDto 标签详情
|
||||
func GetLabelDto(m *model.Label) *LabelDto {
|
||||
return &LabelDto{
|
||||
LabelId: fmt.Sprintf("%d", m.LabelId),
|
||||
LabelName: m.LabelName,
|
||||
ParentId: fmt.Sprintf("%d", m.ParentId),
|
||||
LabelLevel: m.LabelLevel,
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// GetLabelListDto 标签列表
|
||||
func GetLabelListDto(m []*model.Label) []*LabelDto {
|
||||
// 处理返回值
|
||||
responses := make([]*LabelDto, len(m))
|
||||
|
||||
if len(m) > 0 {
|
||||
for i, v := range m {
|
||||
response := &LabelDto{
|
||||
LabelId: fmt.Sprintf("%d", v.LabelId),
|
||||
LabelName: v.LabelName,
|
||||
ParentId: fmt.Sprintf("%d", v.ParentId),
|
||||
LabelLevel: v.LabelLevel,
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
}
|
||||
|
||||
// 将转换后的结构体添加到新切片中
|
||||
responses[i] = response
|
||||
}
|
||||
}
|
||||
|
||||
return responses
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"knowledge/api/model"
|
||||
)
|
||||
|
||||
// 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"` // 二级标签
|
||||
}
|
||||
|
||||
// GetQuestionDto 题目详情
|
||||
func GetQuestionDto(m *model.Question) *QuestionDto {
|
||||
return &QuestionDto{
|
||||
QuestionId: fmt.Sprintf("%d", m.QuestionId),
|
||||
QuestionName: m.QuestionName,
|
||||
QuestionType: m.QuestionType,
|
||||
QuestionStatus: m.QuestionStatus,
|
||||
IsDelete: m.IsDelete,
|
||||
QuestionSource: m.QuestionSource,
|
||||
QuestionAnswer: m.QuestionAnswer,
|
||||
QuestionAnalysis: m.QuestionAnalysis,
|
||||
Difficulty: m.Difficulty,
|
||||
FirstLabelId: fmt.Sprintf("%d", *m.FirstLabelId),
|
||||
SecondLabelId: fmt.Sprintf("%d", *m.SecondLabelId),
|
||||
CreatedAt: m.CreatedAt,
|
||||
UpdatedAt: m.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// GetQuestionListDto 题目列表
|
||||
func GetQuestionListDto(m []*model.Question) []*QuestionDto {
|
||||
// 处理返回值
|
||||
responses := make([]*QuestionDto, len(m))
|
||||
|
||||
if len(m) > 0 {
|
||||
for i, v := range m {
|
||||
response := &QuestionDto{
|
||||
QuestionId: fmt.Sprintf("%d", v.QuestionId),
|
||||
QuestionName: v.QuestionName,
|
||||
QuestionType: v.QuestionType,
|
||||
QuestionStatus: v.QuestionStatus,
|
||||
IsDelete: v.IsDelete,
|
||||
QuestionSource: v.QuestionSource,
|
||||
QuestionAnswer: v.QuestionAnswer,
|
||||
QuestionAnalysis: v.QuestionAnalysis,
|
||||
Difficulty: v.Difficulty,
|
||||
FirstLabelId: fmt.Sprintf("%d", *v.FirstLabelId),
|
||||
SecondLabelId: fmt.Sprintf("%d", *v.SecondLabelId),
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
}
|
||||
|
||||
// 加载一级标签
|
||||
if v.FirstLabel != nil {
|
||||
response = response.LoadFirstLabel(v.FirstLabel)
|
||||
}
|
||||
|
||||
fmt.Println(v.SecondLabel)
|
||||
// 加载二级标签
|
||||
if v.SecondLabel != nil {
|
||||
response = response.LoadSecondLabel(v.SecondLabel)
|
||||
}
|
||||
|
||||
// 将转换后的结构体添加到新切片中
|
||||
responses[i] = response
|
||||
}
|
||||
}
|
||||
|
||||
return responses
|
||||
}
|
||||
|
||||
// LoadFirstLabel 加载一级标签
|
||||
func (r *QuestionDto) LoadFirstLabel(m *model.Label) *QuestionDto {
|
||||
if m != nil {
|
||||
r.FirstLabel = GetLabelDto(m)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// LoadSecondLabel 加载二级标签
|
||||
func (r *QuestionDto) LoadSecondLabel(m *model.Label) *QuestionDto {
|
||||
if m != nil {
|
||||
r.SecondLabel = GetLabelDto(m)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package exception
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/consts"
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// Recover
|
||||
// @Description: 处理全局异常
|
||||
// @return gin.HandlerFunc
|
||||
func Recover() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// 打印错误堆栈信息
|
||||
log.Printf("panic: %v\n", r)
|
||||
debug.PrintStack()
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": consts.ServerError,
|
||||
"message": errorToString(r),
|
||||
"data": "",
|
||||
})
|
||||
// 终止后续接口调用,不加的话recover到异常后,还会继续执行接口里后续代码
|
||||
c.Abort()
|
||||
}
|
||||
}()
|
||||
// 加载完 defer recover,继续后续接口调用
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// recover错误,转string
|
||||
func errorToString(r interface{}) string {
|
||||
switch v := r.(type) {
|
||||
case error:
|
||||
return v.Error()
|
||||
default:
|
||||
return r.(string)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/api/dao"
|
||||
"knowledge/api/responses"
|
||||
)
|
||||
|
||||
// Auth Auth认证
|
||||
func Auth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 获取用户id
|
||||
userId := c.GetInt64("UserId")
|
||||
if userId == 0 {
|
||||
responses.Fail(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户数据
|
||||
adminUserDao := dao.AdminUserDao{}
|
||||
adminUser, err := adminUserDao.GetAdminUserFirstById(userId)
|
||||
if err != nil || adminUser == nil {
|
||||
responses.FailWithMessage("用户数据错误", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if adminUser.Status == 2 {
|
||||
responses.FailWithMessage("用户审核中", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if adminUser.Status == 3 {
|
||||
responses.FailWithMessage("用户已删除或禁用", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if adminUser.IsDisabled == 1 {
|
||||
responses.FailWithMessage("用户已禁用", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if adminUser.IsDeleted == 1 {
|
||||
responses.FailWithMessage("用户已删除", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Cors
|
||||
// @Description: 跨域中间件
|
||||
// @return gin.HandlerFunc
|
||||
func Cors() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
method := c.Request.Method
|
||||
origin := c.Request.Header.Get("Origin")
|
||||
if origin != "" {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
||||
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
|
||||
c.Header("Access-Control-Allow-Credentials", "false")
|
||||
c.Set("content-type", "application/json")
|
||||
}
|
||||
if method == "OPTIONS" {
|
||||
c.AbortWithStatus(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/consts"
|
||||
"knowledge/global"
|
||||
"knowledge/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Jwt jwt认证
|
||||
func Jwt() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
authorization := c.Request.Header.Get("Authorization")
|
||||
if authorization == "" || !strings.HasPrefix(authorization, "Bearer ") {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"message": "请求未授权",
|
||||
"code": consts.TokenError,
|
||||
"data": "",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 去除Bearer
|
||||
authorization = authorization[7:] // 截取字符
|
||||
|
||||
// 检测是否存在黑名单
|
||||
res, _ := global.Redis.Get(c, "jwt_black_"+authorization).Result()
|
||||
if res != "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "token错误/过期",
|
||||
"code": consts.TokenError,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 解析jwt
|
||||
t, err := utils.ParseJwt(authorization)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "token错误/过期",
|
||||
"code": consts.TokenError,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 转换类型
|
||||
userId, err := strconv.ParseInt(t.UserId, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "token错误",
|
||||
"code": consts.TokenError,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("UserId", userId) // 用户id
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"knowledge/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logrus 日志中间件
|
||||
func Logrus() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
// 开始时间
|
||||
startTime := time.Now()
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
// 获取 请求 参数
|
||||
params := make(map[string]string)
|
||||
|
||||
paramsRaw, ok := c.Get("params")
|
||||
if ok {
|
||||
requestParams, ok := paramsRaw.(map[string]string)
|
||||
if ok || len(requestParams) > 0 {
|
||||
params = requestParams
|
||||
}
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
endTime := time.Now()
|
||||
|
||||
// 执行时间
|
||||
latencyTime := fmt.Sprintf("%6v", endTime.Sub(startTime))
|
||||
|
||||
// 请求方式
|
||||
reqMethod := c.Request.Method
|
||||
|
||||
// 请求路由
|
||||
reqUri := c.Request.RequestURI
|
||||
|
||||
// 状态码
|
||||
statusCode := c.Writer.Status()
|
||||
|
||||
// 请求IP
|
||||
clientIP := c.ClientIP()
|
||||
|
||||
// 日志格式
|
||||
global.Logger.WithFields(logrus.Fields{
|
||||
"http_status": statusCode,
|
||||
"total_time": latencyTime,
|
||||
"ip": clientIP,
|
||||
"method": reqMethod,
|
||||
"uri": reqUri,
|
||||
"params": params,
|
||||
}).Info("access")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"knowledge/consts"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// RequestParamsMiddleware 获取请求参数中间件
|
||||
func RequestParamsMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
contentType := c.Request.Header.Get("Content-Type")
|
||||
|
||||
params := make(map[string]string)
|
||||
|
||||
// 判断请求参数类型
|
||||
switch contentType {
|
||||
case "application/json":
|
||||
// 解析 application/json 请求体
|
||||
bodyBytes, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read request body"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 创建新的请求对象,并设置请求体数据
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
|
||||
var jsonParams map[string]interface{}
|
||||
err = json.Unmarshal(bodyBytes, &jsonParams)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"message": "Invalid JSON data",
|
||||
"code": consts.HttpError,
|
||||
"data": "",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
for key, value := range jsonParams {
|
||||
params[key] = fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
// 存储参数到上下文
|
||||
c.Set("params", params)
|
||||
|
||||
case "multipart/form-data", "application/form-data", "application/x-www-form-urlencoded":
|
||||
// 解析 Form 表单参数
|
||||
err := c.Request.ParseForm()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"message": "Invalid form data",
|
||||
"code": consts.HttpError,
|
||||
"data": "",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
for key, values := range c.Request.Form {
|
||||
if len(values) > 0 {
|
||||
params[key] = fmt.Sprintf("%v", values[0])
|
||||
}
|
||||
}
|
||||
|
||||
// 存储参数到上下文
|
||||
c.Set("params", params)
|
||||
|
||||
default:
|
||||
// 解析 URL 参数
|
||||
queryParams := c.Request.URL.Query()
|
||||
|
||||
for key, values := range queryParams {
|
||||
if len(values) > 0 {
|
||||
params[key] = fmt.Sprintf("%v", values[0])
|
||||
}
|
||||
}
|
||||
|
||||
// 存储参数到上下文
|
||||
c.Set("params", params)
|
||||
}
|
||||
|
||||
// 继续处理请求
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AdminUser 后台-用户表
|
||||
type AdminUser struct {
|
||||
UserId int64 `gorm:"column:user_id;type:bigint(20);primary_key;comment:主键id" json:"user_id"`
|
||||
Access string `gorm:"column:access;type:varchar(64);comment:账号;NOT NULL" json:"access"`
|
||||
Password string `gorm:"column:password;type:varchar(128);comment:密码;NOT NULL" json:"password"`
|
||||
Salt string `gorm:"column:salt;type:varchar(255);comment:密码掩码;NOT NULL" json:"salt"`
|
||||
NickName string `gorm:"column:nick_name;type:varchar(255);comment:昵称" json:"nick_name"`
|
||||
Status int `gorm:"column:status;type:tinyint(1);default:2;comment:状态(1:正常 2:审核中 3:审核失败)" json:"status"`
|
||||
IsDeleted int `gorm:"column:is_deleted;type:tinyint(1);default:0;comment:是否被删除(0:否 1:是)" json:"is_deleted"`
|
||||
IsDisabled int `gorm:"column:is_disabled;type:tinyint(1);default:0;comment:是否被禁用(0:否 1:是)" json:"is_disabled"`
|
||||
Phone string `gorm:"column:phone;type:varchar(11);comment:手机号" json:"phone"`
|
||||
Avatar string `gorm:"column:avatar;type:varchar(255);comment:头像" json:"avatar"`
|
||||
Sex int `gorm:"column:sex;type:tinyint(1);comment:性别(1:男 2:女)" json:"sex"`
|
||||
Email string `gorm:"column:email;type:varchar(100);comment:邮箱" json:"email"`
|
||||
Model
|
||||
}
|
||||
|
||||
func (m *AdminUser) TableName() string {
|
||||
return "kb_admin_user"
|
||||
}
|
||||
|
||||
func (m *AdminUser) BeforeCreate(tx *gorm.DB) error {
|
||||
if m.UserId == 0 {
|
||||
m.UserId = global.Snowflake.Generate().Int64()
|
||||
}
|
||||
|
||||
m.CreatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("CreatedAt", m.CreatedAt)
|
||||
|
||||
m.UpdatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Label 标签表
|
||||
type Label struct {
|
||||
LabelId int64 `gorm:"column:label_id;type:bigint(19);primary_key;comment:主键id" json:"label_id"`
|
||||
LabelName string `gorm:"column:label_name;type:varchar(255);comment:标签名称" json:"label_name"`
|
||||
ParentId int64 `gorm:"column:parent_id;type:bigint(19);comment:父级ID(0表示一级)" json:"parent_id"`
|
||||
LabelLevel int `gorm:"column:label_level;type:tinyint(1);default:1;comment:级别(1:1级 2:2级 3:3级)" json:"label_level"`
|
||||
Model
|
||||
}
|
||||
|
||||
func (m *Label) TableName() string {
|
||||
return "kb_label"
|
||||
}
|
||||
|
||||
func (m *Label) BeforeCreate(tx *gorm.DB) error {
|
||||
if m.LabelId == 0 {
|
||||
m.LabelId = global.Snowflake.Generate().Int64()
|
||||
}
|
||||
|
||||
m.CreatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("CreatedAt", m.CreatedAt)
|
||||
|
||||
m.UpdatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Question 题目表(单选-多选-问答-判断)
|
||||
type Question struct {
|
||||
QuestionId int64 `gorm:"column:question_id;type:bigint(19);primary_key;comment:主键id" json:"question_id"`
|
||||
QuestionName string `gorm:"column:question_name;type:varchar(1000);comment:题目名称;NOT NULL" json:"question_name"`
|
||||
QuestionType int `gorm:"column:question_type;type:tinyint(1);default:1;comment:题目类型(1:单选 2:多选 3:问答 4:判断);NOT NULL" json:"question_type"`
|
||||
QuestionStatus int `gorm:"column:question_status;type:tinyint(1);default:1;comment:状态(1:正常 2:禁用)" json:"question_status"`
|
||||
IsDelete int `gorm:"column:is_delete;type:tinyint(1);default:0;comment:是否删除(0:否 1:是)" json:"is_delete"`
|
||||
QuestionSource int `gorm:"column:question_source;type:tinyint(1);comment:题目来源(1:本题库 2:外部数据);NOT NULL" json:"question_source"`
|
||||
QuestionImage string `gorm:"column:question_image;type:varchar(500);comment:题目图片(逗号分隔)" json:"question_image"`
|
||||
QuestionAnswer string `gorm:"column:question_answer;type:varchar(255);comment:答案" json:"question_answer"`
|
||||
QuestionAnalysis string `gorm:"column:question_analysis;type:text;comment:解析" json:"question_analysis"`
|
||||
Difficulty int `gorm:"column:difficulty;type:tinyint(1);default:0;comment:难度(0:未知 1:低 2:中 3:高)" json:"difficulty"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func (m *Question) TableName() string {
|
||||
return "kb_question"
|
||||
}
|
||||
|
||||
func (m *Question) BeforeCreate(tx *gorm.DB) error {
|
||||
if m.QuestionId == 0 {
|
||||
m.QuestionId = global.Snowflake.Generate().Int64()
|
||||
}
|
||||
|
||||
m.CreatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("CreatedAt", m.CreatedAt)
|
||||
|
||||
m.UpdatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"knowledge/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// QuestionOption 题目选项表
|
||||
type QuestionOption struct {
|
||||
OptionId int64 `gorm:"column:option_id;type:bigint(19);primary_key;comment:主键id" json:"option_id"`
|
||||
QuestionId int64 `gorm:"column:question_id;type:bigint(19);comment:题目id" json:"question_id"`
|
||||
OptionValue string `gorm:"column:option_value;type:varchar(255);comment:选项内容" json:"option_value"`
|
||||
Model
|
||||
}
|
||||
|
||||
func (m *QuestionOption) TableName() string {
|
||||
return "kb_question_option"
|
||||
}
|
||||
|
||||
func (m *QuestionOption) BeforeCreate(tx *gorm.DB) error {
|
||||
if m.OptionId == 0 {
|
||||
m.OptionId = global.Snowflake.Generate().Int64()
|
||||
}
|
||||
|
||||
m.CreatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("CreatedAt", m.CreatedAt)
|
||||
|
||||
m.UpdatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Testpaper12 struct {
|
||||
Id uint64 `gorm:"column:id;type:bigint(20) unsigned;primary_key;AUTO_INCREMENT" json:"id"`
|
||||
StemType string `gorm:"column:stem_type;type:varchar(1000);comment:题干名称" json:"stem_type"`
|
||||
Name string `gorm:"column:name;type:varchar(1000);comment:题目名称" json:"name"`
|
||||
Item string `gorm:"column:item;type:varchar(1000);comment:选项" json:"item"`
|
||||
Answer string `gorm:"column:answer;type:varchar(1000);comment:答案" json:"answer"`
|
||||
Explain string `gorm:"column:explain;type:varchar(2000);comment:解析" json:"explain"`
|
||||
QuestionType uint `gorm:"column:question_type;type:tinyint(4) unsigned;comment:题目类型" json:"question_type"`
|
||||
Level uint `gorm:"column:level;type:tinyint(4) unsigned;comment:难易程度" json:"level"`
|
||||
KnowledgeType uint `gorm:"column:knowledge_type;type:tinyint(4) unsigned;comment:知识题库分类" json:"knowledge_type"`
|
||||
PaperUuid string `gorm:"column:paper_uuid;type:varchar(50);comment:所属paper;NOT NULL" json:"paper_uuid"`
|
||||
CreateDate time.Time `gorm:"column:create_date;type:datetime" json:"create_date"`
|
||||
IsMigrate uint `gorm:"column:is_migrate;type:tinyint(4) unsigned;comment:是否迁移" json:"is_migrate"`
|
||||
}
|
||||
|
||||
func (m *Testpaper12) TableName() string {
|
||||
return "tb_testpaper12"
|
||||
}
|
||||
|
||||
func (m *Testpaper12) BeforeCreate(tx *gorm.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
CreatedAt LocalTime `gorm:"column:created_at;type:datetime;comment:创建时间" json:"created_at"`
|
||||
UpdatedAt LocalTime `gorm:"column:updated_at;type:datetime;comment:修改时间" json:"updated_at"`
|
||||
}
|
||||
|
||||
// LocalTime 自定义数据类型
|
||||
type LocalTime time.Time
|
||||
|
||||
func (t *LocalTime) UnmarshalJSON(data []byte) error {
|
||||
if string(data) == "null" {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
// 前端接收的时间字符串
|
||||
str := string(data)
|
||||
// 去除接收的str收尾多余的"
|
||||
timeStr := strings.Trim(str, "\"")
|
||||
t1, err := time.Parse("2006-01-02 15:04:05", timeStr)
|
||||
*t = LocalTime(t1)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t LocalTime) MarshalJSON() ([]byte, error) {
|
||||
formatted := fmt.Sprintf("\"%v\"", time.Time(t).Format("2006-01-02 15:04:05"))
|
||||
return []byte(formatted), nil
|
||||
}
|
||||
|
||||
func (t LocalTime) Value() (driver.Value, error) {
|
||||
// MyTime 转换成 time.Time 类型
|
||||
tTime := time.Time(t)
|
||||
return tTime.Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
|
||||
func (t *LocalTime) Scan(v interface{}) error {
|
||||
switch vt := v.(type) {
|
||||
case time.Time:
|
||||
// 字符串转成 time.Time 类型
|
||||
*t = LocalTime(vt)
|
||||
default:
|
||||
return errors.New("类型处理错误")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *LocalTime) String() string {
|
||||
return fmt.Sprintf("hhh:%s", time.Time(*t).String())
|
||||
}
|
||||
|
||||
func (t *LocalTime) IsEmpty() bool {
|
||||
return time.Time(*t).IsZero()
|
||||
}
|
||||
|
||||
func (m *Model) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||
m.UpdatedAt = LocalTime(time.Now())
|
||||
tx.Statement.SetColumn("UpdatedAt", m.UpdatedAt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
switch {
|
||||
case pageSize > 100:
|
||||
pageSize = 100
|
||||
case pageSize <= 0:
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
return db.Offset(offset).Limit(pageSize)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package requests
|
||||
|
||||
type AdminUserRequest struct {
|
||||
Login // 登陆
|
||||
}
|
||||
|
||||
// Login 登陆
|
||||
type Login struct {
|
||||
Access string `json:"access" form:"access" validate:"required" label:"用户名"` // 用户名
|
||||
Password string `json:"password" form:"password" validate:"required" label:"密码"` // 密码
|
||||
Captcha string `json:"captcha" form:"captcha" validate:"required" label:"验证码"` // 验证码
|
||||
CaptchaId string `json:"captchaId" form:"captchaId" validate:"required"` // 验证码ID
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package requests
|
||||
|
||||
type Requests struct {
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package requests
|
||||
|
||||
type QuestionRequest struct {
|
||||
GetQuestionPage // 获取题目列表-分页
|
||||
AddQuestion // 新增题目
|
||||
}
|
||||
|
||||
// GetQuestionPage 获取题目列表-分页
|
||||
type GetQuestionPage struct {
|
||||
Page int `json:"page" form:"page" label:"页码"`
|
||||
PageSize int `json:"page_size" form:"page_size" label:"每页个数"`
|
||||
QuestionId string `json:"question_id" form:"question_id" label:"主键id"`
|
||||
QuestionName string `json:"question_name" form:"question_name" label:"题目名称"`
|
||||
QuestionType int `json:"question_type" form:"question_type" validate:"required,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:"required,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"`
|
||||
CreatedAt string `json:"created_at" form:"created_at" label:"创建时间"`
|
||||
UpdatedAt string `json:"updated_at" form:"updated_at" label:"修改时间"`
|
||||
Order *GetQuestionPageOrder `json:"order" form:"order" label:"排序"`
|
||||
}
|
||||
|
||||
// GetQuestionPageOrder 获取题目列表-分页-排序条件
|
||||
type GetQuestionPageOrder struct {
|
||||
UpdatedAt string `json:"updated_at" form:"updated_at" label:"排序" validate:"oneof=desc asc"`
|
||||
}
|
||||
|
||||
// AddQuestion 新增题目
|
||||
type AddQuestion struct {
|
||||
QuestionName string `json:"question_name" form:"question_name" validate:"required" label:"题目名称"`
|
||||
QuestionType int `json:"question_type" form:"question_type" validate:"required,oneof=1 2 3 4" label:"题目类型"` // 题目类型(1:单选 2:多选 3:问答 4:判断)
|
||||
QuestionStatus int `json:"question_status" form:"question_status" validate:"required,oneof=1 2" label:"状态"` // 状态(1:正常 2:禁用)
|
||||
QuestionSource int `json:"question_source" form:"question_source" validate:"required,oneof=1 2" label:"题目来源"` // 题目来源(1:本题库 2:外部数据)
|
||||
QuestionAnswer string `json:"question_answer" form:"question_answer" validate:"required" label:"答案"`
|
||||
QuestionAnalysis string `json:"question_analysis" form:"question_analysis" label:"解析"`
|
||||
Difficulty int `json:"difficulty" form:"difficulty" validate:"required,oneof=1 2 3" label:"难度"`
|
||||
FirstLabelId string `json:"first_label_id" form:"first_label_id" validate:"required" label:"一级标签id"`
|
||||
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:"选项"`
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package responses
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/consts"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type res struct {
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func result(code int, data interface{}, msg string, c *gin.Context) {
|
||||
if data == nil {
|
||||
data = gin.H{}
|
||||
}
|
||||
c.JSON(http.StatusOK, res{
|
||||
code,
|
||||
data,
|
||||
msg,
|
||||
})
|
||||
}
|
||||
|
||||
func Ok(c *gin.Context) {
|
||||
result(consts.HttpSuccess, map[string]interface{}{}, "成功", c)
|
||||
}
|
||||
|
||||
func OkWithMessage(message string, c *gin.Context) {
|
||||
result(consts.HttpSuccess, map[string]interface{}{}, message, c)
|
||||
}
|
||||
|
||||
func OkWithData(data interface{}, c *gin.Context) {
|
||||
result(consts.HttpSuccess, data, "成功", c)
|
||||
}
|
||||
|
||||
func OkWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
result(consts.HttpSuccess, data, message, c)
|
||||
}
|
||||
|
||||
func Fail(c *gin.Context) {
|
||||
result(consts.HttpError, map[string]interface{}{}, "失败", c)
|
||||
}
|
||||
|
||||
func FailWithMessage(message string, c *gin.Context) {
|
||||
result(consts.HttpError, map[string]interface{}{}, message, c)
|
||||
}
|
||||
|
||||
func FailWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
result(consts.HttpError, data, message, c)
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"knowledge/api/controller"
|
||||
"knowledge/api/exception"
|
||||
"knowledge/api/middlewares"
|
||||
"knowledge/config"
|
||||
"knowledge/consts"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Init 初始化路由
|
||||
func Init() *gin.Engine {
|
||||
r := gin.New()
|
||||
|
||||
// 环境设置
|
||||
if config.C.Env == "prod" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// 获取请求参数中间件-json格式下会导致接口获取不到请求数据
|
||||
r.Use(middlewares.RequestParamsMiddleware())
|
||||
|
||||
// 日志中间件
|
||||
r.Use(middlewares.Logrus())
|
||||
|
||||
// 异常
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
// 404处理
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
path := c.Request.URL.Path
|
||||
method := c.Request.Method
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"msg": fmt.Sprintf("%s %s not found", method, path),
|
||||
"code": consts.ClientHttpNotFound,
|
||||
"data": "",
|
||||
})
|
||||
})
|
||||
|
||||
// 异常处理
|
||||
r.Use(exception.Recover())
|
||||
|
||||
// 跨域处理
|
||||
r.Use(middlewares.Cors())
|
||||
|
||||
// 加载基础路由
|
||||
api := controller.Api{}
|
||||
|
||||
// 公开路由-不验证权限
|
||||
publicRouter(r, api)
|
||||
|
||||
// 验证jwt
|
||||
r.Use(middlewares.Jwt())
|
||||
|
||||
// 验证权限
|
||||
r.Use(middlewares.Auth())
|
||||
|
||||
// 私有路由-验证权限
|
||||
privateRouter(r, api)
|
||||
|
||||
// 公共路由-验证权限
|
||||
adminRouter(r, api)
|
||||
|
||||
// 基础数据-验证权限
|
||||
basicRouter(r, api)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// publicRouter 公开路由-不验证权限
|
||||
func publicRouter(r *gin.Engine, api controller.Api) {
|
||||
migrateGroup := r.Group("/migrate")
|
||||
{
|
||||
migrateGroup.GET("", api.Migrate.Migrate)
|
||||
}
|
||||
|
||||
adminGroup := r.Group("/admin")
|
||||
|
||||
// 验证码
|
||||
adminGroup.GET("/captcha", api.Public.GetCaptcha)
|
||||
|
||||
// 登陆
|
||||
adminGroup.POST("/login", api.AdminUser.Login)
|
||||
}
|
||||
|
||||
// adminRouter 公共路由-验证权限
|
||||
func adminRouter(r *gin.Engine, api controller.Api) {
|
||||
|
||||
}
|
||||
|
||||
// basicRouter 基础数据-验证权限
|
||||
func basicRouter(r *gin.Engine, api controller.Api) {
|
||||
|
||||
}
|
||||
|
||||
// privateRouter 私有路由-验证权限
|
||||
func privateRouter(r *gin.Engine, api controller.Api) {
|
||||
adminGroup := r.Group("/admin")
|
||||
|
||||
// 题目
|
||||
questionGroup := adminGroup.Group("/question")
|
||||
{
|
||||
// 获取题目列表-分页
|
||||
questionGroup.POST("/page", api.Question.GetQuestionPage)
|
||||
|
||||
// 新增题目
|
||||
questionGroup.POST("", api.Question.AddQuestion)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"knowledge/api/dao"
|
||||
"knowledge/api/dto"
|
||||
"knowledge/api/requests"
|
||||
"knowledge/utils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AdminUserService 后台用户
|
||||
type AdminUserService struct {
|
||||
}
|
||||
|
||||
func (r *AdminUserService) Login(req requests.Login) (res *dto.AdminUserDto, err error) {
|
||||
// 获取用户信息
|
||||
AdminUserDao := dao.AdminUserDao{}
|
||||
adminUser, err := AdminUserDao.GetAdminUserFirstByAccess(req.Access)
|
||||
if err != nil || adminUser == nil {
|
||||
return nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
// 检测用户密码
|
||||
password := md5.Sum([]byte(req.Password + adminUser.Salt))
|
||||
// 将哈希值转换为16进制字符串
|
||||
passwordString := hex.EncodeToString(password[:])
|
||||
|
||||
if passwordString != adminUser.Password {
|
||||
return nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
// 检测用户状态
|
||||
if adminUser.IsDeleted == 1 {
|
||||
return nil, errors.New("非法用户")
|
||||
}
|
||||
|
||||
if adminUser.IsDisabled == 1 {
|
||||
return nil, errors.New("您的账号已被禁用,请联系管理员处理")
|
||||
}
|
||||
|
||||
// 检测用户状态
|
||||
if adminUser.Status != 1 {
|
||||
return nil, errors.New("您的账号已被禁用,请联系管理员处理")
|
||||
}
|
||||
|
||||
token := &utils.Token{
|
||||
UserId: strconv.FormatInt(adminUser.UserId, 10),
|
||||
}
|
||||
|
||||
// 生成jwt
|
||||
jwt, err := token.NewJWT()
|
||||
if err != nil {
|
||||
return nil, errors.New("登陆失败")
|
||||
}
|
||||
|
||||
// 处理返回值
|
||||
g := dto.LoginDto(adminUser)
|
||||
|
||||
// 加载token
|
||||
g.LoadUserDoctor(jwt)
|
||||
|
||||
return g, nil
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"knowledge/api/dao"
|
||||
"knowledge/api/model"
|
||||
"knowledge/api/requests"
|
||||
"knowledge/global"
|
||||
"knowledge/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type QuestionService struct {
|
||||
}
|
||||
|
||||
// AddQuestion 新增题目
|
||||
func (r *QuestionService) AddQuestion(req requests.AddQuestion) (bool, error) {
|
||||
// 验证一级标签
|
||||
firstLabelId, err := strconv.ParseInt(req.FirstLabelId, 10, 64)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
labelDao := dao.LabelDao{}
|
||||
_, err = labelDao.GetLabelFirstById(firstLabelId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 验证二级标签
|
||||
var secondLabelId int64
|
||||
if req.SecondLabelId != "" {
|
||||
secondLabelId, err := strconv.ParseInt(req.SecondLabelId, 10, 64)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err = labelDao.GetLabelFirstById(secondLabelId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// 处理图片
|
||||
var questionImage string
|
||||
if len(req.QuestionImage) > 0 {
|
||||
result := make([]string, len(req.QuestionImage))
|
||||
for i, url := range req.QuestionImage {
|
||||
result[i] = utils.RemoveOssDomain(url)
|
||||
}
|
||||
|
||||
questionImage = strings.Join(result, ",")
|
||||
}
|
||||
|
||||
// 判断选项
|
||||
if req.QuestionType == 1 || req.QuestionType == 2 {
|
||||
if len(req.QuestionOption) == 0 {
|
||||
return false, errors.New("请填入选项")
|
||||
}
|
||||
}
|
||||
|
||||
// 验证重复
|
||||
questionDao := dao.QuestionDao{}
|
||||
|
||||
maps := make(map[string]interface{})
|
||||
maps["question_name"] = req.QuestionName
|
||||
question, _ := questionDao.GetQuestion(maps)
|
||||
if question != nil {
|
||||
return false, errors.New("题目名称重复")
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
tx := global.Db.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
// 新增题目
|
||||
question = &model.Question{
|
||||
QuestionName: req.QuestionName,
|
||||
QuestionType: req.QuestionType,
|
||||
QuestionStatus: req.QuestionStatus,
|
||||
QuestionSource: req.QuestionSource,
|
||||
QuestionImage: questionImage,
|
||||
QuestionAnswer: req.QuestionAnswer,
|
||||
QuestionAnalysis: req.QuestionAnalysis,
|
||||
Difficulty: req.Difficulty,
|
||||
FirstLabelId: &firstLabelId,
|
||||
SecondLabelId: nil,
|
||||
}
|
||||
|
||||
if req.SecondLabelId != "" {
|
||||
question.SecondLabelId = &secondLabelId
|
||||
}
|
||||
|
||||
question, err = questionDao.AddQuestion(tx, question)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return false, errors.New("新增失败")
|
||||
}
|
||||
|
||||
// 新增选项
|
||||
questionOptionDao := dao.QuestionOptionDao{}
|
||||
for _, s := range req.QuestionOption {
|
||||
questionOption := &model.QuestionOption{
|
||||
QuestionId: question.QuestionId,
|
||||
OptionValue: s,
|
||||
}
|
||||
|
||||
questionOption, err := questionOptionDao.AddQuestionOption(tx, questionOption)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return false, errors.New("新增失败")
|
||||
}
|
||||
}
|
||||
|
||||
//tx.Commit()
|
||||
return true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user