mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
feat: redis支持flushdb、菜单资源支持拖拽排序、禁用等
This commit is contained in:
@@ -52,6 +52,7 @@ func (r *Redis) Hset(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
hashValue := new(form.HashValue)
|
||||
ginx.BindJsonAndValid(g, hashValue)
|
||||
rc.ReqParam = hashValue
|
||||
|
||||
hv := hashValue.Value[0]
|
||||
res, err := r.getRedisIns(rc).GetCmdable().HSet(context.TODO(), hashValue.Key, hv["field"].(string), hv["value"]).Result()
|
||||
|
||||
@@ -148,7 +148,7 @@ func (r *Redis) Scan(rc *req.Ctx) {
|
||||
func (r *Redis) TtlKey(rc *req.Ctx) {
|
||||
ri, key := r.checkKeyAndGetRedisIns(rc)
|
||||
ttl, err := ri.GetCmdable().TTL(context.Background(), key).Result()
|
||||
biz.ErrIsNil(err, "ttl失败: %s")
|
||||
biz.ErrIsNilAppendErr(err, "ttl失败: %s")
|
||||
|
||||
if ttl == -1 {
|
||||
rc.ResData = -1
|
||||
@@ -187,3 +187,10 @@ func (r *Redis) PersistKey(rc *req.Ctx) {
|
||||
rc.ReqParam = fmt.Sprintf("%s -> 移除key[%s]的过期时间", ri.Info.GetLogDesc(), key)
|
||||
ri.GetCmdable().Persist(context.Background(), key)
|
||||
}
|
||||
|
||||
// 清空库
|
||||
func (r *Redis) FlushDb(rc *req.Ctx) {
|
||||
ri := r.getRedisIns(rc)
|
||||
rc.ReqParam = fmt.Sprintf("%s -> flushdb", ri.Info.GetLogDesc())
|
||||
ri.GetCmdable().FlushDB(context.Background())
|
||||
}
|
||||
|
||||
@@ -91,6 +91,14 @@ func InitRedisRouter(router *gin.RouterGroup) {
|
||||
Handle(rs.PersistKey)
|
||||
})
|
||||
|
||||
flushDbL := req.NewLogInfo("redis-flushdb").WithSave(true)
|
||||
redis.DELETE(":id/:db/flushdb", func(c *gin.Context) {
|
||||
req.NewCtxWithGin(c).
|
||||
WithLog(flushDbL).
|
||||
WithRequiredPermission(saveDataP).
|
||||
Handle(rs.FlushDb)
|
||||
})
|
||||
|
||||
// 获取string类型值
|
||||
redis.GET(":id/:db/string-value", func(c *gin.Context) {
|
||||
req.NewCtxWithGin(c).Handle(rs.GetStringValue)
|
||||
|
||||
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mayfly-go/internal/sys/api/form"
|
||||
"mayfly-go/internal/sys/api/vo"
|
||||
"mayfly-go/internal/sys/application"
|
||||
@@ -46,8 +47,20 @@ func (r *Resource) DelResource(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (r *Resource) ChangeStatus(rc *req.Ctx) {
|
||||
re := &entity.Resource{}
|
||||
re.Id = uint64(ginx.PathParamInt(rc.GinCtx, "id"))
|
||||
re.Status = int8(ginx.PathParamInt(rc.GinCtx, "status"))
|
||||
r.ResourceApp.Save(re)
|
||||
rid := uint64(ginx.PathParamInt(rc.GinCtx, "id"))
|
||||
status := int8(ginx.PathParamInt(rc.GinCtx, "status"))
|
||||
rc.ReqParam = fmt.Sprintf("id = %d, status = %d", rid, status)
|
||||
r.ResourceApp.ChangeStatus(rid, status)
|
||||
}
|
||||
|
||||
func (r *Resource) Sort(rc *req.Ctx) {
|
||||
var rs []form.ResourceForm
|
||||
rc.GinCtx.ShouldBindJSON(&rs)
|
||||
rc.ReqParam = rs
|
||||
|
||||
for _, v := range rs {
|
||||
sortE := &entity.Resource{Pid: v.Pid, Weight: v.Weight}
|
||||
sortE.Id = uint64(v.Id)
|
||||
r.ResourceApp.Sort(sortE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ type ResourceManageVO struct {
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
Status int `json:"status"`
|
||||
Weight int `json:"weight"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ import (
|
||||
"mayfly-go/internal/sys/domain/entity"
|
||||
"mayfly-go/internal/sys/domain/repository"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Resource interface {
|
||||
@@ -17,6 +20,10 @@ type Resource interface {
|
||||
|
||||
Save(entity *entity.Resource)
|
||||
|
||||
ChangeStatus(resourceId uint64, status int8)
|
||||
|
||||
Sort(re *entity.Resource)
|
||||
|
||||
Delete(id uint64)
|
||||
|
||||
GetAccountResources(accountId uint64, toEntity any)
|
||||
@@ -45,6 +52,7 @@ func (r *resourceAppImpl) GetByIdIn(ids []uint64, toEntity any, orderBy ...strin
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) Save(resource *entity.Resource) {
|
||||
// 更新操作
|
||||
if resource.Id != 0 {
|
||||
if resource.Code != "" {
|
||||
oldRes := r.GetById(resource.Id, "Code")
|
||||
@@ -54,17 +62,88 @@ func (r *resourceAppImpl) Save(resource *entity.Resource) {
|
||||
}
|
||||
}
|
||||
model.UpdateById(resource)
|
||||
} else {
|
||||
if pid := resource.Pid; pid != 0 {
|
||||
biz.IsTrue(r.GetById(uint64(pid)) != nil, "该父资源不存在")
|
||||
}
|
||||
// 默认启用状态
|
||||
if resource.Status == 0 {
|
||||
resource.Status = entity.ResourceStatusEnable
|
||||
}
|
||||
r.checkCode(resource.Code)
|
||||
model.Insert(resource)
|
||||
return
|
||||
}
|
||||
|
||||
// 生成随机八位唯一标识符
|
||||
ui := utils.RandString(8)
|
||||
if pid := resource.Pid; pid != 0 {
|
||||
pResource := r.GetById(uint64(pid))
|
||||
biz.IsTrue(pResource != nil, "该父资源不存在")
|
||||
resource.UiPath = pResource.UiPath + ui + entity.ResourceUiPathSp
|
||||
} else {
|
||||
resource.UiPath = ui + entity.ResourceUiPathSp
|
||||
}
|
||||
// 默认启用状态
|
||||
if resource.Status == 0 {
|
||||
resource.Status = entity.ResourceStatusEnable
|
||||
}
|
||||
r.checkCode(resource.Code)
|
||||
resource.Weight = int(time.Now().Unix())
|
||||
model.Insert(resource)
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) ChangeStatus(resourceId uint64, status int8) {
|
||||
resource := r.resourceRepo.GetById(resourceId)
|
||||
biz.NotNil(resource, "资源不存在")
|
||||
resource.Status = status
|
||||
r.resourceRepo.UpdateByUiPathLike(resource)
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) Sort(sortResource *entity.Resource) {
|
||||
resource := r.resourceRepo.GetById(sortResource.Id)
|
||||
biz.NotNil(resource, "资源不存在")
|
||||
// 未改变父节点,则更新排序值即可
|
||||
if sortResource.Pid == resource.Pid {
|
||||
saveE := &entity.Resource{Weight: sortResource.Weight}
|
||||
saveE.Id = sortResource.Id
|
||||
r.Save(saveE)
|
||||
return
|
||||
}
|
||||
|
||||
// 若资源原本唯一标识路径为:xxxx/yyyy/zzzz/,则获取其父节点路径标识 xxxx/yyyy/ 与自身节点标识 zzzz/
|
||||
splitStr := strings.Split(resource.UiPath, entity.ResourceUiPathSp)
|
||||
// 获取 zzzz/
|
||||
resourceUi := splitStr[len(splitStr)-2] + entity.ResourceUiPathSp
|
||||
// 获取父资源路径 xxxx/yyyy/
|
||||
var parentResourceUiPath string
|
||||
if len(splitStr) > 2 {
|
||||
parentResourceUiPath = strings.Split(resource.UiPath, resourceUi)[0]
|
||||
} else {
|
||||
parentResourceUiPath = resourceUi
|
||||
}
|
||||
|
||||
newParentResourceUiPath := ""
|
||||
if sortResource.Pid != 0 {
|
||||
newParentResource := r.resourceRepo.GetById(uint64(sortResource.Pid))
|
||||
biz.NotNil(newParentResource, "父资源不存在")
|
||||
newParentResourceUiPath = newParentResource.UiPath
|
||||
}
|
||||
|
||||
children := r.resourceRepo.GetChildren(resource.UiPath)
|
||||
for _, v := range children {
|
||||
if v.Id == sortResource.Id {
|
||||
continue
|
||||
}
|
||||
updateUiPath := &entity.Resource{}
|
||||
updateUiPath.Id = v.Id
|
||||
if parentResourceUiPath == resourceUi {
|
||||
updateUiPath.UiPath = newParentResourceUiPath + v.UiPath
|
||||
} else {
|
||||
updateUiPath.UiPath = strings.ReplaceAll(v.UiPath, parentResourceUiPath, newParentResourceUiPath)
|
||||
}
|
||||
r.Save(updateUiPath)
|
||||
}
|
||||
|
||||
// 更新零值使用map,因为pid=0表示根节点
|
||||
updateMap := map[string]interface{}{
|
||||
"pid": sortResource.Pid,
|
||||
"weight": sortResource.Weight,
|
||||
"ui_path": newParentResourceUiPath + resourceUi,
|
||||
}
|
||||
condition := new(entity.Resource)
|
||||
condition.Id = sortResource.Id
|
||||
global.Db.Model(condition).Updates(updateMap)
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) checkCode(code string) {
|
||||
@@ -73,19 +152,18 @@ func (r *resourceAppImpl) checkCode(code string) {
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) Delete(id uint64) {
|
||||
// 查找pid == id的资源
|
||||
condition := &entity.Resource{Pid: int(id)}
|
||||
var resources resourceList
|
||||
r.resourceRepo.GetResourceList(condition, &resources)
|
||||
resource := r.resourceRepo.GetById(id)
|
||||
biz.NotNil(resource, "资源不存在")
|
||||
|
||||
biz.IsTrue(len(resources) == 0, "请先删除该资源的所有子资源")
|
||||
model.DeleteById(condition, id)
|
||||
// 删除角色关联的资源信息
|
||||
model.DeleteByCondition(&entity.RoleResource{ResourceId: id})
|
||||
// 删除当前节点及其所有子节点
|
||||
children := r.resourceRepo.GetChildren(resource.UiPath)
|
||||
for _, v := range children {
|
||||
r.resourceRepo.Delete(v.Id)
|
||||
// 删除角色关联的资源信息
|
||||
model.DeleteByCondition(&entity.RoleResource{ResourceId: v.Id})
|
||||
}
|
||||
}
|
||||
|
||||
func (r *resourceAppImpl) GetAccountResources(accountId uint64, toEntity any) {
|
||||
r.resourceRepo.GetAccountResources(accountId, toEntity)
|
||||
}
|
||||
|
||||
type resourceList []entity.Resource
|
||||
|
||||
@@ -5,6 +5,7 @@ import "mayfly-go/pkg/model"
|
||||
type Resource struct {
|
||||
model.Model
|
||||
Pid int `json:"pid"`
|
||||
UiPath string // 唯一标识路径
|
||||
Type int8 `json:"type"` // 1:菜单路由;2:资源(按钮等)
|
||||
Status int8 `json:"status"` // 1:可用;-1:不可用
|
||||
Code string `json:"code"`
|
||||
@@ -24,4 +25,7 @@ const (
|
||||
// 资源状态
|
||||
ResourceTypeMenu int8 = 1
|
||||
ResourceTypePermission int8 = 2
|
||||
|
||||
// 唯一标识路径分隔符
|
||||
ResourceUiPathSp string = "/"
|
||||
)
|
||||
|
||||
@@ -18,4 +18,10 @@ type Resource interface {
|
||||
|
||||
// 获取账号资源列表
|
||||
GetAccountResources(accountId uint64, toEntity any)
|
||||
|
||||
// 获取所有子节点id
|
||||
GetChildren(uiPath string) []entity.Resource
|
||||
|
||||
// 根据uiPath右匹配更新所有相关类资源
|
||||
UpdateByUiPathLike(resource *entity.Resource)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,18 @@ func (r *resourceRepoImpl) GetByCondition(condition *entity.Resource, cols ...st
|
||||
return model.GetBy(condition, cols...)
|
||||
}
|
||||
|
||||
func (r *resourceRepoImpl) GetChildren(uiPath string) []entity.Resource {
|
||||
sql := "SELECT id, ui_path FROM t_sys_resource WHERE ui_path LIKE ?"
|
||||
var rs []entity.Resource
|
||||
model.GetListBySql2Model(sql, &rs, uiPath+"%")
|
||||
return rs
|
||||
}
|
||||
|
||||
func (r *resourceRepoImpl) UpdateByUiPathLike(resource *entity.Resource) {
|
||||
sql := "UPDATE t_sys_resource SET status=? WHERE (ui_path LIKE ?)"
|
||||
model.ExecSql(sql, resource.Status, resource.UiPath+"%")
|
||||
}
|
||||
|
||||
func (r *resourceRepoImpl) GetAccountResources(accountId uint64, toEntity any) {
|
||||
sql := `SELECT
|
||||
m.id,
|
||||
@@ -51,7 +63,7 @@ func (r *resourceRepoImpl) GetAccountResources(accountId uint64, toEntity any) {
|
||||
FROM
|
||||
t_sys_resource m
|
||||
WHERE
|
||||
m.STATUS = 1
|
||||
m.status = 1
|
||||
AND m.id IN (
|
||||
SELECT DISTINCT
|
||||
( rmb.resource_id )
|
||||
|
||||
@@ -38,6 +38,13 @@ func InitResourceRouter(router *gin.RouterGroup) {
|
||||
Handle(r.ChangeStatus)
|
||||
})
|
||||
|
||||
sort := req.NewLogInfo("资源排序").WithSave(true)
|
||||
db.POST("sort", func(c *gin.Context) {
|
||||
req.NewCtxWithGin(c).
|
||||
WithLog(sort).
|
||||
Handle(r.Sort)
|
||||
})
|
||||
|
||||
delResource := req.NewLogInfo("删除资源").WithSave(true)
|
||||
dePermission := req.NewPermission("resource:delete")
|
||||
db.DELETE(":id", func(c *gin.Context) {
|
||||
|
||||
@@ -72,20 +72,15 @@ func (p *tagTreeAppImpl) Save(tag *entity.TagTree) {
|
||||
if tag.Pid != 0 {
|
||||
parentTag := p.tagTreeRepo.SelectById(tag.Pid)
|
||||
biz.NotNil(parentTag, "父节点不存在")
|
||||
tag.CodePath = parentTag.CodePath + entity.CodePathSeparator + tag.Code
|
||||
tag.CodePath = parentTag.CodePath + tag.Code + entity.CodePathSeparator
|
||||
} else {
|
||||
tag.CodePath = tag.Code
|
||||
tag.CodePath = tag.Code + entity.CodePathSeparator
|
||||
}
|
||||
// 判断该路径是否存在
|
||||
var hasLikeTags []entity.TagTree
|
||||
p.tagTreeRepo.SelectByCondition(&entity.TagTreeQuery{CodePathLike: tag.CodePath}, &hasLikeTags)
|
||||
biz.IsTrue(len(hasLikeTags) == 0, "已存在该标签路径开头的标签, 请修改该标识code")
|
||||
|
||||
// 校验同级标签,是否有以该code为开头的标识符
|
||||
p.tagTreeRepo.SelectByCondition(&entity.TagTreeQuery{Pid: tag.Pid}, &hasLikeTags)
|
||||
for _, v := range hasLikeTags {
|
||||
biz.IsTrue(!strings.HasPrefix(tag.Code, v.Code), "同级标签下的[%s]与[%s]存在相似开头字符, 请修改该标识code", v.Code, tag.Code)
|
||||
}
|
||||
p.tagTreeRepo.Insert(tag)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user