This commit is contained in:
2026-03-18 10:19:42 +08:00
parent 2526ad4414
commit e58dd3529d
267 changed files with 25279 additions and 2 deletions

View File

@@ -0,0 +1,86 @@
/*
* @desc:用户处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 15:08
*/
package tenant
import (
"context"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonConsts "github.com/tiger1103/gfast/v3/internal/app/common/consts"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterAreaDict(New())
}
type sAreaDict struct {
}
func New() *sAreaDict {
return &sAreaDict{}
}
func (s *sAreaDict) GetAreaDictListSearch(ctx context.Context, req *system.AreaDictListReq) (res *system.AreaDictListRes, err error) {
res = new(system.AreaDictListRes)
g.Try(ctx, func(ctx context.Context) {
model := dao.AreaDictDao.Ctx(ctx)
res.Total, err = model.Count()
liberr.ErrIsNil(ctx, err, "获取租户数据失败")
if req.PageNum == 0 {
req.PageNum = 1
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
err = model.Page(res.CurrentPage, req.PageSize).Order("id asc").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
// GetAreaDicById 通过ids查询多个地区信息
func (s *sAreaDict) GetAreaDicById(ctx context.Context, ids []string) (area []*model.AreaDictRes, err error) {
if len(ids) == 0 {
return
}
idsSet := gset.NewStrSetFrom(ids).Slice()
err = g.Try(ctx, func(ctx context.Context) {
err = dao.AreaDictDao.Ctx(ctx).Where(dao.SysUser.Columns().Id+" in(?)", idsSet).
Order(dao.AreaDictDao.Columns().Id + " ASC").Scan(&area)
})
return
}
// GetAreaDict 获取所有正常状态下的
func (s *sAreaDict) GetAreaDict(ctx context.Context) (list []*model.AreaDictRes, err error) {
cache := commonService.Cache()
//从缓存获取
data := cache.Get(ctx, commonConsts.CacheSysDict+"_area")
if !data.IsNil() {
err = data.Structs(&list)
return
}
err = g.Try(ctx, func(ctx context.Context) {
err = dao.AreaDictDao.Ctx(ctx).Where("status", 1).Order("id ASC").Scan(&list)
liberr.ErrIsNil(ctx, err, "获取字典类型数据出错")
//缓存
cache.Set(ctx, commonConsts.CacheSysDict+"_area", list, 0, commonConsts.CacheSysDictTag)
})
return
}

View File

@@ -0,0 +1,66 @@
/*
* @desc:context-service
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 14:51
*/
package context
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
func init() {
service.RegisterContext(New())
}
type sContext struct{}
func New() *sContext {
return &sContext{}
}
// Init 初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改。
func (s *sContext) Init(r *ghttp.Request, customCtx *model.Context) {
r.SetCtxVar(consts.CtxKey, customCtx)
}
// Get 获得上下文变量如果没有设置那么返回nil
func (s *sContext) Get(ctx context.Context) *model.Context {
value := ctx.Value(consts.CtxKey)
if value == nil {
return nil
}
if localCtx, ok := value.(*model.Context); ok {
return localCtx
}
return nil
}
// SetUser 将上下文信息设置到上下文请求中,注意是完整覆盖
func (s *sContext) SetUser(ctx context.Context, ctxUser *model.ContextUser) {
s.Get(ctx).User = ctxUser
}
// GetLoginUser 获取当前登陆用户信息
func (s *sContext) GetLoginUser(ctx context.Context) *model.ContextUser {
context := s.Get(ctx)
if context == nil {
return nil
}
return context.User
}
// GetUserId 获取当前登录用户id
func (s *sContext) GetUserId(ctx context.Context) uint64 {
user := s.GetLoginUser(ctx)
if user != nil {
return user.Id
}
return 0
}

View File

@@ -0,0 +1,17 @@
package logic
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/context"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/middleware"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/personal"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysAuthRule"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysDept"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysLoginLog"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysOperLog"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysPost"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysRole"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUser"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUserOnline"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/token"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/tenant"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/areaDict"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/moduleTenant"

View File

@@ -0,0 +1,135 @@
/*
* @desc:中间件
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 15:05
*/
package middleware
import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libResponse"
)
func init() {
service.RegisterMiddleware(New())
}
func New() *sMiddleware {
return &sMiddleware{}
}
type sMiddleware struct{}
// Ctx 自定义上下文对象
func (s *sMiddleware) Ctx(r *ghttp.Request) {
ctx := r.GetCtx()
// 初始化登录用户信息
data, err := service.GfToken().ParseToken(r)
if err != nil {
// 执行下一步请求逻辑
r.Middleware.Next()
}
if data != nil {
context := new(model.Context)
err = gconv.Struct(data.Data, &context.User)
if err != nil {
g.Log().Error(ctx, err)
// 执行下一步请求逻辑
r.Middleware.Next()
}
service.Context().Init(r, context)
}
// 执行下一步请求逻辑
r.Middleware.Next()
}
// Auth 权限判断处理中间件
func (s *sMiddleware) Auth(r *ghttp.Request) {
ctx := r.GetCtx()
//获取登陆用户id
adminId := service.Context().GetUserId(ctx)
accessParams := r.Get("accessParams").Strings()
accessParamsStr := ""
if len(accessParams) > 0 && accessParams[0] != "undefined" {
accessParamsStr = "?" + gstr.Join(accessParams, "&")
}
url := gstr.TrimLeft(r.Request.URL.Path, "/") + accessParamsStr
/*if r.Method != "GET" && adminId != 1 && url!="api/v1/system/login" {
libResponse.FailJson(true, r, "对不起!演示系统,不能删改数据!")
}*/
//获取无需验证权限的用户id
tagSuperAdmin := false
service.SysUser().NotCheckAuthAdminIds(ctx).Iterator(func(v interface{}) bool {
if gconv.Uint64(v) == adminId {
tagSuperAdmin = true
return false
}
return true
})
if tagSuperAdmin {
r.Middleware.Next()
//不要再往后面执行
return
}
//获取地址对应的菜单id
menuList, err := service.SysAuthRule().GetMenuList(ctx)
if err != nil {
g.Log().Error(ctx, err)
libResponse.FailJson(true, r, "请求数据失败")
}
var menu *model.SysAuthRuleInfoRes
for _, m := range menuList {
ms := gstr.SubStr(m.Name, 0, gstr.Pos(m.Name, "?"))
if m.Name == url || ms == url {
menu = m
break
}
}
//只验证存在数据库中的规则
if menu != nil {
//若是不登录能访问的接口则不判断权限
excludePaths := g.Cfg().MustGet(ctx, "gfToken.excludePaths").Strings()
for _, p := range excludePaths {
if gstr.Equal(menu.Name, gstr.TrimLeft(p, "/")) {
r.Middleware.Next()
return
}
}
//若存在不需要验证的条件则跳过
if gstr.Equal(menu.Condition, "nocheck") {
r.Middleware.Next()
return
}
menuId := menu.Id
//菜单没存数据库不验证权限
if menuId != 0 {
//判断权限操作
enforcer, err := commonService.CasbinEnforcer(ctx)
if err != nil {
g.Log().Error(ctx, err)
libResponse.FailJson(true, r, "获取权限失败")
}
hasAccess := false
hasAccess, err = enforcer.Enforce(fmt.Sprintf("%s%d", service.SysUser().GetCasBinUserPrefix(), adminId), gconv.String(menuId), "All")
if err != nil {
g.Log().Error(ctx, err)
libResponse.FailJson(true, r, "判断权限失败")
}
if !hasAccess {
libResponse.FailJson(true, r, "没有访问权限")
}
}
} else if menu == nil && accessParamsStr != "" {
libResponse.FailJson(true, r, "没有访问权限")
}
r.Middleware.Next()
}

View File

@@ -0,0 +1,189 @@
/*
* @desc:模块租户关系处理
* @company:云南奇讯科技有限公司
* @Author: system
* @Date: 2026/1/6
*/
package moduleTenant
import (
"context"
"fmt"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/http"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
"time"
)
func init() {
service.RegisterModuleTenant(New())
}
type sModuleTenant struct {
}
func New() *sModuleTenant {
return &sModuleTenant{}
}
// Add 添加模块租户关系
func (s *sModuleTenant) Add(ctx context.Context, req *system.ModuleTenantAddReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
// 获取用户信息
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err, "获取用户信息失败")
// 获取sku信息
assetSukRes := new(system.AssetSku)
// 获取当前请求的 headers 并传递到下游
headers := make(map[string]string)
if r := g.RequestFromCtx(ctx); r != nil {
for k, v := range r.Request.Header {
if len(v) > 0 {
headers[k] = v[0]
}
}
}
if err = http.Get(ctx, "asset/sku/getAssetSkuModule", headers, &assetSukRes,
"id", req.AssetSkuId,
); err != nil {
return
}
liberr.ErrIsNil(ctx, err, "获取资产sku信息失败")
if assetSukRes.ExpireAt != nil {
liberr.ErrIsNil(ctx, err, "sku到期时间不能为空")
}
// 获取模块key
var moduleKey string
// 遍历 map 的所有键值对
for key, value := range beans.ModuleAssetId {
if value == assetSukRes.AssetId.Hex() {
moduleKey = key
break
}
}
// 检查是否已存在相同的模块租户关系
var moduleTenant *entity.ModuleTenant
moduleTenant, err = s.GetByModuleKeyAndTenantId(ctx, moduleKey, gconv.Uint64(getUserInfo.TenantId))
liberr.ErrIsNil(ctx, err, "检查模块租户关系失败")
if moduleTenant != nil {
now := gtime.Now()
if moduleTenant.ExpireAt != nil && !moduleTenant.ExpireAt.Before(now) {
// 使用原到期时间 + SKU到期时间
duration := assetSukRes.ExpireAt.Sub(gtime.Now())
assetSukRes.ExpireAt = moduleTenant.ExpireAt.Add(duration)
}
// 更新模块租户关系
_, err = dao.ModuleTenant.Ctx(ctx).TX(tx).WherePri(moduleTenant.Id).Update(do.ModuleTenant{
UpdateBy: getUserInfo.UserName,
ExpireAt: assetSukRes.ExpireAt,
})
return
}
// 设置认证状态
certificationStatus := consts.CertificationStatusPass
if req.TenantModuleType == beans.TenantModuleTypeSupplier {
certificationStatus = consts.CertificationStatusUnverified
}
// 添加模块租户关系
_, err = dao.ModuleTenant.Ctx(ctx).TX(tx).InsertAndGetId(do.ModuleTenant{
CreateBy: getUserInfo.UserName,
UpdateBy: getUserInfo.UserName,
ModuleKey: moduleKey,
AssetId: assetSukRes.AssetId.Hex(),
AssetSkuId: req.AssetSkuId.Hex(),
TenantId: getUserInfo.TenantId,
TenantModuleType: req.TenantModuleType,
CertificationStatus: certificationStatus,
ExpireAt: assetSukRes.ExpireAt,
})
liberr.ErrIsNil(ctx, err, "添加模块租户关系失败")
// 设置缓存
_, err = s.AddRedisByTenantId(ctx, &system.AddRedisByTenantIdReq{
TenantId: getUserInfo.TenantId,
})
liberr.ErrIsNil(ctx, err, "设置缓存失败")
})
return err
})
return
}
// Check 检查模块开通状态
func (s *sModuleTenant) Check(ctx context.Context, req *system.ModuleTenantCheckReq) (res *system.ModuleTenantCheckRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
res = new(system.ModuleTenantCheckRes)
// 查询模块租户关系
moduleTenant, err := s.GetByModuleKeyAndTenantId(ctx, req.ModuleKey, req.TenantId)
liberr.ErrIsNil(ctx, err, "查询模块租户关系失败")
// 判断状态
if g.IsEmpty(moduleTenant) {
// 没有记录,未开通
res.Message = "您未开通此功能模块,请开通后再使用"
res.Status = false
} else {
_, err = s.AddRedisByTenantId(ctx, &system.AddRedisByTenantIdReq{
TenantId: req.TenantId,
})
liberr.ErrIsNil(ctx, err, "设置缓存失败")
// 有记录,检查是否到期
now := gtime.Now()
if moduleTenant.ExpireAt != nil && moduleTenant.ExpireAt.Before(now) {
res.Message = "功能模块已到期,请续期后再使用"
res.Status = false
} else {
res.Status = true
if moduleTenant.CertificationStatus == consts.CertificationStatusPass {
res.Message = "已开通"
res.CertificationStatus = true
} else {
keyValue := consts.GetCertificationStatusKeyValue(moduleTenant.CertificationStatus)
res.Message = fmt.Sprintf("功能模块认证状态:%s", keyValue.Value)
res.CertificationStatus = false
}
}
}
})
return
}
// GetByModuleKeyAndTenantId 根据模块Key和租户ID获取模块租户关系
func (s *sModuleTenant) GetByModuleKeyAndTenantId(ctx context.Context, moduleKey string, tenantId uint64) (moduleTenant *entity.ModuleTenant, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.ModuleTenant.Ctx(ctx).
Where(dao.ModuleTenant.Columns().ModuleKey, moduleKey).
Where(dao.ModuleTenant.Columns().TenantId, tenantId).
Scan(&moduleTenant)
liberr.ErrIsNil(ctx, err, "获取模块租户关系失败")
})
return
}
// AddRedisByTenantId 根据租户ID获取模块租户关系存到redis
func (s *sModuleTenant) AddRedisByTenantId(ctx context.Context, req *system.AddRedisByTenantIdReq) (res *system.AddRedisByTenantIdRes, err error) {
res = new(system.AddRedisByTenantIdRes)
//从数据库获取
err = dao.ModuleTenant.Ctx(ctx).
Where(dao.ModuleTenant.Columns().TenantId, req.TenantId).
Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取模块租户关系失败")
if !g.IsEmpty(res.List) {
err = g.Redis().SetEX(ctx, fmt.Sprintf("module_tenant:tenantId-%d", gconv.Int(req.TenantId)), res.List, gconv.Int64(time.Minute*1))
liberr.ErrIsNil(ctx, err, "设置缓存失败")
}
return
}

