diff --git a/features/fm/email.go b/features/fm/email.go index 24af203..2b87f41 100644 --- a/features/fm/email.go +++ b/features/fm/email.go @@ -20,11 +20,12 @@ func AlarmEmailForward(alarmData *Alarm) error {

Alarm information

Sequence: %d

NE name: %s

-

Title: %s

-

Severity: %s

-

Event Time: %s

-

Automatic send by OMC, don't reply!

- `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime) +

Title: %s

+

Severity: %s

+

Event Time: %s

+

Alarm Status: %d

+

Automatic sent by OMC, please do not reply!

+ `, alarmData.AlarmSeq, alarmData.NeName, alarmData.AlarmTitle, alarmData.OrigSeverity, alarmData.EventTime, alarmData.AlarmStatus) // message := fmt.Sprintf(` // Alarm information @@ -75,10 +76,9 @@ func AlarmEmailForward(alarmData *Alarm) error { EventTime: alarmData.EventTime, ToUser: strings.Join(*emails, ","), } - for _, email := range *emails { - m.SetHeader("To", email) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 - } + m.SetHeader("To", *emails...) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 + //m.SetHeader("To", strings.Join(*emails, " ")) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 //m.SetHeader("To", "zhangshuzhong@agrandtech.com", "simonzhangsz@outlook.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 //m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个 //m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个 diff --git a/features/mml/mml.go b/features/mml/mml.go index 99dbdc7..eeb1004 100644 --- a/features/mml/mml.go +++ b/features/mml/mml.go @@ -112,21 +112,8 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { } if neInfo != nil { - hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) - log.Error(errMsg) - mmlResult = append(mmlResult, errMsg) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - defer conn.Close() - - conn.SetDeadline(time.Now().Add(10 * time.Second)) switch strings.ToLower(neType) { - case "upf": + case "xxx": body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) if err != nil { log.Error("io.ReadAll is failed:", err) @@ -148,16 +135,29 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { // } // log.Debug(string(buf[0:n])) - loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) - _, err = conn.Write([]byte(loginStr)) - if err != nil { - log.Error("Failed to write:", err) - mmlResult = append(mmlResult, err.Error()) - response := Response{mmlResult} - services.ResponseWithJson(w, http.StatusOK, response) - return - } - time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + // hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) + // conn, err := net.Dial("tcp", hostMML) + // if err != nil { + // errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) + // log.Error(errMsg) + // mmlResult = append(mmlResult, errMsg) + // response := Response{mmlResult} + // services.ResponseWithJson(w, http.StatusOK, response) + // return + // } + // defer conn.Close() + + // conn.SetDeadline(time.Now().Add(10 * time.Second)) + // loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) + // _, err = conn.Write([]byte(loginStr)) + // if err != nil { + // log.Error("Failed to write:", err) + // mmlResult = append(mmlResult, err.Error()) + // response := Response{mmlResult} + // services.ResponseWithJson(w, http.StatusOK, response) + // return + // } + // time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) // n, err = conn.Write([]byte(config.GetYamlConfig().MML.User + "\n")) // if err != nil { @@ -203,6 +203,30 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { // log.Debug(string(buf[0:n])) for _, mml := range mmlRequest.MML { + hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) + conn, err := net.Dial("tcp", hostMML) + if err != nil { + errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) + log.Error(errMsg) + mmlResult = append(mmlResult, errMsg) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + defer conn.Close() + + conn.SetDeadline(time.Now().Add(10 * time.Second)) + + loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) + _, err = conn.Write([]byte(loginStr)) + if err != nil { + log.Error("Failed to write:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) mmlCommand := fmt.Sprintf("%s\n", mml) log.Debug("mml command:", mmlCommand) _, err = conn.Write([]byte(mmlCommand)) @@ -233,12 +257,157 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { result := re1.ReplaceAllString(string(buf[config.GetYamlConfig().MML.UpfHeaderLength:n-len(neType)-2]), "") result = re2.ReplaceAllString(result, "") mmlResult = append(mmlResult, result) + conn.Close() //mmlResult = append(mmlResult, string(buf[0:n-len(neType)-2])) // can't read buffer from upf telnet server, so return ok always // mmlResult = append(mmlResult, "COMMAND OK\n") } + case "ims": + body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) + if err != nil { + log.Error("io.ReadAll is failed:", err) + services.ResponseNotFound404UriNotExist(w, r) + return + } + log.Trace("Body:", string(body)) + + mmlRequest := new(MMLRequest) + _ = json.Unmarshal(body, mmlRequest) + + for _, mml := range mmlRequest.MML { + hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) + conn, err := net.Dial("tcp", hostMML) + if err != nil { + errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) + log.Error(errMsg) + mmlResult = append(mmlResult, errMsg) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + defer conn.Close() + + // localAddr := conn.LocalAddr() + // remoteAddr := conn.RemoteAddr() + // if localAddr == nil || remoteAddr == nil { + // errMsg := fmt.Sprintf("connect invalid: localAddr=%v, remoteAddr=%v", localAddr, remoteAddr) + // log.Error(errMsg) + // mmlResult = append(mmlResult, errMsg) + // response := Response{mmlResult} + // services.ResponseWithJson(w, http.StatusOK, response) + // return + // } + conn.SetDeadline(time.Now().Add(10 * time.Second)) + + _, err = conn.Write([]byte(config.GetYamlConfig().MML.User + "\n")) + if err != nil { + log.Error("Failed to write:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + log.Debug(string(buf[0:n])) + + _, err = conn.Write([]byte(config.GetYamlConfig().MML.Password + "\n")) + if err != nil { + log.Error("Failed to write:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + // loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) + // _, err = conn.Write([]byte(loginStr)) + // if err != nil { + // log.Error("Failed to write:", err) + // mmlResult = append(mmlResult, err.Error()) + // response := Response{mmlResult} + // services.ResponseWithJson(w, http.StatusOK, response) + // return + // } + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + log.Trace(string(buf[0 : n-len(neType)-2])) + + mmlCommand := fmt.Sprintf("%s\n", mml) + log.Debug("mml command:", mmlCommand) + _, err = conn.Write([]byte(mmlCommand)) + if err != nil { + log.Error("Failed to write:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE) + + n, err = conn.Read(buf[0:]) + if err != nil { + log.Error("Failed to read:", err) + mmlResult = append(mmlResult, err.Error()) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + log.Trace(string(buf[0 : n-len(neType)-2])) + + re1 := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) // 匹配包含␛的控制字符 + //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 + re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 + //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) + // upf telnet buffer只能读取一次,需要去掉前面的多余字符 + //result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") + result := re1.ReplaceAllString(string(buf[0:]), "") + result = re2.ReplaceAllString(result, "") + mmlResult = append(mmlResult, result) + conn.Close() + } default: + hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port) + conn, err := net.Dial("tcp", hostMML) + if err != nil { + errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) + log.Error(errMsg) + mmlResult = append(mmlResult, errMsg) + response := Response{mmlResult} + services.ResponseWithJson(w, http.StatusOK, response) + return + } + defer conn.Close() + + // localAddr := conn.LocalAddr() + // remoteAddr := conn.RemoteAddr() + // if localAddr == nil || remoteAddr == nil { + // errMsg := fmt.Sprintf("connect invalid: localAddr=%v, remoteAddr=%v", localAddr, remoteAddr) + // log.Error(errMsg) + // mmlResult = append(mmlResult, errMsg) + // response := Response{mmlResult} + // services.ResponseWithJson(w, http.StatusOK, response) + // return + // } + + conn.SetDeadline(time.Now().Add(10 * time.Second)) loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) _, err = conn.Write([]byte(loginStr)) if err != nil { diff --git a/restagent/etc/restconf.yaml b/restagent/etc/restconf.yaml index 8bfb473..167382c 100644 --- a/restagent/etc/restconf.yaml +++ b/restagent/etc/restconf.yaml @@ -38,12 +38,12 @@ database: type: mysql user: root # password: "1000omc@kp!" - # host: "192.168.2.219" + # host: "192.168.5.57" # port: 33066 # name: omc_db backup: d:/local.git/ems.agt/restagent/database password: "root@1234" - host: "192.168.2.152" + host: "192.168.5.57" port: 3306 name: "omc_db" # Redis 缓存数据,数据源声明全小写 @@ -52,8 +52,8 @@ redis: # OMC系统使用库 default: port: 6379 # Redis port - host: "192.168.2.152" # Redis host - password: "redis@1234" + host: "192.168.5.57" # Redis host + password: "" db: 10 # Redis db_num # UDM网元用户库 udmuser: @@ -117,7 +117,7 @@ omc: # Forward interface: # email/sms alarm: - forwardAlarm: true + forwardAlarm: false email: smtp: mail.agrandtech.com port: 25 diff --git a/restagent/makefile b/restagent/makefile index 542a0bb..68fcf75 100644 --- a/restagent/makefile +++ b/restagent/makefile @@ -1,7 +1,7 @@ # Makefile for rest agent project PROJECT = OMC -VERSION = 2.2311.8 +VERSION = 2.2312.8 PLATFORM = amd64 ARMPLATFORM = aarch64 BUILDDIR = ../../build diff --git a/restagent/static/helpDoc/zh_doc.pdf b/restagent/static/helpDoc/zh_doc.pdf new file mode 100644 index 0000000..e25d5ca Binary files /dev/null and b/restagent/static/helpDoc/zh_doc.pdf differ diff --git a/restagent/static/logo/en_brand.png b/restagent/static/logo/en_brand.png new file mode 100644 index 0000000..200025e Binary files /dev/null and b/restagent/static/logo/en_brand.png differ diff --git a/restagent/static/logo/en_icon.png b/restagent/static/logo/en_icon.png new file mode 100644 index 0000000..3ed445d Binary files /dev/null and b/restagent/static/logo/en_icon.png differ diff --git a/restagent/static/logo/zh_brand.png b/restagent/static/logo/zh_brand.png new file mode 100644 index 0000000..5810cf5 Binary files /dev/null and b/restagent/static/logo/zh_brand.png differ diff --git a/restagent/static/logo/zh_icon.png b/restagent/static/logo/zh_icon.png new file mode 100644 index 0000000..a5b6907 Binary files /dev/null and b/restagent/static/logo/zh_icon.png differ diff --git a/src/framework/config/config/config.default.yaml b/src/framework/config/config/config.default.yaml index db223dd..0515333 100644 --- a/src/framework/config/config/config.default.yaml +++ b/src/framework/config/config/config.default.yaml @@ -13,7 +13,7 @@ server: # 日志 logger: fileDir: "/usr/local/omc/log" - fileName: "restagent.log" + fileName: "ems_agt.log" level: 2 # 日志记录的等级 0:silent<1:info<2:warn<3:error maxDay: 180 # 日志会保留 180 天 maxSize: 10 # 调整按 10MB 大小的切割 diff --git a/src/modules/common/common.go b/src/modules/common/common.go index a78c831..6890f58 100644 --- a/src/modules/common/common.go +++ b/src/modules/common/common.go @@ -26,11 +26,11 @@ func Setup(router *gin.Engine) { // 系统可暴露的配置信息 indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig) - // 系统使用文档转存 - indexGroup.POST("/helpDoc", + // 转存上传文件到静态资源 + indexGroup.POST("/transferStaticFile", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.helpDoc", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewCommont.HelpDoc, + controller.NewCommont.TransferStaticFile, ) // 验证码操作处理 diff --git a/src/modules/common/controller/common.go b/src/modules/common/controller/common.go index c7329cf..a47d295 100644 --- a/src/modules/common/controller/common.go +++ b/src/modules/common/controller/common.go @@ -77,13 +77,14 @@ func (s *CommontController) SysConfig(c *gin.Context) { c.JSON(200, result.OkData(data)) } -// 转存帮助文档 +// 转存指定对应文件 // -// POST /helpDoc -func (s *CommontController) HelpDoc(c *gin.Context) { +// POST /transferStaticFile +func (s *CommontController) TransferStaticFile(c *gin.Context) { language := ctx.AcceptLanguage(c) var body struct { UploadPath string `json:"uploadPath" binding:"required"` + StaticPath string `json:"staticPath" binding:"required"` Language string `json:"language" binding:"required"` } if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { @@ -102,8 +103,9 @@ func (s *CommontController) HelpDoc(c *gin.Context) { return } - newFile := fmt.Sprintf("%s/helpDoc/%s_doc.pdf", dir, lang) - fmt.Println(newFile) + delPrefix := strings.Replace(body.StaticPath, static["prefix"].(string), "", 1) + staticPath := strings.Replace(delPrefix, "{language}", lang, 1) + newFile := fmt.Sprintf("%s%s", dir, staticPath) err = file.CopyUploadFile(body.UploadPath, newFile) if err != nil { diff --git a/src/modules/common/service/commont.impl.go b/src/modules/common/service/commont.impl.go index 56a5da0..218d20d 100644 --- a/src/modules/common/service/commont.impl.go +++ b/src/modules/common/service/commont.impl.go @@ -47,5 +47,11 @@ func (s *CommontImpl) SystemConfigInfo() map[string]string { // 系统设置-系统使用文档 helpDoc := s.sysConfigService.SelectConfigValueByKey("sys.helpDoc") infoMap["helpDoc"] = helpDoc + // 国际化切换 + i18nOpen := s.sysConfigService.SelectConfigValueByKey("sys.i18n.open") + infoMap["i18nOpen"] = i18nOpen + // 国际化默认语言 + i18nDefault := s.sysConfigService.SelectConfigValueByKey("sys.i18n.default") + infoMap["i18nDefault"] = i18nDefault return infoMap } diff --git a/src/modules/network_element/controller/perf_kpi.go b/src/modules/network_element/controller/perf_kpi.go new file mode 100644 index 0000000..05919a0 --- /dev/null +++ b/src/modules/network_element/controller/perf_kpi.go @@ -0,0 +1,90 @@ +package controller + +import ( + "ems.agt/lib/core/utils/date" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/vo/result" + neService "ems.agt/src/modules/network_element/service" + "github.com/gin-gonic/gin" +) + +// 实例化控制层 PerfKPIController 结构体 +var NewPerfKPI = &PerfKPIController{ + neInfoService: neService.NewNeInfoImpl, + perfKPIService: neService.NewPerfKPIImpl, +} + +// 性能统计 +// +// PATH /kpi +type PerfKPIController struct { + // 网元信息服务 + neInfoService neService.INeInfo + // 统计信息服务 + perfKPIService neService.IPerfKPI +} + +// 获取统计数据 +// +// GET /data +func (s *PerfKPIController) GoldKPI(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeID string `form:"neId" binding:"required"` + StartTime string `form:"startTime" binding:"required"` + EndTime string `form:"endTime" binding:"required"` + Interval int64 `form:"interval" binding:"required"` + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 时间格式校验 + startTime := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS) + if startTime.IsZero() { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + } + startTimeStr := startTime.Format(date.YYYY_MM_DD_HH_MM_SS) + endTime := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS) + if startTime.IsZero() { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + } + endTimeStr := endTime.Format(date.YYYY_MM_DD_HH_MM_SS) + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 获取数据指标id + var kpiIds []string + kpiTitles := s.perfKPIService.SelectGoldKPITitle(neInfo.NeType) + for _, kpiId := range kpiTitles { + kpiIds = append(kpiIds, kpiId.KPIID) + } + + // 查询数据 + kpiData := s.perfKPIService.SelectGoldKPI(neInfo.RmUID, neInfo.NeType, startTimeStr, endTimeStr, kpiIds, querys.Interval) + c.JSON(200, result.OkData(kpiData)) +} + +// 获取统计标题 +// +// GET /title +func (s *PerfKPIController) Title(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neType := c.Query("neType") + if neType == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + kpiTitles := s.perfKPIService.SelectGoldKPITitle(neType) + + c.JSON(200, result.OkData(kpiTitles)) +} diff --git a/src/modules/network_element/model/perf_kpi.go b/src/modules/network_element/model/perf_kpi.go new file mode 100644 index 0000000..def0164 --- /dev/null +++ b/src/modules/network_element/model/perf_kpi.go @@ -0,0 +1,11 @@ +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"` + TitleJson string `json:"titleJson" gorm:"column:title_json"` + CnTitle string `json:"cnTitle" gorm:"column:cn_title"` + EnTitle string `json:"enTitle" gorm:"column:en_title"` +} diff --git a/src/modules/network_element/network_element.go b/src/modules/network_element/network_element.go index bcb385b..d156c50 100644 --- a/src/modules/network_element/network_element.go +++ b/src/modules/network_element/network_element.go @@ -141,4 +141,17 @@ func Setup(router *gin.Engine) { ) } + // 性能统计信息 + kpiGroup := neGroup.Group("/kpi") + { + kpiGroup.GET("/title", + middleware.PreAuthorize(nil), + controller.NewPerfKPI.Title, + ) + kpiGroup.GET("/data", + middleware.PreAuthorize(nil), + controller.NewPerfKPI.GoldKPI, + ) + } + } diff --git a/src/modules/network_element/repository/perf_kpi.go b/src/modules/network_element/repository/perf_kpi.go new file mode 100644 index 0000000..3035dca --- /dev/null +++ b/src/modules/network_element/repository/perf_kpi.go @@ -0,0 +1,12 @@ +package repository + +import "ems.agt/src/modules/network_element/model" + +// 性能统计 数据层接口 +type IPerfKPI interface { + // SelectGoldKPI 通过ne_type和ne_id查询网元信息 + SelectGoldKPI(rmUID, neType string, startTime, endTime string, kpiIds []string, interval int64) []map[string]any + + // SelectGoldKPITitle + SelectGoldKPITitle(neType string) []model.GoldKPITitle +} diff --git a/src/modules/network_element/repository/perf_kpi.impl.go b/src/modules/network_element/repository/perf_kpi.impl.go new file mode 100644 index 0000000..7a45f48 --- /dev/null +++ b/src/modules/network_element/repository/perf_kpi.impl.go @@ -0,0 +1,77 @@ +package repository + +import ( + "fmt" + "strings" + + "ems.agt/src/framework/datasource" + "ems.agt/src/framework/logger" + "ems.agt/src/modules/network_element/model" +) + +// 实例化数据层 PerfKPIImpl 结构体 +var NewPerfKPIImpl = &PerfKPIImpl{} + +// PerfKPIImpl 性能统计 数据层处理 +type PerfKPIImpl struct{} + +// SelectGoldKPI 通过网元指标数据信息 +func (r *PerfKPIImpl) SelectGoldKPI(rmUID, neType string, startTime, endTime string, kpiIds []string, interval int64) []map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if rmUID != "" { + conditions = append(conditions, "gk.rm_uid = ?") + params = append(params, rmUID) + } + if neType != "" { + conditions = append(conditions, "gk.ne_type = ?") + params = append(params, neType) + } + if startTime != "" { + conditions = append(conditions, "gk.start_time >= ?") + params = append(params, startTime) + } + if endTime != "" { + conditions = append(conditions, "gk.start_time <= ?") + params = append(params, endTime) + } + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询字段列 + timeFormat := "DATE_FORMAT(gk.start_time, '%Y-%m-%d %H:')" + minuteGroup := fmt.Sprintf("LPAD(FLOOR(MINUTE(gk.start_time) / %d) * %d, 2, '0')", interval, interval) + groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, minuteGroup) + var fields = []string{ + groupByField, + "min(CASE WHEN gk.index != '' THEN gk.index ELSE 0 END) AS startIndex", + "min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName", + } + for _, kid := range kpiIds { + str := fmt.Sprintf("sum(CASE WHEN gk.kpi_id = '%s' THEN gk.value ELSE 0 END) AS '%s'", kid, kid) + fields = append(fields, str) + } + fieldsSql := strings.Join(fields, ",") + + // 查询数据 + querySql := fmt.Sprintf("SELECT %s FROM gold_kpi gk %s GROUP BY timeGroup", fieldsSql, whereSql) + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + return results +} + +// SelectGoldKPITitle 通过网元指标数据信息 +func (r *PerfKPIImpl) SelectGoldKPITitle(neType string) []model.GoldKPITitle { + result := []model.GoldKPITitle{} + tx := datasource.DefaultDB().Table("kpi_title").Where("ne_type = ?", neType).Find(&result) + if err := tx.Error; err != nil { + logger.Errorf("Delete err => %v", err) + } + return result +} diff --git a/src/modules/network_element/repository/udm_auth.impl.go b/src/modules/network_element/repository/udm_auth.impl.go index 5971773..bd45095 100644 --- a/src/modules/network_element/repository/udm_auth.impl.go +++ b/src/modules/network_element/repository/udm_auth.impl.go @@ -67,7 +67,7 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { var params []any if v, ok := query["imsi"]; ok && v != "" { conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") - params = append(params, v) + params = append(params, strings.Trim(v.(string), " ")) } if v, ok := query["neId"]; ok && v != "" { conditions = append(conditions, "ne_id = ?") diff --git a/src/modules/network_element/repository/udm_sub.impl.go b/src/modules/network_element/repository/udm_sub.impl.go index 22f6011..db0c993 100644 --- a/src/modules/network_element/repository/udm_sub.impl.go +++ b/src/modules/network_element/repository/udm_sub.impl.go @@ -83,11 +83,11 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { var params []any if v, ok := query["msisdn"]; ok && v != "" { conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')") - params = append(params, v) + params = append(params, strings.Trim(v.(string), " ")) } if v, ok := query["imsi"]; ok && v != "" { conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") - params = append(params, v) + params = append(params, strings.Trim(v.(string), " ")) } if v, ok := query["neId"]; ok && v != "" { conditions = append(conditions, "ne_id = ?") diff --git a/src/modules/network_element/service/perf_kpi.go b/src/modules/network_element/service/perf_kpi.go new file mode 100644 index 0000000..201d2f8 --- /dev/null +++ b/src/modules/network_element/service/perf_kpi.go @@ -0,0 +1,12 @@ +package service + +import "ems.agt/src/modules/network_element/model" + +// 性能统计 数据层接口 +type IPerfKPI interface { + // SelectGoldKPI 通过ne_type和ne_id查询网元信息 + SelectGoldKPI(rmUID, neType string, startTime, endTime string, kpiIds []string, interval int64) []map[string]any + + // SelectGoldKPITitle + SelectGoldKPITitle(neType string) []model.GoldKPITitle +} diff --git a/src/modules/network_element/service/perf_kpi.impl.go b/src/modules/network_element/service/perf_kpi.impl.go new file mode 100644 index 0000000..4003239 --- /dev/null +++ b/src/modules/network_element/service/perf_kpi.impl.go @@ -0,0 +1,31 @@ +package service + +import ( + "ems.agt/src/modules/network_element/model" + "ems.agt/src/modules/network_element/repository" +) + +// 实例化数据层 PerfKPIImpl 结构体 +var NewPerfKPIImpl = &PerfKPIImpl{ + perfKPIRepository: repository.NewPerfKPIImpl, +} + +// PerfKPIImpl 性能统计 数据层处理 +type PerfKPIImpl struct { + // 性能统计数据信息 + perfKPIRepository repository.IPerfKPI +} + +// SelectGoldKPI 通过网元指标数据信息 +func (r *PerfKPIImpl) SelectGoldKPI(rmUID, neType string, startTime, endTime string, kpiIds []string, interval int64) []map[string]any { + data := r.perfKPIRepository.SelectGoldKPI(rmUID, neType, startTime, endTime, kpiIds, interval) + if data == nil { + return []map[string]any{} + } + return data +} + +// SelectGoldKPITitle 通过网元指标数据信息 +func (r *PerfKPIImpl) SelectGoldKPITitle(neType string) []model.GoldKPITitle { + return r.perfKPIRepository.SelectGoldKPITitle(neType) +}