feat: 添加oam模块
This commit is contained in:
31
go.mod
31
go.mod
@@ -4,6 +4,7 @@ go 1.24
|
||||
|
||||
require (
|
||||
github.com/dlclark/regexp2 v1.11.4
|
||||
github.com/expr-lang/expr v1.17.6
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
github.com/go-resty/resty/v2 v2.14.0
|
||||
@@ -24,13 +25,14 @@ require (
|
||||
github.com/prometheus-community/pro-bing v0.7.0
|
||||
github.com/redis/go-redis/v9 v9.12.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v4 v4.24.12
|
||||
github.com/shirou/gopsutil/v4 v4.25.6
|
||||
github.com/slayercat/GoSNMPServer v0.5.2
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.4
|
||||
github.com/tsmask/go-oam v1.0.9
|
||||
github.com/wneessen/go-mail v0.6.2
|
||||
github.com/xuri/excelize/v2 v2.9.0
|
||||
github.com/xuri/xgen v0.0.0-20240722131518-d0691b701898
|
||||
@@ -56,10 +58,11 @@ require (
|
||||
github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/creack/pty v1.1.24 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
@@ -72,11 +75,11 @@ require (
|
||||
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.22.0
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
@@ -91,11 +94,9 @@ require (
|
||||
github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
|
||||
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/metaleap/go-util v0.0.0-20180330192724-a09253046f73 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
@@ -103,7 +104,7 @@ require (
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.21.1 // indirect
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/client_golang v1.20.0
|
||||
@@ -112,14 +113,13 @@ require (
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.4 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect; indirect // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.11 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect; indirect // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect; indirect // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect; indirect // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect; indirect // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect; indirect // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect; indirect // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect; indirect // indirect
|
||||
github.com/tebeka/strftime v0.1.5 // indirect
|
||||
@@ -135,12 +135,11 @@ require (
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||
golang.org/x/image v0.19.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
golang.org/x/tools/cmd/guru v0.1.1-deprecated // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
xorm.io/builder v0.3.13 // indirect
|
||||
)
|
||||
|
||||
76
go.sum
76
go.sum
@@ -29,26 +29,29 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/expr-lang/expr v1.17.6 h1:1h6i8ONk9cexhDmowO/A64VPxHScu7qfSl2k8OlINec=
|
||||
github.com/expr-lang/expr v1.17.6/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU=
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
@@ -88,6 +91,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
@@ -110,8 +115,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -127,8 +133,6 @@ github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc=
|
||||
github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
@@ -185,8 +189,6 @@ github.com/linxGnu/gosmpp v0.3.0/go.mod h1:Ba6SULQql3IbF2A5Mtj3DqMKoFbx1pEz/8xyi
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU669bE=
|
||||
@@ -199,8 +201,6 @@ github.com/metaleap/go-util v0.0.0-20180330192724-a09253046f73 h1:4vKVhAdype/dej
|
||||
github.com/metaleap/go-util v0.0.0-20180330192724-a09253046f73/go.mod h1:l71/5fppWP5A6nqhcxz6wQAYok6pr/vM2+KHIy50/LY=
|
||||
github.com/metaleap/go-xsd v0.0.0-20180330193350-61f7638f502f h1:eeJGcYszuvOpmuJxeq57LaOO8mJurfjpOHJJMfQSD0s=
|
||||
github.com/metaleap/go-xsd v0.0.0-20180330193350-61f7638f502f/go.mod h1:WK3zEKtwVd/v+NM3lh1ZE6MdDfHsdOFFOD5Ezi4Hutg=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -231,15 +231,14 @@ github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
@@ -268,14 +267,12 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ=
|
||||
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
||||
github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
|
||||
github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@@ -287,19 +284,18 @@ github.com/slayercat/GoSNMPServer v0.5.2 h1:IK2d3kz6JoiYHbAZT5H7hrQQRzAD7rxF0iJZ
|
||||
github.com/slayercat/GoSNMPServer v0.5.2/go.mod h1:6taMSIwudR+7pKRO6dz2U+xoNccZds8eiMVlEN66fXY=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
@@ -308,7 +304,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
@@ -329,6 +324,8 @@ github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYN
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/tsmask/go-oam v1.0.9 h1:6g3rpMwSu0x8mzvq4QdMZgbABvMo3ek2D0x18Ecm7uU=
|
||||
github.com/tsmask/go-oam v1.0.9/go.mod h1:HqFtN0LA9BiR1HWyHO++DY0fyYTl2sKVnRrZzuWy9n4=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
@@ -417,8 +414,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -478,8 +475,9 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -503,8 +501,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -513,8 +511,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
var NewIMS = &IMSController{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
cdrEventService: neDataService.NewCDREventIMS,
|
||||
kpiReportService: neDataService.NewPerfKPI,
|
||||
kpiReportService: neDataService.NewKpiReport,
|
||||
}
|
||||
|
||||
// 网元IMS
|
||||
@@ -37,7 +37,7 @@ var NewIMS = &IMSController{
|
||||
type IMSController struct {
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
cdrEventService *neDataService.CDREventIMS // CDR会话事件服务
|
||||
kpiReportService *neDataService.PerfKPI // 统计信息服务
|
||||
kpiReportService *neDataService.KpiReport // 统计信息服务
|
||||
}
|
||||
|
||||
// CDR会话列表
|
||||
|
||||
@@ -12,15 +12,15 @@ import (
|
||||
// 实例化控制层 UPFController 结构体
|
||||
var NewUPF = &UPFController{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
perfKPIService: neDataService.NewPerfKPI,
|
||||
perfKPIService: neDataService.NewKpiReport,
|
||||
}
|
||||
|
||||
// 网元UPF
|
||||
//
|
||||
// PATH /upf
|
||||
type UPFController struct {
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
perfKPIService *neDataService.PerfKPI // 统计信息服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
perfKPIService *neDataService.KpiReport // 统计信息服务
|
||||
}
|
||||
|
||||
// 总流量数 N3上行 N6下行
|
||||
|
||||
46
src/modules/network_data/model/alarm_event.go
Normal file
46
src/modules/network_data/model/alarm_event.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// AlarmEvent 告警_事件记录表
|
||||
type AlarmEvent struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // 网元ID
|
||||
AlarmSeq string `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 同网元类型连续递增
|
||||
AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID
|
||||
AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题
|
||||
AlarmCode string `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码
|
||||
EventTime time.Time `json:"eventTime" gorm:"column:event_time"` // 事件产生时间
|
||||
ObjectUid string `json:"objectUid" gorm:"column:object_uid"` // 对象ID
|
||||
ObjectName string `json:"objectName" gorm:"column:object_name"` // 对象名称
|
||||
ObjectType string `json:"objectType" gorm:"column:object_type"` // 对象类型
|
||||
LocationInfo string `json:"locationInfo" gorm:"column:location_info"` // 告警定位信息
|
||||
AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态
|
||||
SpecificProblem string `json:"specificProblem" gorm:"column:specific_problem"` // 告警问题原因
|
||||
SpecificProblemId string `json:"specificProblemId" gorm:"column:specific_problem_id"` // 告警问题原因ID
|
||||
AddInfo string `json:"addInfo" gorm:"column:add_info"` // 告警辅助信息
|
||||
ClearType string `json:"clearType" gorm:"column:clear_type"` // 清除状态
|
||||
ClearTime time.Time `json:"clearTime" gorm:"column:clear_time"` // 清除时间
|
||||
ClearUser string `json:"clearUser" gorm:"column:clear_user"` // 清除用户
|
||||
Timestamp time.Time `json:"timestamp" gorm:"column:timestamp"` // 创建时间
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*AlarmEvent) TableName() string {
|
||||
return "alarm_event"
|
||||
}
|
||||
|
||||
// AlarmEventQuery 告警事件数据查询参数结构体
|
||||
type AlarmEventQuery struct {
|
||||
NeType string `json:"neType" form:"neType"` // 网元类型
|
||||
NeID string `json:"neId" form:"neId"` // 网元ID
|
||||
AlarmCode string `json:"alarmCode" form:"alarmCode"`
|
||||
AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=Clear Active"` // 告警状态
|
||||
BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time
|
||||
EndTime int64 `json:"endTime" form:"endTime"`
|
||||
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段
|
||||
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc
|
||||
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
|
||||
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
|
||||
}
|
||||
39
src/modules/network_data/model/alarm_forward_log.go
Normal file
39
src/modules/network_data/model/alarm_forward_log.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// AlarmForwardLog 告警_转发日志记录
|
||||
type AlarmForwardLog struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"`
|
||||
NeId string `json:"neId" gorm:"column:ne_id"`
|
||||
AlarmSeq string `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 连续递增
|
||||
AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID
|
||||
AlarmCode string `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码
|
||||
AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题
|
||||
AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态
|
||||
AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型
|
||||
OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度
|
||||
EventTime time.Time `json:"eventTime" gorm:"column:event_time"` // 事件产生时间
|
||||
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at"` // 创建时间
|
||||
Type string `json:"type" gorm:"column:type"` // 转发方式 SMS/EMAIL/SMSC
|
||||
Target string `json:"target" gorm:"column:target"` // 发送目标用户
|
||||
Result string `json:"result" gorm:"column:result"` // 发送结果
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*AlarmForwardLog) TableName() string {
|
||||
return "alarm_forward_log"
|
||||
}
|
||||
|
||||
// AlarmForwardLogQuery 告警转发日志数据查询参数结构体
|
||||
type AlarmForwardLogQuery struct {
|
||||
NeType string `json:"neType" form:"neType"` // 网元类型
|
||||
NeID string `json:"neId" form:"neId"` // 网元ID
|
||||
BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间
|
||||
EndTime int64 `json:"endTime" form:"endTime"`
|
||||
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段
|
||||
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc
|
||||
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
|
||||
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
|
||||
}
|
||||
38
src/modules/network_data/model/alarm_log.go
Normal file
38
src/modules/network_data/model/alarm_log.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// AlarmLog 告警_日志记录
|
||||
type AlarmLog struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"`
|
||||
NeId string `json:"neId" gorm:"column:ne_id"`
|
||||
AlarmSeq string `json:"alarmSeq" gorm:"column:alarm_seq"` // 告警序号 连续递增
|
||||
AlarmId string `json:"alarmId" gorm:"column:alarm_id"` // 告警ID
|
||||
AlarmCode string `json:"alarmCode" gorm:"column:alarm_code"` // 告警状态码
|
||||
AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` // 告警标题
|
||||
AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 告警状态
|
||||
AlarmType string `json:"alarmType" gorm:"column:alarm_type"` // 告警类型
|
||||
OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 严重程度
|
||||
EventTime time.Time `json:"eventTime" gorm:"column:event_time"` // 事件产生时间
|
||||
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at"` // 创建时间
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*AlarmLog) TableName() string {
|
||||
return "alarm_log"
|
||||
}
|
||||
|
||||
// AlarmLogQuery 告警日志数据查询参数结构体
|
||||
type AlarmLogQuery struct {
|
||||
NeType string `json:"neType" form:"neType"` // 网元类型
|
||||
NeID string `json:"neId" form:"neId"` // 网元ID
|
||||
AlarmStatus string `json:"alarmStatus" form:"alarmStatus" binding:"omitempty,oneof=Clear Active"` // 告警状态
|
||||
OrigSeverity string `json:"origSeverity" form:"origSeverity"` // 告警类型
|
||||
BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查event_time
|
||||
EndTime int64 `json:"endTime" form:"endTime"`
|
||||
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=event_time id"` // 排序字段,填写结果字段
|
||||
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc
|
||||
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
|
||||
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
|
||||
}
|
||||
112
src/modules/network_data/model/cbc_message.go
Normal file
112
src/modules/network_data/model/cbc_message.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CBCEventStatus int
|
||||
|
||||
// CBCEventStatus CB事件状态枚举
|
||||
const (
|
||||
CBCEventStatusNull CBCEventStatus = iota // 未知状态
|
||||
CBCEventStatusActive
|
||||
CBCEventStatusInactive
|
||||
)
|
||||
|
||||
func (status CBCEventStatus) Enum() string {
|
||||
switch status {
|
||||
case CBCEventStatusNull:
|
||||
return "NULL"
|
||||
case CBCEventStatusActive:
|
||||
return "ACTIVE"
|
||||
case CBCEventStatusInactive:
|
||||
return "INACTIVE"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
func (status CBCEventStatus) String() string {
|
||||
return fmt.Sprintf("%d", status)
|
||||
}
|
||||
|
||||
// ParseCBCEventStatus 将字符串转换为 枚举类型
|
||||
func ParseCBCEventStatus(s string) CBCEventStatus {
|
||||
if i, err := strconv.Atoi(s); err == nil {
|
||||
return CBCEventStatus(i)
|
||||
}
|
||||
// 如果转换失败,则按名称匹配(忽略大小写)
|
||||
switch strings.ToUpper(s) {
|
||||
case "NULL":
|
||||
return CBCEventStatusNull
|
||||
case "ACTIVE":
|
||||
return CBCEventStatusActive
|
||||
case "INACTIVE":
|
||||
return CBCEventStatusInactive
|
||||
case "":
|
||||
// 如果字符串为空,则返回未知状态
|
||||
return CBCEventStatusNull
|
||||
default:
|
||||
// 默认返回未知状态
|
||||
return CBCEventStatusNull
|
||||
}
|
||||
}
|
||||
|
||||
// CBCMessageQuery 查询条件结构体
|
||||
type CBCMessageQuery struct {
|
||||
NeType string `form:"neType"` // 网元类型
|
||||
NeId string `form:"neId"` // 网元ID
|
||||
EventName string `form:"eventName"` // 事件名称
|
||||
Status string `form:"status"` // 消息状态
|
||||
StartTime string `form:"startTime"` // 创建时间范围-起始
|
||||
EndTime string `form:"endTime"` // 创建时间范围-结束
|
||||
PageNum int `form:"pageNum" binding:"required"`
|
||||
PageSize int `form:"pageSize" binding:"required"`
|
||||
}
|
||||
|
||||
// @Description CBCMessage CB消息
|
||||
type CBCMessage struct {
|
||||
Id int64 `json:"id" gorm:"column:id"` // CB消息ID
|
||||
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // 网元ID
|
||||
MessageJson json.RawMessage `json:"messageJson" gorm:"column:message_json"` // 消息内容JSON
|
||||
Status CBCEventStatus `json:"status" gorm:"column:status"` // 消息状态
|
||||
Detail string `json:"detail" gorm:"column:detail"` // 详情
|
||||
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间
|
||||
UpdatedAt int64 `json:"updatedAt" gorm:"column:updated_at"` // 更新时间
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*CBCMessage) TableName() string {
|
||||
return "cbc_message"
|
||||
}
|
||||
|
||||
// Scan 实现 sql.Scanner 接口,支持从数据库字符串转为 CBCEventStatus
|
||||
func (s *CBCEventStatus) Scan(value interface{}) error {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
*s = ParseCBCEventStatus(v)
|
||||
return nil
|
||||
case []byte:
|
||||
*s = ParseCBCEventStatus(string(v))
|
||||
return nil
|
||||
case int64:
|
||||
*s = CBCEventStatus(v)
|
||||
return nil
|
||||
case int:
|
||||
*s = CBCEventStatus(v)
|
||||
return nil
|
||||
default:
|
||||
return errors.New("unsupported Scan type for CBCEventStatus")
|
||||
}
|
||||
}
|
||||
|
||||
// Value 实现 driver.Valuer 接口,支持将 CBCEventStatus 存为字符串
|
||||
func (s CBCEventStatus) Value() (driver.Value, error) {
|
||||
return s.Enum(), nil
|
||||
}
|
||||
17
src/modules/network_data/model/cdr_event.go
Normal file
17
src/modules/network_data/model/cdr_event.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
// CDREvent CDR会话对象 cdr_event
|
||||
type CDREvent struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"`
|
||||
NeName string `json:"neName" gorm:"column:ne_name"`
|
||||
RmUid string `json:"rmUid" gorm:"column:rm_uid"` // 可能没有
|
||||
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳
|
||||
CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String
|
||||
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*CDREvent) TableName() string {
|
||||
return "cdr_event"
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package model
|
||||
|
||||
// GoldKPITitle 黄金指标标题信息对象 kpi_title
|
||||
type GoldKPITitle struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"`
|
||||
KPIID string `json:"kpiId" gorm:"column:kpi_id"`
|
||||
// KpiTitle 指标标题信息对象 kpi_title
|
||||
type KpiTitle struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
|
||||
KpiId string `json:"kpiId" gorm:"column:kpi_id"` // KPI标识
|
||||
TitleJson string `json:"titleJson" gorm:"column:title_json"`
|
||||
CnTitle string `json:"cnTitle" gorm:"column:cn_title"`
|
||||
EnTitle string `json:"enTitle" gorm:"column:en_title"`
|
||||
StatusFlag string `json:"statusFlag" gorm:"column:status_flag"`
|
||||
CnTitle string `json:"cnTitle" gorm:"column:cn_title"` // 中文名
|
||||
EnTitle string `json:"enTitle" gorm:"column:en_title"` // 英文名
|
||||
StatusFlag string `json:"statusFlag" gorm:"column:status_flag"` // 状态标识 1:启用 0:禁用
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*GoldKPITitle) TableName() string {
|
||||
func (*KpiTitle) TableName() string {
|
||||
return "kpi_title"
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ func (*KpiReport) TableName() string {
|
||||
return "kpi_report"
|
||||
}
|
||||
|
||||
// GoldKPIQuery 黄金指标查询参数结构体
|
||||
type GoldKPIQuery struct {
|
||||
// KPIQuery 指标查询参数结构体
|
||||
type KPIQuery struct {
|
||||
NeType string `form:"neType" binding:"required"`
|
||||
//NeID string `form:"neId" binding:"required"`
|
||||
NeID string `form:"neId"`
|
||||
19
src/modules/network_data/model/ue_event.go
Normal file
19
src/modules/network_data/model/ue_event.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package model
|
||||
|
||||
// UEEvent UE会话对象 ue_event
|
||||
type UEEvent struct {
|
||||
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
NeType string `json:"neType" gorm:"column:ne_type"`
|
||||
NeName string `json:"neName" gorm:"column:ne_name"`
|
||||
RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有
|
||||
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到时间
|
||||
EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型
|
||||
EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String
|
||||
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒
|
||||
TenantID string `json:"tenantID" gorm:"column:tenant_id"` // 租户ID
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*UEEvent) TableName() string {
|
||||
return "ue_event"
|
||||
}
|
||||
@@ -388,5 +388,5 @@ func Setup(router *gin.Engine) {
|
||||
// InitLoad 初始参数
|
||||
func InitLoad() {
|
||||
// 启动时,加载UPF上下行流量
|
||||
go service.NewPerfKPI.UPFTodayFlowLoad(30)
|
||||
go service.NewKpiReport.UPFTodayFlowLoad(30)
|
||||
}
|
||||
|
||||
169
src/modules/network_data/repository/alarm_event.go
Normal file
169
src/modules/network_data/repository/alarm_event.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmEvent 结构体
|
||||
var NewAlarmEvent = &AlarmEvent{}
|
||||
|
||||
// AlarmEvent 告警 数据层处理
|
||||
type AlarmEvent struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r AlarmEvent) SelectByPage(query model.AlarmEventQuery) ([]model.AlarmEvent, int64) {
|
||||
tx := db.DB("").Model(&model.AlarmEvent{})
|
||||
// 查询条件拼接
|
||||
if query.NeType != "" {
|
||||
tx = tx.Where("ne_type = ?", query.NeType)
|
||||
}
|
||||
if query.NeID != "" {
|
||||
tx = tx.Where("ne_id = ?", query.NeID)
|
||||
}
|
||||
if query.AlarmCode != "" {
|
||||
tx = tx.Where("alarm_code = ?", query.AlarmCode)
|
||||
}
|
||||
if query.AlarmStatus != "" {
|
||||
tx = tx.Where("alarm_status = ?", query.AlarmStatus)
|
||||
}
|
||||
if query.BeginTime != 0 {
|
||||
tx = tx.Where("event_time >= ?", query.BeginTime)
|
||||
}
|
||||
if query.EndTime != 0 {
|
||||
tx = tx.Where("event_time <= ?", query.EndTime)
|
||||
}
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.AlarmEvent{}
|
||||
|
||||
// 查询数量为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 排序
|
||||
if query.SortField != "" {
|
||||
sortField := query.SortField
|
||||
if query.SortOrder == "desc" {
|
||||
sortField = sortField + " desc"
|
||||
}
|
||||
tx = tx.Order(sortField)
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize)
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
err := tx.Find(&rows).Error
|
||||
if err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows, total
|
||||
}
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// Select 查询集合
|
||||
func (r AlarmEvent) Select(param model.AlarmEvent) []model.AlarmEvent {
|
||||
tx := db.DB("").Model(&model.AlarmEvent{})
|
||||
// 查询条件拼接
|
||||
if param.NeType != "" {
|
||||
tx = tx.Where("ne_type = ?", param.NeType)
|
||||
}
|
||||
if param.NeId != "" {
|
||||
tx = tx.Where("ne_id = ?", param.NeId)
|
||||
}
|
||||
if param.AlarmId != "" {
|
||||
tx = tx.Where("alarm_id = ?", param.AlarmId)
|
||||
}
|
||||
if param.AlarmCode != "" {
|
||||
tx = tx.Where("alarm_code = ?", param.AlarmCode)
|
||||
}
|
||||
if param.AlarmStatus != "" {
|
||||
tx = tx.Where("alarm_status = ?", param.AlarmStatus)
|
||||
}
|
||||
// 查询数据
|
||||
rows := []model.AlarmEvent{}
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r AlarmEvent) SelectByIds(ids []int64) []model.AlarmEvent {
|
||||
rows := []model.AlarmEvent{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
tx := db.DB("").Model(&model.AlarmEvent{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// Insert 新增信息 返回新增数据ID
|
||||
func (r AlarmEvent) Insert(param model.AlarmEvent) int64 {
|
||||
if param.Timestamp.IsZero() {
|
||||
param.Timestamp = time.Now()
|
||||
}
|
||||
// 执行插入
|
||||
if err := db.DB("").Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
|
||||
// Update 修改信息 返回受影响的行数
|
||||
func (r AlarmEvent) Update(param model.AlarmEvent) int64 {
|
||||
if param.ID <= 0 {
|
||||
return 0
|
||||
}
|
||||
tx := db.DB("").Model(&model.AlarmEvent{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id = ?", param.ID)
|
||||
tx = tx.Omit("id", "timestamp")
|
||||
// 执行更新
|
||||
if err := tx.Updates(param).Error; err != nil {
|
||||
logger.Errorf("update err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r AlarmEvent) DeleteByIds(ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
tx := db.DB("").Where("id in ?", ids)
|
||||
if err := tx.Delete(&model.AlarmEvent{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// SelectAlarmEventSeqLast 查询网元告警最后一条序号
|
||||
func (r AlarmEvent) SelectAlarmEventSeqLast(neType, neId string) int64 {
|
||||
tx := db.DB("").Model(&model.AlarmEvent{})
|
||||
tx = tx.Where("ne_type=? and ne_id=?", neType, neId)
|
||||
tx = tx.Select("alarm_seq").Order("alarm_seq DESC")
|
||||
// 查询数据
|
||||
var AlarmEventSeq int64 = 0
|
||||
if err := tx.Limit(1).Find(&AlarmEventSeq).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return AlarmEventSeq
|
||||
}
|
||||
return AlarmEventSeq
|
||||
}
|
||||
104
src/modules/network_data/repository/alarm_forward_log.go
Normal file
104
src/modules/network_data/repository/alarm_forward_log.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmForwardLog 结构体
|
||||
var NewAlarmForwardLog = &AlarmForwardLog{}
|
||||
|
||||
// AlarmForwardLog 告警转发记录表 数据层处理
|
||||
type AlarmForwardLog struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r AlarmForwardLog) SelectByPage(query model.AlarmForwardLogQuery) ([]model.AlarmForwardLog, int64) {
|
||||
tx := db.DB("").Model(&model.AlarmForwardLog{})
|
||||
// 查询条件拼接
|
||||
if query.NeType != "" {
|
||||
tx = tx.Where("ne_type = ?", query.NeType)
|
||||
}
|
||||
if query.NeID != "" {
|
||||
tx = tx.Where("ne_id = ?", query.NeID)
|
||||
}
|
||||
if query.BeginTime != 0 {
|
||||
tx = tx.Where("created_at >= ?", query.BeginTime)
|
||||
}
|
||||
if query.EndTime != 0 {
|
||||
tx = tx.Where("created_at <= ?", query.EndTime)
|
||||
}
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.AlarmForwardLog{}
|
||||
|
||||
// 查询数量为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 排序
|
||||
if query.SortField != "" {
|
||||
sortField := query.SortField
|
||||
if query.SortOrder == "desc" {
|
||||
sortField = sortField + " desc"
|
||||
}
|
||||
tx = tx.Order(sortField)
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize)
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
err := tx.Find(&rows).Error
|
||||
if err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows, total
|
||||
}
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r AlarmForwardLog) SelectByIds(ids []int64) []model.AlarmForwardLog {
|
||||
rows := []model.AlarmForwardLog{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
tx := db.DB("").Model(&model.AlarmForwardLog{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r AlarmForwardLog) DeleteByIds(ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
tx := db.DB("").Where("id in ?", ids)
|
||||
if err := tx.Delete(&model.AlarmForwardLog{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r AlarmForwardLog) Insert(param model.AlarmForwardLog) int64 {
|
||||
if param.CreatedAt.IsZero() {
|
||||
param.CreatedAt = time.Now()
|
||||
}
|
||||
// 执行插入
|
||||
if err := db.DB("").Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
107
src/modules/network_data/repository/alarm_log.go
Normal file
107
src/modules/network_data/repository/alarm_log.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmLog 结构体
|
||||
var NewAlarmLog = &AlarmLog{}
|
||||
|
||||
// AlarmLog 基站状态记录表 数据层处理
|
||||
type AlarmLog struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r AlarmLog) SelectByPage(query model.AlarmLogQuery) ([]model.AlarmLog, int64) {
|
||||
tx := db.DB("").Model(&model.AlarmLog{})
|
||||
// 查询条件拼接
|
||||
if query.NeType != "" {
|
||||
tx = tx.Where("ne_type = ?", query.NeType)
|
||||
}
|
||||
if query.NeID != "" {
|
||||
tx = tx.Where("ne_id = ?", query.NeID)
|
||||
}
|
||||
if query.AlarmStatus != "" {
|
||||
tx = tx.Where("alarm_status = ?", query.AlarmStatus)
|
||||
}
|
||||
if query.BeginTime != 0 {
|
||||
tx = tx.Where("created_at >= ?", query.BeginTime)
|
||||
}
|
||||
if query.EndTime != 0 {
|
||||
tx = tx.Where("created_at <= ?", query.EndTime)
|
||||
}
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.AlarmLog{}
|
||||
|
||||
// 查询数量为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 排序
|
||||
if query.SortField != "" {
|
||||
sortField := query.SortField
|
||||
if query.SortOrder == "desc" {
|
||||
sortField = sortField + " desc"
|
||||
}
|
||||
tx = tx.Order(sortField)
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize)
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
err := tx.Find(&rows).Error
|
||||
if err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows, total
|
||||
}
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r AlarmLog) SelectByIds(ids []int64) []model.AlarmLog {
|
||||
rows := []model.AlarmLog{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
tx := db.DB("").Model(&model.AlarmLog{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r AlarmLog) DeleteByIds(ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
tx := db.DB("").Where("id in ?", ids)
|
||||
if err := tx.Delete(&model.AlarmLog{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r AlarmLog) Insert(param model.AlarmLog) int64 {
|
||||
if param.CreatedAt.IsZero() {
|
||||
param.CreatedAt = time.Now()
|
||||
}
|
||||
// 执行插入
|
||||
if err := db.DB("").Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
273
src/modules/network_data/repository/cbc_message.go
Normal file
273
src/modules/network_data/repository/cbc_message.go
Normal file
@@ -0,0 +1,273 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 实例化数据层 UEEvent 结构体
|
||||
var NewCBCMessage = &CBCMessage{}
|
||||
|
||||
// UEEvent UE会话事件 数据层处理
|
||||
type CBCMessage struct{}
|
||||
|
||||
// SelectCBCMessage 根据条件分页查询CB消息
|
||||
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
|
||||
var msg []model.CBCMessage
|
||||
var total int64
|
||||
|
||||
tx := db.DB("").Table("cbc_message")
|
||||
|
||||
if query.NeType != "" {
|
||||
tx = tx.Where("ne_type = ?", query.NeType)
|
||||
}
|
||||
if query.NeId != "" {
|
||||
tx = tx.Where("ne_id = ?", query.NeId)
|
||||
}
|
||||
if query.EventName != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(message_json, '$.eventName') = ?", query.EventName)
|
||||
}
|
||||
if query.Status != "" {
|
||||
tx = tx.Where("status = ?", query.Status)
|
||||
}
|
||||
|
||||
var startMicro, endMicro int64
|
||||
var err error
|
||||
if query.StartTime != "" {
|
||||
startMicro, err = parseTimeToMilli(query.StartTime)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("invalid start time: %w", err)
|
||||
}
|
||||
}
|
||||
if query.EndTime != "" {
|
||||
endMicro, err = parseTimeToMilli(query.EndTime)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("invalid end time: %w", err)
|
||||
}
|
||||
}
|
||||
if startMicro > 0 && endMicro > 0 {
|
||||
tx = tx.Where("created_at BETWEEN ? AND ?", startMicro, endMicro)
|
||||
} else if startMicro > 0 {
|
||||
tx = tx.Where("created_at >= ?", startMicro)
|
||||
} else if endMicro > 0 {
|
||||
tx = tx.Where("created_at <= ?", endMicro)
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := tx.Count(&total).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (query.PageNum - 1) * query.PageSize
|
||||
if err := tx.Limit(query.PageSize).Offset(offset).Order("created_at desc").Find(&msg).Error; err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
|
||||
}
|
||||
|
||||
return msg, int(total), nil
|
||||
}
|
||||
|
||||
// SelectCBCMessageByPage 分页查询CB消息
|
||||
// @Description 分页查询CB消息
|
||||
// @param page 页码
|
||||
// @param pageSize 每页大小
|
||||
// @return []model.CBCMessage CB消息列表
|
||||
// @return int 总记录数
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// SelectByPage(1, 10)
|
||||
// func (s *CBCMessage) SelectByPage(pageNum int, pageSize int) ([]model.CBCMessage, int, error) {
|
||||
// var tickets []model.CBCMessage
|
||||
// var total int64
|
||||
|
||||
// // 统计总数
|
||||
// if err := db.DB("").Table("cbc_message").Count(&total).Error; err != nil {
|
||||
// return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
|
||||
// }
|
||||
|
||||
// // 分页查询
|
||||
// offset := (pageNum - 1) * pageSize
|
||||
// if err := db.DB("").Table("cbc_message").
|
||||
// Limit(pageSize).
|
||||
// Offset(offset).
|
||||
// Find(&tickets).Error; err != nil {
|
||||
// return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
|
||||
// }
|
||||
|
||||
// return tickets, int(total), nil
|
||||
// }
|
||||
|
||||
// InsertCBCMessage 插入CB消息
|
||||
// @Description 插入CB消息
|
||||
// @param msg CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// CBCMessage.InsertCBCMessage(msg)
|
||||
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
|
||||
msg.CreatedAt = time.Now().UnixMilli()
|
||||
// 这里可以使用ORM或其他方式将ticket插入到数据库中
|
||||
if err := db.DB("").Table("cbc_message").Create(&msg).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert CBC message: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectCBCMessageById 根据工单ID查询CB消息
|
||||
// @Description 根据工单ID查询CB消息
|
||||
// @param id 工单ID
|
||||
// @return *model.CBCMessage CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// CBCMessage.SelectCBCMessageById(12345)
|
||||
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
|
||||
var msg model.CBCMessage
|
||||
if err := db.DB("").Table("cbc_message").
|
||||
Where("id = ?", id).
|
||||
First(&msg).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to select CBC message: %w", err)
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// SelectByEventName 根据事件名称查询CB消息
|
||||
func (s *CBCMessage) SelectByEventName(eventName string) (*model.CBCMessage, error) {
|
||||
var msg model.CBCMessage
|
||||
if err := db.DB("").Table("cbc_message").
|
||||
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
|
||||
First(&msg).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessage 更新CB消息
|
||||
// @Description 更新CB消息
|
||||
// @param msg CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// mfCBCMessageService.UpdateCBCMessage(msg)
|
||||
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) (*model.CBCMessage, error) {
|
||||
var msg model.CBCMessage
|
||||
now := time.Now().UnixMilli()
|
||||
|
||||
err := db.DB("").Transaction(func(tx *gorm.DB) error {
|
||||
// 在事务中更新
|
||||
if err := tx.Table("cbc_message").
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
"message_json": messageJson,
|
||||
"updated_at": now,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update CBC message: %w", err)
|
||||
}
|
||||
|
||||
// 在事务中查询更新后的记录
|
||||
if err := tx.Table("cbc_message").
|
||||
Where("id = ?", id).
|
||||
First(&msg).Error; err != nil {
|
||||
return fmt.Errorf("failed to fetch updated CBC message: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessage 更新CB消息
|
||||
// @Description 更新CB消息
|
||||
// @param msg CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// UpdateCBCMessageDetail(msg)
|
||||
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
|
||||
now := time.Now().UnixMilli()
|
||||
if err := db.DB("").Table("cbc_message").
|
||||
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
|
||||
Updates(map[string]any{
|
||||
"detail": detail,
|
||||
"updated_at": now,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update CBC message: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteCBCMessage 删除CB消息
|
||||
// @Description 删除CB消息
|
||||
// @param id 工单ID
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// DeleteCBCMessage(12345)
|
||||
func (s *CBCMessage) Delete(id int64) error {
|
||||
// 执行删除操作
|
||||
if err := db.DB("").Table("cbc_message").
|
||||
Where("id = ?", id).
|
||||
Delete(&model.CBCMessage{}).Error; err != nil {
|
||||
return fmt.Errorf("failed to delete CBC message: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessageStatus 更新CB消息状态
|
||||
// @Description 更新CB消息状态,并根据状态变化发送相应的HTTP请求
|
||||
// @param status 新状态
|
||||
// @return error 错误信息
|
||||
func (s *CBCMessage) UpdateStatus(id int64, status model.CBCEventStatus) error {
|
||||
// 更新数据库状态
|
||||
now := time.Now().UnixMilli()
|
||||
if err := db.DB("").Table("cbc_message").
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]interface{}{
|
||||
"status": status,
|
||||
"updated_at": now,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update CBC message status: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Select 查询所有CB消息
|
||||
func (s *CBCMessage) Select(msgs *[]model.CBCMessage) error {
|
||||
if err := db.DB("").Table("cbc_message").Find(&msgs).Error; err != nil {
|
||||
return fmt.Errorf("failed to query CB messages: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectByNeId 根据网元ID查询CB消息
|
||||
func (s *CBCMessage) SelectByNeId(neId string, msgs *[]model.CBCMessage) error {
|
||||
if err := db.DB("").Table("cbc_message").Where("ne_id = ?", neId).Find(&msgs).Error; err != nil {
|
||||
return fmt.Errorf("failed to query CB messages: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 假设 query.StartTime 和 query.EndTime 是 "2006-01-02 15:04:05" 格式字符串
|
||||
func parseTimeToMilli(ts string) (int64, error) {
|
||||
if ts == "" {
|
||||
return 0, nil
|
||||
}
|
||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", ts, time.Local)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return t.UnixMilli(), nil
|
||||
}
|
||||
205
src/modules/network_data/repository/cdr_event.go
Normal file
205
src/modules/network_data/repository/cdr_event.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 CDREvent 结构体
|
||||
var NewCDREvent = &CDREvent{}
|
||||
|
||||
// CDREvent CDR会话事件 数据层处理
|
||||
type CDREvent struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model.CDREvent, int64) {
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Model(&model.CDREvent{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["rmUID"]; ok && v != "" {
|
||||
tx = tx.Where("rm_uid = ?", v)
|
||||
}
|
||||
if v, ok := query["beginTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = v + "000"
|
||||
}
|
||||
tx = tx.Where("created_at >= ?", v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = v + "000"
|
||||
}
|
||||
tx = tx.Where("created_at <= ?", v)
|
||||
}
|
||||
|
||||
// 各个网元特殊查询条件
|
||||
switch neType {
|
||||
case "SMSC":
|
||||
if v, ok := query["callerParty"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["calledParty"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["recordType"]; ok && v != "" {
|
||||
recordTypes := strings.Split(v, ",")
|
||||
var querytrArr []string
|
||||
for _, recordType := range recordTypes {
|
||||
querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType))
|
||||
}
|
||||
tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR ")))
|
||||
}
|
||||
case "SMF":
|
||||
if v, ok := query["recordType"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", v)
|
||||
}
|
||||
if v, ok := query["subscriberID"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["dnn"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", v)
|
||||
}
|
||||
case "SGWC":
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
case "IMS":
|
||||
if v, ok := query["callerParty"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["calledParty"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
}
|
||||
|
||||
var total int64 = 0
|
||||
rows := []model.CDREvent{}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 分页
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 排序
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortField := v
|
||||
sortOrder := "asc"
|
||||
if o, ok := query["sortOrder"]; ok && o != "" {
|
||||
if o == "desc" {
|
||||
sortOrder = "desc"
|
||||
} else {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
}
|
||||
sort.SliceStable(rows, func(i, j int) bool {
|
||||
// 支持的排序字段映射
|
||||
fieldGetters := map[string]func(*model.CDREvent) any{
|
||||
"id": func(row *model.CDREvent) any { return row.ID },
|
||||
"timestamp": func(row *model.CDREvent) any { return row.Timestamp },
|
||||
// 可添加更多支持的字段
|
||||
}
|
||||
|
||||
// 获取字段 getter 函数
|
||||
getter, ok := fieldGetters[sortField]
|
||||
if !ok {
|
||||
// 非法字段,使用默认排序(id升序)
|
||||
return rows[i].ID < rows[j].ID
|
||||
}
|
||||
|
||||
// 获取比较值
|
||||
valI, valJ := getter(&rows[i]), getter(&rows[j])
|
||||
|
||||
// 根据字段类型进行比较
|
||||
switch v := valI.(type) {
|
||||
case int64:
|
||||
if sortOrder == "desc" {
|
||||
return v > valJ.(int64)
|
||||
}
|
||||
return v < valJ.(int64)
|
||||
case string:
|
||||
if sortOrder == "desc" {
|
||||
return v > valJ.(string)
|
||||
}
|
||||
return v < valJ.(string)
|
||||
default:
|
||||
// 不支持的字段类型,使用默认排序
|
||||
return rows[i].ID < rows[j].ID
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r CDREvent) SelectByIds(neType string, ids []int64) []model.CDREvent {
|
||||
rows := []model.CDREvent{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Model(&model.CDREvent{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r CDREvent) DeleteByIds(neType string, ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Where("id in ?", ids)
|
||||
if err := tx.Delete(&model.CDREvent{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Insert 新增信息 返回新增数据ID
|
||||
func (r CDREvent) Insert(param model.CDREvent) int64 {
|
||||
if param.NeType == "" {
|
||||
return 0
|
||||
}
|
||||
if param.CreatedAt == 0 {
|
||||
param.CreatedAt = time.Now().UnixMilli()
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(param.NeType))
|
||||
// 执行插入
|
||||
if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
@@ -4,21 +4,23 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 PerfKPI 结构体
|
||||
var NewPerfKPI = &PerfKPI{}
|
||||
var NewKpiReport = &KpiReport{}
|
||||
|
||||
// PerfKPI 性能统计 数据层处理
|
||||
type PerfKPI struct{}
|
||||
// KpiReport 性能统计 数据层处理
|
||||
type KpiReport struct{}
|
||||
|
||||
// SelectGoldKPI 通过网元指标数据信息
|
||||
func (r *PerfKPI) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map[string]any {
|
||||
func (r *KpiReport) SelectGoldKPI(query model.KPIQuery, kpiIds []string) []map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
@@ -93,7 +95,7 @@ func (r *PerfKPI) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map
|
||||
}
|
||||
|
||||
// SelectGoldKPI 通过网元指标数据信息
|
||||
func (r PerfKPI) SelectKPI(query model.GoldKPIQuery) []model.KpiReport {
|
||||
func (r *KpiReport) SelectKPI(query model.KPIQuery) []model.KpiReport {
|
||||
rows := []model.KpiReport{}
|
||||
if query.NeType == "" {
|
||||
return rows
|
||||
@@ -164,8 +166,8 @@ func (r PerfKPI) SelectKPI(query model.GoldKPIQuery) []model.KpiReport {
|
||||
}
|
||||
|
||||
// SelectGoldKPITitle 网元对应的指标名称
|
||||
func (r *PerfKPI) SelectGoldKPITitle(neType string) []model.GoldKPITitle {
|
||||
result := []model.GoldKPITitle{}
|
||||
func (r *KpiReport) SelectGoldKPITitle(neType string) []model.KpiTitle {
|
||||
result := []model.KpiTitle{}
|
||||
tx := datasource.DefaultDB().Table("kpi_title").Where("ne_type = ? and status_flag = '1'", neType).Find(&result)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Find err => %v", err)
|
||||
@@ -173,9 +175,27 @@ func (r *PerfKPI) SelectGoldKPITitle(neType string) []model.GoldKPITitle {
|
||||
return result
|
||||
}
|
||||
|
||||
// Insert 新增信息 返回新增数据ID
|
||||
func (r KpiReport) Insert(param model.KpiReport) int64 {
|
||||
if param.NeType == "" {
|
||||
return 0
|
||||
}
|
||||
if param.CreatedAt == 0 {
|
||||
param.CreatedAt = time.Now().UnixMilli()
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("kpi_report_%s", strings.ToLower(param.NeType))
|
||||
// 执行插入
|
||||
if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
|
||||
// SelectByPageTitle 分页查询集合
|
||||
func (r PerfKPI) TitleSelectByPage(query map[string]string) ([]model.GoldKPITitle, int64) {
|
||||
tx := datasource.DB("").Model(&model.GoldKPITitle{})
|
||||
func (r KpiReport) TitleSelectByPage(query map[string]string) ([]model.KpiTitle, int64) {
|
||||
tx := datasource.DB("").Model(&model.KpiTitle{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["neType"]; ok && v != "" {
|
||||
tx = tx.Where("ne_type = ?", v)
|
||||
@@ -189,7 +209,7 @@ func (r PerfKPI) TitleSelectByPage(query map[string]string) ([]model.GoldKPITitl
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.GoldKPITitle{}
|
||||
rows := []model.KpiTitle{}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
@@ -222,23 +242,23 @@ func (r PerfKPI) TitleSelectByPage(query map[string]string) ([]model.GoldKPITitl
|
||||
}
|
||||
|
||||
// TitleSelect 网元对应的指标名称
|
||||
func (r PerfKPI) TitleSelect(param model.GoldKPITitle) []model.GoldKPITitle {
|
||||
tx := datasource.DB("").Model(&model.GoldKPITitle{})
|
||||
func (r KpiReport) TitleSelect(param model.KpiTitle) []model.KpiTitle {
|
||||
tx := datasource.DB("").Model(&model.KpiTitle{})
|
||||
// 构建查询条件
|
||||
if param.ID != "" {
|
||||
if param.ID != 0 {
|
||||
tx = tx.Where("id =?", param.ID)
|
||||
}
|
||||
if param.NeType != "" {
|
||||
tx = tx.Where("ne_type =?", param.NeType)
|
||||
}
|
||||
if param.KPIID != "" {
|
||||
tx = tx.Where("kpi_id =?", param.KPIID)
|
||||
if param.KpiId != "" {
|
||||
tx = tx.Where("kpi_id =?", param.KpiId)
|
||||
}
|
||||
if param.StatusFlag != "" {
|
||||
tx = tx.Where("status_flag = ?", param.StatusFlag)
|
||||
}
|
||||
// 查询数据
|
||||
rows := []model.GoldKPITitle{}
|
||||
rows := []model.KpiTitle{}
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
@@ -247,11 +267,11 @@ func (r PerfKPI) TitleSelect(param model.GoldKPITitle) []model.GoldKPITitle {
|
||||
}
|
||||
|
||||
// TitleUpdate 修改信息
|
||||
func (r PerfKPI) TitleUpdate(param model.GoldKPITitle) int64 {
|
||||
if param.ID == "" {
|
||||
func (r KpiReport) TitleUpdate(param model.KpiTitle) int64 {
|
||||
if param.ID == 0 {
|
||||
return 0
|
||||
}
|
||||
tx := datasource.DB("").Model(&model.GoldKPITitle{})
|
||||
tx := datasource.DB("").Model(&model.KpiTitle{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id = ?", param.ID)
|
||||
tx = tx.Omit("id", "kpi_id", "title_json")
|
||||
@@ -264,7 +284,7 @@ func (r PerfKPI) TitleUpdate(param model.GoldKPITitle) int64 {
|
||||
}
|
||||
|
||||
// SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行
|
||||
func (r *PerfKPI) SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) map[string]any {
|
||||
func (r *KpiReport) SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
@@ -303,7 +323,7 @@ func (r *PerfKPI) SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) m
|
||||
}
|
||||
|
||||
// SelectIMSBusyHour 查询IMS忙时流量 SCSCF.06呼叫尝试次数 SCSCF.09呼叫成功次数
|
||||
func (r *PerfKPI) SelectIMSBusyHour(rmUID string, startDate, endDate int64) []map[string]any {
|
||||
func (r *KpiReport) SelectIMSBusyHour(rmUID string, startDate, endDate int64) []map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
@@ -16,7 +16,8 @@ var NewSysTenant = &SysTenant{}
|
||||
type SysTenant struct{}
|
||||
|
||||
// Query 查询租户信息 ID 名称
|
||||
// radioKey 5G_2 4G_3
|
||||
// radioKey 5G_2/4G_3
|
||||
// imsi 123456789012345
|
||||
func (r SysTenant) Query(query map[string]string) (int64, string) {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
@@ -25,6 +26,10 @@ func (r SysTenant) Query(query map[string]string) (int64, string) {
|
||||
conditions = append(conditions, "st2.tenancy_type = 'RADIO' AND st2.tenancy_key = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
conditions = append(conditions, "st2.tenancy_type = 'IMSI' AND st2.tenancy_key like ?")
|
||||
params = append(params, fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
|
||||
170
src/modules/network_data/repository/ue_event.go
Normal file
170
src/modules/network_data/repository/ue_event.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 UEEvent 结构体
|
||||
var NewUEEvent = &UEEvent{}
|
||||
|
||||
// UEEvent UE会话事件 数据层处理
|
||||
type UEEvent struct{}
|
||||
|
||||
// SelectByPage 分页查询集合
|
||||
func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.UEEvent, int64) {
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Model(&model.UEEvent{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["rmUID"]; ok && v != "" {
|
||||
tx = tx.Where("rm_uid = ?", v)
|
||||
}
|
||||
if v, ok := query["beginTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = v + "000"
|
||||
}
|
||||
tx = tx.Where("created_at >= ?", v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = v + "000"
|
||||
}
|
||||
tx = tx.Where("created_at <= ?", v)
|
||||
}
|
||||
if v, ok := query["eventType"]; ok && v != "" {
|
||||
eventTypes := strings.Split(v, ",")
|
||||
tx = tx.Where("event_type in ?", eventTypes)
|
||||
}
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
|
||||
// 查询结果
|
||||
var total int64 = 0
|
||||
rows := []model.UEEvent{}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// 分页
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 排序
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortField := v
|
||||
sortOrder := "asc"
|
||||
if o, ok := query["sortOrder"]; ok && o != "" {
|
||||
if o == "desc" {
|
||||
sortOrder = "desc"
|
||||
} else {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
}
|
||||
sort.SliceStable(rows, func(i, j int) bool {
|
||||
// 支持的排序字段映射
|
||||
fieldGetters := map[string]func(*model.UEEvent) any{
|
||||
"id": func(row *model.UEEvent) any { return row.ID },
|
||||
"timestamp": func(row *model.UEEvent) any { return row.CreatedAt },
|
||||
"createdAt": func(row *model.UEEvent) any { return row.CreatedAt },
|
||||
// 可添加更多支持的字段
|
||||
}
|
||||
|
||||
// 获取字段 getter 函数
|
||||
getter, ok := fieldGetters[sortField]
|
||||
if !ok {
|
||||
// 非法字段,使用默认排序(id升序)
|
||||
return rows[i].ID < rows[j].ID
|
||||
}
|
||||
|
||||
// 获取比较值
|
||||
valI, valJ := getter(&rows[i]), getter(&rows[j])
|
||||
|
||||
// 根据字段类型进行比较
|
||||
switch v := valI.(type) {
|
||||
case int64:
|
||||
if sortOrder == "desc" {
|
||||
return v > valJ.(int64)
|
||||
}
|
||||
return v < valJ.(int64)
|
||||
case string:
|
||||
if sortOrder == "desc" {
|
||||
return v > valJ.(string)
|
||||
}
|
||||
return v < valJ.(string)
|
||||
default:
|
||||
// 不支持的字段类型,使用默认排序
|
||||
return rows[i].ID < rows[j].ID
|
||||
}
|
||||
})
|
||||
}
|
||||
return rows, total
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r UEEvent) SelectByIds(neType string, ids []int64) []model.UEEvent {
|
||||
rows := []model.UEEvent{}
|
||||
if len(ids) <= 0 {
|
||||
return rows
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Model(&model.UEEvent{})
|
||||
// 构建查询条件
|
||||
tx = tx.Where("id in ?", ids)
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r UEEvent) DeleteByIds(neType string, ids []int64) int64 {
|
||||
if len(ids) <= 0 {
|
||||
return 0
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
|
||||
tx := db.DB("").Table(tableName).Where("id in ?", ids)
|
||||
if err := tx.Delete(&model.UEEvent{}).Error; err != nil {
|
||||
logger.Errorf("delete err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Insert 新增信息 返回新增数据ID
|
||||
func (r UEEvent) Insert(param model.UEEvent) int64 {
|
||||
if param.NeType == "" {
|
||||
return 0
|
||||
}
|
||||
if param.CreatedAt == 0 {
|
||||
param.CreatedAt = time.Now().UnixMilli()
|
||||
}
|
||||
// 表名
|
||||
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(param.NeType))
|
||||
// 执行插入
|
||||
if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil {
|
||||
logger.Errorf("insert err => %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return param.ID
|
||||
}
|
||||
85
src/modules/network_data/service/alarm_event.go
Normal file
85
src/modules/network_data/service/alarm_event.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmEvent 结构体
|
||||
var NewAlarmEvent = &AlarmEvent{
|
||||
alarmEventRepository: repository.NewAlarmEvent,
|
||||
}
|
||||
|
||||
// AlarmEvent 告警 服务层处理
|
||||
type AlarmEvent struct {
|
||||
alarmEventRepository *repository.AlarmEvent // 告警数据信息
|
||||
}
|
||||
|
||||
// FindByPage 根据条件分页查询
|
||||
func (r AlarmEvent) FindByPage(query model.AlarmEventQuery) ([]model.AlarmEvent, int64) {
|
||||
return r.alarmEventRepository.SelectByPage(query)
|
||||
}
|
||||
|
||||
// Find 查询
|
||||
func (r AlarmEvent) Find(param model.AlarmEvent) []model.AlarmEvent {
|
||||
return r.alarmEventRepository.Select(param)
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (s AlarmEvent) Insert(param model.AlarmEvent) int64 {
|
||||
return s.alarmEventRepository.Insert(param)
|
||||
}
|
||||
|
||||
// Update 修改信息
|
||||
func (s AlarmEvent) Update(param model.AlarmEvent) int64 {
|
||||
return s.alarmEventRepository.Update(param)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r AlarmEvent) DeleteByIds(ids []int64) (int64, error) {
|
||||
// 检查是否存在
|
||||
data := r.alarmEventRepository.SelectByIds(ids)
|
||||
if len(data) <= 0 {
|
||||
return 0, fmt.Errorf("no data")
|
||||
}
|
||||
|
||||
if len(data) == len(ids) {
|
||||
rows := r.alarmEventRepository.DeleteByIds(ids)
|
||||
return rows, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
|
||||
// FindAlarmEventSeqLast 查询网元告警最后一条序号
|
||||
func (s AlarmEvent) FindAlarmEventSeqLast(neType, neId string) int64 {
|
||||
return s.alarmEventRepository.SelectAlarmEventSeqLast(neType, neId)
|
||||
}
|
||||
|
||||
// ClearByIds 批量清除告警信息
|
||||
func (r AlarmEvent) ClearByIds(ids []int64, clearUser, clearType string) (int64, error) {
|
||||
// 检查是否存在
|
||||
arr := r.alarmEventRepository.SelectByIds(ids)
|
||||
if len(arr) <= 0 {
|
||||
return 0, fmt.Errorf("no data")
|
||||
}
|
||||
|
||||
if len(arr) == len(ids) {
|
||||
var rows int64 = 0
|
||||
for _, v := range arr {
|
||||
v.AlarmStatus = oam.ALARM_STATUS_CLEAR
|
||||
// 告警清除
|
||||
v.ClearType = clearType
|
||||
v.ClearUser = clearUser
|
||||
v.ClearTime = time.Now()
|
||||
rows += r.alarmEventRepository.Update(v)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
return 0, fmt.Errorf("clear fail")
|
||||
}
|
||||
26
src/modules/network_data/service/alarm_forward_log.go
Normal file
26
src/modules/network_data/service/alarm_forward_log.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmForwardLog 结构体
|
||||
var NewAlarmForwardLog = &AlarmForwardLog{
|
||||
alarmForwardLogRepository: repository.NewAlarmForwardLog,
|
||||
}
|
||||
|
||||
// AlarmForwardLog 告警转发记录表 服务层处理
|
||||
type AlarmForwardLog struct {
|
||||
alarmForwardLogRepository *repository.AlarmForwardLog // 告警转发记录信息
|
||||
}
|
||||
|
||||
// FindByPage 根据条件分页查询
|
||||
func (r AlarmForwardLog) FindByPage(query model.AlarmForwardLogQuery) ([]model.AlarmForwardLog, int64) {
|
||||
return r.alarmForwardLogRepository.SelectByPage(query)
|
||||
}
|
||||
|
||||
// Insert 插入数据
|
||||
func (r AlarmForwardLog) Insert(item model.AlarmForwardLog) int64 {
|
||||
return r.alarmForwardLogRepository.Insert(item)
|
||||
}
|
||||
26
src/modules/network_data/service/alarm_log.go
Normal file
26
src/modules/network_data/service/alarm_log.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 AlarmLog 结构体
|
||||
var NewAlarmLog = &AlarmLog{
|
||||
alarmLogRepository: repository.NewAlarmLog,
|
||||
}
|
||||
|
||||
// AlarmLog 基站状态记录表 服务层处理
|
||||
type AlarmLog struct {
|
||||
alarmLogRepository *repository.AlarmLog // 基站状态记录信息
|
||||
}
|
||||
|
||||
// FindByPage 根据条件分页查询
|
||||
func (r AlarmLog) FindByPage(query model.AlarmLogQuery) ([]model.AlarmLog, int64) {
|
||||
return r.alarmLogRepository.SelectByPage(query)
|
||||
}
|
||||
|
||||
// Insert 插入数据
|
||||
func (r AlarmLog) Insert(item model.AlarmLog) int64 {
|
||||
return r.alarmLogRepository.Insert(item)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
"github.com/tsmask/go-oam"
|
||||
)
|
||||
|
||||
// 实例化数据层 Alarm 结构体
|
||||
@@ -61,6 +62,58 @@ func (s Alarm) FindAlarmSeqLast(neType, neId string) int64 {
|
||||
return s.alarmRepository.SelectAlarmSeqLast(neType, neId)
|
||||
}
|
||||
|
||||
// ClearByIds 批量清除告警信息
|
||||
func (r Alarm) ClearByIds(ids []string, clearUser, clearType string) (int64, error) {
|
||||
// 检查是否存在
|
||||
arr := r.alarmRepository.SelectByIds(ids)
|
||||
if len(arr) <= 0 {
|
||||
return 0, fmt.Errorf("no data")
|
||||
}
|
||||
|
||||
if len(arr) == len(ids) {
|
||||
var rows int64 = 0
|
||||
for _, v := range arr {
|
||||
// 状态检查AlarmCode变更告警ID
|
||||
alarmCode := parse.Number(v.AlarmCode)
|
||||
if alarmCode == constants.ALARM_STATE_CHECK || alarmCode == constants.ALARM_CMD_CHECK || alarmCode == constants.ALARM_LICENSE_CHECK {
|
||||
v.AlarmId = fmt.Sprintf("%s%d", v.AlarmCode, v.EventTime.UnixMilli())
|
||||
}
|
||||
v.AlarmStatus = oam.ALARM_STATUS_CLEAR
|
||||
// 告警清除
|
||||
clearTime := time.Now()
|
||||
v.ClearType = clearType
|
||||
v.ClearUser = clearUser
|
||||
v.ClearTime = &clearTime
|
||||
rows += r.alarmRepository.Update(v)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
return 0, fmt.Errorf("clear fail")
|
||||
}
|
||||
|
||||
// AckByIds 批量确认清除告警信息
|
||||
func (r Alarm) AckByIds(ids []string, ackUser, ackState string) (int64, error) {
|
||||
// 检查是否存在
|
||||
arr := r.alarmRepository.SelectByIds(ids)
|
||||
if len(arr) <= 0 {
|
||||
return 0, fmt.Errorf("no data")
|
||||
}
|
||||
|
||||
if len(arr) == len(ids) {
|
||||
var rows int64 = 0
|
||||
for _, v := range arr {
|
||||
// 确认清除
|
||||
v.AckState = ackState
|
||||
ackTime := time.Now()
|
||||
v.AckTime = &ackTime
|
||||
v.AckUser = ackUser
|
||||
rows += r.alarmRepository.Update(v)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
return 0, fmt.Errorf("ack fail")
|
||||
}
|
||||
|
||||
// AlarmClearByIds 批量清除告警信息
|
||||
func (r Alarm) AlarmClearByIds(ids []string, clearUser string) (int64, error) {
|
||||
// 检查是否存在
|
||||
|
||||
453
src/modules/network_data/service/cbc_message.go
Normal file
453
src/modules/network_data/service/cbc_message.go
Normal file
@@ -0,0 +1,453 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 实例化数据层 CBCMessage 结构体
|
||||
var NewCBCMessage = &CBCMessage{
|
||||
cbcMessageRepository: repository.NewCBCMessage,
|
||||
}
|
||||
|
||||
// CBCMessage CB消息 服务层处理
|
||||
type CBCMessage struct {
|
||||
cbcMessageRepository *repository.CBCMessage // UE会话事件数据信息
|
||||
}
|
||||
|
||||
// SelectByPage 根据条件分页查询CB消息
|
||||
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
|
||||
return s.cbcMessageRepository.SelectByPage(query)
|
||||
}
|
||||
|
||||
// SelectCBCMessageById 根据工单ID查询CB消息
|
||||
// @Description 根据工单ID查询CB消息
|
||||
// @param id 工单ID
|
||||
// @return *model.CBCMessage CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// CBCMessage.SelectCBCMessageById(12345)
|
||||
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
|
||||
return s.cbcMessageRepository.SelectById(id)
|
||||
}
|
||||
|
||||
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
|
||||
// 解析messageJson获取eventName
|
||||
var messageData map[string]interface{}
|
||||
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
|
||||
return fmt.Errorf("failed to parse message_json: %w", err)
|
||||
}
|
||||
|
||||
// 提取eventName
|
||||
eventName, ok := messageData["eventName"].(string)
|
||||
if !ok || eventName == "" {
|
||||
return fmt.Errorf("eventName is required in message_json")
|
||||
}
|
||||
|
||||
// 检查是否已存在相同的eventName
|
||||
var err error
|
||||
var existingMsg *model.CBCMessage
|
||||
if existingMsg, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
|
||||
return fmt.Errorf("failed to check existing CBC message: %w", err)
|
||||
}
|
||||
|
||||
if existingMsg != nil {
|
||||
return fmt.Errorf("CBC message with eventName '%s' already exists for neType '%s' and neId '%s'",
|
||||
eventName, existingMsg.NeType, existingMsg.NeId)
|
||||
}
|
||||
return s.cbcMessageRepository.Insert(msg)
|
||||
}
|
||||
|
||||
// UpdateCBCMessage 更新CB消息
|
||||
// @Description 更新CB消息
|
||||
// @param msg CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// mfCBCMessageService.UpdateCBCMessage(msg)
|
||||
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error {
|
||||
// 解析messageJson获取eventName
|
||||
var messageData map[string]interface{}
|
||||
if err := json.Unmarshal(messageJson, &messageData); err != nil {
|
||||
return fmt.Errorf("failed to parse message_json: %w", err)
|
||||
}
|
||||
// 提取eventName
|
||||
eventName, ok := messageData["eventName"].(string)
|
||||
if !ok || eventName == "" {
|
||||
return fmt.Errorf("eventName is required in message_json")
|
||||
}
|
||||
|
||||
// 检查是否已存在相同的eventName
|
||||
var err error
|
||||
if _, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("no existing CBC message found with eventName: %s", eventName)
|
||||
}
|
||||
return fmt.Errorf("failed to query existing CBC message: %w", err)
|
||||
}
|
||||
|
||||
// 如果存在,更新记录
|
||||
var msg *model.CBCMessage
|
||||
if msg, err = s.cbcMessageRepository.Update(id, messageJson); err != nil {
|
||||
return fmt.Errorf("failed to update CBC message: %w", err)
|
||||
}
|
||||
|
||||
// 如果状态是ACTIVE,发送更新请求
|
||||
if msg.Status == model.CBCEventStatusActive {
|
||||
if err := s.sendUpdateRequest(*msg); err != nil {
|
||||
return fmt.Errorf("failed to send update request: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessage 更新CB消息
|
||||
// @Description 更新CB消息
|
||||
// @param msg CB消息对象
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// UpdateCBCMessageDetail(msg)
|
||||
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
|
||||
if err := s.cbcMessageRepository.UpdateDetail(eventName, detail); err != nil {
|
||||
return fmt.Errorf("failed to update CBC message detail: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteCBCMessage 删除CB消息
|
||||
// @Description 删除CB消息
|
||||
// @param id 工单ID
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// mfCBCMessageService.DeleteCBCMessage(12345)
|
||||
func (s *CBCMessage) Delete(id int64) error {
|
||||
// 先查询记录状态
|
||||
var err error
|
||||
var msg *model.CBCMessage
|
||||
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("CBC message with ID %d not found", id)
|
||||
}
|
||||
return fmt.Errorf("failed to query CBC message: %w", err)
|
||||
}
|
||||
|
||||
// 检查状态是否为ACTIVE
|
||||
if msg.Status == model.CBCEventStatusActive {
|
||||
return fmt.Errorf("cannot delete an active CBC message (ID: %d)", id)
|
||||
}
|
||||
|
||||
// 执行删除操作
|
||||
if err := s.cbcMessageRepository.Delete(id); err != nil {
|
||||
return fmt.Errorf("failed to delete CBC message: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessageStatus 更新CB消息状态
|
||||
// @Description 更新CB消息状态,并根据状态变化发送相应的HTTP请求
|
||||
// @param status 新状态
|
||||
// @return error 错误信息
|
||||
func (s *CBCMessage) UpdateStatus(id int64, status string) error {
|
||||
newStatus := model.ParseCBCEventStatus(status)
|
||||
|
||||
// 查询所有需要更新的记录
|
||||
var err error
|
||||
var msg *model.CBCMessage
|
||||
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("CBC message with ID %d not found", id)
|
||||
}
|
||||
return fmt.Errorf("failed to query CBC message: %w", err)
|
||||
}
|
||||
|
||||
oldStatus := msg.Status
|
||||
|
||||
// 检查状态是否发生变化
|
||||
if oldStatus == newStatus {
|
||||
return fmt.Errorf("CBC message status is already %s", newStatus.Enum())
|
||||
}
|
||||
|
||||
// 更新数据库状态
|
||||
if err := s.cbcMessageRepository.UpdateStatus(id, newStatus); err != nil {
|
||||
return fmt.Errorf("failed to update CBC message status: %w", err)
|
||||
}
|
||||
|
||||
// 根据状态变化发送HTTP请求
|
||||
if err := s.handleStatusChange(*msg, oldStatus, newStatus); err != nil {
|
||||
// 记录错误但不中断处理其他消息
|
||||
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessageStatus 更新CB消息状态
|
||||
// @Description 更新CB消息状态,并根据状态变化发送相应的HTTP请求
|
||||
// @param status 新状态
|
||||
// @return error 错误信息
|
||||
func (s *CBCMessage) UpdateStatusByNeId(neId string, status string) error {
|
||||
newStatus := model.ParseCBCEventStatus(status)
|
||||
|
||||
// 查询所有需要更新的记录
|
||||
msgs := make([]model.CBCMessage, 0)
|
||||
if err := s.cbcMessageRepository.SelectByNeId(neId, &msgs); err != nil {
|
||||
return fmt.Errorf("failed to query CB messages: %w", err)
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
oldStatus := msg.Status
|
||||
|
||||
// 检查状态是否发生变化
|
||||
if oldStatus == newStatus {
|
||||
continue // 状态没有变化,跳过
|
||||
}
|
||||
|
||||
// 更新数据库状态
|
||||
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
|
||||
return fmt.Errorf("failed to update CBC message status: %w", err)
|
||||
}
|
||||
|
||||
// 根据状态变化发送HTTP请求
|
||||
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
|
||||
// 记录错误但不中断处理其他消息
|
||||
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCBCMessageStatus 更新CB消息状态
|
||||
// @Description 更新CB消息状态,并根据状态变化发送相应的HTTP请求
|
||||
// @param status 新状态
|
||||
// @return error 错误信息
|
||||
func (s *CBCMessage) UpdateAllStatus(status string) error {
|
||||
newStatus := model.ParseCBCEventStatus(status)
|
||||
|
||||
// 查询所有需要更新的记录
|
||||
msgs := make([]model.CBCMessage, 0)
|
||||
if err := s.cbcMessageRepository.Select(&msgs); err != nil {
|
||||
return fmt.Errorf("failed to query CB messages: %w", err)
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
oldStatus := msg.Status
|
||||
|
||||
// 检查状态是否发生变化
|
||||
if oldStatus == newStatus {
|
||||
continue // 状态没有变化,跳过
|
||||
}
|
||||
|
||||
// 更新数据库状态
|
||||
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
|
||||
return fmt.Errorf("failed to update CBC message status: %w", err)
|
||||
}
|
||||
|
||||
// 根据状态变化发送HTTP请求
|
||||
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
|
||||
// 记录错误但不中断处理其他消息
|
||||
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportXlsx 导出数据到 xlsx 文件
|
||||
func (r CBCMessage) ExportXlsx(rows []model.CBCMessage, fileName, language string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": i18n.TKey(language, "alarm.export.alarmType"),
|
||||
"B1": i18n.TKey(language, "alarm.export.origSeverity"),
|
||||
"C1": i18n.TKey(language, "alarm.export.alarmTitle"),
|
||||
"D1": i18n.TKey(language, "alarm.export.eventTime"),
|
||||
"E1": i18n.TKey(language, "alarm.export.alarmId"),
|
||||
"F1": i18n.TKey(language, "alarm.export.alarmCode"),
|
||||
"G1": i18n.TKey(language, "ne.common.neType"),
|
||||
"H1": i18n.TKey(language, "ne.common.neName"),
|
||||
"I1": i18n.TKey(language, "ne.common.neId"),
|
||||
}
|
||||
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
|
||||
cells := map[string]any{
|
||||
"A" + idx: row.NeType,
|
||||
"B" + idx: row.NeId,
|
||||
"C" + idx: row.MessageJson, // 这里假设 MessageJson 已经是字符串格式
|
||||
"D" + idx: row.Status.Enum(),
|
||||
"E" + idx: row.Detail,
|
||||
"F" + idx: time.UnixMilli(row.CreatedAt).Format(time.RFC3339),
|
||||
"G" + idx: time.UnixMilli(row.UpdatedAt).Format(time.RFC3339),
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, cells)
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
// handleStatusChange 处理状态变化时的HTTP请求
|
||||
func (s *CBCMessage) handleStatusChange(msg model.CBCMessage, oldStatus, newStatus model.CBCEventStatus) error {
|
||||
// 从NULL/INACTIVE状态修改为ACTIVE
|
||||
if (oldStatus == model.CBCEventStatusNull || oldStatus == model.CBCEventStatusInactive) &&
|
||||
newStatus == model.CBCEventStatusActive {
|
||||
return s.sendActivateRequest(msg)
|
||||
}
|
||||
|
||||
// 从ACTIVE更改为INACTIVE状态
|
||||
if oldStatus == model.CBCEventStatusActive && newStatus == model.CBCEventStatusInactive {
|
||||
return s.sendDeactivateRequest(msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getCBCNetworkElement 获取CBC网元的IP和端口信息
|
||||
// 这个方法需要根据你的实际网元管理系统来实现
|
||||
func (s *CBCMessage) getCBCNetworkElement(neId string) (string, int64, error) {
|
||||
// 查询网元信息
|
||||
neInfo := neService.NewNeInfo.FindByNeTypeAndNeID("CBC", neId)
|
||||
if neInfo.IP == "" {
|
||||
return "", 0, fmt.Errorf("CBC network element not found for neId: %s", neId)
|
||||
}
|
||||
return neInfo.IP, neInfo.Port, nil
|
||||
}
|
||||
|
||||
// CBCHTTPClient CBC网元HTTP客户端
|
||||
type CBCHTTPClient struct {
|
||||
client *http.Client
|
||||
baseURL string
|
||||
}
|
||||
|
||||
// NewCBCHTTPClient 创建CBC HTTP客户端
|
||||
func NewCBCHTTPClient(baseURL string) *CBCHTTPClient {
|
||||
return &CBCHTTPClient{
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
baseURL: baseURL,
|
||||
}
|
||||
}
|
||||
|
||||
// PostMessage 发送POST请求创建消息
|
||||
func (c *CBCHTTPClient) PostMessage(messageData []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
|
||||
return c.sendRequest("POST", url, messageData)
|
||||
}
|
||||
|
||||
// PutMessage 发送PUT请求更新消息
|
||||
func (c *CBCHTTPClient) PutMessage(messageData []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
|
||||
return c.sendRequest("PUT", url, messageData)
|
||||
}
|
||||
|
||||
// DeleteMessage 发送DELETE请求删除消息
|
||||
func (c *CBCHTTPClient) DeleteMessage(eventName string, deletePayload []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message/%s", c.baseURL, eventName)
|
||||
return c.sendRequest("DELETE", url, deletePayload)
|
||||
}
|
||||
|
||||
// sendRequest 发送HTTP请求
|
||||
func (c *CBCHTTPClient) sendRequest(method, url string, body []byte) error {
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create %s request: %w", method, err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send %s request: %w", method, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("%s request failed with status: %d, body: %s",
|
||||
method, resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 在CBCMessageService中添加方法
|
||||
func (s *CBCMessage) getCBCHTTPClient(neId string) (*CBCHTTPClient, error) {
|
||||
cbcIP, cbcPort, err := s.getCBCNetworkElement(neId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get CBC network element info: %w", err)
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%d", cbcIP, cbcPort)
|
||||
return NewCBCHTTPClient(baseURL), nil
|
||||
}
|
||||
|
||||
// 重构后的激活请求
|
||||
func (s *CBCMessage) sendActivateRequest(msg model.CBCMessage) error {
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 直接使用 MessageJson 发送POST请求
|
||||
return client.PostMessage(msg.MessageJson)
|
||||
}
|
||||
|
||||
// 重构后的更新请求
|
||||
func (s *CBCMessage) sendUpdateRequest(msg model.CBCMessage) error {
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 直接使用 MessageJson 发送POST请求
|
||||
return client.PostMessage(msg.MessageJson)
|
||||
}
|
||||
|
||||
// 重构后的停用请求
|
||||
func (s *CBCMessage) sendDeactivateRequest(msg model.CBCMessage) error {
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析和构造删除载荷的逻辑保持不变
|
||||
var messageData map[string]interface{}
|
||||
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
|
||||
return fmt.Errorf("failed to parse message_json: %w", err)
|
||||
}
|
||||
|
||||
eventName, ok := messageData["eventName"].(string)
|
||||
if !ok || eventName == "" {
|
||||
return fmt.Errorf("eventName not found in message_json")
|
||||
}
|
||||
|
||||
deletePayload := make(map[string]interface{})
|
||||
if messageIdProfile, exists := messageData["messageIdProfile"]; exists {
|
||||
deletePayload["messageIdProfile"] = messageIdProfile
|
||||
}
|
||||
if warningAreaList, exists := messageData["warningAreaList"]; exists {
|
||||
deletePayload["warningAreaList"] = warningAreaList
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(deletePayload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal delete payload: %w", err)
|
||||
}
|
||||
|
||||
return client.DeleteMessage(eventName, payloadBytes)
|
||||
}
|
||||
645
src/modules/network_data/service/cdr_event.go
Normal file
645
src/modules/network_data/service/cdr_event.go
Normal file
@@ -0,0 +1,645 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
sysService "be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
// 实例化数据层 CDREvent 结构体
|
||||
var NewCDREvent = &CDREvent{
|
||||
cdrEventRepository: repository.NewCDREvent,
|
||||
}
|
||||
|
||||
// CDREvent CDR会话事件 服务层处理
|
||||
type CDREvent struct {
|
||||
cdrEventRepository *repository.CDREvent // CDR会话事件数据信息
|
||||
}
|
||||
|
||||
// FindByPage 根据条件分页查询
|
||||
func (r CDREvent) FindByPage(neType string, query map[string]string) ([]model.CDREvent, int64) {
|
||||
return r.cdrEventRepository.SelectByPage(neType, query)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r CDREvent) DeleteByIds(neType string, ids []int64) (int64, error) {
|
||||
// 检查是否存在
|
||||
rows := r.cdrEventRepository.SelectByIds(neType, ids)
|
||||
if len(rows) <= 0 {
|
||||
return 0, fmt.Errorf("not data")
|
||||
}
|
||||
|
||||
if len(rows) == len(ids) {
|
||||
rows := r.cdrEventRepository.DeleteByIds(neType, ids)
|
||||
return rows, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (s CDREvent) Insert(param model.CDREvent) int64 {
|
||||
return s.cdrEventRepository.Insert(param)
|
||||
}
|
||||
|
||||
// ExportSMSC 导出数据到 xlsx 文件
|
||||
func (r CDREvent) ExportSMSC(rows []model.CDREvent, fileName, language string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "NE Name",
|
||||
"C1": "Record Behavior",
|
||||
"D1": "Service Type",
|
||||
"E1": "Caller",
|
||||
"F1": "Called",
|
||||
"G1": "Result",
|
||||
"H1": "Time",
|
||||
}
|
||||
// 读取字典数据 CDR 原因码
|
||||
dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var cdrJSON map[string]interface{}
|
||||
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 记录类型
|
||||
recordType := ""
|
||||
if v, ok := cdrJSON["recordType"]; ok && v != nil {
|
||||
recordType = v.(string)
|
||||
}
|
||||
// 服务类型
|
||||
serviceType := ""
|
||||
if v, ok := cdrJSON["serviceType"]; ok && v != nil {
|
||||
serviceType = v.(string)
|
||||
}
|
||||
// 被叫
|
||||
called := ""
|
||||
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
|
||||
called = v.(string)
|
||||
}
|
||||
// 主叫
|
||||
caller := ""
|
||||
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
|
||||
caller = v.(string)
|
||||
}
|
||||
// 呼叫结果 0失败,1成功
|
||||
callResult := "Fail"
|
||||
if v, ok := cdrJSON["result"]; ok && v != nil {
|
||||
resultVal := parse.Number(v)
|
||||
if resultVal == 1 {
|
||||
callResult = "Success"
|
||||
}
|
||||
}
|
||||
// 结果原因
|
||||
if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" {
|
||||
cause := fmt.Sprint(v)
|
||||
for _, v := range dictCDRCauseCode {
|
||||
if cause == v.DictValue {
|
||||
callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DictLabel))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 取时间
|
||||
timeStr := ""
|
||||
if v, ok := cdrJSON["updateTime"]; ok && v != nil {
|
||||
if releaseTime := parse.Number(v); releaseTime > 0 {
|
||||
timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
} else {
|
||||
timeStr = v.(string)
|
||||
}
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: row.NeName,
|
||||
"C" + idx: recordType,
|
||||
"D" + idx: serviceType,
|
||||
"E" + idx: caller,
|
||||
"F" + idx: called,
|
||||
"G" + idx: callResult,
|
||||
"H" + idx: timeStr,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
// ExportSMF 导出数据到 xlsx 文件
|
||||
func (r CDREvent) ExportSMF(rows []model.CDREvent, fileName string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "Charging ID",
|
||||
"C1": "NE Name",
|
||||
"D1": "Resource Unique ID",
|
||||
"E1": "Subscriber ID Data",
|
||||
"F1": "Subscriber ID Type",
|
||||
"G1": "Data Volume Uplink",
|
||||
"H1": "Data Volume Downlink",
|
||||
"I1": "Data Total Volume",
|
||||
"J1": "Duration",
|
||||
"K1": "Invocation Time",
|
||||
"L1": "User Identifier",
|
||||
"M1": "SSC Mode",
|
||||
"N1": "DNN ID",
|
||||
"O1": "PDU Type",
|
||||
"P1": "RAT Type",
|
||||
"Q1": "PDU IPv4 Address",
|
||||
"R1": "Network Function IPv4",
|
||||
"S1": "PDU IPv6 Address Swith Prefix",
|
||||
"T1": "Record Network Function ID",
|
||||
"U1": "Record Type",
|
||||
"V1": "Record Opening Time",
|
||||
}
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var cdrJSON map[string]interface{}
|
||||
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 计费ID
|
||||
chargingID := ""
|
||||
if v, ok := cdrJSON["chargingID"]; ok && v != nil {
|
||||
chargingID = fmt.Sprint(parse.Number(v))
|
||||
}
|
||||
// 订阅 ID 类型
|
||||
subscriptionIDType := "-"
|
||||
// 订阅 ID 数据
|
||||
subscriptionIDData := "-"
|
||||
if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil {
|
||||
if sub, subOk := v.(map[string]any); subOk && sub != nil {
|
||||
subscriptionIDType = sub["subscriptionIDType"].(string)
|
||||
subscriptionIDData = sub["subscriptionIDData"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
// 网络功能 IPv4 地址
|
||||
networkFunctionIPv4Address := ""
|
||||
if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil {
|
||||
if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil {
|
||||
networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
// 数据量上行链路
|
||||
var dataVolumeUplink int64 = 0
|
||||
// 数据量下行链路
|
||||
var dataVolumeDownlink int64 = 0
|
||||
// 数据总量
|
||||
var dataTotalVolume int64 = 0
|
||||
if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil {
|
||||
usageList := v.([]any)
|
||||
if len(usageList) > 0 {
|
||||
for _, used := range usageList {
|
||||
usedUnit := used.(map[string]any)
|
||||
usedUnitList := usedUnit["usedUnitContainer"].([]any)
|
||||
if len(usedUnitList) > 0 {
|
||||
for _, data := range usedUnitList {
|
||||
udata := data.(map[string]any)
|
||||
if dup, dupOk := udata["dataVolumeUplink"]; dupOk {
|
||||
dataVolumeUplink += parse.Number(dup)
|
||||
}
|
||||
if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk {
|
||||
dataVolumeDownlink += parse.Number(ddown)
|
||||
}
|
||||
if dt, dtOk := udata["dataTotalVolume"]; dtOk {
|
||||
dataTotalVolume += parse.Number(dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 时长
|
||||
duration := "-"
|
||||
if v, ok := cdrJSON["duration"]; ok && v != nil {
|
||||
duration = fmt.Sprint(parse.Number(v))
|
||||
}
|
||||
// 调用时间
|
||||
invocationTimestamp := ""
|
||||
if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil {
|
||||
invocationTimestamp = v.(string)
|
||||
}
|
||||
// 记录打开时间
|
||||
User_Identifier := ""
|
||||
SSC_Mode := ""
|
||||
RAT_Type := ""
|
||||
DNN_ID := ""
|
||||
PDU_Type := ""
|
||||
PDU_IPv4 := ""
|
||||
PDU_IPv6 := ""
|
||||
if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil {
|
||||
pduInfo := v.(map[string]any)
|
||||
|
||||
if v, ok := pduInfo["userIdentifier"]; ok && v != nil {
|
||||
User_Identifier = v.(string)
|
||||
}
|
||||
if v, ok := pduInfo["sSCMode"]; ok && v != nil {
|
||||
SSC_Mode = v.(string)
|
||||
}
|
||||
if v, ok := pduInfo["rATType"]; ok && v != nil {
|
||||
RAT_Type = v.(string)
|
||||
}
|
||||
if v, ok := pduInfo["dNNID"]; ok && v != nil {
|
||||
DNN_ID = v.(string)
|
||||
}
|
||||
if v, ok := pduInfo["pDUType"]; ok && v != nil {
|
||||
PDU_Type = v.(string)
|
||||
}
|
||||
if v, ok := pduInfo["pDUAddress"]; ok && v != nil {
|
||||
pDUAddress := v.(map[string]any)
|
||||
if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil {
|
||||
PDU_IPv4 = addr.(string)
|
||||
}
|
||||
if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil {
|
||||
PDU_IPv6 = addr.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录网络参数ID
|
||||
recordNFID := ""
|
||||
if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil {
|
||||
recordNFID = v.(string)
|
||||
}
|
||||
|
||||
//记录开始时间
|
||||
recordOpeningTime := ""
|
||||
if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
|
||||
recordOpeningTime = v.(string)
|
||||
}
|
||||
|
||||
//记录类型
|
||||
recordType := ""
|
||||
if v, ok := cdrJSON["recordType"]; ok && v != nil {
|
||||
recordType = v.(string)
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: chargingID,
|
||||
"C" + idx: row.NeName,
|
||||
"D" + idx: row.RmUid,
|
||||
"E" + idx: subscriptionIDData,
|
||||
"F" + idx: subscriptionIDType,
|
||||
"G" + idx: dataVolumeUplink,
|
||||
"H" + idx: dataVolumeDownlink,
|
||||
"I" + idx: dataTotalVolume,
|
||||
"J" + idx: duration,
|
||||
"K" + idx: invocationTimestamp,
|
||||
"L" + idx: User_Identifier,
|
||||
"M" + idx: SSC_Mode,
|
||||
"N" + idx: DNN_ID,
|
||||
"O" + idx: PDU_Type,
|
||||
"P" + idx: RAT_Type,
|
||||
"Q" + idx: PDU_IPv4,
|
||||
"R" + idx: networkFunctionIPv4Address,
|
||||
"S" + idx: PDU_IPv6,
|
||||
"T" + idx: recordNFID,
|
||||
"U" + idx: recordType,
|
||||
"V" + idx: recordOpeningTime,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
// ExportSGWC 导出数据到 xlsx 文件
|
||||
func (r CDREvent) ExportSGWC(rows []model.CDREvent, fileName string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "NE Name",
|
||||
"C1": "Resource Unique ID",
|
||||
"D1": "Charging ID",
|
||||
"E1": "IMSI",
|
||||
"F1": "MSISDN",
|
||||
"G1": "GPRS Uplink",
|
||||
"H1": "GPRS Downlink",
|
||||
"I1": "Duration",
|
||||
"J1": "Invocation Time",
|
||||
"K1": "PGW Address",
|
||||
"L1": "SGW Address",
|
||||
"M1": "RAT Type",
|
||||
"N1": "PDPPDN Type",
|
||||
"O1": "PDPPDN Address",
|
||||
"P1": "Node Address",
|
||||
"Q1": "Node Type",
|
||||
"R1": "Record Access Point Name NI",
|
||||
"S1": "Record Cause For Rec Closing",
|
||||
"T1": "Record Sequence Number",
|
||||
"U1": "Local Record Sequence Number",
|
||||
"V1": "Record Type",
|
||||
"W1": "Record Opening Time",
|
||||
}
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var cdrJSON map[string]interface{}
|
||||
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 计费ID
|
||||
chargingID := ""
|
||||
if v, ok := cdrJSON["chargingID"]; ok && v != nil {
|
||||
chargingID = fmt.Sprint(parse.Number(v))
|
||||
}
|
||||
// IMSI
|
||||
servedIMSI := ""
|
||||
if v, ok := cdrJSON["servedIMSI"]; ok && v != nil {
|
||||
servedIMSI = fmt.Sprint(v)
|
||||
}
|
||||
// MSISDN
|
||||
servedMSISDN := ""
|
||||
if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil {
|
||||
servedMSISDN = fmt.Sprint(v)
|
||||
}
|
||||
// pGWAddressUsed
|
||||
pGWAddressUsed := ""
|
||||
if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil {
|
||||
pGWAddressUsed = fmt.Sprint(v)
|
||||
headerCells["K1"] = "PGW Address"
|
||||
}
|
||||
if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil {
|
||||
pGWAddressUsed = fmt.Sprint(v)
|
||||
headerCells["K1"] = "GGSN Address"
|
||||
}
|
||||
// sGWAddress
|
||||
sGWAddress := ""
|
||||
if v, ok := cdrJSON["sGWAddress"]; ok && v != nil {
|
||||
sGWAddress = fmt.Sprint(v)
|
||||
headerCells["L1"] = "SGW Address"
|
||||
}
|
||||
if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil {
|
||||
sGWAddress = fmt.Sprint(v)
|
||||
headerCells["L1"] = "SGSN Address"
|
||||
}
|
||||
// recordType
|
||||
recordType := ""
|
||||
if v, ok := cdrJSON["recordType"]; ok && v != nil {
|
||||
recordType = fmt.Sprint(v)
|
||||
}
|
||||
// rATType
|
||||
rATType := ""
|
||||
if v, ok := cdrJSON["rATType"]; ok && v != nil {
|
||||
rATType = fmt.Sprint(v)
|
||||
}
|
||||
// pdpPDNType
|
||||
pdpPDNType := ""
|
||||
if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil {
|
||||
pdpPDNType = fmt.Sprint(v)
|
||||
}
|
||||
// servedPDPPDNAddress
|
||||
servedPDPPDNAddress := ""
|
||||
if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil {
|
||||
servedPDPPDNAddress = fmt.Sprint(v)
|
||||
}
|
||||
// servedPDPPDNAddress
|
||||
servingNodeAddress := []string{}
|
||||
if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil {
|
||||
for _, v := range v.([]any) {
|
||||
servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v))
|
||||
}
|
||||
}
|
||||
// servingNodeType
|
||||
servingNodeType := []string{}
|
||||
if v, ok := cdrJSON["servingNodeType"]; ok && v != nil {
|
||||
for _, v := range v.([]any) {
|
||||
if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil {
|
||||
servingNodeType = append(servingNodeType, fmt.Sprint(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
// accessPointNameNI
|
||||
accessPointNameNI := ""
|
||||
if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil {
|
||||
accessPointNameNI = fmt.Sprint(v)
|
||||
}
|
||||
// causeForRecClosing
|
||||
causeForRecClosing := ""
|
||||
if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil {
|
||||
causeForRecClosing = fmt.Sprint(v)
|
||||
}
|
||||
// recordSequenceNumber
|
||||
recordSequenceNumber := ""
|
||||
if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil {
|
||||
recordSequenceNumber = fmt.Sprint(v)
|
||||
}
|
||||
// localRecordSequenceNumber
|
||||
localRecordSequenceNumber := ""
|
||||
if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil {
|
||||
localRecordSequenceNumber = fmt.Sprint(v)
|
||||
}
|
||||
// 数据量上行链路
|
||||
var dataVolumeGPRSUplink int64 = 0
|
||||
// 数据量下行链路
|
||||
var dataVolumeGPRSDownlink int64 = 0
|
||||
if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil {
|
||||
usageList := v.([]any)
|
||||
if len(usageList) > 0 {
|
||||
for _, used := range usageList {
|
||||
usedUnit := used.(map[string]any)
|
||||
if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk {
|
||||
dataVolumeGPRSUplink = parse.Number(dup)
|
||||
}
|
||||
if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk {
|
||||
dataVolumeGPRSDownlink = parse.Number(ddown)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 时长
|
||||
duration := "-"
|
||||
if v, ok := cdrJSON["duration"]; ok && v != nil {
|
||||
duration = fmt.Sprint(parse.Number(v))
|
||||
}
|
||||
// 调用时间
|
||||
invocationTimestamp := ""
|
||||
if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
|
||||
invocationTimestamp = v.(string)
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: row.NeName,
|
||||
"C" + idx: row.RmUid,
|
||||
"D" + idx: chargingID,
|
||||
"E" + idx: servedIMSI,
|
||||
"F" + idx: servedMSISDN,
|
||||
"G" + idx: dataVolumeGPRSUplink,
|
||||
"H" + idx: dataVolumeGPRSDownlink,
|
||||
"I" + idx: duration,
|
||||
"J" + idx: invocationTimestamp,
|
||||
"K" + idx: pGWAddressUsed,
|
||||
"L" + idx: sGWAddress,
|
||||
"M" + idx: rATType,
|
||||
"N" + idx: pdpPDNType,
|
||||
"O" + idx: servedPDPPDNAddress,
|
||||
"P" + idx: strings.Join(servingNodeAddress, ","),
|
||||
"Q" + idx: strings.Join(servingNodeType, ","),
|
||||
"R" + idx: accessPointNameNI,
|
||||
"S" + idx: causeForRecClosing,
|
||||
"T" + idx: recordSequenceNumber,
|
||||
"U" + idx: localRecordSequenceNumber,
|
||||
"V" + idx: recordType,
|
||||
"W" + idx: invocationTimestamp,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
// ExportIMS 导出数据到 xlsx 文件
|
||||
func (r CDREvent) ExportIMS(rows []model.CDREvent, fileName, language string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "NE Name",
|
||||
"C1": "Record Behavior",
|
||||
"D1": "Type",
|
||||
"E1": "Caller",
|
||||
"F1": "Called",
|
||||
"G1": "Duration",
|
||||
"H1": "Result Code",
|
||||
"I1": "Result Cause",
|
||||
"J1": "Call Start Time",
|
||||
"K1": "Hangup Time",
|
||||
}
|
||||
// 读取字典数据 CDR SIP响应代码类别类型
|
||||
dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code")
|
||||
// 读取字典数据 CDR SIP响应代码类别类型原因
|
||||
dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause")
|
||||
// 读取字典数据 CDR 呼叫类型
|
||||
dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var cdrJSON map[string]any
|
||||
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 记录类型
|
||||
recordType := ""
|
||||
if v, ok := cdrJSON["recordType"]; ok && v != nil {
|
||||
recordType = v.(string)
|
||||
}
|
||||
// 呼叫类型
|
||||
callType := "sms"
|
||||
callTypeLable := "SMS"
|
||||
if v, ok := cdrJSON["callType"]; ok && v != nil {
|
||||
callType = v.(string)
|
||||
for _, v := range dictCDRCallType {
|
||||
if callType == v.DictValue {
|
||||
callTypeLable = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 被叫
|
||||
called := ""
|
||||
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
|
||||
called = v.(string)
|
||||
}
|
||||
// 主叫
|
||||
caller := ""
|
||||
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
|
||||
caller = v.(string)
|
||||
}
|
||||
// 时长
|
||||
duration := "-"
|
||||
if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
|
||||
duration = fmt.Sprintf("%ds", parse.Number(v))
|
||||
}
|
||||
// 呼叫结果 非短信都有code作为结果 sms短信都ok
|
||||
callResult := "Other"
|
||||
callCause := "Call failure for other reason"
|
||||
if callType == "sms" {
|
||||
callResult = "Success"
|
||||
callCause = "Normal Send"
|
||||
} else {
|
||||
if v, ok := cdrJSON["cause"]; ok && v != nil {
|
||||
cause := fmt.Sprint(v)
|
||||
for _, v := range dictCDRSipCode {
|
||||
if cause == v.DictValue {
|
||||
callResult = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, v := range dictCDRSipCodeCause {
|
||||
if cause == v.DictValue {
|
||||
callCause = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 呼叫时间
|
||||
seizureTimeStr := ""
|
||||
if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
|
||||
if seizureTime := parse.Number(v); seizureTime > 0 {
|
||||
seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
} else {
|
||||
seizureTimeStr = v.(string)
|
||||
}
|
||||
}
|
||||
// 挂断时间
|
||||
releaseTimeStr := ""
|
||||
if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
|
||||
if releaseTime := parse.Number(v); releaseTime > 0 {
|
||||
releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
} else {
|
||||
releaseTimeStr = v.(string)
|
||||
}
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: row.NeName,
|
||||
"C" + idx: recordType,
|
||||
"D" + idx: callTypeLable,
|
||||
"E" + idx: caller,
|
||||
"F" + idx: called,
|
||||
"G" + idx: duration,
|
||||
"H" + idx: callResult,
|
||||
"I" + idx: callCause,
|
||||
"J" + idx: seizureTimeStr,
|
||||
"K" + idx: releaseTimeStr,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
@@ -14,26 +14,26 @@ import (
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 PerfKPI 结构体
|
||||
var NewPerfKPI = &PerfKPI{
|
||||
perfKPIRepository: repository.NewPerfKPI,
|
||||
// 实例化数据层 KpiReport 结构体
|
||||
var NewKpiReport = &KpiReport{
|
||||
kpiReportRepository: repository.NewKpiReport,
|
||||
}
|
||||
|
||||
// PerfKPI 性能统计 服务层处理
|
||||
type PerfKPI struct {
|
||||
perfKPIRepository *repository.PerfKPI // 性能统计数据信息
|
||||
// KpiReport 性能统计 服务层处理
|
||||
type KpiReport struct {
|
||||
kpiReportRepository *repository.KpiReport // 性能统计数据信息
|
||||
}
|
||||
|
||||
// SelectGoldKPI 通过网元指标数据信息
|
||||
func (r *PerfKPI) SelectGoldKPI(query model.GoldKPIQuery) []map[string]any {
|
||||
func (r *KpiReport) SelectGoldKPI(query model.KPIQuery) []map[string]any {
|
||||
// 获取数据指标id
|
||||
var kpiIds []string
|
||||
kpiTitles := r.perfKPIRepository.SelectGoldKPITitle(query.NeType)
|
||||
for _, kpiId := range kpiTitles {
|
||||
kpiIds = append(kpiIds, kpiId.KPIID)
|
||||
kpiTitles := r.kpiReportRepository.SelectGoldKPITitle(query.NeType)
|
||||
for _, v := range kpiTitles {
|
||||
kpiIds = append(kpiIds, v.KpiId)
|
||||
}
|
||||
|
||||
data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds)
|
||||
data := r.kpiReportRepository.SelectGoldKPI(query, kpiIds)
|
||||
if data == nil {
|
||||
return []map[string]any{}
|
||||
}
|
||||
@@ -41,29 +41,39 @@ func (r *PerfKPI) SelectGoldKPI(query model.GoldKPIQuery) []map[string]any {
|
||||
}
|
||||
|
||||
// SelectGoldKPITitle 网元对应的指标名称
|
||||
func (r *PerfKPI) SelectGoldKPITitle(neType string) []model.GoldKPITitle {
|
||||
return r.perfKPIRepository.SelectGoldKPITitle(neType)
|
||||
func (r *KpiReport) SelectGoldKPITitle(neType string) []model.KpiTitle {
|
||||
return r.kpiReportRepository.SelectGoldKPITitle(neType)
|
||||
}
|
||||
|
||||
// FindTitle 网元对应的指标名称
|
||||
func (r KpiReport) FindTitle(neType string) []model.KpiTitle {
|
||||
return r.kpiReportRepository.SelectGoldKPITitle(neType)
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (s KpiReport) Insert(param model.KpiReport) int64 {
|
||||
return s.kpiReportRepository.Insert(param)
|
||||
}
|
||||
|
||||
// TitleSelectByPage 分页查询指标名称
|
||||
func (r *PerfKPI) TitleSelectByPage(query map[string]string) ([]model.GoldKPITitle, int64) {
|
||||
return r.perfKPIRepository.TitleSelectByPage(query)
|
||||
func (r *KpiReport) TitleSelectByPage(query map[string]string) ([]model.KpiTitle, int64) {
|
||||
return r.kpiReportRepository.TitleSelectByPage(query)
|
||||
}
|
||||
|
||||
// TitleFind 查询信息
|
||||
func (r PerfKPI) TitleFind(param model.GoldKPITitle) []model.GoldKPITitle {
|
||||
return r.perfKPIRepository.TitleSelect(param)
|
||||
func (r KpiReport) TitleFind(param model.KpiTitle) []model.KpiTitle {
|
||||
return r.kpiReportRepository.TitleSelect(param)
|
||||
}
|
||||
|
||||
// TitleUpdate 修改指标状态
|
||||
func (r *PerfKPI) TitleUpdate(param model.GoldKPITitle) int64 {
|
||||
return r.perfKPIRepository.TitleUpdate(param)
|
||||
func (r *KpiReport) TitleUpdate(param model.KpiTitle) int64 {
|
||||
return r.kpiReportRepository.TitleUpdate(param)
|
||||
}
|
||||
|
||||
// FindData 通过网元指标数据信息
|
||||
func (s PerfKPI) FindData(query model.GoldKPIQuery) []map[string]any {
|
||||
func (s KpiReport) FindData(query model.KPIQuery) []map[string]any {
|
||||
// 原始数据
|
||||
rows := s.perfKPIRepository.SelectKPI(query)
|
||||
rows := s.kpiReportRepository.SelectKPI(query)
|
||||
if len(rows) <= 0 {
|
||||
return []map[string]any{}
|
||||
}
|
||||
@@ -169,7 +179,7 @@ func (s PerfKPI) FindData(query model.GoldKPIQuery) []map[string]any {
|
||||
|
||||
// UPFTodayFlowFind 查询UPF总流量 N3上行 N6下行
|
||||
// day 统计天数
|
||||
func (r PerfKPI) UPFTodayFlowFind(rmUID string, day int) (int64, int64) {
|
||||
func (r KpiReport) UPFTodayFlowFind(rmUID string, day int) (int64, int64) {
|
||||
// 获取当前日期
|
||||
now := time.Now()
|
||||
var upTotal, downTotal int64
|
||||
@@ -197,7 +207,7 @@ func (r PerfKPI) UPFTodayFlowFind(rmUID string, day int) (int64, int64) {
|
||||
}
|
||||
|
||||
// UPFTodayFlow UPF流量今日统计
|
||||
func (r PerfKPI) UPFTodayFlowUpdate(rmUID string, upValue, downValue int64) error {
|
||||
func (r KpiReport) UPFTodayFlowUpdate(rmUID string, upValue, downValue int64) error {
|
||||
// 按日期存储统计数据
|
||||
dateKey := time.Now().Format("2006-01-02")
|
||||
key := fmt.Sprintf("%sUPF_FLOW:%s:%s", cachekey.NE_DATA_KEY, rmUID, dateKey)
|
||||
@@ -214,7 +224,7 @@ func (r PerfKPI) UPFTodayFlowUpdate(rmUID string, upValue, downValue int64) erro
|
||||
|
||||
// UPFTodayFlowLoad UPF上下行数据到redis
|
||||
// day 统计天数
|
||||
func (r PerfKPI) UPFTodayFlowLoad(day int) {
|
||||
func (r KpiReport) UPFTodayFlowLoad(day int) {
|
||||
cacheKeys, _ := redis.GetKeys("", cachekey.NE_KEY+"UPF:*")
|
||||
if len(cacheKeys) == 0 {
|
||||
return
|
||||
@@ -237,7 +247,7 @@ func (r PerfKPI) UPFTodayFlowLoad(day int) {
|
||||
endTime := beginTime + 24*60*60*1000 - 1
|
||||
// 查询历史数据
|
||||
// down * 8 / 1000 / 1000 单位M
|
||||
info := r.perfKPIRepository.SelectUPFTotalFlow("UPF", v.RmUID, fmt.Sprint(beginTime), fmt.Sprint(endTime))
|
||||
info := r.kpiReportRepository.SelectUPFTotalFlow("UPF", v.RmUID, fmt.Sprint(beginTime), fmt.Sprint(endTime))
|
||||
if v, ok := info["up"]; ok && v == nil {
|
||||
info["up"] = 0
|
||||
}
|
||||
@@ -267,7 +277,7 @@ func (r PerfKPI) UPFTodayFlowLoad(day int) {
|
||||
}
|
||||
|
||||
// IMSBusyHour IMS忙时流量统计
|
||||
func (r PerfKPI) IMSBusyHour(rmUID string, timestamp int64) []map[string]any {
|
||||
func (r KpiReport) IMSBusyHour(rmUID string, timestamp int64) []map[string]any {
|
||||
t := time.UnixMilli(timestamp)
|
||||
beginTime := t
|
||||
endTime := t
|
||||
@@ -284,7 +294,7 @@ func (r PerfKPI) IMSBusyHour(rmUID string, timestamp int64) []map[string]any {
|
||||
endTime = beginTime.Add(time.Hour - time.Millisecond)
|
||||
}
|
||||
// 转换为毫秒级时间戳
|
||||
return r.perfKPIRepository.SelectIMSBusyHour(rmUID, beginTime.UnixMilli(), endTime.UnixMilli())
|
||||
return r.kpiReportRepository.SelectIMSBusyHour(rmUID, beginTime.UnixMilli(), endTime.UnixMilli())
|
||||
}
|
||||
|
||||
// 定义结构体用于存储话务量值和对应的时间
|
||||
@@ -294,12 +304,12 @@ type TrafficData struct {
|
||||
}
|
||||
|
||||
// IMSBusyWeek IMS忙时流量统计 周
|
||||
func (r PerfKPI) IMSBusyWeek(rmUID string, weekStart, weekEnd int64) map[string]any {
|
||||
func (r KpiReport) IMSBusyWeek(rmUID string, weekStart, weekEnd int64) map[string]any {
|
||||
weekStartTime := time.UnixMilli(weekStart)
|
||||
weekEndTime := time.UnixMilli(weekEnd)
|
||||
|
||||
// 1. 获取一周内每小时的呼叫数据
|
||||
data := r.perfKPIRepository.SelectIMSBusyHour(rmUID, weekStartTime.UnixMilli(), weekEndTime.UnixMilli())
|
||||
data := r.kpiReportRepository.SelectIMSBusyHour(rmUID, weekStartTime.UnixMilli(), weekEndTime.UnixMilli())
|
||||
|
||||
if len(data) == 0 {
|
||||
return map[string]any{
|
||||
229
src/modules/network_data/service/ue_event.go
Normal file
229
src/modules/network_data/service/ue_event.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
sysService "be.ems/src/modules/system/service"
|
||||
"github.com/tsmask/go-oam"
|
||||
)
|
||||
|
||||
// 实例化数据层 UEEvent 结构体
|
||||
var NewUEEvent = &UEEvent{
|
||||
ueEventRepository: repository.NewUEEvent,
|
||||
}
|
||||
|
||||
// UEEvent UE会话事件 服务层处理
|
||||
type UEEvent struct {
|
||||
ueEventRepository *repository.UEEvent // UE会话事件数据信息
|
||||
}
|
||||
|
||||
// FindByPage 根据条件分页查询
|
||||
func (r UEEvent) FindByPage(neType string, query map[string]string) ([]model.UEEvent, int64) {
|
||||
return r.ueEventRepository.SelectByPage(neType, query)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r UEEvent) DeleteByIds(neType string, ids []int64) (int64, error) {
|
||||
// 检查是否存在
|
||||
rows := r.ueEventRepository.SelectByIds(neType, ids)
|
||||
if len(rows) <= 0 {
|
||||
return 0, fmt.Errorf("no data")
|
||||
}
|
||||
|
||||
if len(rows) == len(ids) {
|
||||
rows := r.ueEventRepository.DeleteByIds(neType, ids)
|
||||
return rows, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r UEEvent) Insert(param model.UEEvent) int64 {
|
||||
return r.ueEventRepository.Insert(param)
|
||||
}
|
||||
|
||||
// ExportAMF 导出数据到 xlsx 文件
|
||||
func (r UEEvent) ExportAMF(rows []model.UEEvent, fileName, language string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "IMSI",
|
||||
"C1": "Event Type",
|
||||
"D1": "Result",
|
||||
"E1": "Time",
|
||||
}
|
||||
// 读取字典数据 UE 事件类型
|
||||
dictUEEventType := sysService.NewSysDictData.SelectDictDataByType("ue_event_type")
|
||||
// 读取字典数据 UE 事件认证代码类型
|
||||
dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code")
|
||||
// 读取字典数据 UE 事件CM状态
|
||||
dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var eventJSON map[string]interface{}
|
||||
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// 取IMSI
|
||||
imsi := ""
|
||||
if v, ok := eventJSON["imsi"]; ok && v != nil {
|
||||
imsi = v.(string)
|
||||
}
|
||||
// 取类型
|
||||
eventType := ""
|
||||
for _, v := range dictUEEventType {
|
||||
if row.EventType == v.DictValue {
|
||||
eventType = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
// 取结果
|
||||
eventResult := ""
|
||||
// 取时间
|
||||
timeStr := ""
|
||||
if row.EventType == oam.UENB_TYPE_AUTH {
|
||||
if v, ok := eventJSON["authTime"]; ok && v != nil {
|
||||
timeStr = v.(string)
|
||||
}
|
||||
if v, ok := eventJSON["authCode"]; ok && v != nil {
|
||||
eventResult = v.(string)
|
||||
for _, v := range dictUEAauthCode {
|
||||
if eventResult == v.DictValue {
|
||||
eventResult = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if row.EventType == oam.UENB_TYPE_DETACH {
|
||||
if v, ok := eventJSON["detachTime"]; ok && v != nil {
|
||||
timeStr = v.(string)
|
||||
}
|
||||
eventResult = "Success"
|
||||
}
|
||||
if row.EventType == oam.UENB_TYPE_CM {
|
||||
if v, ok := eventJSON["changeTime"]; ok && v != nil {
|
||||
timeStr = v.(string)
|
||||
}
|
||||
if v, ok := eventJSON["status"]; ok && v != nil {
|
||||
eventResult = fmt.Sprint(v)
|
||||
for _, v := range dictUEEventCmState {
|
||||
if eventResult == v.DictValue {
|
||||
eventResult = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: imsi,
|
||||
"C" + idx: eventType,
|
||||
"D" + idx: eventResult,
|
||||
"E" + idx: timeStr,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
// ExportMME 导出数据到 xlsx 文件
|
||||
func (r UEEvent) ExportMME(rows []model.UEEvent, fileName, language string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": "ID",
|
||||
"B1": "IMSI",
|
||||
"C1": "Event Type",
|
||||
"D1": "Result",
|
||||
"E1": "Time",
|
||||
}
|
||||
// 读取字典数据 UE 事件类型
|
||||
dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type")
|
||||
// 读取字典数据 UE 事件认证代码类型
|
||||
dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code")
|
||||
// 读取字典数据 UE 事件CM状态
|
||||
dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
// 解析 JSON 字符串为 map
|
||||
var eventJSON map[string]interface{}
|
||||
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
|
||||
if err != nil {
|
||||
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// 取IMSI
|
||||
imsi := ""
|
||||
if v, ok := eventJSON["imsi"]; ok && v != nil {
|
||||
imsi = v.(string)
|
||||
}
|
||||
// 取类型
|
||||
eventType := row.EventType
|
||||
for _, v := range dictUEEventType {
|
||||
if row.EventType == v.DictValue {
|
||||
eventType = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
// 取结果
|
||||
eventResult := ""
|
||||
if v, ok := eventJSON["result"]; ok && v != nil {
|
||||
eventResult = v.(string)
|
||||
if row.EventType == oam.UENB_TYPE_AUTH {
|
||||
for _, v := range dictUEAauthCode {
|
||||
if eventResult == v.DictValue {
|
||||
eventResult = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if row.EventType == oam.UENB_TYPE_CM {
|
||||
for _, v := range dictUEEventCmState {
|
||||
if eventResult == v.DictValue {
|
||||
eventResult = i18n.TKey(language, v.DictLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 取时间
|
||||
timeStr := ""
|
||||
if v, ok := eventJSON["timestamp"]; ok && v != nil {
|
||||
rowTime := parse.Number(v)
|
||||
timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
}
|
||||
|
||||
dataCells = append(dataCells, map[string]any{
|
||||
"A" + idx: row.ID,
|
||||
"B" + idx: imsi,
|
||||
"C" + idx: eventType,
|
||||
"D" + idx: eventResult,
|
||||
"E" + idx: timeStr,
|
||||
})
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
|
||||
}
|
||||
11
src/modules/notification/notification.go
Normal file
11
src/modules/notification/notification.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"be.ems/src/framework/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 模块路由注册
|
||||
func Setup(router *gin.Engine) {
|
||||
logger.Infof("开始加载 ====> notification 模块路由")
|
||||
}
|
||||
126
src/modules/notification/service/email.go
Normal file
126
src/modules/notification/service/email.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
ht "html/template"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wneessen/go-mail"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// EmailAlarm 发告警邮件
|
||||
func EmailAlarm(a neDataModel.Alarm, neIP string) error {
|
||||
emailList := fmt.Sprint(config.Get("alarm.alarmEmailForward.emailList"))
|
||||
if len(emailList) == 0 {
|
||||
return fmt.Errorf("email list is empty")
|
||||
}
|
||||
|
||||
// 模板
|
||||
htmlBodyTemplate := `
|
||||
<strong>Alarm information</strong>
|
||||
<p style="text-indent: 2.5em;">Sequence: {{.AlarmSeq}}</p>
|
||||
<p style="text-indent: 2.5em;">NE Name: {{.NeName}}</p>
|
||||
<p style="text-indent: 4.5em;">NE IP: {{.NeIp}}</p>
|
||||
<p style="text-indent: 5em;">Title: {{.AlarmTitle}}</p>
|
||||
<p style="text-indent: 3.5em;">Severity: {{.OrigSeverity}}</p>
|
||||
<p style="text-indent: 2.5em;">Event Time: {{.AlarmTime}}</p>
|
||||
<p style="text-indent: 2em;">Alarm Status: {{.AlarmStatus}}</p>
|
||||
<i>Automatic sent by OMC, please do not reply!</i>
|
||||
`
|
||||
htmlTpl, err := ht.New("htmltpl").Parse(htmlBodyTemplate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("EmailAlarm Parse alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
// 参数值
|
||||
data := map[string]any{
|
||||
"AlarmSeq": a.AlarmSeq,
|
||||
"NeName": a.NeName,
|
||||
"NeIp": neIP,
|
||||
"AlarmTitle": a.AlarmTitle,
|
||||
"OrigSeverity": a.OrigSeverity,
|
||||
"AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339),
|
||||
"AlarmStatus": a.AlarmStatus,
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if err := htmlTpl.Execute(buffer, data); err != nil {
|
||||
return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
htmlStr := buffer.String()
|
||||
|
||||
// 发送邮件
|
||||
err = EmailSendHTML(htmlStr, strings.Split(emailList, ","))
|
||||
if err != nil {
|
||||
return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// EmailSendHTML 发送HTML邮件
|
||||
func EmailSendHTML(htmlStr string, toEmailArr []string) error {
|
||||
// QQ 邮箱:
|
||||
// SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25)
|
||||
// 163 邮箱:
|
||||
// SMTP 服务器地址:smtp.163.com(端口:25)
|
||||
// host := "mail.agrandtech.com"
|
||||
// port := 25
|
||||
// userName := "smtpext@agrandtech.com"
|
||||
// password := "1000smtp@omc!"
|
||||
|
||||
emailConf := config.Get("alarm.alarmEmailForward").(map[string]any)
|
||||
enable := parse.Boolean(emailConf["enable"])
|
||||
if !enable {
|
||||
return fmt.Errorf("email notification not enable")
|
||||
}
|
||||
title := fmt.Sprint(emailConf["title"])
|
||||
smtp := fmt.Sprint(emailConf["smtp"])
|
||||
port := parse.Number(emailConf["port"])
|
||||
user := fmt.Sprint(emailConf["user"])
|
||||
password := fmt.Sprint(emailConf["password"])
|
||||
|
||||
message := mail.NewMsg()
|
||||
// 发件人
|
||||
if err := message.From(user); err != nil {
|
||||
return fmt.Errorf("failed to set From address: %s", err)
|
||||
}
|
||||
// 收件人
|
||||
hasTo := false
|
||||
for _, v := range toEmailArr {
|
||||
if err := message.AddTo(v); err != nil {
|
||||
logger.Errorf("failed to set To address: %v %s", v, err)
|
||||
continue
|
||||
}
|
||||
hasTo = true
|
||||
}
|
||||
if !hasTo {
|
||||
return fmt.Errorf("failed to set To address not has")
|
||||
}
|
||||
// 邮件主题
|
||||
message.Subject(title)
|
||||
// 邮件HTML内容
|
||||
message.SetBodyString(mail.TypeTextHTML, htmlStr)
|
||||
// 连接到邮件SMTP服务器
|
||||
client, err := mail.NewClient(smtp,
|
||||
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
||||
mail.WithUsername(user),
|
||||
mail.WithPort(int(port)),
|
||||
mail.WithPassword(password),
|
||||
mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create mail client: %s", err)
|
||||
}
|
||||
// 发送
|
||||
if err := client.DialAndSend(message); err != nil {
|
||||
return fmt.Errorf("failed to send mail: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
164
src/modules/notification/service/smsc.go
Normal file
164
src/modules/notification/service/smsc.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
tt "text/template"
|
||||
"time"
|
||||
|
||||
"github.com/linxGnu/gosmpp"
|
||||
"github.com/linxGnu/gosmpp/data"
|
||||
"github.com/linxGnu/gosmpp/pdu"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
var smscSession *gosmpp.Session
|
||||
|
||||
// connSM 连接smsc
|
||||
func connSM() *gosmpp.Session {
|
||||
if smscSession != nil {
|
||||
return smscSession
|
||||
}
|
||||
smscAddr := fmt.Sprint(config.Get("alarm.alarmSMSForward.smscAddr"))
|
||||
systemType := fmt.Sprint(config.Get("alarm.alarmSMSForward.systemType"))
|
||||
systemID := fmt.Sprint(config.Get("alarm.alarmSMSForward.systemID"))
|
||||
password := fmt.Sprint(config.Get("alarm.alarmSMSForward.password"))
|
||||
// 建立连接
|
||||
session, err := gosmpp.NewSession(
|
||||
gosmpp.TXConnector(gosmpp.NonTLSDialer, gosmpp.Auth{
|
||||
SMSC: smscAddr,
|
||||
SystemID: systemID,
|
||||
Password: password,
|
||||
SystemType: systemType,
|
||||
}),
|
||||
gosmpp.Settings{
|
||||
ReadTimeout: 2 * time.Second,
|
||||
OnSubmitError: func(_ pdu.PDU, err error) {
|
||||
logger.Errorf("failed to smpp submit error: %s", err.Error())
|
||||
},
|
||||
OnRebindingError: func(err error) {
|
||||
logger.Errorf("failed to smpp rebinding error: %s", err.Error())
|
||||
},
|
||||
}, -1)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to create smpp new session error: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
// defer session.Close()
|
||||
smscSession = session
|
||||
return smscSession
|
||||
}
|
||||
|
||||
// newSubmitSM 构建短信提交
|
||||
func newSubmitSM(destSM string, message string) (*pdu.SubmitSM, error) {
|
||||
dataCoding := parse.Number(config.Get("alarm.alarmSMSForward.dataCoding"))
|
||||
enc := data.FromDataCoding(byte(dataCoding))
|
||||
srcSM := fmt.Sprint(config.Get("alarm.alarmSMSForward.serviceNumber"))
|
||||
// 源地址
|
||||
srcAddr := pdu.NewAddress()
|
||||
srcAddr.SetTon(5)
|
||||
srcAddr.SetNpi(0)
|
||||
err := srcAddr.SetAddress(srcSM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
destAddr := pdu.NewAddress()
|
||||
destAddr.SetTon(1)
|
||||
destAddr.SetNpi(1)
|
||||
err = destAddr.SetAddress(destSM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// build up submitSM
|
||||
submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
|
||||
submitSM.SourceAddr = srcAddr
|
||||
submitSM.DestAddr = destAddr
|
||||
if err = submitSM.Message.SetMessageWithEncoding(message, enc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
submitSM.ProtocolID = 0
|
||||
submitSM.RegisteredDelivery = 1
|
||||
submitSM.ReplaceIfPresentFlag = 0
|
||||
submitSM.EsmClass = 0
|
||||
return submitSM, nil
|
||||
}
|
||||
|
||||
// SMSCAlarm 发告警短信
|
||||
func SMSCAlarm(a neDataModel.Alarm, neIP string) error {
|
||||
mobileList := fmt.Sprint(config.Get("alarm.alarmSMSForward.mobileList"))
|
||||
if len(mobileList) == 0 {
|
||||
return fmt.Errorf("smsc list is empty")
|
||||
}
|
||||
|
||||
// 模板
|
||||
textBodyTemplate := `Alarm Notification
|
||||
Sequence: {{.AlarmSeq}},
|
||||
NE Name: {{.NeName}}
|
||||
NE IP: {{.NeIp}}
|
||||
Title: {{.AlarmTitle}}
|
||||
Severity: {{.OrigSeverity}}
|
||||
Event Time: {{.AlarmTime}}
|
||||
Alarm Status: {{.AlarmStatus}}
|
||||
Automatic sent by OMC, please do not reply!`
|
||||
textTpl, err := tt.New("texttpl").Parse(textBodyTemplate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SMSCAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
// 参数值
|
||||
data := map[string]any{
|
||||
"AlarmSeq": a.AlarmSeq,
|
||||
"NeName": a.NeName,
|
||||
"NeIp": neIP,
|
||||
"AlarmTitle": a.AlarmTitle,
|
||||
"OrigSeverity": a.OrigSeverity,
|
||||
"AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339),
|
||||
"AlarmStatus": a.AlarmStatus,
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if err := textTpl.Execute(buffer, data); err != nil {
|
||||
return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
textStr := buffer.String()
|
||||
|
||||
// 发送短信
|
||||
err = SMSCSendText(textStr, strings.Split(mobileList, ","))
|
||||
if err != nil {
|
||||
return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SMSCSendText 发送文本短信
|
||||
func SMSCSendText(textStr string, toMobileArr []string) error {
|
||||
enable := parse.Boolean(config.Get("alarm.alarmSMSForward.enable"))
|
||||
if !enable {
|
||||
return fmt.Errorf("smsc notification not enable")
|
||||
}
|
||||
sm := connSM()
|
||||
if sm == nil {
|
||||
return fmt.Errorf("smpp new session create failed")
|
||||
}
|
||||
|
||||
errArr := []string{}
|
||||
for _, v := range toMobileArr {
|
||||
submitSM, err := newSubmitSM(v, textStr)
|
||||
if err != nil {
|
||||
errArr = append(errArr, err.Error())
|
||||
continue
|
||||
}
|
||||
if err = sm.Transceiver().Submit(submitSM); err != nil {
|
||||
errArr = append(errArr, err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(errArr) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errArr, ","))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
721
src/modules/oam/controller/api_rest.go
Normal file
721
src/modules/oam/controller/api_rest.go
Normal file
@@ -0,0 +1,721 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/tsmask/go-oam"
|
||||
goOamState "github.com/tsmask/go-oam/modules/state/service"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
oamService "be.ems/src/modules/oam/service"
|
||||
)
|
||||
|
||||
// NewAPIRest 实例化控制层
|
||||
var NewAPIRest = &APIRestController{}
|
||||
|
||||
// APIRestController 北向定义 控制层处理
|
||||
//
|
||||
// PATH /api/rest
|
||||
type APIRestController struct{}
|
||||
|
||||
// ResolveAlarm 接收告警
|
||||
//
|
||||
// POST /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms
|
||||
func (s APIRestController) ResolveAlarm(c *gin.Context) {
|
||||
var body []struct {
|
||||
AlarmSeq int `json:"alarmSeq"`
|
||||
AlarmId string `json:"alarmId"`
|
||||
NeId string `json:"neId"` // 收到实际是rmUID
|
||||
AlarmCode int `json:"alarmCode"`
|
||||
AlarmTitle string `json:"alarmTitle"`
|
||||
EventTime string `json:"eventTime"`
|
||||
AlarmType string `json:"alarmType"`
|
||||
OrigSeverity string `json:"origSeverity"`
|
||||
PerceivedSeverity string `json:"perceivedSeverity"`
|
||||
PVFlag string `json:"pvFlag"`
|
||||
NeName string `json:"neName"`
|
||||
NeType string `json:"neType"`
|
||||
ObjectUid string `json:"objectUid"`
|
||||
ObjectName string `json:"objectName"`
|
||||
ObjectType string `json:"objectType"`
|
||||
LocationInfo string `json:"locationInfo"`
|
||||
Province string `json:"province"`
|
||||
AlarmStatus int `json:"alarmStatus"`
|
||||
SpecificProblem string `json:"specificProblem"`
|
||||
SpecificProblemID string `json:"specificProblemID"`
|
||||
AddInfo string `json:"addInfo"`
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
|
||||
// alarmTypeValue 映射值
|
||||
alarmTypeValue := func(str string) string {
|
||||
arr := []string{
|
||||
oam.ALARM_TYPE_COMMUNICATION_ALARM,
|
||||
oam.ALARM_TYPE_EQUIPMENT_ALARM,
|
||||
oam.ALARM_TYPE_PROCESSING_FAILURE,
|
||||
oam.ALARM_TYPE_ENVIRONMENTAL_ALARM,
|
||||
oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if v == str {
|
||||
return v
|
||||
}
|
||||
if fmt.Sprint(k+1) == str {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// origSeverityValue 映射值
|
||||
origSeverityValue := func(str string) string {
|
||||
arr := []string{
|
||||
oam.ALARM_SEVERITY_CRITICAL,
|
||||
oam.ALARM_SEVERITY_MAJOR,
|
||||
oam.ALARM_SEVERITY_MINOR,
|
||||
oam.ALARM_SEVERITY_WARNING,
|
||||
oam.ALARM_SEVERITY_EVENT,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if v == str {
|
||||
return v
|
||||
}
|
||||
if fmt.Sprint(k+1) == str {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// alarmStatusValue 映射值
|
||||
alarmStatusValue := func(value int) string {
|
||||
arr := []string{
|
||||
oam.ALARM_STATUS_CLEAR,
|
||||
oam.ALARM_STATUS_ACTIVE,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if k == value {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return oam.ALARM_STATUS_ACTIVE
|
||||
}
|
||||
|
||||
alarmArr := make([]oam.Alarm, 0)
|
||||
for _, v := range body {
|
||||
if !strings.EqualFold(v.NeType, elementTypeValue) {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||
return
|
||||
}
|
||||
// 产生时间
|
||||
eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339)
|
||||
// 创建告警
|
||||
alarm := oam.Alarm{
|
||||
NeUid: v.NeId, // 网元唯一标识
|
||||
AlarmTime: eventTime.UnixMilli(), // 事件产生时间
|
||||
AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应
|
||||
AlarmCode: v.AlarmCode, // 告警状态码
|
||||
AlarmType: alarmTypeValue(v.AlarmType), // 告警类型
|
||||
AlarmTitle: v.AlarmTitle, // 告警标题
|
||||
PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别
|
||||
AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态
|
||||
SpecificProblem: v.SpecificProblem, // 告警问题原因
|
||||
SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID
|
||||
AddInfo: v.AddInfo, // 告警辅助信息
|
||||
LocationInfo: v.LocationInfo, // 告警定位信息
|
||||
}
|
||||
alarmArr = append(alarmArr, alarm)
|
||||
}
|
||||
|
||||
errArr := make([]string, 0)
|
||||
for _, alarm := range alarmArr {
|
||||
if err := oamService.NewAlarm.Resolve(alarm); err != nil {
|
||||
errArr = append(errArr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errArr) > 0 {
|
||||
c.JSON(200, resp.ErrData(errArr))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveCDR 接收话单
|
||||
//
|
||||
// POST /cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent
|
||||
func (s APIRestController) ResolveCDR(c *gin.Context) {
|
||||
var body struct {
|
||||
NeType string `json:"neType" `
|
||||
NeName string `json:"neName" `
|
||||
RmUID string `json:"rmUID" `
|
||||
Timestamp int `json:"timestamp" `
|
||||
CDR map[string]any `json:"CDR" `
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||
return
|
||||
}
|
||||
|
||||
recordTime := time.Now()
|
||||
if body.Timestamp > 1e12 {
|
||||
recordTime = time.UnixMilli(int64(body.Timestamp))
|
||||
} else if body.Timestamp > 1e9 {
|
||||
recordTime = time.Unix(int64(body.Timestamp), 0)
|
||||
}
|
||||
// 创建CDR
|
||||
cdr := oam.CDR{
|
||||
NeUid: body.RmUID, // 网元唯一标识
|
||||
RecordTime: recordTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||
Data: body.CDR, // 话单信息
|
||||
}
|
||||
if err := oamService.NewCDR.Resolve(cdr); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveKPI 接收KPI
|
||||
//
|
||||
// POST /performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index
|
||||
func (s APIRestController) ResolveKPI(c *gin.Context) {
|
||||
var body struct {
|
||||
Timestamp string `json:"TimeStamp" binding:"required"`
|
||||
Task struct {
|
||||
Period struct {
|
||||
StartTime string `json:"StartTime"`
|
||||
EndTime string `json:"EndTime"`
|
||||
} `json:"Period" binding:"required"`
|
||||
NE struct {
|
||||
NEName string `json:"NEName"`
|
||||
RmUID string `json:"rmUID"`
|
||||
NeType string `json:"NeType"`
|
||||
KPIs []struct {
|
||||
KPIID string `json:"KPIID"`
|
||||
Value int64 `json:"Value"`
|
||||
Err string `json:"Err"`
|
||||
} `json:"KPIs" binding:"required"`
|
||||
} `json:"NE" binding:"required"`
|
||||
} `json:"Task" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
if !strings.EqualFold(body.Task.NE.NeType, elementTypeValue) {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||
return
|
||||
}
|
||||
// index := c.Param("index")
|
||||
|
||||
timestamp := body.Timestamp
|
||||
taskPeriod := body.Task.Period
|
||||
taskNeKPIs := body.Task.NE.KPIs
|
||||
// 时间数据处理
|
||||
receiverTime := date.ParseStrToDate(timestamp, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
startTime := date.ParseStrToDate(taskPeriod.StartTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
endTime := date.ParseStrToDate(taskPeriod.EndTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
granularity := parse.Number(endTime.Sub(startTime).Seconds())
|
||||
// kpi data数据
|
||||
KpiValues := make(map[string]float64, 0)
|
||||
for _, v := range taskNeKPIs {
|
||||
KpiValues[v.KPIID] = float64(v.Value)
|
||||
}
|
||||
|
||||
// 创建KPI
|
||||
kpi := oam.KPI{
|
||||
NeUid: body.Task.NE.RmUID, // 网元唯一标识
|
||||
RecordTime: receiverTime.UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||
Granularity: granularity, // 时间间隔 5/10/.../60/300 (秒)
|
||||
Data: KpiValues, // 指标信息
|
||||
}
|
||||
if err := oamService.NewKPI.Resolve(kpi); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveNBState 接收基站状态变更
|
||||
//
|
||||
// POST /ueManagement/v1/elementType/:elementTypeValue/objectType/nbState
|
||||
func (s APIRestController) ResolveNBState(c *gin.Context) {
|
||||
var body struct {
|
||||
NeType string `json:"neType" `
|
||||
NeName string `json:"neName" `
|
||||
RmUID string `json:"rmUID"`
|
||||
StateList []struct {
|
||||
Address string `json:"address" `
|
||||
Name string `json:"name" `
|
||||
Position string `json:"position" `
|
||||
NbName string `json:"nbName" `
|
||||
State string `json:"state" ` // "OFF" or "ON"
|
||||
OffTime string `json:"offTime" ` //if State=OFF, will set it
|
||||
OnTime string `json:"onTime" ` //if State=ON , will set it
|
||||
}
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||
return
|
||||
}
|
||||
|
||||
if len(body.StateList) == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "no stateList"))
|
||||
return
|
||||
}
|
||||
|
||||
nbStateArr := make([]oam.NBState, 0)
|
||||
for _, v := range body.StateList {
|
||||
if v.Address == "" || v.State == "" {
|
||||
continue
|
||||
}
|
||||
stateTime := date.ParseStrToDate(v.OffTime, time.RFC3339)
|
||||
stateStr := oam.NB_STATE_OFF
|
||||
if v.State == "ON" {
|
||||
stateTime = date.ParseStrToDate(v.OnTime, time.RFC3339)
|
||||
stateStr = oam.NB_STATE_ON
|
||||
}
|
||||
|
||||
// 创建NbState
|
||||
nbState := oam.NBState{
|
||||
NeUid: body.RmUID, // 网元唯一标识
|
||||
RecordTime: time.Now().UnixMilli(), // 记录时间 时间戳毫秒,Push时自动填充
|
||||
Address: v.Address, // 基站地址
|
||||
DeviceName: v.NbName, // 基站设备名称
|
||||
State: stateStr, // 基站状态 ON/OFF
|
||||
StateTime: stateTime.UnixMilli(), // 基站状态时间 时间戳毫秒
|
||||
Name: v.Name, // 基站名称 网元标记
|
||||
Position: v.Position, // 基站位置 网元标记
|
||||
}
|
||||
nbStateArr = append(nbStateArr, nbState)
|
||||
}
|
||||
|
||||
errArr := make([]string, 0)
|
||||
for _, nbState := range nbStateArr {
|
||||
if err := oamService.NewNBState.Resolve(nbState); err != nil {
|
||||
errArr = append(errArr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errArr) > 0 {
|
||||
c.JSON(200, resp.ErrData(errArr))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveUENB 接收终端接入基站
|
||||
//
|
||||
// POST /logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent
|
||||
func (s APIRestController) ResolveUENB(c *gin.Context) {
|
||||
var body struct {
|
||||
NeType string `json:"neType" `
|
||||
NeName string `json:"neName" `
|
||||
RmUID string `json:"rmUID" `
|
||||
Timestamp int64 `json:"timestamp" `
|
||||
EventType string `json:"eventType" `
|
||||
EventJson map[string]any `json:"eventJSON" `
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
if !strings.EqualFold(body.NeType, elementTypeValue) {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "elementType is inconsistent with neType"))
|
||||
return
|
||||
}
|
||||
|
||||
// 记录时间
|
||||
recordTime := time.Now()
|
||||
if body.Timestamp > 1e12 {
|
||||
recordTime = time.UnixMilli(int64(body.Timestamp))
|
||||
} else if body.Timestamp > 1e9 {
|
||||
recordTime = time.Unix(int64(body.Timestamp), 0)
|
||||
}
|
||||
|
||||
// 创建UENB
|
||||
uenb := oam.UENB{
|
||||
NeUid: body.RmUID, // 网元唯一标识
|
||||
RecordTime: recordTime.UnixMilli(), // 记录时间
|
||||
NBId: "0", // 基站ID
|
||||
CellId: "0", // 小区ID
|
||||
TAC: "", // TAC
|
||||
IMSI: "", // IMSI
|
||||
Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值
|
||||
Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型
|
||||
}
|
||||
|
||||
// 基站ID
|
||||
if v, ok := body.EventJson["eNBID"]; ok && v != nil {
|
||||
uenb.NBId = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body.EventJson["gNBID"]; ok && v != nil {
|
||||
uenb.NBId = fmt.Sprint(v)
|
||||
}
|
||||
// 小区ID
|
||||
if v, ok := body.EventJson["cellID"]; ok && v != nil {
|
||||
uenb.CellId = fmt.Sprint(v)
|
||||
}
|
||||
// TAC
|
||||
if v, ok := body.EventJson["tacID"]; ok && v != nil {
|
||||
uenb.TAC = fmt.Sprint(v)
|
||||
}
|
||||
// IMSI
|
||||
if v, ok := body.EventJson["imsi"]; ok && v != nil {
|
||||
uenb.IMSI = fmt.Sprint(v)
|
||||
}
|
||||
// 结果值
|
||||
if v, ok := body.EventJson["result"]; ok && v != nil {
|
||||
uenb.Result = fmt.Sprint(v)
|
||||
}
|
||||
// 终端接入基站类型
|
||||
if v, ok := body.EventJson["type"]; ok && v != nil {
|
||||
switch v := fmt.Sprint(v); v {
|
||||
case "detach":
|
||||
uenb.Type = oam.UENB_TYPE_DETACH
|
||||
case "auth-result":
|
||||
uenb.Type = oam.UENB_TYPE_AUTH
|
||||
case "cm-state":
|
||||
uenb.Type = oam.UENB_TYPE_CM
|
||||
}
|
||||
}
|
||||
|
||||
if err := oamService.NewUENB.Resolve(uenb); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveUENBByAMF 接收终端接入基站-AMF
|
||||
//
|
||||
// POST /upload-ue/v1/:eventType
|
||||
func (s APIRestController) ResolveUENBByAMF(c *gin.Context) {
|
||||
var body map[string]any
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 创建UENB
|
||||
uenb := oam.UENB{
|
||||
NeUid: "4400HXAMF001", // 网元唯一标识
|
||||
RecordTime: 0, // 记录时间
|
||||
NBId: "0", // 基站ID
|
||||
CellId: "0", // 小区ID
|
||||
TAC: "", // TAC
|
||||
IMSI: "", // IMSI
|
||||
Result: oam.UENB_RESULT_AUTH_SUCCESS, // 结果值
|
||||
Type: oam.UENB_TYPE_DETACH, // 终端接入基站类型
|
||||
}
|
||||
|
||||
// 从eventJson中获取rmUID
|
||||
if v, ok := body["rmUID"]; ok {
|
||||
uenb.NeUid = fmt.Sprint(v)
|
||||
}
|
||||
|
||||
// 统一格式
|
||||
eventType := c.Param("eventType")
|
||||
switch eventType {
|
||||
case "auth-result":
|
||||
// {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"}
|
||||
if v, ok := body["imsi"]; ok {
|
||||
uenb.IMSI = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["cellID"]; ok {
|
||||
uenb.CellId = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["gNBID"]; ok {
|
||||
uenb.NBId = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["tacID"]; ok {
|
||||
uenb.TAC = fmt.Sprint(v)
|
||||
}
|
||||
|
||||
if v, ok := body["authCode"]; ok {
|
||||
uenb.Result = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["authTime"]; ok {
|
||||
authTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||
uenb.RecordTime = authTime.UnixMilli()
|
||||
}
|
||||
uenb.Type = oam.UENB_TYPE_AUTH
|
||||
case "detach":
|
||||
// {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"}
|
||||
if v, ok := body["imsi"]; ok {
|
||||
uenb.IMSI = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["detachResult"]; ok {
|
||||
if v == "0" {
|
||||
uenb.Result = oam.UENB_RESULT_AUTH_SUCCESS
|
||||
} else {
|
||||
uenb.Result = fmt.Sprint(v)
|
||||
}
|
||||
}
|
||||
if v, ok := body["detachTime"]; ok {
|
||||
detachTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||
uenb.RecordTime = detachTime.UnixMilli()
|
||||
}
|
||||
uenb.Type = oam.UENB_TYPE_DETACH
|
||||
case "cm-state":
|
||||
// {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2}
|
||||
if v, ok := body["imsi"]; ok {
|
||||
uenb.IMSI = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["status"]; ok {
|
||||
uenb.Result = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body["changeTime"]; ok {
|
||||
changeTime := date.ParseStrToDate(fmt.Sprint(v), date.YYYY_MM_DD_HH_MM_SS)
|
||||
uenb.RecordTime = changeTime.UnixMilli()
|
||||
}
|
||||
uenb.Type = oam.UENB_TYPE_CM
|
||||
}
|
||||
|
||||
if err := oamService.NewUENB.Resolve(uenb); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// ResolveAlarmHistory 拉取告警历史
|
||||
//
|
||||
// GET /faultManagement/v1/elementType/:elementTypeValue/objectType/alarms
|
||||
func (s APIRestController) ResolveAlarmHistory(c *gin.Context) {
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
|
||||
// Get alarms from OMC return 204
|
||||
if strings.ToLower(elementTypeValue) == "omc" {
|
||||
c.JSON(200, resp.OkMsg("omc alarms no content"))
|
||||
return
|
||||
}
|
||||
|
||||
// alarmTypeValue 映射值
|
||||
alarmTypeValue := func(str string) string {
|
||||
arr := []string{
|
||||
oam.ALARM_TYPE_COMMUNICATION_ALARM,
|
||||
oam.ALARM_TYPE_EQUIPMENT_ALARM,
|
||||
oam.ALARM_TYPE_PROCESSING_FAILURE,
|
||||
oam.ALARM_TYPE_ENVIRONMENTAL_ALARM,
|
||||
oam.ALARM_TYPE_QUALITY_OF_SERVICE_ALARM,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if v == str {
|
||||
return v
|
||||
}
|
||||
if fmt.Sprint(k+1) == str {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// origSeverityValue 映射值
|
||||
origSeverityValue := func(str string) string {
|
||||
arr := []string{
|
||||
oam.ALARM_SEVERITY_CRITICAL,
|
||||
oam.ALARM_SEVERITY_MAJOR,
|
||||
oam.ALARM_SEVERITY_MINOR,
|
||||
oam.ALARM_SEVERITY_WARNING,
|
||||
oam.ALARM_SEVERITY_EVENT,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if v == str {
|
||||
return v
|
||||
}
|
||||
if fmt.Sprint(k+1) == str {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// alarmStatusValue 映射值
|
||||
alarmStatusValue := func(value int) string {
|
||||
arr := []string{
|
||||
oam.ALARM_STATUS_CLEAR,
|
||||
oam.ALARM_STATUS_ACTIVE,
|
||||
}
|
||||
for k, v := range arr {
|
||||
if k == value {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return oam.ALARM_STATUS_ACTIVE
|
||||
}
|
||||
|
||||
alarmArr := make([]oam.Alarm, 0)
|
||||
type body struct {
|
||||
AlarmSeq int `json:"alarmSeq"`
|
||||
AlarmId string `json:"alarmId"`
|
||||
NeId string `json:"neId"` // 收到实际是rmUID
|
||||
AlarmCode int `json:"alarmCode"`
|
||||
AlarmTitle string `json:"alarmTitle"`
|
||||
EventTime string `json:"eventTime"`
|
||||
AlarmType string `json:"alarmType"`
|
||||
OrigSeverity string `json:"origSeverity"`
|
||||
PerceivedSeverity string `json:"perceivedSeverity"`
|
||||
PVFlag string `json:"pvFlag"`
|
||||
NeName string `json:"neName"`
|
||||
NeType string `json:"neType"`
|
||||
ObjectUid string `json:"objectUid"`
|
||||
ObjectName string `json:"objectName"`
|
||||
ObjectType string `json:"objectType"`
|
||||
LocationInfo string `json:"locationInfo"`
|
||||
Province string `json:"province"`
|
||||
AlarmStatus int `json:"alarmStatus"`
|
||||
SpecificProblem string `json:"specificProblem"`
|
||||
SpecificProblemID string `json:"specificProblemID"`
|
||||
AddInfo string `json:"addInfo"`
|
||||
}
|
||||
parseItem := func(v body) oam.Alarm {
|
||||
// 产生时间
|
||||
eventTime := date.ParseStrToDate(v.EventTime, time.RFC3339)
|
||||
// 创建告警
|
||||
alarm := oam.Alarm{
|
||||
NeUid: v.NeId, // 网元唯一标识
|
||||
AlarmTime: eventTime.UnixMilli(), // 事件产生时间
|
||||
AlarmId: v.AlarmId, // 告警ID 唯一,清除时对应
|
||||
AlarmCode: v.AlarmCode, // 告警状态码
|
||||
AlarmType: alarmTypeValue(v.AlarmType), // 告警类型
|
||||
AlarmTitle: v.AlarmTitle, // 告警标题
|
||||
PerceivedSeverity: origSeverityValue(v.OrigSeverity), // 告警级别
|
||||
AlarmStatus: alarmStatusValue(v.AlarmStatus), // 告警状态
|
||||
SpecificProblem: v.SpecificProblem, // 告警问题原因
|
||||
SpecificProblemID: v.SpecificProblemID, // 告警问题原因ID
|
||||
AddInfo: v.AddInfo, // 告警辅助信息
|
||||
LocationInfo: v.LocationInfo, // 告警定位信息
|
||||
}
|
||||
return alarm
|
||||
}
|
||||
var neInfos []neModel.NeInfo
|
||||
if elementTypeValue == "all" {
|
||||
neInfos = neService.NewNeInfo.Find(neModel.NeInfo{}, false, false)
|
||||
} else {
|
||||
neInfos = neService.NewNeInfo.FindByNeType(strings.ToUpper(elementTypeValue))
|
||||
}
|
||||
for _, neInfo := range neInfos {
|
||||
data, err := neFetchlink.AlarmHistory(neInfo)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to fetch alarm history:%s", err.Error())
|
||||
continue
|
||||
}
|
||||
if len(data) == 0 {
|
||||
logger.Warnf("not found sync alarms %s", neInfo.RmUID)
|
||||
continue
|
||||
}
|
||||
|
||||
bodyArr := make([]body, 0)
|
||||
// 将 []map[string]any 序列化为 JSON 字符串
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
logger.Errorf("marshal error: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 反序列化到结构体
|
||||
err = json.Unmarshal(jsonData, &bodyArr)
|
||||
if err != nil {
|
||||
logger.Errorf("Error unmarshal error: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
for _, v := range bodyArr {
|
||||
alarmArr = append(alarmArr, parseItem(v))
|
||||
}
|
||||
}
|
||||
|
||||
errArr := make([]string, 0)
|
||||
for _, alarm := range alarmArr {
|
||||
if err := oamService.NewAlarm.Resolve(alarm); err != nil {
|
||||
errArr = append(errArr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errArr) > 0 {
|
||||
c.JSON(200, resp.OkData(errArr))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// QuerySystemState 查询系统状态
|
||||
//
|
||||
// GET /systemManagement/v1/elementType/:elementTypeValue/objectType/systemState
|
||||
func (s APIRestController) QuerySystemState(c *gin.Context) {
|
||||
elementTypeValue := c.Param("elementTypeValue")
|
||||
if strings.ToLower(elementTypeValue) != "omc" {
|
||||
c.JSON(200, resp.ErrMsg("elementType only omc"))
|
||||
return
|
||||
}
|
||||
info := goOamState.NewState.Info()
|
||||
info.SerialNum = "-"
|
||||
info.ExpiryDate = "-"
|
||||
info.Capability = 50
|
||||
info.Version = "config.Version"
|
||||
c.JSON(200, info)
|
||||
}
|
||||
|
||||
// NeConfigOMC 网元配置对端网管信息
|
||||
//
|
||||
// PUT /systemManagement/v1/elementType/:elementTypeValue/objectType/config/omcNeConfig
|
||||
func (s APIRestController) NeConfigOMC(c *gin.Context) {
|
||||
c.JSON(204, nil)
|
||||
}
|
||||
|
||||
// @Description CBSManagement CB消息
|
||||
type CBSState struct {
|
||||
NeName string `json:"neName"` // 网元名称
|
||||
RmUID string `json:"rmUID"` // 网元唯一标识
|
||||
EventData []oamService.CBSEventData `json:"eventData"` // 事件数据
|
||||
}
|
||||
|
||||
func (s APIRestController) ResolveCBSState(c *gin.Context) {
|
||||
var state CBSState
|
||||
if err := c.ShouldBindBodyWithJSON(&state); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
for _, eventData := range state.EventData {
|
||||
if err := oamService.NewCBS.Resolve(eventData); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
42
src/modules/oam/oam.go
Normal file
42
src/modules/oam/oam.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package oam
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/oam/service"
|
||||
)
|
||||
|
||||
// Setup 模块路由注册
|
||||
func Setup(router *gin.Engine) {
|
||||
logger.Infof("开始加载 ====> oam 模块路由")
|
||||
|
||||
// 网管接收端收告警
|
||||
oam.AlarmReceiveRoute(router, service.NewAlarm.Resolve)
|
||||
// 网管接收端收终端接入基站
|
||||
oam.UENBReceiveRoute(router, service.NewUENB.Resolve)
|
||||
// 网管接收端收基站状态
|
||||
oam.NBStateReceiveRoute(router, service.NewNBState.Resolve)
|
||||
// 网管接收端收话单
|
||||
oam.CDRReceiveRoute(router, service.NewCDR.Resolve)
|
||||
// 网管接收端收KPI
|
||||
oam.KPIReceiveRoute(router, service.NewKPI.Resolve)
|
||||
|
||||
// APIRest 北向定义
|
||||
// aprRest := controller.NewAPIRest
|
||||
// aprRestGroup := router.Group("/api/rest")
|
||||
// {
|
||||
// aprRestGroup.GET("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarmHistory)
|
||||
// aprRestGroup.POST("/faultManagement/v1/elementType/:elementTypeValue/objectType/alarms", aprRest.ResolveAlarm)
|
||||
// aprRestGroup.POST("/cdrManagement/v1/elementType/:elementTypeValue/objectType/cdrEvent", aprRest.ResolveCDR)
|
||||
// aprRestGroup.POST("/performanceManagement/v1/elementType/:elementTypeValue/objectType/kpiReport/:index", aprRest.ResolveKPI)
|
||||
// aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/nbState", aprRest.ResolveNBState)
|
||||
// aprRestGroup.POST("/ueManagement/v1/elementType/:elementTypeValue/objectType/cbsState", aprRest.ResolveCBSState)
|
||||
// aprRestGroup.POST("/logManagement/v1/elementType/:elementTypeValue/objectType/ueEvent", aprRest.ResolveUENB)
|
||||
// router.POST("/upload-ue/v1/:eventType", aprRest.ResolveUENBByAMF) // AMF特殊上报
|
||||
// aprRestGroup.GET("/systemManagement/v1/elementType/:elementTypeValue/objectType/systemState", aprRest.QuerySystemState)
|
||||
// aprRestGroup.PUT("/systemManagement/v1/elementType/:elementTypeValue/objectType/config/omcNeConfig", aprRest.NeConfigOMC)
|
||||
// }
|
||||
|
||||
}
|
||||
301
src/modules/oam/service/alarm.go
Normal file
301
src/modules/oam/service/alarm.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
notificationService "be.ems/src/modules/notification/service"
|
||||
traceService "be.ems/src/modules/trace/service"
|
||||
wsService "be.ems/src/modules/ws/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 Alarm 结构体
|
||||
var NewAlarm = &Alarm{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
wsService: wsService.NewWSSend,
|
||||
alarmService: neDataService.NewAlarm,
|
||||
alarmEventService: neDataService.NewAlarmEvent,
|
||||
alarmLogService: neDataService.NewAlarmLog,
|
||||
alarmForwardLogService: neDataService.NewAlarmForwardLog,
|
||||
}
|
||||
|
||||
// Alarm 消息处理
|
||||
type Alarm struct {
|
||||
neInfoService *neService.NeInfo
|
||||
wsService *wsService.WSSend
|
||||
alarmService *neDataService.Alarm
|
||||
alarmEventService *neDataService.AlarmEvent
|
||||
alarmLogService *neDataService.AlarmLog
|
||||
alarmForwardLogService *neDataService.AlarmForwardLog
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *Alarm) Resolve(a oam.Alarm) error {
|
||||
// 是否存在网元
|
||||
neInfo := s.neInfoService.FindByRmuid(a.NeUid)
|
||||
if neInfo.NeType == "" || neInfo.RmUID != a.NeUid {
|
||||
return fmt.Errorf("resolve alarm network element does not exist %s", a.NeUid)
|
||||
}
|
||||
|
||||
// seq 告警序号
|
||||
lastSeq := neDataService.NewAlarm.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId)
|
||||
|
||||
alarmTime := time.UnixMilli(a.AlarmTime)
|
||||
// 告警信息
|
||||
alarm := neDataModel.Alarm{
|
||||
NeType: neInfo.NeType,
|
||||
NeId: neInfo.NeId,
|
||||
NeName: neInfo.NeName,
|
||||
Province: neInfo.Province,
|
||||
PvFlag: neInfo.PvFlag,
|
||||
AlarmSeq: fmt.Sprintf("%d", lastSeq+1),
|
||||
AlarmId: a.AlarmId,
|
||||
AlarmTitle: a.AlarmTitle,
|
||||
AlarmCode: fmt.Sprintf("%d", a.AlarmCode),
|
||||
EventTime: alarmTime,
|
||||
AlarmType: a.AlarmType,
|
||||
OrigSeverity: a.PerceivedSeverity,
|
||||
PerceivedSeverity: a.PerceivedSeverity,
|
||||
ObjectUid: neInfo.RmUID,
|
||||
ObjectName: neInfo.NeName,
|
||||
ObjectType: neInfo.NeType,
|
||||
LocationInfo: a.LocationInfo,
|
||||
AlarmStatus: a.AlarmStatus,
|
||||
SpecificProblem: a.SpecificProblem,
|
||||
SpecificProblemId: a.SpecificProblemID,
|
||||
AddInfo: a.AddInfo,
|
||||
}
|
||||
|
||||
// 进行清除
|
||||
if a.AlarmStatus == oam.ALARM_STATUS_CLEAR {
|
||||
if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT {
|
||||
if err := s.clearEvent(alarm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := s.clear(alarm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// 进行新增
|
||||
if a.AlarmStatus == oam.ALARM_STATUS_ACTIVE {
|
||||
if a.PerceivedSeverity == oam.ALARM_SEVERITY_EVENT {
|
||||
if err := s.addEvent(alarm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := s.add(alarm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
if err := s.saveLog(alarm); err != nil {
|
||||
return err
|
||||
}
|
||||
// 推送
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId), alarm)
|
||||
// 通知
|
||||
go s.notify(neInfo.IP, alarm)
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveLog 记录日志
|
||||
func (s *Alarm) saveLog(alarm neDataModel.Alarm) error {
|
||||
alarmLog := neDataModel.AlarmLog{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmSeq: alarm.AlarmSeq,
|
||||
AlarmId: alarm.AlarmId,
|
||||
AlarmTitle: alarm.AlarmTitle,
|
||||
AlarmCode: alarm.AlarmCode,
|
||||
AlarmStatus: alarm.AlarmStatus,
|
||||
AlarmType: alarm.AlarmType,
|
||||
OrigSeverity: alarm.PerceivedSeverity,
|
||||
EventTime: alarm.EventTime,
|
||||
}
|
||||
insertId := s.alarmLogService.Insert(alarmLog)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("save alarm log fail")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// add 新增告警
|
||||
func (s *Alarm) add(alarm neDataModel.Alarm) error {
|
||||
// 检查网元告警ID是否唯一
|
||||
alarmIdArr := s.alarmService.Find(neDataModel.Alarm{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmId: alarm.AlarmId,
|
||||
})
|
||||
if len(alarmIdArr) > 0 {
|
||||
return fmt.Errorf("already exists alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
insertId := s.alarmService.Insert(alarm)
|
||||
if insertId != "" {
|
||||
alarm.ID = insertId
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("add alarm fail")
|
||||
}
|
||||
|
||||
// clear 清除告警
|
||||
func (s *Alarm) clear(alarm neDataModel.Alarm) error {
|
||||
// 检查网元告警ID是否唯一
|
||||
alarmIdArr := s.alarmService.Find(neDataModel.Alarm{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmId: alarm.AlarmId,
|
||||
})
|
||||
if len(alarmIdArr) != 1 {
|
||||
return fmt.Errorf("not exists alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
|
||||
// 告警清除
|
||||
rows, _ := s.alarmService.ClearByIds([]string{alarmIdArr[0].ID}, alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR)
|
||||
if rows > 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("clear fail alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
|
||||
// addEvent 新增告警事件
|
||||
func (s *Alarm) addEvent(alarm neDataModel.Alarm) error {
|
||||
// 检查网元告警ID是否唯一
|
||||
alarmIdArr := s.alarmEventService.Find(neDataModel.AlarmEvent{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmId: alarm.AlarmId,
|
||||
})
|
||||
if len(alarmIdArr) > 0 {
|
||||
return fmt.Errorf("event already exists alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
// seq 告警序号
|
||||
lastSeq := s.alarmEventService.FindAlarmEventSeqLast(alarm.NeType, alarm.NeId)
|
||||
|
||||
alarmEvent := neDataModel.AlarmEvent{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmSeq: fmt.Sprintf("%d", lastSeq+1),
|
||||
AlarmId: alarm.AlarmId,
|
||||
AlarmTitle: alarm.AlarmTitle,
|
||||
AlarmCode: alarm.AlarmCode,
|
||||
EventTime: alarm.EventTime,
|
||||
ObjectUid: alarm.ObjectUid,
|
||||
ObjectName: alarm.ObjectName,
|
||||
ObjectType: alarm.ObjectType,
|
||||
LocationInfo: alarm.LocationInfo,
|
||||
AlarmStatus: alarm.AlarmStatus,
|
||||
SpecificProblem: alarm.SpecificProblem,
|
||||
SpecificProblemId: alarm.SpecificProblemId,
|
||||
AddInfo: alarm.AddInfo,
|
||||
}
|
||||
insertId := s.alarmEventService.Insert(alarmEvent)
|
||||
if insertId > 0 {
|
||||
alarmEvent.ID = insertId
|
||||
// 网元重启后,清除活动告警
|
||||
if alarm.AlarmCode == fmt.Sprintf("%d", constants.ALARM_EVENT_REBOOT) {
|
||||
rows := s.alarmService.Find(neDataModel.Alarm{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmStatus: oam.ALARM_STATUS_ACTIVE,
|
||||
})
|
||||
ids := make([]string, 0)
|
||||
for _, v := range rows {
|
||||
ids = append(ids, v.ID)
|
||||
}
|
||||
s.alarmService.ClearByIds(ids, alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR)
|
||||
}
|
||||
// 网元重启后,有跟踪任务的需要重新补发启动任务
|
||||
if alarm.AlarmCode == fmt.Sprintf("%d", constants.ALARM_EVENT_REBOOT) {
|
||||
traceService.NewTraceTask.RunUnstopped(alarm.NeType, alarm.NeId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("event add fail")
|
||||
}
|
||||
|
||||
// clearEvent 清除告警事件
|
||||
func (s *Alarm) clearEvent(alarm neDataModel.Alarm) error {
|
||||
alarmEventService := neDataService.NewAlarmEvent
|
||||
// 检查网元告警ID是否唯一
|
||||
alarmIdArr := alarmEventService.Find(neDataModel.AlarmEvent{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmId: alarm.AlarmId,
|
||||
})
|
||||
if len(alarmIdArr) != 1 {
|
||||
return fmt.Errorf("event not exists alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
|
||||
// 告警清除
|
||||
rows, _ := s.alarmEventService.ClearByIds([]int64{alarmIdArr[0].ID}, alarm.ObjectUid, constants.ALARM_CLEAR_TYPE_AUTO_CLEAR)
|
||||
if rows > 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("event clear fail alarmId:%s", alarm.AlarmId)
|
||||
}
|
||||
|
||||
// notify 通知
|
||||
func (s *Alarm) notify(neIp string, alarm neDataModel.Alarm) {
|
||||
// 邮箱
|
||||
emailEnable := parse.Boolean(config.Get("notification.email.enable"))
|
||||
if emailEnable {
|
||||
emailList := fmt.Sprint(config.Get("notification.email.emailList"))
|
||||
emailResult := "Sent Successfully!"
|
||||
emailErr := notificationService.EmailAlarm(alarm, neIp)
|
||||
if emailErr != nil {
|
||||
emailResult = emailErr.Error()
|
||||
}
|
||||
s.notifyLog(alarm, "EMAIL", emailList, emailResult)
|
||||
}
|
||||
|
||||
// 短信
|
||||
smscEnable := parse.Boolean(config.Get("notification.smsc.enable"))
|
||||
if smscEnable {
|
||||
mobileList := fmt.Sprint(config.Get("notification.smsc.mobileList"))
|
||||
smscResult := "Sent Successfully!"
|
||||
smscErr := notificationService.SMSCAlarm(alarm, neIp)
|
||||
if smscErr != nil {
|
||||
smscResult = smscErr.Error()
|
||||
}
|
||||
s.notifyLog(alarm, "SMSC", mobileList, smscResult)
|
||||
}
|
||||
}
|
||||
|
||||
// notifyLog 通知日志
|
||||
func (s *Alarm) notifyLog(alarm neDataModel.Alarm, forwardBy, toUser, result string) error {
|
||||
alarmForwardLog := neDataModel.AlarmForwardLog{
|
||||
NeType: alarm.NeType,
|
||||
NeId: alarm.NeId,
|
||||
AlarmSeq: alarm.AlarmSeq,
|
||||
AlarmId: alarm.AlarmId,
|
||||
AlarmTitle: alarm.AlarmTitle,
|
||||
AlarmCode: alarm.AlarmCode,
|
||||
AlarmStatus: alarm.AlarmStatus,
|
||||
AlarmType: alarm.AlarmType,
|
||||
OrigSeverity: alarm.OrigSeverity,
|
||||
EventTime: alarm.EventTime,
|
||||
Type: forwardBy,
|
||||
Target: toUser,
|
||||
Result: result,
|
||||
}
|
||||
// 记录日志
|
||||
insertId := s.alarmForwardLogService.Insert(alarmForwardLog)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("notify alarm log fail")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
29
src/modules/oam/service/cbs_state.go
Normal file
29
src/modules/oam/service/cbs_state.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 CDR 结构体
|
||||
var NewCBS = &CBS{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
cbcMessageService: neDataService.NewCBCMessage,
|
||||
}
|
||||
|
||||
// CDR 消息处理
|
||||
type CBS struct {
|
||||
neInfoService *neService.NeInfo
|
||||
cbcMessageService *neDataService.CBCMessage // CDR会话事件服务
|
||||
}
|
||||
|
||||
type CBSEventData struct {
|
||||
EventName string `json:"eventName"` // 事件名称
|
||||
MessageId int64 `json:"messageId"` // 消息ID
|
||||
Detail string `json:"detail"` // 详情
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *CBS) Resolve(c CBSEventData) error {
|
||||
return s.cbcMessageService.UpdateDetail(c.EventName, c.Detail)
|
||||
}
|
||||
71
src/modules/oam/service/cdr.go
Normal file
71
src/modules/oam/service/cdr.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
wsService "be.ems/src/modules/ws/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 CDR 结构体
|
||||
var NewCDR = &CDR{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
wsService: wsService.NewWSSend,
|
||||
cdrEventService: neDataService.NewCDREvent,
|
||||
}
|
||||
|
||||
// CDR 消息处理
|
||||
type CDR struct {
|
||||
neInfoService *neService.NeInfo
|
||||
wsService *wsService.WSSend
|
||||
cdrEventService *neDataService.CDREvent // CDR会话事件服务
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *CDR) Resolve(c oam.CDR) error {
|
||||
if c.Data == nil {
|
||||
return fmt.Errorf("cdr data is nil")
|
||||
}
|
||||
// 是否存在网元
|
||||
neInfo := s.neInfoService.FindByRmuid(c.NeUid)
|
||||
if neInfo.NeType == "" || neInfo.RmUID != c.NeUid {
|
||||
return fmt.Errorf("resolve cdr network element does not exist %s", c.NeUid)
|
||||
}
|
||||
|
||||
cdrByte, _ := json.Marshal(c.Data)
|
||||
cdrEvent := neDataModel.CDREvent{
|
||||
NeType: neInfo.NeType,
|
||||
NeName: neInfo.NeName,
|
||||
RmUid: neInfo.RmUID,
|
||||
Timestamp: c.RecordTime,
|
||||
CdrJson: string(cdrByte),
|
||||
CreatedAt: c.RecordTime,
|
||||
}
|
||||
insertId := s.cdrEventService.Insert(cdrEvent)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("add cdr data fail")
|
||||
}
|
||||
cdrEvent.ID = insertId
|
||||
|
||||
// 推送到ws订阅组
|
||||
switch neInfo.NeType {
|
||||
case "IMS":
|
||||
dataMap := c.Data.(map[string]any)
|
||||
v, ok := dataMap["recordType"]
|
||||
if ok && (v == "MOC" || v == "MTSM") {
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_IMS_CDR, neInfo.NeId), cdrEvent)
|
||||
}
|
||||
case "SMF":
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMF_CDR, neInfo.NeId), cdrEvent)
|
||||
case "SMSC":
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMSC_CDR, neInfo.NeId), cdrEvent)
|
||||
case "SGWC":
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SGWC_CDR, neInfo.NeId), cdrEvent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
241
src/modules/oam/service/kpi.go
Normal file
241
src/modules/oam/service/kpi.go
Normal file
@@ -0,0 +1,241 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/expr"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
wsService "be.ems/src/modules/ws/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 KPI 结构体
|
||||
var NewKPI = &KPI{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
wsService: wsService.NewWSSend,
|
||||
kpiReportService: neDataService.NewKpiReport,
|
||||
kpiCReportService: neDataService.NewKpiCReport,
|
||||
}
|
||||
|
||||
// KPI 消息处理
|
||||
type KPI struct {
|
||||
neInfoService *neService.NeInfo
|
||||
wsService *wsService.WSSend
|
||||
kpiReportService *neDataService.KpiReport
|
||||
kpiCReportService *neDataService.KpiCReport
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *KPI) Resolve(k oam.KPI) error {
|
||||
if len(k.Data) == 0 {
|
||||
return fmt.Errorf("kpi data is nil")
|
||||
}
|
||||
// 是否存在网元
|
||||
neInfo := s.neInfoService.FindByRmuid(k.NeUid)
|
||||
if neInfo.NeType == "" || neInfo.RmUID != k.NeUid {
|
||||
return fmt.Errorf("resolve kpi network element does not exist %s", k.NeUid)
|
||||
}
|
||||
|
||||
// 时间片
|
||||
curTime := time.Now()
|
||||
curSeconds := curTime.Hour()*3600 + curTime.Minute()*60 + curTime.Second()
|
||||
index := int64(curSeconds) / k.Granularity
|
||||
|
||||
if err := s.saveKPIData(neInfo, k, index); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.saveKPIDataC(neInfo, k, index); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveKPIData 存储KPI数据并推送到ws订阅组
|
||||
func (s KPI) saveKPIData(neInfo neModel.NeInfo, k oam.KPI, index int64) error {
|
||||
// 时间数据处理
|
||||
recordTime := time.Now()
|
||||
if k.RecordTime > 1e12 {
|
||||
recordTime = time.UnixMilli(k.RecordTime)
|
||||
} else if k.RecordTime > 1e9 {
|
||||
recordTime = time.Unix(k.RecordTime, 0)
|
||||
}
|
||||
recordDate := date.ParseDateToStr(recordTime, "2006-01-02")
|
||||
recordEndTime := date.ParseDateToStr(recordTime, "15:04:05")
|
||||
startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second)
|
||||
recordStartTime := date.ParseDateToStr(startTime, "15:04:05")
|
||||
|
||||
// kpi data数据json
|
||||
kpiTitles := s.kpiReportService.FindTitle(neInfo.NeType)
|
||||
KpiValues := make([]map[string]any, 0)
|
||||
for _, kt := range kpiTitles {
|
||||
item := map[string]any{
|
||||
"kpiId": kt.KpiId,
|
||||
"value": 0,
|
||||
"err": "",
|
||||
}
|
||||
// 匹配指标记录
|
||||
for k, v := range k.Data {
|
||||
if k == kt.KpiId {
|
||||
item["value"] = v
|
||||
}
|
||||
}
|
||||
KpiValues = append(KpiValues, item)
|
||||
}
|
||||
|
||||
KpiValuesByte, err := json.Marshal(KpiValues)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// KPI 信息
|
||||
kpiData := neDataModel.KpiReport{
|
||||
NeType: neInfo.NeType,
|
||||
NeName: neInfo.NeName,
|
||||
RmUid: neInfo.RmUID,
|
||||
Date: recordDate,
|
||||
StartTime: recordStartTime,
|
||||
EndTime: recordEndTime,
|
||||
Index: index,
|
||||
Granularity: k.Granularity,
|
||||
KpiValues: string(KpiValuesByte),
|
||||
CreatedAt: k.RecordTime,
|
||||
}
|
||||
insertId := s.kpiReportService.Insert(kpiData)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("add kpi data fail")
|
||||
}
|
||||
kpiData.ID = insertId
|
||||
|
||||
// 指标事件对象
|
||||
data := map[string]any{
|
||||
"neType": kpiData.NeType,
|
||||
"neName": kpiData.NeName,
|
||||
"rmUID": kpiData.RmUid,
|
||||
"startIndex": kpiData.Index,
|
||||
"timeGroup": kpiData.CreatedAt,
|
||||
// kip_id ...
|
||||
}
|
||||
for _, v := range KpiValues {
|
||||
data[fmt.Sprint(v["kpiId"])] = v["value"]
|
||||
}
|
||||
|
||||
// 推送到ws订阅组
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI, neInfo.NeType, neInfo.NeId), data)
|
||||
// 更新UPF总流量
|
||||
if neInfo.NeType == "UPF" {
|
||||
upValue := parse.Number(data["UPF.03"])
|
||||
downValue := parse.Number(data["UPF.06"])
|
||||
s.kpiReportService.UPFTodayFlowUpdate(neInfo.RmUID, upValue, downValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveKPIDataC 存储自定义KPI数据并推送到ws订阅组
|
||||
func (s KPI) saveKPIDataC(neInfo neModel.NeInfo, k oam.KPI, index int64) error {
|
||||
// 时间数据处理
|
||||
recordTime := time.Now()
|
||||
if k.RecordTime > 1e12 {
|
||||
recordTime = time.UnixMilli(k.RecordTime)
|
||||
} else if k.RecordTime > 1e9 {
|
||||
recordTime = time.Unix(k.RecordTime, 0)
|
||||
}
|
||||
recordDate := date.ParseDateToStr(recordTime, "2006-01-02")
|
||||
recordEndTime := date.ParseDateToStr(recordTime, "15:04:05")
|
||||
startTime := recordTime.Add(-time.Duration(k.Granularity) * time.Second)
|
||||
recordStartTime := date.ParseDateToStr(startTime, "15:04:05")
|
||||
|
||||
// kpi data数据json
|
||||
kpiCTitles := s.kpiCReportService.FindTitle(neInfo.NeType)
|
||||
KpiValues := make([]map[string]any, 0)
|
||||
// 自定义指标的表达式环境变量
|
||||
KpiExprEnv := make(map[string]any, 0)
|
||||
for k, v := range k.Data {
|
||||
KpiExprEnv[k] = v
|
||||
}
|
||||
// 自定义指标的计算
|
||||
for _, v := range kpiCTitles {
|
||||
item := map[string]any{
|
||||
"kpiId": v.KpiId,
|
||||
"value": 0,
|
||||
"err": "",
|
||||
}
|
||||
|
||||
// 匹配指标记录
|
||||
if envValue, envOk := KpiExprEnv[v.KpiId]; envOk {
|
||||
item["value"] = envValue
|
||||
}
|
||||
|
||||
// 计算结果
|
||||
exprStr, exprEnv := expr.ParseExprEnv(v.Expression, KpiExprEnv)
|
||||
result, err := expr.Eval(exprStr, exprEnv)
|
||||
if err != nil {
|
||||
item["value"] = 0
|
||||
item["err"] = err.Error()
|
||||
} else {
|
||||
if v.Unit == "%" {
|
||||
resultV, ok := result.(float64)
|
||||
if !ok || math.IsNaN(resultV) {
|
||||
resultV = 0
|
||||
}
|
||||
if resultV > 100 {
|
||||
result = 100
|
||||
}
|
||||
if resultV <= 0 {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
item["value"] = result
|
||||
}
|
||||
KpiValues = append(KpiValues, item)
|
||||
}
|
||||
KpiValuesByte, err := json.Marshal(KpiValues)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// KPI 信息
|
||||
kpiCData := neDataModel.KpiCReport{
|
||||
NeType: neInfo.NeType,
|
||||
NeName: neInfo.NeName,
|
||||
RmUid: neInfo.RmUID,
|
||||
Date: recordDate,
|
||||
StartTime: recordStartTime,
|
||||
EndTime: recordEndTime,
|
||||
Index: index,
|
||||
Granularity: k.Granularity,
|
||||
KpiValues: string(KpiValuesByte),
|
||||
CreatedAt: k.RecordTime,
|
||||
}
|
||||
insertId := s.kpiCReportService.Insert(kpiCData)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("add kpic data fail")
|
||||
}
|
||||
kpiCData.ID = insertId
|
||||
|
||||
// 指标事件对象
|
||||
data := map[string]any{
|
||||
"neType": kpiCData.NeType,
|
||||
"neName": kpiCData.NeName,
|
||||
"rmUID": kpiCData.RmUid,
|
||||
"startIndex": kpiCData.Index,
|
||||
"timeGroup": kpiCData.CreatedAt,
|
||||
// kip_id ...
|
||||
}
|
||||
for _, v := range KpiValues {
|
||||
data[fmt.Sprint(v["kpiId"])] = v["value"]
|
||||
}
|
||||
|
||||
// 推送到ws订阅组
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s_%s", wsService.GROUP_KPI_C, neInfo.NeType, neInfo.NeId), data)
|
||||
return nil
|
||||
}
|
||||
65
src/modules/oam/service/nb_state.go
Normal file
65
src/modules/oam/service/nb_state.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/utils/date"
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
wsService "be.ems/src/modules/ws/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 NBState 结构体
|
||||
var NewNBState = &NBState{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
wsService: wsService.NewWSSend,
|
||||
nbStateService: neDataService.NewNBState,
|
||||
}
|
||||
|
||||
// NBState 消息处理
|
||||
type NBState struct {
|
||||
neInfoService *neService.NeInfo
|
||||
wsService *wsService.WSSend
|
||||
nbStateService *neDataService.NBState
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *NBState) Resolve(n oam.NBState) error {
|
||||
// 是否存在网元
|
||||
neInfo := s.neInfoService.FindByRmuid(n.NeUid)
|
||||
if neInfo.NeType == "" || neInfo.RmUID != n.NeUid {
|
||||
return fmt.Errorf("resolve nb_state network element does not exist %s", n.NeUid)
|
||||
}
|
||||
|
||||
nbState := neDataModel.NBState{
|
||||
NeType: neInfo.NeType,
|
||||
NeId: neInfo.NeId,
|
||||
RmUid: neInfo.RmUID,
|
||||
Address: n.Address,
|
||||
Name: n.Name,
|
||||
Position: n.Position,
|
||||
NbName: n.DeviceName,
|
||||
State: n.State,
|
||||
Time: date.ParseDateToStr(n.StateTime, time.RFC3339),
|
||||
}
|
||||
insertId := s.nbStateService.Insert(nbState)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("add nb_state data fail")
|
||||
}
|
||||
nbState.ID = insertId
|
||||
|
||||
// 推送到ws订阅组
|
||||
switch neInfo.NeType {
|
||||
case "AMF":
|
||||
s.wsService.ByGroupID(wsService.GROUP_AMF_NB, nbState)
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_AMF_NB, neInfo.NeId), nbState)
|
||||
case "MME":
|
||||
s.wsService.ByGroupID(wsService.GROUP_MME_NB, nbState)
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_MME_NB, neInfo.NeId), nbState)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
69
src/modules/oam/service/ue_nb.go
Normal file
69
src/modules/oam/service/ue_nb.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/tsmask/go-oam"
|
||||
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataRepository "be.ems/src/modules/network_data/repository"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
wsService "be.ems/src/modules/ws/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 UENB 结构体
|
||||
var NewUENB = &UENB{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
wsService: wsService.NewWSSend,
|
||||
ueEventService: neDataService.NewUEEvent,
|
||||
}
|
||||
|
||||
// UENB 消息处理
|
||||
type UENB struct {
|
||||
neInfoService *neService.NeInfo
|
||||
wsService *wsService.WSSend
|
||||
ueEventService *neDataService.UEEvent // UE会话事件服务
|
||||
}
|
||||
|
||||
// Resolve 接收处理
|
||||
func (s *UENB) Resolve(u oam.UENB) error {
|
||||
// 是否存在网元
|
||||
neInfo := s.neInfoService.FindByRmuid(u.NeUid)
|
||||
if neInfo.NeType == "" || neInfo.RmUID != u.NeUid {
|
||||
return fmt.Errorf("resolve ue_nb network element does not exist %s", u.NeUid)
|
||||
}
|
||||
// 查询租户ID
|
||||
tenantID, _ := neDataRepository.NewSysTenant.Query(map[string]string{
|
||||
"imsi": u.IMSI,
|
||||
})
|
||||
|
||||
uenbByte, _ := json.Marshal(u)
|
||||
uenbEvent := neDataModel.UEEvent{
|
||||
NeType: neInfo.NeType,
|
||||
NeName: neInfo.NeName,
|
||||
RmUID: neInfo.RmUID,
|
||||
Timestamp: u.RecordTime,
|
||||
EventType: u.Type,
|
||||
EventJSONStr: string(uenbByte),
|
||||
TenantID: fmt.Sprintf("%d", tenantID),
|
||||
}
|
||||
|
||||
insertId := s.ueEventService.Insert(uenbEvent)
|
||||
if insertId <= 0 {
|
||||
return fmt.Errorf("add ue_nb data fail")
|
||||
}
|
||||
uenbEvent.ID = insertId
|
||||
|
||||
// 推送到ws订阅组
|
||||
switch neInfo.NeType {
|
||||
case "AMF":
|
||||
s.wsService.ByGroupID(wsService.GROUP_AMF_UE, uenbEvent)
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_AMF_UE, neInfo.NeId), uenbEvent)
|
||||
case "MME":
|
||||
s.wsService.ByGroupID(wsService.GROUP_MME_UE, uenbEvent)
|
||||
s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_MME_UE, neInfo.NeId), uenbEvent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user