Compare commits

...

6 Commits

Author SHA1 Message Date
Eg
569e6618a8 🎨 新增路由||优化返回数据结构 2022-06-02 16:22:36 +08:00
Eg
fb5f8ca2a5 🎨 新增获取用户详情接口 2022-06-02 16:22:01 +08:00
Eg
090acb0454 🎨 新增获取提交列表接口 2022-06-02 16:21:42 +08:00
Eg
991165125f 🎨 优化问题列表接口 2022-06-02 16:21:08 +08:00
Eg
6945e6db93 🎨 优化model和日志,完善配置文件 2022-05-26 23:53:18 +08:00
Eg
8c5fa60081 🎨 优化model 2022-05-26 15:40:21 +08:00
26 changed files with 225 additions and 75 deletions

2
.env
View File

@@ -1,3 +1,5 @@
LOG_FILE_ENABLE=1
# Nacos配置
NACOS_HOST=127.0.0.1
NACOS_PORT=8848

View File

@@ -5,7 +5,6 @@ import (
"online_code/core"
"online_code/models/param"
"online_code/repository"
"online_code/utils"
)
type problemApi struct{}
@@ -26,8 +25,7 @@ func (problemApi) GetProbleList(ctx *gin.Context) {
core.R(ctx).FailWithMessage("获取题目列表失败: " + err.Error())
return
}
// 计算总页码
totalPage := utils.GenTotalPage(count, p.Size)
// 返回结果
core.R(ctx).OkWithData(core.PageData{Current: p.Current, Size: p.Size, Total: count, TotalPage: totalPage, Records: records})
core.R(ctx).OkDataPage(count, core.PageData{Current: p.Current, Size: p.Size, Total: count, Records: records})
}

31
api/submit.go Normal file
View File

@@ -0,0 +1,31 @@
package api
import (
"github.com/gin-gonic/gin"
"online_code/core"
"online_code/models/param"
"online_code/repository"
)
type submitApi struct{}
func SubmitApi() *submitApi {
return &submitApi{}
}
func (submitApi) GetSubmitList(c *gin.Context) {
var p param.GetSubmitList
if err := c.ShouldBind(&p); err != nil {
core.R(c).FailWithMessage("参数错误: " + err.Error())
return
}
records, count, err := repository.SubmitService().GetList(p)
if err != nil {
core.R(c).FailWithMessage("获取提交列表失败: " + err.Error())
return
}
// 返回结果
core.R(c).OkDataPage(count, core.PageData{Current: p.Current, Size: p.Size, Total: count, Records: records})
}

32
api/user.go Normal file
View File

@@ -0,0 +1,32 @@
package api
import (
"github.com/gin-gonic/gin"
"online_code/client"
"online_code/core"
"online_code/models/entity"
)
type userApi struct{}
func UserApi() *userApi {
return &userApi{}
}
// GetUserInfo 获取用户详情
func (userApi) GetUserInfo(ctx *gin.Context) {
// 获取用户信息
identity := ctx.Param("identity")
if identity == "" {
core.R(ctx).FailWithMessage("参数不能为空: identity")
return
}
userData := entity.UserBasic{}
err := client.MySQL.Omit("password").Where("identity = ?", identity).Take(&userData).Error
if err != nil {
core.R(ctx).FailWithMessage("获取用户信息失败: " + err.Error())
return
}
core.R(ctx).OkWithData(userData)
}

View File

