feat(admin): 新增个人中心功能并优化用户相关逻辑

- 新增个人中心相关接口和页面,包括用户信息获取、修改密码、更新手机号等
- 重构用户相关逻辑,增加缓存支持,优化权限验证和菜单获取
- 更新数据库连接配置,调整表前缀和连接信息
This commit is contained in:
zcool321
2025-06-17 13:43:48 +08:00
parent ff9ba2ca26
commit 6641de33d7
31 changed files with 757 additions and 147 deletions

5
.gitignore vendored
View File

@@ -1,7 +1,6 @@
# Vue 项目忽略项
node_modules
.idea
.vscode
.dist
.cache
@@ -19,4 +18,6 @@ go.sum
*.tmp
# 本地配置文件
**/config/config.yaml
**/config/config.yaml
**/attachment/**
**/temp/**

View File

@@ -7,7 +7,7 @@ import (
)
type ConfigListReq struct {
g.Meta `path:"/config/list" method:"POST" tags:"配置管理" summary:"配置列表"`
g.Meta `path:"/config/list" method:"POST" perms:"admin:config:query" tags:"配置管理" summary:"配置列表"`
Keywords string `json:"keywords" dc:"名称"`
DataType int `json:"dataType" dc:"数据类型"`
Enable int `json:"enable" dc:"是否启用"`
@@ -20,14 +20,14 @@ type ConfigListRes struct {
}
type ConfigGetReq struct {
g.Meta `path:"/config/get/:id" method:"get" tags:"配置管理" summary:"配置获取"`
g.Meta `path:"/config/get/:id" method:"get" perms:"admin:config:query" tags:"配置管理" summary:"配置获取"`
Id int64 `json:"id" dc:"ID"`
}
type ConfigGetRes = entity.Config
type ConfigSaveReq struct {
g.Meta `path:"/config/save/:id" method:"post" tags:"配置管理" summary:"配置保存"`
g.Meta `path:"/config/save/:id" method:"post" perms:"admin:config:save" tags:"配置管理" summary:"配置保存"`
Id int64 `json:"id"`
Name string `json:"name" dc:"配置名称" v:"required#配置名称不能为空"`
Key string `json:"key" dc:"配置键" v:"required#键不能为空"`
@@ -46,7 +46,7 @@ type ConfigSaveRes struct {
}
type ConfigDeleteReq struct {
g.Meta `path:"/config/delete/:ids" method:"post" tags:"配置管理" summary:"配置删除"`
g.Meta `path:"/config/delete/:ids" method:"post" perms:"admin:config:delete" tags:"配置管理" summary:"配置删除"`
Ids string `json:"ids" dc:"删除id列表"`
}

View File

@@ -7,7 +7,7 @@ import (
)
type DeptListReq struct {
g.Meta `path:"/dept/list" method:"POST" tags:"部门管理" summary:"部门列表"`
g.Meta `path:"/dept/list" method:"POST" perms:"admin:dept:query" tags:"部门管理" summary:"部门列表"`
Keywords string `json:"keywords" dc:"名称"`
Code string `json:"code" dc:"部门编码"`
Enable int `json:"enable" dc:"是否启用"`
@@ -27,14 +27,14 @@ type DeptOptionsReq struct {
type DeptOptionsRes = []*input2.OptionVal
type DeptGetReq struct {
g.Meta `path:"/dept/get/:id" method:"get" tags:"部门管理" summary:"部门获取"`
g.Meta `path:"/dept/get/:id" method:"get" perms:"admin:dept:query" tags:"部门管理" summary:"部门获取"`
Id int64 `json:"id" dc:"ID"`
}
type DeptGetRes = entity.Dept
type DeptSaveReq struct {
g.Meta `path:"/dept/save/:id" method:"post" tags:"部门管理" summary:"部门保存"`
g.Meta `path:"/dept/save/:id" method:"post" perms:"admin:dept:save" tags:"部门管理" summary:"部门保存"`
Id int64 `json:"id"`
ParentId int64 `json:"parentId" v:"required#父级不能为空"`
Name string `json:"name" dc:"部门名称" v:"required#部门名称不能为空"`
@@ -50,7 +50,7 @@ type DeptSaveRes struct {
}
type DeptDeleteReq struct {
g.Meta `path:"/dept/delete/:ids" method:"post" tags:"部门管理" summary:"部门删除"`
g.Meta `path:"/dept/delete/:ids" method:"post" perms:"admin:dept:delete" tags:"部门管理" summary:"部门删除"`
Ids string `json:"ids" dc:"删除id列表"`
}

View File

@@ -6,7 +6,7 @@ import (
)
type MenuListReq struct {
g.Meta `path:"/menu/list" method:"post" tags:"菜单管理" summary:"菜单列表"`
g.Meta `path:"/menu/list" method:"post" perms:"admin:menu:query" tags:"菜单管理" summary:"菜单列表"`
Name string `json:"name" dc:"菜单名称"`
Enable int `json:"enable" dc:"是否启用"`
input2.PageReq
@@ -26,14 +26,14 @@ type MenuOptionsReq struct {
type MenuOptionsRes = []*input2.OptionVal
type MenuGetReq struct {
g.Meta `path:"/menu/get/:id" method:"get" tags:"菜单管理" summary:"菜单获取"`
g.Meta `path:"/menu/get/:id" method:"get" perms:"admin:menu:query" tags:"菜单管理" summary:"菜单获取"`
Id int `json:"id" dc:"ID"`
}
type MenuGetRes = input2.Menu
type MenuSaveReq struct {
g.Meta `path:"/menu/save/:id" method:"post" tags:"菜单管理" summary:"菜单保存"`
g.Meta `path:"/menu/save/:id" method:"post" perms:"admin:menu:save" tags:"菜单管理" summary:"菜单保存"`
Id int `json:"id"`
ParentId int `json:"parentId" v:"required#父级不能为空"`
Name string `json:"name" dc:"菜单名称" v:"required#菜单名称不能为空"`
@@ -57,7 +57,7 @@ type MenuSaveRes struct {
}
type MenuDeleteReq struct {
g.Meta `path:"/menu/delete/:ids" method:"post" tags:"菜单管理" summary:"菜单删除"`
g.Meta `path:"/menu/delete/:ids" method:"post" perms:"admin:menu:delete" tags:"菜单管理" summary:"菜单删除"`
Ids []int `json:"ids" dc:"删除id列表"`
}

View File

@@ -7,7 +7,7 @@ import (
)
type RoleListReq struct {
g.Meta `path:"/role/list" method:"post" tags:"角色管理" summary:"角色列表"`
g.Meta `path:"/role/list" method:"post" perms:"admin:role:query" tags:"角色管理" summary:"角色列表"`
Keywords string `json:"keywords" dc:"角色或编码名称"`
Name string `json:"name" dc:"角色名称"`
Enable int `json:"enable" dc:"是否启用"`
@@ -27,7 +27,7 @@ type RoleOptionsReq struct {
type RoleOptionsRes = []*input2.OptionVal
type RoleSaveReq struct {
g.Meta `path:"/role/save/:id" method:"post" tags:"角色管理" summary:"角色保存"`
g.Meta `path:"/role/save/:id" method:"post" perms:"admin:role:save" tags:"角色管理" summary:"角色保存"`
Id int64 `json:"id"`
Name string `json:"name" dc:"名称" v:"required#名称不能为空"`
Code string `json:"code" dc:"编码"`
@@ -41,14 +41,14 @@ type RoleSaveRes struct {
}
type RoleGetReq struct {
g.Meta `path:"/role/get/:id" method:"get" tags:"角色管理" summary:"角色获取"`
g.Meta `path:"/role/get/:id" method:"get" perms:"admin:role:query" tags:"角色管理" summary:"角色获取"`
Id int64 `json:"id" dc:"ID"`
}
type RoleGetRes = entity.Role
type RoleDeleteReq struct {
g.Meta `path:"/role/delete/:ids" method:"post" tags:"角色管理" summary:"角色删除"`
g.Meta `path:"/role/delete/:ids" method:"post" perms:"admin:role:delete" tags:"角色管理" summary:"角色删除"`
Ids string `json:"ids" dc:"删除id列表"`
}

View File

@@ -1,13 +1,14 @@
package v1
import (
input2 "gmanager/internal/admin/model/input"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
input2 "gmanager/internal/admin/model/input"
)
type UserListReq struct {
g.Meta `path:"/user/list" method:"post" tags:"用户管理" summary:"用户列表"`
g.Meta `path:"/user/list" method:"post" perms:"admin:user:query" tags:"用户管理" summary:"用户列表"`
Keywords string `json:"keywords" dc:"用户/手机号/昵称名称"`
DeptId int64 `json:"deptId" dc:"部门"`
Status int `json:"code" dc:"用户状态"`
@@ -22,7 +23,7 @@ type UserListRes struct {
}
type UserSaveReq struct {
g.Meta `path:"/user/save/:id" method:"post" tags:"用户管理" summary:"用户保存"`
g.Meta `path:"/user/save/:id" method:"post" perms:"admin:user:save" tags:"用户管理" summary:"用户保存"`
Id int64 `json:"id"`
DeptId int64 `json:"deptId" dc:"部门id" v:"required#部门不能为空"`
UserName string `json:"userName" dc:"用户名称" v:"required#用户名称不能为空"`
@@ -44,14 +45,14 @@ type UserSaveRes struct {
}
type UserGetReq struct {
g.Meta `path:"/user/get/:id" method:"get" tags:"用户管理" summary:"用户获取"`
g.Meta `path:"/user/get/:id" method:"get" perms:"admin:user:query" tags:"用户管理" summary:"用户获取"`
Id int64 `json:"id" dc:"ID"`
}
type UserGetRes = input2.User
type UserDeleteReq struct {
g.Meta `path:"/user/delete/:ids" method:"post" tags:"用户管理" summary:"用户删除"`
g.Meta `path:"/user/delete/:ids" method:"post" perms:"admin:user:delete" tags:"用户管理" summary:"用户删除"`
Ids string `json:"ids" dc:"删除id列表"`
}
@@ -59,7 +60,7 @@ type UserDeleteRes struct {
}
type UserPasswordResetReq struct {
g.Meta `path:"/user/password/reset/:id" method:"post" tags:"用户管理" summary:"用户密码重置"`
g.Meta `path:"/user/password/reset/:id" method:"post" perms:"admin:user:reset-password" tags:"用户管理" summary:"用户密码重置"`
Id int64 `json:"id"`
Password string `json:"password" dc:"密码" v:"required#密码不能为空"`
}
@@ -86,7 +87,7 @@ type UserMenusReq struct {
type UserMenusRes = []*input2.UserMenu
type UserExportReq struct {
g.Meta `path:"/user/export" method:"get" tags:"用户管理" summary:"用户数据导出"`
g.Meta `path:"/user/export" method:"get" perms:"admin:user:export" tags:"用户管理" summary:"用户数据导出"`
Keywords string `json:"keywords" dc:"用户/手机号/昵称名称"`
DeptId int64 `json:"deptId" dc:"部门"`
Status int `json:"code" dc:"用户状态"`
@@ -99,19 +100,19 @@ type UserExportRes struct {
}
type UserImportReq struct {
g.Meta `path:"/user/import" method:"post" tags:"用户管理" summary:"批量导入用户"`
File *ghttp.UploadFile `json:"file" type:"file" dc:"分片文件"`
g.Meta `path:"/user/import" method:"post" perms:"admin:user:import" tags:"用户管理" summary:"批量导入用户"`
File *ghttp.UploadFile `json:"file" type:"file" dc:"文件"`
}
type UserImportRes struct {
Code int `json:"code" dc:"状态码"` // 状态码
InvalidCount int `json:"invalidCount" dc:"手机号"` // 无效数据条数
ValidCount int `json:"validCount" dc:"手机号"` // 有效数据条数
MessageList []string `json:"messageList" dc:"手机号"` // 错误信息
Code int `json:"code" dc:"状态码"`
InvalidCount int `json:"invalidCount" dc:"无效数据条数"`
ValidCount int `json:"validCount" dc:"有效数据条数"`
MessageList []string `json:"messageList" dc:"错误信息"`
}
type UserTemplateReq struct {
g.Meta `path:"/user/template" method:"get" tags:"用户管理" summary:"批量创建用户模版下载"`
g.Meta `path:"/user/template" method:"get" perms:"admin:user:import" tags:"用户管理" summary:"批量创建用户模版下载"`
}
type UserTemplateRes struct {

View File

@@ -0,0 +1,69 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
"gmanager/internal/admin/model/input"
)
type UserProfileReq struct {
g.Meta `path:"/user/profile" method:"get" tags:"个人中心" summary:"个人中心信息获取"`
}
type UserProfileRes = input.UserProfile
type UserSaveProfileReq struct {
g.Meta `path:"/user/saveProfile" method:"post" tags:"个人中心" summary:"个人中心信息保存"`
Id int64 `json:"id"`
NickName string `json:"nickName" dc:"昵称"`
Mobile string `json:"mobile" dc:"手机号"`
Email string `json:"email" dc:"邮箱"`
Gender int `json:"gender" dc:"性别"`
Address string `json:"address" dc:"地址"`
Avatar string `json:"avatar" dc:"头像地址"`
}
type UserSaveProfileRes struct {
}
type UserChangePasswordReq struct {
g.Meta `path:"/user/changePassword" method:"post" tags:"个人中心" summary:"个人中心修改密码"`
OldPassword string `json:"oldPassword" dc:"原密码" v:"required#原密码不能为空"`
NewPassword string `json:"newPassword" dc:"新密码" v:"required#新密码不能为空"`
}
type UserChangePasswordRes struct {
}
type UserSendMobileCodeReq struct {
g.Meta `path:"/user/sendMobileCode" method:"post" tags:"个人中心" summary:"个人中心发送手机验证码"`
Mobile string `json:"mobile" dc:"手机号" v:"required#手机号不能为空"`
}
type UserSendMobileCodeRes struct {
}
type UserSaveMobileReq struct {
g.Meta `path:"/user/saveMobile" method:"post" tags:"个人中心" summary:"个人中心修改手机号"`
Mobile string `json:"mobile" dc:"手机号" v:"required#手机号不能为空"`
Code string `json:"code" dc:"验证码" v:"required#验证码不能为空"`
}
type UserSaveMobileRes struct {
}
type UserSendEmailCodeReq struct {
g.Meta `path:"/user/sendEmailCode" method:"post" tags:"个人中心" summary:"个人中心发送Email验证码"`
Email string `json:"mobile" dc:"邮箱" v:"required#邮箱不能为空"`
}
type UserSendEmailCodeRes struct {
}
type UserSaveEmailReq struct {
g.Meta `path:"/user/saveEmail" method:"post" tags:"个人中心" summary:"个人中心修改Email"`
Email string `json:"mobile" dc:"邮箱" v:"required#邮箱不能为空"`
Code string `json:"code" dc:"验证码" v:"required#验证码不能为空"`
}
type UserSaveEmailRes struct {
}

View File

@@ -0,0 +1,17 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
// UploadFileReq 上传文件
type UploadFileReq struct {
g.Meta `path:"/upload/file" tags:"附件" method:"post" summary:"上传附件"`
File *ghttp.UploadFile `json:"file" type:"file" dc:"文件"`
}
type UploadFileRes struct {
Url string `json:"url" dc:"URL"`
Name string `json:"name" dc:"名称"`
}

View File

@@ -5,7 +5,7 @@ go 1.23.0
toolchain go1.24.0
require (
github.com/goflyfox/gtoken/v2 v2.0.0
github.com/goflyfox/gtoken/v2 v2.0.1
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
github.com/gogf/gf/v2 v2.9.0
github.com/mojocn/base64Captcha v1.3.8

View File

@@ -6,9 +6,20 @@ gfcli:
dao:
- link: "mysql:root:123456@tcp(127.0.0.1:3306)/gmanager"
descriptionTag: true
path: "./internal/admin"
removePrefix: "sys_"
tables: "sys_dept,sys_config,sys_log,sys_menu,sys_role,sys_role_menu,sys_user,sys_user_role,sys_user_role_casbin"
build:
name: "gmanager" # 编译后的可执行文件名称
arch: "amd64" # 不填默认当前系统架构可选386,amd64,arm,all
system: "linux" # 不填默认当前系统平台可选linux,darwin,windows,all
packSrc: "resource" # 将resource目录打包进可执行文件静态资源无需单独部署
packDst: "internal/packed/packed.go" # 打包后生成的Go文件路径一般使用相对路径指定到本项目目录中
version: ""
output: "./temp/gmanager" # 可执行文件生成路径
extra: ""
docker:
build: "-a amd64 -s linux -p temp -ew"
tagPrefixes:

View File

@@ -37,5 +37,8 @@ const (
// 缓存 cache
const (
CacheConfig = "config"
CacheData = "data"
CacheConfig = "config" // 配置缓存
CacheUserPerm = "userPerm_%d" // 用户按钮权限缓存
CacheUserMenu = "userMenu_%d" // 用户菜单权限缓存
)

View File

@@ -4,7 +4,6 @@ import (
"context"
"github.com/gogf/gf/v2/util/gconv"
v1 "gmanager/api/admin/v1"
"gmanager/internal/admin/consts"
"gmanager/internal/admin/logic"
"strings"
)
@@ -19,9 +18,6 @@ func (c *dept) List(ctx context.Context, req *v1.DeptListReq) (res *v1.DeptListR
}
func (c *dept) Options(ctx context.Context, req *v1.DeptOptionsReq) (res *v1.DeptOptionsRes, err error) {
if req != nil && req.Enable == 0 {
req.Enable = consts.EnableYes
}
res, err = logic.Dept.Options(ctx, req)
return
}

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
v1 "gmanager/api/admin/v1"
"gmanager/internal/admin/logic"
@@ -46,13 +47,13 @@ func (c *user) PasswordReset(ctx context.Context, req *v1.UserPasswordResetReq)
// UserInfo 获取用户信息接口
func (c *user) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) {
res, err = logic.Login.UserInfo(ctx, req)
res, err = logic.User.UserInfo(ctx, req)
return
}
// UserMenus 获取用户菜单接口
func (c *user) UserMenus(ctx context.Context, req *v1.UserMenusReq) (res *v1.UserMenusRes, err error) {
res, err = logic.Login.UserMenus(ctx, req)
res, err = logic.User.UserMenus(ctx, req)
return
}
@@ -70,3 +71,41 @@ func (c *user) Template(ctx context.Context, req *v1.UserTemplateReq) (res *v1.U
err = logic.User.Template(ctx, req)
return
}
func (c *user) Profile(ctx context.Context, req *v1.UserProfileReq) (res *v1.UserProfileRes, err error) {
res, err = logic.User.Profile(ctx, req)
return
}
func (c *user) SaveProfile(ctx context.Context, req *v1.UserSaveProfileReq) (res *v1.UserSaveProfileRes, err error) {
err = logic.User.SaveProfile(ctx, req)
return
}
func (c *user) ChangePassword(ctx context.Context, req *v1.UserChangePasswordReq) (res *v1.UserChangePasswordRes, err error) {
if req.OldPassword == req.NewPassword {
return nil, gerror.New("原密码和新密码一致")
}
err = logic.User.ChangePassword(ctx, req)
return
}
func (c *user) SendMobileCode(ctx context.Context, req *v1.UserSendMobileCodeReq) (res *v1.UserSendMobileCodeRes, err error) {
err = logic.User.SendMobileCode(ctx, req)
return
}
func (c *user) SaveMobile(ctx context.Context, req *v1.UserSaveMobileReq) (res *v1.UserSaveMobileRes, err error) {
err = logic.User.SaveMobile(ctx, req)
return
}
func (c *user) SendEmailCode(ctx context.Context, req *v1.UserSendEmailCodeReq) (res *v1.UserSendEmailCodeRes, err error) {
err = logic.User.SendEmailCode(ctx, req)
return
}
func (c *user) SaveEmail(ctx context.Context, req *v1.UserSaveEmailReq) (res *v1.UserSaveEmailRes, err error) {
err = logic.User.SaveEmail(ctx, req)
return
}

View File

@@ -111,7 +111,7 @@ func (s *log) SaveLog(ctx context.Context, input *input.LogData) error {
logMeta.UpdateAt = gtime.Now()
}
if session != nil {
operator = session.Username
operator = session.UserName
}
if input.PkVal > 0 {
logMeta.Id = input.PkVal

View File

@@ -63,7 +63,8 @@ func (s *login) Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes,
Id: model.Id,
Uuid: model.Uuid,
NickName: model.NickName,
Username: model.UserName,
UserName: model.UserName,
UserType: model.UserType,
}
// 认证成功调用Generate生成Token
res.AccessToken, err = gftoken.GToken.Generate(ctx, req.Username, sessionUser)
@@ -113,39 +114,6 @@ func (s *login) Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRe
return
}
// GetTree 菜单树形菜单
func (s *login) GetTree(pid int64, list []*entity2.Menu) (tree []*input2.UserMenu) {
tree = make([]*input2.UserMenu, 0, len(list))
for _, v := range list {
if v.ParentId == pid {
name := v.RouteName
if name == "" {
name = v.RoutePath
}
t := &input2.UserMenu{
Id: v.Id,
Name: name,
Component: v.Component,
Path: v.RoutePath,
Redirect: v.Redirect,
Meta: input2.Meta{
AlwaysShow: v.AlwaysShow == 1,
Hidden: v.Enable != 1,
Icon: v.Icon,
KeepAlive: v.KeepAlive == 1,
Title: v.Name,
},
}
child := s.GetTree(v.Id, list)
if len(child) > 0 {
t.Children = child
}
tree = append(tree, t)
}
}
return
}
func (s *login) CaptchaGet(ctx context.Context, req *v1.CaptchaReq) (res *v1.CaptchaRes, err error) {
res = &v1.CaptchaRes{}
res.CodeId, res.Img, err = captcha.Generate(ctx)

View File

@@ -2,21 +2,25 @@ package logic
import (
"context"
"fmt"
"gmanager/api/admin/v1"
"gmanager/internal/admin/consts"
"gmanager/internal/admin/dao"
"gmanager/internal/admin/model/do"
"gmanager/internal/admin/model/entity"
"gmanager/internal/admin/model/input"
"gmanager/internal/library/cache"
"gmanager/internal/library/gftoken"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/gogf/gf/v2/util/guid"
v1 "gmanager/api/admin/v1"
"gmanager/internal/admin/consts"
dao2 "gmanager/internal/admin/dao"
"gmanager/internal/admin/model/do"
entity2 "gmanager/internal/admin/model/entity"
input2 "gmanager/internal/admin/model/input"
"gmanager/internal/library/gftoken"
)
// User 用户服务
@@ -29,8 +33,8 @@ func (s *user) List(ctx context.Context, in *v1.UserListReq) (res *v1.UserListRe
if in == nil {
return
}
m := dao2.User.Ctx(ctx)
columns := dao2.User.Columns()
m := dao.User.Ctx(ctx)
columns := dao.User.Columns()
res = &v1.UserListRes{}
// where条件
@@ -67,7 +71,7 @@ func (s *user) List(ctx context.Context, in *v1.UserListReq) (res *v1.UserListRe
} else {
m = m.Order("id desc")
}
var pageList []*input2.User
var pageList []*input.User
if err = m.Page(in.PageNum, in.PageSize).Scan(&pageList); err != nil {
err = gerror.Wrap(err, "获取数据失败!")
}
@@ -87,11 +91,11 @@ func (s *user) List(ctx context.Context, in *v1.UserListReq) (res *v1.UserListRe
// Get 获取用户详情
func (s *user) Get(ctx context.Context, id int64) (res *v1.UserGetRes, err error) {
err = dao2.User.Ctx(ctx).Where(dao2.User.Columns().Id, id).Scan(&res)
err = dao.User.Ctx(ctx).Where(dao.User.Columns().Id, id).Scan(&res)
if err != nil {
return
}
values, err := dao2.UserRole.Ctx(ctx).Fields(dao2.UserRole.Columns().RoleId).Where(dao2.UserRole.Columns().UserId, id).Array()
values, err := dao.UserRole.Ctx(ctx).Fields(dao.UserRole.Columns().RoleId).Where(dao.UserRole.Columns().UserId, id).Array()
if err != nil {
return
}
@@ -107,8 +111,8 @@ func (s *user) Save(ctx context.Context, in *v1.UserSaveReq) error {
return gerror.Wrap(err, "数据转换错误")
}
m := dao2.User.Ctx(ctx)
columns := dao2.User.Columns()
m := dao.User.Ctx(ctx)
columns := dao.User.Columns()
// 用户名唯一性校验
nameCount, err := m.Where(columns.UserName, model.UserName).
@@ -130,7 +134,7 @@ func (s *user) Save(ctx context.Context, in *v1.UserSaveReq) error {
}
_ = Log.Save(ctx, model, consts.UPDATE)
// 删除历史角色
_, err = dao2.UserRole.Ctx(ctx).Where(dao2.UserRole.Columns().UserId, model.Id).Delete()
_, err = dao.UserRole.Ctx(ctx).Where(dao.UserRole.Columns().UserId, model.Id).Delete()
if err != nil {
return err
}
@@ -156,7 +160,7 @@ func (s *user) Save(ctx context.Context, in *v1.UserSaveReq) error {
return err
}
model.Id = modelId
_ = Log.SaveLog(ctx, &input2.LogData{
_ = Log.SaveLog(ctx, &input.LogData{
Model: model,
OperType: consts.INSERT,
OperRemark: "角色ID" + gconv.String(in.RoleIds),
@@ -167,24 +171,24 @@ func (s *user) Save(ctx context.Context, in *v1.UserSaveReq) error {
userRoleList := g.List{}
for _, roleId := range in.RoleIds {
userRoleList = append(userRoleList,
g.Map{dao2.UserRole.Columns().UserId: model.Id,
dao2.UserRole.Columns().RoleId: roleId,
g.Map{dao.UserRole.Columns().UserId: model.Id,
dao.UserRole.Columns().RoleId: roleId,
})
}
_, err = dao2.UserRole.Ctx(ctx).Insert(userRoleList)
_, err = dao.UserRole.Ctx(ctx).Insert(userRoleList)
return err
}
// Delete 删除用户
func (s *user) Delete(ctx context.Context, ids []int) error {
// 删除用户角色关联
_, err := dao2.UserRole.Ctx(ctx).WhereIn(dao2.UserRole.Columns().UserId, ids).Delete()
_, err := dao.UserRole.Ctx(ctx).WhereIn(dao.UserRole.Columns().UserId, ids).Delete()
if err != nil {
return err
}
// 删除用户
_, err = dao2.User.Ctx(ctx).WhereIn(dao2.User.Columns().Id, ids).Delete()
_, err = dao.User.Ctx(ctx).WhereIn(dao.User.Columns().Id, ids).Delete()
if err != nil {
return err
}
@@ -209,8 +213,8 @@ func (s *user) PasswordReset(ctx context.Context, in *v1.UserPasswordResetReq) e
return err
}
userId := gftoken.GetSessionUser(ctx).Id
columns := dao2.User.Columns()
_, err = dao2.User.Ctx(ctx).Where(columns.Id, in.Id).Update(do.User{
columns := dao.User.Columns()
_, err = dao.User.Ctx(ctx).Where(columns.Id, in.Id).Update(do.User{
UpdateId: userId,
UpdateAt: gtime.Now(),
Password: password,
@@ -219,9 +223,9 @@ func (s *user) PasswordReset(ctx context.Context, in *v1.UserPasswordResetReq) e
}
// UserInfo 获取用户信息接口
func (s *login) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) {
var model *entity2.User
err = dao2.User.Ctx(ctx).Where(dao2.User.Columns().UserName, gftoken.GetUserKey(ctx)).Scan(&model)
func (s *user) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) {
var model *entity.User
err = dao.User.Ctx(ctx).Where(dao.User.Columns().UserName, gftoken.GetUserKey(ctx)).Scan(&model)
if err != nil {
return
}
@@ -229,11 +233,11 @@ func (s *login) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.User
err = gerror.NewCode(gcode.CodeValidationFailed, "用户名信息获取失败!")
return
}
perms, err := getUserPerms(ctx, model.Id, model.UserType)
perms, err := getUserPerms(ctx, false)
if err != nil {
return
}
roleNames, err := getUserRoleNames(ctx, model.Id, model.UserType)
roleNames, err := getUserRoleNames(ctx)
if err != nil {
return
}
@@ -250,35 +254,65 @@ func (s *login) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.User
}
// UserMenus 获取用户菜单接口
func (s *login) UserMenus(ctx context.Context, in *v1.UserMenusReq) (res *v1.UserMenusRes, err error) {
func (s *user) UserMenus(ctx context.Context, in *v1.UserMenusReq) (res *v1.UserMenusRes, err error) {
var (
model *entity2.User
menus []*entity2.Menu
columns = dao2.Menu.Columns()
menus []*entity.Menu
)
res = &v1.UserMenusRes{}
m := dao2.Menu.Ctx(ctx).Where(columns.Enable, consts.EnableYes).WhereNot(columns.Type, consts.MenuTypeButton)
// 获取当前用户
err = dao2.User.Ctx(ctx).Where(dao2.User.Columns().UserName, gftoken.GetUserKey(ctx)).Scan(&model)
menus, err = getUserMenus(ctx, false)
if err != nil {
return
}
if model.UserType == consts.UserTypeAdmin {
if len(menus) > 0 {
tree := s.GetTree(0, menus)
res = &tree
}
return
}
/** getUserMenus 获取用户菜单
* @param cacheFlag 是否缓存
*/
func getUserMenus(ctx context.Context, cacheFlag bool) (menus []*entity.Menu, err error) {
var (
columns = dao.Menu.Columns()
)
sessionUser := gftoken.GetSessionUser(ctx)
if sessionUser == nil {
return
}
if cacheFlag { // 使用缓存
cacheMap, err2 := cache.Instance().Get(ctx, fmt.Sprintf(consts.CacheUserMenu, sessionUser.Id))
if err2 != nil {
return nil, err2
}
if len(cacheMap) > 0 {
err = gconv.Struct(cacheMap[consts.CacheData], &menus)
if err != nil {
return nil, err
}
if len(menus) > 0 {
return
}
}
}
m := dao.Menu.Ctx(ctx).Where(columns.Enable, consts.EnableYes).WhereNot(columns.Type, consts.MenuTypeButton)
if sessionUser.UserType == consts.UserTypeAdmin {
m = m.OrderAsc(columns.Sort)
if err = m.Scan(&menus); err != nil {
err = gerror.Wrap(err, "获取数据失败!")
}
} else {
roleIds, err2 := dao2.UserRole.Ctx(ctx).Fields(dao2.UserRole.Columns().RoleId).
Where(dao2.UserRole.Columns().UserId, model.Id).Array()
roleIds, err2 := dao.UserRole.Ctx(ctx).Fields(dao.UserRole.Columns().RoleId).
Where(dao.UserRole.Columns().UserId, sessionUser.Id).Array()
if err2 != nil {
return nil, err2
}
if len(roleIds) == 0 {
return
}
menuIds, err2 := dao2.RoleMenu.Ctx(ctx).Fields(dao2.RoleMenu.Columns().MenuId).
WhereIn(dao2.RoleMenu.Columns().RoleId, gconv.SliceInt64(roleIds)).Array()
menuIds, err2 := dao.RoleMenu.Ctx(ctx).Fields(dao.RoleMenu.Columns().MenuId).
WhereIn(dao.RoleMenu.Columns().RoleId, gconv.SliceInt64(roleIds)).Array()
if err2 != nil {
return nil, err2
}
@@ -288,56 +322,114 @@ func (s *login) UserMenus(ctx context.Context, in *v1.UserMenusReq) (res *v1.Use
return nil, err2
}
}
// 设置缓存
if len(menus) > 0 {
tree := s.GetTree(0, menus)
res = &tree
err = cache.Instance().Set(ctx, fmt.Sprintf(consts.CacheUserMenu, sessionUser.Id), g.Map{consts.CacheData: menus})
if err != nil {
return
}
}
return
}
// GetTree 菜单树形菜单
func (s *user) GetTree(pid int64, list []*entity.Menu) (tree []*input.UserMenu) {
tree = make([]*input.UserMenu, 0, len(list))
for _, v := range list {
if v.ParentId == pid {
name := v.RouteName
if name == "" {
name = v.RoutePath
}
t := &input.UserMenu{
Id: v.Id,
Name: name,
Component: v.Component,
Path: v.RoutePath,
Redirect: v.Redirect,
Meta: input.Meta{
AlwaysShow: v.AlwaysShow == 1,
Hidden: v.Enable != 1,
Icon: v.Icon,
KeepAlive: v.KeepAlive == 1,
Title: v.Name,
},
}
child := s.GetTree(v.Id, list)
if len(child) > 0 {
t.Children = child
}
tree = append(tree, t)
}
}
return
}
// getUserRoleNames 获取用户对应角色名称
func getUserRoleNames(ctx context.Context, userId int64, userType int) (res []string, err error) {
if userType == consts.UserTypeAdmin {
func getUserRoleNames(ctx context.Context) (res []string, err error) {
sessionUser := gftoken.GetSessionUser(ctx)
if sessionUser == nil {
return
}
if sessionUser.UserType == consts.UserTypeAdmin {
res = append(res, consts.RoleAdmin)
return
}
values, err := dao2.UserRole.Ctx(ctx).Fields(dao2.UserRole.Columns().RoleId).Where(dao2.UserRole.Columns().UserId, userId).Array()
values, err := dao.UserRole.Ctx(ctx).Fields(dao.UserRole.Columns().RoleId).Where(dao.UserRole.Columns().UserId, sessionUser.Id).Array()
if err != nil {
return
}
var roles []*entity2.Role
err = dao2.Role.Ctx(ctx).WhereIn(dao2.Role.Columns().Id, gconv.SliceInt64(values)).Scan(&roles)
var roles []*entity.Role
err = dao.Role.Ctx(ctx).WhereIn(dao.Role.Columns().Id, gconv.SliceInt64(values)).Scan(&roles)
for _, e := range roles {
res = append(res, e.Code)
}
return
}
// getUserPerms 获取用户对应按钮权限
func getUserPerms(ctx context.Context, userId int64, userType int) (res []string, err error) {
/** getUserPerms 获取用户对应按钮权限
* @param cacheFlag 是否使用缓存
*/
func getUserPerms(ctx context.Context, cacheFlag bool) (res []string, err error) {
sessionUser := gftoken.GetSessionUser(ctx)
if sessionUser == nil {
return
}
if cacheFlag { // 使用缓存
cacheMap, err2 := cache.Instance().Get(ctx, fmt.Sprintf(consts.CacheUserPerm, sessionUser.Id))
if err2 != nil {
return nil, err2
}
if len(cacheMap) > 0 {
res = gconv.SliceStr(cacheMap[consts.CacheData])
if len(res) > 0 {
return
}
}
}
// 管理员权限
var menus []*entity2.Menu
columns := dao2.Menu.Columns()
m := dao2.Menu.Ctx(ctx).Where(columns.Enable, consts.EnableYes).Where(columns.Type, consts.MenuTypeButton)
if userType == consts.UserTypeAdmin {
var menus []*entity.Menu
columns := dao.Menu.Columns()
m := dao.Menu.Ctx(ctx).Where(columns.Enable, consts.EnableYes).Where(columns.Type, consts.MenuTypeButton)
if sessionUser.UserType == consts.UserTypeAdmin {
// 管理员获取所有按钮权限
if err = m.Scan(&menus); err != nil {
return nil, err
}
} else {
roleIds, err2 := dao2.UserRole.Ctx(ctx).Fields(dao2.UserRole.Columns().RoleId).
Where(dao2.UserRole.Columns().UserId, userId).Array()
roleIds, err2 := dao.UserRole.Ctx(ctx).Fields(dao.UserRole.Columns().RoleId).
Where(dao.UserRole.Columns().UserId, sessionUser.Id).Array()
if err2 != nil {
return nil, err2
}
if len(roleIds) == 0 {
return
}
menuIds, err2 := dao2.RoleMenu.Ctx(ctx).Fields(dao2.RoleMenu.Columns().MenuId).
WhereIn(dao2.RoleMenu.Columns().RoleId, gconv.SliceInt64(roleIds)).Array()
menuIds, err2 := dao.RoleMenu.Ctx(ctx).Fields(dao.RoleMenu.Columns().MenuId).
WhereIn(dao.RoleMenu.Columns().RoleId, gconv.SliceInt64(roleIds)).Array()
if err2 != nil {
return nil, err2
}
@@ -356,5 +448,45 @@ func getUserPerms(ctx context.Context, userId int64, userType int) (res []string
}
}
}
// 设置缓存
if len(res) > 0 {
err = cache.Instance().Set(ctx, fmt.Sprintf(consts.CacheUserPerm, sessionUser.Id), g.Map{consts.CacheData: res})
if err != nil {
return
}
}
return
}
func (s *user) CheckPerm(ctx context.Context, perm string) bool {
perms, err := getUserPerms(ctx, true)
if err != nil {
g.Log().Info(ctx, err)
return false
}
for _, userPerm := range perms {
if userPerm == perm {
return true
}
}
return false
}
// CheckUrl 菜单校验
// TODO 只有用户菜单权限,但是用户菜单以来组织机构和角色???
func (s *user) CheckUrl(ctx context.Context, path string) bool {
menus, err := getUserMenus(ctx, true)
if err != nil {
g.Log().Info(ctx, err)
return false
}
for _, e := range menus {
if e.Type != consts.MenuTypeMenu {
continue
}
if gstr.HasPrefix(path, "/admin/"+e.RoutePath) {
return true
}
}
return false
}

View File

@@ -0,0 +1,119 @@
package logic
import (
"context"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
v1 "gmanager/api/admin/v1"
"gmanager/internal/admin/consts"
dao2 "gmanager/internal/admin/dao"
"gmanager/internal/admin/model/do"
"gmanager/internal/library/gftoken"
)
func (s *user) Profile(ctx context.Context, req *v1.UserProfileReq) (res *v1.UserProfileRes, err error) {
model, err := s.Get(ctx, gftoken.GetUserId(ctx))
if err != nil {
return
}
if model == nil {
return nil, nil
}
deptMap, err := Dept.DeptMap(ctx)
if err != nil {
return nil, err
}
val, err := dao2.Role.Ctx(ctx).Fields("GROUP_CONCAT(name)").WhereIn(dao2.Role.Columns().Id, model.RoleIds).Value()
if err != nil {
return nil, err
}
res = &v1.UserProfileRes{
Id: model.Id,
UserName: model.UserName,
NickName: model.NickName,
Mobile: model.Mobile,
Avatar: model.Avatar,
Email: model.Email,
Gender: model.Gender,
CreateAt: model.CreateAt,
DeptName: deptMap[model.DeptId].Name,
RoleNames: val.String(),
}
return
}
func (s *user) SaveProfile(ctx context.Context, in *v1.UserSaveProfileReq) error {
userId := gftoken.GetUserId(ctx)
var model do.User
err := gconv.Struct(in, &model)
if err != nil {
return gerror.Wrap(err, "数据转换错误")
}
model.Id = userId
model.UpdateId = userId
model.UpdateAt = gtime.Now()
_, err = dao2.User.Ctx(ctx).OmitEmpty().Where(dao2.User.Columns().Id, model.Id).Update(model)
if err != nil {
return err
}
_ = Log.Save(ctx, model, consts.UPDATE)
return err
}
// ChangePassword 修改密码
func (s *user) ChangePassword(ctx context.Context, in *v1.UserChangePasswordReq) error {
userId := gftoken.GetUserId(ctx)
res, err := s.Get(ctx, userId)
if err != nil {
return err
}
if res == nil {
return nil
}
oldPassword, err := gmd5.Encrypt(in.OldPassword + res.Salt)
if err != nil {
return err
}
if oldPassword != res.Password {
return gerror.New("原密码错误")
}
password, err := gmd5.Encrypt(in.NewPassword + res.Salt)
if err != nil {
return err
}
columns := dao2.User.Columns()
_, err = dao2.User.Ctx(ctx).Where(columns.Id, userId).Update(do.User{
UpdateId: userId,
UpdateAt: gtime.Now(),
Password: password,
})
return nil
}
func (s *user) SendMobileCode(ctx context.Context, req *v1.UserSendMobileCodeReq) error {
return nil
}
func (s *user) SaveMobile(ctx context.Context, req *v1.UserSaveMobileReq) error {
// 验证码校验
userId := gftoken.GetUserId(ctx)
return s.SaveProfile(ctx, &v1.UserSaveProfileReq{Id: userId, Mobile: req.Mobile})
}
func (s *user) SendEmailCode(ctx context.Context, req *v1.UserSendEmailCodeReq) error {
return nil
}
func (s *user) SaveEmail(ctx context.Context, req *v1.UserSaveEmailReq) error {
// 验证码校验
userId := gftoken.GetUserId(ctx)
return s.SaveProfile(ctx, &v1.UserSaveProfileReq{Id: userId, Email: req.Email})
}

View File

@@ -0,0 +1,23 @@
package middleware
import (
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
)
// DemoNotice 演示环境提示
func DemoNotice(r *ghttp.Request) {
r.Middleware.Next()
var (
msg string
err = r.GetError()
)
if err != nil {
msg = err.Error()
if gstr.Contains(msg, "denied to user") {
r.SetError(gerror.New("演示环境,禁止操作"))
}
}
}

View File

@@ -0,0 +1,50 @@
package middleware
import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"gmanager/internal/admin/consts"
"gmanager/internal/admin/logic"
"gmanager/internal/library/gftoken"
)
// UserPerm 权限校验
func UserPerm(r *ghttp.Request) {
// 不认证URL
if gftoken.HasExcludePath(r) {
r.Middleware.Next()
return
}
ctx := r.Context()
user := gftoken.GetSessionUser(ctx)
// 用户登陆校验部分需要处理
if user == nil {
r.Middleware.Next()
return
}
// 管理员不校验
if user.UserType == consts.UserTypeAdmin {
r.Middleware.Next()
return
}
// 按钮权限校验
perms := r.GetServeHandler().GetMetaTag("perms")
if perms != "" { // 需要权限校验
permArray := gstr.Split(perms, ",")
for _, perm := range permArray {
if !logic.User.CheckPerm(ctx, perm) {
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
Code: gcode.CodeSecurityReason.Code(),
Message: "按钮权限不足",
})
r.ExitAll()
}
}
}
r.Middleware.Next()
}

