357 lines
8.3 KiB
Go
357 lines
8.3 KiB
Go
package tree
|
||
|
||
import (
|
||
"app/cfg"
|
||
"app/models"
|
||
"app/utils"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
|
||
"github.com/google/uuid"
|
||
"github.com/veypi/OneBD/rest"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
var _ = Router.Get("/:id/descendants", getDescendantsHandle)
|
||
var _ = Router.Get("/:id/:min_level/", getHandle)
|
||
var _ = Router.Get("/:id/", getHandle)
|
||
var _ = Router.Get("", getHandle)
|
||
|
||
// 获取树节点
|
||
func getHandle(x *rest.X) (any, error) {
|
||
utils.SetCORSHeaders(x)
|
||
id, ok := x.Params.Get("id")
|
||
minLevel, hasMinLevel := x.Params.Get("min_level")
|
||
|
||
if !ok || id == "-1" {
|
||
fmt.Print("id is not ok")
|
||
// 获取所有根节点
|
||
var trees []models.Tree
|
||
query := cfg.DB()
|
||
|
||
// 如果指定了最小级别,添加筛选条件
|
||
if hasMinLevel {
|
||
minLevelInt := 0
|
||
fmt.Sscanf(minLevel, "%d", &minLevelInt)
|
||
query = query.Where("level >= ?", minLevelInt)
|
||
}
|
||
|
||
if err := query.Find(&trees).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
return trees, nil
|
||
}
|
||
|
||
// 获取特定节点及其子节点
|
||
var tree models.Tree
|
||
if err := cfg.DB().Where("id = ?", id).First(&tree).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
children, _ := tree.Children(cfg.DB())
|
||
var res = map[string]interface{}{
|
||
"node": tree,
|
||
"children": children,
|
||
}
|
||
|
||
return res, nil
|
||
}
|
||
func getDescendantsHandle(x *rest.X) (any, error) {
|
||
utils.SetCORSHeaders(x)
|
||
id, ok := x.Params.Get("id")
|
||
if !ok {
|
||
return nil, errors.New("缺少id")
|
||
}
|
||
|
||
// 获取特定节点
|
||
var tree models.Tree
|
||
if err := cfg.DB().Where("id = ?", id).First(&tree).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 获取所有子孙节点
|
||
descendants, err := tree.Descendants(cfg.DB())
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"node": tree,
|
||
"descendants": descendants,
|
||
}, nil
|
||
}
|
||
|
||
var _ = Router.Post("", postHandle)
|
||
|
||
// 创建树节点
|
||
func postHandle(x *rest.X) (any, error) {
|
||
fmt.Print("postHandle")
|
||
utils.SetCORSHeaders(x)
|
||
tree := &models.Tree{}
|
||
if err := json.NewDecoder(x.Request.Body).Decode(&tree); err != nil {
|
||
return nil, err
|
||
}
|
||
tree.ID = uuid.New().String()[0:32]
|
||
// 设置级别
|
||
if tree.ParentID == "-1" || tree.ParentID == "" {
|
||
tree.Level = 0
|
||
} else {
|
||
var parent models.Tree
|
||
if err := cfg.DB().Where("id = ?", tree.ParentID).First(&parent).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
tree.Level = parent.Level + 1
|
||
}
|
||
|
||
if err := cfg.DB().Create(&tree).Error; err != nil {
|
||
fmt.Println(err)
|
||
return nil, err
|
||
}
|
||
fmt.Println(tree)
|
||
return tree, nil
|
||
}
|
||
|
||
var _ = Router.Patch("/:id/", patchHandle)
|
||
|
||
// 更新树节点
|
||
func patchHandle(x *rest.X) (any, error) {
|
||
utils.SetCORSHeaders(x)
|
||
// 从URL获取ID
|
||
body, err := io.ReadAll(x.Request.Body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("读取请求体失败: %v", err)
|
||
}
|
||
fmt.Printf("收到的请求体内容: %s\n", string(body))
|
||
|
||
id, ok := x.Params.Get("id")
|
||
if !ok {
|
||
return nil, errors.New("缺少id")
|
||
}
|
||
var updateMap map[string]interface{}
|
||
if err := json.Unmarshal(body, &updateMap); err != nil {
|
||
return nil, fmt.Errorf("解析JSON失败: %v", err)
|
||
}
|
||
// 先检查节点是否存在
|
||
var tree models.Tree
|
||
if err := cfg.DB().Where("id = ?", id).First(&tree).Error; err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return nil, errors.New("节点不存在")
|
||
}
|
||
return nil, err
|
||
}
|
||
|
||
// 解析请求数据
|
||
|
||
// if err := x.Parse(&updateMap); err != nil { // 使用 x.Parse 替代 json.NewDecoder
|
||
// return nil, err
|
||
// }
|
||
|
||
// 如果更新包含parent_id,需要特殊处理层级
|
||
if parentID, ok := updateMap["parent_id"]; ok {
|
||
newParentID, ok := parentID.(string)
|
||
if !ok {
|
||
return nil, errors.New("parent_id 必须是字符串类型")
|
||
}
|
||
|
||
// 检查是否形成循环引用
|
||
if newParentID == tree.ID {
|
||
return nil, errors.New("不能将节点的父节点设置为自身")
|
||
}
|
||
|
||
if newParentID != tree.ParentID {
|
||
var newLevel int
|
||
// 检查新的父节点是否存在(除非是设置为根节点)
|
||
if newParentID != "-1" && newParentID != "" {
|
||
var parent models.Tree
|
||
if err := cfg.DB().Where("id = ?", newParentID).First(&parent).Error; err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return nil, errors.New("父节点不存在")
|
||
}
|
||
return nil, err
|
||
}
|
||
|
||
// 检查新父节点是否是当前节点的子节点
|
||
children, err := tree.Children(cfg.DB())
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for _, child := range children {
|
||
if child.ID == newParentID {
|
||
return nil, errors.New("不能将子节点设置为父节点")
|
||
}
|
||
}
|
||
|
||
newLevel = parent.Level + 1
|
||
} else {
|
||
newLevel = 0
|
||
}
|
||
|
||
// 开始事务
|
||
tx := cfg.DB().Begin()
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
tx.Rollback()
|
||
}
|
||
}()
|
||
|
||
// 更新当前节点的 parent_id 和 level
|
||
if err := tx.Model(&models.Tree{}).Where("id = ?", tree.ID).Updates(map[string]interface{}{
|
||
"parent_id": newParentID,
|
||
"level": newLevel,
|
||
}).Error; err != nil {
|
||
tx.Rollback()
|
||
return nil, err
|
||
}
|
||
if err := updateChildrenLevels(tx, tree.ID, newLevel); err != nil {
|
||
tx.Rollback()
|
||
return nil, err
|
||
}
|
||
|
||
if err := tx.Commit().Error; err != nil {
|
||
return nil, err
|
||
}
|
||
// 递归更新所有子节点的 level
|
||
// if err := tx.Exec(`UPDATE trees,
|
||
// (WITH RECURSIVE tree_paths AS (
|
||
// SELECT id, parent_id, 0 as depth
|
||
// FROM trees WHERE id = ?
|
||
// UNION ALL
|
||
// SELECT t.id, t.parent_id, tp.depth + 1
|
||
// FROM trees t
|
||
// JOIN tree_paths tp ON t.parent_id = tp.id
|
||
// )
|
||
// SELECT id, depth FROM tree_paths WHERE id != ?) as paths
|
||
// SET trees.level = ? + paths.depth
|
||
// WHERE trees.id = paths.id`, tree.ID, tree.ID, newLevel).Error; err != nil {
|
||
// tx.Rollback()
|
||
// return nil, err
|
||
// }
|
||
|
||
// if err := tx.Commit().Error; err != nil {
|
||
// return nil, err
|
||
// }
|
||
}
|
||
}
|
||
|
||
// 删除不允许更新的字段
|
||
delete(updateMap, "id")
|
||
delete(updateMap, "level") // level 不允许直接更新
|
||
|
||
// 只更新提供的字段
|
||
if len(updateMap) > 0 {
|
||
if err := cfg.DB().Model(&tree).Updates(updateMap).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 重新查询更新后的完整数据
|
||
if err := cfg.DB().Where("id = ?", id).First(&tree).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return tree, nil
|
||
}
|
||
|
||
var _ = Router.Delete("/:id/", deleteHandle)
|
||
|
||
// 删除树节点
|
||
func deleteHandle(x *rest.X) (any, error) {
|
||
// 从路径中获取ID
|
||
utils.SetCORSHeaders(x)
|
||
id, ok := x.Params.Get("id")
|
||
if !ok {
|
||
return nil, errors.New("缺少id")
|
||
}
|
||
|
||
// 从body中获取cascade参数
|
||
var params struct {
|
||
Cascade bool `json:"cascade"`
|
||
}
|
||
if err := x.Parse(¶ms); err != nil {
|
||
params.Cascade = false // 默认不级联删除
|
||
}
|
||
|
||
var tree models.Tree
|
||
if err := cfg.DB().Where("id = ?", id).First(&tree).Error; err != nil {
|
||
|
||
return nil, err
|
||
}
|
||
|
||
tx := cfg.DB().Begin()
|
||
|
||
if params.Cascade {
|
||
// 级联删除
|
||
if err := tx.Where(
|
||
"id = ? OR parent_id = ? OR parent_id IN (SELECT id FROM trees WHERE level > ?)",
|
||
tree.ID, tree.ID, tree.Level,
|
||
).Delete(&models.Tree{}).Error; err != nil {
|
||
tx.Rollback()
|
||
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 非级联删除,子节点提升
|
||
if err := tx.Model(&models.Tree{}).Where("parent_id = ?", tree.ID).Update(
|
||
"parent_id", tree.ParentID,
|
||
).Error; err != nil {
|
||
tx.Rollback()
|
||
|
||
return nil, err
|
||
}
|
||
|
||
// 删除当前节点
|
||
if err := tx.Delete(&tree).Error; err != nil {
|
||
tx.Rollback()
|
||
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
tx.Commit()
|
||
|
||
var res = map[string]interface{}{
|
||
"msg": "删除成功",
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
var _ = Router.Any("/*", anyHandle)
|
||
|
||
func anyHandle(x *rest.X) (any, error) {
|
||
utils.SetCORSHeaders(x)
|
||
fmt.Print("anyHandle")
|
||
return nil, nil
|
||
}
|
||
func updateChildrenLevels(tx *gorm.DB, parentID string, parentLevel int) error {
|
||
// 查找直接子节点
|
||
var children []models.Tree
|
||
if err := tx.Where("parent_id = ?", parentID).Find(&children).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
// 没有子节点,直接返回
|
||
if len(children) == 0 {
|
||
return nil
|
||
}
|
||
|
||
// 更新每个直接子节点的层级
|
||
for _, child := range children {
|
||
// 计算新的层级
|
||
newLevel := parentLevel + 1
|
||
|
||
// 更新当前子节点的层级
|
||
if err := tx.Model(&models.Tree{}).Where("id = ?", child.ID).Update("level", newLevel).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
// 递归更新该子节点的所有子节点
|
||
if err := updateChildrenLevels(tx, child.ID, newLevel); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|