View File

@@ -0,0 +1,96 @@
/*
* @desc:xxxx功能描述
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/11/3 9:55
*/
package personal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/grand"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
service "github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterPersonal(New())
}
type sPersonal struct {
}
func New() *sPersonal {
return &sPersonal{}
}
func (s *sPersonal) GetPersonalInfo(ctx context.Context, req *system.PersonalInfoReq) (res *system.PersonalInfoRes, err error) {
res = new(system.PersonalInfoRes)
userId := service.Context().GetUserId(ctx)
res.User, err = service.SysUser().GetUserInfoById(ctx, userId)
var dept *entity.SysDept
dept, err = service.SysDept().GetByDeptId(ctx, res.User.DeptId)
res.DeptName = dept.DeptName
allRoles, err := service.SysRole().GetRoleList(ctx)
roles, err := service.SysUser().GetAdminRole(ctx, userId, allRoles)
name := make([]string, len(roles))
roleIds := make([]uint, len(roles))
for k, v := range roles {
name[k] = v.Name
roleIds[k] = v.Id
}
res.Roles = name
if err != nil {
return
}
return
}
func (s *sPersonal) EditPersonal(ctx context.Context, req *system.PersonalEditReq) (user *model.LoginUserRes, err error) {
userId := service.Context().GetUserId(ctx)
err = service.SysUser().UserNameOrMobileExists(ctx, "", req.Mobile, int64(userId))
if err != nil {
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).TX(tx).WherePri(userId).Update(do.SysUser{
Mobile: req.Mobile,
UserNickname: req.Nickname,
Remark: req.Remark,
Sex: req.Sex,
UserEmail: req.UserEmail,
Describe: req.Describe,
Avatar: req.Avatar,
})
liberr.ErrIsNil(ctx, err, "修改用户信息失败")
user, err = service.SysUser().GetUserById(ctx, userId)
liberr.ErrIsNil(ctx, err)
})
return err
})
return
}
func (s *sPersonal) ResetPwdPersonal(ctx context.Context, req *system.PersonalResetPwdReq) (res *system.PersonalResetPwdRes, err error) {
userId := service.Context().GetUserId(ctx)
salt := grand.S(10)
password := libUtils.EncryptPassword(req.Password, salt)
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).WherePri(userId).Update(g.Map{
dao.SysUser.Columns().UserSalt: salt,
dao.SysUser.Columns().UserPassword: password,
})
liberr.ErrIsNil(ctx, err, "重置用户密码失败")
})
return
}

View File

@@ -0,0 +1,360 @@
/*
* @desc:菜单处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 16:14
*/
package sysAuthRule
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysAuthRule(New())
}
func New() *sSysAuthRule {
return &sSysAuthRule{}
}
type sSysAuthRule struct {
}
func (s *sSysAuthRule) GetMenuListSearch(ctx context.Context, req *system.RuleSearchReq) (res []*model.SysAuthRuleInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysAuthRule.Ctx(ctx)
if req.Title != "" {
m = m.Where("title like ?", "%"+req.Title+"%")
}
if req.Component != "" {
m = m.Where("component like ?", "%"+req.Component+"%")
}
err = m.Fields(model.SysAuthRuleInfoRes{}).Order("weigh desc,id asc").Scan(&res)
liberr.ErrIsNil(ctx, err, "获取菜单失败")
})
return
}
// GetIsMenuList 获取isMenu=0|1
func (s *sSysAuthRule) GetIsMenuList(ctx context.Context) ([]*model.SysAuthRuleInfoRes, error) {
list, err := s.GetMenuList(ctx)
if err != nil {
return nil, err
}
var gList = make([]*model.SysAuthRuleInfoRes, 0, len(list))
for _, v := range list {
if v.MenuType == 0 || v.MenuType == 1 {
gList = append(gList, v)
}
}
return gList, nil
}
// GetMenuList 获取所有菜单
func (s *sSysAuthRule) GetMenuList(ctx context.Context) (list []*model.SysAuthRuleInfoRes, err error) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysAuthMenu, s.getMenuListFromDb, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
liberr.ErrIsNil(ctx, err)
}
return
}
// GetMenuListByRole 根据角色获取所有菜单
func (s *sSysAuthRule) GetMenuListByRole(ctx context.Context) (list []*model.SysAuthRuleInfoRes, err error) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysAuthMenu, s.getMenuListFromDb, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
liberr.ErrIsNil(ctx, err)
}
isSuperAdmin, err := service.SysUser().IsSuperAdmin(ctx, &system.IsSuperAdminReq{})
if err != nil {
return
}
if !isSuperAdmin {
// 根据token获取用户id
userId := service.Context().GetUserId(ctx)
if !g.IsEmpty(userId) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e, "获取权限引擎失败")
var userRole []string
userRole, err = enforcer.GetRolesForUser(fmt.Sprintf("%s%d", service.SysUser().GetCasBinUserPrefix(), service.Context().GetUserId(ctx)))
liberr.ErrIsNil(ctx, err, "获取用户角色失败")
userPermissions := enforcer.GetPermissionsForUser(userRole[0])
// 构建规则ID的map避免多次遍历
ruleMap := make(map[string]struct{})
for _, item := range userPermissions {
if len(item) > 1 {
ruleMap[item[1]] = struct{}{}
}
}
// 遍历菜单列表,判断 ruleMap 中是否包含 v.Id
var filteredList []*model.SysAuthRuleInfoRes
for _, v := range list {
if _, exists := ruleMap[gconv.String(v.Id)]; exists {
filteredList = append(filteredList, v)
}
}
list = filteredList
}
}
return
}
// 从数据库获取所有菜单
func (s *sSysAuthRule) getMenuListFromDb(ctx context.Context) (value interface{}, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var v []*model.SysAuthRuleInfoRes
//从数据库获取
err = dao.SysAuthRule.Ctx(ctx).
Fields(model.SysAuthRuleInfoRes{}).Order("weigh desc,id asc").Scan(&v)
liberr.ErrIsNil(ctx, err, "获取菜单数据失败")
value = v
})
return
}
// GetIsButtonList 获取所有按钮isMenu=2 菜单列表
func (s *sSysAuthRule) GetIsButtonList(ctx context.Context) ([]*model.SysAuthRuleInfoRes, error) {
list, err := s.GetMenuList(ctx)
if err != nil {
return nil, err
}
var gList = make([]*model.SysAuthRuleInfoRes, 0, len(list))
for _, v := range list {
if v.MenuType == 2 {
gList = append(gList, v)
}
}
return gList, nil
}
// Add 添加菜单
func (s *sSysAuthRule) Add(ctx context.Context, req *system.RuleAddReq) (err error) {
if s.menuNameExists(ctx, req.Name, 0) {
err = gerror.New("接口规则已经存在")
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
//菜单数据
data := do.SysAuthRule{
Pid: req.Pid,
Name: req.Name,
Title: req.Title,
Icon: req.Icon,
Condition: req.Condition,
Remark: req.Remark,
MenuType: req.MenuType,
Weigh: req.Weigh,
IsHide: req.IsHide,
Path: req.Path,
Component: req.Component,
IsLink: req.IsLink,
IsIframe: req.IsIframe,
IsCached: req.IsCached,
Redirect: req.Redirect,
IsAffix: req.IsAffix,
LinkUrl: req.LinkUrl,
}
ruleId, e := dao.SysAuthRule.Ctx(ctx).TX(tx).InsertAndGetId(data)
liberr.ErrIsNil(ctx, e, "添加菜单失败")
e = s.BindRoleRule(ctx, ruleId, req.Roles)
liberr.ErrIsNil(ctx, e, "添加菜单失败")
})
return err
})
if err == nil {
// 删除相关缓存
commonService.Cache().Remove(ctx, consts.CacheSysAuthMenu)
}
return
}
// 检查菜单规则是否存在
func (s *sSysAuthRule) menuNameExists(ctx context.Context, name string, id uint) bool {
m := dao.SysAuthRule.Ctx(ctx).Where("name=?", name)
if id != 0 {
m = m.Where("id!=?", id)
}
c, err := m.Fields(dao.SysAuthRule.Columns().Id).Limit(1).One()
if err != nil {
g.Log().Error(ctx, err)
return false
}
return !c.IsEmpty()
}
// BindRoleRule 绑定角色权限
func (s *sSysAuthRule) BindRoleRule(ctx context.Context, ruleId interface{}, roleIds []uint) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
for _, roleId := range roleIds {
_, err = enforcer.AddPolicy(fmt.Sprintf("%d", roleId), fmt.Sprintf("%d", ruleId), "All")
liberr.ErrIsNil(ctx, err)
}
})
return
}
func (s *sSysAuthRule) Get(ctx context.Context, id uint) (rule *entity.SysAuthRule, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysAuthRule.Ctx(ctx).WherePri(id).Scan(&rule)
liberr.ErrIsNil(ctx, err, "获取菜单失败")
})
return
}
func (s *sSysAuthRule) GetMenuRoles(ctx context.Context, id uint) (roleIds []uint, err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
policies := enforcer.GetFilteredNamedPolicy("p", 1, gconv.String(id))
for _, policy := range policies {
roleIds = append(roleIds, gconv.Uint(policy[0]))
}
})
return
}
func (s *sSysAuthRule) Update(ctx context.Context, req *system.RuleUpdateReq) (err error) {
if s.menuNameExists(ctx, req.Name, req.Id) {
err = gerror.New("接口规则已经存在")
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
//菜单数据
data := do.SysAuthRule{
Pid: req.Pid,
Name: req.Name,
Title: req.Title,
Icon: req.Icon,
Condition: req.Condition,
Remark: req.Remark,
MenuType: req.MenuType,
Weigh: req.Weigh,
IsHide: req.IsHide,
Path: req.Path,
Component: req.Component,
IsLink: req.IsLink,
IsIframe: req.IsIframe,
IsCached: req.IsCached,
Redirect: req.Redirect,
IsAffix: req.IsAffix,
LinkUrl: req.LinkUrl,
}
_, e := dao.SysAuthRule.Ctx(ctx).TX(tx).WherePri(req.Id).Update(data)
liberr.ErrIsNil(ctx, e, "添加菜单失败")
e = s.UpdateRoleRule(ctx, req.Id, req.Roles)
liberr.ErrIsNil(ctx, e, "添加菜单失败")
})
return err
})
if err == nil {
// 删除相关缓存
commonService.Cache().Remove(ctx, consts.CacheSysAuthMenu)
}
return
}
func (s *sSysAuthRule) UpdateRoleRule(ctx context.Context, ruleId uint, roleIds []uint) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
//删除旧权限
_, e = enforcer.RemoveFilteredPolicy(1, gconv.String(ruleId))
liberr.ErrIsNil(ctx, e)
// 添加新权限
roleIdsStrArr := gconv.Strings(roleIds)
for _, v := range roleIdsStrArr {
_, e = enforcer.AddPolicy(v, gconv.String(ruleId), "All")
liberr.ErrIsNil(ctx, e)
}
})
return
}
func (s *sSysAuthRule) GetMenuListTree(pid uint, list []*model.SysAuthRuleInfoRes) []*model.SysAuthRuleTreeRes {
tree := make([]*model.SysAuthRuleTreeRes, 0, len(list))
for _, menu := range list {
if menu.Pid == pid {
t := &model.SysAuthRuleTreeRes{
SysAuthRuleInfoRes: menu,
}
child := s.GetMenuListTree(menu.Id, list)
if child != nil {
t.Children = child
}
tree = append(tree, t)
}
}
return tree
}
// DeleteMenuByIds 删除菜单
func (s *sSysAuthRule) DeleteMenuByIds(ctx context.Context, ids []int) (err error) {
var list []*model.SysAuthRuleInfoRes
list, err = s.GetMenuList(ctx)
if err != nil {
return
}
childrenIds := make([]int, 0, len(list))
for _, id := range ids {
rules := s.FindSonByParentId(list, gconv.Uint(id))
for _, child := range rules {
childrenIds = append(childrenIds, gconv.Int(child.Id))
}
}
ids = append(ids, childrenIds...)
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
return g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysAuthRule.Ctx(ctx).Where("id in (?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除失败")
//删除权限
enforcer, err := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, err)
for _, v := range ids {
_, err = enforcer.RemoveFilteredPolicy(1, gconv.String(v))
liberr.ErrIsNil(ctx, err)
}
// 删除相关缓存
commonService.Cache().Remove(ctx, consts.CacheSysAuthMenu)
})
})
return
}
func (s *sSysAuthRule) FindSonByParentId(list []*model.SysAuthRuleInfoRes, pid uint) []*model.SysAuthRuleInfoRes {
children := make([]*model.SysAuthRuleInfoRes, 0, len(list))
for _, v := range list {
if v.Pid == pid {
children = append(children, v)
fChildren := s.FindSonByParentId(list, v.Id)
children = append(children, fChildren...)
}
}
return children
}

