package graph_link 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 links []models.GraphLink if err := cfg.DB().Where("stage_id = ?", stageID).Find(&links).Error; err != nil { return nil, err } return links, 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 link models.GraphLink if err := cfg.DB().Where("id = ?", id).First(&link).Error; err != nil { return nil, err } sourceNode, _ := link.SourceNode(cfg.DB()) targetNode, _ := link.TargetNode(cfg.DB()) return map[string]interface{}{ "link": link, "source_node": sourceNode, "target_node": targetNode, }, nil } var _ = Router.Post("", postHandle) // 创建图形连接 func postHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) link := &models.GraphLink{} if err := json.NewDecoder(x.Request.Body).Decode(&link); err != nil { return nil, err } link.ID = uuid.New().String()[0:32] // 如果没有提供LinkID,则生成一个 if link.LinkID == "" { link.LinkID = fmt.Sprintf("%s-%s", link.SourceID, link.TargetID) } // 验证源节点是否存在 var sourceNode models.GraphNode if err := cfg.DB().Where("instance_id = ?", link.SourceID).First(&sourceNode).Error; err != nil { return nil, errors.New("源节点不存在") } // 验证目标节点是否存在 var targetNode models.GraphNode if err := cfg.DB().Where("instance_id = ?", link.TargetID).First(&targetNode).Error; err != nil { return nil, errors.New("目标节点不存在") } // 验证两个节点是否在同一个阶段 if sourceNode.StageID != targetNode.StageID { return nil, errors.New("源节点和目标节点必须在同一个阶段") } // 设置阶段ID link.StageID = sourceNode.StageID // 验证是否已存在相同的连接 var count int64 if err := cfg.DB().Model(&models.GraphLink{}).Where("source_id = ? AND target_id = ?", link.SourceID, link.TargetID).Count(&count).Error; err != nil { return nil, err } if count > 0 { return nil, errors.New("已存在相同的连接") } if err := cfg.DB().Create(&link).Error; err != nil { return nil, err } return link, 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 link models.GraphLink if err := cfg.DB().Where("id = ?", id).First(&link).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("连接不存在") } return nil, err } // 如果更新包含source_id或target_id,需要验证节点是否存在和是否在同一阶段 sourceID, hasSourceID := updateMap["source_id"] targetID, hasTargetID := updateMap["target_id"] if hasSourceID || hasTargetID { newSourceID := link.SourceID newTargetID := link.TargetID if hasSourceID { var ok bool newSourceID, ok = sourceID.(string) if !ok { return nil, errors.New("source_id 必须是字符串类型") } } if hasTargetID { var ok bool newTargetID, ok = targetID.(string) if !ok { return nil, errors.New("target_id 必须是字符串类型") } } // 验证源节点是否存在 var sourceNode models.GraphNode if err := cfg.DB().Where("instance_id = ?", newSourceID).First(&sourceNode).Error; err != nil { return nil, errors.New("源节点不存在") } // 验证目标节点是否存在 var targetNode models.GraphNode if err := cfg.DB().Where("instance_id = ?", newTargetID).First(&targetNode).Error; err != nil { return nil, errors.New("目标节点不存在") } // 验证两个节点是否在同一个阶段 if sourceNode.StageID != targetNode.StageID { return nil, errors.New("源节点和目标节点必须在同一个阶段") } // 验证是否已存在相同的连接 var count int64 if err := cfg.DB().Model(&models.GraphLink{}).Where("id != ? AND source_id = ? AND target_id = ?", id, newSourceID, newTargetID).Count(&count).Error; err != nil { return nil, err } if count > 0 { return nil, errors.New("已存在相同的连接") } // 更新阶段ID updateMap["stage_id"] = sourceNode.StageID // 更新LinkID updateMap["link_id"] = fmt.Sprintf("%s-%s", newSourceID, newTargetID) } // 删除不允许更新的字段 delete(updateMap, "id") // 只更新提供的字段 if len(updateMap) > 0 { if err := cfg.DB().Model(&link).Updates(updateMap).Error; err != nil { return nil, err } } // 重新查询更新后的完整数据 if err := cfg.DB().Where("id = ?", id).First(&link).Error; err != nil { return nil, err } return link, 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 link models.GraphLink if err := cfg.DB().Where("id = ?", id).First(&link).Error; err != nil { return nil, err } // 删除连接 if err := cfg.DB().Delete(&link).Error; err != nil { return nil, err } return map[string]interface{}{ "msg": "删除成功", }, nil } var _ = Router.Any("/*", anyHandle) func anyHandle(x *rest.X) (any, error) { utils.SetCORSHeaders(x) return nil, nil }