wcc před 3 měsíci
rodič
revize
4ab0dad356
7 změnil soubory, kde provedl 159 přidání a 25 odebrání
  1. 1 0
      graph/go.mod
  2. 2 0
      graph/go.sum
  3. 4 4
      graph/graph_test.go
  4. 32 18
      graph/init.go
  5. 9 1
      graph/main.go
  6. 97 0
      graph/templates/graph.html
  7. 14 2
      graph/utils.go

+ 1 - 0
graph/go.mod

@@ -19,6 +19,7 @@ require (
 	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/gin-gonic/gin v1.10.0 // indirect
+	github.com/go-echarts/go-echarts/v2 v2.5.3 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.20.0 // indirect

+ 2 - 0
graph/go.sum

@@ -36,6 +36,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
 github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-echarts/go-echarts/v2 v2.5.3 h1:5SFAA6bAIWz52VnVGlCM1UZXo8nSdN+H9E8Ysi4m5ec=
+github.com/go-echarts/go-echarts/v2 v2.5.3/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=

+ 4 - 4
graph/graph_test.go

@@ -31,10 +31,10 @@ func TestCheckLegalRelationships(t *testing.T) {
 		log.Fatal("连接失败:", err)
 	}
 	defer client.Close()
-	names := []string{"华芳创业投资有限公司", "北京剑鱼信息技术有限公司", "河南折扣牛哟有限公司", "上海元藩投资有限公司"}
-
-	has, res, err := client.CheckLegalRelationships(names, 3, 0)
-	log.Println(has, res, err)
+	//names := []string{"北京剑鱼信息技术有限公司", "河南拓普计算机网络工程有限公司", "上海元藩投资有限公司"}
+	names := []string{"万达集团股份有限公司", "万达石化有限公司", "山东万达电缆有限公司", "山东万达化工有限公司", "山东万达热电有限公司", "山东万达进出口有限公司", "山东耐斯特炭黑有限公司", "山东万达宝通轮胎有限公司", "山东明宇化学有限公司", "大连万达集团股份有限公司", "大连万达(上海)金融集团有限公司", "大连万达集团咨询服务有限公司", "北京万达足球俱乐部有限公司", "北京红舸科技文化有限公司", "北京万达文化产业集团有限公司"}
+	has, result, err := client.CheckLegalRelationships(names, 4, 1)
+	log.Println(has, result, err)
 }
 
 func TestFetchLegalByVid(t *testing.T) {

+ 32 - 18
graph/init.go

@@ -7,6 +7,7 @@ import (
 	"log"
 	"strings"
 	"sync"
+	"time"
 )
 
 func InitMgo() {
@@ -33,24 +34,27 @@ type NebulaClient struct {
 	mu      sync.Mutex
 }
 
-// NewNebulaClient 初始化客户端-NebulaGraph
+// NewNebulaClient 初始化 NebulaGraph 客户端
 func NewNebulaClient(hosts []nebula.HostAddress, username, password string) (*NebulaClient, error) {
 	client := &NebulaClient{
 		hosts:    hosts,
 		username: username,
 		password: password,
 	}
-	err := client.connect()
-	if err != nil {
+	if err := client.connect(); err != nil {
 		return nil, err
 	}
 	return client, nil
 }
 
+// connect 建立连接
 func (c *NebulaClient) connect() error {
 	config := nebula.GetDefaultConf()
-	config.UseHTTP2 = false
-	config.HandshakeKey = ""
+	config.TimeOut = time.Minute * 10 // 连接超时
+	config.IdleTime = time.Minute * 5 // 空闲 session 存活时间
+	config.MaxConnPoolSize = 10       // 最大连接池大小
+	config.UseHTTP2 = false           // 禁用 HTTP2(如需要)
+	config.HandshakeKey = ""          // 默认密钥
 
 	pool, err := nebula.NewConnectionPool(c.hosts, config, nebula.DefaultLogger{})
 	if err != nil {
@@ -68,53 +72,63 @@ func (c *NebulaClient) connect() error {
 	return nil
 }
 
-// 自动重连逻辑:当返回错误里包含 session 不存在时触发重连
+// ExecuteWithReconnect 执行查询,检测 session 异常自动重连
 func (c *NebulaClient) ExecuteWithReconnect(query string) (*nebula.ResultSet, error) {
 	c.mu.Lock()
 	defer c.mu.Unlock()
 
-	// 如果 session 为 nil,则重新连接
+	// session 为 nil 时尝试重新连接
 	if c.session == nil {
-		log.Println("session 为 nil,重连中...")
+		log.Println("session 为 nil,尝试连接...")
 		if err := c.connect(); err != nil {
 			return nil, err
 		}
 	}
 
+	// 执行查询
 	resp, err := c.session.Execute(query)
-	if err != nil || !resp.IsSucceed() {
-		// 检查是否是 session 已失效
-		if strings.Contains(resp.GetErrorMsg(), "Session") ||
-			(err != nil && strings.Contains(err.Error(), "Session")) {
+	if err != nil || resp == nil || !resp.IsSucceed() {
+		errMsg := ""
+		if err != nil {
+			errMsg = err.Error()
+		}
+		if resp != nil {
+			errMsg = resp.GetErrorMsg()
+		}
 
-			log.Println("session 可能失效,正在重连...")
+		if strings.Contains(errMsg, "Session") {
+			log.Println("Session 异常,尝试重连...")
 			if c.pool != nil {
 				c.pool.Close()
 			}
 			if err := c.connect(); err != nil {
 				return nil, fmt.Errorf("重连失败: %w", err)
 			}
-			// 重试一次查询
+			// 重试一次
 			resp, err = c.session.Execute(query)
 			if err != nil {
-				return nil, err
+				return nil, fmt.Errorf("重连后执行失败: %w", err)
 			}
-			if !resp.IsSucceed() {
+			if resp == nil || !resp.IsSucceed() {
 				return nil, fmt.Errorf("重连后查询失败: %s", resp.GetErrorMsg())
 			}
-		} else {
-			return nil, fmt.Errorf("查询失败: %s", resp.GetErrorMsg())
+			return resp, nil
 		}
+
+		return nil, fmt.Errorf("查询失败: %s", errMsg)
 	}
 
 	return resp, nil
 }
 
+// Close 释放资源
 func (c *NebulaClient) Close() {
 	if c.session != nil {
 		c.session.Release()
+		c.session = nil
 	}
 	if c.pool != nil {
 		c.pool.Close()
+		c.pool = nil
 	}
 }

+ 9 - 1
graph/main.go

@@ -158,12 +158,19 @@ func main() {
 	//3、改造方法,使用连接池,避免session过去//
 	// 初始化 Gin 路由
 	r := gin.Default()
+	// 加载模板文件(你可以自定义路径)
+	r.LoadHTMLGlob("templates/*")
+
 	client, err := NewNebulaClient(HostList, UserName, PassWord)
 	if err != nil {
 		log.Fatal("连接失败:", err)
 	}
 	defer client.Close()
 	// 注册 POST 接口
+	// 提供 HTML 页面
+	r.GET("/legal/graph", func(c *gin.Context) {
+		c.HTML(http.StatusOK, "graph.html", nil)
+	})
 	r.POST("/check-relations", func(c *gin.Context) {
 		var req CheckRequest
 		if err := c.ShouldBindJSON(&req); err != nil {
@@ -176,7 +183,7 @@ func main() {
 			res := CheckResponse{
 				Code: -1,
 				Data: results,
-				Msg:  "请求失败",
+				Msg:  "请求失败;" + err.Error(),
 			}
 			c.JSON(http.StatusInternalServerError, res)
 			return
@@ -198,6 +205,7 @@ func main() {
 	r.Run(":8080")
 }
 
+// dda 针对某个企业,单独生节点数据
 func dda() {
 	name := "北京拓普丰联信息科技股份有限公司"
 	rea, resb := GetInvByLevel(name, 5, 0, false)

+ 97 - 0
graph/templates/graph.html

@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>ECharts 关系图示例</title>
+    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
+</head>
+<body>
+<div id="main" style="width: 1200px; height: 800px;"></div>
+<script type="text/javascript">
+    var myChart = echarts.init(document.getElementById('main'));
+
+    var option = {
+        title: {
+            text: '投资关系图'
+        },
+        tooltip: {},
+        animationDurationUpdate: 1500,
+        animationEasingUpdate: 'quinticInOut',
+        series: [
+            {
+                type: 'graph',
+                layout: 'none',
+                symbolSize: 50,
+                roam: true,
+                label: {
+                    show: true
+                },
+                edgeSymbol: ['circle', 'arrow'],
+                edgeSymbolSize: [4, 10],
+                edgeLabel: {
+                    fontSize: 20
+                },
+                data: [
+                    {
+                        name: '北京剑鱼信息技术有限公司',
+                        x: 300,
+                        y: 300
+                    },
+                    {
+                        name: '北京拓普丰联信息科技股份有限公司',
+                        x: 800,
+                        y: 300
+                    },
+                    {
+                        name: '宁波隆华汇博源创业投资合伙企业(有限合伙)',
+                        x: 550,
+                        y: 100
+                    },
+                    {
+                        name: '上海元藩投资有限公司',
+                        x: 550,
+                        y: 500
+                    }
+                ],
+                links: [
+                    {
+                        source: '上海元藩投资有限公司',
+                        target: '宁波隆华汇博源创业投资合伙企业(有限合伙)',
+                        symbolSize: [5, 20],
+                        label: {
+                            show: true
+                        },
+                        lineStyle: {
+                            width: 5,
+                            curveness: 0.2
+                        }
+                    },
+                    {
+                        source: '宁波隆华汇博源创业投资合伙企业(有限合伙)',
+                        target: '北京拓普丰联信息科技股份有限公司',
+                        label: {
+                            show: true
+                        },
+                        lineStyle: {
+                            curveness: 0.2
+                        }
+                    },
+                    {
+                        source: '北京拓普丰联信息科技股份有限公司',
+                        target: '北京剑鱼信息技术有限公司'
+                    }
+                ],
+                lineStyle: {
+                    opacity: 0.9,
+                    width: 2,
+                    curveness: 0
+                }
+            }
+        ]
+    };
+
+    myChart.setOption(option);
+</script>
+</body>
+</html>

+ 14 - 2
graph/utils.go

@@ -864,7 +864,10 @@ RETURN p LIMIT 1
 					if err != nil {
 						log.Println("getVidByName err", err, vid)
 					}
-					pathNames = append(pathNames, lea.Name)
+					if lea != nil && lea.Name != "" {
+						pathNames = append(pathNames, lea.Name)
+					}
+					//pathNames = append(pathNames, lea.Name)
 				}
 
 				// 解析带方向的路径
@@ -876,7 +879,9 @@ RETURN p LIMIT 1
 						if err != nil {
 							log.Println("getVidByName err", err, vid)
 						}
-						pathNames = append(pathNames, lea.Name)
+						if lea != nil && lea.Name != "" {
+							pathNames = append(pathNames, lea.Name)
+						}
 					}
 				}
 
@@ -1086,6 +1091,10 @@ RETURN p LIMIT 1
 		if err != nil {
 			return false, nil, fmt.Errorf("查询失败: %w", err)
 		}
+
+		if resp == nil {
+			return false, nil, fmt.Errorf("查询失败,response is nil")
+		}
 		if !resp.IsSucceed() {
 			return false, nil, fmt.Errorf("执行失败: %s", resp.GetErrorMsg())
 		}
@@ -1182,3 +1191,6 @@ RETURN p LIMIT 1
 	}
 	return false, nil, nil
 }
+
+// ---//
+// 1. 数据结构定义