From 397947f0b95e2175f5ebf52e4bfd77113fd7f0a0 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 17 Sep 2025 16:53:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1-=E5=AF=BC=E5=87=BA=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89KPI=E6=95=B0=E6=8D=AE=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backup_export_kpi/backup_export_kpi.go | 192 ++++++++++++- .../network_data/model/kpi_c_report.go | 52 ++++ .../network_data/repository/kpi_c_report.go | 252 ++++++++++++++++++ .../network_data/service/kpi_c_report.go | 192 +++++++++++++ 4 files changed, 678 insertions(+), 10 deletions(-) create mode 100644 src/modules/network_data/model/kpi_c_report.go create mode 100644 src/modules/network_data/repository/kpi_c_report.go create mode 100644 src/modules/network_data/service/kpi_c_report.go diff --git a/src/modules/crontask/processor/backup_export_kpi/backup_export_kpi.go b/src/modules/crontask/processor/backup_export_kpi/backup_export_kpi.go index 8c1d10e7..378bf5eb 100644 --- a/src/modules/crontask/processor/backup_export_kpi/backup_export_kpi.go +++ b/src/modules/crontask/processor/backup_export_kpi/backup_export_kpi.go @@ -22,18 +22,20 @@ import ( ) var NewProcessor = &BackupExportKPIProcessor{ - count: 0, - backupService: neDataService.NewBackup, - neInfoService: neService.NewNeInfo, - perfKPIService: neDataService.NewPerfKPI, + count: 0, + backupService: neDataService.NewBackup, + neInfoService: neService.NewNeInfo, + perfKPIService: neDataService.NewPerfKPI, + kpiCReportService: neDataService.NewKpiCReport, } // BackupExportKPI 队列任务处理 type BackupExportKPIProcessor struct { - count int // 执行次数 - backupService *neDataService.Backup // 备份相关服务 - neInfoService *neService.NeInfo // 网元信息服务 - perfKPIService *neDataService.PerfKPI // 统计信息服务 + count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + neInfoService *neService.NeInfo // 网元信息服务 + perfKPIService *neDataService.PerfKPI // 统计信息服务 + kpiCReportService *neDataService.KpiCReport // KPI统计服务 } func (s *BackupExportKPIProcessor) Execute(data any) (any, error) { @@ -47,7 +49,7 @@ func (s *BackupExportKPIProcessor) Execute(data any) (any, error) { } var params struct { - DataType []string `json:"dataType"` // 类型支持 ims/smsc/smf/sgwc + DataType []string `json:"dataType"` // 类型支持 ims/amf/udm/smf/pcf/upf/mme/smsc FileType string `json:"fileType"` // 文件类型 csv/xlsx Hour int `json:"hour"` // 数据时间从任务执行时间前的小时数 } @@ -70,6 +72,8 @@ func (s *BackupExportKPIProcessor) Execute(data any) (any, error) { if ne.NeType == "UPF" { interval = 5 } + + // query := neDataModel.GoldKPIQuery{ NeType: ne.NeType, NeID: ne.NeId, @@ -78,7 +82,18 @@ func (s *BackupExportKPIProcessor) Execute(data any) (any, error) { StartTime: fmt.Sprintf("%d", start.UnixMilli()), EndTime: fmt.Sprintf("%d", end.UnixMilli()), } - result[ne.NeName] = s.exportKPI(query, params.FileType) + result[ne.NeName+"_kpi"] = s.exportKPI(query, params.FileType) + + // + queryC := neDataModel.KPICQuery{ + NeType: ne.NeType, + NeID: ne.NeId, + RmUID: ne.RmUID, + Interval: interval, + BeginTime: start.UnixMilli(), + EndTime: end.UnixMilli(), + } + result[ne.NeName+"_kpic"] = s.exportKPIC(queryC, params.FileType) } } @@ -242,3 +257,160 @@ func (s *BackupExportKPIProcessor) exportKPI(query neDataModel.GoldKPIQuery, fil } return "ok" } + +// exportKPI 导出KPIC数据 +func (s *BackupExportKPIProcessor) exportKPIC(query neDataModel.KPICQuery, fileType string) string { + rows := s.kpiCReportService.FindData(query) + if len(rows) == 0 { + return "no data" + } + + // 获取数据指标id + kpiTitleMap := make(map[string]string, 0) + kpiTitles := s.kpiCReportService.FindTitle(query.NeType) + for _, v := range kpiTitles { + kpiTitleMap[v.KpiId] = v.Title + } + + // 导出文件名称 + dateStr := date.ParseDateToStr(parse.Number(query.EndTime), date.YYYYMMDDHHMMSS) + fileName := fmt.Sprintf("%s_%s_kpic_export_%d_%s.%s", strings.ToLower(query.NeType), query.NeID, len(rows), dateStr, fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/%s_kpi", strings.ToLower(query.NeType)), fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + data := [][]string{} + + // 获取kpiIdMap的键并排序 + var sortedKpiIds []string + for kpiId := range kpiTitleMap { + sortedKpiIds = append(sortedKpiIds, kpiId) + } + sort.Strings(sortedKpiIds) // 按字母排序 + + // 头 - 按排序后的顺序添加标题 + header := []string{} + for _, kpiId := range sortedKpiIds { + header = append(header, kpiTitleMap[kpiId]) + } + header = append(header, "NE Name") + header = append(header, "Time") + data = append(data, header) + + for _, row := range rows { + // 取时间 + timeStr := "" + if v, ok := row["timeGroup"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DD_HH_MM_SS_GMT_TZ) + } else { + timeStr = fmt.Sprintf("%s", v) + } + } + // 取网元名称 + neName := "" + if v, ok := row["neName"]; ok && v != nil { + neName = fmt.Sprintf("%s", v) + } + + // 按排序后的顺序获取数据 + dataRow := []string{} + for _, kpiId := range sortedKpiIds { + value := "" + if v, ok := row[kpiId]; ok && v != nil { + value = fmt.Sprint(v) + } + dataRow = append(dataRow, value) + } + dataRow = append(dataRow, neName) + dataRow = append(dataRow, timeStr) + data = append(data, dataRow) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 获取kpiIdMap的键并排序 + var sortedKpiIds []string + for kpiId := range kpiTitleMap { + sortedKpiIds = append(sortedKpiIds, kpiId) + } + sort.Strings(sortedKpiIds) // 按字母排序 + + // 第一行表头标题 - 按排序后的顺序 + headerCells := map[string]string{} + colIndex := 0 + + // 先添加KPI标题列 + for i, kpiId := range sortedKpiIds { + colLetter := string(rune('A' + i)) + headerCells[colLetter+"1"] = kpiTitleMap[kpiId] + colIndex++ + } + + // 添加NE Name和Time列 + neNameCol := string(rune('A' + colIndex)) + headerCells[neNameCol+"1"] = "NE Name" + colIndex++ + + timeCol := string(rune('A' + colIndex)) + headerCells[timeCol+"1"] = "Time" + + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + + // 取时间和网元名称 + timeStr := "" + if v, ok := row["timeGroup"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DD_HH_MM_SS_GMT_TZ) + } else { + timeStr = fmt.Sprintf("%s", v) + } + } + + neName := "" + if v, ok := row["neName"]; ok && v != nil { + neName = fmt.Sprintf("%s", v) + } + + // 按排序后的顺序填充数据 + dataCell := map[string]any{} + + // 填充KPI数据 + for j, kpiId := range sortedKpiIds { + value := "" + if v, ok := row[kpiId]; ok && v != nil { + value = fmt.Sprint(v) + } + colLetter := string(rune('A' + j)) + dataCell[colLetter+idx] = value + } + + // 填充NE Name和Time + dataCell[neNameCol+idx] = neName + dataCell[timeCol+idx] = timeStr + + dataCells = append(dataCells, dataCell) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, ""); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} diff --git a/src/modules/network_data/model/kpi_c_report.go b/src/modules/network_data/model/kpi_c_report.go new file mode 100644 index 00000000..9cd6aedf --- /dev/null +++ b/src/modules/network_data/model/kpi_c_report.go @@ -0,0 +1,52 @@ +package model + +// KpiCTitle 自定义指标标题信息对象 kpi_title +type KpiCTitle struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + KpiId string `json:"kpiId" gorm:"column:kpi_id"` + Title string `json:"title" gorm:"column:title"` + Expression string `json:"expression" gorm:"column:expression"` + Unit string `json:"unit" gorm:"column:unit"` + Status string `json:"status" gorm:"column:status"` // 0-Inactive/1-Active/2-Deleted + Description string `json:"description" gorm:"column:description"` + CreatedBy string `json:"createdBy" gorm:"column:created_by"` + UpdatedAt int64 `json:"updatedAt" gorm:"column:updated_at"` +} + +// TableName 表名称 +func (*KpiCTitle) TableName() string { + return "kpi_c_title" +} + +// KpiCReport 自定义指标报表信息对象 +type KpiCReport 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 +} + +// TableName 表名称 +func (*KpiCReport) TableName() string { + return "kpi_c_report" +} + +// KPICQuery 指标查询参数结构体 +type KPICQuery struct { + NeType string `form:"neType" binding:"required"` + NeID string `form:"neId" binding:"required"` + BeginTime int64 `form:"beginTime" binding:"required"` // 开始时间戳(毫秒)1739361200999 + EndTime int64 `form:"endTime" binding:"required"` // 结束时间戳(毫秒)1739361210088 + 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/repository/kpi_c_report.go b/src/modules/network_data/repository/kpi_c_report.go new file mode 100644 index 00000000..f87a7c51 --- /dev/null +++ b/src/modules/network_data/repository/kpi_c_report.go @@ -0,0 +1,252 @@ +package repository + +import ( + "fmt" + "sort" + "strings" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 KpiCReport 结构体 +var NewKpiCReport = &KpiCReport{} + +// KpiCReport 性能统计 数据层处理 +type KpiCReport struct{} + +// SelectGoldKPI 通过网元指标数据信息 +func (r KpiCReport) SelectKPI(query model.KPICQuery) []model.KpiCReport { + rows := []model.KpiCReport{} + if query.NeType == "" { + return rows + } + + tx := db.DB("").Model(&model.KpiCReport{}) + // 表名 + tableName := fmt.Sprintf("kpi_c_report_%s", strings.ToLower(query.NeType)) + tx.Table(tableName) + // 构建查询条件 + if query.RmUID != "" { + tx = tx.Where("rm_uid = ?", query.RmUID) + } + if query.BeginTime != 0 { + tx = tx.Where("created_at >= ?", query.BeginTime) + } + if query.EndTime != 0 { + tx = tx.Where("created_at <= ?", query.EndTime) + } + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + // 排序 + if query.SortField != "" { + sortField := query.SortField + sortOrder := query.SortOrder + sort.SliceStable(rows, func(i, j int) bool { + // 支持的排序字段映射 + fieldGetters := map[string]func(*model.KpiCReport) any{ + "id": func(row *model.KpiCReport) any { return row.ID }, + "timeGroup": func(row *model.KpiCReport) any { return row.CreatedAt }, + "createdAt": func(row *model.KpiCReport) any { return row.CreatedAt }, + // 可添加更多支持的字段 + } + + // 获取字段 getter 函数 + getter, ok := fieldGetters[sortField] + if !ok { + // 非法字段,使用默认排序(id升序) + return rows[i].ID < rows[j].ID + } + + // 获取比较值 + valI, valJ := getter(&rows[i]), getter(&rows[j]) + + // 根据字段类型进行比较 + switch v := valI.(type) { + case int64: + if sortOrder == "desc" { + return v > valJ.(int64) + } + return v < valJ.(int64) + case string: + if sortOrder == "desc" { + return v > valJ.(string) + } + return v < valJ.(string) + default: + // 不支持的字段类型,使用默认排序 + return rows[i].ID < rows[j].ID + } + }) + } + return rows +} + +// Insert 新增信息 返回新增数据ID +func (r KpiCReport) Insert(param model.KpiCReport) int64 { + if param.NeType == "" { + return 0 + } + if param.CreatedAt == 0 { + param.CreatedAt = time.Now().UnixMilli() + } + // 表名 + tableName := fmt.Sprintf("kpi_c_report_%s", strings.ToLower(param.NeType)) + // 执行插入 + if err := db.DB("").Table(tableName).Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} + +// SelectKPITitle 网元对应的指标名称 +func (r KpiCReport) SelectKPITitle(neType string) []model.KpiCTitle { + rows := []model.KpiCTitle{} + if neType == "" { + return rows + } + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + tx = tx.Where("ne_type =?", neType) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// TitleLastKPIId 查询指标标题最后kpiid +func (r KpiCReport) TitleLastKPIId(neType string) string { + tx := db.DB("").Model(&model.KpiCTitle{}) + tx = tx.Where("ne_type=?", neType) + tx = tx.Select("kpi_id").Order("kpi_id DESC") + // 查询数据 + var kpiId string = "" + if err := tx.Limit(1).Find(&kpiId).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return kpiId + } + return kpiId +} + +// SelectByPageTitle 分页查询集合 +func (r KpiCReport) TitleSelectByPage(query map[string]string) ([]model.KpiCTitle, int64) { + tx := db.DB("").Model(&model.KpiCTitle{}) + // 查询条件拼接 + if v, ok := query["neType"]; ok && v != "" { + tx = tx.Where("ne_type = ?", v) + } + if v, ok := query["status"]; ok && v != "" { + tx = tx.Where("status = ?", v) + } else { + tx = tx.Where("status != ?", "2") + } + + // 查询结果 + var total int64 = 0 + rows := []model.KpiCTitle{} + + // 查询数量 长度为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize)) + + // 排序 + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v + if o, ok := query["sortOrder"]; ok && o != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + tx = tx.Order(sortSql) + } + + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query err => %v", err) + } + + return rows, total +} + +// TitleSelect 网元对应的指标名称 +func (r KpiCReport) TitleSelect(param model.KpiCTitle) []model.KpiCTitle { + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + if param.NeType != "" { + tx = tx.Where("ne_type =?", param.NeType) + } + if param.Title != "" { + tx = tx.Where("title = ?", param.Title) + } + if param.Status != "" { + tx = tx.Where("status = ?", param.Status) + } + // 查询数据 + rows := []model.KpiCTitle{} + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// TitleInsert 新增信息 +func (r KpiCReport) TitleInsert(param model.KpiCTitle) int64 { + if param.CreatedBy != "" { + param.UpdatedAt = time.Now().UnixMilli() + } + param.Status = "1" + tx := db.DB("").Create(¶m) + if err := tx.Error; err != nil { + logger.Errorf("CreateInBatches err => %v", err) + } + return param.ID +} + +// TitleUpdate 修改信息 +func (r KpiCReport) TitleUpdate(param model.KpiCTitle) int64 { + if param.ID <= 0 { + return 0 + } + param.UpdatedAt = time.Now().UnixMilli() + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + tx = tx.Where("id = ?", param.ID) + tx = tx.Omit("id", "created_by") + // 执行更新 + if err := tx.Updates(param).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// TitleDeleteByIds 批量删除信息 +func (r KpiCReport) TitleDeleteByIds(ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + tx := db.DB("").Model(&model.KpiCTitle{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + if err := tx.Update("status", 2).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/network_data/service/kpi_c_report.go b/src/modules/network_data/service/kpi_c_report.go new file mode 100644 index 00000000..a6fc073c --- /dev/null +++ b/src/modules/network_data/service/kpi_c_report.go @@ -0,0 +1,192 @@ +package service + +import ( + "encoding/json" + "fmt" + "sort" + + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" +) + +// 实例化数据层 KpiCReport 结构体 +var NewKpiCReport = &KpiCReport{ + kpiCReportRepository: repository.NewKpiCReport, +} + +// KpiCReport 自定义性能统计 服务层处理 +type KpiCReport struct { + kpiCReportRepository *repository.KpiCReport // 自定义KPI数据信息 +} + +// FindKPI 通过网元指标数据信息 +func (s KpiCReport) FindData(query model.KPICQuery) []map[string]any { + // 标题单位映射 + kpicTitles := s.kpiCReportRepository.SelectKPITitle(query.NeType) + kpicTitleUnitMap := map[string]string{} + for _, v := range kpicTitles { + kpicTitleUnitMap[v.KpiId] = v.Unit + } + // 原始数据 + rows := s.kpiCReportRepository.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["kpiId"]; ok { + kpiId = fmt.Sprint(k) + } + 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["kpiId"]; ok { + kpiId = fmt.Sprint(k) + } + 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 { + value := v.(float64) + startItem[kpiId].(float64) + startItem[kpiId] = value + // value := parse.Number(startItem[kpiId]) + // startItem[kpiId] = value + parse.Number(v) + } + } + } + // 处理单位 + for _, kpiId := range kpiIds { + unit, ok := kpicTitleUnitMap[kpiId] + if !ok { + continue + } + // "Mbps" "%" + if unit == "%" { + startItem[kpiId] = startItem[kpiId].(float64) / float64(len(records)) + } + } + } + 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 +} + +// Insert 新增信息 +func (s KpiCReport) Insert(param model.KpiCReport) int64 { + return s.kpiCReportRepository.Insert(param) +} + +// FindKPITitle 网元对应的指标名称 +func (r KpiCReport) FindTitle(neType string) []model.KpiCTitle { + return r.kpiCReportRepository.SelectKPITitle(neType) +} + +// TitleLastKPIId 指标标题最后kpiid +func (r KpiCReport) TitleLastKPIId(neType string) string { + return r.kpiCReportRepository.TitleLastKPIId(neType) +} + +// FindByPage 根据条件分页查询 +func (r KpiCReport) TitleFindByPage(query map[string]string) ([]model.KpiCTitle, int64) { + return r.kpiCReportRepository.TitleSelectByPage(query) +} + +// TitleFind 查询信息 +func (r KpiCReport) TitleFind(param model.KpiCTitle) []model.KpiCTitle { + return r.kpiCReportRepository.TitleSelect(param) +} + +// TitleUpdate 更新信息 +func (r KpiCReport) TitleUpdate(param model.KpiCTitle) int64 { + return r.kpiCReportRepository.TitleUpdate(param) +} + +// TitleDeleteByIds 批量删除信息 +func (r KpiCReport) TitleDeleteByIds(ids []int64) (int64, error) { + rows := r.kpiCReportRepository.TitleDeleteByIds(ids) + if rows > 0 { + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// TitleInsert 新增信息 +func (r KpiCReport) TitleInsert(param model.KpiCTitle) int64 { + return r.kpiCReportRepository.TitleInsert(param) +}