diff --git a/src/modules/network_data/controller/all_kpi.go b/src/modules/network_data/controller/all_kpi.go index 32ec48b..0dfc34a 100644 --- a/src/modules/network_data/controller/all_kpi.go +++ b/src/modules/network_data/controller/all_kpi.go @@ -3,7 +3,6 @@ package controller import ( "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/vo/result" "nms_cxy/src/modules/network_data/model" neDataService "nms_cxy/src/modules/network_data/service" @@ -38,18 +37,6 @@ func (s *PerfKPIController) GoldKPI(c *gin.Context) { 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"))) - return - } - endTime := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS) - if endTime.IsZero() { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } if querys.Interval < 5 || querys.Interval > 3600 { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 7e0a96e..4f6833c 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -50,13 +50,13 @@ func (s *IMSController) CDRList(c *gin.Context) { return } - // 查询网元获取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 - // } - // querys.RmUID = neInfo.RmUID + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -104,6 +104,13 @@ func (s *IMSController) CDRExport(c *gin.Context) { if querys.PageSize > 10000 { querys.PageSize = 10000 } + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID data := s.cdrEventService.SelectPage(querys) if parse.Number(data["total"]) == 0 { // 导出数据记录为空 @@ -119,8 +126,8 @@ func (s *IMSController) CDRExport(c *gin.Context) { "A1": "ID", "B1": "Record Behavior", "C1": "Type", - "D1": "Called", - "E1": "Caller", + "D1": "Caller", + "E1": "Called", "F1": "Duration", "G1": "Result", "H1": "Time", @@ -194,8 +201,8 @@ func (s *IMSController) CDRExport(c *gin.Context) { "A" + idx: row.ID, "B" + idx: recordType, "C" + idx: callTypeLable, - "D" + idx: called, - "E" + idx: caller, + "D" + idx: caller, + "E" + idx: called, "F" + idx: duration, "G" + idx: callResult, "H" + idx: timeStr, diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index 04d9156..a318433 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -48,13 +48,13 @@ func (s *SMFController) CDRList(c *gin.Context) { return } - // 查询网元获取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 - // } - // querys.RmUID = neInfo.RmUID + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -102,6 +102,13 @@ func (s *SMFController) CDRExport(c *gin.Context) { if querys.PageSize > 10000 { querys.PageSize = 10000 } + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID data := s.cdrEventService.SelectPage(querys) if parse.Number(data["total"]) == 0 { // 导出数据记录为空 diff --git a/src/modules/network_data/controller/smsc.go b/src/modules/network_data/controller/smsc.go new file mode 100644 index 0000000..4dbb507 --- /dev/null +++ b/src/modules/network_data/controller/smsc.go @@ -0,0 +1,198 @@ +package controller + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" + "nms_cxy/src/framework/utils/file" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/vo/result" + "nms_cxy/src/modules/network_data/model" + neDataService "nms_cxy/src/modules/network_data/service" + neService "nms_cxy/src/modules/network_element/service" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 SMSCController 结构体 +var NewSMSCController = &SMSCController{ + neInfoService: neService.NewNeInfoImpl, + cdrEventService: neDataService.NewCDREventSMSCImpl, +} + +// 网元SMSC +// +// PATH /smsc +type SMSCController struct { + // 网元信息服务 + neInfoService neService.INeInfo + // CDR会话事件服务 + cdrEventService neDataService.ICDREventSMSC +} + +// CDR会话列表 +// +// GET /cdr/list +func (s *SMSCController) CDRList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys model.CDREventSMSCQuery + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID + + // 查询数据 + data := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(data)) +} + +// CDR会话删除 +// +// DELETE /cdr/:cdrIds +func (s *SMSCController) CDRRemove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + cdrIds := c.Param("cdrIds") + if cdrIds == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 处理字符转id数组后去重 + ids := strings.Split(cdrIds, ",") + uniqueIDs := parse.RemoveDuplicates(ids) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + rows, err := s.cdrEventService.DeleteByIds(uniqueIDs) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, result.OkMsg(msg)) +} + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *SMSCController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventSMSCQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + // 查询网元信息 rmUID + 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 + } + querys.RmUID = neInfo.RmUID + data := s.cdrEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventSMSC) + + // 导出文件名称 + fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Record Behavior", + "C1": "Service Type", + "D1": "Caller", + "E1": "Called", + "F1": "Result", + "G1": "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.CDRJSONStr), &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" + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["updateTime"]; ok && v != nil { + releaseTime := parse.Number(v) + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: recordType, + "C" + idx: serviceType, + "D" + idx: caller, + "E" + idx: called, + "F" + idx: callResult, + "G" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/udm_auth.go b/src/modules/network_data/controller/udm_auth.go index 099ba5f..36de76f 100644 --- a/src/modules/network_data/controller/udm_auth.go +++ b/src/modules/network_data/controller/udm_auth.go @@ -15,6 +15,7 @@ import ( "nms_cxy/src/framework/vo/result" "nms_cxy/src/modules/network_data/model" neDataService "nms_cxy/src/modules/network_data/service" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" neService "nms_cxy/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -81,7 +82,7 @@ func (s *UDMAuthController) Info(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -150,7 +151,7 @@ func (s *UDMAuthController) Add(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -199,7 +200,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -247,7 +248,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -310,7 +311,7 @@ func (s *UDMAuthController) Remove(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -357,7 +358,7 @@ func (s *UDMAuthController) Removes(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -412,7 +413,11 @@ func (s *UDMAuthController) Export(c *gin.Context) { data := [][]string{} data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) for _, v := range list { - data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + opc := v.Opc + if opc == "-" { + opc = "" + } + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc}) } // 输出到文件 err := file.WriterFileCSV(data, filePath) @@ -426,7 +431,11 @@ func (s *UDMAuthController) Export(c *gin.Context) { // 转换数据 data := [][]string{} for _, v := range list { - data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + opc := v.Opc + if opc == "-" { + opc = "" + } + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc}) } // 输出到文件 err = file.WriterFileTXT(data, ",", filePath) @@ -447,6 +456,8 @@ func (s *UDMAuthController) Import(c *gin.Context) { var body struct { NeId string `json:"neId" binding:"required"` UploadPath string `json:"uploadPath" binding:"required"` + TypeVal string `json:"typeVal" binding:"required,oneof=default k4"` + TypeData any `json:"typeData"` } if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) @@ -498,16 +509,30 @@ func (s *UDMAuthController) Import(c *gin.Context) { } defer telnetClient.Close() - // 发送MML - cmd := fmt.Sprintf("import authdat:path=%s", neFilePath) - data, err := telnet.ConvertToStr(telnetClient, cmd) - if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) + // 结果信息 + var resultMsg string + var resultErr error + + // 默认的情况 发送MML + if body.TypeVal == "default" { + cmd := fmt.Sprintf("import authdat:path=%s", neFilePath) + resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd) + } + + // K4类型发特定请求 + if body.TypeVal == "k4" { + resultMsg, resultErr = neFetchlink.UDMImportAuth(neInfo.IP, map[string]any{ + "path": neFilePath, "k4": body.TypeData, + }) + } + + if resultErr != nil { + c.JSON(200, result.ErrMsg(resultErr.Error())) return } // 命令ok时 - if strings.Contains(data, "ok") { + if strings.Contains(resultMsg, "ok") { if strings.HasSuffix(body.UploadPath, ".csv") { data := file.ReadFileCSV(localFilePath) neId := "" @@ -519,5 +544,5 @@ func (s *UDMAuthController) Import(c *gin.Context) { go s.udmAuthService.InsertData(neId, "txt", data) } } - c.JSON(200, result.OkMsg(data)) + c.JSON(200, result.OkMsg(resultMsg)) } diff --git a/src/modules/network_data/controller/udm_sub.go b/src/modules/network_data/controller/udm_sub.go index 8c955d3..2b7a82e 100644 --- a/src/modules/network_data/controller/udm_sub.go +++ b/src/modules/network_data/controller/udm_sub.go @@ -82,7 +82,7 @@ func (s *UDMSubController) Info(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -177,7 +177,7 @@ func (s *UDMSubController) Add(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -231,7 +231,7 @@ func (s *UDMSubController) Adds(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -284,7 +284,7 @@ func (s *UDMSubController) Edit(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -389,7 +389,7 @@ func (s *UDMSubController) Remove(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) @@ -436,7 +436,7 @@ func (s *UDMSubController) Removes(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - + // 网元主机的Telnet客户端 telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go index 259c102..c076da1 100644 --- a/src/modules/network_data/model/cdr_event_smf.go +++ b/src/modules/network_data/model/cdr_event_smf.go @@ -13,15 +13,6 @@ type CDREventSMF struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` // ====== 非数据库字段属性 ====== - - // RecordType string `json:"recordType" gorm:"column:record_type"` - // ChargingID string `json:"chargingID" gorm:"column:charging_id"` - // SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"` - // Duration string `json:"duration" gorm:"column:duration"` - // DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"` - // DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"` - // DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"` - // PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"` } // CDREventSMFQuery CDR会话对象SMF查询参数结构体 diff --git a/src/modules/network_data/model/cdr_event_smsc.go b/src/modules/network_data/model/cdr_event_smsc.go new file mode 100644 index 0000000..6a50e59 --- /dev/null +++ b/src/modules/network_data/model/cdr_event_smsc.go @@ -0,0 +1,30 @@ +package model + +import "time" + +// CDREventSMSC CDR会话对象SMSC cdr_event_smsc +type CDREventSMSC struct { + ID string `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"` + CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` +} + +// CDREventSMSCQuery CDR会话对象SMSC查询参数结构体 +type CDREventSMSCQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型SMSC + NeID string `json:"neId" form:"neId" binding:"required"` + RmUID string `json:"rmUID" form:"rmUID"` + RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOSM MTSM + CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 + CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 + StartTime string `json:"startTime" form:"startTime"` + EndTime string `json:"endTime" form:"endTime"` + SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 + 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"` +} diff --git a/src/modules/network_data/model/perf_kpi.go b/src/modules/network_data/model/perf_kpi.go index 108d81f..be88a06 100644 --- a/src/modules/network_data/model/perf_kpi.go +++ b/src/modules/network_data/model/perf_kpi.go @@ -16,7 +16,7 @@ type GoldKPIQuery struct { NeID string `form:"neId" binding:"required"` StartTime string `form:"startTime" binding:"required"` EndTime string `form:"endTime" binding:"required"` - Interval int64 `form:"interval" binding:"required"` + Interval int64 `form:"interval" binding:"required,oneof=5 60 300 900 1800 3600"` RmUID string `form:"rmUID"` SortField string `form:"sortField" binding:"omitempty,oneof=timeGroup"` SortOrder string `form:"sortOrder" binding:"omitempty,oneof=asc desc"` diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 69a75a2..eecf700 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -61,6 +61,25 @@ func Setup(router *gin.Engine) { ) } + // 网元SMSC + smscGroup := neDataGroup.Group("/smsc") + { + smscGroup.GET("/cdr/list", + middleware.PreAuthorize(nil), + controller.NewSMSCController.CDRList, + ) + smscGroup.DELETE("/cdr/:cdrIds", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewSMSCController.CDRRemove, + ) + smscGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewSMSCController.CDRExport, + ) + } + // 网元SMF smfGroup := neDataGroup.Group("/smf") { diff --git a/src/modules/network_data/repository/cdr_event_ims.impl.go b/src/modules/network_data/repository/cdr_event_ims.impl.go index 08fe879..cc6813a 100644 --- a/src/modules/network_data/repository/cdr_event_ims.impl.go +++ b/src/modules/network_data/repository/cdr_event_ims.impl.go @@ -84,13 +84,24 @@ func (r *CDREventIMSImpl) SelectPage(querys model.CDREventIMSQuery) map[string]a conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?") params = append(params, querys.CalledParty) } + // MySQL8支持的 + // if querys.RecordType != "" { + // recordTypes := strings.Split(querys.RecordType, ",") + // placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) + // conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) + // for _, recordType := range recordTypes { + // params = append(params, recordType) + // } + // } + // Mariadb不支持json in查询改or if querys.RecordType != "" { recordTypes := strings.Split(querys.RecordType, ",") - placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) - conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) + var queryStrArr []string for _, recordType := range recordTypes { + queryStrArr = append(queryStrArr, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") params = append(params, recordType) } + conditions = append(conditions, fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) } // 构建查询条件语句 diff --git a/src/modules/network_data/repository/cdr_event_smf.impl.go b/src/modules/network_data/repository/cdr_event_smf.impl.go index 9b40825..abc71ac 100644 --- a/src/modules/network_data/repository/cdr_event_smf.impl.go +++ b/src/modules/network_data/repository/cdr_event_smf.impl.go @@ -14,7 +14,6 @@ import ( // 实例化数据层 CDREventSMFImpl 结构体 var NewCDREventSMFImpl = &CDREventSMFImpl{ selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smf`, - // selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`, resultMap: map[string]string{ "id": "ID", @@ -24,20 +23,6 @@ var NewCDREventSMFImpl = &CDREventSMFImpl{ "timestamp": "Timestamp", "cdr_json": "CDRJSONStr", "created_at": "CreatedAt", - // "id": "ID", - // "ne_type": "NeType", - // "ne_name": "NeName", - // "rm_uid": "RmUID", - // "timestamp": "Timestamp", - // "record_type": "RecordType", - // "charging_id": "ChargingID", - // "subscriber_id": "SubscriberID", - // "duration": "Duration", - // "data_volume_uplink": "DataVolumeUplink", - // "data_volume_downlink": "DataVolumeDownlink", - // "data_total_volume": "DataTotalVolume", - // "pdu_address": "PDUAddress", - // "created_at": "CreatedAt", }, } diff --git a/src/modules/network_data/repository/cdr_event_smsc.go b/src/modules/network_data/repository/cdr_event_smsc.go new file mode 100644 index 0000000..6950a00 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smsc.go @@ -0,0 +1,15 @@ +package repository + +import "nms_cxy/src/modules/network_data/model" + +// CDR会话事件SMSC 数据层接口 +type ICDREventSMSC interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMSCQuery) map[string]any + + // SelectByIds 通过ID查询 + SelectByIds(cdrIds []string) []model.CDREventSMSC + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) int64 +} diff --git a/src/modules/network_data/repository/cdr_event_smsc.impl.go b/src/modules/network_data/repository/cdr_event_smsc.impl.go new file mode 100644 index 0000000..9f955d5 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smsc.impl.go @@ -0,0 +1,181 @@ +package repository + +import ( + "fmt" + "strings" + + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/repo" + "nms_cxy/src/modules/network_data/model" +) + +// 实例化数据层 CDREventSMSCImpl 结构体 +var NewCDREventSMSCImpl = &CDREventSMSCImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smsc`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_name": "NeName", + "rm_uid": "RmUID", + "timestamp": "Timestamp", + "cdr_json": "CDRJSONStr", + "created_at": "CreatedAt", + }, +} + +// CDREventSMSCImpl CDR会话事件 数据层处理 +type CDREventSMSCImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *CDREventSMSCImpl) convertResultRows(rows []map[string]any) []model.CDREventSMSC { + arr := make([]model.CDREventSMSC, 0) + for _, row := range rows { + item := model.CDREventSMSC{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询 +func (r *CDREventSMSCImpl) SelectPage(querys model.CDREventSMSCQuery) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if querys.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, querys.NeType) + } + if querys.RmUID != "" { + conditions = append(conditions, "rm_uid = ?") + params = append(params, querys.RmUID) + } + if querys.StartTime != "" { + conditions = append(conditions, "timestamp >= ?") + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) + } + if querys.EndTime != "" { + conditions = append(conditions, "timestamp <= ?") + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) + } + // MySQL8支持的 + // if querys.RecordType != "" { + // recordTypes := strings.Split(querys.RecordType, ",") + // placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) + // conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) + // for _, recordType := range recordTypes { + // params = append(params, recordType) + // } + // } + // Mariadb不支持json in查询改or + if querys.RecordType != "" { + recordTypes := strings.Split(querys.RecordType, ",") + var queryStrArr []string + for _, recordType := range recordTypes { + queryStrArr = append(queryStrArr, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") + params = append(params, recordType) + } + conditions = append(conditions, fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.CDREventSMSC{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from cdr_event_smsc" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + orderSql := "" + if querys.SortField != "" { + sortSql := querys.SortField + if querys.SortOrder != "" { + if querys.SortOrder == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectByIds 通过ID查询 +func (r *CDREventSMSCImpl) SelectByIds(cdrIds []string) []model.CDREventSMSC { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.CDREventSMSC{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSMSCImpl) DeleteByIds(cdrIds []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + sql := "delete from cdr_event_smsc where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_data/repository/perf_kpi.go b/src/modules/network_data/repository/perf_kpi.go index 478a70f..ec2e302 100644 --- a/src/modules/network_data/repository/perf_kpi.go +++ b/src/modules/network_data/repository/perf_kpi.go @@ -7,15 +7,9 @@ type IPerfKPI interface { // SelectGoldKPI 通过网元指标数据信息 SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map[string]any - // select from new kpi report table, exp. kpi_report_upf - SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any - // SelectGoldKPITitle 网元对应的指标名称 SelectGoldKPITitle(neType string) []model.GoldKPITitle // SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行 SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) map[string]any - - // select upf throughput from new kpi_report - SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any } diff --git a/src/modules/network_data/repository/perf_kpi.impl.go b/src/modules/network_data/repository/perf_kpi.impl.go index bb78942..6f4423b 100644 --- a/src/modules/network_data/repository/perf_kpi.impl.go +++ b/src/modules/network_data/repository/perf_kpi.impl.go @@ -17,76 +17,6 @@ type PerfKPIImpl struct{} // SelectGoldKPI 通过网元指标数据信息 func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if query.RmUID != "" { - conditions = append(conditions, "gk.rm_uid = ?") - params = append(params, query.RmUID) - } - if query.NeType != "" { - conditions = append(conditions, "gk.ne_type = ?") - params = append(params, query.NeType) - } - if query.StartTime != "" { - conditions = append(conditions, "gk.start_time >= ?") - params = append(params, query.StartTime) - } - if query.EndTime != "" { - conditions = append(conditions, "gk.start_time <= ?") - params = append(params, query.EndTime) - } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询字段列 - timeFormat := "DATE_FORMAT(gk.start_time, '%Y-%m-%d %H:%i:')" - secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval) - groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup) - if query.Interval > 60 { - minute := query.Interval / 60 - timeFormat = "DATE_FORMAT(gk.start_time, '%Y-%m-%d %H:')" - minuteGroup := fmt.Sprintf("LPAD(FLOOR(MINUTE(gk.start_time) / %d) * %d, 2, '0')", minute, minute) - 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_type != '' THEN gk.ne_type ELSE 0 END) AS neType", - "min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName", - } - for _, kid := range kpiIds { - // 特殊字段,只取最后一次收到的非0值 - if kid == "AMF.01" || kid == "UDM.01" || kid == "UDM.02" || kid == "UDM.03" || kid == "SMF.01" { - str := fmt.Sprintf("IFNULL(SUBSTRING_INDEX(GROUP_CONCAT( CASE WHEN gk.kpi_id = '%s' and gk.VALUE != 0 THEN gk.VALUE END ), ',', 1), 0) AS '%s'", kid, kid) - fields = append(fields, str) - } else { - str := fmt.Sprintf("sum(CASE WHEN gk.kpi_id = '%s' THEN gk.value ELSE 0 END) AS '%s'", kid, kid) - fields = append(fields, str) - } - } - fieldsSql := strings.Join(fields, ",") - - // 查询数据 - if query.SortField == "" { - query.SortField = "timeGroup" - } - if query.SortOrder == "" { - query.SortOrder = "desc" - } - orderSql := fmt.Sprintf(" order by %s %s", query.SortField, query.SortOrder) - querySql := fmt.Sprintf("SELECT %s FROM gold_kpi gk %s GROUP BY timeGroup %s", fieldsSql, whereSql, orderSql) - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err => %v", err) - } - return results -} - -func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -100,43 +30,15 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) // params = append(params, query.NeType) tableName += strings.ToLower(query.NeType) } - - var dateStr1, dateStr2, timeStr1, timeStr2 string if query.StartTime != "" { - dateStr1 = query.StartTime[:10] - timeStr1 = query.StartTime[11:] + conditions = append(conditions, "gk.created_at >= ?") + params = append(params, query.StartTime) } if query.EndTime != "" { - dateStr2 = query.EndTime[:10] - timeStr2 = query.EndTime[11:] - } - if dateStr1 == dateStr2 && dateStr1 != "" { - conditions = append(conditions, "gk.`date` = ?") - params = append(params, dateStr1) - conditions = append(conditions, "gk.`start_time` >= ?") - params = append(params, timeStr1) - conditions = append(conditions, "gk.`start_time` <= ?") - params = append(params, timeStr2) - } else { - if dateStr1 != "" { - conditions = append(conditions, "(gk.`date` > ? OR (gk.`date` = ? AND gk.`start_time` >= ?))") - params = append(params, dateStr1, dateStr1, timeStr1) - } - if dateStr2 != "" { - conditions = append(conditions, "(gk.`date` < ? OR (gk.`date` = ? AND gk.`start_time` <= ?))") - params = append(params, dateStr2, dateStr2, timeStr2) - } + conditions = append(conditions, "gk.created_at <= ?") + params = append(params, query.EndTime) } - // var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" - // if query.StartTime != "" { - // conditions = append(conditions, dateTimeStr+" >= ?") - // params = append(params, query.StartTime) - // } - // if query.EndTime != "" { - // conditions = append(conditions, dateTimeStr+" <= ?") - // params = append(params, query.EndTime) - // } // 构建查询条件语句 whereSql := "" if len(conditions) > 0 { @@ -144,18 +46,9 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) } // 查询字段列 - var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" - timeFormat := "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:%i:')" - secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval) - groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup) - if query.Interval > 60 { - minute := query.Interval / 60 - timeFormat = "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:')" - minuteGroup := fmt.Sprintf("LPAD(FLOOR(MINUTE(gk.start_time) / %d) * %d, 2, '0')", minute, minute) - groupByField = fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, minuteGroup) - } var fields = []string{ - groupByField, + // fmt.Sprintf("FROM_UNIXTIME(FLOOR(gk.created_at / (%d * 1000)) * %d) AS timeGroup", query.Interval, query.Interval), + fmt.Sprintf("CONCAT(FLOOR(gk.created_at / (%d * 1000)) * (%d * 1000)) AS timeGroup", query.Interval, query.Interval), // 时间戳毫秒 "min(CASE WHEN gk.index != '' THEN gk.index ELSE 0 END) AS startIndex", "min(CASE WHEN gk.ne_type != '' THEN gk.ne_type ELSE 0 END) AS neType", "min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName", @@ -204,19 +97,19 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID, startDate, endDate strin var conditions []string var params []any if neType != "" { - conditions = append(conditions, "gk.ne_type = ?") + conditions = append(conditions, "kupf.ne_type = ?") params = append(params, neType) } if rmUID != "" { - conditions = append(conditions, "gk.rm_uid = ?") + conditions = append(conditions, "kupf.rm_uid = ?") params = append(params, rmUID) } if startDate != "" { - conditions = append(conditions, "gk.date >= ?") + conditions = append(conditions, "kupf.created_at >= ?") params = append(params, startDate) } if endDate != "" { - conditions = append(conditions, "gk.date <= ?") + conditions = append(conditions, "kupf.created_at <= ?") params = append(params, endDate) } // 构建查询条件语句 @@ -226,44 +119,11 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID, startDate, endDate strin } // 查询数据 - querySql := fmt.Sprintf("SELECT sum( CASE WHEN gk.kpi_id = 'UPF.03' THEN gk.VALUE ELSE 0 END ) AS 'up', sum( CASE WHEN gk.kpi_id = 'UPF.06' THEN gk.VALUE ELSE 0 END ) AS 'down' FROM gold_kpi gk %s", whereSql) - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err => %v", err) - } - return results[0] -} - -// SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行 -func (r *PerfKPIImpl) SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if neType != "" { - conditions = append(conditions, "gk.ne_type = ?") - params = append(params, neType) - } - if rmUID != "" { - conditions = append(conditions, "gk.rm_uid = ?") - params = append(params, rmUID) - } - if startDate != "" { - conditions = append(conditions, "gk.date >= ?") - params = append(params, startDate) - } - if endDate != "" { - conditions = append(conditions, "gk.date <= ?") - params = append(params, endDate) - } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := fmt.Sprintf("SELECT sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[2].kpi_id') = 'UPF.03' THEN JSON_EXTRACT(gk.kpi_values, '$[2].value') ELSE 0 END ) AS 'up', sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[5].kpi_id') = 'UPF.06' THEN JSON_EXTRACT(gk.kpi_values, '$[5].value') ELSE 0 END ) AS 'down' FROM kpi_report_upf gk %s", whereSql) - results, err := datasource.RawDB("", querySql, params) + querySql := `SELECT + sum( CASE WHEN JSON_EXTRACT(kupf.kpi_values, '$[2].kpi_id') = 'UPF.03' THEN JSON_EXTRACT(kupf.kpi_values, '$[2].value') ELSE 0 END ) AS 'up', + sum( CASE WHEN JSON_EXTRACT(kupf.kpi_values, '$[5].kpi_id') = 'UPF.06' THEN JSON_EXTRACT(kupf.kpi_values, '$[5].value') ELSE 0 END ) AS 'down' + FROM kpi_report_upf kupf` + results, err := datasource.RawDB("", querySql+whereSql, params) if err != nil { logger.Errorf("query err => %v", err) } diff --git a/src/modules/network_data/service/cdr_event_smsc.go b/src/modules/network_data/service/cdr_event_smsc.go new file mode 100644 index 0000000..ab43f21 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smsc.go @@ -0,0 +1,12 @@ +package service + +import "nms_cxy/src/modules/network_data/model" + +// CDR会话事件SMSC 服务层接口 +type ICDREventSMSC interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMSCQuery) map[string]any + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) (int64, error) +} diff --git a/src/modules/network_data/service/cdr_event_smsc.impl.go b/src/modules/network_data/service/cdr_event_smsc.impl.go new file mode 100644 index 0000000..582f7f2 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smsc.impl.go @@ -0,0 +1,37 @@ +package service + +import ( + "fmt" + + "nms_cxy/src/modules/network_data/model" + "nms_cxy/src/modules/network_data/repository" +) + +var NewCDREventSMSCImpl = &CDREventSMSCImpl{ + cdrEventRepository: repository.NewCDREventSMSCImpl, +} + +type CDREventSMSCImpl struct { + // CDR会话事件数据信息 + cdrEventRepository repository.ICDREventSMSC +} + +func (r *CDREventSMSCImpl) SelectPage(querys model.CDREventSMSCQuery) map[string]any { + return r.cdrEventRepository.SelectPage(querys) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSMSCImpl) DeleteByIds(cdrIds []string) (int64, error) { + // 检查是否存在 + ids := r.cdrEventRepository.SelectByIds(cdrIds) + if len(ids) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(ids) == len(cdrIds) { + rows := r.cdrEventRepository.DeleteByIds(cdrIds) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} diff --git a/src/modules/network_data/service/perf_kpi.impl.go b/src/modules/network_data/service/perf_kpi.impl.go index c46fd2c..d06a32c 100644 --- a/src/modules/network_data/service/perf_kpi.impl.go +++ b/src/modules/network_data/service/perf_kpi.impl.go @@ -31,8 +31,7 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery) []map[string]any { kpiIds = append(kpiIds, kpiId.KPIID) } - //data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds) - data := r.perfKPIRepository.SelectKpiReport(query, kpiIds) + data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds) if data == nil { return []map[string]any{} } @@ -46,12 +45,11 @@ func (r *PerfKPIImpl) SelectGoldKPITitle(neType string) []model.GoldKPITitle { // SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行 func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID string, day int) map[string]any { - // 获取当前日期 now := time.Now() - endDate := now.Format("2006-01-02") + // 获取当前日期 + endDate := fmt.Sprint(now.UnixMilli()) // 将当前日期前几天数 - afterDays := now.AddDate(0, 0, -day) - startDate := afterDays.Format("2006-01-02") + startDate := fmt.Sprint(now.AddDate(0, 0, -day).Truncate(24 * time.Hour).UnixMilli()) var info map[string]any @@ -61,14 +59,18 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID string, day int) map[stri if infoStr != "" { json.Unmarshal([]byte(infoStr), &info) expireSecond, _ := redis.GetExpire("", key) - expireMinute := (time.Duration(int64(expireSecond)) * time.Second) - if expireMinute > 2*time.Minute { + if expireSecond > 120 { return info } } - //info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate) - info = r.perfKPIRepository.SelectUPFThroughput(neType, rmUID, startDate, endDate) + info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate) + if v, ok := info["up"]; ok && v == nil { + info["up"] = 0 + } + if v, ok := info["down"]; ok && v == nil { + info["down"] = 0 + } // 保存到缓存 infoJSON, _ := json.Marshal(info) diff --git a/src/modules/network_data/udm_auth_k4_test.go b/src/modules/network_data/udm_auth_k4_test.go new file mode 100644 index 0000000..434cd2c --- /dev/null +++ b/src/modules/network_data/udm_auth_k4_test.go @@ -0,0 +1,54 @@ +package networkdata + +import ( + "crypto/des" + "errors" + "testing" +) + +// UDM K4加密 +func encrypt(origData, key []byte) ([]byte, error) { + if len(origData) < 1 || len(key) < 1 { + return nil, errors.New("wrong data or key") + } + block, err := des.NewCipher(key) + if err != nil { + return nil, err + } + bs := block.BlockSize() + if len(origData)%bs != 0 { + return nil, errors.New("wrong padding") + } + out := make([]byte, len(origData)) + dst := out + for len(origData) > 0 { + block.Encrypt(dst, origData[:bs]) + origData = origData[bs:] + dst = dst[bs:] + } + return out, nil +} + +func TestEncrypt(t *testing.T) { + // key := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef} + // 0123456789abcdef + + // ki := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef} + // 0123456789abcdef0123456789abcdef + + // k4 password + key := []byte{0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34} + // 1234123412341234 + + // k4 crypt ki + ki := []byte{0x80, 0x5D, 0xAD, 0xC6, 0xE8, 0xA5, 0x4A, 0x0D, 0x59, 0xD6, 0x22, 0xC7, 0xA0, 0x4D, 0x08, 0xE0} + // 805DADC6E8A54A0D59D622C7A04D08E0 + + kis, err := encrypt(ki, key) + + // 加密后的,放导入导入文件里ki + t.Errorf("kis: %x\n", kis) + // 3e479135bb16f45dc874a18831b54d71 + + t.Errorf("err: %v\n", err) +}