View File

@@ -1,6 +1,7 @@
package input
import (
"github.com/gogf/gf/v2/os/gtime"
"gmanager/internal/admin/model/entity"
)
@@ -14,3 +15,16 @@ type User struct {
DeptName string `json:"deptName"`
RoleIds []int64 `json:"roleIds"`
}
type UserProfile struct {
Id int64 `json:"id" description:"主键"`
UserName string `json:"userName" description:"登录名/11111"`
Mobile string `json:"mobile" description:"手机号"`
Email string `json:"email" description:"email"`
NickName string `json:"nickName" description:"昵称"`
Gender int `json:"gender" description:"性别;0:保密,1:男,2:女"`
Avatar string `json:"avatar" description:"头像地址"`
CreateAt *gtime.Time `json:"createAt" description:"创建时间"`
DeptName string `json:"deptName" description:"部门"`
RoleNames string `json:"roleNames" description:"角色"`
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcmd"
"gmanager/internal/admin/controller"
"gmanager/internal/admin/middleware"
common "gmanager/internal/common/controller"
"gmanager/internal/library/cache"
"gmanager/internal/library/gftoken"
)
@@ -31,13 +33,14 @@ var (
//跨域处理,安全起见正式环境请注释该行
group.Middleware(func(r *ghttp.Request) {
r.Response.CORSDefault()
g.Log().Info(ctx, r.GetServeHandler().GetMetaTag("perms"))
r.Middleware.Next()
})
// gtoken认证
group.Middleware(gftoken.MiddlewareAuth)
group.Middleware(gftoken.MiddlewareAuth) // gtoken登陆认证
group.Middleware(middleware.UserPerm) // 用户权限认证
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Middleware(middleware.DemoNotice) // 演示环境提示
group.Bind(
common.Upload,
controller.Login,
controller.Dept,
controller.User,

View File

@@ -0,0 +1,5 @@
package consts
const (
StorageTypeLocal = 1
)

View File

@@ -0,0 +1,16 @@
package controller
import (
"context"
v1 "gmanager/api/common/v1"
"gmanager/internal/common/logic"
)
type upload struct{}
var Upload = new(upload)
func (c *upload) Upload(ctx context.Context, req *v1.UploadFileReq) (res *v1.UploadFileRes, err error) {
res, err = logic.Upload.Upload(ctx, req)
return
}

View File

@@ -0,0 +1,50 @@
package logic
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"gmanager/internal/common/consts"
"gmanager/internal/common/model/input"
"gmanager/internal/common/service"
)
type storageFile struct{}
func NewStorageFile() *storageFile {
return &storageFile{}
}
func init() {
service.RegisterStorage(NewStorageFile())
}
func (s *storageFile) Upload(ctx context.Context, file *input.UploadFile) (res *input.UploadFileRes, err error) {
// TODO 上传信息需要配置化
var (
attachmentPath = "attachment"
nowDate = gtime.Date()
storageType = consts.StorageTypeLocal
)
fullDirPath := gfile.MainPkgPath() + "/resource/public/" + attachmentPath + "/" + nowDate
fileName, err := file.File.Save(fullDirPath, true)
if err != nil {
return
}
// 不含静态文件夹的路径
fullPath := "/" + attachmentPath + "/" + nowDate + "/" + fileName
res = &input.UploadFileRes{
Name: fileName,
OriName: file.File.Filename,
Type: storageType,
Path: fullDirPath,
FileUrl: "http://localhost:8000" + fullPath,
Size: file.File.Size,
Ext: gfile.Ext(fullPath),
}
g.Log().Info(ctx, "upload file", res)
return
}

View File

@@ -0,0 +1,31 @@
package logic
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
v1 "gmanager/api/common/v1"
"gmanager/internal/common/model/input"
"gmanager/internal/common/service"
)
// Upload 上传服务
var Upload = new(upload)
type upload struct{}
// Upload 上传文件
func (s *upload) Upload(ctx context.Context, in *v1.UploadFileReq) (res *v1.UploadFileRes, err error) {
uploadRes, err := service.Storage().Upload(ctx, &input.UploadFile{File: in.File})
if err != nil {
return
}
if uploadRes == nil {
err = gerror.New("上传失败")
return
}
res = &v1.UploadFileRes{
Name: uploadRes.Name,
Url: uploadRes.FileUrl,
}
return
}

