From adb0d5f4e28f9ff01314b597301d6bebd06732c4 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 15 Jul 2025 14:51:16 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E9=87=8D=E6=9E=84=E6=8E=A5=E6=94=B6CDR?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backup_export_cdr/backup_export_cdr.go | 99 ++- src/modules/network_data/controller/ims.go | 57 +- src/modules/network_data/controller/sgwc.go | 55 +- src/modules/network_data/controller/smf.go | 61 +- src/modules/network_data/controller/smsc.go | 57 +- src/modules/network_data/model/cdr_event.go | 17 + .../network_data/model/cdr_event_ims.go | 33 - .../network_data/model/cdr_event_sgwc.go | 32 - .../network_data/model/cdr_event_smf.go | 33 - .../network_data/model/cdr_event_smsc.go | 33 - .../network_data/repository/cdr_event.go | 167 +++++ .../network_data/repository/cdr_event_ims.go | 107 --- .../network_data/repository/cdr_event_sgwc.go | 95 --- .../network_data/repository/cdr_event_smf.go | 98 --- .../network_data/repository/cdr_event_smsc.go | 107 --- src/modules/network_data/service/cdr_event.go | 645 ++++++++++++++++++ .../network_data/service/cdr_event_ims.go | 173 ----- .../network_data/service/cdr_event_sgwc.go | 235 ------- .../network_data/service/cdr_event_smf.go | 230 ------- .../network_data/service/cdr_event_smsc.go | 137 ---- src/modules/oam/service/cdr.go | 73 ++ src/modules/ws/processor/cdr_connect.go | 78 +-- 22 files changed, 1059 insertions(+), 1563 deletions(-) create mode 100644 src/modules/network_data/model/cdr_event.go delete mode 100644 src/modules/network_data/model/cdr_event_ims.go delete mode 100644 src/modules/network_data/model/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/model/cdr_event_smf.go delete mode 100644 src/modules/network_data/model/cdr_event_smsc.go create mode 100644 src/modules/network_data/repository/cdr_event.go delete mode 100644 src/modules/network_data/repository/cdr_event_ims.go delete mode 100644 src/modules/network_data/repository/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/repository/cdr_event_smf.go delete mode 100644 src/modules/network_data/repository/cdr_event_smsc.go create mode 100644 src/modules/network_data/service/cdr_event.go delete mode 100644 src/modules/network_data/service/cdr_event_ims.go delete mode 100644 src/modules/network_data/service/cdr_event_sgwc.go delete mode 100644 src/modules/network_data/service/cdr_event_smf.go delete mode 100644 src/modules/network_data/service/cdr_event_smsc.go create mode 100644 src/modules/oam/service/cdr.go diff --git a/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go index c04b6781..755e1d6f 100644 --- a/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go +++ b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go @@ -15,7 +15,6 @@ import ( "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" @@ -23,26 +22,20 @@ import ( ) var NewProcessor = &BackupExportCDRProcessor{ - count: 0, - backupService: neDataService.NewBackup, - sysDictService: systemService.NewSysDictData, - neInfoService: neService.NewNeInfo, - imsCDREventService: neDataService.NewCDREventIMS, - smscCDREventService: neDataService.NewCDREventSMSC, - smfCDREventService: neDataService.NewCDREventSMF, - sgwcCDREventService: neDataService.NewCDREventSGWC, + count: 0, + backupService: neDataService.NewBackup, + sysDictService: systemService.NewSysDictData, + neInfoService: neService.NewNeInfo, + cdrEventService: neDataService.NewCDREvent, } // BackupExportCDR 队列任务处理 type BackupExportCDRProcessor struct { - count int // 执行次数 - backupService *neDataService.Backup // 备份相关服务 - sysDictService *systemService.SysDictData // 字典类型数据服务 - neInfoService *neService.NeInfo // 网元信息服务 - imsCDREventService *neDataService.CDREventIMS // IMS-CDR会话事件服务 - smscCDREventService *neDataService.CDREventSMSC // SMSC-CDR会话事件服务 - smfCDREventService *neDataService.CDREventSMF // SMF-CDR会话事件服务 - sgwcCDREventService *neDataService.CDREventSGWC // SGWC-CDR会话事件服务 + count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + sysDictService *systemService.SysDictData // 字典类型数据服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } func (s *BackupExportCDRProcessor) Execute(data any) (any, error) { @@ -104,16 +97,16 @@ func (s BackupExportCDRProcessor) exportIMS(hour int, rmUID, fileType string) st start := end.Add(-time.Duration(hour) * time.Hour) language := "en" - query := neDataModel.CDREventIMSQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + 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.imsCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("IMS", query) if total == 0 { return "no data" } @@ -393,16 +386,16 @@ func (s BackupExportCDRProcessor) exportSMSC(hour int, rmUID, fileType string) s start := end.Add(-time.Duration(hour) * time.Hour) language := "en" - query := neDataModel.CDREventSMSCQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + 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.smscCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SMSC", query) if total == 0 { return "no data" } @@ -609,16 +602,16 @@ func (s BackupExportCDRProcessor) exportSMF(hour int, rmUID, fileType string) st 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 := neDataModel.CDREventSMFQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + 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.smfCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SMF", query) if total == 0 { return "no data" } @@ -1017,16 +1010,16 @@ func (s BackupExportCDRProcessor) exportSGWC(hour int, rmUID, fileType string) s 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 := neDataModel.CDREventSGWCQuery{ - SortField: "timestamp", - SortOrder: "asc", - RmUID: rmUID, - BeginTime: start.UnixMilli(), - EndTime: end.UnixMilli(), - PageNum: 1, - PageSize: 30000, + 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.sgwcCDREventService.FindByPage(query) + rows, total := s.cdrEventService.FindByPage("SGWC", query) if total == 0 { return "no data" } diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 08861dd2..c4ca4431 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -19,15 +18,15 @@ import ( // 实例化控制层 IMSController 结构体 var NewIMS = &IMSController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventIMS, + cdrEventService: neDataService.NewCDREvent, } // 网元IMS // // PATH /ims type IMSController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventIMS // CDR会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } // CDR会话列表 @@ -50,23 +49,20 @@ type IMSController struct { // @Router /neData/ims/cdr/list [get] func (s *IMSController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventIMSQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -99,7 +95,7 @@ func (s *IMSController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("IMS", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -110,7 +106,7 @@ func (s *IMSController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/ims // @Accept json @@ -120,28 +116,23 @@ func (s *IMSController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/ims/cdr/export [post] +// @Router /neData/ims/cdr/export [get] func (s *IMSController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventIMSQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -151,7 +142,7 @@ func (s *IMSController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.cdrEventService.ExportIMS(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/controller/sgwc.go b/src/modules/network_data/controller/sgwc.go index 8c72f621..ea7589ec 100644 --- a/src/modules/network_data/controller/sgwc.go +++ b/src/modules/network_data/controller/sgwc.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -17,7 +16,7 @@ import ( // 实例化控制层 SGWCController 结构体 var NewSGWC = &SGWCController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSGWC, + cdrEventService: neDataService.NewCDREvent, UDMExtendService: neDataService.NewUDMExtend, } @@ -25,9 +24,9 @@ var NewSGWC = &SGWCController{ // // PATH /sgwc type SGWCController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSGWC // CDR会话事件服务 - UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 + UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 } // CDR会话列表 @@ -50,23 +49,20 @@ type SGWCController struct { // @Router /neData/sgwc/cdr/list [get] func (s *SGWCController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSGWCQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -99,7 +95,7 @@ func (s *SGWCController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SGWC", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -123,25 +119,20 @@ func (s *SGWCController) CDRRemove(c *gin.Context) { // @Router /neData/sgwc/cdr/export [post] func (s *SGWCController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSGWCQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -151,7 +142,7 @@ func (s *SGWCController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) + saveFilePath, err := s.cdrEventService.ExportSGWC(rows, fileName) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index 9e382bff..e1e77d9b 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -9,7 +9,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" @@ -20,7 +19,7 @@ import ( // 实例化控制层 SMFController 结构体 var NewSMF = &SMFController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSMF, + cdrEventService: neDataService.NewCDREvent, UDMExtendService: neDataService.NewUDMExtend, } @@ -28,9 +27,9 @@ var NewSMF = &SMFController{ // // PATH /smf type SMFController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSMF // CDR会话事件服务 - UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 + UDMExtendService *neDataService.UDMExtend // UDM用户信息服务 } // CDR会话列表 @@ -52,23 +51,20 @@ type SMFController struct { // @Router /neData/smf/cdr/list [get] func (s *SMFController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSMFQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -101,7 +97,7 @@ func (s *SMFController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SMF", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -112,7 +108,7 @@ func (s *SMFController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/smf // @Accept json @@ -122,28 +118,23 @@ func (s *SMFController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/smf/cdr/export [post] +// @Router /neData/smf/cdr/export [get] func (s *SMFController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSMFQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -153,7 +144,7 @@ func (s *SMFController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) + saveFilePath, err := s.cdrEventService.ExportSMF(rows, fileName) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return @@ -219,7 +210,7 @@ func (s *SMFController) SubUserNum(c *gin.Context) { // @Security TokenAuth // @Summary Online session user list information // @Description Online session user list information -// @Router /neData/smf/session/list [get] +// @Router /neData/smf/sub/list [get] func (s *SMFController) SubUserList(c *gin.Context) { language := reqctx.AcceptLanguage(c) var query struct { diff --git a/src/modules/network_data/controller/smsc.go b/src/modules/network_data/controller/smsc.go index fc9420e0..f3efc33e 100644 --- a/src/modules/network_data/controller/smsc.go +++ b/src/modules/network_data/controller/smsc.go @@ -8,7 +8,6 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" @@ -18,15 +17,15 @@ import ( // 实例化控制层 SMSCController 结构体 var NewSMSC = &SMSCController{ neInfoService: neService.NewNeInfo, - cdrEventService: neDataService.NewCDREventSMSC, + cdrEventService: neDataService.NewCDREvent, } // 网元SMSC // // PATH /smsc type SMSCController struct { - neInfoService *neService.NeInfo // 网元信息服务 - cdrEventService *neDataService.CDREventSMSC // CDR会话事件服务 + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREvent // CDR会话事件服务 } // CDR会话列表 @@ -49,23 +48,20 @@ type SMSCController struct { // @Router /neData/smsc/cdr/list [get] func (s *SMSCController) CDRList(c *gin.Context) { language := reqctx.AcceptLanguage(c) - var querys model.CDREventSMSCQuery - if err := c.ShouldBindQuery(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return + query := reqctx.QueryMap(c) + // 限制导出数据集 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } - // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - - // 查询数据 - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) } @@ -98,7 +94,7 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { ids = append(ids, parse.Number(v)) } - rows, err := s.cdrEventService.DeleteByIds(ids) + rows, err := s.cdrEventService.DeleteByIds("SMSC", ids) if err != nil { c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) return @@ -109,7 +105,7 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { // CDR会话列表导出 // -// POST /cdr/export +// GET /cdr/export // // @Tags network_data/smsc // @Accept json @@ -119,28 +115,23 @@ func (s *SMSCController) CDRRemove(c *gin.Context) { // @Security TokenAuth // @Summary CDR Session List Export // @Description CDR Session List Export -// @Router /neData/smsc/cdr/export [post] +// @Router /neData/smsc/cdr/export [get] func (s *SMSCController) CDRExport(c *gin.Context) { language := reqctx.AcceptLanguage(c) - // 查询结果,根据查询条件结果,单页最大值限制 - var querys model.CDREventSMSCQuery - if err := c.ShouldBindBodyWithJSON(&querys); err != nil { - errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) - c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) - return - } + query := reqctx.QueryMap(c) // 限制导出数据集 - if querys.PageSize > 10000 { - querys.PageSize = 10000 + pageSize := parse.Number(query["pageSize"]) + if pageSize > 10000 { + query["pageSize"] = "10000" } // 查询网元信息 rmUID - neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - querys.RmUID = neInfo.RmUID - rows, total := s.cdrEventService.FindByPage(querys) + query["rmUID"] = neInfo.RmUID + rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query) if total == 0 { // 导出数据记录为空 c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) @@ -150,7 +141,7 @@ func (s *SMSCController) CDRExport(c *gin.Context) { // 导出文件名称 fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) // 导出数据表格 - saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) + saveFilePath, err := s.cdrEventService.ExportSMSC(rows, fileName, language) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/model/cdr_event.go b/src/modules/network_data/model/cdr_event.go new file mode 100644 index 00000000..8b713d13 --- /dev/null +++ b/src/modules/network_data/model/cdr_event.go @@ -0,0 +1,17 @@ +package model + +// CDREvent CDR会话对象 cdr_event +type CDREvent 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"` // 可能没有 + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 + CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String + CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 +} + +// TableName 表名称 +func (*CDREvent) TableName() string { + return "cdr_event" +} diff --git a/src/modules/network_data/model/cdr_event_ims.go b/src/modules/network_data/model/cdr_event_ims.go deleted file mode 100644 index 8c383ad2..00000000 --- a/src/modules/network_data/model/cdr_event_ims.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventIMS CDR会话对象IMS cdr_event_ims -type CDREventIMS 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"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventIMS) TableName() string { - return "cdr_event_ims" -} - -// CDREventIMSQuery CDR会话对象IMS查询参数结构体 -type CDREventIMSQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=IMS"` // 网元类型IMS - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC - CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 - CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_sgwc.go b/src/modules/network_data/model/cdr_event_sgwc.go deleted file mode 100644 index 26562065..00000000 --- a/src/modules/network_data/model/cdr_event_sgwc.go +++ /dev/null @@ -1,32 +0,0 @@ -package model - -// CDREventSGWC CDR会话对象SGWC cdr_event_sgwc -type CDREventSGWC 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"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSGWC) TableName() string { - return "cdr_event_sgwc" -} - -// CDREventSGWCQuery CDR会话对象SGWC查询参数结构体 -type CDREventSGWCQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SGWC"` // SGWC - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - IMSI string `json:"imsi" form:"imsi"` - MSISDN string `json:"msisdn" form:"msisdn"` - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go deleted file mode 100644 index a6df3ced..00000000 --- a/src/modules/network_data/model/cdr_event_smf.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventSMF CDR会话对象SMF cdr_event_smf -type CDREventSMF 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"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSMF) TableName() string { - return "cdr_event_smf" -} - -// CDREventSMFQuery CDR会话对象SMF查询参数结构体 -type CDREventSMFQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SMF"` // 网元类型, 暂时支持SMF - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 暂时没用到 - SubscriberID string `json:"subscriberID" form:"subscriberID"` - DNN string `json:"dnn" form:"dnn"` - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_smsc.go b/src/modules/network_data/model/cdr_event_smsc.go deleted file mode 100644 index 753e694a..00000000 --- a/src/modules/network_data/model/cdr_event_smsc.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -// CDREventSMSC CDR会话对象SMSC cdr_event_smsc -type CDREventSMSC 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"` // 可能没有 - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳 - CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String - CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒 -} - -// TableName 表名称 -func (*CDREventSMSC) TableName() string { - return "cdr_event_smsc" -} - -// CDREventSMSCQuery CDR会话对象SMSC查询参数结构体 -type CDREventSMSCQuery struct { - NeType string `json:"neType" form:"neType" binding:"required,oneof=SMSC"` // 网元类型, 暂时支持SMSC - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOSM MTSM - CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 - CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 - BeginTime int64 `json:"beginTime" form:"beginTime"` // 开始时间 查timestamp - EndTime int64 `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event.go new file mode 100644 index 00000000..4ce8532e --- /dev/null +++ b/src/modules/network_data/repository/cdr_event.go @@ -0,0 +1,167 @@ +package repository + +import ( + "fmt" + "strings" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 CDREvent 结构体 +var NewCDREvent = &CDREvent{} + +// CDREvent CDR会话事件 数据层处理 +type CDREvent struct{} + +// SelectByPage 分页查询集合 +func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model.CDREvent, int64) { + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.CDREvent{}) + // 查询条件拼接 + if v, ok := query["rmUID"]; ok && v != "" { + tx = tx.Where("rm_uid = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = v + "000" + } + tx = tx.Where("timestamp <= ?", v) + } + + // 各个网元特殊查询条件 + switch neType { + case "SMSC": + if v, ok := query["callerParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + } + if v, ok := query["calledParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + } + if v, ok := query["recordType"]; ok && v != "" { + recordTypes := strings.Split(v, ",") + var querytrArr []string + for _, recordType := range recordTypes { + querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) + } + tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) + } + case "SMF": + if v, ok := query["recordType"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", v) + } + if v, ok := query["subscriberID"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", v) + } + if v, ok := query["dnn"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", v) + } + case "SGWC": + if v, ok := query["imsi"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", v) + } + if v, ok := query["msisdn"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", v) + } + case "IMS": + if v, ok := query["callerParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", v) + } + if v, ok := query["calledParty"]; ok && v != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", v) + } + } + + var total int64 = 0 + rows := []model.CDREvent{} + + // 查询数量 长度为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 +} + +// SelectByIds 通过ID查询 +func (r CDREvent) SelectByIds(neType string, ids []int64) []model.CDREvent { + rows := []model.CDREvent{} + if len(ids) <= 0 { + return rows + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Model(&model.CDREvent{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r CDREvent) DeleteByIds(neType string, ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType)) + tx := db.DB("").Table(tableName).Where("id in ?", ids) + if err := tx.Delete(&model.CDREvent{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// Insert 新增信息 返回新增数据ID +func (r CDREvent) Insert(param model.CDREvent) int64 { + if param.NeType == "" { + return 0 + } + if param.CreatedAt == 0 { + param.CreatedAt = time.Now().UnixMilli() + } + // 表名 + tableName := fmt.Sprintf("cdr_event_%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 +} diff --git a/src/modules/network_data/repository/cdr_event_ims.go b/src/modules/network_data/repository/cdr_event_ims.go deleted file mode 100644 index 814bd83d..00000000 --- a/src/modules/network_data/repository/cdr_event_ims.go +++ /dev/null @@ -1,107 +0,0 @@ -package repository - -import ( - "fmt" - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventIMS 结构体 -var NewCDREventIMS = &CDREventIMS{} - -// CDREventIMS CDR会话事件 数据层处理 -type CDREventIMS struct{} - -// SelectByPage 分页查询集合 -func (r CDREventIMS) SelectByPage(query model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { - tx := db.DB("").Model(&model.CDREventIMS{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - 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 query.CallerParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", query.CallerParty) - } - if query.CalledParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", query.CalledParty) - } - - if query.RecordType != "" { - recordTypes := strings.Split(query.RecordType, ",") - var querytrArr []string - for _, recordType := range recordTypes { - querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) - } - tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventIMS{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventIMS) SelectByIds(ids []int64) []model.CDREventIMS { - rows := []model.CDREventIMS{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventIMS{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventIMS) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventIMS{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_sgwc.go b/src/modules/network_data/repository/cdr_event_sgwc.go deleted file mode 100644 index 6410120f..00000000 --- a/src/modules/network_data/repository/cdr_event_sgwc.go +++ /dev/null @@ -1,95 +0,0 @@ -package repository - -import ( - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSGWC 结构体 -var NewCDREventSGWC = &CDREventSGWC{} - -// CDREventSGWC CDR会话事件 数据层处理 -type CDREventSGWC struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSGWC) SelectByPage(query model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { - tx := db.DB("").Model(&model.CDREventSGWC{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.IMSI != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", query.IMSI) - } - if query.MSISDN != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", query.MSISDN) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSGWC{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSGWC) SelectByIds(ids []int64) []model.CDREventSGWC { - rows := []model.CDREventSGWC{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSGWC{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSGWC) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSGWC{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_smf.go b/src/modules/network_data/repository/cdr_event_smf.go deleted file mode 100644 index 6892e19d..00000000 --- a/src/modules/network_data/repository/cdr_event_smf.go +++ /dev/null @@ -1,98 +0,0 @@ -package repository - -import ( - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSMF 结构体 -var NewCDREventSMF = &CDREventSMF{} - -// CDREventSMF CDR会话事件 数据层处理 -type CDREventSMF struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSMF) SelectByPage(query model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { - tx := db.DB("").Model(&model.CDREventSMF{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.RecordType != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", query.RecordType) - } - if query.SubscriberID != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", query.SubscriberID) - } - if query.DNN != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", query.DNN) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSMF{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSMF) SelectByIds(ids []int64) []model.CDREventSMF { - rows := []model.CDREventSMF{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSMF{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMF) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSMF{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/cdr_event_smsc.go b/src/modules/network_data/repository/cdr_event_smsc.go deleted file mode 100644 index 928e5063..00000000 --- a/src/modules/network_data/repository/cdr_event_smsc.go +++ /dev/null @@ -1,107 +0,0 @@ -package repository - -import ( - "fmt" - "strings" - - "be.ems/src/framework/database/db" - "be.ems/src/framework/logger" - "be.ems/src/modules/network_data/model" -) - -// 实例化数据层 CDREventSMSC 结构体 -var NewCDREventSMSC = &CDREventSMSC{} - -// CDREventSMSC CDR会话事件 数据层处理 -type CDREventSMSC struct{} - -// SelectByPage 分页查询集合 -func (r CDREventSMSC) SelectByPage(query model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { - tx := db.DB("").Model(&model.CDREventSMSC{}) - // 查询条件拼接 - if query.NeType != "" { - tx = tx.Where("ne_type = ?", query.NeType) - } - if query.RmUID != "" { - tx = tx.Where("rm_uid = ?", query.RmUID) - } - if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) - } - if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) - } - if query.CallerParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", query.CallerParty) - } - if query.CalledParty != "" { - tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", query.CalledParty) - } - - if query.RecordType != "" { - recordTypes := strings.Split(query.RecordType, ",") - var querytrArr []string - for _, recordType := range recordTypes { - querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) - } - tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR "))) - } - - // 查询结果 - var total int64 = 0 - rows := []model.CDREventSMSC{} - - // 查询数量为0直接返回 - if err := tx.Count(&total).Error; err != nil || total <= 0 { - return rows, total - } - - // 排序 - if query.SortField != "" { - sortField := query.SortField - if query.SortOrder == "desc" { - sortField = sortField + " desc" - } - tx = tx.Order(sortField) - } - - // 查询数据分页 - pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) - tx = tx.Limit(pageSize).Offset(pageSize * pageNum) - err := tx.Find(&rows).Error - if err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows, total - } - return rows, total -} - -// SelectByIds 通过ID查询 -func (r *CDREventSMSC) SelectByIds(ids []int64) []model.CDREventSMSC { - rows := []model.CDREventSMSC{} - if len(ids) <= 0 { - return rows - } - tx := db.DB("").Model(&model.CDREventSMSC{}) - // 构建查询条件 - tx = tx.Where("id in ?", ids) - // 查询数据 - if err := tx.Find(&rows).Error; err != nil { - logger.Errorf("query find err => %v", err.Error()) - return rows - } - return rows -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMSC) DeleteByIds(ids []int64) int64 { - if len(ids) <= 0 { - return 0 - } - tx := db.DB("").Where("id in ?", ids) - if err := tx.Delete(&model.CDREventSMSC{}).Error; err != nil { - logger.Errorf("delete err => %v", err.Error()) - return 0 - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/service/cdr_event.go b/src/modules/network_data/service/cdr_event.go new file mode 100644 index 00000000..952e0ebf --- /dev/null +++ b/src/modules/network_data/service/cdr_event.go @@ -0,0 +1,645 @@ +package service + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/file" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" + sysService "be.ems/src/modules/system/service" +) + +// 实例化数据层 CDREvent 结构体 +var NewCDREvent = &CDREvent{ + cdrEventRepository: repository.NewCDREvent, +} + +// CDREvent CDR会话事件 服务层处理 +type CDREvent struct { + cdrEventRepository *repository.CDREvent // CDR会话事件数据信息 +} + +// FindByPage 根据条件分页查询 +func (r CDREvent) FindByPage(neType string, query map[string]string) ([]model.CDREvent, int64) { + return r.cdrEventRepository.SelectByPage(neType, query) +} + +// DeleteByIds 批量删除信息 +func (r CDREvent) DeleteByIds(neType string, ids []int64) (int64, error) { + // 检查是否存在 + rows := r.cdrEventRepository.SelectByIds(neType, ids) + if len(rows) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(rows) == len(ids) { + rows := r.cdrEventRepository.DeleteByIds(neType, ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// Insert 新增信息 +func (s CDREvent) Insert(param model.CDREvent) int64 { + return s.cdrEventRepository.Insert(param) +} + +// ExportSMSC 导出数据到 xlsx 文件 +func (r CDREvent) ExportSMSC(rows []model.CDREvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Service Type", + "E1": "Caller", + "F1": "Called", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR 原因码 + dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 服务类型 + serviceType := "" + if v, ok := cdrJSON["serviceType"]; ok && v != nil { + serviceType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫结果 0失败,1成功 + callResult := "Fail" + if v, ok := cdrJSON["result"]; ok && v != nil { + resultVal := parse.Number(v) + if resultVal == 1 { + callResult = "Success" + } + } + // 结果原因 + if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { + cause := fmt.Sprint(v) + for _, v := range dictCDRCauseCode { + if cause == v.DataValue { + callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["updateTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + timeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: serviceType, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportSMF 导出数据到 xlsx 文件 +func (r CDREvent) ExportSMF(rows []model.CDREvent, fileName string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Charging ID", + "C1": "NE Name", + "D1": "Resource Unique ID", + "E1": "Subscriber ID Data", + "F1": "Subscriber ID Type", + "G1": "Data Volume Uplink", + "H1": "Data Volume Downlink", + "I1": "Data Total Volume", + "J1": "Duration", + "K1": "Invocation Time", + "L1": "User Identifier", + "M1": "SSC Mode", + "N1": "DNN ID", + "O1": "PDU Type", + "P1": "RAT Type", + "Q1": "PDU IPv4 Address", + "R1": "Network Function IPv4", + "S1": "PDU IPv6 Address Swith Prefix", + "T1": "Record Network Function ID", + "U1": "Record Type", + "V1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + + // 网络功能 IPv4 地址 + networkFunctionIPv4Address := "" + if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { + if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { + networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) + } + } + + // 数据量上行链路 + var dataVolumeUplink int64 = 0 + // 数据量下行链路 + var dataVolumeDownlink int64 = 0 + // 数据总量 + var dataTotalVolume int64 = 0 + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink += parse.Number(dup) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink += parse.Number(ddown) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume += parse.Number(dt) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + User_Identifier := "" + SSC_Mode := "" + RAT_Type := "" + DNN_ID := "" + PDU_Type := "" + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + } + + // 记录网络参数ID + recordNFID := "" + if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { + recordNFID = v.(string) + } + + //记录开始时间 + recordOpeningTime := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + recordOpeningTime = v.(string) + } + + //记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: chargingID, + "C" + idx: row.NeName, + "D" + idx: row.RmUid, + "E" + idx: subscriptionIDData, + "F" + idx: subscriptionIDType, + "G" + idx: dataVolumeUplink, + "H" + idx: dataVolumeDownlink, + "I" + idx: dataTotalVolume, + "J" + idx: duration, + "K" + idx: invocationTimestamp, + "L" + idx: User_Identifier, + "M" + idx: SSC_Mode, + "N" + idx: DNN_ID, + "O" + idx: PDU_Type, + "P" + idx: RAT_Type, + "Q" + idx: PDU_IPv4, + "R" + idx: networkFunctionIPv4Address, + "S" + idx: PDU_IPv6, + "T" + idx: recordNFID, + "U" + idx: recordType, + "V" + idx: recordOpeningTime, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportSGWC 导出数据到 xlsx 文件 +func (r CDREvent) ExportSGWC(rows []model.CDREvent, fileName string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Resource Unique ID", + "D1": "Charging ID", + "E1": "IMSI", + "F1": "MSISDN", + "G1": "GPRS Uplink", + "H1": "GPRS Downlink", + "I1": "Duration", + "J1": "Invocation Time", + "K1": "PGW Address", + "L1": "SGW Address", + "M1": "RAT Type", + "N1": "PDPPDN Type", + "O1": "PDPPDN Address", + "P1": "Node Address", + "Q1": "Node Type", + "R1": "Record Access Point Name NI", + "S1": "Record Cause For Rec Closing", + "T1": "Record Sequence Number", + "U1": "Local Record Sequence Number", + "V1": "Record Type", + "W1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // IMSI + servedIMSI := "" + if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { + servedIMSI = fmt.Sprint(v) + } + // MSISDN + servedMSISDN := "" + if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { + servedMSISDN = fmt.Sprint(v) + } + // pGWAddressUsed + pGWAddressUsed := "" + if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "PGW Address" + } + if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "GGSN Address" + } + // sGWAddress + sGWAddress := "" + if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGW Address" + } + if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGSN Address" + } + // recordType + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = fmt.Sprint(v) + } + // rATType + rATType := "" + if v, ok := cdrJSON["rATType"]; ok && v != nil { + rATType = fmt.Sprint(v) + } + // pdpPDNType + pdpPDNType := "" + if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { + pdpPDNType = fmt.Sprint(v) + } + // servedPDPPDNAddress + servedPDPPDNAddress := "" + if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { + servedPDPPDNAddress = fmt.Sprint(v) + } + // servedPDPPDNAddress + servingNodeAddress := []string{} + if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { + for _, v := range v.([]any) { + servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) + } + } + // servingNodeType + servingNodeType := []string{} + if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { + for _, v := range v.([]any) { + if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { + servingNodeType = append(servingNodeType, fmt.Sprint(v)) + } + } + } + // accessPointNameNI + accessPointNameNI := "" + if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { + accessPointNameNI = fmt.Sprint(v) + } + // causeForRecClosing + causeForRecClosing := "" + if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { + causeForRecClosing = fmt.Sprint(v) + } + // recordSequenceNumber + recordSequenceNumber := "" + if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { + recordSequenceNumber = fmt.Sprint(v) + } + // localRecordSequenceNumber + localRecordSequenceNumber := "" + if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { + localRecordSequenceNumber = fmt.Sprint(v) + } + // 数据量上行链路 + var dataVolumeGPRSUplink int64 = 0 + // 数据量下行链路 + var dataVolumeGPRSDownlink int64 = 0 + if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { + dataVolumeGPRSUplink = parse.Number(dup) + } + if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { + dataVolumeGPRSDownlink = parse.Number(ddown) + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + invocationTimestamp = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: row.RmUid, + "D" + idx: chargingID, + "E" + idx: servedIMSI, + "F" + idx: servedMSISDN, + "G" + idx: dataVolumeGPRSUplink, + "H" + idx: dataVolumeGPRSDownlink, + "I" + idx: duration, + "J" + idx: invocationTimestamp, + "K" + idx: pGWAddressUsed, + "L" + idx: sGWAddress, + "M" + idx: rATType, + "N" + idx: pdpPDNType, + "O" + idx: servedPDPPDNAddress, + "P" + idx: strings.Join(servingNodeAddress, ","), + "Q" + idx: strings.Join(servingNodeType, ","), + "R" + idx: accessPointNameNI, + "S" + idx: causeForRecClosing, + "T" + idx: recordSequenceNumber, + "U" + idx: localRecordSequenceNumber, + "V" + idx: recordType, + "W" + idx: invocationTimestamp, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} + +// ExportIMS 导出数据到 xlsx 文件 +func (r CDREvent) ExportIMS(rows []model.CDREvent, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Type", + "E1": "Caller", + "F1": "Called", + "G1": "Duration", + "H1": "Result Code", + "I1": "Result Cause", + "J1": "Call Start Time", + "K1": "Hangup Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code") + // 读取字典数据 CDR SIP响应代码类别类型原因 + dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]any + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DataValue { + callTypeLable = i18n.TKey(language, v.DataLabel) + break + } + } + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprintf("%ds", parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Other" + callCause := "Call failure for other reason" + if callType == "sms" { + callResult = "Success" + callCause = "Normal Send" + } else { + if v, ok := cdrJSON["cause"]; ok && v != nil { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DataValue { + callResult = i18n.TKey(language, v.DataLabel) + break + } + } + for _, v := range dictCDRSipCodeCause { + if cause == v.DataValue { + callCause = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + // 呼叫时间 + seizureTimeStr := "" + if v, ok := cdrJSON["seizureTime"]; ok && v != nil { + if seizureTime := parse.Number(v); seizureTime > 0 { + seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + seizureTimeStr = v.(string) + } + } + // 挂断时间 + releaseTimeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + releaseTimeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: callTypeLable, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: duration, + "H" + idx: callResult, + "I" + idx: callCause, + "J" + idx: seizureTimeStr, + "K" + idx: releaseTimeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} diff --git a/src/modules/network_data/service/cdr_event_ims.go b/src/modules/network_data/service/cdr_event_ims.go deleted file mode 100644 index 30ad78a8..00000000 --- a/src/modules/network_data/service/cdr_event_ims.go +++ /dev/null @@ -1,173 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 CDREventIMS 结构体 -var NewCDREventIMS = &CDREventIMS{ - cdrEventIMSRepository: repository.NewCDREventIMS, -} - -// CDREventImpl CDR会话事件IMS 服务层处理 -type CDREventIMS struct { - cdrEventIMSRepository *repository.CDREventIMS // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventIMS) FindByPage(query model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { - return r.cdrEventIMSRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventIMS) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventIMSRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventIMSRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventIMS) ExportXlsx(rows []model.CDREventIMS, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Record Behavior", - "D1": "Type", - "E1": "Caller", - "F1": "Called", - "G1": "Duration", - "H1": "Result Code", - "I1": "Result Cause", - "J1": "Call Start Time", - "K1": "Hangup Time", - } - // 读取字典数据 CDR SIP响应代码类别类型 - dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code") - // 读取字典数据 CDR SIP响应代码类别类型原因 - dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause") - // 读取字典数据 CDR 呼叫类型 - dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]any - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - // 呼叫类型 - callType := "sms" - callTypeLable := "SMS" - if v, ok := cdrJSON["callType"]; ok && v != nil { - callType = v.(string) - for _, v := range dictCDRCallType { - if callType == v.DataValue { - callTypeLable = i18n.TKey(language, v.DataLabel) - break - } - } - } - // 被叫 - called := "" - if v, ok := cdrJSON["calledParty"]; ok && v != nil { - called = v.(string) - } - // 主叫 - caller := "" - if v, ok := cdrJSON["callerParty"]; ok && v != nil { - caller = v.(string) - } - // 时长 - duration := "-" - if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { - duration = fmt.Sprintf("%ds", parse.Number(v)) - } - // 呼叫结果 非短信都有code作为结果 sms短信都ok - callResult := "Other" - callCause := "Call failure for other reason" - if callType == "sms" { - callResult = "Success" - callCause = "Normal Send" - } else { - if v, ok := cdrJSON["cause"]; ok && v != nil { - cause := fmt.Sprint(v) - for _, v := range dictCDRSipCode { - if cause == v.DataValue { - callResult = i18n.TKey(language, v.DataLabel) - break - } - } - for _, v := range dictCDRSipCodeCause { - if cause == v.DataValue { - callCause = i18n.TKey(language, v.DataLabel) - break - } - } - } - } - // 呼叫时间 - seizureTimeStr := "" - if v, ok := cdrJSON["seizureTime"]; ok && v != nil { - if seizureTime := parse.Number(v); seizureTime > 0 { - seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - seizureTimeStr = v.(string) - } - } - // 挂断时间 - releaseTimeStr := "" - if v, ok := cdrJSON["releaseTime"]; ok && v != nil { - if releaseTime := parse.Number(v); releaseTime > 0 { - releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - releaseTimeStr = v.(string) - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: recordType, - "D" + idx: callTypeLable, - "E" + idx: caller, - "F" + idx: called, - "G" + idx: duration, - "H" + idx: callResult, - "I" + idx: callCause, - "J" + idx: seizureTimeStr, - "K" + idx: releaseTimeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_sgwc.go b/src/modules/network_data/service/cdr_event_sgwc.go deleted file mode 100644 index ca6ede41..00000000 --- a/src/modules/network_data/service/cdr_event_sgwc.go +++ /dev/null @@ -1,235 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" - - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" -) - -// 实例化数据层 CDREventSGWC 结构体 -var NewCDREventSGWC = &CDREventSGWC{ - cdrEventRepository: repository.NewCDREventSGWC, -} - -// CDREventSGWC CDR会话事件SGWC 服务层处理 -type CDREventSGWC struct { - cdrEventRepository *repository.CDREventSGWC // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSGWC) FindByPage(query model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { - return r.cdrEventRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSGWC) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSGWC) ExportXlsx(rows []model.CDREventSGWC, fileName string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Resource Unique ID", - "D1": "Charging ID", - "E1": "IMSI", - "F1": "MSISDN", - "G1": "GPRS Uplink", - "H1": "GPRS Downlink", - "I1": "Duration", - "J1": "Invocation Time", - "K1": "PGW Address", - "L1": "SGW Address", - "M1": "RAT Type", - "N1": "PDPPDN Type", - "O1": "PDPPDN Address", - "P1": "Node Address", - "Q1": "Node Type", - "R1": "Record Access Point Name NI", - "S1": "Record Cause For Rec Closing", - "T1": "Record Sequence Number", - "U1": "Local Record Sequence Number", - "V1": "Record Type", - "W1": "Record Opening Time", - } - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 计费ID - chargingID := "" - if v, ok := cdrJSON["chargingID"]; ok && v != nil { - chargingID = fmt.Sprint(parse.Number(v)) - } - // IMSI - servedIMSI := "" - if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { - servedIMSI = fmt.Sprint(v) - } - // MSISDN - servedMSISDN := "" - if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { - servedMSISDN = fmt.Sprint(v) - } - // pGWAddressUsed - pGWAddressUsed := "" - if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { - pGWAddressUsed = fmt.Sprint(v) - headerCells["K1"] = "PGW Address" - } - if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { - pGWAddressUsed = fmt.Sprint(v) - headerCells["K1"] = "GGSN Address" - } - // sGWAddress - sGWAddress := "" - if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { - sGWAddress = fmt.Sprint(v) - headerCells["L1"] = "SGW Address" - } - if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { - sGWAddress = fmt.Sprint(v) - headerCells["L1"] = "SGSN Address" - } - // recordType - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = fmt.Sprint(v) - } - // rATType - rATType := "" - if v, ok := cdrJSON["rATType"]; ok && v != nil { - rATType = fmt.Sprint(v) - } - // pdpPDNType - pdpPDNType := "" - if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { - pdpPDNType = fmt.Sprint(v) - } - // servedPDPPDNAddress - servedPDPPDNAddress := "" - if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { - servedPDPPDNAddress = fmt.Sprint(v) - } - // servedPDPPDNAddress - servingNodeAddress := []string{} - if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { - for _, v := range v.([]any) { - servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) - } - } - // servingNodeType - servingNodeType := []string{} - if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { - for _, v := range v.([]any) { - if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { - servingNodeType = append(servingNodeType, fmt.Sprint(v)) - } - } - } - // accessPointNameNI - accessPointNameNI := "" - if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { - accessPointNameNI = fmt.Sprint(v) - } - // causeForRecClosing - causeForRecClosing := "" - if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { - causeForRecClosing = fmt.Sprint(v) - } - // recordSequenceNumber - recordSequenceNumber := "" - if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { - recordSequenceNumber = fmt.Sprint(v) - } - // localRecordSequenceNumber - localRecordSequenceNumber := "" - if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { - localRecordSequenceNumber = fmt.Sprint(v) - } - // 数据量上行链路 - var dataVolumeGPRSUplink int64 = 0 - // 数据量下行链路 - var dataVolumeGPRSDownlink int64 = 0 - if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { - usageList := v.([]any) - if len(usageList) > 0 { - for _, used := range usageList { - usedUnit := used.(map[string]any) - if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { - dataVolumeGPRSUplink = parse.Number(dup) - } - if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { - dataVolumeGPRSDownlink = parse.Number(ddown) - } - } - } - } - // 时长 - duration := "-" - if v, ok := cdrJSON["duration"]; ok && v != nil { - duration = fmt.Sprint(parse.Number(v)) - } - // 调用时间 - invocationTimestamp := "" - if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { - invocationTimestamp = v.(string) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: row.RmUid, - "D" + idx: chargingID, - "E" + idx: servedIMSI, - "F" + idx: servedMSISDN, - "G" + idx: dataVolumeGPRSUplink, - "H" + idx: dataVolumeGPRSDownlink, - "I" + idx: duration, - "J" + idx: invocationTimestamp, - "K" + idx: pGWAddressUsed, - "L" + idx: sGWAddress, - "M" + idx: rATType, - "N" + idx: pdpPDNType, - "O" + idx: servedPDPPDNAddress, - "P" + idx: strings.Join(servingNodeAddress, ","), - "Q" + idx: strings.Join(servingNodeType, ","), - "R" + idx: accessPointNameNI, - "S" + idx: causeForRecClosing, - "T" + idx: recordSequenceNumber, - "U" + idx: localRecordSequenceNumber, - "V" + idx: recordType, - "W" + idx: invocationTimestamp, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go deleted file mode 100644 index cb5bc7fb..00000000 --- a/src/modules/network_data/service/cdr_event_smf.go +++ /dev/null @@ -1,230 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" -) - -// 实例化数据层 CDREventSMF 结构体 -var NewCDREventSMF = &CDREventSMF{ - cdrEventRepository: repository.NewCDREventSMF, -} - -// CDREventSMF CDR会话事件SMF 服务层处理 -type CDREventSMF struct { - cdrEventRepository *repository.CDREventSMF // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSMF) FindByPage(querys model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { - return r.cdrEventRepository.SelectByPage(querys) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMF) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSMF) ExportXlsx(rows []model.CDREventSMF, fileName string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "Charging ID", - "C1": "NE Name", - "D1": "Resource Unique ID", - "E1": "Subscriber ID Data", - "F1": "Subscriber ID Type", - "G1": "Data Volume Uplink", - "H1": "Data Volume Downlink", - "I1": "Data Total Volume", - "J1": "Duration", - "K1": "Invocation Time", - "L1": "User Identifier", - "M1": "SSC Mode", - "N1": "DNN ID", - "O1": "PDU Type", - "P1": "RAT Type", - "Q1": "PDU IPv4 Address", - "R1": "Network Function IPv4", - "S1": "PDU IPv6 Address Swith Prefix", - "T1": "Record Network Function ID", - "U1": "Record Type", - "V1": "Record Opening Time", - } - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 计费ID - chargingID := "" - if v, ok := cdrJSON["chargingID"]; ok && v != nil { - chargingID = fmt.Sprint(parse.Number(v)) - } - // 订阅 ID 类型 - subscriptionIDType := "-" - // 订阅 ID 数据 - subscriptionIDData := "-" - if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { - if sub, subOk := v.(map[string]any); subOk && sub != nil { - subscriptionIDType = sub["subscriptionIDType"].(string) - subscriptionIDData = sub["subscriptionIDData"].(string) - } - } - - // 网络功能 IPv4 地址 - networkFunctionIPv4Address := "" - if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { - if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { - networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) - } - } - - // 数据量上行链路 - var dataVolumeUplink int64 = 0 - // 数据量下行链路 - var dataVolumeDownlink int64 = 0 - // 数据总量 - var dataTotalVolume int64 = 0 - if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { - usageList := v.([]any) - if len(usageList) > 0 { - for _, used := range usageList { - usedUnit := used.(map[string]any) - usedUnitList := usedUnit["usedUnitContainer"].([]any) - if len(usedUnitList) > 0 { - for _, data := range usedUnitList { - udata := data.(map[string]any) - if dup, dupOk := udata["dataVolumeUplink"]; dupOk { - dataVolumeUplink += parse.Number(dup) - } - if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { - dataVolumeDownlink += parse.Number(ddown) - } - if dt, dtOk := udata["dataTotalVolume"]; dtOk { - dataTotalVolume += parse.Number(dt) - } - } - } - } - } - } - // 时长 - duration := "-" - if v, ok := cdrJSON["duration"]; ok && v != nil { - duration = fmt.Sprint(parse.Number(v)) - } - // 调用时间 - invocationTimestamp := "" - if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { - invocationTimestamp = v.(string) - } - // 记录打开时间 - User_Identifier := "" - SSC_Mode := "" - RAT_Type := "" - DNN_ID := "" - PDU_Type := "" - PDU_IPv4 := "" - PDU_IPv6 := "" - if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { - pduInfo := v.(map[string]any) - - if v, ok := pduInfo["userIdentifier"]; ok && v != nil { - User_Identifier = v.(string) - } - if v, ok := pduInfo["sSCMode"]; ok && v != nil { - SSC_Mode = v.(string) - } - if v, ok := pduInfo["rATType"]; ok && v != nil { - RAT_Type = v.(string) - } - if v, ok := pduInfo["dNNID"]; ok && v != nil { - DNN_ID = v.(string) - } - if v, ok := pduInfo["pDUType"]; ok && v != nil { - PDU_Type = v.(string) - } - if v, ok := pduInfo["pDUAddress"]; ok && v != nil { - pDUAddress := v.(map[string]any) - if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { - PDU_IPv4 = addr.(string) - } - if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { - PDU_IPv6 = addr.(string) - } - } - } - - // 记录网络参数ID - recordNFID := "" - if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { - recordNFID = v.(string) - } - - //记录开始时间 - recordOpeningTime := "" - if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { - recordOpeningTime = v.(string) - } - - //记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: chargingID, - "C" + idx: row.NeName, - "D" + idx: row.RmUid, - "E" + idx: subscriptionIDData, - "F" + idx: subscriptionIDType, - "G" + idx: dataVolumeUplink, - "H" + idx: dataVolumeDownlink, - "I" + idx: dataTotalVolume, - "J" + idx: duration, - "K" + idx: invocationTimestamp, - "L" + idx: User_Identifier, - "M" + idx: SSC_Mode, - "N" + idx: DNN_ID, - "O" + idx: PDU_Type, - "P" + idx: RAT_Type, - "Q" + idx: PDU_IPv4, - "R" + idx: networkFunctionIPv4Address, - "S" + idx: PDU_IPv6, - "T" + idx: recordNFID, - "U" + idx: recordType, - "V" + idx: recordOpeningTime, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/network_data/service/cdr_event_smsc.go b/src/modules/network_data/service/cdr_event_smsc.go deleted file mode 100644 index 99006c31..00000000 --- a/src/modules/network_data/service/cdr_event_smsc.go +++ /dev/null @@ -1,137 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - "strconv" - - "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" - "be.ems/src/framework/utils/parse" - "be.ems/src/modules/network_data/model" - "be.ems/src/modules/network_data/repository" - sysService "be.ems/src/modules/system/service" -) - -// 实例化数据层 CDREventSMSC 结构体 -var NewCDREventSMSC = &CDREventSMSC{ - cdrEventRepository: repository.NewCDREventSMSC, -} - -// CDREventSMSC CDR会话事件SMSC 服务层处理 -type CDREventSMSC struct { - cdrEventRepository *repository.CDREventSMSC // CDR会话事件数据信息 -} - -// FindByPage 根据条件分页查询 -func (r *CDREventSMSC) FindByPage(query model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { - return r.cdrEventRepository.SelectByPage(query) -} - -// DeleteByIds 批量删除信息 -func (r *CDREventSMSC) DeleteByIds(ids []int64) (int64, error) { - // 检查是否存在 - rows := r.cdrEventRepository.SelectByIds(ids) - if len(rows) <= 0 { - return 0, fmt.Errorf("not data") - } - - if len(rows) == len(ids) { - rows := r.cdrEventRepository.DeleteByIds(ids) - return rows, nil - } - // 删除信息失败! - return 0, fmt.Errorf("delete fail") -} - -// ExportXlsx 导出数据到 xlsx 文件 -func (r CDREventSMSC) ExportXlsx(rows []model.CDREventSMSC, fileName, language string) (string, error) { - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "NE Name", - "C1": "Record Behavior", - "D1": "Service Type", - "E1": "Caller", - "F1": "Called", - "G1": "Result", - "H1": "Time", - } - // 读取字典数据 CDR 原因码 - dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var cdrJSON map[string]interface{} - err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) - if err != nil { - logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) - continue - } - // 记录类型 - recordType := "" - if v, ok := cdrJSON["recordType"]; ok && v != nil { - recordType = v.(string) - } - // 服务类型 - serviceType := "" - if v, ok := cdrJSON["serviceType"]; ok && v != nil { - serviceType = v.(string) - } - // 被叫 - called := "" - if v, ok := cdrJSON["calledParty"]; ok && v != nil { - called = v.(string) - } - // 主叫 - caller := "" - if v, ok := cdrJSON["callerParty"]; ok && v != nil { - caller = v.(string) - } - // 呼叫结果 0失败,1成功 - callResult := "Fail" - if v, ok := cdrJSON["result"]; ok && v != nil { - resultVal := parse.Number(v) - if resultVal == 1 { - callResult = "Success" - } - } - // 结果原因 - if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { - cause := fmt.Sprint(v) - for _, v := range dictCDRCauseCode { - if cause == v.DataValue { - callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) - break - } - } - } - // 取时间 - timeStr := "" - if v, ok := cdrJSON["updateTime"]; ok && v != nil { - if releaseTime := parse.Number(v); releaseTime > 0 { - timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } else { - timeStr = v.(string) - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: row.NeName, - "C" + idx: recordType, - "D" + idx: serviceType, - "E" + idx: caller, - "F" + idx: called, - "G" + idx: callResult, - "H" + idx: timeStr, - }) - } - - // 导出数据表格 - return file.WriteSheet(headerCells, dataCells, fileName, "") -} diff --git a/src/modules/oam/service/cdr.go b/src/modules/oam/service/cdr.go new file mode 100644 index 00000000..7173087d --- /dev/null +++ b/src/modules/oam/service/cdr.go @@ -0,0 +1,73 @@ +package service + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/logger" + "github.com/tsmask/go-oam" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +// 实例化服务层 CDR 结构体 +var NewCDR = &CDR{ + neInfoService: neService.NewNeInfo, + wsService: wsService.NewWSSend, + cdrEventService: neDataService.NewCDREvent, +} + +// CDR 消息处理 +type CDR struct { + neInfoService *neService.NeInfo + wsService *wsService.WSSend + cdrEventService *neDataService.CDREvent // CDR会话事件服务 +} + +// Resolve 接收处理 +func (s *CDR) Resolve(c oam.CDR) error { + if c.Data == nil { + return fmt.Errorf("cdr data is nil") + } + // 是否存在网元 + neInfo := s.neInfoService.FindByRmuid(c.NeUid) + if neInfo.NeType == "" || neInfo.RmUID != c.NeUid { + logger.Warnf("resolve cdr network element does not exist %s", c.NeUid) + return fmt.Errorf("resolve cdr network element does not exist %s", c.NeUid) + } + + cdrByte, _ := json.Marshal(c.Data) + cdrEvent := neDataModel.CDREvent{ + NeType: neInfo.NeType, + NeName: neInfo.NeName, + RmUid: neInfo.RmUID, + Timestamp: c.RecordTime, + CdrJson: string(cdrByte), + CreatedAt: c.RecordTime, + } + insertId := s.cdrEventService.Insert(cdrEvent) + if insertId <= 0 { + return fmt.Errorf("add cdr data fail") + } + cdrEvent.ID = insertId + + // 推送到ws订阅组 + switch neInfo.NeType { + case "IMS": + dataMap := c.Data.(map[string]any) + v, ok := dataMap["recordType"] + if ok && (v == "MOC" || v == "MTSM") { + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_IMS_CDR, neInfo.NeId), cdrEvent) + } + case "SMF": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMF_CDR, neInfo.NeId), cdrEvent) + case "SMSC": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SMSC_CDR, neInfo.NeId), cdrEvent) + case "SGWC": + s.wsService.ByGroupID(fmt.Sprintf("%s_%s", wsService.GROUP_SGWC_CDR, neInfo.NeId), cdrEvent) + } + return nil +} diff --git a/src/modules/ws/processor/cdr_connect.go b/src/modules/ws/processor/cdr_connect.go index a3848860..884008c4 100644 --- a/src/modules/ws/processor/cdr_connect.go +++ b/src/modules/ws/processor/cdr_connect.go @@ -6,79 +6,29 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/resp" - neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neInfoService "be.ems/src/modules/network_element/service" ) -// GetCDRConnectByIMS 获取CDR会话事件-IMS -func GetCDRConnectByIMS(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventIMSQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") +// GetCDRConnect 获取CDR会话事件 +func GetCDRConnect(requestID string, data any) ([]byte, error) { + if data == nil { + logger.Errorf("ws processor GetCDRConnect data is nil") + return nil, fmt.Errorf("query data error") + } + dataMap := data.(map[string]any) + query := make(map[string]string, 0) + for k, v := range dataMap { + query[k] = fmt.Sprintf("%v", v) } // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { + neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query["neType"], query["neId"]) + if neInfo.NeType == "" { return nil, fmt.Errorf("query neinfo not found") } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventIMS.FindByPage(query) - resultByte, err := json.Marshal(resp.Ok(map[string]any{ - "requestId": requestID, - "data": map[string]any{"rows": rows, "total": total}, - })) - return resultByte, err -} - -// GetCDRConnectBySMF 获取CDR会话事件-SMF -func GetCDRConnectBySMF(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventSMFQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") - } - - // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("query neinfo not found") - } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventSMF.FindByPage(query) - resultByte, err := json.Marshal(resp.Ok(map[string]any{ - "requestId": requestID, - "data": map[string]any{"rows": rows, "total": total}, - })) - return resultByte, err -} - -// GetCDRConnectBySMSC 获取CDR会话事件-SMSC -func GetCDRConnectBySMSC(requestID string, data any) ([]byte, error) { - msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventSMSCQuery - err := json.Unmarshal(msgByte, &query) - if err != nil { - logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) - return nil, fmt.Errorf("query data structure error") - } - - // 查询网元信息 rmUID - neInfo := neInfoService.NewNeInfo.FindByNeTypeAndNeID(query.NeType, query.NeID) - if neInfo.NeId != query.NeID || neInfo.IP == "" { - return nil, fmt.Errorf("query neinfo not found") - } - query.RmUID = neInfo.RmUID - - rows, total := neDataService.NewCDREventSMSC.FindByPage(query) + query["rmUID"] = neInfo.RmUID + rows, total := neDataService.NewCDREvent.FindByPage(neInfo.NeType, query) resultByte, err := json.Marshal(resp.Ok(map[string]any{ "requestId": requestID, "data": map[string]any{"rows": rows, "total": total},