View File

@@ -0,0 +1,198 @@
/*
* @desc:部门管理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/26 15:14
*/
package sysDept
import (
"context"
"database/sql"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysDept(New())
}
func New() *sSysDept {
return &sSysDept{}
}
type sSysDept struct {
}
func (s *sSysDept) GetList(ctx context.Context, req *system.DeptSearchReq) (list []*entity.SysDept, err error) {
list, err = s.GetFromCache(ctx)
if err != nil {
return
}
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
rList := make([]*entity.SysDept, 0, len(list))
for _, v := range list {
if gconv.Uint64(getUserInfo.TenantId) != v.TenantId {
continue
}
if req.DeptName != "" || req.Status != "" {
if req.DeptName != "" && !gstr.ContainsI(v.DeptName, req.DeptName) {
continue
}
if req.Status != "" && v.Status != gconv.Uint(req.Status) {
continue
}
}
rList = append(rList, v)
}
list = rList
return
}
func (s *sSysDept) GetFromCache(ctx context.Context) (list []*entity.SysDept, err error) {
err = g.Try(ctx, func(ctx context.Context) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysDept, func(ctx context.Context) (value interface{}, err error) {
err = dao.SysDept.Ctx(ctx).Scan(&list)
liberr.ErrIsNil(ctx, err, "获取部门列表失败")
value = list
return
}, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
liberr.ErrIsNil(ctx, err)
}
})
return
}
// Add 添加部门
func (s *sSysDept) Add(ctx context.Context, req *system.DeptAddReq) (id int64, err error) {
err = g.Try(ctx, func(ctx context.Context) {
if g.IsEmpty(req.TenantId) {
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
req.TenantId = gconv.Uint64(getUserInfo.TenantId)
}
var insertId sql.Result
insertId, err = dao.SysDept.Ctx(ctx).Insert(do.SysDept{
ParentId: req.ParentID,
DeptName: req.DeptName,
OrderNum: req.OrderNum,
Leader: req.Leader,
Phone: req.Phone,
Email: req.Email,
Status: req.Status,
CreatedBy: service.Context().GetUserId(ctx),
TenantId: req.TenantId,
})
liberr.ErrIsNil(ctx, err, "添加部门失败")
id, err = insertId.LastInsertId()
liberr.ErrIsNil(ctx, err, "获取插入id失败")
// 删除缓存
commonService.Cache().Remove(ctx, consts.CacheSysDept)
})
return
}
// Edit 部门修改
func (s *sSysDept) Edit(ctx context.Context, req *system.DeptEditReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysDept.Ctx(ctx).WherePri(req.DeptId).Update(do.SysDept{
ParentId: req.ParentID,
DeptName: req.DeptName,
OrderNum: req.OrderNum,
Leader: req.Leader,
Phone: req.Phone,
Email: req.Email,
Status: req.Status,
UpdatedBy: service.Context().GetUserId(ctx),
})
liberr.ErrIsNil(ctx, err, "修改部门失败")
// 删除缓存
commonService.Cache().Remove(ctx, consts.CacheSysDept)
})
return
}
func (s *sSysDept) Delete(ctx context.Context, id uint64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
var list []*entity.SysDept
err = dao.SysDept.Ctx(ctx).Scan(&list)
liberr.ErrIsNil(ctx, err, "不存在部门信息")
children := s.FindSonByParentId(list, id)
ids := make([]uint64, 0, len(list))
for _, v := range children {
ids = append(ids, v.DeptId)
}
ids = append(ids, id)
_, err = dao.SysDept.Ctx(ctx).Where(dao.SysDept.Columns().DeptId+" in (?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除部门失败")
// 删除缓存
commonService.Cache().Remove(ctx, consts.CacheSysDept)
})
return
}
func (s *sSysDept) FindSonByParentId(deptList []*entity.SysDept, deptId uint64) []*entity.SysDept {
children := make([]*entity.SysDept, 0, len(deptList))
for _, v := range deptList {
if v.ParentId == deptId {
children = append(children, v)
fChildren := s.FindSonByParentId(deptList, v.DeptId)
children = append(children, fChildren...)
}
}
return children
}
// GetListTree 部门树形菜单
func (s *sSysDept) GetListTree(pid uint64, list []*entity.SysDept) (deptTree []*model.SysDeptTreeRes) {
deptTree = make([]*model.SysDeptTreeRes, 0, len(list))
for _, v := range list {
if v.ParentId == pid {
t := &model.SysDeptTreeRes{
SysDept: v,
}
child := s.GetListTree(v.DeptId, list)
if len(child) > 0 {
t.Children = child
}
deptTree = append(deptTree, t)
}
}
return
}
// GetByDeptId 通过部门id获取部门信息
func (s *sSysDept) GetByDeptId(ctx context.Context, deptId uint64) (dept *entity.SysDept, err error) {
var depts []*entity.SysDept
depts, err = s.GetFromCache(ctx)
if err != nil {
return
}
for _, v := range depts {
if v.DeptId == deptId {
dept = v
break
}
}
return
}

View File

@@ -0,0 +1,103 @@
/*
* @desc:登录日志
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/26 15:20
*/
package sysLoginLog
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysLoginLog(New())
}
func New() *sSysLoginLog {
return &sSysLoginLog{
Pool: grpool.New(100),
}
}
type sSysLoginLog struct {
Pool *grpool.Pool
}
func (s *sSysLoginLog) Invoke(ctx context.Context, data *model.LoginLogParams) {
s.Pool.Add(
ctx,
func(ctx context.Context) {
//写入日志数据
service.SysUser().LoginLog(ctx, data)
},
)
}
func (s *sSysLoginLog) List(ctx context.Context, req *system.LoginLogSearchReq) (res *system.LoginLogSearchRes, err error) {
res = new(system.LoginLogSearchRes)
if req.PageNum == 0 {
req.PageNum = 1
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
m := dao.SysLoginLog.Ctx(ctx)
order := "info_id DESC"
if req.LoginName != "" {
m = m.Where("login_name like ?", "%"+req.LoginName+"%")
}
if req.Status != "" {
m = m.Where("status", gconv.Int(req.Status))
}
if req.Ipaddr != "" {
m = m.Where("ipaddr like ?", "%"+req.Ipaddr+"%")
}
if req.LoginLocation != "" {
m = m.Where("login_location like ?", "%"+req.LoginLocation+"%")
}
if len(req.DateRange) != 0 {
m = m.Where("login_time >=? AND login_time <=?", req.DateRange[0], req.DateRange[1])
}
if req.SortName != "" {
if req.SortOrder != "" {
order = req.SortName + " " + req.SortOrder
} else {
order = req.SortName + " DESC"
}
}
err = g.Try(ctx, func(ctx context.Context) {
res.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取日志失败")
err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取日志数据失败")
})
return
}
func (s *sSysLoginLog) DeleteLoginLogByIds(ctx context.Context, ids []int) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysLoginLog.Ctx(ctx).Delete("info_id in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
func (s *sSysLoginLog) ClearLoginLog(ctx context.Context) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = g.DB().Ctx(ctx).Exec(ctx, "truncate "+dao.SysLoginLog.Table())
liberr.ErrIsNil(ctx, err, "清除失败")
})
return
}