View File

@@ -0,0 +1,17 @@
package input
import "github.com/gogf/gf/v2/net/ghttp"
type UploadFile struct {
File *ghttp.UploadFile `json:"file" type:"file" dc:"文件"`
}
type UploadFileRes struct {
Name string `json:"name" description:"文件名"`
OriName string `json:"oriName" description:"文件原始名"`
Path string `json:"path" description:"本地路径"`
FileUrl string `json:"fileUrl" description:"url"`
Type int `json:"storageType" description:"存储类型"`
Size int64 `json:"size" description:"文件大小"`
Ext string `json:"ext" description:"扩展名"`
}

View File

View File

@@ -0,0 +1,28 @@
package service
import (
"context"
"gmanager/internal/common/model/input"
)
type (
IStorage interface {
// Upload 上传文件
Upload(ctx context.Context, file *input.UploadFile) (res *input.UploadFileRes, err error)
}
)
var (
storage IStorage
)
func Storage() IStorage {
if storage == nil {
panic("implement not found for interface IStorage, forgot register?")
}
return storage
}
func RegisterStorage(i IStorage) {
storage = i
}

View File

@@ -1,8 +1,9 @@
package bean
type SessionUser struct {
Id int64 `form:"id" json:"id"` // 主键
Uuid string `form:"uuid" json:"uuid"` // UUID
Username string `form:"username" json:"username"` // 登录名/11111
NickName string `form:"nickname" json:"nickname"` // 昵称
Id int64 `json:"id"` // 主键
Uuid string `json:"uuid"` // UUID
UserName string `json:"userName"` // 登录名/11111
NickName string `json:"nickName"` // 昵称
UserType int `json:"userType"` // 类型
}