@@ -13,11 +13,21 @@ var MySQL *gorm.DB
func InitMySQLClient() {
// 创建连接对象
conn, err := gorm.Open(mysql.Open(config.Scd.MySQL.GetDSN()), &gorm.Config{Logger: logger.DefaultGormLogger()})
mysqlConfig := mysql.Config{
DSN: config.Scd.MySQL.GetDSN(),
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式
DontSupportRenameColumn: true, // 用 `change` 重命名列
}
conn, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{Logger: logger.DefaultGormLogger()})
if err != nil {
log.Panic("初始化MySQL连接失败, 错误信息: %v", err)
} else {
log.Debug("MySQL连接成功")
}
MySQL = conn
//db, err := conn.DB()
//db.SetMaxIdleConns(10) // 用于设置连接池中空闲连接的最大数量
//db.SetMaxOpenConns(100) // 用于设置数据库连接的最大打开数量
//db.SetConnMaxLifetime(time.Hour) // 设置连接的最大存活时间
}

View File

@@ -1,20 +1,20 @@
package types
import (
"github.com/google/uuid"
"gorm.io/gorm"
"time"
)
// BaseDbModel 数据库通用字段
type BaseDbModel struct {
Id string `json:"id" gorm:"type:varchar(50);primarykey"`
CreatedAt DateTime `json:"createdAt"`
UpdatedAt DateTime `json:"updatedAt"`
ID uint `gorm:"type:int(11);primarykey;" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index:deleted"`
}
// BeforeCreate 创建数据库对象之前生成UUID
/*// BeforeCreate 创建数据库对象之前生成UUID
func (m *BaseDbModel) BeforeCreate(*gorm.DB) (err error) {
m.Id = uuid.New().String()
return
}
}*/

View File

@@ -1,4 +1,4 @@
app:
api:
port: 8083
name: online_code
version: v1
@@ -15,5 +15,5 @@ mysql:
redis:
host: 127.0.0.1
port: 6379
password: loser123
password: loser7659
db: 0

View File