View File

@@ -0,0 +1,195 @@
/*
* @desc:后台操作日志业务处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/21 16:14
*/
package sysOperLog
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
)
type sOperateLog struct {
Pool *grpool.Pool
}
func init() {
service.RegisterOperateLog(New())
}
func New() *sOperateLog {
return &sOperateLog{
Pool: grpool.New(100),
}
}
// OperationLog 操作日志写入
func (s *sOperateLog) OperationLog(r *ghttp.Request) {
userInfo := service.Context().GetLoginUser(r.GetCtx())
if userInfo == nil {
return
}
url := r.Request.URL //请求地址
//获取菜单
//获取地址对应的菜单id
menuList, err := service.SysAuthRule().GetMenuList(r.GetCtx())
if err != nil {
g.Log().Error(r.GetCtx(), err)
return
}
var menu *model.SysAuthRuleInfoRes
path := gstr.TrimLeft(url.Path, "/")
for _, m := range menuList {
if gstr.Equal(m.Name, path) {
menu = m
break
}
}
data := &model.SysOperLogAdd{
User: userInfo,
Menu: menu,
Url: url,
Params: r.GetMap(),
Method: r.Method,
ClientIp: libUtils.GetClientIp(r.GetCtx()),
OperatorType: 1,
}
s.Invoke(gctx.New(), data)
}
func (s *sOperateLog) Invoke(ctx context.Context, data *model.SysOperLogAdd) {
s.Pool.Add(ctx, func(ctx context.Context) {
//写入日志数据
s.operationLogAdd(ctx, data)
})
}
// OperationLogAdd 添加操作日志
func (s *sOperateLog) operationLogAdd(ctx context.Context, data *model.SysOperLogAdd) {
menuTitle := ""
if data.Menu != nil {
menuTitle = data.Menu.Title
}
dept, err := service.SysDept().GetByDeptId(ctx, data.User.DeptId)
if err != nil {
g.Log().Error(ctx, err)
return
}
if dept == nil {
dept = &entity.SysDept{}
}
insertData := &do.SysOperLog{
Title: menuTitle,
Method: data.Url.Path,
RequestMethod: data.Method,
OperatorType: data.OperatorType,
OperName: data.User.UserName,
DeptName: dept.DeptName,
OperIp: data.ClientIp,
OperLocation: libUtils.GetCityByIp(data.ClientIp),
OperTime: gtime.Now(),
OperParam: data.Params,
}
rawQuery := data.Url.RawQuery
if rawQuery != "" {
rawQuery = "?" + rawQuery
}
insertData.OperUrl = data.Url.Path + rawQuery
_, err = dao.SysOperLog.Ctx(ctx).Insert(insertData)
if err != nil {
g.Log().Error(ctx, err)
}
}
func (s *sOperateLog) List(ctx context.Context, req *system.SysOperLogSearchReq) (listRes *system.SysOperLogSearchRes, err error) {
listRes = new(system.SysOperLogSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysOperLog.Ctx(ctx)
if req.Title != "" {
m = m.Where(dao.SysOperLog.Columns().Title+" = ?", req.Title)
}
if req.RequestMethod != "" {
m = m.Where(dao.SysOperLog.Columns().RequestMethod+" = ?", req.RequestMethod)
}
if req.OperName != "" {
m = m.Where(dao.SysOperLog.Columns().OperName+" like ?", "%"+req.OperName+"%")
}
if len(req.DateRange) != 0 {
m = m.Where("oper_time >=? AND oper_time <=?", req.DateRange[0], req.DateRange[1])
}
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "oper_id DESC"
if req.OrderBy != "" {
order = req.OrderBy
}
var res []*model.SysOperLogInfoRes
err = m.Fields(system.SysOperLogSearchRes{}).Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = make([]*model.SysOperLogListRes, len(res))
for k, v := range res {
listRes.List[k] = &model.SysOperLogListRes{
OperId: v.OperId,
Title: v.Title,
RequestMethod: v.RequestMethod,
OperName: v.OperName,
DeptName: v.DeptName,
LinkedDeptName: v.LinkedDeptName,
OperUrl: v.OperUrl,
OperIp: v.OperIp,
OperLocation: v.OperLocation,
OperParam: v.OperParam,
OperTime: v.OperTime,
}
}
})
return
}
func (s *sOperateLog) GetByOperId(ctx context.Context, operId uint64) (res *model.SysOperLogInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysOperLog.Ctx(ctx).WithAll().Where(dao.SysOperLog.Columns().OperId, operId).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
})
return
}
func (s *sOperateLog) DeleteByIds(ctx context.Context, ids []uint64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysOperLog.Ctx(ctx).Delete("oper_id in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
func (s *sOperateLog) ClearLog(ctx context.Context) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = g.DB().Ctx(ctx).Exec(ctx, "truncate "+dao.SysOperLog.Table())
liberr.ErrIsNil(ctx, err, "清除失败")
})
return
}

View File

@@ -0,0 +1,111 @@
/*
* @desc:岗位管理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/26 15:28
*/
package sysPost
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysPost(New())
}
func New() *sSysPost {
return &sSysPost{}
}
type sSysPost struct {
}
// List 岗位列表
func (s *sSysPost) List(ctx context.Context, req *system.PostSearchReq) (res *system.PostSearchRes, err error) {
res = new(system.PostSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysPost.Ctx(ctx)
if req != nil {
if req.PostCode != "" {
m = m.Where("post_code like ?", "%"+req.PostCode+"%")
}
if req.PostName != "" {
m = m.Where("post_name like ?", "%"+req.PostName+"%")
}
if req.Status != "" {
m = m.Where("status", gconv.Uint(req.Status))
}
}
res.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取岗位失败")
if req.PageNum == 0 {
req.PageNum = 1
}
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
res.CurrentPage = req.PageNum
err = m.Page(req.PageNum, req.PageSize).Order("post_sort asc,post_id asc").Scan(&res.PostList)
liberr.ErrIsNil(ctx, err, "获取岗位失败")
})
return
}
func (s *sSysPost) Add(ctx context.Context, req *system.PostAddReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysPost.Ctx(ctx).Insert(do.SysPost{
PostCode: req.PostCode,
PostName: req.PostName,
PostSort: req.PostSort,
Status: req.Status,
Remark: req.Remark,
CreatedBy: service.Context().GetUserId(ctx),
})
liberr.ErrIsNil(ctx, err, "添加岗位失败")
})
return
}
func (s *sSysPost) Edit(ctx context.Context, req *system.PostEditReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysPost.Ctx(ctx).WherePri(req.PostId).Update(do.SysPost{
PostCode: req.PostCode,
PostName: req.PostName,
PostSort: req.PostSort,
Status: req.Status,
Remark: req.Remark,
UpdatedBy: service.Context().GetUserId(ctx),
})
liberr.ErrIsNil(ctx, err, "修改岗位失败")
})
return
}
func (s *sSysPost) Delete(ctx context.Context, ids []int) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysPost.Ctx(ctx).Where(dao.SysPost.Columns().PostId+" in(?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
// GetUsedPost 获取正常状态的岗位
func (s *sSysPost) GetUsedPost(ctx context.Context) (list []*entity.SysPost, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysPost.Ctx(ctx).Where(dao.SysPost.Columns().Status, 1).
Order(dao.SysPost.Columns().PostSort + " ASC, " + dao.SysPost.Columns().PostId + " ASC ").Scan(&list)
liberr.ErrIsNil(ctx, err, "获取岗位数据失败")
})
return
}

View File

@@ -0,0 +1,225 @@
/*
* @desc:角色管理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/26 15:54
*/
package sysRole
import (
"context"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysRole(New())
}
func New() *sSysRole {
return &sSysRole{}
}
type sSysRole struct {
}
func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *system.RoleListReq) (res *system.RoleListRes, err error) {
res = new(system.RoleListRes)
g.Try(ctx, func(ctx context.Context) {
model := dao.SysRole.Ctx(ctx)
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
model = model.Where("tenant_id", gconv.Uint64(getUserInfo.TenantId))
if req.RoleName != "" {
model = model.Where("name like ?", "%"+req.RoleName+"%")
}
if req.Status != "" {
model = model.Where("status", gconv.Int(req.Status))
}
res.Total, err = model.Count()
liberr.ErrIsNil(ctx, err, "获取角色数据失败")
if req.PageNum == 0 {
req.PageNum = 1
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
err = model.Page(res.CurrentPage, req.PageSize).Order("id asc").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
// GetRoleList 获取角色列表
func (s *sSysRole) GetRoleList(ctx context.Context) (list []*entity.SysRole, err error) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysRole, s.getRoleListFromDb, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
}
return
}
// GetRoleListInfo 获取角色列表信息
func (s *sSysRole) GetRoleListInfo(ctx context.Context) (list []*entity.SysRole, err error) {
cache := commonService.Cache()
//从缓存获取
iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysRole, s.getRoleListFromDb, 0, consts.CacheSysAuthTag)
if !iList.IsEmpty() {
err = gconv.Struct(iList, &list)
}
var user *beans.User
user, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
rList := make([]*entity.SysRole, 0, len(list))
for _, v := range list {
if !g.IsEmpty(user.TenantId) && gconv.Uint64(user.TenantId) != v.TenantId {
continue
}
rList = append(rList, v)
}
list = rList
return
}
// 从数据库获取所有角色
func (s *sSysRole) getRoleListFromDb(ctx context.Context) (value interface{}, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var v []*entity.SysRole
//从数据库获取
err = dao.SysRole.Ctx(ctx).
Order(dao.SysRole.Columns().ListOrder + " asc," + dao.SysRole.Columns().Id + " asc").
Scan(&v)
liberr.ErrIsNil(ctx, err, "获取角色数据失败")
value = v
})
return
}
// AddRoleRule 添加角色权限
func (s *sSysRole) AddRoleRule(ctx context.Context, ruleIds []uint, roleId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
ruleIdsStr := gconv.Strings(ruleIds)
for _, v := range ruleIdsStr {
_, err = enforcer.AddPolicy(gconv.String(roleId), v, "All")
liberr.ErrIsNil(ctx, err)
}
})
return
}
// DelRoleRule 删除角色权限
func (s *sSysRole) DelRoleRule(ctx context.Context, roleId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
_, err = enforcer.RemoveFilteredPolicy(0, gconv.String(roleId))
liberr.ErrIsNil(ctx, e)
})
return
}
func (s *sSysRole) AddRole(ctx context.Context, req *system.RoleAddReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
req.TenantId = gconv.Uint64(gconv.Uint64(getUserInfo.TenantId))
roleId, e := dao.SysRole.Ctx(ctx).TX(tx).InsertAndGetId(req)
liberr.ErrIsNil(ctx, e, "添加角色失败")
//添加角色权限
e = s.AddRoleRule(ctx, req.MenuIds, roleId)
liberr.ErrIsNil(ctx, e)
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
})
return err
})
return
}
func (s *sSysRole) Get(ctx context.Context, id uint) (res *entity.SysRole, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysRole.Ctx(ctx).WherePri(id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取角色信息失败")
})
return
}
// GetFilteredNamedPolicy 获取角色关联的菜单规则
func (s *sSysRole) GetFilteredNamedPolicy(ctx context.Context, id uint) (gpSlice []int, err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
gp := enforcer.GetFilteredNamedPolicy("p", 0, gconv.String(id))
gpSlice = make([]int, len(gp))
for k, v := range gp {
gpSlice[k] = gconv.Int(v[1])
}
})
return
}
// EditRole 修改角色
func (s *sSysRole) EditRole(ctx context.Context, req *system.RoleEditReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
_, e := dao.SysRole.Ctx(ctx).TX(tx).WherePri(req.Id).Data(&do.SysRole{
Status: req.Status,
ListOrder: req.ListOrder,
Name: req.Name,
Remark: req.Remark,
}).Update()
liberr.ErrIsNil(ctx, e, "修改角色失败")
//删除角色权限
e = s.DelRoleRule(ctx, req.Id)
liberr.ErrIsNil(ctx, e)
//添加角色权限
e = s.AddRoleRule(ctx, req.MenuIds, req.Id)
liberr.ErrIsNil(ctx, e)
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
})
return err
})
return
}
// DeleteByIds 删除角色
func (s *sSysRole) DeleteByIds(ctx context.Context, ids []int64) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysRole.Ctx(ctx).TX(tx).Where(dao.SysRole.Columns().Id+" in(?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除角色失败")
//删除角色权限
for _, v := range ids {
err = s.DelRoleRule(ctx, v)
liberr.ErrIsNil(ctx, err)
}
//清除缓存
commonService.Cache().Remove(ctx, consts.CacheSysRole)
})
return err
})
return
}