View File

@@ -11,6 +11,7 @@ import (
)
var GToken gtoken.Token
var m gtoken.Middleware
func init() {
options := &gtoken.Options{}
@@ -21,17 +22,30 @@ func init() {
}
// 创建gtoken对象
GToken = gtoken.NewDefaultToken(*options)
m = gtoken.NewDefaultMiddleware(GToken,
"/admin/login", "/admin/captcha/get")
}
func MiddlewareAuth(r *ghttp.Request) {
gtoken.NewDefaultMiddleware(GToken,
"/admin/login", "/admin/captcha/get").Auth(r)
m.Auth(r)
}
func HasExcludePath(r *ghttp.Request) bool {
return m.HasExcludePath(r)
}
func GetUserKey(ctx context.Context) string {
return g.RequestFromCtx(ctx).GetCtxVar(gtoken.KeyUserKey).String()
}
func GetUserId(ctx context.Context) int64 {
user := GetSessionUser(ctx)
if user == nil {
return 0
}
return user.Id
}
func GetSessionUser(ctx context.Context) *bean.SessionUser {
var user *bean.SessionUser
data, err := GetData(ctx)
@@ -48,7 +62,10 @@ func GetSessionUser(ctx context.Context) *bean.SessionUser {
}
func GetData(ctx context.Context) (data any, err error) {
userKey := g.RequestFromCtx(ctx).GetCtxVar(gtoken.KeyUserKey).String()
_, data, err = GToken.Get(ctx, userKey)
userKey := g.RequestFromCtx(ctx).GetCtxVar(gtoken.KeyUserKey)
if userKey.IsNil() {
return
}
_, data, err = GToken.Get(ctx, userKey.String())
return
}

View File

@@ -3,7 +3,6 @@ server:
address: ":8000"
openapiPath: "/api.json"
swaggerPath: "/swagger"
serverRoot: "resource/public" # 静态文件服务的目录根路径,配置时自动开启静态文件服务。
# 日志基本配置
# 此配置类似nginx主要对请求日志的记录
logPath: "./logs" # 日志文件存储目录路径,建议使用绝对路径。默认为空,表示关闭
@@ -37,7 +36,7 @@ database:
level: "all"
stdout: true
default:
link: "mysql:uroot:Aa123456!#@tcp(127.0.0.1:3306)/gmanager"
link: "mysql:uroot:Aa123456!#@tcp(127.0.0.1:3306)/gf_cms"
debug: true
gToken: