2024-11-22 16:41:04 +08:00
|
|
|
|
// Package database define database operation functions
|
|
|
|
|
|
package database
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
2025-05-13 16:34:25 +08:00
|
|
|
|
"fmt"
|
2024-11-22 16:41:04 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
|
2025-08-05 15:20:07 +08:00
|
|
|
|
"modelRT/constants"
|
2024-11-27 09:11:48 +08:00
|
|
|
|
"modelRT/diagram"
|
2025-06-06 16:41:52 +08:00
|
|
|
|
"modelRT/logger"
|
2024-11-22 16:41:04 +08:00
|
|
|
|
"modelRT/orm"
|
2024-12-03 16:38:17 +08:00
|
|
|
|
"modelRT/sql"
|
2024-11-22 16:41:04 +08:00
|
|
|
|
|
2024-11-27 09:11:48 +08:00
|
|
|
|
"github.com/gofrs/uuid"
|
2025-01-09 15:56:40 +08:00
|
|
|
|
"gorm.io/gorm"
|
2024-11-22 16:41:04 +08:00
|
|
|
|
"gorm.io/gorm/clause"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-05-13 16:34:25 +08:00
|
|
|
|
// QueryTopologic return the topologic info of the circuit diagram
|
2025-06-06 16:41:52 +08:00
|
|
|
|
func QueryTopologic(ctx context.Context, tx *gorm.DB) ([]orm.Topologic, error) {
|
2024-11-22 16:41:04 +08:00
|
|
|
|
var topologics []orm.Topologic
|
|
|
|
|
|
// ctx超时判断
|
|
|
|
|
|
cancelCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
2025-01-09 15:56:40 +08:00
|
|
|
|
|
2025-06-13 15:34:49 +08:00
|
|
|
|
result := tx.WithContext(cancelCtx).Clauses(clause.Locking{Strength: "UPDATE"}).Raw(sql.RecursiveSQL, constants.UUIDNilStr).Scan(&topologics)
|
2024-11-22 16:41:04 +08:00
|
|
|
|
if result.Error != nil {
|
2025-06-13 15:34:49 +08:00
|
|
|
|
logger.Error(ctx, "query circuit diagram topologic info by start node uuid failed", "start_node_uuid", constants.UUIDNilStr, "error", result.Error)
|
2024-11-22 16:41:04 +08:00
|
|
|
|
return nil, result.Error
|
|
|
|
|
|
}
|
|
|
|
|
|
return topologics, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-13 16:34:25 +08:00
|
|
|
|
// QueryTopologicFromDB return the result of query topologic info from DB
|
2025-06-06 16:41:52 +08:00
|
|
|
|
func QueryTopologicFromDB(ctx context.Context, tx *gorm.DB, componentTypeMap map[uuid.UUID]int) (*diagram.MultiBranchTreeNode, error) {
|
|
|
|
|
|
topologicInfos, err := QueryTopologic(ctx, tx)
|
2024-11-27 09:11:48 +08:00
|
|
|
|
if err != nil {
|
2025-06-06 16:41:52 +08:00
|
|
|
|
logger.Error(ctx, "query topologic info failed", "error", err)
|
2025-05-20 16:08:17 +08:00
|
|
|
|
return nil, err
|
2024-11-27 09:11:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-20 16:08:17 +08:00
|
|
|
|
tree, err := BuildMultiBranchTree(topologicInfos, componentTypeMap)
|
2025-05-13 16:34:25 +08:00
|
|
|
|
if err != nil {
|
2025-06-06 16:41:52 +08:00
|
|
|
|
logger.Error(ctx, "init topologic failed", "error", err)
|
2025-05-20 16:08:17 +08:00
|
|
|
|
return nil, err
|
2024-11-27 09:11:48 +08:00
|
|
|
|
}
|
2025-05-20 16:08:17 +08:00
|
|
|
|
return tree, nil
|
2024-11-22 16:41:04 +08:00
|
|
|
|
}
|
2024-12-03 16:38:17 +08:00
|
|
|
|
|
|
|
|
|
|
// InitCircuitDiagramTopologic return circuit diagram topologic info from postgres
|
2025-05-13 16:34:25 +08:00
|
|
|
|
func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic, componentTypeMap map[uuid.UUID]int) error {
|
|
|
|
|
|
var rootVertex *diagram.MultiBranchTreeNode
|
2024-12-03 16:38:17 +08:00
|
|
|
|
for _, node := range topologicNodes {
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if node.UUIDFrom == constants.UUIDNil {
|
2025-05-13 16:34:25 +08:00
|
|
|
|
// rootVertex = node.UUIDTo
|
|
|
|
|
|
var componentType int
|
|
|
|
|
|
componentType, ok := componentTypeMap[node.UUIDFrom]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return fmt.Errorf("can not get component type by uuid: %s", node.UUIDFrom)
|
|
|
|
|
|
}
|
|
|
|
|
|
rootVertex = diagram.NewMultiBranchTree(node.UUIDFrom, componentType)
|
2024-12-03 16:38:17 +08:00
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-13 16:34:25 +08:00
|
|
|
|
if rootVertex == nil {
|
|
|
|
|
|
return fmt.Errorf("root vertex is nil")
|
|
|
|
|
|
}
|
2024-12-03 16:38:17 +08:00
|
|
|
|
|
|
|
|
|
|
for _, node := range topologicNodes {
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if node.UUIDFrom == constants.UUIDNil {
|
2025-05-13 16:34:25 +08:00
|
|
|
|
var componentType int
|
|
|
|
|
|
componentType, ok := componentTypeMap[node.UUIDTo]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return fmt.Errorf("can not get component type by uuid: %s", node.UUIDTo)
|
|
|
|
|
|
}
|
|
|
|
|
|
nodeVertex := diagram.NewMultiBranchTree(node.UUIDTo, componentType)
|
|
|
|
|
|
|
|
|
|
|
|
rootVertex.AddChild(nodeVertex)
|
2024-12-03 16:38:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-13 16:34:25 +08:00
|
|
|
|
|
|
|
|
|
|
node := rootVertex
|
|
|
|
|
|
for _, nodeVertex := range node.Children {
|
|
|
|
|
|
nextVertexs := make([]*diagram.MultiBranchTreeNode, 0)
|
|
|
|
|
|
nextVertexs = append(nextVertexs, nodeVertex)
|
|
|
|
|
|
}
|
2024-12-03 16:38:17 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2025-04-30 16:44:58 +08:00
|
|
|
|
|
2025-05-20 16:08:17 +08:00
|
|
|
|
// TODO 电流互感器不单独划分间隔,以母线、浇筑母线、变压器为间隔原件
|
2025-05-13 16:34:25 +08:00
|
|
|
|
func IntervalBoundaryDetermine(uuid uuid.UUID) bool {
|
2025-05-20 16:08:17 +08:00
|
|
|
|
fmt.Println(uuid)
|
2025-04-30 16:44:58 +08:00
|
|
|
|
var componentID int64
|
|
|
|
|
|
diagram.GetComponentMap(componentID)
|
|
|
|
|
|
// TODO 判断 component 的类型是否为间隔
|
2025-05-20 16:08:17 +08:00
|
|
|
|
// TODO 0xA1B2C3D4,高四位表示可以成为间隔的compoent类型的值为FFFF,普通 component 类型的值为 0000。低四位中前二位表示component的一级类型,例如母线 PT、母联/母分、进线等,低四位中后二位表示一级类型中包含的具体类型,例如母线 PT中包含的电压互感器、隔离开关、接地开关、避雷器、带电显示器等。
|
2025-05-16 14:24:55 +08:00
|
|
|
|
num := uint32(0xA1B2C3D4) // 八位16进制数
|
|
|
|
|
|
high16 := uint16(num >> 16)
|
|
|
|
|
|
fmt.Printf("原始值: 0x%X\n", num) // 输出: 0xA1B2C3D4
|
|
|
|
|
|
fmt.Printf("高十六位: 0x%X\n", high16) // 输出: 0xA1B2
|
2025-04-30 16:44:58 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-05-13 16:34:25 +08:00
|
|
|
|
|
|
|
|
|
|
// BuildMultiBranchTree return the multi branch tree by topologic info and component type map
|
|
|
|
|
|
func BuildMultiBranchTree(topologics []orm.Topologic, componentTypeMap map[uuid.UUID]int) (*diagram.MultiBranchTreeNode, error) {
|
2025-05-20 16:08:17 +08:00
|
|
|
|
nodeMap := make(map[uuid.UUID]*diagram.MultiBranchTreeNode, len(topologics)*2)
|
2025-05-13 16:34:25 +08:00
|
|
|
|
|
|
|
|
|
|
for _, topo := range topologics {
|
2025-05-16 14:24:55 +08:00
|
|
|
|
if _, exists := nodeMap[topo.UUIDFrom]; !exists {
|
2025-05-20 16:08:17 +08:00
|
|
|
|
// skip special uuid
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if topo.UUIDTo != constants.UUIDNil {
|
2025-05-16 14:24:55 +08:00
|
|
|
|
var ok bool
|
2025-05-20 16:08:17 +08:00
|
|
|
|
componentType, ok := componentTypeMap[topo.UUIDFrom]
|
2025-05-13 16:34:25 +08:00
|
|
|
|
if !ok {
|
|
|
|
|
|
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDFrom)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nodeMap[topo.UUIDFrom] = &diagram.MultiBranchTreeNode{
|
|
|
|
|
|
ID: topo.UUIDFrom,
|
|
|
|
|
|
NodeComponentType: componentType,
|
2025-05-20 16:08:17 +08:00
|
|
|
|
Children: make([]*diagram.MultiBranchTreeNode, 0),
|
2025-05-13 16:34:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if _, exists := nodeMap[topo.UUIDTo]; !exists {
|
2025-05-20 16:08:17 +08:00
|
|
|
|
// skip special uuid
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if topo.UUIDTo != constants.UUIDNil {
|
2025-05-16 14:24:55 +08:00
|
|
|
|
var ok bool
|
2025-05-20 16:08:17 +08:00
|
|
|
|
componentType, ok := componentTypeMap[topo.UUIDTo]
|
2025-05-16 14:24:55 +08:00
|
|
|
|
if !ok {
|
|
|
|
|
|
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDTo)
|
|
|
|
|
|
}
|
2025-05-13 16:34:25 +08:00
|
|
|
|
|
2025-05-20 16:08:17 +08:00
|
|
|
|
nodeMap[topo.UUIDTo] = &diagram.MultiBranchTreeNode{
|
|
|
|
|
|
ID: topo.UUIDTo,
|
|
|
|
|
|
NodeComponentType: componentType,
|
|
|
|
|
|
Children: make([]*diagram.MultiBranchTreeNode, 0),
|
|
|
|
|
|
}
|
2025-05-13 16:34:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, topo := range topologics {
|
|
|
|
|
|
var parent *diagram.MultiBranchTreeNode
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if topo.UUIDFrom == constants.UUIDNil {
|
2025-05-16 14:24:55 +08:00
|
|
|
|
var componentType int
|
2025-05-13 16:34:25 +08:00
|
|
|
|
parent = &diagram.MultiBranchTreeNode{
|
2025-06-13 15:34:49 +08:00
|
|
|
|
ID: constants.UUIDNil,
|
2025-05-13 16:34:25 +08:00
|
|
|
|
NodeComponentType: componentType,
|
|
|
|
|
|
}
|
2025-06-13 15:34:49 +08:00
|
|
|
|
nodeMap[constants.UUIDNil] = parent
|
2025-05-13 16:34:25 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
parent = nodeMap[topo.UUIDFrom]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-20 16:08:17 +08:00
|
|
|
|
var child *diagram.MultiBranchTreeNode
|
2025-06-13 15:34:49 +08:00
|
|
|
|
if topo.UUIDTo == constants.UUIDNil {
|
2025-05-20 16:08:17 +08:00
|
|
|
|
var componentType int
|
|
|
|
|
|
child = &diagram.MultiBranchTreeNode{
|
|
|
|
|
|
ID: topo.UUIDTo,
|
|
|
|
|
|
NodeComponentType: componentType,
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
child = nodeMap[topo.UUIDTo]
|
|
|
|
|
|
}
|
2025-05-13 16:34:25 +08:00
|
|
|
|
child.Parent = parent
|
|
|
|
|
|
parent.Children = append(parent.Children, child)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return root vertex
|
2025-06-13 15:34:49 +08:00
|
|
|
|
root, exists := nodeMap[constants.UUIDNil]
|
2025-05-13 16:34:25 +08:00
|
|
|
|
if !exists {
|
|
|
|
|
|
return nil, fmt.Errorf("root node not found")
|
|
|
|
|
|
}
|
|
|
|
|
|
return root, nil
|
|
|
|
|
|
}
|