package graph_node 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/", getHandle) //TODO第一个命名生效 var _ = Router.Get("", getHandle) func getHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) stageID, ok := x.Params.Get("id") if !ok { return nil, errors.New("缺少stage_id") } var nodes []models.GraphNode if err := cfg.DB().Where("stage_id = ?", stageID).Find(&nodes).Error; err != nil { return nil, err } return nodes, nil } // 获取单个节点详情 func getOneHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) id, ok := x.Params.Get("id") if !ok { return nil, errors.New("缺少id") } var node models.GraphNode if err := cfg.DB().Where("id = ?", id).First(&node).Error; err != nil { return nil, err } tree, _ := node.Tree(cfg.DB()) links, _ := node.Links(cfg.DB()) return map[string]interface{}{ "node": node, "tree": tree, "links": links, }, nil } var _ = Router.Post("", postHandle) // 创建图形节点 func postHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) node := &models.GraphNode{} if err := json.NewDecoder(x.Request.Body).Decode(&node); err != nil { return nil, err } node.ID = uuid.New().String()[0:32] // 验证树节点是否存在 var tree models.Tree if err := cfg.DB().Where("id = ?", node.TreeID).First(&tree).Error; err != nil { return nil, errors.New("树节点不存在") } // 验证阶段是否存在 var stage models.Stage if err := cfg.DB().Where("id = ?", node.StageID).First(&stage).Error; err != nil { return nil, errors.New("阶段不存在") } // 验证树节点是否是阶段指定树节点的子孙节点 if stage.TreeID != "" && stage.TreeID != "root" { var stageTree models.Tree if err := cfg.DB().Where("id = ?", stage.TreeID).First(&stageTree).Error; err != nil { return nil, errors.New("阶段指定的树节点不存在") } // 获取阶段树节点的所有子孙节点 descendants, err := stageTree.Descendants(cfg.DB()) if err != nil { return nil, err } // 检查当前树节点是否是阶段树节点或其子孙节点 isValid := tree.ID == stageTree.ID for _, d := range descendants { if tree.ID == d.ID { isValid = true break } } if !isValid { return nil, errors.New("树节点不满足阶段要求") } } if err := cfg.DB().Create(&node).Error; err != nil { return nil, err } return node, 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) } 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 node models.GraphNode if err := cfg.DB().Where("id = ?", id).First(&node).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("节点不存在") } return nil, err } // 如果更新包含tree_id,需要验证树节点是否存在和是否符合阶段要求 if treeID, ok := updateMap["tree_id"]; ok { newTreeID, ok := treeID.(string) if !ok { return nil, errors.New("tree_id 必须是字符串类型") } var tree models.Tree if err := cfg.DB().Where("id = ?", newTreeID).First(&tree).Error; err != nil { return nil, errors.New("树节点不存在") } var stage models.Stage if err := cfg.DB().Where("id = ?", node.StageID).First(&stage).Error; err != nil { return nil, errors.New("阶段不存在") } // 验证树节点是否是阶段指定树节点的子孙节点 if stage.TreeID != "" && stage.TreeID != "root" { var stageTree models.Tree if err := cfg.DB().Where("id = ?", stage.TreeID).First(&stageTree).Error; err != nil { return nil, errors.New("阶段指定的树节点不存在") } // 获取阶段树节点的所有子孙节点 descendants, err := stageTree.Descendants(cfg.DB()) if err != nil { return nil, err } // 检查当前树节点是否是阶段树节点或其子孙节点 isValid := tree.ID == stageTree.ID for _, d := range descendants { if tree.ID == d.ID { isValid = true break } } if !isValid { return nil, errors.New("树节点不满足阶段要求") } } } // 删除不允许更新的字段 delete(updateMap, "id") // 只更新提供的字段 if len(updateMap) > 0 { if err := cfg.DB().Model(&node).Updates(updateMap).Error; err != nil { return nil, err } } // 重新查询更新后的完整数据 if err := cfg.DB().Where("id = ?", id).First(&node).Error; err != nil { return nil, err } return node, nil } var _ = Router.Delete("/:id/", deleteHandle) // 删除图形节点 func deleteHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) id, ok := x.Params.Get("id") if !ok { return nil, errors.New("缺少id") } var node models.GraphNode if err := cfg.DB().Where("id = ?", id).First(&node).Error; err != nil { return nil, err } // 开始事务 tx := cfg.DB().Begin() // 删除与该节点关联的所有连接 if err := tx.Where("prev_id = ? OR next_id = ?", id, id).Delete(&models.GraphLink{}).Error; err != nil { tx.Rollback() return nil, err } // 删除节点 if err := tx.Delete(&node).Error; err != nil { tx.Rollback() return nil, err } tx.Commit() return map[string]interface{}{ "msg": "删除成功", }, nil } var _ = Router.Any("/*", anyHandle) func anyHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) return nil, nil }