From 24fc8115d61775d47d37c9f68929cb82cca24626 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 8 Sep 2025 18:31:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BF=99=E6=97=B6=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E5=91=A8=E5=86=85=E8=AF=9D=E5=8A=A1=E9=87=8F?= =?UTF-8?q?=E6=9C=80=E9=AB=98=E7=9A=84=E5=9B=9B=E4=B8=AA=E5=B0=8F=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E5=B9=B3=E5=9D=87=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/ims.go | 57 ++++++++++ src/modules/network_data/network_data.go | 4 + .../network_data/repository/all_perf_kpi.go | 2 +- .../network_data/service/all_perf_kpi.go | 103 ++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index f5a2a8ae..48bddf15 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -419,3 +419,60 @@ func (s IMSController) KPIBusyHour(c *gin.Context) { data := s.kpiReportService.IMSBusyHour(neInfo.RmUID, query.Timestamp) c.JSON(200, resp.OkData(data)) } + +// KPI 忙时统计 周 +// +// GET /kpi/busy-week +// +// @Tags network_data/ims +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param timestamp query int64 false "timestamp" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Busy week statistics +// @Description Busy week statistics +// @Router /neData/ims/kpi/busy-week [get] +func (s IMSController) KPIBusyWeek(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeID string `form:"neId" binding:"required"` + WeekStart int64 `form:"weekStart" binding:"required"` // 时间戳毫秒 年月日 + WeekEnd int64 `form:"weekEnd" binding:"required"` // 时间戳毫秒 年月日 + } + if err := c.ShouldBindQuery(&query); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if query.WeekStart < 1e12 || query.WeekStart > 1e13 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "weekStart format is ms")) + return + } + if query.WeekEnd < 1e12 || query.WeekEnd > 1e13 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "weekEnd format is ms")) + return + } + if query.WeekEnd < query.WeekStart || query.WeekEnd == query.WeekStart { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "weekEnd must be greater than weekStart and not equal to weekStart")) + return + } + // 计算周差 + weekDiff := query.WeekEnd - query.WeekStart + // 周差是否7天 + if weekDiff-7*24*60*60*1000 != -1000 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "weekEnd must be 7 days after weekStart")) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.FindByNeTypeAndNeID("IMS", query.NeID) + if neInfo.NeId != query.NeID || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + data := s.kpiReportService.IMSBusyWeek(neInfo.RmUID, query.WeekStart, query.WeekEnd) + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 2bc328c8..d38329aa 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -109,6 +109,10 @@ func Setup(router *gin.Engine) { middleware.PreAuthorize(nil), controller.NewIMS.KPIBusyHour, ) + imsGroup.GET("/kpi/busy-week", + middleware.PreAuthorize(nil), + controller.NewIMS.KPIBusyWeek, + ) } // 网元SMSC diff --git a/src/modules/network_data/repository/all_perf_kpi.go b/src/modules/network_data/repository/all_perf_kpi.go index aacef538..dcfca454 100644 --- a/src/modules/network_data/repository/all_perf_kpi.go +++ b/src/modules/network_data/repository/all_perf_kpi.go @@ -329,7 +329,7 @@ func (r *PerfKPI) SelectIMSBusyHour(rmUID string, startDate, endDate int64) []ma querySql := `SELECT CONCAT(FLOOR(kims.created_at / (3600 * 1000)) * (3600 * 1000)) AS timeGroup, sum( CASE WHEN JSON_EXTRACT(kims.kpi_values, '$[5].kpi_id') = 'SCSCF.06' THEN JSON_EXTRACT(kims.kpi_values, '$[5].value') ELSE 0 END ) AS 'callAttempts', - sum( CASE WHEN JSON_EXTRACT(kims.kpi_values, '$[8].kpi_id') = ' ' THEN JSON_EXTRACT(kims.kpi_values, '$[8].value') ELSE 0 END ) AS 'callCompletions' + sum( CASE WHEN JSON_EXTRACT(kims.kpi_values, '$[8].kpi_id') = 'SCSCF.09' THEN JSON_EXTRACT(kims.kpi_values, '$[8].value') ELSE 0 END ) AS 'callCompletions' FROM kpi_report_ims kims` results, err := datasource.RawDB("", querySql+whereSql+" GROUP by timeGroup ", params) if err != nil { diff --git a/src/modules/network_data/service/all_perf_kpi.go b/src/modules/network_data/service/all_perf_kpi.go index d9a76a8d..fc093f02 100644 --- a/src/modules/network_data/service/all_perf_kpi.go +++ b/src/modules/network_data/service/all_perf_kpi.go @@ -286,3 +286,106 @@ func (r PerfKPI) IMSBusyHour(rmUID string, timestamp int64) []map[string]any { // 转换为毫秒级时间戳 return r.perfKPIRepository.SelectIMSBusyHour(rmUID, beginTime.UnixMilli(), endTime.UnixMilli()) } + +// 定义结构体用于存储话务量值和对应的时间 +type TrafficData struct { + Time int64 `json:"time"` // 时间戳(毫秒) + Value float64 `json:"value"` // 话务量值 +} + +// IMSBusyWeek IMS忙时流量统计 周 +func (r PerfKPI) 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()) + + if len(data) == 0 { + return map[string]any{ + "busyHourAverageBHCA": 0, + "busyHourAverageBHCC": 0, + "topFourHoursBHCA": []float64{}, + "topFourHoursBHCC": []float64{}, + "totalHours": 0, + } + } + + // 2. 分离BHCA和BHCC数据,并按降序排序 + var bhcaData []TrafficData + var bhccData []TrafficData + + for _, row := range data { + // 获取时间戳 + timeValue := int64(0) + if t, ok := row["timeGroup"]; ok { + timeValue = parse.Number(t) + } + + // 处理BHCA数据 + if value, ok := row["callAttempts"]; ok { + bhcaVal := parse.Number(value) + bhcaData = append(bhcaData, TrafficData{ + Time: timeValue, + Value: float64(bhcaVal), + }) + } + + // 处理BHCC数据 + if value, ok := row["callCompletions"]; ok { + bhccVal := parse.Number(value) + bhccData = append(bhccData, TrafficData{ + Time: timeValue, + Value: float64(bhccVal), + }) + } + } + // 按降序排序(值大的在前) + sort.Slice(bhcaData, func(i, j int) bool { return bhcaData[i].Value > bhcaData[j].Value }) + sort.Slice(bhccData, func(i, j int) bool { return bhccData[i].Value > bhccData[j].Value }) + + // 3. 取前四个最高值并计算平均值 + topFourBHCA := getTopFourTrafficData(bhcaData) + topFourBHCC := getTopFourTrafficData(bhccData) + + avgBHCA := calculateTrafficDataAverage(topFourBHCA) + avgBHCC := calculateTrafficDataAverage(topFourBHCC) + + // 4. 返回结果 + return map[string]any{ + "busyHourAverageBHCA": avgBHCA, + "busyHourAverageBHCC": avgBHCC, + "topFourHoursBHCA": topFourBHCA, + "topFourHoursBHCC": topFourBHCC, + "totalHours": len(data), + } +} + +// 辅助函数:获取前四个最高值的TrafficData +func getTopFourTrafficData(data []TrafficData) []TrafficData { + if len(data) == 0 { + return []TrafficData{} + } + + // 最多取前四个值 + maxCount := 4 + if len(data) < maxCount { + maxCount = len(data) + } + + return data[:maxCount] +} + +// 辅助函数:计算TrafficData的平均值 +func calculateTrafficDataAverage(data []TrafficData) float64 { + if len(data) == 0 { + return 0 + } + + var sum float64 = 0 + for _, v := range data { + sum += v.Value + } + + return sum / float64(len(data)) +}