feat: 合并代码
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"ems.agt/src/framework/errorcatch"
|
||||
"ems.agt/src/framework/middleware"
|
||||
"ems.agt/src/framework/middleware/security"
|
||||
"ems.agt/src/modules/chart"
|
||||
"ems.agt/src/modules/common"
|
||||
"ems.agt/src/modules/crontask"
|
||||
"ems.agt/src/modules/monitor"
|
||||
@@ -120,6 +121,8 @@ func initModulesRoute(app *gin.Engine) {
|
||||
networkelement.Setup(app)
|
||||
// 跟踪模块
|
||||
trace.Setup(app)
|
||||
// 图表模块
|
||||
chart.Setup(app)
|
||||
// 调度任务模块--暂无接口
|
||||
crontask.Setup(app)
|
||||
// 监控模块 - 含调度处理加入队列,放最后
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 项目信息
|
||||
framework:
|
||||
name: "CN EMS"
|
||||
version: "2.2312.10"
|
||||
version: "2.2401.1"
|
||||
|
||||
# 应用服务配置
|
||||
server:
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
type localeItem struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
// localeMap 国际化数据组
|
||||
@@ -30,30 +31,43 @@ func LoadLocaleData(language string) []localeItem {
|
||||
localeData = append(localeData, localeItem{
|
||||
Key: v.DictLabel,
|
||||
Value: v.DictValue,
|
||||
Code: v.DictCode,
|
||||
})
|
||||
}
|
||||
localeMap[language] = localeData
|
||||
return localeData
|
||||
}
|
||||
|
||||
// ValueKey 值转换键
|
||||
func ValueKey(language, value string) string {
|
||||
key := value
|
||||
if value == "" {
|
||||
return key
|
||||
}
|
||||
// UpdateKeyValue 更新键对应的值
|
||||
func UpdateKeyValue(language, key, value string) bool {
|
||||
arr, ok := localeMap[language]
|
||||
if !ok || len(arr) == 0 {
|
||||
arr = LoadLocaleData(language)
|
||||
}
|
||||
|
||||
code := ""
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
for _, v := range arr {
|
||||
if v.Value == value {
|
||||
key = v.Key
|
||||
if v.Key == key {
|
||||
code = v.Code
|
||||
break
|
||||
}
|
||||
}
|
||||
return key
|
||||
|
||||
// 更新字典数据
|
||||
sysDictDataService := systemService.NewSysDictDataImpl
|
||||
item := sysDictDataService.SelectDictDataByCode(code)
|
||||
if item.DictCode == code && item.DictLabel == key {
|
||||
item.DictValue = value
|
||||
row := sysDictDataService.UpdateDictData(item)
|
||||
if row > 0 {
|
||||
delete(localeMap, language)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TKey 翻译键
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
/**无Token可访问白名单 */
|
||||
var URL_WHITE_LIST = []string{"/performanceManagement", "/faultManagement", "/systemState"}
|
||||
var URL_WHITE_LIST = []string{"/performanceManagement", "/faultManagement", "/systemState", "/omcNeConfig"}
|
||||
|
||||
// PreAuthorize 用户身份授权认证校验
|
||||
//
|
||||
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
)
|
||||
|
||||
// Get 发送 GET 请求
|
||||
// timeout 超时时间(秒)
|
||||
func Get(url string, headers map[string]string, timeout uint8) ([]byte, error) {
|
||||
if timeout < 1 || timeout > 180 {
|
||||
timeout = 1
|
||||
// timeout 超时时间(毫秒)
|
||||
func Get(url string, headers map[string]string, timeout int) ([]byte, error) {
|
||||
if timeout < 100 || timeout > 180_000 {
|
||||
timeout = 100
|
||||
}
|
||||
client := &http.Client{
|
||||
Timeout: time.Duration(timeout) * time.Second, // 设置超时时间为 5 秒
|
||||
Timeout: time.Duration(timeout) * time.Millisecond, // 超时时间
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
||||
238
src/framework/utils/ip2region/binding.go
Normal file
238
src/framework/utils/ip2region/binding.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package ip2region
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderInfoLength = 256
|
||||
VectorIndexRows = 256
|
||||
VectorIndexCols = 256
|
||||
VectorIndexSize = 8
|
||||
SegmentIndexBlockSize = 14
|
||||
)
|
||||
|
||||
// --- Index policy define
|
||||
|
||||
type IndexPolicy int
|
||||
|
||||
const (
|
||||
VectorIndexPolicy IndexPolicy = 1
|
||||
BTreeIndexPolicy IndexPolicy = 2
|
||||
)
|
||||
|
||||
func (i IndexPolicy) String() string {
|
||||
switch i {
|
||||
case VectorIndexPolicy:
|
||||
return "VectorIndex"
|
||||
case BTreeIndexPolicy:
|
||||
return "BtreeIndex"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// --- Header define
|
||||
|
||||
type Header struct {
|
||||
// data []byte
|
||||
Version uint16
|
||||
IndexPolicy IndexPolicy
|
||||
CreatedAt uint32
|
||||
StartIndexPtr uint32
|
||||
EndIndexPtr uint32
|
||||
}
|
||||
|
||||
func NewHeader(input []byte) (*Header, error) {
|
||||
if len(input) < 16 {
|
||||
return nil, fmt.Errorf("invalid input buffer")
|
||||
}
|
||||
|
||||
return &Header{
|
||||
Version: binary.LittleEndian.Uint16(input),
|
||||
IndexPolicy: IndexPolicy(binary.LittleEndian.Uint16(input[2:])),
|
||||
CreatedAt: binary.LittleEndian.Uint32(input[4:]),
|
||||
StartIndexPtr: binary.LittleEndian.Uint32(input[8:]),
|
||||
EndIndexPtr: binary.LittleEndian.Uint32(input[12:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// --- searcher implementation
|
||||
|
||||
type Searcher struct {
|
||||
handle *os.File
|
||||
|
||||
ioCount int
|
||||
|
||||
// use it only when this feature enabled.
|
||||
// Preload the vector index will reduce the number of IO operations
|
||||
// thus speedup the search process
|
||||
vectorIndex []byte
|
||||
|
||||
// content buffer.
|
||||
// running with the whole xdb file cached
|
||||
contentBuff []byte
|
||||
}
|
||||
|
||||
func baseNew(dbFile string, vIndex []byte, cBuff []byte) (*Searcher, error) {
|
||||
var err error
|
||||
|
||||
// content buff first
|
||||
if cBuff != nil {
|
||||
return &Searcher{
|
||||
vectorIndex: nil,
|
||||
contentBuff: cBuff,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// open the xdb binary file
|
||||
handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Searcher{
|
||||
handle: handle,
|
||||
vectorIndex: vIndex,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewWithFileOnly(dbFile string) (*Searcher, error) {
|
||||
return baseNew(dbFile, nil, nil)
|
||||
}
|
||||
|
||||
func NewWithVectorIndex(dbFile string, vIndex []byte) (*Searcher, error) {
|
||||
return baseNew(dbFile, vIndex, nil)
|
||||
}
|
||||
|
||||
func NewWithBuffer(cBuff []byte) (*Searcher, error) {
|
||||
return baseNew("", nil, cBuff)
|
||||
}
|
||||
|
||||
func (s *Searcher) Close() {
|
||||
if s.handle != nil {
|
||||
err := s.handle.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetIOCount return the global io count for the last search
|
||||
func (s *Searcher) GetIOCount() int {
|
||||
return s.ioCount
|
||||
}
|
||||
|
||||
// SearchByStr find the region for the specified ip string
|
||||
func (s *Searcher) SearchByStr(str string) (string, error) {
|
||||
ip, err := CheckIP(str)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return s.Search(ip)
|
||||
}
|
||||
|
||||
// Search find the region for the specified long ip
|
||||
func (s *Searcher) Search(ip uint32) (string, error) {
|
||||
// reset the global ioCount
|
||||
s.ioCount = 0
|
||||
|
||||
// locate the segment index block based on the vector index
|
||||
var il0 = (ip >> 24) & 0xFF
|
||||
var il1 = (ip >> 16) & 0xFF
|
||||
var idx = il0*VectorIndexCols*VectorIndexSize + il1*VectorIndexSize
|
||||
var sPtr, ePtr = uint32(0), uint32(0)
|
||||
if s.vectorIndex != nil {
|
||||
sPtr = binary.LittleEndian.Uint32(s.vectorIndex[idx:])
|
||||
ePtr = binary.LittleEndian.Uint32(s.vectorIndex[idx+4:])
|
||||
} else if s.contentBuff != nil {
|
||||
sPtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx:])
|
||||
ePtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx+4:])
|
||||
} else {
|
||||
// read the vector index block
|
||||
var buff = make([]byte, VectorIndexSize)
|
||||
err := s.read(int64(HeaderInfoLength+idx), buff)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("read vector index block at %d: %w", HeaderInfoLength+idx, err)
|
||||
}
|
||||
|
||||
sPtr = binary.LittleEndian.Uint32(buff)
|
||||
ePtr = binary.LittleEndian.Uint32(buff[4:])
|
||||
}
|
||||
|
||||
// fmt.Printf("sPtr=%d, ePtr=%d", sPtr, ePtr)
|
||||
|
||||
// binary search the segment index to get the region
|
||||
var dataLen, dataPtr = 0, uint32(0)
|
||||
var buff = make([]byte, SegmentIndexBlockSize)
|
||||
var l, h = 0, int((ePtr - sPtr) / SegmentIndexBlockSize)
|
||||
for l <= h {
|
||||
m := (l + h) >> 1
|
||||
p := sPtr + uint32(m*SegmentIndexBlockSize)
|
||||
err := s.read(int64(p), buff)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("read segment index at %d: %w", p, err)
|
||||
}
|
||||
|
||||
// decode the data step by step to reduce the unnecessary operations
|
||||
sip := binary.LittleEndian.Uint32(buff)
|
||||
if ip < sip {
|
||||
h = m - 1
|
||||
} else {
|
||||
eip := binary.LittleEndian.Uint32(buff[4:])
|
||||
if ip > eip {
|
||||
l = m + 1
|
||||
} else {
|
||||
dataLen = int(binary.LittleEndian.Uint16(buff[8:]))
|
||||
dataPtr = binary.LittleEndian.Uint32(buff[10:])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("dataLen: %d, dataPtr: %d", dataLen, dataPtr)
|
||||
if dataLen == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// load and return the region data
|
||||
var regionBuff = make([]byte, dataLen)
|
||||
err := s.read(int64(dataPtr), regionBuff)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("read region at %d: %w", dataPtr, err)
|
||||
}
|
||||
|
||||
return string(regionBuff), nil
|
||||
}
|
||||
|
||||
// do the data read operation based on the setting.
|
||||
// content buffer first or will read from the file.
|
||||
// this operation will invoke the Seek for file based read.
|
||||
func (s *Searcher) read(offset int64, buff []byte) error {
|
||||
if s.contentBuff != nil {
|
||||
cLen := copy(buff, s.contentBuff[offset:])
|
||||
if cLen != len(buff) {
|
||||
return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
|
||||
}
|
||||
} else {
|
||||
_, err := s.handle.Seek(offset, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("seek to %d: %w", offset, err)
|
||||
}
|
||||
|
||||
s.ioCount++
|
||||
rLen, err := s.handle.Read(buff)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle read: %w", err)
|
||||
}
|
||||
|
||||
if rLen != len(buff) {
|
||||
return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,12 +1,59 @@
|
||||
package ip2region
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ems.agt/src/framework/logger"
|
||||
)
|
||||
|
||||
// 网络地址(内网)
|
||||
const LOCAT_HOST = "127.0.0.1"
|
||||
|
||||
// 全局查询对象
|
||||
var searcher *Searcher
|
||||
|
||||
//go:embed ip2region.xdb
|
||||
var ip2regionDB embed.FS
|
||||
|
||||
func init() {
|
||||
// 从 dbPath 加载整个 xdb 到内存
|
||||
buf, err := ip2regionDB.ReadFile("ip2region.xdb")
|
||||
if err != nil {
|
||||
logger.Fatalf("failed error load xdb from : %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 用全局的 cBuff 创建完全基于内存的查询对象。
|
||||
base, err := NewWithBuffer(buf)
|
||||
if err != nil {
|
||||
logger.Errorf("failed error create searcher with content: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 赋值到全局查询对象
|
||||
searcher = base
|
||||
}
|
||||
|
||||
// RegionSearchByIp 查询IP所在地
|
||||
//
|
||||
// 国家|区域|省份|城市|ISP
|
||||
func RegionSearchByIp(ip string) (string, int, int64) {
|
||||
ip = ClientIP(ip)
|
||||
if ip == LOCAT_HOST {
|
||||
// "0|0|0|内网IP|内网IP"
|
||||
return "0|0|0|app.common.noIPregion|app.common.noIPregion", 0, 0
|
||||
}
|
||||
tStart := time.Now()
|
||||
region, err := searcher.SearchByStr(ip)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to SearchIP(%s): %s\n", ip, err)
|
||||
return "0|0|0|0|0", 0, 0
|
||||
}
|
||||
return region, 0, time.Since(tStart).Milliseconds()
|
||||
}
|
||||
|
||||
// RealAddressByIp 地址IP所在地
|
||||
//
|
||||
// 218.4.167.70 江苏省 苏州市
|
||||
@@ -15,7 +62,21 @@ func RealAddressByIp(ip string) string {
|
||||
if ip == LOCAT_HOST {
|
||||
return "app.common.noIPregion" // 内网IP
|
||||
}
|
||||
return "app.common.noIPregion" // 内网IP
|
||||
region, err := searcher.SearchByStr(ip)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to SearchIP(%s): %s\n", ip, err)
|
||||
return "app.common.unknown" // 未知
|
||||
}
|
||||
parts := strings.Split(region, "|")
|
||||
province := parts[2]
|
||||
city := parts[3]
|
||||
if province == "0" && city != "0" {
|
||||
if city == "内网IP" {
|
||||
return "app.common.noIPregion" // 内网IP
|
||||
}
|
||||
return city
|
||||
}
|
||||
return province + " " + city
|
||||
}
|
||||
|
||||
// ClientIP 处理客户端IP地址显示iPv4
|
||||
|
||||
BIN
src/framework/utils/ip2region/ip2region.xdb
Normal file
BIN
src/framework/utils/ip2region/ip2region.xdb
Normal file
Binary file not shown.
175
src/framework/utils/ip2region/util.go
Normal file
175
src/framework/utils/ip2region/util.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package ip2region
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var shiftIndex = []int{24, 16, 8, 0}
|
||||
|
||||
func CheckIP(ip string) (uint32, error) {
|
||||
var ps = strings.Split(strings.TrimSpace(ip), ".")
|
||||
if len(ps) != 4 {
|
||||
return 0, fmt.Errorf("invalid ip address `%s`", ip)
|
||||
}
|
||||
|
||||
var val = uint32(0)
|
||||
for i, s := range ps {
|
||||
d, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("the %dth part `%s` is not an integer", i, s)
|
||||
}
|
||||
|
||||
if d < 0 || d > 255 {
|
||||
return 0, fmt.Errorf("the %dth part `%s` should be an integer bettween 0 and 255", i, s)
|
||||
}
|
||||
|
||||
val |= uint32(d) << shiftIndex[i]
|
||||
}
|
||||
|
||||
// convert the ip to integer
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func Long2IP(ip uint32) string {
|
||||
return fmt.Sprintf("%d.%d.%d.%d", (ip>>24)&0xFF, (ip>>16)&0xFF, (ip>>8)&0xFF, ip&0xFF)
|
||||
}
|
||||
|
||||
func MidIP(sip uint32, eip uint32) uint32 {
|
||||
return uint32((uint64(sip) + uint64(eip)) >> 1)
|
||||
}
|
||||
|
||||
// LoadHeader load the header info from the specified handle
|
||||
func LoadHeader(handle *os.File) (*Header, error) {
|
||||
_, err := handle.Seek(0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("seek to the header: %w", err)
|
||||
}
|
||||
|
||||
var buff = make([]byte, HeaderInfoLength)
|
||||
rLen, err := handle.Read(buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rLen != len(buff) {
|
||||
return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
|
||||
}
|
||||
|
||||
return NewHeader(buff)
|
||||
}
|
||||
|
||||
// LoadHeaderFromFile load header info from the specified db file path
|
||||
func LoadHeaderFromFile(dbFile string) (*Header, error) {
|
||||
handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err)
|
||||
}
|
||||
|
||||
defer func(handle *os.File) {
|
||||
_ = handle.Close()
|
||||
}(handle)
|
||||
|
||||
header, err := LoadHeader(handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// LoadHeaderFromBuff wrap the header info from the content buffer
|
||||
func LoadHeaderFromBuff(cBuff []byte) (*Header, error) {
|
||||
return NewHeader(cBuff[0:256])
|
||||
}
|
||||
|
||||
// LoadVectorIndex util function to load the vector index from the specified file handle
|
||||
func LoadVectorIndex(handle *os.File) ([]byte, error) {
|
||||
// load all the vector index block
|
||||
_, err := handle.Seek(HeaderInfoLength, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("seek to vector index: %w", err)
|
||||
}
|
||||
|
||||
var buff = make([]byte, VectorIndexRows*VectorIndexCols*VectorIndexSize)
|
||||
rLen, err := handle.Read(buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rLen != len(buff) {
|
||||
return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
|
||||
}
|
||||
|
||||
return buff, nil
|
||||
}
|
||||
|
||||
// LoadVectorIndexFromFile load vector index from a specified file path
|
||||
func LoadVectorIndexFromFile(dbFile string) ([]byte, error) {
|
||||
handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = handle.Close()
|
||||
}()
|
||||
|
||||
vIndex, err := LoadVectorIndex(handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vIndex, nil
|
||||
}
|
||||
|
||||
// LoadContent load the whole xdb content from the specified file handle
|
||||
func LoadContent(handle *os.File) ([]byte, error) {
|
||||
// get file size
|
||||
fi, err := handle.Stat()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat: %w", err)
|
||||
}
|
||||
|
||||
size := fi.Size()
|
||||
|
||||
// seek to the head of the file
|
||||
_, err = handle.Seek(0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("seek to get xdb file length: %w", err)
|
||||
}
|
||||
|
||||
var buff = make([]byte, size)
|
||||
rLen, err := handle.Read(buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rLen != len(buff) {
|
||||
return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff))
|
||||
}
|
||||
|
||||
return buff, nil
|
||||
}
|
||||
|
||||
// LoadContentFromFile load the whole xdb content from the specified db file path
|
||||
func LoadContentFromFile(dbFile string) ([]byte, error) {
|
||||
handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = handle.Close()
|
||||
}()
|
||||
|
||||
cBuff, err := LoadContent(handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cBuff, nil
|
||||
}
|
||||
|
||||
40
src/modules/chart/chart.go
Normal file
40
src/modules/chart/chart.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package chart
|
||||
|
||||
import (
|
||||
"ems.agt/src/framework/logger"
|
||||
"ems.agt/src/framework/middleware"
|
||||
"ems.agt/src/framework/middleware/collectlogs"
|
||||
"ems.agt/src/modules/chart/controller"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 模块路由注册
|
||||
func Setup(router *gin.Engine) {
|
||||
logger.Infof("开始加载 ====> chart 模块路由")
|
||||
|
||||
chartGroup := router.Group("/chart")
|
||||
|
||||
// 关系图
|
||||
chartGraphGroup := chartGroup.Group("/graph")
|
||||
{
|
||||
chartGraphGroup.GET("",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewChartGraph.Load,
|
||||
)
|
||||
chartGraphGroup.GET("/groups",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewChartGraph.GroupNames,
|
||||
)
|
||||
chartGraphGroup.POST("",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.chartGraph", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewChartGraph.Save,
|
||||
)
|
||||
chartGraphGroup.DELETE("/:group",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.chartGraph", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewChartGraph.Delete,
|
||||
)
|
||||
}
|
||||
}
|
||||
100
src/modules/chart/controller/chart_graph.go
Normal file
100
src/modules/chart/controller/chart_graph.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"ems.agt/src/framework/i18n"
|
||||
"ems.agt/src/framework/utils/ctx"
|
||||
"ems.agt/src/framework/vo/result"
|
||||
chartService "ems.agt/src/modules/chart/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 实例化控制层 ChartGraphController 结构体
|
||||
var NewChartGraph = &ChartGraphController{
|
||||
chartGraphService: chartService.NewChartGraphImpl,
|
||||
}
|
||||
|
||||
// G6关系图
|
||||
//
|
||||
// PATH /graph
|
||||
type ChartGraphController struct {
|
||||
// G6关系图数据表服务
|
||||
chartGraphService chartService.IChartGraph
|
||||
}
|
||||
|
||||
// 获取关系图组名
|
||||
//
|
||||
// GET /groups
|
||||
func (s *ChartGraphController) GroupNames(c *gin.Context) {
|
||||
data := s.chartGraphService.SelectGroup()
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
// 获取关系图数据
|
||||
//
|
||||
// GET /
|
||||
func (s *ChartGraphController) Load(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var querys struct {
|
||||
Group string `form:"group" binding:"required"`
|
||||
Type string `form:"type" binding:"omitempty,oneof=node edge combo"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
data := s.chartGraphService.LoadData(querys.Group, querys.Type)
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
// 保存关系图数据
|
||||
//
|
||||
// POST /
|
||||
func (s *ChartGraphController) Save(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
Group string `json:"group" binding:"required"`
|
||||
Data struct {
|
||||
Nodes []map[string]any `json:"nodes" binding:"required"`
|
||||
Edges []map[string]any `json:"edges" binding:"required"`
|
||||
Combos []map[string]any `json:"combos" binding:"required"`
|
||||
} `json:"data" binding:"required"`
|
||||
}
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"nodes": body.Data.Nodes,
|
||||
"edges": body.Data.Edges,
|
||||
"combos": body.Data.Combos,
|
||||
}
|
||||
saveNum := s.chartGraphService.SaveData(body.Group, data)
|
||||
if saveNum > 0 {
|
||||
c.JSON(200, result.Ok(nil))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.Err(nil))
|
||||
}
|
||||
|
||||
// 删除关系图数据
|
||||
//
|
||||
// DELETE /:group
|
||||
func (s *ChartGraphController) Delete(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
group := c.Param("group")
|
||||
if group == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
deleteNum := s.chartGraphService.DeleteGroup(group)
|
||||
if deleteNum > 0 {
|
||||
c.JSON(200, result.Ok(nil))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.Err(nil))
|
||||
}
|
||||
31
src/modules/chart/model/chart_graph.go
Normal file
31
src/modules/chart/model/chart_graph.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package model
|
||||
|
||||
// ChartGraph G6关系图数据对象 chart_graph
|
||||
type ChartGraph struct {
|
||||
RowID int64 `json:"rowId,omitempty" gorm:"column:row_id;primaryKey;autoIncrement"` // 记录ID
|
||||
RowType string `json:"rowType,omitempty" gorm:"column:row_type"` // 记录类型(node/edge/combo)
|
||||
RowGroup string `json:"rowGroup,omitempty" gorm:"column:row_group"` // 记录组名
|
||||
ID string `json:"id,omitempty" gorm:"column:id"` // 元素ID
|
||||
Type string `json:"type,omitempty" gorm:"column:type"` // node/combo 类型
|
||||
Depth int `json:"depth,omitempty" gorm:"column:depth"` // node/combo 深度
|
||||
X float64 `json:"x,omitempty" gorm:"column:x"` // node/combo 横向坐标
|
||||
Y float64 `json:"y,omitempty" gorm:"column:y"` // node/combo 纵向坐标
|
||||
Size string `json:"size,omitempty" gorm:"column:size"` // node/combo 大小-JSON数组
|
||||
Icon string `json:"icon,omitempty" gorm:"column:icon"` // node-部分类型支持图标JSON配置
|
||||
Img string `json:"img,omitempty" gorm:"column:img"` // node-img 图片
|
||||
ClipCfg string `json:"clipCfg,omitempty" gorm:"column:clip_cfg"` // node-img 图片裁剪JSON配置
|
||||
Direction string `json:"direction,omitempty" gorm:"column:direction"` // node-triangle 三角形的方向(up/down/left/right)
|
||||
Source string `json:"source,omitempty" gorm:"column:source"` // edge-边起始
|
||||
Target string `json:"target,omitempty" gorm:"column:target"` // edge-边目标
|
||||
ComboID string `json:"combo_id,omitempty" gorm:"column:combo_id"` // combo-分组
|
||||
Padding string `json:"padding,omitempty" gorm:"column:padding"` // combo-JSON分组内边距
|
||||
ParentID string `json:"parentId,omitempty" gorm:"column:parent_id"` // combo-父级分组
|
||||
Children string `json:"children,omitempty" gorm:"column:children"` // combo-JSON分组内含元素
|
||||
Style string `json:"style,omitempty" gorm:"column:style"` // 元素样式-JONS配置
|
||||
Label string `json:"label,omitempty" gorm:"column:label"` // 标签文本
|
||||
LabelCfg string `json:"labelCfg,omitempty" gorm:"column:label_cfg"` // 标签文本-JSON配置
|
||||
}
|
||||
|
||||
func (ChartGraph) TableName() string {
|
||||
return "chart_graph"
|
||||
}
|
||||
21
src/modules/chart/repository/chart_graph.go
Normal file
21
src/modules/chart/repository/chart_graph.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package repository
|
||||
|
||||
import "ems.agt/src/modules/chart/model"
|
||||
|
||||
// G6关系图数据 数据层接口
|
||||
type IChartGraph interface {
|
||||
// SelectPage 根据条件分页查询字典类型
|
||||
SelectPage(query map[string]any) map[string]any
|
||||
|
||||
// SelectList 根据实体查询
|
||||
SelectList(graph model.ChartGraph) []model.ChartGraph
|
||||
|
||||
// SelectGroup 查询组名
|
||||
SelectGroup() []string
|
||||
|
||||
// Insert 批量添加
|
||||
Inserts(graphs []model.ChartGraph) int64
|
||||
|
||||
// Delete 删除组数据
|
||||
DeleteGroup(rowGroup string) int64
|
||||
}
|
||||
194
src/modules/chart/repository/chart_graph.impl.go
Normal file
194
src/modules/chart/repository/chart_graph.impl.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"ems.agt/src/framework/datasource"
|
||||
"ems.agt/src/framework/logger"
|
||||
"ems.agt/src/framework/utils/parse"
|
||||
"ems.agt/src/framework/utils/repo"
|
||||
"ems.agt/src/modules/chart/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 NewChartGraphImpl 结构体
|
||||
var NewChartGraphImpl = &ChartGraphImpl{
|
||||
selectSql: `select
|
||||
row_id, row_type, row_group,
|
||||
id, type, depth, x, y, size, icon, img,
|
||||
clip_cfg, direction,
|
||||
source, target, combo_id,
|
||||
padding, parent_id, children,
|
||||
style, label, label_cfg
|
||||
from chart_graph`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"row_id": "RowID",
|
||||
"row_type": "RowType",
|
||||
"row_group": "RowGroup",
|
||||
"id": "ID",
|
||||
"type": "Type",
|
||||
"depth": "Depth",
|
||||
"x": "X",
|
||||
"y": "Y",
|
||||
"size": "Size",
|
||||
"icon": "Icon",
|
||||
"img": "Img",
|
||||
"clip_cfg": "ClipCfg",
|
||||
"direction": "Direction",
|
||||
"source": "Source",
|
||||
"target": "Target",
|
||||
"combo_id": "ComboID",
|
||||
"padding": "Padding",
|
||||
"parent_id": "ParentID",
|
||||
"children": "Children",
|
||||
"style": "Style",
|
||||
"label": "Label",
|
||||
"label_cfg": "LabelCfg",
|
||||
},
|
||||
}
|
||||
|
||||
// ChartGraphImpl G6关系图数据表 数据层处理
|
||||
type ChartGraphImpl struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *ChartGraphImpl) convertResultRows(rows []map[string]any) []model.ChartGraph {
|
||||
arr := make([]model.ChartGraph, 0)
|
||||
for _, row := range rows {
|
||||
item := model.ChartGraph{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询字典类型
|
||||
func (r *ChartGraphImpl) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["rowType"]; ok && v != "" {
|
||||
conditions = append(conditions, "row_type = ?")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["rowGroup"]; ok && v != "" {
|
||||
conditions = append(conditions, "row_group = ?")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.ChartGraph{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from chart_graph"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return result
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *ChartGraphImpl) SelectList(graph model.ChartGraph) []model.ChartGraph {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if graph.RowType != "" {
|
||||
conditions = append(conditions, "row_type = ?")
|
||||
params = append(params, graph.RowType)
|
||||
}
|
||||
if graph.RowGroup != "" {
|
||||
conditions = append(conditions, "row_group = ?")
|
||||
params = append(params, graph.RowGroup)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by depth asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectGroup 查询组名
|
||||
func (r *ChartGraphImpl) SelectGroup() []string {
|
||||
rows := []string{}
|
||||
// 查询数量 长度为0直接返回
|
||||
querySql := "select row_group as 'str' from chart_graph GROUP BY row_group"
|
||||
strRows, err := datasource.RawDB("", querySql, nil)
|
||||
if err != nil {
|
||||
logger.Errorf("Query err => %v", err)
|
||||
return rows
|
||||
}
|
||||
for _, v := range strRows {
|
||||
rows = append(rows, v["str"].(string))
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *ChartGraphImpl) Inserts(graphs []model.ChartGraph) int64 {
|
||||
tx := datasource.DefaultDB().CreateInBatches(graphs, 2000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除组数据
|
||||
func (r *ChartGraphImpl) DeleteGroup(rowGroup string) int64 {
|
||||
tx := datasource.DefaultDB().Where("row_group = ?", rowGroup).Delete(&model.ChartGraph{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
16
src/modules/chart/service/chart_graph.go
Normal file
16
src/modules/chart/service/chart_graph.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package service
|
||||
|
||||
// G6关系图数据 服务层接口
|
||||
type IChartGraph interface {
|
||||
// SelectGroup 查询组名
|
||||
SelectGroup() []string
|
||||
|
||||
// LoadData 查询所组图数据
|
||||
LoadData(rowGroup, rowType string) map[string]any
|
||||
|
||||
// SaveData 添加组图数据
|
||||
SaveData(rowGroup string, data map[string]any) int64
|
||||
|
||||
// DeleteGroup 删除所组图数据
|
||||
DeleteGroup(rowGroup string) int64
|
||||
}
|
||||
359
src/modules/chart/service/chart_graph.impl.go
Normal file
359
src/modules/chart/service/chart_graph.impl.go
Normal file
@@ -0,0 +1,359 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"ems.agt/src/framework/utils/parse"
|
||||
"ems.agt/src/modules/chart/model"
|
||||
chartRepository "ems.agt/src/modules/chart/repository"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
// 实例化服务层 ChartGraphImpl 结构体
|
||||
var NewChartGraphImpl = &ChartGraphImpl{
|
||||
graphRepository: chartRepository.NewChartGraphImpl,
|
||||
}
|
||||
|
||||
// ChartGraphImpl G6关系图数据表 服务层处理
|
||||
type ChartGraphImpl struct {
|
||||
// G6关系图数据服务
|
||||
graphRepository chartRepository.IChartGraph
|
||||
}
|
||||
|
||||
// SelectGroup 查询组名
|
||||
func (s *ChartGraphImpl) SelectGroup() []string {
|
||||
return s.graphRepository.SelectGroup()
|
||||
}
|
||||
|
||||
// LoadData 查询所组图数据
|
||||
func (s *ChartGraphImpl) LoadData(rowGroup, rowType string) map[string]any {
|
||||
// 查询数据
|
||||
graph := model.ChartGraph{
|
||||
RowGroup: rowGroup,
|
||||
}
|
||||
if rowType != "" {
|
||||
graph.RowType = rowType
|
||||
}
|
||||
data := s.graphRepository.SelectList(graph)
|
||||
|
||||
// 数据项
|
||||
nodes := []map[string]any{}
|
||||
edges := []map[string]any{}
|
||||
combos := []map[string]any{}
|
||||
|
||||
for _, v := range data {
|
||||
if v.RowType == "node" {
|
||||
nodes = append(nodes, s.loadNode(v))
|
||||
}
|
||||
if v.RowType == "edge" {
|
||||
edges = append(edges, s.loadEdge(v))
|
||||
}
|
||||
if v.RowType == "combo" {
|
||||
combos = append(combos, s.loadCombo(v))
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"nodes": nodes,
|
||||
"edges": edges,
|
||||
"combos": combos,
|
||||
}
|
||||
}
|
||||
|
||||
// loadNode 图数据Node
|
||||
func (s *ChartGraphImpl) loadNode(v model.ChartGraph) map[string]any {
|
||||
node := map[string]any{
|
||||
"id": v.ID,
|
||||
"comboId": v.ComboID,
|
||||
"x": v.X,
|
||||
"y": v.Y,
|
||||
"type": v.Type,
|
||||
"depth": v.Depth,
|
||||
}
|
||||
|
||||
// 元素样式
|
||||
style := map[string]any{}
|
||||
if len(v.Style) > 7 {
|
||||
json.Unmarshal([]byte(v.Style), &style)
|
||||
}
|
||||
node["style"] = style
|
||||
|
||||
// 元素大小
|
||||
if strings.Contains(v.Size, "[") {
|
||||
sizeArr := []int64{}
|
||||
json.Unmarshal([]byte(v.Size), &sizeArr)
|
||||
node["size"] = sizeArr
|
||||
} else {
|
||||
node["size"] = parse.Number(v.Size)
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
node["label"] = v.Label
|
||||
labelCfg := map[string]any{}
|
||||
if len(v.LabelCfg) > 7 {
|
||||
json.Unmarshal([]byte(v.LabelCfg), &labelCfg)
|
||||
}
|
||||
node["labelCfg"] = labelCfg
|
||||
|
||||
// 三角形属性
|
||||
if v.Type == "triangle" {
|
||||
node["direction"] = v.Direction
|
||||
}
|
||||
|
||||
// 图片属性
|
||||
if strings.Index(v.Type, "image") == 0 {
|
||||
node["img"] = v.Img
|
||||
clipCfg := map[string]any{}
|
||||
if len(v.ClipCfg) > 7 {
|
||||
json.Unmarshal([]byte(v.ClipCfg), &clipCfg)
|
||||
}
|
||||
node["clipCfg"] = clipCfg
|
||||
}
|
||||
|
||||
// 图标属性
|
||||
if v.Icon != "" {
|
||||
icon := map[string]any{}
|
||||
if len(v.Icon) > 7 {
|
||||
json.Unmarshal([]byte(v.Icon), &icon)
|
||||
}
|
||||
node["icon"] = icon
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// loadEdge 图数据Edge
|
||||
func (s *ChartGraphImpl) loadEdge(v model.ChartGraph) map[string]any {
|
||||
edge := map[string]any{
|
||||
"id": v.ID,
|
||||
"source": v.Source,
|
||||
"target": v.Target,
|
||||
"type": v.Type,
|
||||
}
|
||||
|
||||
// 元素样式
|
||||
style := map[string]any{}
|
||||
if len(v.Style) > 7 {
|
||||
json.Unmarshal([]byte(v.Style), &style)
|
||||
}
|
||||
edge["style"] = style
|
||||
|
||||
// 标签文本
|
||||
edge["label"] = v.Label
|
||||
labelCfg := map[string]any{}
|
||||
if len(v.LabelCfg) > 7 {
|
||||
json.Unmarshal([]byte(v.LabelCfg), &labelCfg)
|
||||
}
|
||||
edge["labelCfg"] = labelCfg
|
||||
|
||||
return edge
|
||||
}
|
||||
|
||||
// loadCombo 图数据Combo
|
||||
func (s *ChartGraphImpl) loadCombo(v model.ChartGraph) map[string]any {
|
||||
combo := map[string]any{
|
||||
"id": v.ID,
|
||||
"x": v.X,
|
||||
"y": v.Y,
|
||||
"type": v.Type,
|
||||
"depth": v.Depth,
|
||||
}
|
||||
|
||||
// 元素样式
|
||||
style := map[string]any{}
|
||||
if len(v.Style) > 7 {
|
||||
json.Unmarshal([]byte(v.Style), &style)
|
||||
}
|
||||
combo["style"] = style
|
||||
|
||||
// 元素大小
|
||||
if strings.Contains(v.Size, "[") {
|
||||
sizeArr := []int64{}
|
||||
json.Unmarshal([]byte(v.Size), &sizeArr)
|
||||
combo["size"] = sizeArr
|
||||
} else {
|
||||
combo["size"] = parse.Number(v.Size)
|
||||
}
|
||||
|
||||
// 元素内边距
|
||||
if strings.Contains(v.Padding, "[") {
|
||||
paddingArr := []int64{}
|
||||
json.Unmarshal([]byte(v.Padding), &paddingArr)
|
||||
combo["padding"] = paddingArr
|
||||
} else {
|
||||
combo["padding"] = parse.Number(v.Padding)
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
combo["label"] = v.Label
|
||||
labelCfg := map[string]any{}
|
||||
if len(v.LabelCfg) > 7 {
|
||||
json.Unmarshal([]byte(v.LabelCfg), &labelCfg)
|
||||
}
|
||||
combo["labelCfg"] = labelCfg
|
||||
|
||||
// 分组内元素
|
||||
if v.Children != "" {
|
||||
children := []map[string]any{}
|
||||
if len(v.Children) > 7 {
|
||||
json.Unmarshal([]byte(v.Children), &children)
|
||||
}
|
||||
combo["children"] = children
|
||||
}
|
||||
|
||||
return combo
|
||||
}
|
||||
|
||||
// SaveData 添加组图数据
|
||||
func (s *ChartGraphImpl) SaveData(rowGroup string, data map[string]any) int64 {
|
||||
graphs := []model.ChartGraph{}
|
||||
nodes := data["nodes"].([]map[string]any)
|
||||
graphNodes := s.saveNode(rowGroup, nodes)
|
||||
graphs = append(graphs, graphNodes...)
|
||||
edges := data["edges"].([]map[string]any)
|
||||
graphEdges := s.saveEdge(rowGroup, edges)
|
||||
graphs = append(graphs, graphEdges...)
|
||||
combos := data["combos"].([]map[string]any)
|
||||
graphCombos := s.saveCombo(rowGroup, combos)
|
||||
graphs = append(graphs, graphCombos...)
|
||||
// 删除组数据后插入
|
||||
if len(graphs) > 0 {
|
||||
s.graphRepository.DeleteGroup(rowGroup)
|
||||
}
|
||||
return s.graphRepository.Inserts(graphs)
|
||||
}
|
||||
|
||||
// saveNode 图数据Node
|
||||
func (s *ChartGraphImpl) saveNode(rowGroup string, nodes []map[string]any) []model.ChartGraph {
|
||||
var graphs []model.ChartGraph
|
||||
for _, v := range nodes {
|
||||
node := model.ChartGraph{
|
||||
RowType: "node",
|
||||
RowGroup: rowGroup,
|
||||
ID: v["id"].(string),
|
||||
X: v["x"].(float64),
|
||||
Y: v["y"].(float64),
|
||||
Type: v["type"].(string),
|
||||
}
|
||||
if comboId, ok := v["comboId"]; ok && comboId != nil {
|
||||
node.ComboID = comboId.(string)
|
||||
}
|
||||
if depth, ok := v["depth"]; ok && depth != nil {
|
||||
node.Depth = int(depth.(float64))
|
||||
}
|
||||
if styleByte, err := json.Marshal(v["style"]); err == nil {
|
||||
node.Style = string(styleByte)
|
||||
}
|
||||
|
||||
// 元素大小
|
||||
if sizeByte, err := json.Marshal(v["size"]); err == nil {
|
||||
node.Size = string(sizeByte)
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
if label, ok := v["label"]; ok && label != nil {
|
||||
node.Label = label.(string)
|
||||
}
|
||||
if labelCfgByte, err := json.Marshal(v["labelCfg"]); err == nil {
|
||||
node.LabelCfg = string(labelCfgByte)
|
||||
}
|
||||
// 三角形属性
|
||||
if direction, ok := v["direction"]; ok && direction != nil && node.Type == "triangle" {
|
||||
node.Direction = direction.(string)
|
||||
}
|
||||
// 图片属性
|
||||
if img, ok := v["img"]; ok && img != nil {
|
||||
node.Img = img.(string)
|
||||
if clipCfgByte, err := json.Marshal(v["clipCfg"]); err == nil {
|
||||
node.ClipCfg = string(clipCfgByte)
|
||||
}
|
||||
}
|
||||
// 图标属性
|
||||
if icon, ok := v["icon"]; ok && icon != nil {
|
||||
if iconByte, err := json.Marshal(icon); err == nil {
|
||||
node.Icon = string(iconByte)
|
||||
}
|
||||
}
|
||||
|
||||
graphs = append(graphs, node)
|
||||
}
|
||||
return graphs
|
||||
}
|
||||
|
||||
// saveEdge 图数据Edge
|
||||
func (s *ChartGraphImpl) saveEdge(rowGroup string, edges []map[string]any) []model.ChartGraph {
|
||||
var graphs []model.ChartGraph
|
||||
for _, v := range edges {
|
||||
edge := model.ChartGraph{
|
||||
RowType: "edge",
|
||||
RowGroup: rowGroup,
|
||||
ID: v["id"].(string),
|
||||
Source: v["source"].(string),
|
||||
Target: v["target"].(string),
|
||||
Type: v["type"].(string),
|
||||
}
|
||||
|
||||
if styleByte, err := json.Marshal(v["style"]); err == nil {
|
||||
edge.Style = string(styleByte)
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
if label, ok := v["label"]; ok && label != nil {
|
||||
edge.Label = label.(string)
|
||||
}
|
||||
if labelCfgByte, err := json.Marshal(v["labelCfg"]); err == nil {
|
||||
edge.LabelCfg = string(labelCfgByte)
|
||||
}
|
||||
|
||||
graphs = append(graphs, edge)
|
||||
}
|
||||
return graphs
|
||||
}
|
||||
|
||||
// saveCombo 图数据Combo
|
||||
func (s *ChartGraphImpl) saveCombo(rowGroup string, combos []map[string]any) []model.ChartGraph {
|
||||
var graphs []model.ChartGraph
|
||||
for _, v := range combos {
|
||||
combo := model.ChartGraph{
|
||||
RowType: "combo",
|
||||
RowGroup: rowGroup,
|
||||
ID: v["id"].(string),
|
||||
X: v["x"].(float64),
|
||||
Y: v["y"].(float64),
|
||||
Type: v["type"].(string),
|
||||
}
|
||||
if depth, ok := v["depth"]; ok && depth != nil {
|
||||
combo.Depth = int(depth.(float64))
|
||||
}
|
||||
if styleByte, err := json.Marshal(v["style"]); err == nil {
|
||||
combo.Style = string(styleByte)
|
||||
}
|
||||
if paddingByte, err := json.Marshal(v["padding"]); err == nil {
|
||||
combo.Padding = string(paddingByte)
|
||||
}
|
||||
if childrenByte, err := json.Marshal(v["children"]); err == nil {
|
||||
combo.Children = string(childrenByte)
|
||||
}
|
||||
|
||||
// 元素大小
|
||||
if sizeByte, err := json.Marshal(v["size"]); err == nil {
|
||||
combo.Size = string(sizeByte)
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
if label, ok := v["label"]; ok && label != nil {
|
||||
combo.Label = label.(string)
|
||||
}
|
||||
if labelCfgByte, err := json.Marshal(v["labelCfg"]); err == nil {
|
||||
combo.LabelCfg = string(labelCfgByte)
|
||||
}
|
||||
|
||||
graphs = append(graphs, combo)
|
||||
}
|
||||
return graphs
|
||||
}
|
||||
|
||||
// Delete 删除所组图数据
|
||||
func (s *ChartGraphImpl) DeleteGroup(rowGroup string) int64 {
|
||||
return s.graphRepository.DeleteGroup(rowGroup)
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
var alarmDefine BarParams
|
||||
|
||||
err = json.Unmarshal([]byte(sysJob.TargetParams), &alarmDefine)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
log.Error("Failed to Unmarshal:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"ems.agt/lib/dborm"
|
||||
"ems.agt/lib/log"
|
||||
"ems.agt/restagent/config"
|
||||
"ems.agt/src/framework/cron"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
@@ -68,36 +69,22 @@ type SystemState struct {
|
||||
var client = resty.New()
|
||||
|
||||
func init() {
|
||||
/*
|
||||
client.
|
||||
SetTimeout(10 * time.Second).
|
||||
SetRetryCount(1).
|
||||
SetRetryWaitTime(1 * time.Second).
|
||||
SetRetryMaxWaitTime(2 * time.Second).
|
||||
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||
return 0, errors.New("quota exceeded")
|
||||
})
|
||||
*/
|
||||
client.
|
||||
SetTimeout(time.Duration(400 * time.Millisecond))
|
||||
// SetRetryCount(1).
|
||||
// SetRetryWaitTime(time.Duration(1 * time.Second)).
|
||||
// SetRetryMaxWaitTime(time.Duration(2 * time.Second))
|
||||
//client.SetTimeout(2 * time.Second)
|
||||
}
|
||||
|
||||
func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
var err error
|
||||
|
||||
s.count++
|
||||
// options := data.(cron.JobData)
|
||||
// // sysJob := options.SysJob
|
||||
// // var params BarParams
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
var params BarParams
|
||||
|
||||
// // // err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
// // // if err == nil {
|
||||
// // // duration = params.Duration
|
||||
// // // }
|
||||
_ = json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
// if err == nil {
|
||||
// duration = params.Duration
|
||||
// }
|
||||
|
||||
var nes []dborm.NeInfo
|
||||
_, err = dborm.XormGetAllNeInfo(&nes)
|
||||
@@ -112,7 +99,6 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
requestURI := fmt.Sprintf("/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", strings.ToLower(ne.NeType))
|
||||
requestURL := fmt.Sprintf("http://%s:%s%s", ne.Ip, ne.Port, requestURI)
|
||||
log.Debug("requestURL: Get", requestURL)
|
||||
client := resty.New()
|
||||
response, err := client.R().
|
||||
EnableTrace().
|
||||
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||
@@ -127,23 +113,27 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
log.Debug("StatusCode: ", response.StatusCode())
|
||||
switch response.StatusCode() {
|
||||
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||
log.Debug("response body:", string(response.Body()))
|
||||
log.Trace("response body:", string(response.Body()))
|
||||
state := new(SystemState)
|
||||
_ = json.Unmarshal(response.Body(), &state)
|
||||
var dateStr *string = nil
|
||||
if state.ExpiryDate != "" {
|
||||
dateStr = &state.ExpiryDate
|
||||
}
|
||||
neState := new(dborm.NeState)
|
||||
neState.NeType = ne.NeType
|
||||
neState.NeId = ne.NeId
|
||||
neState.Version = state.Version
|
||||
neState.Capability = state.Capability
|
||||
neState.SerialNum = state.SerialNum
|
||||
neState.ExpiryDate = state.ExpiryDate
|
||||
neState.ExpiryDate = *dateStr
|
||||
cu, _ := json.Marshal(state.CpuUsage)
|
||||
neState.CpuUsage = string(cu)
|
||||
mu, _ := json.Marshal(state.MemUsage)
|
||||
neState.MemUsage = string(mu)
|
||||
ds, _ := json.Marshal(state.DiskSpace)
|
||||
neState.DiskSpace = string(ds)
|
||||
log.Debug("neState:", neState)
|
||||
log.Trace("neState:", neState)
|
||||
_, err := dborm.XormInsertNeState(neState)
|
||||
if err != nil {
|
||||
log.Error("Failed to insert ne_state:", err)
|
||||
@@ -152,7 +142,7 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
}
|
||||
succNum++
|
||||
default:
|
||||
log.Debug("response body:", string(response.Body()))
|
||||
log.Trace("response body:", string(response.Body()))
|
||||
body := new(map[string]interface{})
|
||||
_ = json.Unmarshal(response.Body(), &body)
|
||||
failNum++
|
||||
|
||||
@@ -165,6 +165,14 @@ func (s *SysJobController) Edit(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
job := s.sysJobService.SelectJobById(body.JobID)
|
||||
if job.JobID != body.JobID {
|
||||
// 没有可访问调度任务数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "job.noData")))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查属性值唯一
|
||||
uniqueJob := s.sysJobService.CheckUniqueJobName(body.JobName, body.JobGroup, body.JobID)
|
||||
if !uniqueJob {
|
||||
@@ -174,6 +182,19 @@ func (s *SysJobController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, job.JobName)
|
||||
if i18nValue != job.JobName {
|
||||
i18n.UpdateKeyValue(language, job.JobName, body.JobName)
|
||||
body.JobName = job.JobName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, job.Remark)
|
||||
if i18nValue2 != job.Remark {
|
||||
i18n.UpdateKeyValue(language, job.Remark, body.Remark)
|
||||
body.Remark = job.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysJobService.UpdateJob(body)
|
||||
if rows > 0 {
|
||||
@@ -244,8 +265,8 @@ func (s *SysJobController) Status(c *gin.Context) {
|
||||
// 更新状态
|
||||
job.Status = body.Status
|
||||
job.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
ok := s.sysJobService.ChangeStatus(job)
|
||||
if ok {
|
||||
rows := s.sysJobService.UpdateJob(job)
|
||||
if rows > 0 {
|
||||
c.JSON(200, result.Ok(nil))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ type SysJobLogController struct {
|
||||
func (s *SysJobLogController) List(c *gin.Context) {
|
||||
// 查询参数转换map
|
||||
querys := ctx.QueryMap(c)
|
||||
// 任务ID优先级更高
|
||||
if v, ok := querys["jobId"]; ok && v != nil {
|
||||
jobInfo := service.NewSysJobImpl.SelectJobById(v.(string))
|
||||
querys["jobName"] = jobInfo.JobName
|
||||
querys["jobGroup"] = jobInfo.JobGroup
|
||||
}
|
||||
data := s.sysJobLogService.SelectJobLogPage(querys)
|
||||
|
||||
rows := data["rows"].([]model.SysJobLog)
|
||||
|
||||
@@ -59,7 +59,7 @@ func (r *SysJobLogImpl) SelectJobLogPage(query map[string]any) map[string]any {
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["jobName"]; ok && v != "" {
|
||||
conditions = append(conditions, "job_name like concat(?, '%')")
|
||||
conditions = append(conditions, "job_name = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["jobGroup"]; ok && v != "" {
|
||||
|
||||
@@ -27,9 +27,6 @@ type ISysJob interface {
|
||||
// DeleteJobByIds 批量删除调度任务信息
|
||||
DeleteJobByIds(jobIds []string) (int64, error)
|
||||
|
||||
// ChangeStatus 任务调度状态修改
|
||||
ChangeStatus(sysJob model.SysJob) bool
|
||||
|
||||
// RunQueueJob 立即运行一次调度任务
|
||||
RunQueueJob(sysJob model.SysJob) bool
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ func (r *SysJobImpl) DeleteJobByIds(jobIds []string) (int64, error) {
|
||||
jobs := r.sysJobRepository.SelectJobByIds(jobIds)
|
||||
if len(jobs) <= 0 {
|
||||
// 没有可访问调度任务数据!
|
||||
return 0, fmt.Errorf("There is no accessible scheduling task data!")
|
||||
return 0, fmt.Errorf("there is no accessible scheduling task data")
|
||||
}
|
||||
if len(jobs) == len(jobIds) {
|
||||
// 清除任务
|
||||
@@ -97,30 +97,7 @@ func (r *SysJobImpl) DeleteJobByIds(jobIds []string) (int64, error) {
|
||||
return rows, nil
|
||||
}
|
||||
// 删除调度任务信息失败!
|
||||
return 0, fmt.Errorf("Failed to delete scheduling task information!")
|
||||
}
|
||||
|
||||
// ChangeStatus 任务调度状态修改
|
||||
func (r *SysJobImpl) ChangeStatus(sysJob model.SysJob) bool {
|
||||
// 更新状态
|
||||
newSysJob := model.SysJob{
|
||||
JobID: sysJob.JobID,
|
||||
Status: sysJob.Status,
|
||||
UpdateBy: sysJob.UpdateBy,
|
||||
}
|
||||
rows := r.sysJobRepository.UpdateJob(newSysJob)
|
||||
if rows > 0 {
|
||||
//状态正常添加队列任务
|
||||
if sysJob.Status == common.STATUS_YES {
|
||||
r.insertQueueJob(sysJob, true)
|
||||
}
|
||||
// 状态禁用删除队列任务
|
||||
if sysJob.Status == common.STATUS_NO {
|
||||
r.deleteQueueJob(sysJob)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return 0, fmt.Errorf("failed to delete scheduling task information")
|
||||
}
|
||||
|
||||
// ResetQueueJob 重置初始调度任务
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"ems.agt/src/framework/i18n"
|
||||
"ems.agt/src/framework/utils/ctx"
|
||||
"ems.agt/src/framework/utils/parse"
|
||||
@@ -23,6 +25,9 @@ type NeInfoController struct {
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
|
||||
// neStateCacheMap 网元状态缓存最后一次成功的信息
|
||||
var neStateCacheMap map[string]map[string]any = make(map[string]map[string]any)
|
||||
|
||||
// 网元状态
|
||||
//
|
||||
// GET /state
|
||||
@@ -42,14 +47,31 @@ func (s *NeInfoController) NeState(c *gin.Context) {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
neKey := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
|
||||
|
||||
// 网元直连
|
||||
resData, err := neService.NeState(neInfo)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg("connection failure"))
|
||||
// 异常取上次缓存
|
||||
if v, ok := neStateCacheMap[neKey]; ok && v != nil {
|
||||
v["online"] = false
|
||||
neStateCacheMap[neKey] = v
|
||||
} else {
|
||||
neStateCacheMap[neKey] = map[string]any{
|
||||
"online": false,
|
||||
"neId": neInfo.NeId,
|
||||
"neName": neInfo.NeName,
|
||||
"neType": neInfo.NeType,
|
||||
"neIP": neInfo.IP,
|
||||
}
|
||||
}
|
||||
c.JSON(200, result.OkData(neStateCacheMap[neKey]))
|
||||
return
|
||||
}
|
||||
|
||||
// 存入缓存
|
||||
resData["online"] = true
|
||||
neStateCacheMap[neKey] = resData
|
||||
c.JSON(200, result.OkData(resData))
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("bad authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
|
||||
msg := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
|
||||
|
||||
// 发送MML
|
||||
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
|
||||
|
||||
@@ -216,7 +216,7 @@ func (s *UDMSubController) Adds(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("bad udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
|
||||
msg := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
|
||||
body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
|
||||
// static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增
|
||||
if body.StaticIp != "" {
|
||||
|
||||
@@ -135,7 +135,7 @@ func (r *NeInfoImpl) SelectNeList(ne model.NeInfo) []model.NeInfo {
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc "
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc, ne_id desc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
|
||||
@@ -52,8 +52,14 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) [
|
||||
"min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName",
|
||||
}
|
||||
for _, kid := range kpiIds {
|
||||
str := fmt.Sprintf("sum(CASE WHEN gk.kpi_id = '%s' THEN gk.value ELSE 0 END) AS '%s'", kid, kid)
|
||||
fields = append(fields, str)
|
||||
// 特殊字段,只取最后一次收到的非0值
|
||||
if kid == "AMF.01" || kid == "UDM.01" || kid == "UDM.02" || kid == "UDM.03" {
|
||||
str := fmt.Sprintf("IFNULL(SUBSTRING_INDEX(GROUP_CONCAT( CASE WHEN gk.kpi_id = '%s' and gk.VALUE != 0 THEN gk.VALUE END ), ',', 1), 0) AS '%s'", kid, kid)
|
||||
fields = append(fields, str)
|
||||
} else {
|
||||
str := fmt.Sprintf("sum(CASE WHEN gk.kpi_id = '%s' THEN gk.value ELSE 0 END) AS '%s'", kid, kid)
|
||||
fields = append(fields, str)
|
||||
}
|
||||
}
|
||||
fieldsSql := strings.Join(fields, ",")
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
func NeState(neInfo model.NeInfo) (map[string]any, error) {
|
||||
// 网元直连
|
||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
|
||||
resBytes, err := fetch.Get(neUrl, nil, 1)
|
||||
resBytes, err := fetch.Get(neUrl, nil, 200)
|
||||
if err != nil {
|
||||
logger.Warnf("NeState %s", err.Error())
|
||||
return nil, err
|
||||
@@ -33,6 +33,7 @@ func NeState(neInfo model.NeInfo) (map[string]any, error) {
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"neName": neInfo.NeName,
|
||||
"neIP": neInfo.IP,
|
||||
"refreshTime": time.Now().UnixMilli(), // 获取时间
|
||||
"version": resData["version"],
|
||||
"capability": resData["capability"],
|
||||
|
||||
@@ -128,13 +128,32 @@ func (s *SysConfigController) Edit(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
config := s.sysConfigService.SelectConfigById(body.ConfigID)
|
||||
if config.ConfigID != body.ConfigID {
|
||||
configInfo := s.sysConfigService.SelectConfigById(body.ConfigID)
|
||||
if configInfo.ConfigID != body.ConfigID {
|
||||
// 没有可访问参数配置数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "config.noData")))
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, configInfo.ConfigName)
|
||||
if i18nValue != configInfo.ConfigName {
|
||||
i18n.UpdateKeyValue(language, configInfo.ConfigName, body.ConfigName)
|
||||
body.ConfigName = configInfo.ConfigName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, configInfo.ConfigValue)
|
||||
if i18nValue2 != configInfo.ConfigValue {
|
||||
i18n.UpdateKeyValue(language, configInfo.ConfigValue, body.ConfigValue)
|
||||
body.ConfigValue = configInfo.ConfigValue
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue3 := i18n.TKey(language, configInfo.Remark)
|
||||
if i18nValue3 != configInfo.Remark {
|
||||
i18n.UpdateKeyValue(language, configInfo.Remark, body.Remark)
|
||||
body.Remark = configInfo.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysConfigService.UpdateConfig(body)
|
||||
if rows > 0 {
|
||||
@@ -262,7 +281,7 @@ func (s *SysConfigController) Export(c *gin.Context) {
|
||||
|
||||
// 参数配置修改配置参数
|
||||
//
|
||||
// PUT /changeConfigValue
|
||||
// PUT /changeValue
|
||||
func (s *SysConfigController) ConfigValue(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
@@ -282,13 +301,21 @@ func (s *SysConfigController) ConfigValue(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 与旧值相等不变更
|
||||
if info.ConfigValue == body.Value {
|
||||
// 与旧值相等 不变更
|
||||
i18nValue := i18n.TKey(language, info.ConfigValue)
|
||||
if i18nValue == body.Value {
|
||||
// 变更状态与旧值相等!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "config.errValueEq")))
|
||||
return
|
||||
}
|
||||
info.ConfigValue = body.Value
|
||||
|
||||
// 多语言非原始值
|
||||
if i18nValue != info.ConfigValue {
|
||||
i18n.UpdateKeyValue(language, info.ConfigValue, body.Value)
|
||||
} else {
|
||||
info.ConfigValue = body.Value
|
||||
}
|
||||
|
||||
info.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysConfigService.UpdateConfig(info)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -201,6 +201,13 @@ func (s *SysDeptController) Edit(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, deptInfo.DeptName)
|
||||
if i18nValue != deptInfo.DeptName {
|
||||
i18n.UpdateKeyValue(language, deptInfo.DeptName, body.DeptName)
|
||||
body.DeptName = deptInfo.DeptName
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysDeptService.UpdateDept(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -140,8 +140,8 @@ func (s *SysDictDataController) Edit(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 检查字典编码是否存在
|
||||
SysDictDataController := s.sysDictDataService.SelectDictDataByCode(body.DictCode)
|
||||
if SysDictDataController.DictCode != body.DictCode {
|
||||
sysDictData := s.sysDictDataService.SelectDictDataByCode(body.DictCode)
|
||||
if sysDictData.DictCode != body.DictCode {
|
||||
// 没有可访问字典编码数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "dictData.noData")))
|
||||
return
|
||||
@@ -156,6 +156,19 @@ func (s *SysDictDataController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, sysDictData.DictLabel)
|
||||
if i18nValue != sysDictData.DictLabel {
|
||||
i18n.UpdateKeyValue(language, sysDictData.DictLabel, body.DictLabel)
|
||||
body.DictLabel = sysDictData.DictLabel
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, sysDictData.Remark)
|
||||
if i18nValue2 != sysDictData.Remark {
|
||||
i18n.UpdateKeyValue(language, sysDictData.Remark, body.Remark)
|
||||
body.Remark = sysDictData.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysDictDataService.UpdateDictData(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -151,6 +151,19 @@ func (s *SysDictTypeController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, dictInfo.DictName)
|
||||
if i18nValue != dictInfo.DictName {
|
||||
i18n.UpdateKeyValue(language, dictInfo.DictName, body.DictName)
|
||||
body.DictName = dictInfo.DictName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, dictInfo.Remark)
|
||||
if i18nValue2 != dictInfo.Remark {
|
||||
i18n.UpdateKeyValue(language, dictInfo.Remark, body.Remark)
|
||||
body.Remark = dictInfo.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysDictTypeService.UpdateDictType(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -216,6 +216,19 @@ func (s *SysMenuController) Edit(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, menuInfo.MenuName)
|
||||
if i18nValue != menuInfo.MenuName {
|
||||
i18n.UpdateKeyValue(language, menuInfo.MenuName, body.MenuName)
|
||||
body.MenuName = menuInfo.MenuName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, menuInfo.Remark)
|
||||
if i18nValue2 != menuInfo.Remark {
|
||||
i18n.UpdateKeyValue(language, menuInfo.Remark, body.Remark)
|
||||
body.Remark = menuInfo.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysMenuService.UpdateMenu(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -125,8 +125,8 @@ func (s *SysPostController) Edit(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
post := s.sysPostService.SelectPostById(body.PostID)
|
||||
if post.PostID != body.PostID {
|
||||
postInfo := s.sysPostService.SelectPostById(body.PostID)
|
||||
if postInfo.PostID != body.PostID {
|
||||
// 没有可访问岗位数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "post.noData")))
|
||||
return
|
||||
@@ -150,6 +150,19 @@ func (s *SysPostController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, postInfo.PostName)
|
||||
if i18nValue != postInfo.PostName {
|
||||
i18n.UpdateKeyValue(language, postInfo.PostName, body.PostName)
|
||||
body.PostName = postInfo.PostName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, postInfo.Remark)
|
||||
if i18nValue2 != postInfo.Remark {
|
||||
i18n.UpdateKeyValue(language, postInfo.Remark, body.Remark)
|
||||
body.Remark = postInfo.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysPostService.UpdatePost(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -139,8 +139,8 @@ func (s *SysRoleController) Edit(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
role := s.sysRoleService.SelectRoleById(body.RoleID)
|
||||
if role.RoleID != body.RoleID {
|
||||
roleInfo := s.sysRoleService.SelectRoleById(body.RoleID)
|
||||
if roleInfo.RoleID != body.RoleID {
|
||||
// 没有可访问角色数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "role.noData")))
|
||||
return
|
||||
@@ -166,6 +166,19 @@ func (s *SysRoleController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 多语言非原始值
|
||||
i18nValue := i18n.TKey(language, roleInfo.RoleName)
|
||||
if i18nValue != roleInfo.RoleName {
|
||||
i18n.UpdateKeyValue(language, roleInfo.RoleName, body.RoleName)
|
||||
body.RoleName = roleInfo.RoleName
|
||||
}
|
||||
// 多语言非原始值
|
||||
i18nValue2 := i18n.TKey(language, roleInfo.Remark)
|
||||
if i18nValue2 != roleInfo.Remark {
|
||||
i18n.UpdateKeyValue(language, roleInfo.Remark, body.Remark)
|
||||
body.Remark = roleInfo.Remark
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
rows := s.sysRoleService.UpdateRole(body)
|
||||
if rows > 0 {
|
||||
|
||||
@@ -70,6 +70,10 @@ func (s *TcpdumpController) NeTask(c *gin.Context) {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
if strings.Contains(msg, "command not found") {
|
||||
c.JSON(200, result.ErrMsg("Command [tcpdump] Not Found"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(map[string]any{
|
||||
"cmd": cmdStr,
|
||||
@@ -211,6 +215,14 @@ func (s *TcpdumpController) NeUPFTask(c *gin.Context) {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
if strings.Contains(msg, "command not found") {
|
||||
c.JSON(200, result.ErrMsg("Command [expect] Not Found"))
|
||||
return
|
||||
}
|
||||
if strings.Contains(msg, "Unable to connect to remote host") {
|
||||
c.JSON(200, result.ErrMsg("Connection Refused"))
|
||||
return
|
||||
}
|
||||
s := strings.Index(msg, "pcap dispatch trace:")
|
||||
if s != -1 {
|
||||
e := strings.Index(msg, "\r\nupfd1#")
|
||||
@@ -243,6 +255,14 @@ func (s *TcpdumpController) NeUPFTask(c *gin.Context) {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
if strings.Contains(msg, "command not found") {
|
||||
c.JSON(200, result.ErrMsg("Command [expect] Not Found"))
|
||||
return
|
||||
}
|
||||
if strings.Contains(msg, "Unable to connect to remote host") {
|
||||
c.JSON(200, result.ErrMsg("Connection Refused"))
|
||||
return
|
||||
}
|
||||
s := strings.Index(msg, "pcap dispatch trace:")
|
||||
if s == -1 {
|
||||
s = strings.Index(msg, "Write ")
|
||||
|
||||
Reference in New Issue
Block a user