View File

@@ -0,0 +1,784 @@
/*
* @desc:用户处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 15:08
*/
package sysUser
import (
"context"
"fmt"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/database/gdb"
"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/mssola/user_agent"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysUser(New())
}
type sSysUser struct {
casBinUserPrefix string //CasBin 用户id前缀
}
func New() *sSysUser {
return &sSysUser{
casBinUserPrefix: "u_",
}
}
func (s *sSysUser) GetCasBinUserPrefix() string {
return s.casBinUserPrefix
}
func (s *sSysUser) NotCheckAuthAdminIds(ctx context.Context) *gset.Set {
ids := g.Cfg().MustGet(ctx, "system.notCheckAuthAdminIds")
if !g.IsNil(ids) {
return gset.NewFrom(ids)
}
return gset.New()
}
func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, req *system.UserLoginReq) (user *model.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user, err = s.GetUserByUsername(ctx, req.Username)
liberr.ErrIsNil(ctx, err)
liberr.ValueIsNil(user, "账号密码错误")
//验证密码
if libUtils.EncryptPassword(req.Password, user.UserSalt) != user.UserPassword {
liberr.ErrIsNil(ctx, gerror.New("账号密码错误"))
}
//账号状态
if user.UserStatus == 0 {
liberr.ErrIsNil(ctx, gerror.New("账号已被冻结"))
}
})
return
}
// GetUserByUsername 通过用户名获取用户信息
func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (user *model.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user = &model.LoginUserRes{}
err = dao.SysUser.Ctx(ctx).Fields(user).Where(dao.SysUser.Columns().UserName, userName).Scan(user)
liberr.ErrIsNil(ctx, err, "账号密码错误")
})
return
}
// GetUserById 通过用户名获取用户信息
func (s *sSysUser) GetUserById(ctx context.Context, id uint64) (user *model.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user = &model.LoginUserRes{}
err = dao.SysUser.Ctx(ctx).Fields(user).WherePri(id).Scan(user)
liberr.ErrIsNil(ctx, err, "获取用户信息失败")
})
return
}
// LoginLog 记录登录日志
func (s *sSysUser) LoginLog(ctx context.Context, params *model.LoginLogParams) {
ua := user_agent.New(params.UserAgent)
browser, _ := ua.Browser()
loginData := &do.SysLoginLog{
LoginName: params.Username,
Ipaddr: params.Ip,
LoginLocation: libUtils.GetCityByIp(params.Ip),
Browser: browser,
Os: ua.OS(),
Status: params.Status,
Msg: params.Msg,
LoginTime: gtime.Now(),
Module: params.Module,
}
_, err := dao.SysLoginLog.Ctx(ctx).Insert(loginData)
if err != nil {
g.Log().Error(ctx, err)
}
}
func (s *sSysUser) UpdateLoginInfo(ctx context.Context, id uint64, ip string) (err error) {
g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).WherePri(id).Unscoped().Update(g.Map{
dao.SysUser.Columns().LastLoginIp: ip,
dao.SysUser.Columns().LastLoginTime: gtime.Now(),
})
liberr.ErrIsNil(ctx, err, "更新用户登录信息失败")
})
return
}
// GetAdminRules 获取用户菜单数据
func (s *sSysUser) GetAdminRules(ctx context.Context, userId uint64) (menuList []*model.UserMenus, permissions []string, err error) {
err = g.Try(ctx, func(ctx context.Context) {
//是否超管
isSuperAdmin := false
//获取无需验证权限的用户id
s.NotCheckAuthAdminIds(ctx).Iterator(func(v interface{}) bool {
if gconv.Uint64(v) == userId {
isSuperAdmin = true
return false
}
return true
})
//获取用户菜单数据
allRoles, err := service.SysRole().GetRoleList(ctx)
liberr.ErrIsNil(ctx, err)
roles, err := s.GetAdminRole(ctx, userId, allRoles)
liberr.ErrIsNil(ctx, err)
name := make([]string, len(roles))
roleIds := make([]uint, len(roles))
for k, v := range roles {
name[k] = v.Name
roleIds[k] = v.Id
}
//获取菜单信息
if isSuperAdmin {
//超管获取所有菜单
permissions = []string{"*/*/*"}
menuList, err = s.GetAllMenus(ctx)
liberr.ErrIsNil(ctx, err)
} else {
menuList, err = s.GetAdminMenusByRoleIds(ctx, roleIds)
liberr.ErrIsNil(ctx, err)
permissions, err = s.GetPermissions(ctx, roleIds)
liberr.ErrIsNil(ctx, err)
}
})
return
}
// GetAdminRole 获取用户角色
func (s *sSysUser) GetAdminRole(ctx context.Context, userId uint64, allRoleList []*entity.SysRole) (roles []*entity.SysRole, err error) {
var roleIds []uint
roleIds, err = s.GetAdminRoleIds(ctx, userId)
if err != nil {
return
}
roles = make([]*entity.SysRole, 0, len(allRoleList))
for _, v := range allRoleList {
for _, id := range roleIds {
if id == v.Id {
roles = append(roles, v)
}
}
if len(roles) == len(roleIds) {
break
}
}
return
}
// GetAdminRoleIds 获取用户角色ids
func (s *sSysUser) GetAdminRoleIds(ctx context.Context, userId uint64) (roleIds []uint, err error) {
enforcer, e := commonService.CasbinEnforcer(ctx)
if e != nil {
err = e
return
}
//查询关联角色规则
groupPolicy := enforcer.GetFilteredGroupingPolicy(0, fmt.Sprintf("%s%d", s.casBinUserPrefix, userId))
if len(groupPolicy) > 0 {
roleIds = make([]uint, len(groupPolicy))
//得到角色id的切片
for k, v := range groupPolicy {
roleIds[k] = gconv.Uint(v[1])
}
}
return
}
func (s *sSysUser) GetAllMenus(ctx context.Context) (menus []*model.UserMenus, err error) {
//获取所有开启的菜单
var allMenus []*model.SysAuthRuleInfoRes
allMenus, err = service.SysAuthRule().GetIsMenuList(ctx)
if err != nil {
return
}
menus = make([]*model.UserMenus, len(allMenus))
for k, v := range allMenus {
var menu *model.UserMenu
menu = s.setMenuData(menu, v)
menus[k] = &model.UserMenus{UserMenu: menu}
}
menus = s.GetMenusTree(menus, 0)
return
}
func (s *sSysUser) GetAdminMenusByRoleIds(ctx context.Context, roleIds []uint) (menus []*model.UserMenus, err error) {
//获取角色对应的菜单id
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
menuIds := map[int64]int64{}
for _, roleId := range roleIds {
//查询当前权限
gp := enforcer.GetFilteredPolicy(0, gconv.String(roleId))
for _, p := range gp {
mid := gconv.Int64(p[1])
menuIds[mid] = mid
}
}
//获取所有开启的菜单
allMenus, err := service.SysAuthRule().GetIsMenuList(ctx)
liberr.ErrIsNil(ctx, err)
menus = make([]*model.UserMenus, 0, len(allMenus))
for _, v := range allMenus {
if _, ok := menuIds[gconv.Int64(v.Id)]; gstr.Equal(v.Condition, "nocheck") || ok {
var roleMenu *model.UserMenu
roleMenu = s.setMenuData(roleMenu, v)
menus = append(menus, &model.UserMenus{UserMenu: roleMenu})
}
}
menus = s.GetMenusTree(menus, 0)
})
return
}
func (s *sSysUser) GetMenusTree(menus []*model.UserMenus, pid uint) []*model.UserMenus {
returnList := make([]*model.UserMenus, 0, len(menus))
for _, menu := range menus {
if menu.Pid == pid {
menu.Children = s.GetMenusTree(menus, menu.Id)
returnList = append(returnList, menu)
}
}
return returnList
}
func (s *sSysUser) setMenuData(menu *model.UserMenu, entity *model.SysAuthRuleInfoRes) *model.UserMenu {
menu = &model.UserMenu{
Id: entity.Id,
Pid: entity.Pid,
Name: gstr.CaseCamelLower(gstr.Replace(entity.Name, "/", "_")),
Component: entity.Component,
Path: entity.Path,
MenuMeta: &model.MenuMeta{
Icon: entity.Icon,
Title: entity.Title,
IsLink: "",
IsHide: entity.IsHide == 1,
IsKeepAlive: entity.IsCached == 1,
IsAffix: entity.IsAffix == 1,
IsIframe: entity.IsIframe == 1,
},
}
if menu.MenuMeta.IsIframe || entity.IsLink == 1 {
menu.MenuMeta.IsLink = entity.LinkUrl
}
return menu
}
func (s *sSysUser) GetPermissions(ctx context.Context, roleIds []uint) (userButtons []string, err error) {
err = g.Try(ctx, func(ctx context.Context) {
//获取角色对应的菜单id
enforcer, err := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, err)
menuIds := map[int64]int64{}
for _, roleId := range roleIds {
//查询当前权限
gp := enforcer.GetFilteredPolicy(0, gconv.String(roleId))
for _, p := range gp {
mid := gconv.Int64(p[1])
menuIds[mid] = mid
}
}
//获取所有开启的按钮
allButtons, err := service.SysAuthRule().GetIsButtonList(ctx)
liberr.ErrIsNil(ctx, err)
userButtons = make([]string, 0, len(allButtons))
for _, button := range allButtons {
if _, ok := menuIds[gconv.Int64(button.Id)]; gstr.Equal(button.Condition, "nocheck") || ok {
userButtons = append(userButtons, button.Name)
}
}
})
return
}
// List 用户列表
func (s *sSysUser) List(ctx context.Context, req *system.UserSearchReq) (total interface{}, userList []*entity.SysUser, err error) {
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysUser.Ctx(ctx)
if req.KeyWords != "" {
keyWords := "%" + req.KeyWords + "%"
m = m.Where("user_name like ? or user_nickname like ?", keyWords, keyWords)
}
if req.DeptId != "" {
deptIds, e := s.getSearchDeptIds(ctx, gconv.Uint64(req.DeptId))
liberr.ErrIsNil(ctx, e)
m = m.Where("dept_id in (?)", deptIds)
}
if req.Status != "" {
m = m.Where("user_status", gconv.Int(req.Status))
}
if req.Mobile != "" {
m = m.Where("mobile like ?", "%"+req.Mobile+"%")
}
if len(req.DateRange) > 0 {
m = m.Where("created_at >=? AND created_at <=?", req.DateRange[0], req.DateRange[1])
}
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
if req.PageNum == 0 {
req.PageNum = 1
}
total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取用户数据失败")
err = m.FieldsEx(dao.SysUser.Columns().UserPassword, dao.SysUser.Columns().UserSalt).
Page(req.PageNum, req.PageSize).Order("id asc").Scan(&userList)
liberr.ErrIsNil(ctx, err, "获取用户列表失败")
})
return
}
// GetUsersRoleDept 获取多个用户角色 部门信息
func (s *sSysUser) GetUsersRoleDept(ctx context.Context, userList []*entity.SysUser) (users []*model.SysUserRoleDeptRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
allRoles, e := service.SysRole().GetRoleList(ctx)
liberr.ErrIsNil(ctx, e)
depts, e := service.SysDept().GetFromCache(ctx)
liberr.ErrIsNil(ctx, e)
users = make([]*model.SysUserRoleDeptRes, len(userList))
for k, u := range userList {
var dept *entity.SysDept
users[k] = &model.SysUserRoleDeptRes{
SysUser: u,
}
for _, d := range depts {
if u.DeptId == uint64(d.DeptId) {
dept = d
}
}
users[k].Dept = dept
roles, e := s.GetAdminRole(ctx, u.Id, allRoles)
liberr.ErrIsNil(ctx, e)
for _, r := range roles {
users[k].RoleInfo = append(users[k].RoleInfo, &model.SysUserRoleInfoRes{RoleId: r.Id, Name: r.Name})
}
}
})
return
}
// GetList 用户列表(根据当前租户)
func (s *sSysUser) GetList(ctx context.Context, req *system.GetUserSearchReq) (total interface{}, userList []*entity.SysUser, err error) {
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysUser.Ctx(ctx)
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
var tenantDetails *entity.Tenant
tenantDetails, err = service.Tenant().GetTenantDetails(ctx, gconv.Uint64(getUserInfo.TenantId))
liberr.ErrIsNil(ctx, err)
if tenantDetails.TenantType == consts.TenantTypeAgent {
var adminByIdList []entity.Tenant
adminByIdList, err = service.Tenant().GetTenantAdminById(ctx, tenantDetails.Id)
liberr.ErrIsNil(ctx, err)
idList := make([]uint64, 0)
for _, user := range adminByIdList {
idList = append(idList, gconv.Uint64(user.AdminBy))
}
m = m.Where("id in (?)", idList)
} else {
m = m.Where("tenant_id", tenantDetails.Id)
}
if req.KeyWords != "" {
keyWords := "%" + req.KeyWords + "%"
m = m.Where("user_name like ? or user_nickname like ?", keyWords, keyWords)
}
if req.DeptId != "" {
deptIds, e := s.getSearchDeptIds(ctx, gconv.Uint64(req.DeptId))
liberr.ErrIsNil(ctx, e)
m = m.Where("dept_id in (?)", deptIds)
}
if req.Status != "" {
m = m.Where("user_status", gconv.Int(req.Status))
}
if req.Mobile != "" {
m = m.Where("mobile like ?", "%"+req.Mobile+"%")
}
if len(req.DateRange) > 0 {
m = m.Where("created_at >=? AND created_at <=?", req.DateRange[0], req.DateRange[1])
}
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
if req.PageNum == 0 {
req.PageNum = 1
}
total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取用户数据失败")
err = m.FieldsEx(dao.SysUser.Columns().UserPassword, dao.SysUser.Columns().UserSalt).
Page(req.PageNum, req.PageSize).Order("id asc").Scan(&userList)
liberr.ErrIsNil(ctx, err, "获取用户列表失败")
})
return
}
// GetUsersRoleDeptInfo 获取多个用户角色 部门信息
func (s *sSysUser) GetUsersRoleDeptInfo(ctx context.Context, userList []*entity.SysUser) (users []*model.SysUserRoleDeptRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
allRoles, e := service.SysRole().GetRoleList(ctx)
liberr.ErrIsNil(ctx, e)
depts, e := service.SysDept().GetFromCache(ctx)
liberr.ErrIsNil(ctx, e)
users = make([]*model.SysUserRoleDeptRes, len(userList))
for k, u := range userList {
var dept *entity.SysDept
users[k] = &model.SysUserRoleDeptRes{
SysUser: u,
}
for _, d := range depts {
if u.DeptId == d.DeptId {
dept = d
}
}
users[k].Dept = dept
roles, e := s.GetAdminRole(ctx, u.Id, allRoles)
liberr.ErrIsNil(ctx, e)
for _, r := range roles {
users[k].IsOperation = true
if r.Id == consts.SuperAdminId || r.Id == consts.SalesAgentId || r.Id == consts.SiteAdminId {
users[k].IsOperation = false
}
users[k].RoleInfo = append(users[k].RoleInfo, &model.SysUserRoleInfoRes{RoleId: r.Id, Name: r.Name})
}
}
})
return
}
func (s *sSysUser) GetTenantInfo(ctx context.Context, userList []*model.SysUserRoleDeptRes) (user []*model.SysUserRoleDeptRes, err error) {
// 1. 创建一个用于存放 ID 的空字符串切片
idList := make([]uint64, 0, len(userList))
// 2. 遍历原始列表
for _, user := range userList {
idList = append(idList, gconv.Uint64(user.TenantId))
}
var tenantList *system.GetTenantDetailsByIdsRes
tenantList, err = service.Tenant().GetTenantDetailsByIds(ctx, &system.GetTenantDetailsByIdsReq{
TenantIds: idList,
})
liberr.ErrIsNil(ctx, err)
for _, user := range userList {
for _, tenant := range tenantList.List {
if user.TenantId == tenant.Id {
user.TenantName = tenant.TenantName
}
}
}
return userList, nil
}
func (s *sSysUser) getSearchDeptIds(ctx context.Context, deptId uint64) (deptIds []uint64, err error) {
err = g.Try(ctx, func(ctx context.Context) {
deptAll, e := service.SysDept().GetFromCache(ctx)
liberr.ErrIsNil(ctx, e)
deptWithChildren := service.SysDept().FindSonByParentId(deptAll, deptId)
deptIds = make([]uint64, len(deptWithChildren))
for k, v := range deptWithChildren {
deptIds[k] = v.DeptId
}
deptIds = append(deptIds, deptId)
})
return
}
func (s *sSysUser) Add(ctx context.Context, req *system.UserAddReq) (res *system.UserAddRes, err error) {
err = s.UserNameOrMobileExists(ctx, req.UserName, req.Mobile)
if err != nil {
return
}
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
liberr.ErrIsNil(ctx, err)
req.UserSalt = grand.S(10)
req.Password = libUtils.EncryptPassword(req.Password, req.UserSalt)
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
userId, e := dao.SysUser.Ctx(ctx).TX(tx).InsertAndGetId(do.SysUser{
UserName: req.UserName,
Mobile: req.Mobile,
UserNickname: req.NickName,
UserPassword: req.Password,
UserSalt: req.UserSalt,
UserStatus: req.Status,
UserEmail: req.Email,
Sex: req.Sex,
DeptId: req.DeptId,
Remark: req.Remark,
IsAdmin: req.IsAdmin,
TenantId: gconv.Uint64(getUserInfo.TenantId),
})
res = new(system.UserAddRes)
res.UserId = userId
liberr.ErrIsNil(ctx, e, "添加用户失败")
e = s.addUserRole(ctx, req.RoleIds, userId)
liberr.ErrIsNil(ctx, e, "设置用户权限失败")
e = s.AddUserPost(ctx, tx, req.PostIds, userId)
liberr.ErrIsNil(ctx, e)
})
return err
})
return
}
func (s *sSysUser) Edit(ctx context.Context, req *system.UserEditReq) (err error) {
err = s.UserNameOrMobileExists(ctx, "", req.Mobile, req.UserId)
if err != nil {
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).TX(tx).WherePri(req.UserId).Update(do.SysUser{
Mobile: req.Mobile,
UserNickname: req.NickName,
UserStatus: req.Status,
UserEmail: req.Email,
Sex: req.Sex,
DeptId: req.DeptId,
Remark: req.Remark,
IsAdmin: req.IsAdmin,
})
liberr.ErrIsNil(ctx, err, "修改用户信息失败")
//设置用户所属角色信息
err = s.EditUserRole(ctx, req.RoleIds, req.UserId)
liberr.ErrIsNil(ctx, err, "设置用户权限失败")
err = s.AddUserPost(ctx, tx, req.PostIds, req.UserId)
liberr.ErrIsNil(ctx, err)
})
return err
})
return
}
// AddUserPost 添加用户岗位信息
func (s *sSysUser) AddUserPost(ctx context.Context, tx gdb.TX, postIds []int64, userId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
//删除旧岗位信息
_, err = dao.SysUserPost.Ctx(ctx).TX(tx).Where(dao.SysUserPost.Columns().UserId, userId).Delete()
liberr.ErrIsNil(ctx, err, "设置用户岗位失败")
if len(postIds) == 0 {
return
}
//添加用户岗位信息
data := g.List{}
for _, v := range postIds {
data = append(data, g.Map{
dao.SysUserPost.Columns().UserId: userId,
dao.SysUserPost.Columns().PostId: v,
})
}
_, err = dao.SysUserPost.Ctx(ctx).TX(tx).Data(data).Insert()
liberr.ErrIsNil(ctx, err, "设置用户岗位失败")
})
return
}
// AddUserRole 添加用户角色信息
func (s *sSysUser) addUserRole(ctx context.Context, roleIds []int64, userId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
for _, v := range roleIds {
_, e = enforcer.AddGroupingPolicy(fmt.Sprintf("%s%d", s.casBinUserPrefix, userId), gconv.String(v))
liberr.ErrIsNil(ctx, e)
}
})
return
}
// EditUserRole 修改用户角色信息
func (s *sSysUser) EditUserRole(ctx context.Context, roleIds []int64, userId int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
//删除用户旧角色信息
enforcer.RemoveFilteredGroupingPolicy(0, fmt.Sprintf("%s%d", s.casBinUserPrefix, userId))
for _, v := range roleIds {
_, err = enforcer.AddGroupingPolicy(fmt.Sprintf("%s%d", s.casBinUserPrefix, userId), gconv.String(v))
liberr.ErrIsNil(ctx, err)
}
})
return
}
func (s *sSysUser) UserNameOrMobileExists(ctx context.Context, userName, mobile string, id ...int64) error {
user := (*entity.SysUser)(nil)
err := g.Try(ctx, func(ctx context.Context) {
m := dao.SysUser.Ctx(ctx)
if len(id) > 0 {
m = m.Where(dao.SysUser.Columns().Id+" != ", id)
}
m = m.Where(fmt.Sprintf("%s='%s' OR %s='%s'",
dao.SysUser.Columns().UserName,
userName,
dao.SysUser.Columns().Mobile,
mobile))
err := m.Limit(1).Scan(&user)
liberr.ErrIsNil(ctx, err, "获取用户信息失败")
if user == nil {
return
}
if user.UserName == userName {
liberr.ErrIsNil(ctx, gerror.New("账号已存在"))
}
if user.Mobile == mobile {
liberr.ErrIsNil(ctx, gerror.New("手机号已存在"))
}
})
return err
}
// GetEditUser 获取编辑用户信息
func (s *sSysUser) GetEditUser(ctx context.Context, id uint64) (res *system.UserGetEditRes, err error) {
res = new(system.UserGetEditRes)
err = g.Try(ctx, func(ctx context.Context) {
//获取用户信息
res.User, err = s.GetUserInfoById(ctx, id)
liberr.ErrIsNil(ctx, err)
//获取已选择的角色信息
res.CheckedRoleIds, err = s.GetAdminRoleIds(ctx, id)
liberr.ErrIsNil(ctx, err)
res.CheckedPosts, err = s.GetUserPostIds(ctx, id)
liberr.ErrIsNil(ctx, err)
})
return
}
// GetUserInfoById 通过Id获取用户信息
func (s *sSysUser) GetUserInfoById(ctx context.Context, id uint64, withPwd ...bool) (user *entity.SysUser, err error) {
err = g.Try(ctx, func(ctx context.Context) {
if len(withPwd) > 0 && withPwd[0] {
//用户用户信息
err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, id).Scan(&user)
} else {
//用户用户信息
err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, id).
FieldsEx(dao.SysUser.Columns().UserPassword, dao.SysUser.Columns().UserSalt).Scan(&user)
}
liberr.ErrIsNil(ctx, err, "获取用户数据失败")
})
return
}
// GetUserPostIds 获取用户岗位
func (s *sSysUser) GetUserPostIds(ctx context.Context, userId uint64) (postIds []int64, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var list []*entity.SysUserPost
err = dao.SysUserPost.Ctx(ctx).Where(dao.SysUserPost.Columns().UserId, userId).Scan(&list)
liberr.ErrIsNil(ctx, err, "获取用户岗位信息失败")
postIds = make([]int64, 0)
for _, entity := range list {
postIds = append(postIds, entity.PostId)
}
})
return
}
// ResetUserPwd 重置用户密码
func (s *sSysUser) ResetUserPwd(ctx context.Context, req *system.UserResetPwdReq) (err error) {
salt := grand.S(10)
password := libUtils.EncryptPassword(req.Password, salt)
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).WherePri(req.Id).Update(g.Map{
dao.SysUser.Columns().UserSalt: salt,
dao.SysUser.Columns().UserPassword: password,
})
liberr.ErrIsNil(ctx, err, "重置用户密码失败")
})
return
}
func (s *sSysUser) ChangeUserStatus(ctx context.Context, req *system.UserStatusReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).WherePri(req.Id).Update(do.SysUser{UserStatus: req.UserStatus})
liberr.ErrIsNil(ctx, err, "设置用户状态失败")
})
return
}
// Delete 删除用户
func (s *sSysUser) Delete(ctx context.Context, ids []int) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysUser.Ctx(ctx).TX(tx).Where(dao.SysUser.Columns().Id+" in(?)", ids).Delete()
liberr.ErrIsNil(ctx, err, "删除用户失败")
//删除对应权限
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e)
for _, v := range ids {
enforcer.RemoveFilteredGroupingPolicy(0, fmt.Sprintf("%s%d", s.casBinUserPrefix, v))
}
//删除用户对应的岗位
_, err = dao.SysUserPost.Ctx(ctx).TX(tx).Delete(dao.SysUserPost.Columns().UserId+" in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除用户的岗位失败")
})
return err
})
return
}
// GetUsers 通过用户ids查询多个用户信息
func (s *sSysUser) GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error) {
if len(ids) == 0 {
return
}
idsSet := gset.NewIntSetFrom(ids).Slice()
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id+" in(?)", idsSet).
Order(dao.SysUser.Columns().Id + " ASC").Scan(&users)
})
return
}
func (s *sSysUser) IsSuperAdmin(ctx context.Context, req *system.IsSuperAdminReq) (isSuperAdmin bool, err error) {
_ = req
isSuperAdmin = false
// 获取用户id
getUserInfo, err := utils.GetUserInfo(ctx)
if err != nil {
return
}
userId := getUserInfo.Id
if !g.IsEmpty(userId) {
var roleIds []uint
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, gconv.Uint64(userId))
liberr.ErrIsNil(ctx, err, "获取用户角色失败")
for _, v := range roleIds {
if v == consts.SuperAdminId {
isSuperAdmin = true
return
} else {
isSuperAdmin = false
}
}
}
return
}

