This commit is contained in:
Wyle.Gong-巩文昕
2025-04-22 16:42:48 +08:00
commit 67b0ad2723
95 changed files with 10508 additions and 0 deletions
+356
View File
@@ -0,0 +1,356 @@
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(&params); 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
}
+14
View File
@@ -0,0 +1,14 @@
//
// init.go
// Copyright (C) 2025 veypi <i@veypi.com>
// 2025-02-27
// Distributed under terms of the MIT license.
//
package tree
import (
"github.com/veypi/OneBD/rest"
)
var Router = rest.NewRouter()