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 }