初始化提交
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
package controller
|
||||
|
||||
// Api api接口
|
||||
type Api struct {
|
||||
Basic // 基础数据
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/api/requests"
|
||||
"hospital-admin-api/api/responses"
|
||||
"hospital-admin-api/global"
|
||||
"hospital-admin-api/utils"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Basic struct{}
|
||||
|
||||
// GetCaptcha 获取验证码
|
||||
func (b *Basic) GetCaptcha(c *gin.Context) {
|
||||
time.Sleep(20 * time.Second)
|
||||
id, b64s, err := utils.GenerateCaptcha()
|
||||
if err != nil {
|
||||
responses.FailWithMessage("验证码获取失败", c)
|
||||
}
|
||||
|
||||
responses.OkWithData(gin.H{
|
||||
"id": id,
|
||||
"b64s": b64s,
|
||||
}, c)
|
||||
}
|
||||
|
||||
// Login 登陆
|
||||
func (b *Basic) Login(c *gin.Context) {
|
||||
var login requests.Login
|
||||
|
||||
if err := c.ShouldBind(&login); err != nil {
|
||||
responses.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数验证
|
||||
if err := global.Validate.Struct(login); err != nil {
|
||||
responses.FailWithMessage(utils.Translate(err), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证验证码
|
||||
isValid := utils.VerifyCaptcha(login)
|
||||
if !isValid {
|
||||
// 验证码错误
|
||||
responses.FailWithMessage("验证码错误", c)
|
||||
return
|
||||
}
|
||||
responses.Ok(c)
|
||||
}
|
||||
|
||||
// GetCaptchaTest 获取验证码
|
||||
func (b *Basic) GetCaptchaTest(c *gin.Context) {
|
||||
// path := "/admin/basic/captcha-test/:id"
|
||||
// url := c.Request.RequestURI
|
||||
//
|
||||
// method := "get"
|
||||
//
|
||||
// if KeyMatch2(url, path) && "get" == method {
|
||||
// responses.Ok(c)
|
||||
// return
|
||||
// }
|
||||
// responses.Fail(c)
|
||||
// return
|
||||
|
||||
// t := utils.Token{}
|
||||
// t.UserId = 1
|
||||
// t.RoleId = 1
|
||||
// t.DeptId = 1
|
||||
// t.PostId = 1
|
||||
//
|
||||
// au, err := t.NewJWT()
|
||||
// if err != nil {
|
||||
// responses.FailWithMessage(err.Error(), c)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// responses.OkWithData(au, c)
|
||||
|
||||
// au, err := utils.NewJWT(123456)
|
||||
// if err != nil {
|
||||
// responses.FailWithMessage(err.Error(), c)
|
||||
// }
|
||||
//
|
||||
// responses.OkWithData(au, c)
|
||||
// global.Logger.WithFields(logrus.Fields{
|
||||
// "name": "key",
|
||||
// "values": "value",
|
||||
// }).Info("测试")
|
||||
//
|
||||
// result, err := global.Redis.Get(c, "111").Result()
|
||||
// if err != nil {
|
||||
// fmt.Println(err.Error())
|
||||
// responses.Fail(c)
|
||||
// return
|
||||
// }
|
||||
// fmt.Println(result)
|
||||
|
||||
responses.Ok(c)
|
||||
}
|
||||
|
||||
func KeyMatch2(key1 string, key2 string) bool {
|
||||
key2 = strings.Replace(key2, "/*", "/.*", -1)
|
||||
fmt.Println(key2)
|
||||
re := regexp.MustCompile(`:[^/]+`)
|
||||
key2 = re.ReplaceAllString(key2, "$1[^/]+$2")
|
||||
|
||||
return RegexMatch(key1, "^"+key2+"$")
|
||||
}
|
||||
|
||||
func RegexMatch(key1 string, key2 string) bool {
|
||||
res, err := regexp.MatchString(key2, key1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
package dao
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hospital-admin-api/api/model"
|
||||
"hospital-admin-api/global"
|
||||
)
|
||||
|
||||
type AdminMenuApi struct {
|
||||
}
|
||||
|
||||
// GetAdminMenuApiListByMenuID 菜单id获取菜单api
|
||||
// menuId 菜单id
|
||||
func (r *AdminMenuApi) GetAdminMenuApiListByMenuID(menuId int64) (m []*model.AdminMenuApi, err error) {
|
||||
err = global.Db.Where("menu_id = ?", menuId).Preload("API").Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hospital-admin-api/api/model"
|
||||
"hospital-admin-api/global"
|
||||
)
|
||||
|
||||
type AdminRole struct {
|
||||
}
|
||||
|
||||
// GetAdminRoleFirstById 角色id获取用户角色
|
||||
// roleId 角色id
|
||||
func (r *AdminRole) GetAdminRoleFirstById(roleId int64) (m model.AdminRole, err error) {
|
||||
err = global.Db.First(&m, roleId).Error
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hospital-admin-api/api/model"
|
||||
"hospital-admin-api/global"
|
||||
)
|
||||
|
||||
type AdminRoleMenu struct {
|
||||
}
|
||||
|
||||
// GetAdminMenuListByRoleId GetAdminRoleById 角色id获取用户角色
|
||||
// roleId 角色id
|
||||
func (r *AdminRoleMenu) GetAdminMenuListByRoleId(roleId int64) (m []*model.AdminRoleMenu, err error) {
|
||||
err = global.Db.Where("role_id = ?", roleId).Preload("Menu").Find(&m).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"hospital-admin-api/api/model"
|
||||
"hospital-admin-api/global"
|
||||
)
|
||||
|
||||
type AdminUser struct {
|
||||
}
|
||||
|
||||
// GetAdminUserFirstById 用户id获取用户数据
|
||||
// roleId 用户id
|
||||
func (r *AdminUser) GetAdminUserFirstById(userId int64) (m model.AdminUser, err error) {
|
||||
err = global.Db.First(&m, userId).Error
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package exception
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/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.SERVER_ERROR,
|
||||
"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,153 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/api/dao"
|
||||
"hospital-admin-api/api/responses"
|
||||
"hospital-admin-api/consts"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Auth Auth认证
|
||||
func Auth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 获取角色id
|
||||
roleId := c.GetInt64("RoleId")
|
||||
if roleId == 0 {
|
||||
responses.Fail(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户id
|
||||
userId := c.GetInt64("UserId")
|
||||
if userId == 0 {
|
||||
responses.Fail(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户数据
|
||||
AdminUserDao := dao.AdminUser{}
|
||||
adminUser, err := AdminUserDao.GetAdminUserFirstById(userId)
|
||||
if err != nil || adminUser.UserId == 0 {
|
||||
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
|
||||
}
|
||||
|
||||
// 获取角色数据
|
||||
AdminRoleDao := dao.AdminRole{}
|
||||
adminRole, err := AdminRoleDao.GetAdminRoleFirstById(roleId)
|
||||
if err != nil || adminRole.RoleId == 0 {
|
||||
responses.FailWithMessage("用户数据错误", c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 超级管理员不验证权限
|
||||
if adminRole.IsAdmin == 1 {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取角色菜单
|
||||
AdminRoleMenuDao := dao.AdminRoleMenu{}
|
||||
adminRoleMenu, _ := AdminRoleMenuDao.GetAdminMenuListByRoleId(roleId)
|
||||
if adminRoleMenu == nil {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "暂无权限",
|
||||
"code": consts.CLIENT_HTTP_UNAUTHORIZED,
|
||||
"data": "",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var apiPermissions = make(map[string]bool)
|
||||
|
||||
// 获取菜单对应api
|
||||
AdminMenuApiDao := dao.AdminMenuApi{}
|
||||
for _, v := range adminRoleMenu {
|
||||
AdminMenuApi, _ := AdminMenuApiDao.GetAdminMenuApiListByMenuID(v.MenuID)
|
||||
if AdminMenuApi == nil {
|
||||
// 菜单无需权限
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 将API权限存储在apiPermissions中
|
||||
for _, api := range AdminMenuApi {
|
||||
apiPermissions[api.API.APIPath+api.API.APIMethod] = true
|
||||
}
|
||||
}
|
||||
|
||||
path := ""
|
||||
// 找到最后一个数字的索引
|
||||
lastSlashIndex := strings.LastIndex(c.Request.RequestURI, "/")
|
||||
if lastSlashIndex != -1 {
|
||||
// 替换最后一个数字部分为 :id
|
||||
path = c.Request.RequestURI[:lastSlashIndex] + "/:id" + c.Request.Method
|
||||
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "请求路径错误",
|
||||
"code": consts.SERVER_ERROR,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 在apiPermissions中查找对应的API权限
|
||||
hasPermission := apiPermissions[path]
|
||||
if !hasPermission {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "暂无权限",
|
||||
"code": consts.CLIENT_HTTP_UNAUTHORIZED,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// Auth 权限
|
||||
// func Auth() gin.HandlerFunc {
|
||||
// return func(c *gin.Context) {
|
||||
// fmt.Println(123)
|
||||
|
||||
//
|
||||
// // result, err := dao.AdminRole.GetAdminRoleById(roleId)
|
||||
// // fmt.Println(result)
|
||||
// // if err != nil {
|
||||
// // responses.FailWithMessage("用户数据错误", c)
|
||||
// // c.Abort()
|
||||
// // return
|
||||
// // }
|
||||
// // responses.OkWithData(&result, c)
|
||||
// // c.Abort()
|
||||
//
|
||||
// // 获取请求路径
|
||||
// // url := c.Request.RequestURI
|
||||
// c.Next()
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,28 @@
|
||||
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)
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/api/responses"
|
||||
"hospital-admin-api/consts"
|
||||
"hospital-admin-api/global"
|
||||
"hospital-admin-api/utils"
|
||||
"net/http"
|
||||
"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.TOKEN_ERROR,
|
||||
"data": "",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 去除Bearer
|
||||
authorization = authorization[7:] // 截取字符
|
||||
|
||||
// 检测是否存在黑名单
|
||||
res, _ := global.Redis.Get(c, "jwt_black_"+authorization).Result()
|
||||
if res != "" {
|
||||
responses.Fail(c)
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 解析jwt
|
||||
t, err := utils.ParseJwt(authorization)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "token错误/过期",
|
||||
"code": consts.TOKEN_ERROR,
|
||||
"data": "",
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("UserId", t.UserId) // 用户id
|
||||
c.Set("RoleId", t.RoleId) // 角色id
|
||||
c.Set("DeptId", t.DeptId) // 部门id
|
||||
c.Set("PostId", t.PostId) // 岗位id
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"hospital-admin-api/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logrus 日志中间件
|
||||
func Logrus() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
// 开始时间
|
||||
startTime := time.Now()
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
// 结束时间
|
||||
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,
|
||||
}).Info("access")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package model
|
||||
|
||||
// AdminApi 后台-接口表
|
||||
type AdminAPI struct {
|
||||
Model
|
||||
APIID int64 `gorm:"column:api_id;type:bigint(19);primary_key;AUTO_INCREMENT;comment:主键id" json:"api_id"`
|
||||
APIName string `gorm:"column:api_name;type:varchar(100);comment:api名称;NOT NULL" json:"api_name"`
|
||||
APIPath string `gorm:"column:api_path;type:varchar(255);comment:接口路径(全路径 id为:id);NOT NULL" json:"api_path"`
|
||||
APIMethod string `gorm:"column:api_method;type:varchar(10);comment:请求类型(put:修改 post:新增 get:获取 );NOT NULL" json:"api_method"`
|
||||
}
|
||||
|
||||
func (m *AdminAPI) TableName() string {
|
||||
return "gdxz_admin_api"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// AdminDept 后台-部门表
|
||||
type AdminDept struct {
|
||||
DeptId int64 `gorm:"column:dept_id;type:bigint(19);primary_key;comment:主键id" json:"dept_id"`
|
||||
ParentId int64 `gorm:"column:parent_id;type:bigint(19);comment:本表父级id" json:"parent_id"`
|
||||
DeptName string `gorm:"column:dept_name;type:varchar(255);comment:部门名称" json:"dept_name"`
|
||||
DeptStatus int `gorm:"column:dept_status;type:tinyint(1);default:1;comment:部门状态(1:正常 2:删除)" json:"dept_status"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:datetime;comment:创建时间" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;comment:修改时间" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (m *AdminDept) TableName() string {
|
||||
return "gdxz_admin_dept"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package model
|
||||
|
||||
// AdminMenu 后台-菜单表
|
||||
type AdminMenu struct {
|
||||
Model
|
||||
MenuId int64 `gorm:"column:menu_id;type:bigint(19);primary_key;comment:主键id" json:"menu_id"`
|
||||
MenuName string `gorm:"column:menu_name;type:varchar(30);comment:菜单名称" json:"menu_name"`
|
||||
ParentId int `gorm:"column:parent_id;type:int(10);default:0;comment:父菜单ID(0表示一级)" json:"parent_id"`
|
||||
MenuStatus int `gorm:"column:menu_status;type:tinyint(1);default:1;comment:菜单状态(0:隐藏 1:正常)此优先级最高" json:"menu_status"`
|
||||
MenuType int `gorm:"column:menu_type;type:tinyint(1);comment:菜单类型(1:模块 2:菜单 2:按钮)" json:"menu_type"`
|
||||
Permission string `gorm:"column:permission;type:varchar(255);comment:标识" json:"permission"`
|
||||
OrderNum int `gorm:"column:order_num;type:int(4);default:0;comment:显示顺序" json:"order_num"`
|
||||
Icon string `gorm:"column:icon;type:varchar(255);comment:图标地址" json:"icon"`
|
||||
Path string `gorm:"column:path;type:varchar(255);comment:页面地址(#表示当前页)" json:"path"`
|
||||
}
|
||||
|
||||
func (m *AdminMenu) TableName() string {
|
||||
return "gdxz_admin_menu"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package model
|
||||
|
||||
// AdminMenuApi 后台-菜单-接口表
|
||||
type AdminMenuApi struct {
|
||||
MenuId int64 `gorm:"column:menu_id;type:bigint(19);primary_key;comment:菜单id" json:"menu_id"`
|
||||
ApiId int64 `gorm:"column:api_id;type:bigint(19);primary_key;comment:接口id" json:"api_id"`
|
||||
Menu AdminMenu `gorm:"foreignkey:MenuId;association_foreignkey:MenuID"`
|
||||
API AdminAPI `gorm:"foreignkey:ApiId;association_foreignkey:APIID"`
|
||||
}
|
||||
|
||||
func (m *AdminMenuApi) TableName() string {
|
||||
return "gdxz_admin_menu_api"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// AdminPost 后台-岗位表
|
||||
type AdminPost struct {
|
||||
PostId int64 `gorm:"column:post_id;type:bigint(19);primary_key;comment:主键id" json:"post_id"`
|
||||
PostName string `gorm:"column:post_name;type:varchar(255);comment:部门名称" json:"post_name"`
|
||||
PostStatus int `gorm:"column:post_status;type:tinyint(1);default:1;comment:状态(1:正常 2:删除)" json:"post_status"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:datetime;comment:创建时间" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;comment:修改时间" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (m *AdminPost) TableName() string {
|
||||
return "gdxz_admin_post"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package model
|
||||
|
||||
// AdminRole 后台-角色表
|
||||
type AdminRole struct {
|
||||
Model
|
||||
RoleId int64 `gorm:"column:role_id;type:bigint(19);primary_key;comment:主键id" json:"role_id"`
|
||||
RoleName string `gorm:"column:role_name;type:varchar(100);comment:角色名称" json:"role_name"`
|
||||
RoleStatus int `gorm:"column:role_status;type:tinyint(1);default:1;comment:角色状态(1:正常 2:禁用)" json:"role_status"`
|
||||
IsAdmin int `gorm:"column:is_admin;type:tinyint(1);default:0;comment:是否管理员(0:否 1:是)" json:"is_admin"`
|
||||
}
|
||||
|
||||
func (m *AdminRole) TableName() string {
|
||||
return "gdxz_admin_role"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package model
|
||||
|
||||
// AdminRoleMenu 后台-角色-菜单表
|
||||
type AdminRoleMenu struct {
|
||||
RoleID int64 `gorm:"column:role_id;type:bigint(19);primary_key;comment:权限id" json:"role_id"`
|
||||
MenuID int64 `gorm:"column:menu_id;type:bigint(19);primary_key;comment:菜单id" json:"menu_id"`
|
||||
Menu AdminMenu `gorm:"foreignKey:MenuID"`
|
||||
Role AdminRole `gorm:"foreignKey:RoleID"`
|
||||
}
|
||||
|
||||
func (m *AdminRoleMenu) TableName() string {
|
||||
return "gdxz_admin_role_menu"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// AdminUser 后台-用户表
|
||||
type AdminUser struct {
|
||||
UserId int64 `gorm:"column:user_id;type:bigint(19);primary_key;comment:主键id" json:"user_id"`
|
||||
UserName string `gorm:"column:user_name;type:varchar(64);comment:用户名" json:"user_name"`
|
||||
Password string `gorm:"column:password;type:varchar(128);comment:密码" json:"password"`
|
||||
Salt string `gorm:"column:salt;type:varchar(255);comment:密码掩码" json:"salt"`
|
||||
Status int `gorm:"column:status;type:tinyint(1);default:2;comment:状态(1:正常 2:审核中 3:删除)" json:"status"`
|
||||
NickName string `gorm:"column:nick_name;type:varchar(255);comment:昵称" json:"nick_name"`
|
||||
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"`
|
||||
RoleId int64 `gorm:"column:role_id;type:bigint(19);comment:角色表" json:"role_id"`
|
||||
DeptId int64 `gorm:"column:dept_id;type:bigint(19);comment:部门id" json:"dept_id"`
|
||||
PostId int64 `gorm:"column:post_id;type:bigint(19);comment:岗位id" json:"post_id"`
|
||||
CreateBy int64 `gorm:"column:create_by;type:bigint(19);comment:创建者id(用户表id)" json:"create_by"`
|
||||
UpdateBy int64 `gorm:"column:update_by;type:bigint(19);comment:更新者id(用户表id)" json:"update_by"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:datetime;comment:创建时间" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;comment:修改时间" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (m *AdminUser) TableName() string {
|
||||
return "gdxz_admin_user"
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"reflect"
|
||||
"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())
|
||||
}
|
||||
|
||||
// BeforeCreate 注册 BeforeCreate 回调函数
|
||||
func (m *Model) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
// 动态访问 YourModel 结构体本身
|
||||
model := tx.Statement.Dest
|
||||
|
||||
// 设置创建时间
|
||||
layout := "2006-01-02 15:04:05"
|
||||
strTime := "2019-08-09 11:35:52"
|
||||
parsedTime, err := time.Parse(layout, strTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 使用反射设置创建时间字段
|
||||
createdAtField := reflect.ValueOf(model).Elem().FieldByName("CreatedAt")
|
||||
if createdAtField.CanSet() {
|
||||
createdAtField.Set(reflect.ValueOf(parsedTime))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package requests
|
||||
|
||||
type Requests struct {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package requests
|
||||
|
||||
type Basic struct {
|
||||
Login // 登陆
|
||||
}
|
||||
|
||||
// Login 登陆
|
||||
type Login struct {
|
||||
Username string `json:"username" form:"username" validate:"required" label:"用户名"` // 用户名
|
||||
Password string `json:"password" form:"password" validate:"required"` // 密码
|
||||
Captcha string `json:"captcha" form:"captcha" validate:"required"` // 验证码
|
||||
CaptchaId string `json:"captchaId" form:"captchaId" validate:"required"` // 验证码ID
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package responses
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/consts"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Response 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, Response{
|
||||
code,
|
||||
data,
|
||||
msg,
|
||||
})
|
||||
}
|
||||
|
||||
func Ok(c *gin.Context) {
|
||||
Result(consts.HTTP_SUCCESS, map[string]interface{}{}, "成功", c)
|
||||
}
|
||||
|
||||
func OkWithMessage(message string, c *gin.Context) {
|
||||
Result(consts.HTTP_SUCCESS, map[string]interface{}{}, message, c)
|
||||
}
|
||||
|
||||
func OkWithData(data interface{}, c *gin.Context) {
|
||||
Result(consts.HTTP_SUCCESS, data, "成功", c)
|
||||
}
|
||||
|
||||
func OkWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
Result(consts.HTTP_SUCCESS, data, message, c)
|
||||
}
|
||||
|
||||
func Fail(c *gin.Context) {
|
||||
Result(consts.HTTP_ERROR, map[string]interface{}{}, "失败", c)
|
||||
}
|
||||
|
||||
func FailWithMessage(message string, c *gin.Context) {
|
||||
Result(consts.HTTP_ERROR, map[string]interface{}{}, message, c)
|
||||
}
|
||||
|
||||
func FailWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
Result(consts.HTTP_ERROR, data, message, c)
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"hospital-admin-api/api/controller"
|
||||
"hospital-admin-api/api/exception"
|
||||
"hospital-admin-api/api/middlewares"
|
||||
"hospital-admin-api/consts"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Init 初始化路由
|
||||
func Init() *gin.Engine {
|
||||
r := gin.New()
|
||||
|
||||
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.CLIENT_HTTP_NOT_FOUND,
|
||||
"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)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// publicRouter 公开路由-不验证权限
|
||||
func publicRouter(r *gin.Engine, api controller.Api) {
|
||||
adminGroup := r.Group("/admin")
|
||||
baseGroup := adminGroup.Group("/basic")
|
||||
{
|
||||
// 验证码
|
||||
baseGroup.GET("captcha", api.Basic.GetCaptcha)
|
||||
|
||||
// 登陆
|
||||
baseGroup.POST("login", api.Basic.Login)
|
||||
}
|
||||
}
|
||||
|
||||
// privateRouter 私有路由
|
||||
func privateRouter(r *gin.Engine, api controller.Api) {
|
||||
adminGroup := r.Group("/admin")
|
||||
base1Group := adminGroup.Group("/basic")
|
||||
{
|
||||
// 验证码
|
||||
base1Group.GET("captcha-test/:id", api.Basic.GetCaptchaTest)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package service
|
||||
|
||||
type Basic struct{}
|
||||
|
||||
// Login 登陆
|
||||
func (b *Basic) Login() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package service
|
||||
|
||||
type AdminUser struct {
|
||||
}
|
||||
Reference in New Issue
Block a user