feat: 忙时定义为一周内话务量最高的四个小时的平均值

This commit is contained in:
TsMask
2025-09-08 18:31:21 +08:00
parent ec02b6cbb3
commit 24fc8115d6
4 changed files with 165 additions and 1 deletions

View File

@@ -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))
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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))
}