新增保存菜单接口

This commit is contained in:
李寻欢 2024-02-02 11:44:11 +08:00
parent 13b121be3c
commit 1d1ca21815
5 changed files with 267 additions and 1 deletions

24
api/admin/menu/save.go Normal file
View 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
View 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
View 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"`
}

View File

@ -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
View 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 = &param.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"] = &param.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
}