View File

@@ -0,0 +1,185 @@
/*
* @desc:用户在线状态处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2023/1/10 14:50
*/
package sysUserOnline
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/grpool"
"github.com/gogf/gf/v2/os/gtime"
"github.com/mssola/user_agent"
"github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/api/v1/system"
comModel "github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysUserOnline(New())
}
func New() *sSysUserOnline {
return &sSysUserOnline{
Pool: grpool.New(100),
}
}
type sSysUserOnline struct {
Pool *grpool.Pool
}
func (s *sSysUserOnline) Invoke(ctx context.Context, params *model.SysUserOnlineParams) {
s.Pool.Add(ctx, func(ctx context.Context) {
//写入数据
s.SaveOnline(ctx, params)
})
}
// SaveOnline 保存用户在线状态
func (s *sSysUserOnline) SaveOnline(ctx context.Context, params *model.SysUserOnlineParams) {
err := g.Try(ctx, func(ctx context.Context) {
ua := user_agent.New(params.UserAgent)
browser, _ := ua.Browser()
os := ua.OS()
var (
info *entity.SysUserOnline
data = &do.SysUserOnline{
Uuid: params.Uuid,
Token: params.Token,
CreateTime: gtime.Now(),
UserName: params.Username,
Ip: params.Ip,
Explorer: browser,
Os: os,
}
)
//查询是否已存在当前用户
err := dao.SysUserOnline.Ctx(ctx).Fields(dao.SysUserOnline.Columns().Id).
Where(dao.SysUserOnline.Columns().Token, data.Token).
Scan(&info)
liberr.ErrIsNil(ctx, err)
//若已存在则更新
if info != nil {
_, err = dao.SysUserOnline.Ctx(ctx).
Where(dao.SysUserOnline.Columns().Id, info.Id).
FieldsEx(dao.SysUserOnline.Columns().Id).Update(data)
liberr.ErrIsNil(ctx, err)
} else { //否则新增
_, err = dao.SysUserOnline.Ctx(ctx).
FieldsEx(dao.SysUserOnline.Columns().Id).Insert(data)
liberr.ErrIsNil(ctx, err)
}
})
if err != nil {
g.Log().Error(ctx, err)
}
}
// CheckUserOnline 检查在线用户
func (s *sSysUserOnline) CheckUserOnline(ctx context.Context) {
param := &system.SysUserOnlineSearchReq{
PageReq: common.PageReq{
PageReq: comModel.PageReq{
PageNum: 1,
PageSize: 50,
},
},
}
var total int
for {
var (
res *system.SysUserOnlineSearchRes
err error
)
res, err = s.GetOnlineListPage(ctx, param, true)
if err != nil {
g.Log().Error(ctx, err)
break
}
if res.List == nil {
break
}
for _, v := range res.List {
if b := s.UserIsOnline(ctx, v.Token); !b {
s.DeleteOnlineByToken(ctx, v.Token)
}
}
if param.PageNum*param.PageSize >= total {
break
}
param.PageNum++
}
}
// GetOnlineListPage 搜素在线用户列表
func (s *sSysUserOnline) GetOnlineListPage(ctx context.Context, req *system.SysUserOnlineSearchReq, hasToken ...bool) (res *system.SysUserOnlineSearchRes, err error) {
if req.PageNum == 0 {
req.PageNum = 1
}
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
model := dao.SysUserOnline.Ctx(ctx)
if req.Ip != "" {
model = model.Where("ip like ?", "%"+req.Ip+"%")
}
if req.Username != "" {
model = model.Where("user_name like ?", "%"+req.Username+"%")
}
res = new(system.SysUserOnlineSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
res.Total, err = model.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if len(hasToken) == 0 || !hasToken[0] {
model = model.FieldsEx("token")
}
err = model.Page(req.PageNum, req.PageSize).Order("create_time DESC").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
func (s *sSysUserOnline) UserIsOnline(ctx context.Context, token string) bool {
err := g.Try(ctx, func(ctx context.Context) {
_, _, err := service.GfToken().GetTokenData(ctx, token)
liberr.ErrIsNil(ctx, err)
})
return err == nil
}
func (s *sSysUserOnline) DeleteOnlineByToken(ctx context.Context, token string) (err error) {
_, err = dao.SysUserOnline.Ctx(ctx).Delete(dao.SysUserOnline.Columns().Token, token)
return
}
func (s *sSysUserOnline) ForceLogout(ctx context.Context, ids []int) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
var onlineList []*entity.SysUserOnline
onlineList, err = s.GetInfosByIds(ctx, ids)
liberr.ErrIsNil(ctx, err)
_, err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Id+" in(?)", ids).Delete()
liberr.ErrIsNil(ctx, err)
for _, v := range onlineList {
err = service.GfToken().RemoveToken(ctx, v.Token)
liberr.ErrIsNil(ctx, err)
}
})
return
}
func (s *sSysUserOnline) GetInfosByIds(ctx context.Context, ids []int) (onlineList []*entity.SysUserOnline, err error) {
err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Id+" in(?)", ids).Scan(&onlineList)
return
}