@@ -3,6 +3,7 @@ package core
import (
"github.com/gin-gonic/gin"
"net/http"
"online_code/utils"
)
// 返回数据包装
@@ -59,6 +60,15 @@ func (r rs) OkDetailed(data interface{}, message string) {
r.Result(SUCCESS, data, message)
}
// OkDataPage 返回分页数据
func (r rs) OkDataPage(count int64, page PageData) {
// 计算总页码
totalPage := utils.GenTotalPage(count, page.Size)
page.TotalPage = totalPage
// 返回结果
r.Result(SUCCESS, page, "操作成功")
}
// Fail 返回默认失败
func (r rs) Fail() {
r.Result(ERROR, nil, "操作失败")

1
go.mod
View File

@@ -9,7 +9,6 @@ require (
github.com/fsnotify/fsnotify v1.5.1
github.com/gin-gonic/gin v1.7.7
github.com/go-redis/redis/v8 v8.11.5
github.com/google/uuid v1.1.2
github.com/spf13/viper v1.10.1
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c

View File

@@ -9,12 +9,12 @@ import (
// 初始化数据库表
func databaseTable() {
dbs := []any{
new(entity.User),
new(entity.Category),
new(entity.Problem),
new(entity.ProblemCategory),
new(entity.Submit),
new(entity.UserBasic),
new(entity.TestCase),
new(entity.CategoryBasic),
new(entity.ProblemCategory),
//new(entity.ProblemBasic),
//new(entity.SubmitBasic),
}
if err := client.MySQL.AutoMigrate(dbs...); err != nil {

View File

@@ -2,18 +2,25 @@ package main
import (
"fmt"
"git.echol.cn/loser/logger"
"git.echol.cn/loser/logger/log"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
"net/http"
"online_code/config"
"online_code/core"
"online_code/initialize"
"online_code/route"
"time"
)
var g errgroup.Group
func init() {
logger.InitLogger(logger.LogConfig{Mode: logger.Dev, LokiEnable: false, FileEnable: true})
initialize.InitSystem() // 初始化系统配置
}
// 启动入口
func main() {
// 强制日志颜色化

View File

@@ -2,14 +2,14 @@ package entity
import "online_code/common/types"
// Category 分类表
type Category struct {
// CategoryBasic 分类表
type CategoryBasic struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'分类的唯一标识'"`
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'问题表的唯一标识'"`
Name string `json:"name" gorm:"column:name;type:varchar(100);comment:'分类名称'" `
ParentId int `json:"parent_id" gorm:"column:parent_id;type:int(11);comment:'父级ID'" `
}
func (table *Category) TableName() string {
return "category"
func (table *CategoryBasic) TableName() string {
return "category_basic"
}

View File

@@ -1,21 +0,0 @@
package entity
import "online_code/common/types"
// Problem 问题表
type Problem struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'问题表的唯一标识'" ` // 问题表的唯一标识
ProblemCategories []*ProblemCategory `json:"problem_categories" gorm:"foreignKey:problem_id;references:id;comment:'关联问题分类表'" ` // 关联问题分类表
Title string `json:"title" gorm:"column:title;type:varchar(255);comment:'文章标题'" ` // 文章标题
Content string `json:"content" gorm:"column:content;type:text;comment:'文章正文'" ` // 文章正文
MaxRuntime int `json:"max_runtime" gorm:"column:max_runtime;type:int(11);comment:'最大运行时长'" ` // 最大运行时长
MaxMem int `json:"max_mem" gorm:"column:max_mem;type:int(11);comment:'最大运行内存'" ` // 最大运行内存
TestCases []*TestCase `json:"test_cases" gorm:"foreignKey:problem_identity;references:identity;comment:'关联测试用例表'" ` // 关联测试用例表
PassNum int64 `json:"pass_num" gorm:"column:pass_num;type:int(11);comment:'通过次数'" ` // 通过次数
SubmitNum int64 `json:"submit_num" gorm:"column:submit_num;type:int(11);comment:'提交次数'" ` // 提交次数
}
func (table *Problem) TableName() string {
return "problem_basic"
}

View File

@@ -0,0 +1,21 @@
package entity
import "online_code/common/types"
// ProblemBasic 问题基础表
type ProblemBasic struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'问题表的唯一标识'"` // 问题表的唯一标识
ProblemCategories []ProblemCategory `json:"problem_categories" gorm:"ForeignKey:ProblemId;comment:'关联问题分类表'"` // 关联问题分类表
Title string `json:"title" gorm:"column:title;type:varchar(255);comment:'文章标题'"` // 文章标题
Content string `json:"content" gorm:"column:content;type:text;comment:'文章正文'"` // 文章正文
MaxRuntime int `json:"max_runtime" gorm:"column:max_runtime;type:int(11);comment:'最大运行时长'"` // 最大运行时长
MaxMem int `json:"max_mem" gorm:"column:max_mem;type:int(11);comment:'最大运行内存'"` // 最大运行内存
TestCases []TestCase `json:"test_cases" gorm:"foreignKey:ProblemIdentity;comment:'关联测试用例表'"` // 关联测试用例表
PassNum int64 `json:"pass_num" gorm:"column:pass_num;type:int(11);comment:'通过次数'"` // 通过次数
SubmitNum int64 `json:"submit_num" gorm:"column:submit_num;type:int(11);comment:'提交次数'"` // 提交次数
}
func (table *ProblemBasic) TableName() string {
return "problem_basic"
}

View File

@@ -7,9 +7,9 @@ import (
// ProblemCategory 问题分类关联表
type ProblemCategory struct {
types.BaseDbModel
ProblemId uint `json:"problem_id" gorm:"column:problem_id;type:int(11);comment:'问题的ID'" ` // 问题的ID
CategoryId uint `json:"category_id" gorm:"column:category_id;type:int(11);comment:'分类的ID'" ` // 分类的ID
CategoryBasic *Category `json:"category_basic" gorm:"foreignKey:id;references:category_id;comment:'关联分类的基础信息表'" ` // 关联分类的基础信息表
ProblemId uint `json:"problem_id" gorm:"column:problem_id;type:int(11);comment:'问题的ID'" ` // 问题的ID
CategoryId uint `json:"category_id" gorm:"column:category_id;type:int(11);comment:'分类的ID'" ` // 分类的ID
CategoryBasic *CategoryBasic `json:"category_basic" gorm:"foreignKey:CategoryId;comment:'关联分类的基础信息表'" ` // 关联分类的基础信息表
}
func (table *ProblemCategory) TableName() string {

View File

@@ -1,16 +0,0 @@
package entity
// Submit 提交表
type Submit struct {
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'用户唯一标识'" ` // 唯一标识
ProblemIdentity string `json:"problem_identity" gorm:"column:problem_identity;type:varchar(36);comment:'问题表的唯一标识'" ` // 问题表的唯一标识
ProblemBasic *Problem `json:"problem_basic" gorm:"foreignKey:identity;references:problem_identity;comment:'关联问题基础表'" ` // 关联问题基础表
UserIdentity string `json:"user_identity" gorm:"column:user_identity;type:varchar(36);comment:'用户表的唯一标识'" ` // 用户表的唯一标识
UserBasic *User `json:"user_basic" gorm:"foreignKey:identity;references:user_identity;comment:'联用户基础表'" ` // 关联用户基础表
Path string `json:"path" gorm:"column:path;type:varchar(255);comment:'代码存放路径'" ` // 代码存放路径
Status int `json:"status" gorm:"column:status;type:tinyint(1);comment:'状态'" ` // 【-1-待判断1-答案正确2-答案错误3-运行超时4-运行超内存, 5-编译错误】
}
func (table *Submit) TableName() string {
return "submit"
}

View File

@@ -0,0 +1,19 @@
package entity
import "online_code/common/types"
// SubmitBasic 提交表
type SubmitBasic struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'用户唯一标识'" ` // 唯一标识
ProblemIdentity string `json:"problem_identity" gorm:"column:problem_identity;type:varchar(36);comment:'问题表的唯一标识'" ` // 问题表的唯一标识
ProblemBasic *ProblemBasic `json:"problem_basic" gorm:"foreignKey:ProblemIdentity;comment:'关联问题基础表'" ` // 关联问题基础表
UserIdentity string `json:"user_identity" gorm:"column:user_identity;type:varchar(36);comment:'用户表的唯一标识'" ` // 用户表的唯一标识
UserBasic *UserBasic `json:"user_basic" gorm:"foreignKey:UserIdentity;comment:'联用户基础表'" ` // 关联用户基础表
Path string `json:"path" gorm:"column:path;type:varchar(255);comment:'代码存放路径'" ` // 代码存放路径
Status int `json:"status" gorm:"column:status;type:tinyint(1);comment:'状态'" ` // 【-1-待判断1-答案正确2-答案错误3-运行超时4-运行超内存, 5-编译错误】
}
func (table *SubmitBasic) TableName() string {
return "submit_basic"
}

View File

@@ -5,8 +5,8 @@ import "online_code/common/types"
// TestCase 测试用例
type TestCase struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(255);comment:'用户唯一标识''" `
ProblemIdentity string `json:"problem_identity" gorm:"column:problem_identity;type:varchar(255);comment:'问题'" `
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'测试用例唯一标识''" `
ProblemIdentity string `json:"problem_identity" gorm:"column:problem_identity;type:varchar(36);comment:'问题'" `
Input string `json:"input" gorm:"column:input;type:text;" `
Output string `json:"output" gorm:"column:output;type:text;" `
}

View File

@@ -2,7 +2,7 @@ package entity
import "online_code/common/types"
type User struct {
type UserBasic struct {
types.BaseDbModel
Identity string `json:"identity" gorm:"column:identity;type:varchar(36);comment:'用户唯一标识'"`
Name string `json:"name" gorm:"column:name;type:varchar(100);not null;comment:'用户名'"`
@@ -14,6 +14,6 @@ type User struct {
IsAdmin int `json:"is_admin" gorm:"column:is_admin;type:tinyint(1);comment:'是否是管理员【0-否1-是】'"`
}
func (table *User) TableName() string {
return "user"
func (table *UserBasic) TableName() string {
return "user_basic"
}

View File

@@ -2,5 +2,6 @@ package param
type GetProblemList struct {
page
Keyword string `json:"keyword" form:"keyword"` // 问题关键字
Keyword string `json:"keyword" form:"keyword"` // 问题关键字
CategoryIdentity string `json:"category_identity" form:"category_identity"` // 问题分类标识
}

8
models/param/submit.go Normal file
View File

@@ -0,0 +1,8 @@
package param
type GetSubmitList struct {
page
ProblemIdentity string `json:"problemIdentity" form:"problemIdentity"`
UserIdentity string `json:"userIdentity" form:"userIdentity"`
Status int `json:"status" form:"status"`
}

View File

@@ -13,19 +13,23 @@ func ProblemService() *problemService {
}
// GetList 获取题目列表
func (problemService) GetList(p param.GetProblemList) (records entity.Problem, count int64, err error) {
sel := client.MySQL.Scopes(page(p.Current, p.Size))
func (problemService) GetList(p param.GetProblemList) (records []entity.ProblemBasic, count int64, err error) {
sel := client.MySQL.Scopes(page(p.Current, p.Size)).Preload("ProblemCategories").Preload("ProblemCategories.CategoryBasic")
if p.Keyword != "" {
sel.Where("title LIKE ? OR content like ?", "%"+p.Keyword+"%", "%"+p.Keyword+"%")
}
if p.CategoryIdentity != "" {
sel.Joins("RIGHT JOINN problem_category pc on pc.problem_id = problem.id").
Where("pc.category_id= (SELECT cb.id FROM category cb WHERE cb.identity = ?)", p.CategoryIdentity)
}
err = sel.Order("updated_at DESC").Find(&records).Offset(-1).Limit(-1).Count(&count).Error
return
}
// GetProblemInfo 获取题目详情
func (problemService) GetProblemInfo(id int) (problem entity.Problem, err error) {
func (problemService) GetProblemInfo(id int) (problem entity.ProblemBasic, err error) {
err = client.MySQL.Where("id = ?", id).Find(&problem).Error
return
}

28
repository/submit.go Normal file
View File

@@ -0,0 +1,28 @@
package repository
import (
"online_code/client"
"online_code/models/entity"
"online_code/models/param"
)
type submitService struct{}
func SubmitService() *submitService {
return &submitService{}
}
func (submitService) GetList(p param.GetSubmitList) (records []entity.SubmitBasic, count int64, err error) {
tx := client.MySQL.Scopes(page(p.Current, p.Size))
if p.ProblemIdentity != "" {
tx = tx.Where("problem_identity = ?", p.ProblemIdentity)
}
if p.UserIdentity != "" {
tx = tx.Where("user_identity = ?", p.UserIdentity)
}
if p.Status != 0 && p.Status != 1 && p.Status != 2 {
tx = tx.Where("status = ?", p.Status)
}
err = tx.Offset(-1).Limit(-1).Count(&count).Find(&records).Error
return
}

7
repository/user.go Normal file
View File

@@ -0,0 +1,7 @@
package repository
type userService struct{}
func UserService() *userService {
return &userService{}
}

View File

@@ -3,6 +3,6 @@ package route
import "github.com/gin-gonic/gin"
func InitRoute(g *gin.RouterGroup) {
api := g.Group("/api")
problem(api.Group("/problem"))
problem(g.Group("/problem"))
user(g.Group("/user"))
}

10
route/user.go Normal file
View File

@@ -0,0 +1,10 @@
package route
import (
"github.com/gin-gonic/gin"
"online_code/api"
)
func user(g *gin.RouterGroup) {
g.GET("/:identity", api.UserApi().GetUserInfo) // 获取用户详情
}