237 lines
5.9 KiB
Go
237 lines
5.9 KiB
Go
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
|
||
}
|