diff --git a/src/modules/network_data/controller/all_perf_kpi.go b/src/modules/network_data/controller/all_perf_kpi.go index 935c4568..bcb8590c 100644 --- a/src/modules/network_data/controller/all_perf_kpi.go +++ b/src/modules/network_data/controller/all_perf_kpi.go @@ -91,7 +91,7 @@ func (s *PerfKPIController) GoldKPI(c *gin.Context) { } // 查询数据 - kpiData := s.perfKPIService.SelectGoldKPI(querys) + kpiData := s.perfKPIService.FindData(querys) c.JSON(200, result.OkData(kpiData)) } diff --git a/src/modules/network_data/model/perf_kpi.go b/src/modules/network_data/model/perf_kpi.go index 87c73184..43014405 100644 --- a/src/modules/network_data/model/perf_kpi.go +++ b/src/modules/network_data/model/perf_kpi.go @@ -15,6 +15,26 @@ func (*GoldKPITitle) TableName() string { return "kpi_title" } +// KpiReport 指标报表信息对象 +type KpiReport 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"` + Date string `json:"date" gorm:"column:date"` // Date of the report yyyy-mm-dd hh:mi:ss + StartTime string `json:"startTime" gorm:"column:start_time"` // Start time of the report hh:mi:ss + EndTime string `json:"endTime" gorm:"column:end_time"` // End time of the report hh:mi:ss + Index int64 `json:"index" gorm:"column:index"` // Index of the report + Granularity int64 `json:"granularity" gorm:"column:granularity"` // Time granualarity: 5/10/.../60/300 (second) + KpiValues string `json:"kpiValues" gorm:"column:kpi_values"` // KPI values JSON String + CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // Creation time 接收到的timestamp秒级存储毫秒时间戳 +} + +// TableName 表名称 +func (*KpiReport) TableName() string { + return "kpi_report" +} + // GoldKPIQuery 黄金指标查询参数结构体 type GoldKPIQuery struct { NeType string `form:"neType" binding:"required"` diff --git a/src/modules/network_data/repository/all_perf_kpi.go b/src/modules/network_data/repository/all_perf_kpi.go index 57c17bf4..94c9d55c 100644 --- a/src/modules/network_data/repository/all_perf_kpi.go +++ b/src/modules/network_data/repository/all_perf_kpi.go @@ -91,6 +91,44 @@ func (r *PerfKPI) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map return results } +// SelectGoldKPI 通过网元指标数据信息 +func (r PerfKPI) SelectKPI(query model.GoldKPIQuery) []model.KpiReport { + rows := []model.KpiReport{} + if query.NeType == "" { + return rows + } + + tx := datasource.DB("").Model(&model.KpiReport{}) + // 表名 + tableName := fmt.Sprintf("kpi_report_%s", strings.ToLower(query.NeType)) + tx = tx.Table(tableName) + // 构建查询条件 + if query.RmUID != "" { + rmUIDs := strings.Split(query.RmUID, ",") + tx = tx.Where("rm_uid in ?", rmUIDs) + } + if query.StartTime != "" { + tx = tx.Where("created_at >= ?", query.StartTime) + } + if query.EndTime != "" { + tx = tx.Where("created_at <= ?", query.EndTime) + } + // 排序 + if query.SortField == "" || query.SortField == "timeGroup" { + query.SortField = "created_at" + } + if query.SortOrder == "" { + query.SortOrder = "desc" + } + tx = tx.Order(fmt.Sprintf("%s %s", query.SortField, query.SortOrder)) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + // SelectGoldKPITitle 网元对应的指标名称 func (r *PerfKPI) SelectGoldKPITitle(neType string) []model.GoldKPITitle { result := []model.GoldKPITitle{} diff --git a/src/modules/network_data/service/all_perf_kpi.go b/src/modules/network_data/service/all_perf_kpi.go index 36dc3d35..5d3a30d6 100644 --- a/src/modules/network_data/service/all_perf_kpi.go +++ b/src/modules/network_data/service/all_perf_kpi.go @@ -3,6 +3,7 @@ package service import ( "encoding/json" "fmt" + "sort" "time" "be.ems/src/framework/constants/cachekey" @@ -44,6 +45,113 @@ func (r *PerfKPI) SelectGoldKPITitle(neType string) []model.GoldKPITitle { return r.perfKPIRepository.SelectGoldKPITitle(neType) } +// FindData 通过网元指标数据信息 +func (s PerfKPI) FindData(query model.GoldKPIQuery) []map[string]any { + // 原始数据 + rows := s.perfKPIRepository.SelectKPI(query) + if len(rows) <= 0 { + return []map[string]any{} + } + + kpiIdsHas := false + kpiIds := []string{} + // 处理数据 + arr := []map[string]any{} + for _, row := range rows { + // 解析 JSON 字符串为 map + var kpiValues []map[string]any + err := json.Unmarshal([]byte(row.KpiValues), &kpiValues) + if err != nil { + continue + } + + item := map[string]any{ + "neType": row.NeType, + "neName": row.NeName, + "rmUID": row.RmUid, + "startIndex": row.Index, + "timeGroup": row.CreatedAt, + } + + // 遍历 kpiValues 数组 + for _, v := range kpiValues { + kpiId := "-" + if k, ok := v["kpi_id"]; ok { + kpiId = fmt.Sprint(k) + } + item[kpiId] = v["value"] + } + + arr = append(arr, item) + + // 添加指标ID + if !kpiIdsHas { + for _, v := range kpiValues { + kpiId := "-" + if k, ok := v["kpi_id"]; ok { + kpiId = fmt.Sprint(k) + } + kpiIds = append(kpiIds, kpiId) + } + kpiIdsHas = true + } + } + + // 时间密度分钟 数值单位秒 5分钟的传入300秒 + timeInterval := query.Interval + // 创建一个map来存储按时间段合并后的数据 + timeGroup := make(map[int64][]map[string]any) + // 遍历每个数据项 + for _, v := range arr { + itemTime := parse.Number(v["timeGroup"]) + // 计算时间戳的x分钟时间段(使用秒并除以x分钟) + timeMinute := itemTime / 1000 / timeInterval * timeInterval + // 合并到对应的时间段 + timeGroup[timeMinute] = append(timeGroup[timeMinute], v) + } + // 时间组合输出 + data := []map[string]any{} + for _, records := range timeGroup { + if len(records) <= 0 { + continue + } + // 转换为具体时间显示(根据需要可以格式化显示) + // timeStr := time.Unix(k, 0).Format("2006-01-02 15:04:05") + // fmt.Printf("Time Group: %s records: %d\n", timeStr, len(records)) + startItem := records[len(records)-1] // 取最后一条数据也是最开始startIndex + if len(records) >= 2 { // 最后一条数据不参与计算 + for _, record := range records[:len(records)-1] { + // fmt.Printf(" - startIndex: %v, Value: %v\n", record["startIndex"], record["timeGroup"]) + // 遍历kpiIds数组对lastRecord赋值 + for _, kpiId := range kpiIds { + if v, ok := record[kpiId]; ok { + // 特殊字段,只取一次收到的非0值 + if kpiId == "AMF.01" || kpiId == "UDM.01" || kpiId == "UDM.02" || kpiId == "UDM.03" || kpiId == "SMF.01" { + // startItem[kpiId] = parse.Number(v) + continue // startIndex的值不累加不取最后 + } else { + value := parse.Number(startItem[kpiId]) + startItem[kpiId] = value + parse.Number(v) + } + } + } + } + } + data = append(data, startItem) + } + + // 按时间排序 + sort.SliceStable(data, func(i, j int) bool { + vi := parse.Number(data[i]["timeGroup"]) + vj := parse.Number(data[j]["timeGroup"]) + if query.SortOrder == "asc" { + return vi < vj // asc + } + return vi > vj // desc + }) + return data +} + // UPFTodayFlowFind 查询UPF总流量 N3上行 N6下行 // day 统计天数 func (r PerfKPI) UPFTodayFlowFind(rmUID string, day int) (int64, int64) {