✨ 新增保存菜单接口
This commit is contained in:
parent
13b121be3c
commit
1d1ca21815
24
api/admin/menu/save.go
Normal file
24
api/admin/menu/save.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package menu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
menuParam "wechat-robot/model/param/menu"
|
||||||
|
"wechat-robot/pkg/response"
|
||||||
|
"wechat-robot/service/menu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @description: 保存菜单
|
||||||
|
// @param ctx
|
||||||
|
func Save(ctx *gin.Context) {
|
||||||
|
var p menuParam.Save
|
||||||
|
if err := ctx.ShouldBind(&p); err != nil {
|
||||||
|
response.New(ctx).SetError(err).Fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := menu.Save(p); err != nil {
|
||||||
|
response.New(ctx).SetError(err).Fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.New(ctx).Success()
|
||||||
|
}
|
148
internal/orm/sort.go
Normal file
148
internal/orm/sort.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gitee.ltd/lxh/logger/log"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @title checkHasDeletedAt
|
||||||
|
// @description 检查指定表是否有id_del字段
|
||||||
|
// @param tx *gorm.DB "已开启的事务对象"
|
||||||
|
// @param tableName string "表名"
|
||||||
|
// @return bool "是否包含"
|
||||||
|
func checkHasDeletedAt(tx *gorm.DB, tableName string) bool {
|
||||||
|
var columns []string
|
||||||
|
// SQL语句
|
||||||
|
sql := fmt.Sprintf("select COLUMN_NAME from information_schema.COLUMNS where table_name = '%s'", tableName)
|
||||||
|
err := tx.Raw(sql).Scan(&columns).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("查询表字段失败: %v", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return slices.Contains(columns, "id_del")
|
||||||
|
}
|
||||||
|
|
||||||
|
// @title checkHasUpdatedAt
|
||||||
|
// @description 检查指定表是否有updated_at字段
|
||||||
|
// @param tx *gorm.DB "已开启的事务对象"
|
||||||
|
// @param tableName string "表名"
|
||||||
|
// @return bool "是否包含"
|
||||||
|
func checkHasUpdatedAt(tx *gorm.DB, tableName string) bool {
|
||||||
|
var columns []string
|
||||||
|
// SQL语句
|
||||||
|
sql := fmt.Sprintf("select COLUMN_NAME from information_schema.COLUMNS where table_name = '%s'", tableName)
|
||||||
|
err := tx.Raw(sql).Scan(&columns).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("查询表字段失败: %v", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return slices.Contains(columns, "updated_at")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSortBefore
|
||||||
|
// @description 更新之前处理序号
|
||||||
|
// @param tx *gorm.DB "已开启的事务对象"
|
||||||
|
// @param model any "模型对象"
|
||||||
|
// @return error "错误信息"
|
||||||
|
func UpdateSortBefore(tx *gorm.DB, tableName, id string, sort int, param string) (err error) {
|
||||||
|
// 查出原来的排序号
|
||||||
|
var oldSort int
|
||||||
|
err = tx.Table(tableName).Select("`sort`").Where("id = ?", id).Scan(&oldSort).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("查询老数据失败: %v", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 如果相等,啥都不干
|
||||||
|
if oldSort == sort {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否包含 id_del 字段
|
||||||
|
hasDeletedAt := checkHasDeletedAt(tx, tableName)
|
||||||
|
|
||||||
|
// 处理排序
|
||||||
|
// 如果老的排序号小于新的,(老, 新]之间的排序号都要-1
|
||||||
|
// 如果老的大于新的,[老, 新)排序号-1
|
||||||
|
if oldSort < sort {
|
||||||
|
// 老的小于新的,[老, 新) + 1
|
||||||
|
sel := tx.Table(tableName).
|
||||||
|
Where("sort <= ? AND sort > ?", sort, oldSort)
|
||||||
|
if hasDeletedAt {
|
||||||
|
sel.Where("id_del = 0")
|
||||||
|
}
|
||||||
|
if param != "" {
|
||||||
|
sel.Where(param) // 自定义条件
|
||||||
|
}
|
||||||
|
err = sel.Update("sort", gorm.Expr("sort - 1")).Error
|
||||||
|
} else {
|
||||||
|
// 老的大于新的,[新, 老) + 1
|
||||||
|
sel := tx.Table(tableName).
|
||||||
|
Where("sort >= ? AND sort < ?", sort, oldSort)
|
||||||
|
if hasDeletedAt {
|
||||||
|
sel.Where("id_del = 0")
|
||||||
|
}
|
||||||
|
if param != "" {
|
||||||
|
sel.Where(param) // 自定义条件
|
||||||
|
}
|
||||||
|
err = sel.Update("sort", gorm.Expr("sort + 1")).Error
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSortBefore
|
||||||
|
// @description 新建之前处理序号
|
||||||
|
// @param tx *gorm.DB "已开启的事务对象"
|
||||||
|
// @param model any "模型对象"
|
||||||
|
// @return error "错误信息"
|
||||||
|
func CreateSortBefore(tx *gorm.DB, tableName string, sort int, param string) (err error) {
|
||||||
|
// 查询是否包含 id_del 字段
|
||||||
|
hasDeletedAt := checkHasDeletedAt(tx, tableName)
|
||||||
|
|
||||||
|
// 处理排序,如果没有传,就会是在最前面
|
||||||
|
sel := tx.Table(tableName).Where("sort >= ?", sort)
|
||||||
|
if hasDeletedAt {
|
||||||
|
sel.Where("id_del = 0")
|
||||||
|
}
|
||||||
|
if param != "" {
|
||||||
|
sel.Where(param)
|
||||||
|
}
|
||||||
|
err = sel.Update("sort", gorm.Expr("sort + 1")).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("处理前置排序失败:%v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DealSortAfter
|
||||||
|
// @description 处理序号之后
|
||||||
|
// @param tx *gorm.DB "已开启的事务对象"
|
||||||
|
// @param modelName string "表名"
|
||||||
|
// @return error "错误信息"
|
||||||
|
func DealSortAfter(tx *gorm.DB, modelName, param string) (err error) {
|
||||||
|
// 保存成功,刷新排序
|
||||||
|
if param != "" {
|
||||||
|
param = " AND " + param
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否包含 id_del 字段
|
||||||
|
hasDeletedAt := checkHasDeletedAt(tx, modelName)
|
||||||
|
if hasDeletedAt {
|
||||||
|
param += " AND id_del = 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有更新时间字段,也更新一下值
|
||||||
|
updateParam := ""
|
||||||
|
if checkHasUpdatedAt(tx, modelName) {
|
||||||
|
updateParam = ",updated_at = NOW()"
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("UPDATE %s a, (SELECT (@i := @i + 1) i, id FROM %s WHERE 1=1 %s order by sort ASC) i, "+
|
||||||
|
"(SELECT @i := 0) ir SET a.sort = i.i %s WHERE a.id = i.id", modelName, modelName, param, updateParam)
|
||||||
|
err = tx.Exec(sql).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("刷新排序失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
16
model/param/menu/save.go
Normal file
16
model/param/menu/save.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package menu
|
||||||
|
|
||||||
|
import "wechat-robot/pkg/types"
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @description: 保存菜单入参
|
||||||
|
type Save struct {
|
||||||
|
Id string `json:"id" form:"id" comment:"菜单Id"`
|
||||||
|
Type types.MenuType `json:"type" form:"type" comment:"菜单类型(菜单或按钮)" validate:"oneof=MENU BUTTON"`
|
||||||
|
Name string `json:"name" form:"name" comment:"页面组件名称"`
|
||||||
|
Path string `json:"path" form:"path" comment:"访问路径"`
|
||||||
|
Title string `json:"title" form:"title" comment:"菜单标题"`
|
||||||
|
Icon string `json:"icon" form:"icon" comment:"菜单图标"`
|
||||||
|
Sort int `json:"sort" form:"sort" comment:"排序值(数字越小越靠前)"`
|
||||||
|
ParentId string `json:"parentId" form:"parentId" comment:"父级菜单ID"`
|
||||||
|
}
|
@ -9,5 +9,6 @@ import (
|
|||||||
// @description: 菜单相关
|
// @description: 菜单相关
|
||||||
// @param g
|
// @param g
|
||||||
func menu(g *gin.RouterGroup) {
|
func menu(g *gin.RouterGroup) {
|
||||||
g.GET("/self", menuApi.GetUserMenuTree)
|
g.GET("/self", menuApi.GetUserMenuTree) // 获取当前用户菜单
|
||||||
|
g.POST("", menuApi.Save) // 保存菜单
|
||||||
}
|
}
|
||||||
|
77
service/menu/save.go
Normal file
77
service/menu/save.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package menu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"wechat-robot/internal/database"
|
||||||
|
"wechat-robot/internal/orm"
|
||||||
|
"wechat-robot/model/entity"
|
||||||
|
menuParam "wechat-robot/model/param/menu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save
|
||||||
|
// @description: 保存菜单
|
||||||
|
// @param param menuParam.Save 菜单数据
|
||||||
|
// @return err error 错误信息
|
||||||
|
func Save(param menuParam.Save) (err error) {
|
||||||
|
tx := database.Client.Begin()
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 提前梳理出参数
|
||||||
|
paramSql := "parent_id IS NULL"
|
||||||
|
if param.ParentId != "" {
|
||||||
|
paramSql = fmt.Sprintf("parent_id = '%s'", param.ParentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if param.Id == "" {
|
||||||
|
// 新增
|
||||||
|
var m entity.Menu
|
||||||
|
// 预处理排序
|
||||||
|
if err = orm.CreateSortBefore(tx, m.TableName(), param.Sort, paramSql); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 组装参数
|
||||||
|
m.Type = param.Type
|
||||||
|
m.Name = param.Name
|
||||||
|
m.Path = param.Path
|
||||||
|
m.Title = param.Title
|
||||||
|
m.Icon = param.Icon
|
||||||
|
m.Sort = param.Sort
|
||||||
|
if param.ParentId != "" {
|
||||||
|
m.ParentId = ¶m.ParentId
|
||||||
|
}
|
||||||
|
err = tx.Create(&m).Error
|
||||||
|
} else {
|
||||||
|
// 修改
|
||||||
|
// 预处理排序
|
||||||
|
if err = orm.UpdateSortBefore(tx, entity.Menu{}.TableName(), param.Id, param.Sort, paramSql); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 组装参数
|
||||||
|
var m = make(map[string]any)
|
||||||
|
m["type"] = param.Type
|
||||||
|
m["name"] = param.Name
|
||||||
|
m["path"] = param.Path
|
||||||
|
m["title"] = param.Title
|
||||||
|
m["icon"] = param.Icon
|
||||||
|
m["sort"] = param.Sort
|
||||||
|
if param.ParentId != "" {
|
||||||
|
m["parent_id"] = ¶m.ParentId
|
||||||
|
}
|
||||||
|
err = tx.Model(&entity.Menu{}).Where("id = ?", param.Id).Updates(m).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理排序
|
||||||
|
err = orm.DealSortAfter(tx, entity.Menu{}.TableName(), paramSql)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user