testFlow/api/tree/handler.go
Wyle.Gong-巩文昕 67b0ad2723 init
2025-04-22 16:42:48 +08:00

357 lines
8.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}