Merge branch 'main-v2' into lite-ba
This commit is contained in:
@@ -107,9 +107,10 @@ func processSQLFile(db *gorm.DB, filePath string) {
|
||||
// 忽略重复记录错误
|
||||
// Error 1062 (23000): Duplicate entry 'value' for key 'key_name'
|
||||
log.Println(err.Error())
|
||||
} else if strings.Contains(errorStr, "unknown column") {
|
||||
} else if strings.Contains(errorStr, "unknown column") || strings.Contains(errorStr, "no such column") {
|
||||
// 忽略未知字段错误
|
||||
// Error 1054 (42S22): Unknown column 'field_name' in 'table'
|
||||
// sql logic error: no such column: "field_name" (1)
|
||||
} else if strings.Contains(errorStr, "can't drop") {
|
||||
// 忽略删除字段或索引错误
|
||||
// Error 1091 (42000): Can't DROP COLUMN `field_name`; check that it exists
|
||||
|
||||
@@ -31,6 +31,13 @@ type Oauth2ClientController struct {
|
||||
// GET /list
|
||||
func (s Oauth2ClientController) List(c *gin.Context) {
|
||||
query := reqctx.QueryMap(c)
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
rows, total := s.oauth2ClientService.FindByPage(query)
|
||||
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
|
||||
}
|
||||
|
||||
@@ -61,26 +61,49 @@ func (s *BackupExportCDRProcessor) Execute(data any) (any, error) {
|
||||
}
|
||||
|
||||
for _, v := range params.DataType {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(params.Hour) * time.Hour)
|
||||
query := map[string]string{
|
||||
"neType": "",
|
||||
"neId": "",
|
||||
"rmUID": "",
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
}
|
||||
switch v {
|
||||
case "ims":
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: "IMS"}, false, false)
|
||||
for _, ne := range neList {
|
||||
result[ne.NeName] = s.exportIMS(params.Hour, ne.RmUID, params.FileType)
|
||||
query["neType"] = "IMS"
|
||||
query["neId"] = ne.NeId
|
||||
query["rmUID"] = ne.RmUID
|
||||
result[ne.NeName] = s.exportIMS(query, params.FileType)
|
||||
}
|
||||
case "smsc":
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMSC"}, false, false)
|
||||
for _, ne := range neList {
|
||||
result[ne.NeName] = s.exportSMSC(params.Hour, ne.RmUID, params.FileType)
|
||||
query["neType"] = "SMSC"
|
||||
query["neId"] = ne.NeId
|
||||
query["rmUID"] = ne.RmUID
|
||||
result[ne.NeName] = s.exportSMSC(query, params.FileType)
|
||||
}
|
||||
case "smf":
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMF"}, false, false)
|
||||
for _, ne := range neList {
|
||||
result[ne.NeName] = s.exportSMF(params.Hour, ne.RmUID, params.FileType)
|
||||
query["neType"] = "SMF"
|
||||
query["neId"] = ne.NeId
|
||||
query["rmUID"] = ne.RmUID
|
||||
result[ne.NeName] = s.exportSMF(query, params.FileType)
|
||||
}
|
||||
case "sgwc":
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SGWC"}, false, false)
|
||||
for _, ne := range neList {
|
||||
result[ne.NeName] = s.exportSGWC(params.Hour, ne.RmUID, params.FileType)
|
||||
query["neType"] = "SGWC"
|
||||
query["neId"] = ne.NeId
|
||||
query["rmUID"] = ne.RmUID
|
||||
result[ne.NeName] = s.exportSGWC(query, params.FileType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,30 +113,21 @@ func (s *BackupExportCDRProcessor) Execute(data any) (any, error) {
|
||||
}
|
||||
|
||||
// exportIMS 导出IMS-CDR会话事件数据
|
||||
func (s BackupExportCDRProcessor) exportIMS(hour int, rmUID, fileType string) string {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(hour) * time.Hour)
|
||||
|
||||
func (s BackupExportCDRProcessor) exportIMS(query map[string]string, fileType string) string {
|
||||
language := "en"
|
||||
query := map[string]string{
|
||||
"sortField": "timestamp",
|
||||
"sortOrder": "asc",
|
||||
"rmUID": rmUID,
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": fmt.Sprint(1),
|
||||
"pageSize": fmt.Sprint(30000),
|
||||
}
|
||||
rows, total := s.cdrEventService.FindByPage("IMS", query)
|
||||
neType := query["neType"]
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
neId := query["neId"]
|
||||
endTime := parse.Number(query["endTime"])
|
||||
rows, total := s.cdrEventService.FindByPage(neType, query)
|
||||
if total == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("ims_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/ims_cdr_event", fileName)
|
||||
dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -379,30 +393,21 @@ func (s BackupExportCDRProcessor) exportIMS(hour int, rmUID, fileType string) st
|
||||
}
|
||||
|
||||
// exportSMSC 导出SMSC-CDR会话事件数据
|
||||
func (s BackupExportCDRProcessor) exportSMSC(hour int, rmUID, fileType string) string {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(hour) * time.Hour)
|
||||
|
||||
func (s BackupExportCDRProcessor) exportSMSC(query map[string]string, fileType string) string {
|
||||
language := "en"
|
||||
query := map[string]string{
|
||||
"sortField": "timestamp",
|
||||
"sortOrder": "asc",
|
||||
"rmUID": rmUID,
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": fmt.Sprint(1),
|
||||
"pageSize": fmt.Sprint(30000),
|
||||
}
|
||||
rows, total := s.cdrEventService.FindByPage("SMSC", query)
|
||||
neType := query["neType"]
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
neId := query["neId"]
|
||||
endTime := parse.Number(query["endTime"])
|
||||
rows, total := s.cdrEventService.FindByPage(neType, query)
|
||||
if total == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/smsc_cdr_event", fileName)
|
||||
dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -596,29 +601,20 @@ func (s BackupExportCDRProcessor) exportSMSC(hour int, rmUID, fileType string) s
|
||||
}
|
||||
|
||||
// exportSMF 导出SMF-CDR会话事件数据
|
||||
func (s BackupExportCDRProcessor) exportSMF(hour int, rmUID, fileType string) string {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(hour) * time.Hour)
|
||||
|
||||
query := map[string]string{
|
||||
"sortField": "timestamp",
|
||||
"sortOrder": "asc",
|
||||
"rmUID": rmUID,
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": fmt.Sprint(1),
|
||||
"pageSize": fmt.Sprint(30000),
|
||||
}
|
||||
rows, total := s.cdrEventService.FindByPage("SMF", query)
|
||||
func (s BackupExportCDRProcessor) exportSMF(query map[string]string, fileType string) string {
|
||||
neType := query["neType"]
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
neId := query["neId"]
|
||||
endTime := parse.Number(query["endTime"])
|
||||
rows, total := s.cdrEventService.FindByPage(neType, query)
|
||||
if total == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("smf_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/smf_cdr_event", fileName)
|
||||
dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -1004,29 +1000,20 @@ func (s BackupExportCDRProcessor) exportSMF(hour int, rmUID, fileType string) st
|
||||
}
|
||||
|
||||
// exportSGWC 导出SGWC-CDR会话事件数据
|
||||
func (s BackupExportCDRProcessor) exportSGWC(hour int, rmUID, fileType string) string {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(hour) * time.Hour)
|
||||
|
||||
query := map[string]string{
|
||||
"sortField": "timestamp",
|
||||
"sortOrder": "asc",
|
||||
"rmUID": rmUID,
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": fmt.Sprint(1),
|
||||
"pageSize": fmt.Sprint(30000),
|
||||
}
|
||||
rows, total := s.cdrEventService.FindByPage("SGWC", query)
|
||||
func (s BackupExportCDRProcessor) exportSGWC(query map[string]string, fileType string) string {
|
||||
neType := query["neType"]
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
neId := query["neId"]
|
||||
endTime := parse.Number(query["endTime"])
|
||||
rows, total := s.cdrEventService.FindByPage(neType, query)
|
||||
if total == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/sgwc_cdr_event", fileName)
|
||||
dateStr := date.ParseDateToStr(endTime, date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("%s_%s_cdr_export_%d_%s.%s", neTypeLower, neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/cdr/%s", neTypeLower), fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,416 @@
|
||||
package backup_export_kpi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/cron"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neModel "be.ems/src/modules/ne/model"
|
||||
neService "be.ems/src/modules/ne/service"
|
||||
neDataModel "be.ems/src/modules/ne_data/model"
|
||||
neDataService "be.ems/src/modules/ne_data/service"
|
||||
)
|
||||
|
||||
var NewProcessor = &BackupExportKPIProcessor{
|
||||
count: 0,
|
||||
backupService: neDataService.NewBackup,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
kpiReportService: neDataService.NewKpiReport,
|
||||
kpicReportService: neDataService.NewKpiCReport,
|
||||
}
|
||||
|
||||
// BackupExportKPI 队列任务处理
|
||||
type BackupExportKPIProcessor struct {
|
||||
count int // 执行次数
|
||||
backupService *neDataService.Backup // 备份相关服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
kpiReportService *neDataService.KpiReport // 统计信息服务
|
||||
kpicReportService *neDataService.KpiCReport // 统计信息服务
|
||||
}
|
||||
|
||||
func (s *BackupExportKPIProcessor) Execute(data any) (any, error) {
|
||||
s.count++ // 执行次数加一
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count)
|
||||
// 返回结果,用于记录执行结果
|
||||
result := map[string]any{
|
||||
"count": s.count,
|
||||
}
|
||||
|
||||
var params struct {
|
||||
DataType []string `json:"dataType"` // 类型支持 ims/amf/udm/smf/pcf/upf/mme/smsc
|
||||
FileType string `json:"fileType"` // 文件类型 csv/xlsx
|
||||
Hour int `json:"hour"` // 数据时间从任务执行时间前的小时数
|
||||
}
|
||||
if err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !(params.FileType == "csv" || params.FileType == "xlsx") {
|
||||
return nil, fmt.Errorf("file type error, only support csv,xlsx")
|
||||
}
|
||||
|
||||
for _, v := range params.DataType {
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: strings.ToUpper(v)}, false, false)
|
||||
for _, ne := range neList {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
start := end.Add(-time.Duration(params.Hour) * time.Hour)
|
||||
// 密度
|
||||
var interval int64 = 60
|
||||
if ne.NeType == "UPF" {
|
||||
interval = 5
|
||||
}
|
||||
|
||||
// 指标
|
||||
query := neDataModel.KPIQuery{
|
||||
NeType: ne.NeType,
|
||||
NeID: ne.NeId,
|
||||
RmUID: ne.RmUID,
|
||||
Interval: interval,
|
||||
BeginTime: start.UnixMilli(),
|
||||
EndTime: end.UnixMilli(),
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// exportKPI 导出KPI数据
|
||||
func (s *BackupExportKPIProcessor) exportKPI(query neDataModel.KPIQuery, fileType string) string {
|
||||
rows := s.kpiReportService.FindData(query)
|
||||
if len(rows) == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 获取数据指标id
|
||||
kpiIdMap := make(map[string]string, 0)
|
||||
kpiTitles := s.kpiReportService.FindTitle(query.NeType)
|
||||
for _, v := range kpiTitles {
|
||||
kpiIdMap[v.KpiId] = v.EnTitle
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
dateStr := date.ParseDateToStr(parse.Number(query.EndTime), date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("%s_%s_kpi_export_%d_%s.%s", strings.ToLower(query.NeType), query.NeID, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, fmt.Sprintf("/kpi/%s", 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 kpiIdMap {
|
||||
sortedKpiIds = append(sortedKpiIds, kpiId)
|
||||
}
|
||||
sort.Strings(sortedKpiIds) // 按字母排序
|
||||
|
||||
// 头 - 按排序后的顺序添加标题
|
||||
header := []string{}
|
||||
for _, kpiId := range sortedKpiIds {
|
||||
header = append(header, kpiIdMap[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_DDTHH_MM_SSZ)
|
||||
} 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 kpiIdMap {
|
||||
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"] = kpiIdMap[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_DDTHH_MM_SSZ)
|
||||
} 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"
|
||||
}
|
||||
|
||||
// exportKPI 导出KPI数据
|
||||
func (s *BackupExportKPIProcessor) exportKPIC(query neDataModel.KPICQuery, fileType string) string {
|
||||
rows := s.kpicReportService.FindData(query)
|
||||
if len(rows) == 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 获取数据指标id
|
||||
kpiIdMap := make(map[string]string, 0)
|
||||
kpiTitles := s.kpiReportService.FindTitle(query.NeType)
|
||||
for _, v := range kpiTitles {
|
||||
kpiIdMap[v.KpiId] = v.EnTitle
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
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("/kpi/%s", 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 kpiIdMap {
|
||||
sortedKpiIds = append(sortedKpiIds, kpiId)
|
||||
}
|
||||
sort.Strings(sortedKpiIds) // 按字母排序
|
||||
|
||||
// 头 - 按排序后的顺序添加标题
|
||||
header := []string{}
|
||||
for _, kpiId := range sortedKpiIds {
|
||||
header = append(header, kpiIdMap[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_DDTHH_MM_SSZ)
|
||||
} 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 kpiIdMap {
|
||||
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"] = kpiIdMap[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_DDTHH_MM_SSZ)
|
||||
} 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"
|
||||
}
|
||||
@@ -79,8 +79,6 @@ func (s BackupExportLogProcessor) exportOperate(hour int, fileType string) strin
|
||||
query := map[string]string{
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": "1",
|
||||
"pageSize": "30000",
|
||||
}
|
||||
rows, total := s.sysOperateService.FindByPage(query, "")
|
||||
if total == 0 {
|
||||
@@ -97,7 +95,8 @@ func (s BackupExportLogProcessor) exportOperate(hour int, fileType string) strin
|
||||
converI18n(language, &rows)
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("sys_log_operate_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
dateStr := date.ParseDateToStr(end.UnixMilli(), date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("sys_log_operate_export_%d_%s.%s", len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_operate", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
@@ -243,8 +242,6 @@ func (s BackupExportLogProcessor) exportLogin(hour int, fileType string) string
|
||||
query := map[string]string{
|
||||
"beginTime": fmt.Sprint(start.UnixMilli()),
|
||||
"endTime": fmt.Sprint(end.UnixMilli()),
|
||||
"pageNum": "1",
|
||||
"pageSize": "30000",
|
||||
}
|
||||
rows, total := s.sysLogLoginService.FindByPage(query, "")
|
||||
if total == 0 {
|
||||
@@ -263,7 +260,8 @@ func (s BackupExportLogProcessor) exportLogin(hour int, fileType string) string
|
||||
converI18n(language, &rows)
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("sys_log_login_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType)
|
||||
dateStr := date.ParseDateToStr(end.UnixMilli(), date.YYYYMMDDHHMMSS)
|
||||
fileName := fmt.Sprintf("sys_log_login_export_%d_%s.%s", len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_login", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
|
||||
@@ -85,9 +85,10 @@ func (s BackupExportUDMProcessor) exportAuth(neId, fileType string) string {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("auth_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/auth", fileName)
|
||||
// 导出文件名称
|
||||
dateStr := time.Now().Format("20060102150405")
|
||||
fileName := fmt.Sprintf("auth_%s_export_%d_%s.%s", neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/udm/auth", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -139,9 +140,10 @@ func (s BackupExportUDMProcessor) exportSub(neId, fileType string) string {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("sub_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/sub", fileName)
|
||||
// 导出文件名称
|
||||
dateStr := time.Now().Format("20060102150405")
|
||||
fileName := fmt.Sprintf("sub_%s_export_%d_%s.%s", neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/udm/sub", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -187,9 +189,10 @@ func (s BackupExportUDMProcessor) exportVOIP(neId, fileType string) string {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("voip_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/voip", fileName)
|
||||
// 导出文件名称
|
||||
dateStr := time.Now().Format("20060102150405")
|
||||
fileName := fmt.Sprintf("voip_%s_export_%d_%s.%s", neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/udm/voip", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
@@ -233,9 +236,10 @@ func (s BackupExportUDMProcessor) exportVolte(neId, fileType string) string {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("volte_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/volte", fileName)
|
||||
// 导出文件名称
|
||||
dateStr := time.Now().Format("20060102150405")
|
||||
fileName := fmt.Sprintf("volte_%s_export_%d_%s.%s", neId, len(rows), dateStr, fileType)
|
||||
filePath := filepath.Join(s.backupService.BACKUP_DIR, "/udm/volte", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
triggerMax int64 = 3 // 阈值:连续触发次数大于该值才会产生告警
|
||||
triggerCount sync.Map // 阈值连续触发次数,存储每个事件的触发记录
|
||||
triggerWindow time.Duration = 5 * time.Second // 事件触发的时间窗口
|
||||
triggerMax int64 = 3 // 阈值:连续触发次数大于该值才会产生告警
|
||||
triggerCount sync.Map // 阈值连续触发次数,存储每个事件的触发记录
|
||||
triggerWindow time.Duration = 30 * time.Second // 事件触发的时间窗口
|
||||
)
|
||||
|
||||
var NewProcessor = &NeAlarmStateCheckCMDProcessor{
|
||||
|
||||
@@ -3,6 +3,7 @@ package processor
|
||||
import (
|
||||
"be.ems/src/framework/cron"
|
||||
processorBackupExportCDR "be.ems/src/modules/crontask/processor/backup_export_cdr"
|
||||
processorBackupExportKPI "be.ems/src/modules/crontask/processor/backup_export_kpi"
|
||||
processorBackupExportLog "be.ems/src/modules/crontask/processor/backup_export_log"
|
||||
processorBackupExportTable "be.ems/src/modules/crontask/processor/backup_export_table"
|
||||
processorBackupExportUDM "be.ems/src/modules/crontask/processor/backup_export_udm"
|
||||
@@ -60,4 +61,6 @@ func InitCronQueue() {
|
||||
cron.CreateQueue("backup_export_cdr", processorBackupExportCDR.NewProcessor)
|
||||
// 备份-导出Log数据
|
||||
cron.CreateQueue("backup_export_log", processorBackupExportLog.NewProcessor)
|
||||
// 备份-导出KPI数据
|
||||
cron.CreateQueue("backup_export_kpi", processorBackupExportKPI.NewProcessor)
|
||||
}
|
||||
|
||||
@@ -395,8 +395,6 @@ func (s NeInfoController) Add(c *gin.Context) {
|
||||
// 已有网元可获取的信息
|
||||
if body.ServerState != nil {
|
||||
if v, ok := body.ServerState["version"]; ok && v != nil {
|
||||
neVersion.Name = "-"
|
||||
neVersion.Path = "-"
|
||||
neVersion.Version = fmt.Sprint(v)
|
||||
}
|
||||
if v, ok := body.ServerState["sn"]; ok && v != nil {
|
||||
@@ -499,8 +497,6 @@ func (s NeInfoController) Edit(c *gin.Context) {
|
||||
// 已有网元可获取的信息
|
||||
if body.ServerState != nil {
|
||||
if v, ok := body.ServerState["version"]; ok && v != nil {
|
||||
neVersion.Name = "-"
|
||||
neVersion.Path = "-"
|
||||
neVersion.Version = fmt.Sprint(v)
|
||||
neVersion.UpdateBy = loginUserName
|
||||
}
|
||||
|
||||
@@ -80,28 +80,99 @@ func (s NeConfigBackup) FileLocalToNe(neInfo model.NeInfo, localFile string) err
|
||||
return fmt.Errorf("unzip err")
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
// sshClient, err := NewNeInfo.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("ne info ssh client err")
|
||||
// }
|
||||
// defer sshClient.Close()
|
||||
// // 网元主机的SSH客户端进行文件传输
|
||||
// sftpClient, err := sshClient.NewClientSFTP()
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("ne info sftp client err")
|
||||
// }
|
||||
// defer sftpClient.Close()
|
||||
// 本地复制到网元端
|
||||
if err := s.FileLocalToNePath(neInfo, localDirPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirPath) // 删除本地临时目录
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileNeToLocal 网元备份文件网元端复制到本地
|
||||
func (s NeConfigBackup) FileNeToLocal(neInfo model.NeInfo) (string, error) {
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 网管本地路径
|
||||
omcPath := "/usr/local/omc/backup/ne_config"
|
||||
if runtime.GOOS == "windows" {
|
||||
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||
}
|
||||
localDirPath := fmt.Sprintf("%s/%s/%s/from_ne_tmp", omcPath, neTypeLower, neInfo.NeId)
|
||||
|
||||
// 网元端复制到本地
|
||||
if err := s.FileNeToLocalPath(neInfo, localDirPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 压缩zip文件名
|
||||
zipFileName := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, neInfo.NeId, date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS))
|
||||
zipFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neInfo.NeId, zipFileName)
|
||||
if err := file.CompressZipByDir(zipFilePath, localDirPath); err != nil {
|
||||
return "", fmt.Errorf("compress zip err")
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirPath) // 删除本地临时目录
|
||||
return zipFilePath, nil
|
||||
}
|
||||
|
||||
// FileNeToLocalPath 网元备份文件网元端复制到本地路径
|
||||
func (s NeConfigBackup) FileNeToLocalPath(neInfo model.NeInfo, localDirPath string) error {
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
|
||||
// 网元配置文件先复制到临时目录
|
||||
cmd.Exec("sudo mkdir -p /tmp/omc/ne_config && sudo chmod 777 -R /tmp/omc")
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/ne_config/%s/%s", neTypeLower, neInfo.NeId)
|
||||
switch neTypeLower {
|
||||
case "ims":
|
||||
// ims目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/ims", neDirTemp))
|
||||
imsDirArr := [...]string{"bgcf", "icscf", "ismc", "mmtel", "mrf", "oam_manages.yaml", "pcscf", "scscf", "vars.cfg", "zlog"}
|
||||
for _, v := range imsDirArr {
|
||||
cmd.Exec(fmt.Sprintf("sudo cp -rf /usr/local/etc/ims/%s %s/ims", v, neDirTemp))
|
||||
}
|
||||
// mf目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/mf && sudo cp -rf /usr/local/etc/mf %s", neDirTemp, neDirTemp))
|
||||
// rtproxy目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/rtproxy && sudo cp -rf /usr/local/etc/rtproxy/rtproxy.conf %s/rtproxy", neDirTemp, neDirTemp))
|
||||
// iwf目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/iwf && sudo cp -rf /usr/local/etc/iwf/*.yaml %s/iwf", neDirTemp, neDirTemp))
|
||||
case "udm":
|
||||
// udm目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s && sudo cp -rf /usr/local/etc/udm/*.yaml %s", neDirTemp, neDirTemp))
|
||||
// kvdb目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/kvdb && sudo cp -rf /usr/local/etc/kvdb/*.{rdb,conf} %s/kvdb", neDirTemp, neDirTemp))
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/kvdb && sudo cp -rf /usr/local/etc/kvdb/log %s/kvdb", neDirTemp, neDirTemp))
|
||||
case "smsc":
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s && sudo cp -rf /usr/local/etc/smsc/{*.yaml,*.conf,*conf.txt} %s", neDirTemp, neDirTemp))
|
||||
cmd.Exec(fmt.Sprintf("sudo cp -rf /usr/local/etc/smsc/conf %s/conf", neDirTemp))
|
||||
default:
|
||||
nePath := fmt.Sprintf("/usr/local/etc/%s/*.yaml", neTypeLower)
|
||||
if neTypeLower == "amf" {
|
||||
nePath = fmt.Sprintf("/usr/local/etc/%s/*.{yaml,csv}", neTypeLower)
|
||||
}
|
||||
if neTypeLower == "mme" {
|
||||
nePath = fmt.Sprintf("/usr/local/etc/%s/*.{yaml,conf,csv}", neTypeLower)
|
||||
}
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s && sudo cp -rf %s %s", neDirTemp, nePath, neDirTemp))
|
||||
}
|
||||
|
||||
// 网元端复制到本地
|
||||
if err := file.CopyDir(neDirTemp, localDirPath); err != nil {
|
||||
return fmt.Errorf("copy config err")
|
||||
}
|
||||
cmd.Exec(fmt.Sprintf("sudo rm -rf %s", neDirTemp)) // 删除临时目录
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileLocalToNePath 网元备份文件本地路径复制到网元端
|
||||
func (s NeConfigBackup) FileLocalToNePath(neInfo model.NeInfo, localDirPath string) error {
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
|
||||
// 网元配置端上的临时目录
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/ne_config/%s/%s", neTypeLower, neInfo.NeId)
|
||||
// sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p /tmp/omc/ne_config && sudo chmod 777 -R /tmp/omc && sudo rm -rf %s", neDirTemp))
|
||||
cmd.Execf("sudo mkdir -p /tmp/omc/ne_config && sudo chmod 777 -R /tmp/omc && sudo rm -rf %s", neDirTemp)
|
||||
// 复制到网元端
|
||||
// if err = sftpClient.CopyDirLocalToRemote(localDirPath, neDirTemp); err != nil {
|
||||
// return fmt.Errorf("copy config to ne err")
|
||||
// }
|
||||
if err := file.CopyDir(localDirPath, neDirTemp); err != nil {
|
||||
cmd.Exec(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 777 -R /tmp/omc && sudo rm -rf %s", neDirTemp, neDirTemp))
|
||||
// 网元端复制到本地
|
||||
if err := file.CopyDir(neDirTemp, localDirPath); err != nil {
|
||||
return fmt.Errorf("copy config to ne err")
|
||||
}
|
||||
|
||||
@@ -122,85 +193,24 @@ func (s NeConfigBackup) FileLocalToNe(neInfo model.NeInfo, localFile string) err
|
||||
case "smsc":
|
||||
chmodFile := "sudo chmod 777 /usr/local/etc/smsc/{*sys.conf,*conf.txt,conf/is41_operation.conf}"
|
||||
cmd.Exec(fmt.Sprintf("sudo mkdir -p /usr/local/etc/smsc/conf && sudo cp -rf %s/* /usr/local/etc/smsc && %s", neDirTemp, chmodFile))
|
||||
case "udm":
|
||||
// udm目录
|
||||
chmodFile := "sudo chmod 777 /usr/local/etc/udm/*.yaml"
|
||||
cmd.Exec(fmt.Sprintf("sudo cp -rf %s/*.yaml /usr/local/etc/udm && %s", neDirTemp, chmodFile))
|
||||
// kvdb目录
|
||||
cmd.Exec(fmt.Sprintf("sudo mkdir -p /usr/local/etc/kvdb && sudo cp -rf %s/kvdb/* /usr/local/etc/kvdb && sudo chmod 777 /usr/local/etc/kvdb/*.{rdb,conf}", neDirTemp))
|
||||
default:
|
||||
neEtcPath := fmt.Sprintf("/usr/local/etc/%s", neTypeLower)
|
||||
chmodFile := fmt.Sprintf("sudo chmod 777 %s/*.yaml", neEtcPath)
|
||||
if neTypeLower == "mme" {
|
||||
chmodFile = fmt.Sprintf("sudo chmod 777 %s/*.{yaml,conf}", neEtcPath)
|
||||
if neTypeLower == "amf" {
|
||||
chmodFile = fmt.Sprintf("sudo chmod 777 %s/*.{yaml,csv}", neEtcPath)
|
||||
}
|
||||
cmd.Execf("sudo cp -rf %s/* %s && %s", neDirTemp, neEtcPath, chmodFile)
|
||||
if neTypeLower == "mme" {
|
||||
chmodFile = fmt.Sprintf("sudo chmod 777 %s/*.{yaml,conf,csv}", neEtcPath)
|
||||
}
|
||||
cmd.Exec(fmt.Sprintf("sudo cp -rf %s/* %s && %s", neDirTemp, neEtcPath, chmodFile))
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirPath) // 删除本地临时目录
|
||||
cmd.Execf("sudo rm -rf %s", neDirTemp) // 删除临时目录
|
||||
cmd.Exec(fmt.Sprintf("sudo rm -rf %s", neDirTemp)) // 删除临时目录
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileNeToLocal 网元备份文件网元端复制到本地
|
||||
func (s NeConfigBackup) FileNeToLocal(neInfo model.NeInfo) (string, error) {
|
||||
// 网元主机的SSH客户端
|
||||
// sshClient, err := NewNeInfo.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("ne info ssh client err")
|
||||
// }
|
||||
// defer sshClient.Close()
|
||||
// // 网元主机的SSH客户端进行文件传输
|
||||
// sftpClient, err := sshClient.NewClientSFTP()
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("ne info sftp client err")
|
||||
// }
|
||||
// defer sftpClient.Close()
|
||||
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 网管本地路径
|
||||
omcPath := "/usr/local/omc/backup/ne_config"
|
||||
if runtime.GOOS == "windows" {
|
||||
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||
}
|
||||
localDirPath := fmt.Sprintf("%s/%s/%s/from_ne_tmp", omcPath, neTypeLower, neInfo.NeId)
|
||||
|
||||
// 网元配置文件先复制到临时目录
|
||||
// sshClient.RunCMD("sudo mkdir -p /tmp/omc/ne_config && sudo chmod 777 -R /tmp/omc")
|
||||
cmd.Exec("sudo mkdir -p /tmp/omc/ne_config && sudo chmod 777 -R /tmp/omc")
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/ne_config/%s/%s", neTypeLower, neInfo.NeId)
|
||||
switch neTypeLower {
|
||||
case "ims":
|
||||
// ims目录
|
||||
cmd.Execf("mkdir -p %s/ims", neDirTemp)
|
||||
imsDirArr := [...]string{"bgcf", "icscf", "ismc", "mmtel", "mrf", "oam_manages.yaml", "pcscf", "scscf", "vars.cfg", "zlog"}
|
||||
for _, v := range imsDirArr {
|
||||
cmd.Execf("sudo cp -rf /usr/local/etc/ims/%s %s/ims", v, neDirTemp)
|
||||
}
|
||||
// mf目录
|
||||
cmd.Execf("mkdir -p %s/mf && sudo cp -rf /usr/local/etc/mf %s", neDirTemp, neDirTemp)
|
||||
// rtproxy目录
|
||||
cmd.Execf("mkdir -p %s/rtproxy && sudo cp -rf /usr/local/etc/rtproxy/rtproxy.conf %s/rtproxy", neDirTemp, neDirTemp)
|
||||
// iwf目录
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s/iwf && sudo cp -rf /usr/local/etc/iwf/*.yaml %s/iwf", neDirTemp, neDirTemp))
|
||||
case "smsc":
|
||||
cmd.Exec(fmt.Sprintf("mkdir -p %s && sudo cp -rf /usr/local/etc/smsc/{*.yaml,*.conf,*conf.txt} %s", neDirTemp, neDirTemp))
|
||||
cmd.Exec(fmt.Sprintf("sudo cp -rf /usr/local/etc/smsc/conf %s/conf", neDirTemp))
|
||||
default:
|
||||
nePath := fmt.Sprintf("/usr/local/etc/%s/*.yaml", neTypeLower)
|
||||
if neTypeLower == "mme" {
|
||||
nePath = fmt.Sprintf("/usr/local/etc/%s/*.{yaml,conf}", neTypeLower)
|
||||
}
|
||||
cmd.Execf("mkdir -p %s && sudo cp -rf %s %s", neDirTemp, nePath, neDirTemp)
|
||||
}
|
||||
|
||||
// 网元端复制到本地
|
||||
if err := file.CopyDir(neDirTemp, localDirPath); err != nil {
|
||||
return "", fmt.Errorf("copy config err")
|
||||
}
|
||||
|
||||
// 压缩zip文件名
|
||||
zipFileName := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, neInfo.NeId, date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS))
|
||||
zipFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neInfo.NeId, zipFileName)
|
||||
if err := file.CompressZipByDir(zipFilePath, localDirPath); err != nil {
|
||||
return "", fmt.Errorf("compress zip err")
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirPath) // 删除本地临时目录
|
||||
cmd.Execf("sudo rm -rf %s", neDirTemp) // 删除临时目录
|
||||
return zipFilePath, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/modules/ne_data/model"
|
||||
"be.ems/src/modules/ne_data/service"
|
||||
|
||||
@@ -99,3 +100,42 @@ func (s BackupController) FTPPush(c *gin.Context) {
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// 备份文件-导入OMC
|
||||
//
|
||||
// POST /import-omc
|
||||
func (s BackupController) ImportOMC(c *gin.Context) {
|
||||
var body struct {
|
||||
NeType string `json:"neType" binding:"required,oneof=OMC"`
|
||||
Path string `json:"path" binding:"required"` // 文件路径
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||
return
|
||||
}
|
||||
if !strings.HasSuffix(body.Path, ".zip") {
|
||||
c.JSON(200, resp.ErrMsg("Only supports decompression of zip files"))
|
||||
return
|
||||
}
|
||||
|
||||
// 将zip文件解压到本地后复制到网元端
|
||||
localFilePath := file.ParseUploadFileAbsPath(body.Path)
|
||||
if err := s.backupService.BackupOMCImport(localFilePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// 备份文件-导出OMC
|
||||
//
|
||||
// POST /export-omc
|
||||
func (s BackupController) ExportOMC(c *gin.Context) {
|
||||
zipFilePath, err := s.backupService.BackupOMCExport()
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.FileAttachment(zipFilePath, filepath.Base(zipFilePath))
|
||||
}
|
||||
|
||||
@@ -49,10 +49,12 @@ type AMFController struct {
|
||||
func (s *AMFController) UEList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -119,10 +121,12 @@ func (s *AMFController) UERemove(c *gin.Context) {
|
||||
func (s *AMFController) UEExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
|
||||
@@ -17,16 +17,18 @@ import (
|
||||
|
||||
// 实例化控制层 IMSController 结构体
|
||||
var NewIMS = &IMSController{
|
||||
neInfoService: neService.NewNeInfo,
|
||||
cdrEventService: neDataService.NewCDREvent,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
cdrEventService: neDataService.NewCDREvent,
|
||||
kpiReportService: neDataService.NewKpiReport,
|
||||
}
|
||||
|
||||
// 网元IMS
|
||||
//
|
||||
// PATH /ims
|
||||
type IMSController struct {
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
cdrEventService *neDataService.CDREvent // CDR会话事件服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
cdrEventService *neDataService.CDREvent // CDR会话事件服务
|
||||
kpiReportService *neDataService.KpiReport // 统计信息服务
|
||||
}
|
||||
|
||||
// CDR会话列表
|
||||
@@ -50,10 +52,12 @@ type IMSController struct {
|
||||
func (s *IMSController) CDRList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -120,10 +124,12 @@ func (s *IMSController) CDRRemove(c *gin.Context) {
|
||||
func (s *IMSController) CDRExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -236,3 +242,101 @@ func (s *IMSController) UeSessionList(c *gin.Context) {
|
||||
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// KPI 忙时统计
|
||||
//
|
||||
// GET /kpi/busy-hour
|
||||
//
|
||||
// @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 hour statistics
|
||||
// @Description Busy hour statistics
|
||||
// @Router /neData/ims/kpi/busy-hour [get]
|
||||
func (s IMSController) KPIBusyHour(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var query struct {
|
||||
NeID string `form:"neId" binding:"required"`
|
||||
Timestamp int64 `form:"timestamp" 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.Timestamp < 1e12 || query.Timestamp > 1e13 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "timestamp format is ms"))
|
||||
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.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))
|
||||
}
|
||||
|
||||
@@ -49,10 +49,12 @@ type MMEController struct {
|
||||
func (s *MMEController) UEList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -119,10 +121,12 @@ func (s *MMEController) UERemove(c *gin.Context) {
|
||||
func (s *MMEController) UEExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
|
||||
@@ -50,10 +50,12 @@ type SGWCController struct {
|
||||
func (s *SGWCController) CDRList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -120,10 +122,12 @@ func (s *SGWCController) CDRRemove(c *gin.Context) {
|
||||
func (s *SGWCController) CDRExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
|
||||
@@ -52,10 +52,12 @@ type SMFController struct {
|
||||
func (s *SMFController) CDRList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -122,10 +124,12 @@ func (s *SMFController) CDRRemove(c *gin.Context) {
|
||||
func (s *SMFController) CDRExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
|
||||
@@ -49,10 +49,12 @@ type SMSCController struct {
|
||||
func (s *SMSCController) CDRList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
@@ -119,10 +121,12 @@ func (s *SMSCController) CDRRemove(c *gin.Context) {
|
||||
func (s *SMSCController) CDRExport(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
query := reqctx.QueryMap(c)
|
||||
// 限制导出数据集
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageSize > 10000 {
|
||||
query["pageSize"] = "10000"
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
|
||||
@@ -184,6 +184,14 @@ func Setup(router *gin.Engine) {
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.UeSessionList,
|
||||
)
|
||||
imsGroup.GET("/kpi/busy-hour",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.KPIBusyHour,
|
||||
)
|
||||
imsGroup.GET("/kpi/busy-week",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.KPIBusyWeek,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元SMSC
|
||||
@@ -308,6 +316,16 @@ func Setup(router *gin.Engine) {
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_OTHER)),
|
||||
controller.NewBackup.FTPPush,
|
||||
)
|
||||
backupGroup.POST("/import-omc",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
controller.NewBackup.ImportOMC,
|
||||
)
|
||||
backupGroup.POST("/export-omc",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewBackup.ExportOMC,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元UDM 鉴权用户信息
|
||||
|
||||
@@ -91,11 +91,10 @@ func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model.
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
if pageNum == 0 && pageSize > int(total) {
|
||||
pageSize = int(total)
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
}
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
|
||||
@@ -115,7 +115,24 @@ func (r KpiReport) SelectUPF(rmUID string, beginTime, endTime int64) []model.Kpi
|
||||
tx = tx.Where("created_at <= ?", endTime)
|
||||
// 查询数据
|
||||
rows := []model.KpiReport{}
|
||||
if err := tx.Select("kpi_values").Find(&rows).Error; err != nil {
|
||||
if err := tx.Select("kpi_values", "created_at").Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// SelectIMS 查询IMS数据
|
||||
func (r KpiReport) SelectIMS(rmUID string, beginTime, endTime int64) []model.KpiReport {
|
||||
tx := db.DB("").Model(&model.KpiReport{})
|
||||
// 表名
|
||||
tx = tx.Table("kpi_report_ims")
|
||||
tx = tx.Where("rm_uid = ?", rmUID)
|
||||
tx = tx.Where("created_at >= ?", beginTime)
|
||||
tx = tx.Where("created_at <= ?", endTime)
|
||||
// 查询数据
|
||||
rows := []model.KpiReport{}
|
||||
if err := tx.Select("kpi_values", "created_at").Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -56,8 +56,10 @@ func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.U
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
|
||||
@@ -3,10 +3,17 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/cmd"
|
||||
"be.ems/src/framework/ssh"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neModel "be.ems/src/modules/ne/model"
|
||||
neService "be.ems/src/modules/ne/service"
|
||||
"be.ems/src/modules/ne_data/model"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
@@ -15,14 +22,12 @@ import (
|
||||
// 实例化数据层 Backup 结构体
|
||||
var NewBackup = &Backup{
|
||||
BACKUP_DIR: "/usr/local/omc/backup",
|
||||
neInfoService: neService.NewNeInfo,
|
||||
sysConfigService: systemService.NewSysConfig,
|
||||
}
|
||||
|
||||
// Backup 备份相关 服务层处理
|
||||
type Backup struct {
|
||||
BACKUP_DIR string // 备份目录
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
sysConfigService *systemService.SysConfig // 参数配置服务
|
||||
}
|
||||
|
||||
@@ -84,3 +89,194 @@ func (r Backup) FTPPushFile(localFilePath, tag string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BackupOMCImport 网元配置文件复制到网元端覆盖
|
||||
func (r Backup) BackupOMCImport(localZipFile string) error {
|
||||
neInfoService := neService.NewNeInfo
|
||||
neVersionService := neService.NewNeVersion
|
||||
neLicenseService := neService.NewNeLicense
|
||||
neConfigBackupService := neService.NewNeConfigBackup
|
||||
|
||||
// 网管本地路径
|
||||
omcPath := "/usr/local/omc/backup_omc"
|
||||
if runtime.GOOS == "windows" {
|
||||
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||
}
|
||||
// 解压到临时目录
|
||||
omcPathTmp := fmt.Sprintf("%s/import", omcPath)
|
||||
if err := file.UnZip(localZipFile, omcPathTmp); err != nil {
|
||||
return fmt.Errorf("unzip err")
|
||||
}
|
||||
defer os.RemoveAll(omcPathTmp) // 删除本地临时目录
|
||||
|
||||
// 还原OMC-网元信息
|
||||
neInfos := make([]neModel.NeInfo, 0) // 网元信息列表
|
||||
neVersions := make([]neModel.NeVersion, 0) // 网元版本列表
|
||||
neLicenses := make([]neModel.NeLicense, 0) // 网元许可证列表
|
||||
neHosts := make([]neModel.NeHost, 0) // 网元主机列表
|
||||
localDirPath := fmt.Sprintf("%s/omc/db", omcPathTmp)
|
||||
neInfoStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_info.json", localDirPath))
|
||||
for _, str := range neInfoStrArr {
|
||||
var neInfo neModel.NeInfo
|
||||
if err := json.Unmarshal([]byte(str), &neInfo); err != nil {
|
||||
continue
|
||||
}
|
||||
neInfos = append(neInfos, neInfo)
|
||||
}
|
||||
neVersionStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_version.json", localDirPath))
|
||||
for _, str := range neVersionStrArr {
|
||||
var neVersion neModel.NeVersion
|
||||
if err := json.Unmarshal([]byte(str), &neVersion); err != nil {
|
||||
continue
|
||||
}
|
||||
neVersions = append(neVersions, neVersion)
|
||||
}
|
||||
neLicenseStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_license.json", localDirPath))
|
||||
for _, str := range neLicenseStrArr {
|
||||
var neLicense neModel.NeLicense
|
||||
if err := json.Unmarshal([]byte(str), &neLicense); err != nil {
|
||||
continue
|
||||
}
|
||||
neLicenses = append(neLicenses, neLicense)
|
||||
}
|
||||
neHostStrArr := file.ReadFileJSONLine(fmt.Sprintf("%s/ne_host.json", localDirPath))
|
||||
for _, str := range neHostStrArr {
|
||||
var neHost neModel.NeHost
|
||||
if err := json.Unmarshal([]byte(str), &neHost); err != nil {
|
||||
continue
|
||||
}
|
||||
neHosts = append(neHosts, neHost)
|
||||
}
|
||||
// 新增网元信息
|
||||
for _, neInfo := range neInfos {
|
||||
if neInfo.NeId == "" || neInfo.NeType == "OMC" {
|
||||
continue
|
||||
}
|
||||
// 删除网元信息
|
||||
neInfoService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||||
if neInfo.ID > 0 {
|
||||
neInfoService.DeleteByIds([]int64{neInfo.ID})
|
||||
}
|
||||
|
||||
neVersion := neModel.NeVersion{}
|
||||
for _, v := range neVersions {
|
||||
if v.NeId == neInfo.NeId && v.NeType == neInfo.NeType {
|
||||
v.ID = 0
|
||||
neVersion = v
|
||||
break
|
||||
}
|
||||
}
|
||||
neLicense := neModel.NeLicense{}
|
||||
for _, v := range neLicenses {
|
||||
if v.NeId == neInfo.NeId && v.NeType == neInfo.NeType {
|
||||
v.ID = 0
|
||||
neLicense = v
|
||||
break
|
||||
}
|
||||
}
|
||||
neHostArr := make([]neModel.NeHost, 0) // 网元主机列表
|
||||
neHostIDs := strings.Split(neInfo.HostIDs, ",")
|
||||
for _, hostID := range neHostIDs {
|
||||
hostIDNum := parse.Number(hostID)
|
||||
for _, v := range neHosts {
|
||||
if v.ID == hostIDNum {
|
||||
v.ID = 0
|
||||
neHostArr = append(neHostArr, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
neVersionService.Insert(neVersion)
|
||||
neLicenseService.Insert(neLicense)
|
||||
neInfo.Hosts = neHostArr
|
||||
neInfo.CreateBy = "system"
|
||||
neInfoService.Insert(neInfo)
|
||||
}
|
||||
|
||||
// 还原网元备份文件
|
||||
neList := neInfoService.Find(neModel.NeInfo{}, false, false)
|
||||
for _, neInfo := range neList {
|
||||
if neInfo.NeType == "OMC" {
|
||||
continue
|
||||
}
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 配置文件-本地复制到网元端
|
||||
localDirPath := fmt.Sprintf("%s/ne_config/%s/%s", omcPathTmp, neTypeLower, neInfo.NeId)
|
||||
if err := neConfigBackupService.FileLocalToNePath(neInfo, localDirPath); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BackupOMCExport 备份OMC数据导出
|
||||
func (r Backup) BackupOMCExport() (string, error) {
|
||||
neInfoService := neService.NewNeInfo
|
||||
neVersionService := neService.NewNeVersion
|
||||
neLicenseService := neService.NewNeLicense
|
||||
neHostService := neService.NewNeHost
|
||||
neConfigBackupService := neService.NewNeConfigBackup
|
||||
|
||||
// 网管本地路径
|
||||
omcPath := "/usr/local/omc/backup_omc"
|
||||
if runtime.GOOS == "windows" {
|
||||
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||
}
|
||||
omcPathTmp := fmt.Sprintf("%s/tmp", omcPath)
|
||||
defer os.RemoveAll(omcPathTmp) // 删除本地临时目录
|
||||
|
||||
// 备份网元配置文件
|
||||
neList := neInfoService.Find(neModel.NeInfo{}, false, false)
|
||||
for _, neInfo := range neList {
|
||||
if neInfo.NeType == "OMC" {
|
||||
continue
|
||||
}
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 配置文件-网元端复制到本地
|
||||
localDirPath := fmt.Sprintf("%s/ne_config/%s/%s", omcPathTmp, neTypeLower, neInfo.NeId)
|
||||
cmd.Execf("sudo mkdir -p %s", localDirPath)
|
||||
if err := neConfigBackupService.FileNeToLocalPath(neInfo, localDirPath); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 备份OMC
|
||||
neInfos := make([]any, 0) // 网元信息列表
|
||||
neVersions := make([]any, 0) // 网元版本列表
|
||||
neLicenses := make([]any, 0) // 网元许可证列表
|
||||
neHosts := make([]any, 0) // 网元主机列表
|
||||
for _, neInfo := range neList {
|
||||
neVersion := neVersionService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||||
if neVersion.ID > 0 {
|
||||
neVersions = append(neVersions, neVersion)
|
||||
}
|
||||
neLicense := neLicenseService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||||
if neLicense.ID > 0 {
|
||||
neLicenses = append(neLicenses, neLicense)
|
||||
}
|
||||
neHostIDs := strings.Split(neInfo.HostIDs, ",")
|
||||
for _, hostID := range neHostIDs {
|
||||
neHost := neHostService.FindById(parse.Number(hostID))
|
||||
if neHost.ID > 0 {
|
||||
neHosts = append(neHosts, neHost)
|
||||
}
|
||||
}
|
||||
neInfos = append(neInfos, neInfo)
|
||||
}
|
||||
localDirPath := fmt.Sprintf("%s/omc/db", omcPathTmp)
|
||||
cmd.Execf("sudo mkdir -p %s", localDirPath)
|
||||
file.WriterFileJSONLine(neInfos, fmt.Sprintf("%s/ne_info.json", localDirPath))
|
||||
file.WriterFileJSONLine(neVersions, fmt.Sprintf("%s/ne_version.json", localDirPath))
|
||||
file.WriterFileJSONLine(neLicenses, fmt.Sprintf("%s/ne_license.json", localDirPath))
|
||||
file.WriterFileJSONLine(neHosts, fmt.Sprintf("%s/ne_host.json", localDirPath))
|
||||
|
||||
// 压缩zip文件名
|
||||
zipFileName := fmt.Sprintf("BackupOMC-%s.zip", time.Now().Format("20060102150405"))
|
||||
zipFilePath := fmt.Sprintf("%s/%s", omcPath, zipFileName)
|
||||
if err := file.CompressZipByDir(zipFilePath, omcPathTmp); err != nil {
|
||||
return "", fmt.Errorf("compress zip err")
|
||||
}
|
||||
|
||||
return zipFilePath, nil
|
||||
}
|
||||
|
||||
@@ -280,3 +280,222 @@ func (r KpiReport) UPFTodayFlowLoad(day int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IMSBusyHour IMS忙时流量统计
|
||||
// SCSCF.06呼叫尝试次数 SCSCF.09呼叫成功次数
|
||||
func (r KpiReport) IMSBusyHour(rmUID string, timestamp int64) []map[string]any {
|
||||
t := time.UnixMilli(timestamp)
|
||||
beginTime := t
|
||||
endTime := t
|
||||
// 检查时分秒是否都为零
|
||||
if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 {
|
||||
// 获取当天起始时间(00:00:00)
|
||||
beginTime = t.Truncate(time.Hour)
|
||||
// 计算当天结束时间(23:59:59)
|
||||
endTime = beginTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||
} else {
|
||||
// 起始时间:当前小时的 00 分 00 秒
|
||||
beginTime = t.Truncate(time.Hour)
|
||||
// 结束时间:当前小时的 59 分 59 秒 999 毫秒
|
||||
endTime = beginTime.Add(time.Hour - time.Millisecond)
|
||||
}
|
||||
// 转换为毫秒级时间戳
|
||||
rows := r.kpiReportRepository.SelectIMS(rmUID, beginTime.UnixMilli(), endTime.UnixMilli())
|
||||
|
||||
// 创建一个map来存储按时间段合并后的数据
|
||||
timeGroup := make(map[int64]map[string]int64)
|
||||
// 遍历每个数据项
|
||||
for _, row := range rows {
|
||||
// 将毫秒时间戳转换为小时级时间戳(保留到小时的起始毫秒)
|
||||
timeHour := row.CreatedAt / 3600000 * 3600000 // 1小时 = 3600000毫秒
|
||||
|
||||
// 解析 JSON 字符串为 map
|
||||
var kpiValues []map[string]any
|
||||
err := json.Unmarshal([]byte(row.KpiValues), &kpiValues)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var callAttempts, callCompletions int64
|
||||
for _, v := range kpiValues {
|
||||
if k, ok := v["kpiId"]; ok {
|
||||
if k == "SCSCF.06" {
|
||||
callAttempts = parse.Number(v["value"])
|
||||
}
|
||||
if k == "SCSCF.09" {
|
||||
callCompletions = parse.Number(v["value"])
|
||||
}
|
||||
}
|
||||
}
|
||||
// 合并到对应的小时段
|
||||
if _, exists := timeGroup[timeHour]; !exists {
|
||||
timeGroup[timeHour] = map[string]int64{
|
||||
"callAttempts": 0,
|
||||
"callCompletions": 0,
|
||||
}
|
||||
}
|
||||
timeGroup[timeHour]["callAttempts"] += callAttempts
|
||||
timeGroup[timeHour]["callCompletions"] += callCompletions
|
||||
}
|
||||
|
||||
// 时间组合输出
|
||||
data := make([]map[string]any, 0, len(timeGroup))
|
||||
for hour, sums := range timeGroup {
|
||||
data = append(data, map[string]any{
|
||||
"timeGroup": fmt.Sprintf("%d", hour),
|
||||
"callAttempts": sums["callAttempts"],
|
||||
"callCompletions": sums["callCompletions"],
|
||||
})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 定义结构体用于存储话务量值和对应的时间
|
||||
type TrafficData struct {
|
||||
Time int64 `json:"time"` // 时间戳(毫秒)
|
||||
Value float64 `json:"value"` // 话务量值
|
||||
}
|
||||
|
||||
// IMSBusyWeek IMS忙时流量统计 周
|
||||
func (r KpiReport) IMSBusyWeek(rmUID string, weekStart, weekEnd int64) map[string]any {
|
||||
weekStartTime := time.UnixMilli(weekStart)
|
||||
weekEndTime := time.UnixMilli(weekEnd)
|
||||
|
||||
// 1. 获取一周内每小时的呼叫数据
|
||||
// 转换为毫秒级时间戳
|
||||
rows := r.kpiReportRepository.SelectIMS(rmUID, weekStartTime.UnixMilli(), weekEndTime.UnixMilli())
|
||||
|
||||
// 创建一个map来存储按时间段合并后的数据
|
||||
timeGroup := make(map[int64]map[string]int64)
|
||||
// 遍历每个数据项
|
||||
for _, row := range rows {
|
||||
// 将毫秒时间戳转换为小时级时间戳(保留到小时的起始毫秒)
|
||||
timeHour := row.CreatedAt / 3600000 * 3600000 // 1小时 = 3600000毫秒
|
||||
|
||||
// 解析 JSON 字符串为 map
|
||||
var kpiValues []map[string]any
|
||||
err := json.Unmarshal([]byte(row.KpiValues), &kpiValues)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var callAttempts, callCompletions int64
|
||||
for _, v := range kpiValues {
|
||||
if k, ok := v["kpiId"]; ok {
|
||||
if k == "SCSCF.06" {
|
||||
callAttempts = parse.Number(v["value"])
|
||||
}
|
||||
if k == "SCSCF.09" {
|
||||
callCompletions = parse.Number(v["value"])
|
||||
}
|
||||
}
|
||||
}
|
||||
// 合并到对应的小时段
|
||||
if _, exists := timeGroup[timeHour]; !exists {
|
||||
timeGroup[timeHour] = map[string]int64{
|
||||
"callAttempts": 0,
|
||||
"callCompletions": 0,
|
||||
}
|
||||
}
|
||||
timeGroup[timeHour]["callAttempts"] += callAttempts
|
||||
timeGroup[timeHour]["callCompletions"] += callCompletions
|
||||
}
|
||||
|
||||
// 时间组合输出
|
||||
data := make([]map[string]any, 0, len(timeGroup))
|
||||
for hour, sums := range timeGroup {
|
||||
data = append(data, map[string]any{
|
||||
"timeGroup": fmt.Sprintf("%d", hour),
|
||||
"callAttempts": sums["callAttempts"],
|
||||
"callCompletions": sums["callCompletions"],
|
||||
})
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
authService "be.ems/src/modules/auth/service"
|
||||
"be.ems/src/modules/system/model"
|
||||
"be.ems/src/modules/system/service"
|
||||
@@ -48,6 +49,13 @@ type SysLogLoginController struct {
|
||||
// @Router /system/log/login/list [get]
|
||||
func (s *SysLogLoginController) List(c *gin.Context) {
|
||||
query := reqctx.QueryMap(c)
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
dataScopeSQL := reqctx.LoginUserToDataScopeSQL(c, "sys_user", "sys_user")
|
||||
rows, total := s.sysLogLoginService.FindByPage(query, dataScopeSQL)
|
||||
|
||||
@@ -99,6 +107,13 @@ func (s SysLogLoginController) Export(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
query := reqctx.QueryMap(c)
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
dataScopeSQL := reqctx.LoginUserToDataScopeSQL(c, "sys_user", "sys_user")
|
||||
rows, total := s.sysLogLoginService.FindByPage(query, dataScopeSQL)
|
||||
if total == 0 {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/system/model"
|
||||
"be.ems/src/modules/system/service"
|
||||
|
||||
@@ -50,6 +51,13 @@ func (s *SysLogOperateController) List(c *gin.Context) {
|
||||
if v, ok := query["title"]; ok && v != "" {
|
||||
query["title"] = i18n.TFindKeyPrefix(language, "log.operate.title", v)
|
||||
}
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
dataScopeSQL := reqctx.LoginUserToDataScopeSQL(c, "sys_user", "sys_user")
|
||||
rows, total := s.sysLogOperateService.FindByPage(query, dataScopeSQL)
|
||||
@@ -81,6 +89,13 @@ func (s SysLogOperateController) Export(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
query := reqctx.QueryMap(c)
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: pageNum or pageSize not is empty"))
|
||||
return
|
||||
}
|
||||
dataScopeSQL := reqctx.LoginUserToDataScopeSQL(c, "sys_user", "sys_user")
|
||||
rows, total := s.sysLogOperateService.FindByPage(query, dataScopeSQL)
|
||||
if total == 0 {
|
||||
|
||||
@@ -29,20 +29,10 @@ func (r SysLogLogin) SelectByPage(query map[string]string, dataScopeSQL string)
|
||||
tx = tx.Where("status_flag = ?", v)
|
||||
}
|
||||
if v, ok := query["beginTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s000", v)
|
||||
tx = tx.Where("login_time >= ?", v)
|
||||
} else if len(v) == 13 {
|
||||
tx = tx.Where("login_time >= ?", v)
|
||||
}
|
||||
tx = tx.Where("login_time >= ?", v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s999", v)
|
||||
tx = tx.Where("login_time <= ?", v)
|
||||
} else if len(v) == 13 {
|
||||
tx = tx.Where("login_time <= ?", v)
|
||||
}
|
||||
tx = tx.Where("login_time <= ?", v)
|
||||
}
|
||||
if dataScopeSQL != "" {
|
||||
dataScopeSQL = fmt.Sprintf("select distinct user_name from sys_user where %s", dataScopeSQL)
|
||||
@@ -59,8 +49,11 @@ func (r SysLogLogin) SelectByPage(query map[string]string, dataScopeSQL string)
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
}
|
||||
|
||||
err := tx.Order("id desc").Find(&rows).Error
|
||||
if err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
|
||||
@@ -35,20 +35,10 @@ func (r SysLogOperate) SelectByPage(query map[string]string, dataScopeSQL string
|
||||
tx = tx.Where("status_flag = ?", v)
|
||||
}
|
||||
if v, ok := query["beginTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s000", v)
|
||||
tx = tx.Where("opera_time >= ?", v)
|
||||
} else if len(v) == 13 {
|
||||
tx = tx.Where("opera_time >= ?", v)
|
||||
}
|
||||
tx = tx.Where("opera_time <= ?", v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
if len(v) == 10 {
|
||||
v = fmt.Sprintf("%s999", v)
|
||||
tx = tx.Where("opera_time <= ?", v)
|
||||
} else if len(v) == 13 {
|
||||
tx = tx.Where("opera_time <= ?", v)
|
||||
}
|
||||
tx = tx.Where("opera_time <= ?", v)
|
||||
}
|
||||
if dataScopeSQL != "" {
|
||||
dataScopeSQL = fmt.Sprintf("select distinct user_name from sys_user where %s", dataScopeSQL)
|
||||
@@ -65,8 +55,11 @@ func (r SysLogOperate) SelectByPage(query map[string]string, dataScopeSQL string
|
||||
}
|
||||
|
||||
// 查询数据分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
if query["pageNum"] != "" && query["pageSize"] != "" {
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
|
||||
}
|
||||
|
||||
err := tx.Order("id desc").Find(&rows).Error
|
||||
if err != nil {
|
||||
logger.Errorf("query find err => %v", err.Error())
|
||||
|
||||
@@ -167,7 +167,7 @@ func (r SysMenu) CheckUnique(sysMenu model.SysMenu) int64 {
|
||||
tx := db.DB("").Model(&model.SysMenu{})
|
||||
tx = tx.Where("del_flag = '0'")
|
||||
// 查询条件拼接
|
||||
if sysMenu.ParentId <= 0 {
|
||||
if sysMenu.ParentId >= 0 {
|
||||
tx = tx.Where("parent_id = ?", sysMenu.ParentId)
|
||||
}
|
||||
if sysMenu.MenuName != "" {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neInfoService "be.ems/src/modules/ne/service"
|
||||
neDataService "be.ems/src/modules/ne_data/service"
|
||||
)
|
||||
@@ -21,7 +22,12 @@ func GetCDRConnect(requestID string, data any) ([]byte, error) {
|
||||
for k, v := range dataMap {
|
||||
query[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
// 分页检查
|
||||
pageNum := parse.Number(query["pageNum"])
|
||||
pageSize := parse.Number(query["pageSize"])
|
||||
if pageNum == 0 || pageSize == 0 {
|
||||
return nil, fmt.Errorf("pageNum or pageSize not is empty")
|
||||
}
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query["neType"], query["neId"])
|
||||
if neInfo.NeType == "" {
|
||||
|
||||
Reference in New Issue
Block a user