init
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package graph_node
|
||||
|
||||
import (
|
||||
"github.com/veypi/OneBD/rest"
|
||||
)
|
||||
|
||||
var Router = rest.NewRouter()
|
||||
Reference in New Issue
Block a user