View File

@@ -0,0 +1,303 @@
/*
* @desc:用户处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/23 15:08
*/
package tenant
import (
"context"
"database/sql"
"errors"
"fmt"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/minio"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterTenant(New())
}
type sTenant struct {
}
func New() *sTenant {
return &sTenant{}
}
func (s *sTenant) GetTenantListSearch(ctx context.Context, req *system.TenantListReq) (res *system.TenantListRes, err error) {
res = new(system.TenantListRes)
err = g.Try(ctx, func(ctx context.Context) {
res.ImgAddressPrefix = minio.GetFileAddressPrefix(ctx)
model := dao.TenantDao.Ctx(ctx)
// 根据toke获取用户id
userId := service.Context().GetUserId(ctx)
getUserById, err := service.SysUser().GetUserById(ctx, userId)
liberr.ErrIsNil(ctx, err, "获取用户信息失败")
roleIds, err := service.SysUser().GetAdminRoleIds(ctx, userId)
// 根据用户角色查询对应数据9代理10普通
for _, v := range roleIds {
if v == consts.SalesAgentId || v == consts.SiteAdminId {
model = model.Where(dao.TenantDao.Columns().TenantSource, gconv.Int64(getUserById.TenantId))
}
}
if !g.IsEmpty(req.TenantName) {
model = model.Where(dao.TenantDao.Columns().TenantName+" like ? ", "%"+req.TenantName+"%")
}
if !g.IsEmpty(req.TenantType) {
model = model.Where(dao.TenantDao.Columns().TenantType, gconv.Int(req.TenantType))
}
if !g.IsEmpty(req.CityCode) {
model = model.Where(dao.TenantDao.Columns().CityCode, gconv.String(req.CityCode))
}
res.Total, err = model.Count()
liberr.ErrIsNil(ctx, err, "获取租户数据失败")
if req.PageNum == 0 {
req.PageNum = 1
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
err = model.Page(res.CurrentPage, req.PageSize).Order(dao.TenantDao.Columns().CreatedAt + " desc").Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
var list []map[string]interface{}
err = utils.Struct(res.List, &list)
liberr.ErrIsNil(ctx, err, "转换数据失败")
// 2. 提取id
userIds := make([]int, 0, len(list))
cityIds := make([]string, 0, len(list))
for _, obj := range list {
// 提取id并转换JSON数字是float64
idFloat, ok := obj["adminBy"].(float64)
if !ok {
fmt.Println("警告adminBy字段非数字")
continue
}
cityFloat, ok := obj["cityCode"].(string)
if !ok {
fmt.Println("警告cityCode字段非字符串")
continue
}
userIds = append(userIds, int(idFloat))
cityIds = append(cityIds, cityFloat)
}
userList, err := service.SysUser().GetUsers(ctx, userIds)
liberr.ErrIsNil(ctx, err, "获取租户信息失败")
areaDicList, err := service.AreaDict().GetAreaDict(ctx)
liberr.ErrIsNil(ctx, err, "获取地区字典失败")
for _, list := range res.List {
for _, areas := range areaDicList {
if fmt.Sprintf("%d", areas.Id) == list.CityCode {
list.CityName = areas.CityName
list.CityMergerName = areas.MergerName
}
}
for _, users := range userList {
if users.Id == list.AdminBy {
list.UserName = users.UserName
list.Mobile = users.Mobile
list.UserNickname = users.UserNickname
}
}
}
})
return
}
func (s *sTenant) Add(ctx context.Context, req *system.TenantAddReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
// 根据token获取用户id
userId := service.Context().GetUserId(ctx)
var getUserInfo *beans.User
getUserInfo, err = utils.GetUserInfo(ctx)
var userTenantId uint64
if err == nil && !g.IsEmpty(getUserInfo.TenantId) {
userTenantId = gconv.Uint64(getUserInfo.TenantId)
}
if !g.IsEmpty(userId) {
var roleIds []uint
roleIds, err = service.SysUser().GetAdminRoleIds(ctx, userId)
liberr.ErrIsNil(ctx, err, "获取用户角色失败")
// 如果是代理和普通用户只能添加普通类型1普通类型2代理类型
for _, v := range roleIds {
if v == consts.SalesAgentId || v == consts.SiteAdminId {
req.TenantType = consts.TenantTypeSite
if v == consts.SalesAgentId {
// 验证代理区域是否在当前代理的管辖范围内
tenantEntity := new(entity.Tenant)
err = dao.TenantDao.Ctx(ctx).TX(tx).Where(dao.TenantDao.Columns().Id, userTenantId).Scan(tenantEntity)
liberr.ErrIsNil(ctx, err, "获取租户数据失败")
var count int
count, err = dao.AreaDictDao.Ctx(ctx).TX(tx).Where("("+dao.AreaDictDao.Columns().Id+"=? OR "+dao.AreaDictDao.Columns().ParentId+"=?) AND "+dao.AreaDictDao.Columns().Id+"=?", tenantEntity.CityCode, tenantEntity.CityCode, req.CityCode).Count()
liberr.ErrIsNil(ctx, err, "验证代理区域失败")
if count == 0 {
liberr.ErrIsNil(ctx, errors.New("所选城市不在当前代理的管辖范围内"))
}
} else {
if req.TenantType == consts.TenantTypeAgent {
liberr.ErrIsNil(ctx, errors.New("代理商不能添加代理商"))
}
}
break
}
}
} else {
// 如果是普通用户只能添加普通类型1普通类型2代理类型
req.TenantType = consts.TenantTypeSite
}
if req.TenantType == consts.TenantTypeAgent {
// 验证代理区域是否已有代理商
var count int
count, err = dao.TenantDao.Ctx(ctx).TX(tx).Where(dao.TenantDao.Columns().CityCode, req.CityCode).Count()
liberr.ErrIsNil(ctx, err, "获取租户数据失败")
if count > 0 {
liberr.ErrIsNil(ctx, errors.New("该城市已有代理商"))
}
}
var tenantId int64
tenantId, err = dao.TenantDao.Ctx(ctx).TX(tx).InsertAndGetId(do.Tenant{
CreateBy: userId,
UpdateBy: userId,
TenantName: req.TenantName,
TenantType: req.TenantType,
CityCode: req.CityCode,
BusinessLicense: req.BusinessLicense,
TenantSource: userTenantId,
})
liberr.ErrIsNil(ctx, err, "添加租户失败")
var RoleIds = []int64{consts.SiteAdminId}
if !g.IsNil(req.TenantType) && req.TenantType == consts.TenantTypeAgent {
RoleIds = []int64{consts.SalesAgentId}
}
// 在同一事务中添加部门
var deptId int64
var deptInsertId sql.Result
deptInsertId, err = dao.SysDept.Ctx(ctx).TX(tx).Insert(do.SysDept{
ParentId: 0,
DeptName: req.TenantName,
OrderNum: 0,
Leader: req.UserNickname,
Phone: req.Mobile,
Email: req.Mobile + "@qq.com",
Status: 1,
CreatedBy: userId,
TenantId: uint64(tenantId),
})
liberr.ErrIsNil(ctx, err, "添加部门失败")
deptId, err = deptInsertId.LastInsertId()
liberr.ErrIsNil(ctx, err, "获取部门ID失败")
// 在同一事务中添加用户
err = service.SysUser().UserNameOrMobileExists(ctx, req.UserName, req.Mobile)
liberr.ErrIsNil(ctx, err)
userSalt := grand.S(10)
userPassword := libUtils.EncryptPassword(req.UserPassword, userSalt)
var adminUserId int64
adminUserId, err = dao.SysUser.Ctx(ctx).TX(tx).InsertAndGetId(do.SysUser{
UserName: req.UserName,
Mobile: req.Mobile,
UserNickname: req.UserNickname,
UserPassword: userPassword,
UserSalt: userSalt,
UserStatus: 1,
DeptId: uint64(deptId),
IsAdmin: 1,
TenantId: uint64(tenantId),
})
liberr.ErrIsNil(ctx, err, "添加用户失败")
// 添加用户角色信息使用Casbin
enforcer, e := commonService.CasbinEnforcer(ctx)
liberr.ErrIsNil(ctx, e, "获取权限引擎失败")
for _, v := range RoleIds {
_, e = enforcer.AddGroupingPolicy(fmt.Sprintf("u_%d", adminUserId), gconv.String(v))
liberr.ErrIsNil(ctx, e, "设置用户权限失败")
}
// 更新租户的AdminBy字段
_, err = dao.TenantDao.Ctx(ctx).TX(tx).WherePri(tenantId).Update(do.Tenant{
AdminBy: adminUserId,
})
liberr.ErrIsNil(ctx, err, "修改租户信息失败")
})
return err
})
return
}
func (s *sTenant) Edit(ctx context.Context, req *system.TenantEditReq) (err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
userId := service.Context().GetUserId(ctx)
tenant := do.Tenant{
UpdateBy: userId,
TenantName: req.TenantName,
CityCode: req.CityCode,
BusinessLicense: req.BusinessLicense,
}
if !g.IsEmpty(req.TenantType) {
tenant.TenantType = req.TenantType
}
_, err = dao.TenantDao.Ctx(ctx).TX(tx).WherePri(req.Id).Update(tenant)
liberr.ErrIsNil(ctx, err, "修改租户信息失败")
})
return err
})
return
}
func (s *sTenant) GetTenantDetailsByIds(ctx context.Context, req *system.GetTenantDetailsByIdsReq) (res *system.GetTenantDetailsByIdsRes, err error) {
res = new(system.GetTenantDetailsByIdsRes)
if len(req.TenantIds) == 0 {
return
}
idsSet := gset.NewIntSetFrom(gconv.Ints(req.TenantIds)).Slice()
err = g.Try(ctx, func(ctx context.Context) {
err = dao.TenantDao.Ctx(ctx).Where(dao.TenantDao.Columns().Id+" in(?)", idsSet).Order(dao.TenantDao.Columns().Id + " ASC").Scan(&res.List)
})
return
}
func (s *sTenant) GetTenantDetails(ctx context.Context, id uint64) (res *entity.Tenant, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.TenantDao.Ctx(ctx).WherePri(id).Scan(&res)
})
return
}
func (s *sTenant) GetTenantAdminById(ctx context.Context, id uint64) (res []entity.Tenant, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.TenantDao.Ctx(ctx).Where(dao.TenantDao.Columns().Id+" =(?) or "+dao.TenantDao.Columns().TenantSource+" =(?)", id, id).Order(dao.TenantDao.Columns().Id + " ASC").Scan(&res)
})
return
}
func (s *sTenant) GetTenantIdList(ctx context.Context, req *system.GetTenantListReq) (res []entity.Tenant, err error) {
err = g.Try(ctx, func(ctx context.Context) {
model := dao.TenantDao.Ctx(ctx)
if !g.IsEmpty(req.TenantId) {
model.Where(dao.TenantDao.Columns().Id, req.TenantId)
}
err = model.Scan(&res)
})
return
}

View File

@@ -0,0 +1,51 @@
/*
* @desc:token功能
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/27 17:01
*/
package token
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/tiger1103/gfast-token/gftoken"
"github.com/tiger1103/gfast/v3/internal/app/common/consts"
commonModel "github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
type sToken struct {
*gftoken.GfToken
}
func New() *sToken {
var (
ctx = gctx.New()
opt *commonModel.TokenOptions
err = g.Cfg().MustGet(ctx, "gfToken").Struct(&opt)
fun gftoken.OptionFunc
)
liberr.ErrIsNil(ctx, err)
if opt.CacheModel == consts.CacheModelRedis {
fun = gftoken.WithGRedis()
} else {
fun = gftoken.WithGCache()
}
return &sToken{
GfToken: gftoken.NewGfToken(
gftoken.WithCacheKey(opt.CacheKey),
gftoken.WithTimeout(opt.Timeout),
gftoken.WithMaxRefresh(opt.MaxRefresh),
gftoken.WithMultiLogin(opt.MultiLogin),
gftoken.WithExcludePaths(opt.ExcludePaths),
fun,
),
}
}
func init() {
service.RegisterGToken(New())
}