diff --git a/features/cdr/cdrevent.go b/features/cdr/cdrevent.go index 12bb676..f7f0e69 100644 --- a/features/cdr/cdrevent.go +++ b/features/cdr/cdrevent.go @@ -68,6 +68,8 @@ func PostCDREventFrom(w http.ResponseWriter, r *http.Request) { wsService.NewWSSend.ByGroupID(wsService.GROUP_SMF_CDR+neInfo.NeId, cdrEvent) case "SMSC": wsService.NewWSSend.ByGroupID(wsService.GROUP_SMSC_CDR+neInfo.NeId, cdrEvent) + case "SGWC": + wsService.NewWSSend.ByGroupID(wsService.GROUP_SGWC_CDR+neInfo.NeId, cdrEvent) } } diff --git a/features/event/event.go b/features/event/event.go index 1f75012..8ec403a 100644 --- a/features/event/event.go +++ b/features/event/event.go @@ -1,19 +1,17 @@ package event import ( - "encoding/json" "fmt" - "io" "net/http" "strings" "time" "be.ems/lib/core/ctx" "be.ems/lib/dborm" - "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" "be.ems/restagent/config" + "be.ems/src/framework/utils/parse" neService "be.ems/src/modules/network_element/service" wsService "be.ems/src/modules/ws/service" "github.com/gin-gonic/gin" @@ -36,34 +34,100 @@ type UEEvent struct { EventJson map[string]any `json:"eventJSON" xorm:"event_json"` } +// 旧AMF上报处理 func PostUEEventFromAMF(c *gin.Context) { log.Info("PostUEEventFromAMF processing... ") - body, err := io.ReadAll(io.LimitReader(c.Request.Body, global.RequestBodyMaxLen)) - if err != nil { - log.Error("Failed to io.ReadAll: ", err) - services.ResponseNotFound404UriNotExist(c.Writer, c.Request) - return - } - - //vars := mux.Vars(c.Request) eventType, ok := c.Params.Get("eventType") if !ok || eventType == "" { log.Error("eventType is empty") services.ResponseNotFound404UriNotExist(c.Writer, c.Request) return } - ueEvent := new(UEEvent) - err = json.Unmarshal(body, &ueEvent.EventJson) - if err != nil { + var body map[string]any + if err := c.ShouldBindBodyWithJSON(&body); err != nil { log.Error("Failed to Unmarshal ueEvent:", err) services.ResponseInternalServerError500ProcessError(c.Writer, err) return } - ueEvent.NeType = "AMF" - ueEvent.Timestamp = time.Now().Unix() - ueEvent.EventType = eventType - log.Trace("ueEvent AMF:", ueEvent) + + ueEvent := UEEvent{ + NeType: "AMF", + Timestamp: time.Now().Unix(), + EventType: eventType, + } + // 从eventJson中获取rmUID + if v, ok := body["rmUID"]; ok { + ueEvent.RmUID = fmt.Sprint(v) + } else { + ueEvent.RmUID = "4400HXAMF001" + } + if v, ok := body["neName"]; ok { + ueEvent.NeName = fmt.Sprint(v) + } else { + ueEvent.NeName = "AMF_001" + } + + // 统一格式 + eventJson := map[string]any{"cellID": 0, "gNBID": "", "imsi": "", "onlineNumber": 0, "result": "", "tacID": 0, "timestamp": 0, "time": 0, "type": eventType} + switch eventType { + case "auth-result": + // {"authCode":"200","authMessage":"成功","authTime":"2024-12-07 16:48:37","cellID":"3","gNBID":"1","imsi":"460002082100000","onlineNumber":1,"tacID":"81"} + if v, ok := body["imsi"]; ok { + eventJson["imsi"] = fmt.Sprint(v) + } + if v, ok := body["cellID"]; ok { + eventJson["cellID"] = fmt.Sprint(v) + } + if v, ok := body["gNBID"]; ok { + eventJson["gNBID"] = fmt.Sprint(v) + } + if v, ok := body["tacID"]; ok { + eventJson["tacID"] = fmt.Sprint(v) + } + if v, ok := body["onlineNumber"]; ok { + eventJson["onlineNumber"] = parse.Number(v) + } + if v, ok := body["authCode"]; ok { + eventJson["result"] = fmt.Sprint(v) + } + if v, ok := body["authTime"]; ok { + eventJson["timestamp"] = ueEvent.Timestamp + eventJson["time"] = fmt.Sprint(v) + } + case "detach": + // {"detachResult":0,"detachTime":"2024-12-07 18:00:47","imsi":"460002082100000"} + if v, ok := body["imsi"]; ok { + eventJson["imsi"] = fmt.Sprint(v) + } + if v, ok := body["detachResult"]; ok { + if fmt.Sprint(v) == "0" { + eventJson["result"] = "200" + } else { + eventJson["result"] = "500" + } + } + if v, ok := body["detachTime"]; ok { + eventJson["timestamp"] = ueEvent.Timestamp + eventJson["time"] = fmt.Sprint(v) + } + case "cm-state": + // {"changeTime":"2024-12-07 17:07:52","imsi":"460002082100000","onlineNumber":1,"status":2} + if v, ok := body["imsi"]; ok { + eventJson["imsi"] = fmt.Sprint(v) + } + if v, ok := body["onlineNumber"]; ok { + eventJson["onlineNumber"] = parse.Number(v) + } + if v, ok := body["status"]; ok { + eventJson["result"] = fmt.Sprint(v) + } + if v, ok := body["changeTime"]; ok { + eventJson["timestamp"] = ueEvent.Timestamp + eventJson["time"] = fmt.Sprint(v) + } + } + ueEvent.EventJson = eventJson affected, err := dborm.XormInsertTableOne("ue_event_amf", ueEvent) if err != nil && affected <= 0 { @@ -72,13 +136,20 @@ func PostUEEventFromAMF(c *gin.Context) { return } - // AMF没有RmUID,直接推送 - // 推送到ws订阅组 - wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, ueEvent) + // 发送到匹配的网元 + neInfo := neService.NewNeInfo.SelectNeInfoByRmuid(ueEvent.RmUID) + if neInfo.RmUID == ueEvent.RmUID { + // 推送到ws订阅组 + if ueEvent.NeType == "AMF" { + wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, ueEvent) + wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, ueEvent) + } + } services.ResponseStatusOK204NoContent(c.Writer) } +// UE上报处理 func PostUEEvent(w http.ResponseWriter, r *http.Request) { log.Info("PostUEEvent processing... ") @@ -103,7 +174,12 @@ func PostUEEvent(w http.ResponseWriter, r *http.Request) { if neInfo.RmUID == ueEvent.RmUID { // 推送到ws订阅组 if ueEvent.NeType == "MME" { - wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE+neInfo.NeId, ueEvent) + wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE, ueEvent) + wsService.NewWSSend.ByGroupID(wsService.GROUP_MME_UE+"_"+neInfo.NeId, ueEvent) + } + if ueEvent.NeType == "AMF" { + wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE, ueEvent) + wsService.NewWSSend.ByGroupID(wsService.GROUP_AMF_UE+"_"+neInfo.NeId, ueEvent) } } diff --git a/features/fm/smsforward.go b/features/fm/smsforward.go index 325c210..0cb4ac7 100644 --- a/features/fm/smsforward.go +++ b/features/fm/smsforward.go @@ -100,6 +100,11 @@ var smsForward = &(config.GetYamlConfig().Alarm.SMSCForward) func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { log.Info("AlarmForwardBySMPP processing... ") + if smsForward == nil { + err := errors.New("smsForward configuration is nil") + log.Error(err) + return "", err + } userList := smsForward.MobileList auth := gosmpp.Auth{ SMSC: smsForward.SMSCAddr, @@ -133,12 +138,17 @@ func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { log.Error("Failed to create SMPP new session:", err) return userList, err } - defer func() { - _ = trans.Close() - }() + // defer func() { + // if err := trans.Close(); err != nil { + // log.Error(err) + // } + // }() - message := "Alarm Notification: " + alarmData.AlarmTitle + " from " + alarmData.NeType + "_" + alarmData.NeId + " at " + alarmData.EventTime - for _, user := range strings.Split(userList, ",") { + message := "Alarm Notification: " + alarmData.AlarmTitle + + " from " + alarmData.NeType + "_" + alarmData.NeId + + " at " + alarmData.EventTime + users := strings.Split(userList, ",") + for _, user := range users { sm, err := newSubmitSM(user, message) if err != nil { log.Errorf("Failed to newSubmitSM %s short message: %v", user, err) diff --git a/features/pm/kpi_c_title/controller.go b/features/pm/kpi_c_title/controller.go index 1aadbcd..55420ef 100644 --- a/features/pm/kpi_c_title/controller.go +++ b/features/pm/kpi_c_title/controller.go @@ -174,7 +174,7 @@ func (k *KpiCTitle) Post(c *gin.Context) { } userName := ctx.LoginUserToUserName(c) title.CreatedBy = &userName - result := dborm.DefaultDB().Where("ne_type=? and (kpi_id=? or title=?)", title.NeType, title.KpiID, title.Title).First(&title) + result := dborm.DefaultDB().Where("ne_type=? and (kpi_id=? or title=?) and status!='Deleted'", title.NeType, title.KpiID, title.Title).First(&title) if result.RowsAffected > 0 { c.JSON(http.StatusOK, services.ErrResp("custom indicator already exist")) return diff --git a/features/state/getstate.go b/features/state/getstate.go index 61cb781..8ac2d6f 100644 --- a/features/state/getstate.go +++ b/features/state/getstate.go @@ -786,7 +786,9 @@ func GetStateFromNF(w http.ResponseWriter, r *http.Request) { response.Data = data services.ResponseWithJson(w, http.StatusOK, response) return - } else if neType == "omc" { + } + + if neType == "omc" { emsState := GetEMSState("127.0.0.1") services.ResponseWithJson(w, http.StatusOK, emsState) return @@ -1029,10 +1031,19 @@ func GetEMSState(ip string) *SysState { } } - version := "16.1.1" - if global.Version != "" { - version = global.Version + CapabilityInt := config.GetYamlConfig().OMC.Capability + if CapabilityInt == 0 { + CapabilityInt = 5000 } + snStr := config.GetYamlConfig().OMC.Sn + if snStr == "" { + snStr = "-" + } + expiryDateStr := config.GetYamlConfig().OMC.ExpiryDate + if expiryDateStr == "" { + expiryDateStr = "-" + } + hostName, _ := os.Hostname() dbInfo, _ := dborm.XormGetMySQLVersion() emsState := &SysState{ @@ -1041,10 +1052,10 @@ func GetEMSState(ip string) *SysState { DbInfo: dbInfo, IpAddr: ipAddrs, Port: config.GetYamlConfig().Rest[0].Port, - Version: version, - Capability: 9999999, - SerialNum: config.GetYamlConfig().OMC.Sn, - ExpiryDate: "-", + Version: global.Version, + Capability: CapabilityInt, + SerialNum: snStr, + ExpiryDate: expiryDateStr, HardwareInfo: HardwareInfo{CPUs: getCpuNumber(), Memory: getTotalMemory()}, CpuUsage: *cpuUsage, MemUsage: *memUsage, diff --git a/lib/core/conf/conf.go b/lib/core/conf/conf.go index 7e22479..e43d345 100644 --- a/lib/core/conf/conf.go +++ b/lib/core/conf/conf.go @@ -18,7 +18,7 @@ func InitConfig(configFile string) { // 读取配置文件 err := v.ReadInConfig() if err != nil { - fmt.Printf("读取配置文件失败: %v \n", err) + fmt.Printf("failure to read configuration file: %v \n", err) return } } diff --git a/restagent/config/config.go b/restagent/config/config.go index 8f4951c..10f10c9 100644 --- a/restagent/config/config.go +++ b/restagent/config/config.go @@ -67,7 +67,9 @@ type YamlConfig struct { Vendor string `yaml:"vendor"` Dn string `yaml:"dn"` Chk2Ne bool `yaml:"chk2ne"` + Capability uint32 `yaml:"capability"` Sn string `yaml:"sn"` + ExpiryDate string `yaml:"expiryDate"` CheckSign bool `yaml:"checksign"` RootDir string `yaml:"rootDir"` BinDir string `yaml:"binDir"` diff --git a/restagent/etc/restconf.yaml b/restagent/etc/restconf.yaml index c8f8509..afd257c 100644 --- a/restagent/etc/restconf.yaml +++ b/restagent/etc/restconf.yaml @@ -21,6 +21,14 @@ rest: - ipv4: 0.0.0.0 ipv6: port: 33040 + - ipv4: 0.0.0.0 + ipv6: + port: 33443 + scheme: https + clientAuthType: 0 + caFile: ./etc/certs/omc-ca.crt + certFile: ./etc/certs/omc-server.crt + keyFile: ./etc/certs/omc-server.key webServer: enabled: false @@ -54,12 +62,6 @@ redis: host: "192.168.9.58" # Redis host password: "helloearth" db: 10 # Redis db_num - # UDM sub/auth db - udmuser: - port: 6379 # Redis port - host: "192.168.8.58" - password: "helloearth" - db: 0 # Redis db_num # used to specify the default data source for multiple data resourece defaultDataSourceName: "default" @@ -106,7 +108,9 @@ omc: vendor: "" dn: 4600 chk2ne: false - sn: "-" + capability: 50 + sn: "12345678" + expiryDate: "2099-12-31" checksign: false rootDir: ./ binDir: ./bin diff --git a/restagent/makefile b/restagent/makefile index b61249b..db858a6 100644 --- a/restagent/makefile +++ b/restagent/makefile @@ -1,7 +1,7 @@ # Makefile for rest agent project PROJECT = OMC -VERSION = 2.2412.1 +VERSION = 2.2412.4 PLATFORM = amd64 ARMPLATFORM = aarch64 BUILDDIR = ../../build diff --git a/src/framework/config/config/config.default.yaml b/src/framework/config/config/config.default.yaml index 13b1fff..afda8e3 100644 --- a/src/framework/config/config/config.default.yaml +++ b/src/framework/config/config/config.default.yaml @@ -149,9 +149,9 @@ gorm: type: "mysql" host: "127.0.0.1" port: 3306 - username: "<用户名>" - password: "<密码>" - database: "<数据库>" + username: "" + password: "" + database: "" logging: false # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "default" @@ -162,7 +162,7 @@ redis: default: port: 6379 # Redis port host: "127.0.0.1" # Redis host - password: "<密码>" + password: "" db: 0 # Redis db_num # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "default" diff --git a/src/framework/config/config/config.prod.yaml b/src/framework/config/config/config.prod.yaml index 3125e34..7915c59 100644 --- a/src/framework/config/config/config.prod.yaml +++ b/src/framework/config/config/config.prod.yaml @@ -6,27 +6,27 @@ server: # security 安全 security: csrf: - # 允许调用的域名地址的,例如:http:/// + # 允许调用的域名地址的,例如:http:/// refererWhiteList: - "127.0.0.1" - - "" + - "" # GORM 数据源 gorm: dataSource: default: type: "mysql" - host: "" + host: "" port: 3306 - username: "<用户名>" - password: "<密码>" - database: "<数据库>" + username: "" + password: "" + database: "" # Redis 缓存数据 redis: dataSource: default: port: 6379 # Redis port - host: "" - password: "<密码>" + host: "" + password: "" db: 0 # Redis db_num diff --git a/src/framework/datasource/datasource.go b/src/framework/datasource/datasource.go index 736e48d..0bebed8 100644 --- a/src/framework/datasource/datasource.go +++ b/src/framework/datasource/datasource.go @@ -9,6 +9,7 @@ import ( "be.ems/src/framework/config" "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" "gorm.io/driver/mysql" "gorm.io/gorm" @@ -162,3 +163,19 @@ func ExecDB(source string, sql string, parameters []any) (int64, error) { } return res.RowsAffected, nil } + +// PageNumSize 分页页码记录数 +func PageNumSize(pageNum, pageSize any) (int, int) { + // 记录起始索引 + num := parse.Number(pageNum) + if num < 1 { + num = 1 + } + + // 显示记录数 + size := parse.Number(pageSize) + if size < 0 { + size = 10 + } + return int(num - 1), int(size) +} diff --git a/src/framework/utils/ctx/ctx.go b/src/framework/utils/ctx/ctx.go index b9f2f1e..d5c129d 100644 --- a/src/framework/utils/ctx/ctx.go +++ b/src/framework/utils/ctx/ctx.go @@ -16,6 +16,16 @@ import ( "github.com/gin-gonic/gin" ) +// QueryMapString 查询参数转换Map +func QueryMapString(c *gin.Context) map[string]string { + queryValues := c.Request.URL.Query() + queryParams := make(map[string]string) + for key, values := range queryValues { + queryParams[key] = values[0] + } + return queryParams +} + // QueryMap 查询参数转换Map func QueryMap(c *gin.Context) map[string]any { queryValues := c.Request.URL.Query() diff --git a/src/framework/utils/fetch/fetch.go b/src/framework/utils/fetch/fetch.go index be7cc07..d0075b0 100644 --- a/src/framework/utils/fetch/fetch.go +++ b/src/framework/utils/fetch/fetch.go @@ -12,8 +12,13 @@ import ( "os" "strings" "time" + + libGlobal "be.ems/lib/global" ) +// userAgent 自定义 User-Agent +var userAgent = fmt.Sprintf("OMC/%s", libGlobal.Version) + // Get 发送 GET 请求 // timeout 超时时间(毫秒) func Get(url string, headers map[string]string, timeout int) ([]byte, error) { @@ -29,6 +34,8 @@ func Get(url string, headers map[string]string, timeout int) ([]byte, error) { return nil, err } + req.Header.Set("User-Agent", userAgent) + req.Header.Set("Content-Type", "application/json;charset=UTF-8") for key, value := range headers { req.Header.Set(key, value) } @@ -60,8 +67,8 @@ func Post(url string, data url.Values, headers map[string]string) ([]byte, error return nil, err } + req.Header.Set("User-Agent", userAgent) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - for key, value := range headers { req.Header.Set(key, value) } @@ -100,8 +107,8 @@ func PostJSON(url string, data any, headers map[string]string) ([]byte, error) { return nil, err } - req.Header.Set("Content-Type", "application/json") - + req.Header.Set("User-Agent", userAgent) + req.Header.Set("Content-Type", "application/json;charset=UTF-8") for key, value := range headers { req.Header.Set(key, value) } @@ -156,6 +163,7 @@ func PostUploadFile(url string, params map[string]string, file *os.File) ([]byte return nil, fmt.Errorf("failed to create HTTP request: %v", err) } + req.Header.Set("User-Agent", userAgent) req.Header.Set("Content-Type", writer.FormDataContentType()) client := &http.Client{} @@ -193,6 +201,8 @@ func PutJSON(url string, data any, headers map[string]string) ([]byte, error) { return nil, err } + req.Header.Set("User-Agent", userAgent) + req.Header.Set("Content-Type", "application/json;charset=UTF-8") for key, value := range headers { req.Header.Set(key, value) } @@ -224,6 +234,8 @@ func Delete(url string, headers map[string]string) ([]byte, error) { return nil, err } + req.Header.Set("User-Agent", userAgent) + req.Header.Set("Content-Type", "application/json;charset=UTF-8") for key, value := range headers { req.Header.Set(key, value) } diff --git a/src/modules/common/controller/common.go b/src/modules/common/controller/common.go index 5e2ec70..7a871df 100644 --- a/src/modules/common/controller/common.go +++ b/src/modules/common/controller/common.go @@ -10,15 +10,14 @@ import ( // 实例化控制层 CommontController 结构体 var NewCommont = &CommontController{ - commontService: commonService.NewCommontImpl, + commontService: commonService.NewCommont, } // 通用请求 // // PATH / type CommontController struct { - // 通用请求服务 - commontService commonService.ICommont + commontService *commonService.Commont // 通用请求服务 } // 哈希加密 @@ -36,17 +35,12 @@ func (s *CommontController) I18n(c *gin.Context) { i18nLang := i18n.TKey(language, "i18n") hello := i18n.TKey(language, "hello") - ivs := i18n.TTemplate(language, "errorFields", nil) - errorFields := i18n.TTemplate(language, "errorFields", map[string]any{ - "num": 1000, - "hello": "你好", - "h2o2": false, - "fileName": " ====", + errorFields := i18n.TTemplate(language, "dictData.errLabelExists", map[string]any{ + "name": " ====", }) c.JSON(200, map[string]any{ "lang": language, "i18nLang": i18nLang, - "ivs": ivs, "hello": hello, "errorFields": errorFields, }) diff --git a/src/modules/common/controller/file.go b/src/modules/common/controller/file.go index 6dc67b7..0b1391b 100644 --- a/src/modules/common/controller/file.go +++ b/src/modules/common/controller/file.go @@ -95,7 +95,7 @@ func (s *FileController) Upload(c *gin.Context) { newFileName := upFilePath[strings.LastIndex(upFilePath, "/")+1:] c.JSON(200, result.OkData(map[string]string{ - "url": "http://" + c.Request.Host + upFilePath, + "url": "//" + c.Request.Host + upFilePath, "fileName": upFilePath, "newFileName": newFileName, "originalFileName": formFile.Filename, @@ -160,7 +160,7 @@ func (s *FileController) ChunkMerge(c *gin.Context) { newFileName := mergeFilePath[strings.LastIndex(mergeFilePath, "/")+1:] c.JSON(200, result.OkData(map[string]string{ - "url": "http://" + c.Request.Host + mergeFilePath, + "url": "//" + c.Request.Host + mergeFilePath, "fileName": mergeFilePath, "newFileName": newFileName, "originalFileName": body.FileName, diff --git a/src/modules/common/service/commont.go b/src/modules/common/service/commont.go index e8be8db..2378907 100644 --- a/src/modules/common/service/commont.go +++ b/src/modules/common/service/commont.go @@ -1,7 +1,81 @@ package service -// 通用请求 服务层接口 -type ICommont interface { - // SystemConfigInfo 系统配置信息 - SystemConfigInfo() map[string]string +import ( + "fmt" + + "be.ems/lib/global" + "be.ems/src/framework/config" + "be.ems/src/framework/constants/common" + "be.ems/src/framework/utils/machine" + systemService "be.ems/src/modules/system/service" +) + +// 实例化服务层 Commont 结构体 +var NewCommont = &Commont{ + sysUserService: systemService.NewSysUserImpl, + sysConfigService: systemService.NewSysConfigImpl, +} + +// 通用请求 服务层处理 +type Commont struct { + // 用户信息服务 + sysUserService systemService.ISysUser + // 参数配置服务 + sysConfigService systemService.ISysConfig +} + +// SystemConfigInfo 系统配置信息 +func (s *Commont) SystemConfigInfo() map[string]string { + infoMap := map[string]string{} + // 获取打包注入的全局变量信息 + infoMap["version"] = global.Version + infoMap["buildTime"] = global.BuildTime + // 系统首次使用标记 + launchInfo := machine.LaunchInfo + if launchInfo != nil { + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok { + infoMap[common.LAUNCH_BOOTLOADER] = fmt.Sprint(v) + } else { + infoMap[common.LAUNCH_BOOTLOADER] = "true" + } + } else { + infoMap[common.LAUNCH_BOOTLOADER] = "true" + } + // 用户登录认证 + infoMap["loginAuth"] = fmt.Sprint(config.Get("user.loginAuth")) + // 序列号 + infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn")) + // 获取LOGO类型 + logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type") + infoMap["logoType"] = logoType + // 获取LOGO文件 + filePathIcon := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathIcon") + infoMap["filePathIcon"] = filePathIcon + filePathBrand := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathBrand") + infoMap["filePathBrand"] = filePathBrand + // 获取系统名称 + title := s.sysConfigService.SelectConfigValueByKey("sys.title") + infoMap["title"] = title + // 获取版权声明 + copyright := s.sysConfigService.SelectConfigValueByKey("sys.copyright") + infoMap["copyright"] = copyright + // 获取是否开启用户注册功能 + registerUser := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser") + infoMap["registerUser"] = registerUser + // 获取登录界面背景 + loginBackground := s.sysConfigService.SelectConfigValueByKey("sys.loginBackground") + infoMap["loginBackground"] = loginBackground + // 系统设置-官网网址 + officialUrl := s.sysConfigService.SelectConfigValueByKey("sys.officialUrl") + infoMap["officialUrl"] = officialUrl + // 系统设置-系统使用文档 + helpDoc := s.sysConfigService.SelectConfigValueByKey("sys.helpDoc") + infoMap["helpDoc"] = helpDoc + // 国际化切换 + i18nOpen := s.sysConfigService.SelectConfigValueByKey("sys.i18n.open") + infoMap["i18nOpen"] = i18nOpen + // 国际化默认语言 + i18nDefault := s.sysConfigService.SelectConfigValueByKey("sys.i18n.default") + infoMap["i18nDefault"] = i18nDefault + return infoMap } diff --git a/src/modules/common/service/commont.impl.go b/src/modules/common/service/commont.impl.go deleted file mode 100644 index b84b4d4..0000000 --- a/src/modules/common/service/commont.impl.go +++ /dev/null @@ -1,81 +0,0 @@ -package service - -import ( - "fmt" - - "be.ems/lib/global" - "be.ems/src/framework/config" - "be.ems/src/framework/constants/common" - "be.ems/src/framework/utils/machine" - systemService "be.ems/src/modules/system/service" -) - -// 实例化服务层 CommontImpl 结构体 -var NewCommontImpl = &CommontImpl{ - sysUserService: systemService.NewSysUserImpl, - sysConfigService: systemService.NewSysConfigImpl, -} - -// 通用请求 服务层处理 -type CommontImpl struct { - // 用户信息服务 - sysUserService systemService.ISysUser - // 参数配置服务 - sysConfigService systemService.ISysConfig -} - -// SystemConfigInfo 系统配置信息 -func (s *CommontImpl) SystemConfigInfo() map[string]string { - infoMap := map[string]string{} - // 获取打包注入的全局变量信息 - infoMap["version"] = global.Version - infoMap["buildTime"] = global.BuildTime - // 系统首次使用标记 - launchInfo := machine.LaunchInfo - if launchInfo != nil { - if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok { - infoMap[common.LAUNCH_BOOTLOADER] = fmt.Sprint(v) - } else { - infoMap[common.LAUNCH_BOOTLOADER] = "true" - } - } else { - infoMap[common.LAUNCH_BOOTLOADER] = "true" - } - // 用户登录认证 - infoMap["loginAuth"] = fmt.Sprint(config.Get("user.loginAuth")) - // 序列号 - infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn")) - // 获取LOGO类型 - logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type") - infoMap["logoType"] = logoType - // 获取LOGO文件 - filePathIcon := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathIcon") - infoMap["filePathIcon"] = filePathIcon - filePathBrand := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathBrand") - infoMap["filePathBrand"] = filePathBrand - // 获取系统名称 - title := s.sysConfigService.SelectConfigValueByKey("sys.title") - infoMap["title"] = title - // 获取版权声明 - copyright := s.sysConfigService.SelectConfigValueByKey("sys.copyright") - infoMap["copyright"] = copyright - // 获取是否开启用户注册功能 - registerUser := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser") - infoMap["registerUser"] = registerUser - // 获取登录界面背景 - loginBackground := s.sysConfigService.SelectConfigValueByKey("sys.loginBackground") - infoMap["loginBackground"] = loginBackground - // 系统设置-官网网址 - officialUrl := s.sysConfigService.SelectConfigValueByKey("sys.officialUrl") - infoMap["officialUrl"] = officialUrl - // 系统设置-系统使用文档 - helpDoc := s.sysConfigService.SelectConfigValueByKey("sys.helpDoc") - infoMap["helpDoc"] = helpDoc - // 国际化切换 - i18nOpen := s.sysConfigService.SelectConfigValueByKey("sys.i18n.open") - infoMap["i18nOpen"] = i18nOpen - // 国际化默认语言 - i18nDefault := s.sysConfigService.SelectConfigValueByKey("sys.i18n.default") - infoMap["i18nDefault"] = i18nDefault - return infoMap -} diff --git a/src/modules/network_data/controller/all_alarm.go b/src/modules/network_data/controller/all_alarm.go index 2372de9..b6ba8de 100644 --- a/src/modules/network_data/controller/all_alarm.go +++ b/src/modules/network_data/controller/all_alarm.go @@ -48,8 +48,8 @@ func (s *AlarmController) List(c *gin.Context) { querys.RmUID = neInfo.RmUID // 查询数据 - data := s.alarmService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.alarmService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // 告警删除 diff --git a/src/modules/network_data/controller/amf.go b/src/modules/network_data/controller/amf.go index cc78b1e..cdbe143 100644 --- a/src/modules/network_data/controller/amf.go +++ b/src/modules/network_data/controller/amf.go @@ -1,24 +1,20 @@ package controller import ( - "encoding/json" "fmt" - "strconv" "strings" "time" "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" - "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "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" - sysService "be.ems/src/modules/system/service" + "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" ) // 实例化控制层 AMFController 结构体 @@ -47,16 +43,16 @@ func (s *AMFController) UEList(c *gin.Context) { } // 查询网元获取IP - // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - // if neInfo.NeId != querys.NeID || neInfo.IP == "" { - // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - // return - // } - // querys.RmUID = neInfo.RmUID + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("AMF", querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID // 查询数据 - data := s.ueEventService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.ueEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // UE会话删除 @@ -92,7 +88,7 @@ func (s *AMFController) UEExport(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 var querys model.UEEventAMFQuery - if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + if err := c.ShouldBindBodyWithJSON(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -100,105 +96,24 @@ func (s *AMFController) UEExport(c *gin.Context) { if querys.PageSize > 10000 { querys.PageSize = 10000 } - data := s.ueEventService.SelectPage(querys) - if parse.Number(data["total"]) == 0 { + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("AMF", querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID + rows, total := s.ueEventService.SelectPage(querys) + if total == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.UEEventAMF) // 导出文件名称 fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "IMSI", - "C1": "Event Type", - "D1": "Result", - "E1": "Time", - } - // 读取字典数据 UE 事件类型 - dictUEEventType := sysService.NewSysDictData.SelectDictDataByType("ue_event_type") - // 读取字典数据 UE 事件认证代码类型 - dictUEAauthCode := sysService.NewSysDictData.SelectDictDataByType("ue_auth_code") - // 读取字典数据 UE 事件CM状态 - dictUEEventCmState := sysService.NewSysDictData.SelectDictDataByType("ue_event_cm_state") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var eventJSON map[string]interface{} - err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) - if err != nil { - logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) - continue - } - - // 取IMSI - imsi := "" - if v, ok := eventJSON["imsi"]; ok && v != nil { - imsi = v.(string) - } - // 取类型 - eventType := "" - for _, v := range dictUEEventType { - if row.EventType == v.DictValue { - eventType = i18n.TKey(language, v.DictLabel) - break - } - } - // 取结果 - eventResult := "" - // 取时间 - timeStr := "" - if row.EventType == "auth-result" { - if v, ok := eventJSON["authTime"]; ok && v != nil { - timeStr = v.(string) - } - if v, ok := eventJSON["authCode"]; ok && v != nil { - eventResult = v.(string) - for _, v := range dictUEAauthCode { - if eventResult == v.DictValue { - eventResult = i18n.TKey(language, v.DictLabel) - break - } - } - } - } - if row.EventType == "detach" { - if v, ok := eventJSON["detachTime"]; ok && v != nil { - timeStr = v.(string) - } - eventResult = "Success" - } - if row.EventType == "cm-state" { - if v, ok := eventJSON["changeTime"]; ok && v != nil { - timeStr = v.(string) - } - if v, ok := eventJSON["status"]; ok && v != nil { - eventResult = fmt.Sprint(v) - for _, v := range dictUEEventCmState { - if eventResult == v.DictValue { - eventResult = i18n.TKey(language, v.DictLabel) - break - } - } - } - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: imsi, - "C" + idx: eventType, - "D" + idx: eventResult, - "E" + idx: timeStr, - }) - } - // 导出数据表格 - saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -206,3 +121,66 @@ func (s *AMFController) UEExport(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } + +// 接入基站信息列表 +// +// GET /nb/list +func (s *AMFController) NbInfoList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + NbId string `form:"id"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("AMF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.AMFNbInfoList(neInfo, map[string]string{ + "id": query.NbId, + }) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(data)) +} + +// 接入基站状态信息列表 +// +// GET /nb/list-cfg +func (s *AMFController) NbStateList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("AMF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.AMFGnbStateList(neInfo) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(data)) +} diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 60aff2b..3b4aaa9 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -1,25 +1,20 @@ package controller import ( - "encoding/json" "fmt" - "strconv" "strings" "time" "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "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" - sysService "be.ems/src/modules/system/service" + "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" ) // 实例化控制层 IMSController 结构体 @@ -56,8 +51,8 @@ func (s *IMSController) CDRList(c *gin.Context) { querys.RmUID = neInfo.RmUID // 查询数据 - data := s.cdrEventService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // CDR会话删除 @@ -93,7 +88,7 @@ func (s *IMSController) CDRExport(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 var querys model.CDREventIMSQuery - if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + if err := c.ShouldBindBodyWithJSON(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -108,106 +103,17 @@ func (s *IMSController) CDRExport(c *gin.Context) { return } querys.RmUID = neInfo.RmUID - data := s.cdrEventService.SelectPage(querys) - if parse.Number(data["total"]) == 0 { + rows, total := s.cdrEventService.SelectPage(querys) + if total == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.CDREventIMS) // 导出文件名称 fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "Record Behavior", - "C1": "Type", - "D1": "Caller", - "E1": "Called", - "F1": "Duration", - "G1": "Result", - "H1": "Time", - } - // 读取字典数据 CDR SIP响应代码类别类型 - dictCDRSipCode := sysService.NewSysDictData.SelectDictDataByType("cdr_sip_code") - // 读取字典数据 CDR 呼叫类型 - dictCDRCallType := sysService.NewSysDictData.SelectDictDataByType("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]interface{} - err := json.Unmarshal([]byte(row.CDRJSONStr), &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) - } - // 被叫 - called := "" - if v, ok := cdrJSON["calledParty"]; ok && v != nil { - called = v.(string) - } - // 主叫 - caller := "" - if v, ok := cdrJSON["callerParty"]; ok && v != nil { - caller = v.(string) - } - // 呼叫类型 - callType := "sms" - callTypeLable := "SMS" - if v, ok := cdrJSON["callType"]; ok && v != nil { - callType = v.(string) - for _, v := range dictCDRCallType { - if callType == v.DictValue { - callTypeLable = i18n.TKey(language, v.DictLabel) - break - } - } - } - // 时长 - duration := "-" - if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { - duration = fmt.Sprint(parse.Number(v)) - } - // 呼叫结果 非短信都有code作为结果 sms短信都ok - callResult := "Success" - if v, ok := cdrJSON["cause"]; ok && v != nil && callType != "sms" { - cause := fmt.Sprint(v) - for _, v := range dictCDRSipCode { - if cause == v.DictValue { - callResult = i18n.TKey(language, v.DictLabel) - break - } - } - } - // 取时间 - timeStr := "" - if v, ok := cdrJSON["releaseTime"]; ok && v != nil { - releaseTime := parse.Number(v) - timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: recordType, - "C" + idx: callTypeLable, - "D" + idx: caller, - "E" + idx: called, - "F" + idx: duration, - "G" + idx: callResult, - "H" + idx: timeStr, - }) - } - // 导出数据表格 - saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -215,3 +121,68 @@ func (s *IMSController) CDRExport(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } + +// 在线会话用户数量 +// +// GET /session/num +func (s *IMSController) UeSessionNum(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("IMS", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + num, err := neFetchlink.IMSUeSessionNum(neInfo) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(num)) +} + +// 在线会话用户列表信息 +// +// GET /session/list +func (s *IMSController) UeSessionList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + IMSI string `form:"imsi"` + MSISDN string `form:"msisdn"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("IMS", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.IMSUeSessionList(neInfo, map[string]string{ + "imsi": query.IMSI, + "msisdn": query.MSISDN, + }) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(data)) +} diff --git a/src/modules/network_data/controller/mme.go b/src/modules/network_data/controller/mme.go index ac26d60..a6f4933 100644 --- a/src/modules/network_data/controller/mme.go +++ b/src/modules/network_data/controller/mme.go @@ -1,23 +1,18 @@ package controller import ( - "encoding/json" "fmt" - "strconv" "strings" "time" "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "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" - sysService "be.ems/src/modules/system/service" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" ) @@ -48,16 +43,16 @@ func (s *MMEController) UEList(c *gin.Context) { } // 查询网元获取IP - // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - // if neInfo.NeId != querys.NeID || neInfo.IP == "" { - // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - // return - // } - // querys.RmUID = neInfo.RmUID + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("MME", querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID // 查询数据 - data := s.ueEventService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.ueEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // UE会话删除 @@ -101,94 +96,24 @@ func (s *MMEController) UEExport(c *gin.Context) { if querys.PageSize > 10000 { querys.PageSize = 10000 } - data := s.ueEventService.SelectPage(querys) - if parse.Number(data["total"]) == 0 { + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("MME", querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID + rows, total := s.ueEventService.SelectPage(querys) + if total == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.UEEventMME) // 导出文件名称 fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "IMSI", - "C1": "Event Type", - "D1": "Result", - "E1": "Time", - } - // 读取字典数据 UE 事件类型 - dictUEEventType := sysService.NewSysDictData.SelectDictDataByType("ue_event_type") - // 读取字典数据 UE 事件认证代码类型 - dictUEAauthCode := sysService.NewSysDictData.SelectDictDataByType("ue_auth_code") - // 读取字典数据 UE 事件CM状态 - dictUEEventCmState := sysService.NewSysDictData.SelectDictDataByType("ue_event_cm_state") - // 从第二行开始的数据 - dataCells := make([]map[string]any, 0) - for i, row := range rows { - idx := strconv.Itoa(i + 2) - // 解析 JSON 字符串为 map - var eventJSON map[string]interface{} - err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) - if err != nil { - logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) - continue - } - - // 取IMSI - imsi := "" - if v, ok := eventJSON["imsi"]; ok && v != nil { - imsi = v.(string) - } - // 取类型 - eventType := row.EventType - for _, v := range dictUEEventType { - if row.EventType == v.DictValue { - eventType = i18n.TKey(language, v.DictLabel) - break - } - } - // 取结果 - eventResult := "" - if v, ok := eventJSON["result"]; ok && v != nil { - eventResult = v.(string) - if row.EventType == "auth-result" { - for _, v := range dictUEAauthCode { - if eventResult == v.DictValue { - eventResult = i18n.TKey(language, v.DictLabel) - break - } - } - } - if row.EventType == "cm-state" { - for _, v := range dictUEEventCmState { - if eventResult == v.DictValue { - eventResult = i18n.TKey(language, v.DictLabel) - break - } - } - } - } - // 取时间 - timeStr := "" - if v, ok := eventJSON["timestamp"]; ok && v != nil { - rowTime := parse.Number(v) - timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: imsi, - "C" + idx: eventType, - "D" + idx: eventResult, - "E" + idx: timeStr, - }) - } - // 导出数据表格 - saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -196,3 +121,36 @@ func (s *MMEController) UEExport(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } + +// 接入基站信息列表 +// +// GET /nb/list +func (s *MMEController) NbInfoList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + NbId string `form:"id"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("MME", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.MMENbInfoList(neInfo, map[string]string{ + "id": query.NbId, + }) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(data)) +} diff --git a/src/modules/network_data/controller/sgwc.go b/src/modules/network_data/controller/sgwc.go new file mode 100644 index 0000000..f528c41 --- /dev/null +++ b/src/modules/network_data/controller/sgwc.go @@ -0,0 +1,123 @@ +package controller + +import ( + "fmt" + "strings" + "time" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/vo/result" + "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" +) + +// 实例化控制层 SGWCController 结构体 +var NewSGWC = &SGWCController{ + neInfoService: neService.NewNeInfo, + cdrEventService: neDataService.NewCDREventSGWC, + udmUserInfoService: neDataService.NewUDMUserInfo, +} + +// 网元SGWC +// +// PATH /SGWC +type SGWCController struct { + neInfoService *neService.NeInfo // 网元信息服务 + cdrEventService *neDataService.CDREventSGWC // CDR会话事件服务 + udmUserInfoService *neDataService.UDMUserInfo // UDM用户信息服务 +} + +// CDR会话列表 +// +// GET /cdr/list +func (s *SGWCController) CDRList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys model.CDREventSGWCQuery + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 rmUID + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID + + // 查询数据 + rows, total := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) +} + +// CDR会话删除 +// +// DELETE /cdr/:cdrIds +func (s *SGWCController) CDRRemove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + cdrIds := c.Param("cdrIds") + if cdrIds == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 处理字符转id数组后去重 + ids := strings.Split(cdrIds, ",") + uniqueIDs := parse.RemoveDuplicates(ids) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + rows, err := s.cdrEventService.DeleteByIds(uniqueIDs) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, result.OkMsg(msg)) +} + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *SGWCController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventSGWCQuery + if err := c.ShouldBindBodyWithJSON(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + // 查询网元信息 rmUID + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + querys.RmUID = neInfo.RmUID + rows, total := s.cdrEventService.SelectPage(querys) + if total == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + + // 导出文件名称 + fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 导出数据表格 + saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index 094b484..fb29352 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -1,16 +1,12 @@ package controller import ( - "encoding/json" "fmt" - "strconv" "strings" "time" "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" - "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" @@ -57,8 +53,8 @@ func (s *SMFController) CDRList(c *gin.Context) { querys.RmUID = neInfo.RmUID // 查询数据 - data := s.cdrEventService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // CDR会话删除 @@ -109,206 +105,17 @@ func (s *SMFController) CDRExport(c *gin.Context) { return } querys.RmUID = neInfo.RmUID - data := s.cdrEventService.SelectPage(querys) - if parse.Number(data["total"]) == 0 { + rows, total := s.cdrEventService.SelectPage(querys) + if total == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.CDREventSMF) // 导出文件名称 fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) - // 第一行表头标题 - 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.CDRJSONStr), &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) - } - } - - // 数据量上行链路 - dataVolumeUplink := []string{} - // 数据量下行链路 - dataVolumeDownlink := []string{} - // 数据总量 - dataTotalVolume := []string{} - - 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 = append(dataVolumeUplink, fmt.Sprint(parse.Number(dup))) - } - if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { - dataVolumeDownlink = append(dataVolumeDownlink, fmt.Sprint(parse.Number(ddown))) - } - if dt, dtOk := udata["dataTotalVolume"]; dtOk { - dataTotalVolume = append(dataTotalVolume, fmt.Sprint(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) - } - } - - // pduSessionChargingInformation = fmt.Sprintf(`User Identifier: %s - // SSC Mode: %s RAT Type: %s DNN ID: %s - // PDU Type: %s - // PDU IPv4 Address: %s - // PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID, PDU_Type, PDU_IPv4, PDU_IPv6) - } - - // 记录网络参数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: strings.Join(dataVolumeUplink, ","), - "H" + idx: strings.Join(dataVolumeDownlink, ","), - "I" + idx: strings.Join(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, - }) - } - // 导出数据表格 - saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -317,9 +124,39 @@ func (s *SMFController) CDRExport(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } +// 在线订阅用户数量 +// +// GET /sub/num +func (s *SMFController) SubUserNum(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("SMF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + num, err := neFetchlink.SMFSubNum(neInfo) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.OkData(num)) +} + // 在线订阅用户列表信息 // -// GET /subscribers +// GET /sub/list func (s *SMFController) SubUserList(c *gin.Context) { language := ctx.AcceptLanguage(c) var query struct { @@ -334,7 +171,7 @@ func (s *SMFController) SubUserList(c *gin.Context) { return } - // 查询网元信息 rmUID + // 查询网元信息 neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("SMF", query.NeId) if neInfo.NeId != query.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) @@ -364,7 +201,7 @@ func (s *SMFController) SubUserList(c *gin.Context) { imsiStr = strings.TrimPrefix(imsiStr, "imsi-") item["imsi"] = imsiStr // 查UDM拓展信息 - info := s.udmUserInfoService.SelectByIMSIAndNeID(imsiStr, "") + info := s.udmUserInfoService.SelectByIMSIAndNeID(imsiStr, "%") item["remark"] = info.Remark } if v, ok := item["msisdn"]; ok && v != nil { diff --git a/src/modules/network_data/controller/smsc.go b/src/modules/network_data/controller/smsc.go index 167d097..929b0b9 100644 --- a/src/modules/network_data/controller/smsc.go +++ b/src/modules/network_data/controller/smsc.go @@ -1,24 +1,19 @@ package controller import ( - "encoding/json" "fmt" - "strconv" "strings" "time" "be.ems/src/framework/i18n" - "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" - "be.ems/src/framework/utils/date" - "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "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" - "github.com/gin-gonic/gin/binding" ) // 实例化控制层 SMSCController 结构体 @@ -55,8 +50,8 @@ func (s *SMSCController) CDRList(c *gin.Context) { querys.RmUID = neInfo.RmUID // 查询数据 - data := s.cdrEventService.SelectPage(querys) - c.JSON(200, result.Ok(data)) + rows, total := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"rows": rows, "total": total})) } // CDR会话删除 @@ -92,7 +87,7 @@ func (s *SMSCController) CDRExport(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 var querys model.CDREventSMSCQuery - if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + if err := c.ShouldBindBodyWithJSON(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -107,85 +102,17 @@ func (s *SMSCController) CDRExport(c *gin.Context) { return } querys.RmUID = neInfo.RmUID - data := s.cdrEventService.SelectPage(querys) - if parse.Number(data["total"]) == 0 { + rows, total := s.cdrEventService.SelectPage(querys) + if total == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.CDREventSMSC) // 导出文件名称 fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) - // 第一行表头标题 - headerCells := map[string]string{ - "A1": "ID", - "B1": "Record Behavior", - "C1": "Service Type", - "D1": "Caller", - "E1": "Called", - "F1": "Result", - "G1": "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.CDRJSONStr), &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" - } - } - // 取时间 - timeStr := "" - if v, ok := cdrJSON["updateTime"]; ok && v != nil { - releaseTime := parse.Number(v) - timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) - } - - dataCells = append(dataCells, map[string]any{ - "A" + idx: row.ID, - "B" + idx: recordType, - "C" + idx: serviceType, - "D" + idx: caller, - "E" + idx: called, - "F" + idx: callResult, - "G" + idx: timeStr, - }) - } - // 导出数据表格 - saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return diff --git a/src/modules/network_data/model/alarm.go b/src/modules/network_data/model/alarm.go index 4e4bc9a..3c898ed 100644 --- a/src/modules/network_data/model/alarm.go +++ b/src/modules/network_data/model/alarm.go @@ -4,37 +4,37 @@ import "time" // Alarm 告警数据对象 alarm type Alarm struct { - ID string `json:"id" gorm:"id"` - AlarmSeq string `json:"alarmSeq" gorm:"alarm_seq"` - AlarmId string `json:"alarmId" gorm:"alarm_id"` - AlarmTitle string `json:"alarmTitle" gorm:"alarm_title"` - NeType string `json:"neType" gorm:"ne_type"` - NeId string `json:"neId" gorm:"ne_id"` - AlarmCode string `json:"alarmCode" gorm:"alarm_code"` - EventTime time.Time `json:"eventTime" gorm:"event_time"` - AlarmType string `json:"alarmType" gorm:"alarm_type"` - OrigSeverity string `json:"origSeverity" gorm:"orig_severity"` // 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - PerceivedSeverity string `json:"perceivedSeverity" gorm:"perceived_severity"` // 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) - PvFlag string `json:"pvFlag" gorm:"pv_flag"` - NeName string `json:"neName" gorm:"ne_name"` - ObjectUid string `json:"objectUid" gorm:"object_uid"` - ObjectName string `json:"objectName" gorm:"object_name"` - ObjectType string `json:"objectType" gorm:"object_type"` - LocationInfo string `json:"locationInfo" gorm:"location_info"` - Province string `json:"province" gorm:"province"` - AlarmStatus string `json:"alarmStatus" gorm:"alarm_status"` // 0:clear, 1:active - SpecificProblem string `json:"specificProblem" gorm:"specific_problem"` - SpecificProblemId string `json:"specificProblemId" gorm:"specific_problem_id"` - AddInfo string `json:"addInfo" gorm:"add_info"` - Counter string `json:"counter" gorm:"counter"` - LatestEventTime time.Time `json:"latestEventTime" gorm:"latest_event_time"` - AckState string `json:"ackState" gorm:"ack_state"` // 0: Unacked, 1: Acked - AckTime time.Time `json:"ackTime" gorm:"ack_time"` - AckUser string `json:"ackUser" gorm:"ack_user"` - ClearType string `json:"clearType" gorm:"clear_type"` // 0: Unclear, 1: AutoClear, 2: ManualClear - ClearTime time.Time `json:"clearTime" gorm:"clear_time"` - ClearUser string `json:"clearUser" gorm:"clear_user"` - Timestamp time.Time `json:"timestamp" gorm:"timestamp"` + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + AlarmSeq string `json:"alarmSeq" gorm:"column:alarm_seq"` + AlarmId string `json:"alarmId" gorm:"column:alarm_id"` + AlarmTitle string `json:"alarmTitle" gorm:"column:alarm_title"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeId string `json:"neId" gorm:"column:ne_id"` + AlarmCode string `json:"alarmCode" gorm:"column:alarm_code"` + EventTime time.Time `json:"eventTime" gorm:"column:event_time"` + AlarmType string `json:"alarmType" gorm:"column:alarm_type"` + OrigSeverity string `json:"origSeverity" gorm:"column:orig_severity"` // 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) + PerceivedSeverity string `json:"perceivedSeverity" gorm:"column:perceived_severity"` // 1: Critical, 2: Major, 3: Minor, 4: Warning, 5: Event(Only VNF) + PvFlag string `json:"pvFlag" gorm:"column:pv_flag"` + NeName string `json:"neName" gorm:"column:ne_name"` + ObjectUid string `json:"objectUid" gorm:"column:object_uid"` + ObjectName string `json:"objectName" gorm:"column:object_name"` + ObjectType string `json:"objectType" gorm:"column:object_type"` + LocationInfo string `json:"locationInfo" gorm:"column:location_info"` + Province string `json:"province" gorm:"column:province"` + AlarmStatus string `json:"alarmStatus" gorm:"column:alarm_status"` // 0:clear, 1:active + SpecificProblem string `json:"specificProblem" gorm:"column:specific_problem"` + SpecificProblemId string `json:"specificProblemId" gorm:"column:specific_problem_id"` + AddInfo string `json:"addInfo" gorm:"column:add_info"` + Counter string `json:"counter" gorm:"column:counter"` + LatestEventTime time.Time `json:"latestEventTime" gorm:"column:latest_event_time"` + AckState string `json:"ackState" gorm:"column:ack_state"` // 0: Unacked, 1: Acked + AckTime time.Time `json:"ackTime" gorm:"column:ack_time"` + AckUser string `json:"ackUser" gorm:"column:ack_user"` + ClearType string `json:"clearType" gorm:"column:clear_type"` // 0: Unclear, 1: AutoClear, 2: ManualClear + ClearTime time.Time `json:"clearTime" gorm:"column:clear_time"` + ClearUser string `json:"clearUser" gorm:"column:clear_user"` + Timestamp time.Time `json:"timestamp" gorm:"column:timestamp"` } // TableName 表名称 diff --git a/src/modules/network_data/model/cdr_event_ims.go b/src/modules/network_data/model/cdr_event_ims.go index 60973fa..c6e463b 100644 --- a/src/modules/network_data/model/cdr_event_ims.go +++ b/src/modules/network_data/model/cdr_event_ims.go @@ -13,6 +13,11 @@ type CDREventIMS struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } +// TableName 表名称 +func (*CDREventIMS) TableName() string { + return "cdr_event_ims" +} + // CDREventIMSQuery CDR会话对象IMS查询参数结构体 type CDREventIMSQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型IMS diff --git a/src/modules/network_data/model/cdr_event_sgwc.go b/src/modules/network_data/model/cdr_event_sgwc.go new file mode 100644 index 0000000..fedf6a4 --- /dev/null +++ b/src/modules/network_data/model/cdr_event_sgwc.go @@ -0,0 +1,36 @@ +package model + +import "time" + +// CDREventSGWC CDR会话对象SGWC cdr_event_sgwc +type CDREventSGWC struct { + ID string `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"` + CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` + + // ====== 非数据库字段属性 ====== +} + +// 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"` + StartTime string `json:"startTime" form:"startTime"` + EndTime string `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 index c076da1..69e6a06 100644 --- a/src/modules/network_data/model/cdr_event_smf.go +++ b/src/modules/network_data/model/cdr_event_smf.go @@ -15,6 +15,11 @@ type CDREventSMF struct { // ====== 非数据库字段属性 ====== } +// TableName 表名称 +func (*CDREventSMF) TableName() string { + return "cdr_event_smf" +} + // CDREventSMFQuery CDR会话对象SMF查询参数结构体 type CDREventSMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // SMF diff --git a/src/modules/network_data/model/cdr_event_smsc.go b/src/modules/network_data/model/cdr_event_smsc.go index 6a50e59..a851a9b 100644 --- a/src/modules/network_data/model/cdr_event_smsc.go +++ b/src/modules/network_data/model/cdr_event_smsc.go @@ -13,6 +13,11 @@ type CDREventSMSC struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } +// TableName 表名称 +func (*CDREventSMSC) TableName() string { + return "cdr_event_smsc" +} + // CDREventSMSCQuery CDR会话对象SMSC查询参数结构体 type CDREventSMSCQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型SMSC diff --git a/src/modules/network_data/model/udm_user_info.go b/src/modules/network_data/model/udm_user_info.go index 470a9ab..3f3ea4f 100644 --- a/src/modules/network_data/model/udm_user_info.go +++ b/src/modules/network_data/model/udm_user_info.go @@ -6,7 +6,7 @@ type UDMUserInfo struct { IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码 NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 - Remark string `json:"remark" gorm:"remark"` // 备注 + Remark string `json:"remark" gorm:"column:remark"` // 备注 } // TableName 表名称 diff --git a/src/modules/network_data/model/ue_event_amf.go b/src/modules/network_data/model/ue_event_amf.go index 6fa549b..a464926 100644 --- a/src/modules/network_data/model/ue_event_amf.go +++ b/src/modules/network_data/model/ue_event_amf.go @@ -14,6 +14,11 @@ type UEEventAMF struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } +// TableName 表名称 +func (*UEEventAMF) TableName() string { + return "ue_event_amf" +} + // UEEventAMFQuery UE会话对象AMF查询参数结构体 type UEEventAMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF diff --git a/src/modules/network_data/model/ue_event_mme.go b/src/modules/network_data/model/ue_event_mme.go index 8ceab12..bff678a 100644 --- a/src/modules/network_data/model/ue_event_mme.go +++ b/src/modules/network_data/model/ue_event_mme.go @@ -14,6 +14,11 @@ type UEEventMME struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } +// TableName 表名称 +func (*UEEventMME) TableName() string { + return "ue_event_mme" +} + // UEEventMMEQuery UE会话对象MME查询参数结构体 type UEEventMMEQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持MME diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index a114f75..ee2db3a 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -59,6 +59,14 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewIMS.CDRExport, ) + imsGroup.GET("/session/num", + middleware.PreAuthorize(nil), + controller.NewIMS.UeSessionNum, + ) + imsGroup.GET("/session/list", + middleware.PreAuthorize(nil), + controller.NewIMS.UeSessionList, + ) } // 网元SMSC @@ -97,7 +105,11 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewSMF.CDRExport, ) - smfGroup.GET("/subscribers", + smfGroup.GET("/sub/num", + middleware.PreAuthorize(nil), + controller.NewSMF.SubUserNum, + ) + smfGroup.GET("/sub/list", middleware.PreAuthorize(nil), controller.NewSMF.SubUserList, ) @@ -120,6 +132,14 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewAMF.UEExport, ) + amfGroup.GET("/nb/list", + middleware.PreAuthorize(nil), + controller.NewAMF.NbInfoList, + ) + amfGroup.GET("/nb/list-cfg", + middleware.PreAuthorize(nil), + controller.NewAMF.NbStateList, + ) } // 网元UPF @@ -256,5 +276,28 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewMME.UEExport, ) + mmeGroup.GET("/nb/list", + middleware.PreAuthorize(nil), + controller.NewMME.NbInfoList, + ) + } + + // 网元SGWC + sgwcGroup := neDataGroup.Group("/sgwc") + { + sgwcGroup.GET("/cdr/list", + middleware.PreAuthorize(nil), + controller.NewSGWC.CDRList, + ) + sgwcGroup.DELETE("/cdr/:cdrIds", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewSGWC.CDRRemove, + ) + sgwcGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewSGWC.CDRExport, + ) } } diff --git a/src/modules/network_data/repository/alarm.go b/src/modules/network_data/repository/alarm.go index 41d5032..754c0cb 100644 --- a/src/modules/network_data/repository/alarm.go +++ b/src/modules/network_data/repository/alarm.go @@ -1,194 +1,103 @@ package repository import ( - "fmt" "strings" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 Alarm 结构体 -var NewAlarm = &Alarm{ - selectSql: `select - id, alarm_seq, alarm_id, alarm_title, ne_type, ne_id, alarm_code, event_time, - alarm_type, orig_severity, perceived_severity, pv_flag, ne_name, object_uid, object_name, - object_type, location_info, province, alarm_status, specific_problem, specific_problem_id, - add_info, counter, latest_event_time, ack_state, ack_time, ack_user, clear_type, - clear_time, clear_user, timestamp - from alarm`, - - resultMap: map[string]string{ - "id": "ID", - "alarm_seq": "AlarmSeq", - "alarm_id": "AlarmId", - "alarm_title": "AlarmTitle", - "ne_type": "NeType", - "ne_id": "NeId", - "alarm_code": "AlarmCode", - "event_time": "EventTime", - "alarm_type": "AlarmType", - "orig_severity": "OrigSeverity", - "perceived_severity": "PerceivedSeverity", - "pv_flag": "PvFlag", - "ne_name": "NeName", - "object_uid": "ObjectUid", - "object_name": "ObjectName", - "object_type": "ObjectType", - "location_info": "LocationInfo", - "province": "Province", - "alarm_status": "AlarmStatus", - "specific_problem": "SpecificProblem", - "specific_problem_id": "SpecificProblemId", - "add_info": "AddInfo", - "counter": "Counter", - "latest_event_time": "LatestEventTime", - "ack_state": "AckState", - "ack_time": "AckTime", - "ack_user": "AckUser", - "clear_type": "ClearType", - "clear_time": "ClearTime", - "clear_user": "ClearUser", - "timestamp": "Timestamp", - }, -} +var NewAlarm = &Alarm{} // Alarm 告警 数据层处理 -type Alarm struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type Alarm struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *Alarm) convertResultRows(rows []map[string]any) []model.Alarm { - arr := make([]model.Alarm, 0) - for _, row := range rows { - item := model.Alarm{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *Alarm) SelectPage(querys model.AlarmQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r Alarm) SelectByPage(querys model.AlarmQuery) ([]model.Alarm, int64) { + tx := datasource.DB("").Model(&model.Alarm{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "object_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - params = append(params, querys.StartTime) + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] + } + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - params = append(params, querys.EndTime) + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] + } + tx = tx.Where("timestamp <= ?", endTime) } if querys.OrigSeverity != "" { eventTypes := strings.Split(querys.OrigSeverity, ",") - placeholder := repo.KeyPlaceholderByQuery(len(eventTypes)) - conditions = append(conditions, fmt.Sprintf("orig_severity in (%s)", placeholder)) - for _, eventType := range eventTypes { - params = append(params, eventType) - } + tx = tx.Where("orig_severity in (%s)", eventTypes) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.Alarm{} - result := map[string]any{ - "total": 0, - "rows": []model.Alarm{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from alarm" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 func (r *Alarm) SelectByIds(ids []string) []model.Alarm { - placeholder := repo.KeyPlaceholderByQuery(len(ids)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ids) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.Alarm{} + rows := []model.Alarm{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.DB("").Model(&model.Alarm{}) + // 构建查询条件 + 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 *Alarm) DeleteByIds(ids []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(ids)) - sql := "delete from alarm where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ids) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) + if len(ids) <= 0 { return 0 } - return results + tx := datasource.DB("").Where("id in ?", ids) + if err := tx.Delete(&model.Alarm{}).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_ims.go b/src/modules/network_data/repository/cdr_event_ims.go index 598e848..31dc729 100644 --- a/src/modules/network_data/repository/cdr_event_ims.go +++ b/src/modules/network_data/repository/cdr_event_ims.go @@ -6,184 +6,110 @@ import ( "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 CDREventIMS 结构体 -var NewCDREventIMS = &CDREventIMS{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_ims`, +var NewCDREventIMS = &CDREventIMS{} - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "ne_name": "NeName", - "rm_uid": "RmUID", - "timestamp": "Timestamp", - "cdr_json": "CDRJSONStr", - "created_at": "CreatedAt", - }, -} +// CDREventIMS CDR会话事件 数据层处理 +type CDREventIMS struct{} -// CDREventIMS CDR会话事件IMS 数据层处理 -type CDREventIMS struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *CDREventIMS) convertResultRows(rows []map[string]any) []model.CDREventIMS { - arr := make([]model.CDREventIMS, 0) - for _, row := range rows { - item := model.CDREventIMS{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *CDREventIMS) SelectPage(querys model.CDREventIMSQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r CDREventIMS) SelectByPage(querys model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { + tx := datasource.DB("").Model(&model.CDREventIMS{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - if len(querys.StartTime) == 13 { - querys.StartTime = querys.StartTime[:10] + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] } - params = append(params, querys.StartTime) + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - if len(querys.EndTime) == 13 { - querys.EndTime = querys.EndTime[:10] + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] } - params = append(params, querys.EndTime) + tx = tx.Where("timestamp <= ?", endTime) } if querys.CallerParty != "" { - conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.callerParty') = ?") - params = append(params, querys.CallerParty) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", querys.CallerParty) } if querys.CalledParty != "" { - conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?") - params = append(params, querys.CalledParty) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", querys.CalledParty) } - // MySQL8支持的 - // if querys.RecordType != "" { - // recordTypes := strings.Split(querys.RecordType, ",") - // placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) - // conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) - // for _, recordType := range recordTypes { - // params = append(params, recordType) - // } - // } - // Mariadb不支持json in查询改or + if querys.RecordType != "" { recordTypes := strings.Split(querys.RecordType, ",") var queryStrArr []string for _, recordType := range recordTypes { - queryStrArr = append(queryStrArr, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") - params = append(params, recordType) + queryStrArr = append(queryStrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) } - conditions = append(conditions, fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) + tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.CDREventIMS{} - result := map[string]any{ - "total": 0, - "rows": []model.CDREventIMS{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from cdr_event_ims" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 -func (r *CDREventIMS) SelectByIds(cdrIds []string) []model.CDREventIMS { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.CDREventIMS{} +func (r *CDREventIMS) SelectByIds(ids []string) []model.CDREventIMS { + rows := []model.CDREventIMS{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.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(cdrIds []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - sql := "delete from cdr_event_ims where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +func (r *CDREventIMS) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { return 0 } - return results + tx := datasource.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 new file mode 100644 index 0000000..cf87e9d --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_sgwc.go @@ -0,0 +1,103 @@ +package repository + +import ( + "be.ems/src/framework/datasource" + "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(querys model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { + tx := datasource.DB("").Model(&model.CDREventSGWC{}) + // 查询条件拼接 + if querys.NeType != "" { + tx = tx.Where("ne_type = ?", querys.NeType) + } + if querys.RmUID != "" { + tx = tx.Where("rm_uid = ?", querys.RmUID) + } + if querys.StartTime != "" { + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] + } + tx = tx.Where("timestamp >= ?", startTime) + } + if querys.EndTime != "" { + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] + } + tx = tx.Where("timestamp <= ?", endTime) + } + if querys.IMSI != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') = ?", querys.IMSI) + } + if querys.MSISDN != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') = ?", querys.MSISDN) + } + + // 查询结果 + var total int64 = 0 + rows := []model.CDREventSGWC{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 排序 + if querys.SortField != "" { + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" + } + tx = tx.Order(sortField) + } + + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.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 []string) []model.CDREventSGWC { + rows := []model.CDREventSGWC{} + if len(ids) <= 0 { + return rows + } + tx := datasource.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 []string) int64 { + if len(ids) <= 0 { + return 0 + } + tx := datasource.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 index 14f49cf..57341f4 100644 --- a/src/modules/network_data/repository/cdr_event_smf.go +++ b/src/modules/network_data/repository/cdr_event_smf.go @@ -1,170 +1,103 @@ package repository import ( - "fmt" - "strings" - "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 CDREventSMF 结构体 -var NewCDREventSMF = &CDREventSMF{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smf`, - - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "ne_name": "NeName", - "rm_uid": "RmUID", - "timestamp": "Timestamp", - "cdr_json": "CDRJSONStr", - "created_at": "CreatedAt", - }, -} +var NewCDREventSMF = &CDREventSMF{} // CDREventSMF CDR会话事件 数据层处理 -type CDREventSMF struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type CDREventSMF struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *CDREventSMF) convertResultRows(rows []map[string]any) []model.CDREventSMF { - arr := make([]model.CDREventSMF, 0) - for _, row := range rows { - item := model.CDREventSMF{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *CDREventSMF) SelectPage(querys model.CDREventSMFQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r CDREventSMF) SelectByPage(querys model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { + tx := datasource.DB("").Model(&model.CDREventSMF{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - if len(querys.StartTime) == 13 { - querys.StartTime = querys.StartTime[:10] + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] } - params = append(params, querys.StartTime) + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - if len(querys.EndTime) == 13 { - querys.EndTime = querys.EndTime[:10] + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] } - params = append(params, querys.EndTime) + tx = tx.Where("timestamp <= ?", endTime) } if querys.RecordType != "" { - conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") - params = append(params, querys.RecordType) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", querys.RecordType) } if querys.SubscriberID != "" { - conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?") - params = append(params, querys.SubscriberID) + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?", querys.SubscriberID) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.CDREventSMF{} - result := map[string]any{ - "total": 0, - "rows": []model.CDREventSMF{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from cdr_event_smf" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 -func (r *CDREventSMF) SelectByIds(cdrIds []string) []model.CDREventSMF { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.CDREventSMF{} +func (r *CDREventSMF) SelectByIds(ids []string) []model.CDREventSMF { + rows := []model.CDREventSMF{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.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(cdrIds []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - sql := "delete from cdr_event_smf where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +func (r *CDREventSMF) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { return 0 } - return results + tx := datasource.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 index 7673e7b..3b6542c 100644 --- a/src/modules/network_data/repository/cdr_event_smsc.go +++ b/src/modules/network_data/repository/cdr_event_smsc.go @@ -6,176 +6,110 @@ import ( "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 CDREventSMSC 结构体 -var NewCDREventSMSC = &CDREventSMSC{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smsc`, - - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "ne_name": "NeName", - "rm_uid": "RmUID", - "timestamp": "Timestamp", - "cdr_json": "CDRJSONStr", - "created_at": "CreatedAt", - }, -} +var NewCDREventSMSC = &CDREventSMSC{} // CDREventSMSC CDR会话事件 数据层处理 -type CDREventSMSC struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type CDREventSMSC struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *CDREventSMSC) convertResultRows(rows []map[string]any) []model.CDREventSMSC { - arr := make([]model.CDREventSMSC, 0) - for _, row := range rows { - item := model.CDREventSMSC{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *CDREventSMSC) SelectPage(querys model.CDREventSMSCQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r CDREventSMSC) SelectByPage(querys model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { + tx := datasource.DB("").Model(&model.CDREventSMSC{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - if len(querys.StartTime) == 13 { - querys.StartTime = querys.StartTime[:10] + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] } - params = append(params, querys.StartTime) + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - if len(querys.EndTime) == 13 { - querys.EndTime = querys.EndTime[:10] + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] } - params = append(params, querys.EndTime) + tx = tx.Where("timestamp <= ?", endTime) } - // MySQL8支持的 - // if querys.RecordType != "" { - // recordTypes := strings.Split(querys.RecordType, ",") - // placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) - // conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) - // for _, recordType := range recordTypes { - // params = append(params, recordType) - // } - // } - // Mariadb不支持json in查询改or + if querys.CallerParty != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", querys.CallerParty) + } + if querys.CalledParty != "" { + tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') = ?", querys.CalledParty) + } + if querys.RecordType != "" { recordTypes := strings.Split(querys.RecordType, ",") var queryStrArr []string for _, recordType := range recordTypes { - queryStrArr = append(queryStrArr, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") - params = append(params, recordType) + queryStrArr = append(queryStrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType)) } - conditions = append(conditions, fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) + tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(queryStrArr, " OR "))) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.CDREventSMSC{} - result := map[string]any{ - "total": 0, - "rows": []model.CDREventSMSC{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from cdr_event_smsc" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 -func (r *CDREventSMSC) SelectByIds(cdrIds []string) []model.CDREventSMSC { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.CDREventSMSC{} +func (r *CDREventSMSC) SelectByIds(ids []string) []model.CDREventSMSC { + rows := []model.CDREventSMSC{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.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(cdrIds []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - sql := "delete from cdr_event_smsc where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(cdrIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +func (r *CDREventSMSC) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { return 0 } - return results + tx := datasource.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/repository/udm_user_info.go b/src/modules/network_data/repository/udm_user_info.go index c7aead4..259dd0b 100644 --- a/src/modules/network_data/repository/udm_user_info.go +++ b/src/modules/network_data/repository/udm_user_info.go @@ -1,164 +1,91 @@ package repository import ( - "fmt" - "strings" - "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 UDMUserInfo 结构体 -var NewUDMUserInfo = &UDMUserInfo{ - selectSql: `select id, imsi, msisdn, ne_id, remark from u_user_info`, - - resultMap: map[string]string{ - "id": "ID", - "imsi": "IMSI", - "msisdn": "MSISDN", - "ne_id": "NeId", - "remark": "Remark", - }, -} +var NewUDMUserInfo = &UDMUserInfo{} // UDMUserInfo UDM鉴权信息表 数据层处理 -type UDMUserInfo struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type UDMUserInfo struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *UDMUserInfo) convertResultRows(rows []map[string]any) []model.UDMUserInfo { - arr := make([]model.UDMUserInfo, 0) - for _, row := range rows { - item := model.UDMUserInfo{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *UDMUserInfo) SelectPage(query map[string]any) map[string]any { +// SelectByPage 分页查询集合 +func (r UDMUserInfo) SelectByPage(query map[string]string) ([]model.UDMUserInfo, int64) { + tx := datasource.DB("").Model(&model.UDMUserInfo{}) // 查询条件拼接 - var conditions []string - var params []any if v, ok := query["imsi"]; ok && v != "" { - conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") - params = append(params, strings.Trim(v.(string), " ")) + tx = tx.Where("imsi like concat(concat('%', ?), '%')", v) } if v, ok := query["neId"]; ok && v != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, v) + tx = tx.Where("ne_id = ?", v) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.UDMUserInfo{} - result := map[string]any{ - "total": 0, - "rows": []model.UDMUserInfo{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from u_user_info" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if v, ok := query["sortField"]; ok && v != "" { - sortSql := v.(string) - if o, ok := query["sortOrder"]; ok && o != nil && v != "" { - if o == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := v + if o, ok := query["sortOrder"]; ok && o != "" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectList 根据实体查询 func (r *UDMUserInfo) SelectList(u model.UDMUserInfo) []model.UDMUserInfo { - // 查询条件拼接 - var conditions []string - var params []any + tx := datasource.DB("").Model(&model.UDMUserInfo{}) + // 构建查询条件 if u.IMSI != "" { - conditions = append(conditions, "imsi = ?") - params = append(params, u.IMSI) + tx = tx.Where("imsi = ?", u.IMSI) } if u.NeId != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, u.NeId) + tx = tx.Where("ne_id = ?", u.NeId) } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - + tx = tx.Order("imsi asc") // 查询数据 - querySql := r.selectSql + whereSql + " order by imsi asc " - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err => %v", err) + rows := []model.UDMUserInfo{} + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows } - - // 转换实体 - return r.convertResultRows(results) + return rows } -// SelectByIMSIAndNeID 通过imsi和ne_id查询 +// SelectByIMSIAndNeID 通过imsi和ne_id查询 neId为%时模糊imsi查询 func (r *UDMUserInfo) SelectByIMSIAndNeID(imsi, neId string) model.UDMUserInfo { - querySql := r.selectSql + " where imsi = ? and ne_id = ?" - results, err := datasource.RawDB("", querySql, []any{imsi, neId}) - if err != nil { - logger.Errorf("query err => %v", err) - return model.UDMUserInfo{} + tx := datasource.DB("").Model(&model.UDMUserInfo{}) + // 构建查询条件 + if neId == "%" { + tx = tx.Where("imsi like concat(?, '%')", imsi) + } else { + tx = tx.Where(" imsi = ? and ne_id = ?", imsi, neId) + } + // 查询数据 + rows := []model.UDMUserInfo{} + if err := tx.Limit(1).Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) } - // 转换实体 - rows := r.convertResultRows(results) if len(rows) > 0 { return rows[0] } @@ -174,20 +101,17 @@ func (r *UDMUserInfo) Inserts(uArr []model.UDMUserInfo) int64 { return tx.RowsAffected } -// Delete 删除实体 +// Delete 删除实体 neId为%时模糊imsi前缀 func (r *UDMUserInfo) Delete(imsi, neId string) int64 { - tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMUserInfo{}) + tx := datasource.DefaultDB() + if neId == "%" { + tx = tx.Where("imsi like concat(?, '%')", imsi) + } else { + tx = tx.Where(" imsi = ? and ne_id = ?", imsi, neId) + } + tx = tx.Delete(&model.UDMUserInfo{}) if err := tx.Error; err != nil { logger.Errorf("Delete err => %v", err) } return tx.RowsAffected } - -// DeletePrefixByIMSI 删除前缀匹配的实体 -func (r *UDMUserInfo) DeletePrefixByIMSI(imsiPrefix, neId string) int64 { - tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsiPrefix, neId).Delete(&model.UDMUserInfo{}) - if err := tx.Error; err != nil { - logger.Errorf("DeletePrefixByIMSI err => %v", err) - } - return tx.RowsAffected -} diff --git a/src/modules/network_data/repository/ue_event_amf.go b/src/modules/network_data/repository/ue_event_amf.go index 76442b8..9542a6c 100644 --- a/src/modules/network_data/repository/ue_event_amf.go +++ b/src/modules/network_data/repository/ue_event_amf.go @@ -1,175 +1,106 @@ package repository import ( - "fmt" "strings" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 UEEventAMF 结构体 -var NewUEEventAMF = &UEEventAMF{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_amf`, - - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "ne_name": "NeName", - "rm_uid": "RmUID", - "timestamp": "Timestamp", - "event_type": "EventType", - "event_json": "EventJSONStr", - "created_at": "CreatedAt", - }, -} +var NewUEEventAMF = &UEEventAMF{} // UEEventAMF UE会话事件 数据层处理 -type UEEventAMF struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type UEEventAMF struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *UEEventAMF) convertResultRows(rows []map[string]any) []model.UEEventAMF { - arr := make([]model.UEEventAMF, 0) - for _, row := range rows { - item := model.UEEventAMF{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *UEEventAMF) SelectPage(querys model.UEEventAMFQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r UEEventAMF) SelectByPage(querys model.UEEventAMFQuery) ([]model.UEEventAMF, int64) { + tx := datasource.DB("").Model(&model.UEEventAMF{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - if len(querys.StartTime) == 13 { - querys.StartTime = querys.StartTime[:10] + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] } - params = append(params, querys.StartTime) + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - if len(querys.EndTime) == 13 { - querys.EndTime = querys.EndTime[:10] + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] } - params = append(params, querys.EndTime) + tx = tx.Where("timestamp <= ?", endTime) } if querys.EventType != "" { eventTypes := strings.Split(querys.EventType, ",") - placeholder := repo.KeyPlaceholderByQuery(len(eventTypes)) - conditions = append(conditions, fmt.Sprintf("event_type in (%s)", placeholder)) - for _, eventType := range eventTypes { - params = append(params, eventType) - } + tx = tx.Where("event_type in ?", eventTypes) } if querys.IMSI != "" { - conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") - params = append(params, querys.IMSI) + tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", querys.IMSI) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.UEEventAMF{} - result := map[string]any{ - "total": 0, - "rows": []model.UEEventAMF{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from ue_event_amf" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 -func (r *UEEventAMF) SelectByIds(ueIds []string) []model.UEEventAMF { - placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ueIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.UEEventAMF{} +func (r UEEventAMF) SelectByIds(ids []string) []model.UEEventAMF { + rows := []model.UEEventAMF{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.DB("").Model(&model.UEEventAMF{}) + // 构建查询条件 + 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 *UEEventAMF) DeleteByIds(ueIds []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - sql := "delete from ue_event_amf where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ueIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +func (r UEEventAMF) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { return 0 } - return results + tx := datasource.DB("").Where("id in ?", ids) + if err := tx.Delete(&model.UEEventAMF{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected } diff --git a/src/modules/network_data/repository/ue_event_mme.go b/src/modules/network_data/repository/ue_event_mme.go index a035f5a..7da121d 100644 --- a/src/modules/network_data/repository/ue_event_mme.go +++ b/src/modules/network_data/repository/ue_event_mme.go @@ -1,175 +1,106 @@ package repository import ( - "fmt" "strings" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) // 实例化数据层 UEEventMME 结构体 -var NewUEEventMME = &UEEventMME{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_mme`, - - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "ne_name": "NeName", - "rm_uid": "RmUID", - "timestamp": "Timestamp", - "event_type": "EventType", - "event_json": "EventJSONStr", - "created_at": "CreatedAt", - }, -} +var NewUEEventMME = &UEEventMME{} // UEEventMME UE会话事件 数据层处理 -type UEEventMME struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type UEEventMME struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *UEEventMME) convertResultRows(rows []map[string]any) []model.UEEventMME { - arr := make([]model.UEEventMME, 0) - for _, row := range rows { - item := model.UEEventMME{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *UEEventMME) SelectPage(querys model.UEEventMMEQuery) map[string]any { +// SelectByPage 分页查询集合 +func (r UEEventMME) SelectByPage(querys model.UEEventMMEQuery) ([]model.UEEventMME, int64) { + tx := datasource.DB("").Model(&model.UEEventMME{}) // 查询条件拼接 - var conditions []string - var params []any if querys.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, querys.NeType) + tx = tx.Where("ne_type = ?", querys.NeType) } if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) + tx = tx.Where("rm_uid = ?", querys.RmUID) } if querys.StartTime != "" { - conditions = append(conditions, "timestamp >= ?") - if len(querys.StartTime) == 13 { - querys.StartTime = querys.StartTime[:10] + startTime := querys.StartTime + if len(startTime) == 13 { + startTime = startTime[:10] } - params = append(params, querys.StartTime) + tx = tx.Where("timestamp >= ?", startTime) } if querys.EndTime != "" { - conditions = append(conditions, "timestamp <= ?") - if len(querys.EndTime) == 13 { - querys.EndTime = querys.EndTime[:10] + endTime := querys.EndTime + if len(endTime) == 13 { + endTime = endTime[:10] } - params = append(params, querys.EndTime) + tx = tx.Where("timestamp <= ?", endTime) } if querys.EventType != "" { eventTypes := strings.Split(querys.EventType, ",") - placeholder := repo.KeyPlaceholderByQuery(len(eventTypes)) - conditions = append(conditions, fmt.Sprintf("event_type in (%s)", placeholder)) - for _, eventType := range eventTypes { - params = append(params, eventType) - } + tx = tx.Where("event_type in ?", eventTypes) } if querys.IMSI != "" { - conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") - params = append(params, querys.IMSI) + tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') = ?", querys.IMSI) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } + // 查询结果 + var total int64 = 0 + rows := []model.UEEventMME{} - result := map[string]any{ - "total": 0, - "rows": []model.UEEventMME{}, + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from ue_event_mme" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - logger.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - // 排序 - orderSql := "" if querys.SortField != "" { - sortSql := querys.SortField - if querys.SortOrder != "" { - if querys.SortOrder == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } + sortField := querys.SortField + if querys.SortOrder == "desc" { + sortField = sortField + " desc" } - orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + tx = tx.Order(sortField) } - // 查询数据 - querySql := r.selectSql + whereSql + orderSql + pageSql - results, err := datasource.RawDB("", querySql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(querys.PageNum, querys.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("query err => %v", err) + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectByIds 通过ID查询 -func (r *UEEventMME) SelectByIds(ueIds []string) []model.UEEventMME { - placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ueIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.UEEventMME{} +func (r UEEventMME) SelectByIds(ids []string) []model.UEEventMME { + rows := []model.UEEventMME{} + if len(ids) <= 0 { + return rows } - // 转换实体 - return r.convertResultRows(results) + tx := datasource.DB("").Model(&model.UEEventMME{}) + // 构建查询条件 + 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 *UEEventMME) DeleteByIds(ueIds []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - sql := "delete from ue_event_mme where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ueIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +func (r UEEventMME) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { return 0 } - return results + tx := datasource.DB("").Where("id in ?", ids) + if err := tx.Delete(&model.UEEventMME{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected } diff --git a/src/modules/network_data/service/alarm.go b/src/modules/network_data/service/alarm.go index 3df04ea..2729e67 100644 --- a/src/modules/network_data/service/alarm.go +++ b/src/modules/network_data/service/alarm.go @@ -18,8 +18,8 @@ type Alarm struct { } // SelectPage 根据条件分页查询 -func (r *Alarm) SelectPage(querys model.AlarmQuery) map[string]any { - return r.alarmRepository.SelectPage(querys) +func (r *Alarm) SelectPage(querys model.AlarmQuery) ([]model.Alarm, int64) { + return r.alarmRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 diff --git a/src/modules/network_data/service/cdr_event_ims.go b/src/modules/network_data/service/cdr_event_ims.go index 922fb02..1291c81 100644 --- a/src/modules/network_data/service/cdr_event_ims.go +++ b/src/modules/network_data/service/cdr_event_ims.go @@ -1,10 +1,18 @@ 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 结构体 @@ -18,8 +26,8 @@ type CDREventIMS struct { } // SelectPage 根据条件分页查询 -func (r *CDREventIMS) SelectPage(querys model.CDREventIMSQuery) map[string]any { - return r.cdrEventIMSRepository.SelectPage(querys) +func (r *CDREventIMS) SelectPage(querys model.CDREventIMSQuery) ([]model.CDREventIMS, int64) { + return r.cdrEventIMSRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 @@ -37,3 +45,100 @@ func (r *CDREventIMS) DeleteByIds(cdrIds []string) (int64, error) { // 删除信息失败! 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": "Record Behavior", + "C1": "Type", + "D1": "Caller", + "E1": "Called", + "F1": "Duration", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := sysService.NewSysDictData.SelectDictDataByType("cdr_sip_code") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := sysService.NewSysDictData.SelectDictDataByType("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]interface{} + err := json.Unmarshal([]byte(row.CDRJSONStr), &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.DictValue { + callTypeLable = i18n.TKey(language, v.DictLabel) + 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.Sprint(parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Success" + if v, ok := cdrJSON["cause"]; ok && v != nil && callType != "sms" { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DictValue { + callResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["releaseTime"]; 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: recordType, + "C" + idx: callTypeLable, + "D" + idx: caller, + "E" + idx: called, + "F" + idx: duration, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + + // 导出数据表格 + 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 new file mode 100644 index 0000000..316024e --- /dev/null +++ b/src/modules/network_data/service/cdr_event_sgwc.go @@ -0,0 +1,216 @@ +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会话事件数据信息 +} + +// SelectPage 根据条件分页查询 +func (r *CDREventSGWC) SelectPage(querys model.CDREventSGWCQuery) ([]model.CDREventSGWC, int64) { + return r.cdrEventRepository.SelectByPage(querys) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSGWC) DeleteByIds(cdrIds []string) (int64, error) { + // 检查是否存在 + ids := r.cdrEventRepository.SelectByIds(cdrIds) + if len(ids) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(ids) == len(cdrIds) { + rows := r.cdrEventRepository.DeleteByIds(cdrIds) + 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 Used", + "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", + } + // 从第二行开始的数据 + 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.CDRJSONStr), &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) + } + // sGWAddress + sGWAddress := "" + if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { + sGWAddress = 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, + }) + } + + // 导出数据表格 + 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 index abd30a8..cbc2076 100644 --- a/src/modules/network_data/service/cdr_event_smf.go +++ b/src/modules/network_data/service/cdr_event_smf.go @@ -1,8 +1,13 @@ 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" ) @@ -18,8 +23,8 @@ type CDREventSMF struct { } // SelectPage 根据条件分页查询 -func (r *CDREventSMF) SelectPage(querys model.CDREventSMFQuery) map[string]any { - return r.cdrEventRepository.SelectPage(querys) +func (r *CDREventSMF) SelectPage(querys model.CDREventSMFQuery) ([]model.CDREventSMF, int64) { + return r.cdrEventRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 @@ -37,3 +42,190 @@ func (r *CDREventSMF) DeleteByIds(cdrIds []string) (int64, error) { // 删除信息失败! 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.CDRJSONStr), &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 index 3944887..04b6837 100644 --- a/src/modules/network_data/service/cdr_event_smsc.go +++ b/src/modules/network_data/service/cdr_event_smsc.go @@ -1,10 +1,18 @@ 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 结构体 @@ -18,8 +26,8 @@ type CDREventSMSC struct { } // SelectPage 根据条件分页查询 -func (r *CDREventSMSC) SelectPage(querys model.CDREventSMSCQuery) map[string]any { - return r.cdrEventRepository.SelectPage(querys) +func (r *CDREventSMSC) SelectPage(querys model.CDREventSMSCQuery) ([]model.CDREventSMSC, int64) { + return r.cdrEventRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 @@ -37,3 +45,91 @@ func (r *CDREventSMSC) DeleteByIds(cdrIds []string) (int64, error) { // 删除信息失败! 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": "Record Behavior", + "C1": "Service Type", + "D1": "Caller", + "E1": "Called", + "F1": "Result", + "G1": "Time", + } + // 读取字典数据 CDR 原因码 + dictCDRCauseCode := sysService.NewSysDictData.SelectDictDataByType("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.CDRJSONStr), &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.DictValue { + callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DictLabel)) + 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: recordType, + "C" + idx: serviceType, + "D" + idx: caller, + "E" + idx: called, + "F" + idx: callResult, + "G" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go index ba9b37d..28c78ff 100644 --- a/src/modules/network_data/service/udm_sub.go +++ b/src/modules/network_data/service/udm_sub.go @@ -197,7 +197,7 @@ func (r *UDMSubUser) Insert(neId string, u model.UDMSubUser) int64 { r.udmSubRepository.Delete(u.IMSI, neId) // 新增到拓展信息 if u.Remark != "" { - r.udmUserInfoRepository.Delete(u.IMSI, neId) + r.udmUserInfoRepository.Delete(u.IMSI, "%") r.udmUserInfoRepository.Inserts([]model.UDMUserInfo{{ IMSI: u.IMSI, MSISDN: u.MSISDN, @@ -267,9 +267,9 @@ func (r *UDMSubUser) LoadData(neId, imsi, num, remark string) { // 删除原数据 r.udmSubRepository.Delete(keyIMSI, neId) if remark == "-(Deleted)-" { - r.udmUserInfoRepository.Delete(keyIMSI, neId) + r.udmUserInfoRepository.Delete(keyIMSI, "%") } - // 加载数据 + // 加载数据,删除标记为-(Deleted)-加载为空不插入 arr := r.dataByRedis(keyIMSI, neId) if len(arr) < 1 { continue diff --git a/src/modules/network_data/service/udm_user_info.go b/src/modules/network_data/service/udm_user_info.go index da61072..0c53a7d 100644 --- a/src/modules/network_data/service/udm_user_info.go +++ b/src/modules/network_data/service/udm_user_info.go @@ -16,7 +16,7 @@ type UDMUserInfo struct { udmUserInfoRepository *repository.UDMUserInfo } -// SelectByIMSIAndNeID 通过IMSI和网元标识查询信息 +// SelectByIMSIAndNeID 通过IMSI和网元标识查询信息 neId为%时模糊imsi查询 func (r *UDMUserInfo) SelectByIMSIAndNeID(imsi, neId string) model.UDMUserInfo { return r.udmUserInfoRepository.SelectByIMSIAndNeID(imsi, neId) } @@ -27,7 +27,7 @@ func (r *UDMUserInfo) Save(u model.UDMUserInfo) bool { return r.udmUserInfoRepository.Inserts([]model.UDMUserInfo{u}) > 0 } -// Delete 删除信息 +// Delete 删除信息 neId为%时模糊imsi查询 func (r *UDMUserInfo) Delete(imsi, neId string) int64 { return r.udmUserInfoRepository.Delete(imsi, neId) } diff --git a/src/modules/network_data/service/ue_event_amf.go b/src/modules/network_data/service/ue_event_amf.go index 29fdec2..63234e6 100644 --- a/src/modules/network_data/service/ue_event_amf.go +++ b/src/modules/network_data/service/ue_event_amf.go @@ -1,10 +1,16 @@ package service import ( + "encoding/json" "fmt" + "strconv" + "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/file" "be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/repository" + sysService "be.ems/src/modules/system/service" ) // 实例化数据层 UEEventAMF 结构体 @@ -14,13 +20,12 @@ var NewUEEventAMF = &UEEventAMF{ // UEEventAMF UE会话事件AMF 服务层处理 type UEEventAMF struct { - // UE会话事件数据信息 - ueEventRepository *repository.UEEventAMF + ueEventRepository *repository.UEEventAMF // UE会话事件数据信息 } // SelectPage 根据条件分页查询 -func (r *UEEventAMF) SelectPage(querys model.UEEventAMFQuery) map[string]any { - return r.ueEventRepository.SelectPage(querys) +func (r *UEEventAMF) SelectPage(querys model.UEEventAMFQuery) ([]model.UEEventAMF, int64) { + return r.ueEventRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 @@ -38,3 +43,96 @@ func (r *UEEventAMF) DeleteByIds(ueIds []string) (int64, error) { // 删除信息失败! return 0, fmt.Errorf("delete fail") } + +// ExportXlsx 导出数据到 xlsx 文件 +func (r UEEventAMF) ExportXlsx(rows []model.UEEventAMF, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictData.SelectDictDataByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictData.SelectDictDataByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictData.SelectDictDataByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := "" + for _, v := range dictUEEventType { + if row.EventType == v.DictValue { + eventType = i18n.TKey(language, v.DictLabel) + break + } + } + // 取结果 + eventResult := "" + // 取时间 + timeStr := "" + if row.EventType == "auth-result" { + if v, ok := eventJSON["authTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["authCode"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEAauthCode { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + if row.EventType == "detach" { + if v, ok := eventJSON["detachTime"]; ok && v != nil { + timeStr = v.(string) + } + eventResult = "Success" + } + if row.EventType == "cm-state" { + if v, ok := eventJSON["changeTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["status"]; ok && v != nil { + eventResult = fmt.Sprint(v) + for _, v := range dictUEEventCmState { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") +} diff --git a/src/modules/network_data/service/ue_event_mme.go b/src/modules/network_data/service/ue_event_mme.go index dd034b2..7f35a19 100644 --- a/src/modules/network_data/service/ue_event_mme.go +++ b/src/modules/network_data/service/ue_event_mme.go @@ -1,10 +1,18 @@ 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" ) // 实例化数据层 UEEventMME 结构体 @@ -18,8 +26,8 @@ type UEEventMME struct { } // SelectPage 根据条件分页查询 -func (r *UEEventMME) SelectPage(querys model.UEEventMMEQuery) map[string]any { - return r.ueEventRepository.SelectPage(querys) +func (r *UEEventMME) SelectPage(querys model.UEEventMMEQuery) ([]model.UEEventMME, int64) { + return r.ueEventRepository.SelectByPage(querys) } // DeleteByIds 批量删除信息 @@ -37,3 +45,86 @@ func (r *UEEventMME) DeleteByIds(ueIds []string) (int64, error) { // 删除信息失败! return 0, fmt.Errorf("delete fail") } + +// ExportXlsx 导出数据到 xlsx 文件 +func (r UEEventMME) ExportXlsx(rows []model.UEEventMME, fileName, language string) (string, error) { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictData.SelectDictDataByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictData.SelectDictDataByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictData.SelectDictDataByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := row.EventType + for _, v := range dictUEEventType { + if row.EventType == v.DictValue { + eventType = i18n.TKey(language, v.DictLabel) + break + } + } + // 取结果 + eventResult := "" + if v, ok := eventJSON["result"]; ok && v != nil { + eventResult = v.(string) + if row.EventType == "auth-result" { + for _, v := range dictUEAauthCode { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + if row.EventType == "cm-state" { + for _, v := range dictUEEventCmState { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + // 取时间 + timeStr := "" + if v, ok := eventJSON["timestamp"]; ok && v != nil { + rowTime := parse.Number(v) + timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + return file.WriteSheet(headerCells, dataCells, fileName, "") + +} diff --git a/src/modules/network_element/controller/ne_config.go b/src/modules/network_element/controller/ne_config.go index a46da6f..bba6724 100644 --- a/src/modules/network_element/controller/ne_config.go +++ b/src/modules/network_element/controller/ne_config.go @@ -34,10 +34,9 @@ type NeConfigController struct { // // GET /list func (s *NeConfigController) List(c *gin.Context) { - querys := ctx.QueryMap(c) - data := s.neConfigService.SelectPage(querys) - - c.JSON(200, result.Ok(data)) + querys := ctx.QueryMapString(c) + rows, total := s.neConfigService.SelectPage(querys) + c.JSON(200, result.Ok(map[string]any{"total": total, "rows": rows})) } // 网元参数配置可用属性值信息 diff --git a/src/modules/network_element/fetch_link/amf.go b/src/modules/network_element/fetch_link/amf.go new file mode 100644 index 0000000..65cce3b --- /dev/null +++ b/src/modules/network_element/fetch_link/amf.go @@ -0,0 +1,90 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/modules/network_element/model" +) + +// AMFNbInfoList AMF基站信息 +// +// 查询参数 {"id":"7"} +// +// 返回结果 [] +func AMFNbInfoList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/amf/objectType/nbInfo", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["id"]; ok && v != "" { + query = append(query, fmt.Sprintf("nbId=%s", v)) + } + if len(query) > 0 { + neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&")) + } + + var resData map[string]any + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("AMFNbInfoList Get \"%s\"", neUrl) + logger.Errorf("AMFNbInfoList %s", errStr) + return nil, fmt.Errorf("NeService AMF API Error") + } + + // 序列化结果 {"data":[{"id":"7","name":"NR-SA-GNB","address":"192.168.5.100:60110","ueNum":0}]} + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("AMFNbInfoList Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + if arr := v.([]any); len(arr) > 0 { + result := make([]map[string]any, len(arr)) + for i, item := range arr { + result[i] = item.(map[string]any) + } + return result, nil + } + } + return []map[string]any{}, nil +} + +// AMFGnbStateList AMF基站状态信息,对比配置项gnbList +// +// 返回结果 [] +func AMFGnbStateList(neInfo model.NeInfo) ([]map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/amf/objectType/nbState", neInfo.IP, neInfo.Port) + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("AMFNbInfoList Get \"%s\"", neUrl) + logger.Errorf("AMFNbInfoList %s", errStr) + return nil, fmt.Errorf("NeService AMF API Error") + } + + // 序列化结果 {"data":[{"name": "Gnb","address": "192.168.8.1","state": "INACTIVE"}]} + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("AMFNbInfoList Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + if arr := v.([]any); len(arr) > 0 { + result := make([]map[string]any, len(arr)) + for i, item := range arr { + result[i] = item.(map[string]any) + } + return result, nil + } + } + return []map[string]any{}, nil +} diff --git a/src/modules/network_element/fetch_link/hlr.go b/src/modules/network_element/fetch_link/hlr.go index 8a4c119..4d3cfe6 100644 --- a/src/modules/network_element/fetch_link/hlr.go +++ b/src/modules/network_element/fetch_link/hlr.go @@ -37,7 +37,7 @@ func HLRTraceStart(neInfo model.NeInfo, data map[string]any) (string, error) { if v, ok := resData["code"]; ok && v == "0" { return strings.TrimSpace(strings.ToLower(resData["message"])), nil } - return "", fmt.Errorf(resData["message"]) + return "", fmt.Errorf("%s", resData["message"]) } // HLRTraceStop HLR跟踪任务停止 @@ -64,5 +64,5 @@ func HLRTraceStop(neInfo model.NeInfo, data map[string]any) (string, error) { if v, ok := resData["code"]; ok && v == "0" { return strings.TrimSpace(strings.ToLower(resData["message"])), nil } - return "", fmt.Errorf(resData["message"]) + return "", fmt.Errorf("%s", resData["message"]) } diff --git a/src/modules/network_element/fetch_link/ims.go b/src/modules/network_element/fetch_link/ims.go new file mode 100644 index 0000000..015da59 --- /dev/null +++ b/src/modules/network_element/fetch_link/ims.go @@ -0,0 +1,100 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/network_element/model" +) + +// IMSUeSessionNum IMS会话数量 +// +// 返回结果 0 +func IMSUeSessionNum(neInfo model.NeInfo) (int64, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/ims/objectType/ueNum", neInfo.IP, neInfo.Port) + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("IMSUeSessionNum Get \"%s\"", neUrl) + logger.Errorf("IMSUeSessionNum %s", errStr) + return 0, fmt.Errorf("NeService IMS API Error") + } + // 序列化结果 {"data":{"ueNum":0}} + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("IMSUeSessionNum Unmarshal %s", err.Error()) + return 0, err + } + + // 固定返回字段,方便前端解析 + var ueNum int64 = 0 + if v, ok := resData["data"]; ok && v != nil { + if num := v.(map[string]any)["ueNum"]; num != nil { + ueNum = parse.Number(num) + } + } + return ueNum, nil +} + +// IMSUeSessionList IMS会话列表 +// +// 查询参数 {"imsi":"460001230000002","msisdn":"12307551232"} +// +// 返回结果 [] +func IMSUeSessionList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/ims/objectType/ueInfo", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["imsi"]; ok && v != "" { + query = append(query, fmt.Sprintf("imsi=%s", v)) + } + if v, ok := data["msisdn"]; ok && v != "" { + query = append(query, fmt.Sprintf("msisdn=%s", v)) + } + if len(query) > 0 { + neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&")) + } + + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("IMSUeSessionList Get \"%s\"", neUrl) + logger.Errorf("IMSUeSessionList %s", errStr) + return nil, fmt.Errorf("NeService IMS API Error") + } + + // 序列化结果 + // { "data":[ + // { + // "activeTime": "2023-11-29 17:04:54", + // "barring": 0, + // "impu": "sip:12307551232@ims.mnc000.mcc460.3gppnetwork.org", + // "imsi": "460001230000002", + // "msisdn": "12307551232", + // "regState": 1 + // } + // ] } + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("IMSUeSessionList Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + if arr := v.([]any); len(arr) > 0 { + result := make([]map[string]any, len(arr)) + for i, item := range arr { + result[i] = item.(map[string]any) + } + return result, nil + } + } + return []map[string]any{}, nil +} diff --git a/src/modules/network_element/fetch_link/mme.go b/src/modules/network_element/fetch_link/mme.go new file mode 100644 index 0000000..741f48d --- /dev/null +++ b/src/modules/network_element/fetch_link/mme.go @@ -0,0 +1,56 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/modules/network_element/model" +) + +// MMENbInfoList AMF基站信息 +// +// 查询参数 {"id":"7"} +// +// 返回结果 [] +func MMENbInfoList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/mme/objectType/nbInfo", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["id"]; ok && v != "" { + query = append(query, fmt.Sprintf("nbId=%s", v)) + } + if len(query) > 0 { + neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&")) + } + + var resData map[string]any + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("MMENbInfoList Get \"%s\"", neUrl) + logger.Errorf("MMENbInfoList %s", errStr) + return nil, fmt.Errorf("NeService AMF API Error") + } + + // 序列化结果 {"data":[{"id":"7","name":"NR-SA-GNB","address":"192.168.5.100:60110","ueNum":0}]} + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("MMENbInfoList Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + if arr := v.([]any); len(arr) > 0 { + result := make([]map[string]any, len(arr)) + for i, item := range arr { + result[i] = item.(map[string]any) + } + return result, nil + } + } + return []map[string]any{}, nil +} diff --git a/src/modules/network_element/fetch_link/ne_config.go b/src/modules/network_element/fetch_link/ne_config.go index 4695351..5e159b6 100644 --- a/src/modules/network_element/fetch_link/ne_config.go +++ b/src/modules/network_element/fetch_link/ne_config.go @@ -68,6 +68,10 @@ func NeConfigInfo(neInfo model.NeInfo, paramName string) (map[string]any, error) logger.Errorf("NeConfigInfo Unmarshal %s", err.Error()) return nil, err } + // 网元参数配置信息为空时是{},需要补充data属性 + if _, ok := resData["data"]; !ok { + resData["data"] = []map[string]any{} + } return resData, nil } diff --git a/src/modules/network_element/fetch_link/smf.go b/src/modules/network_element/fetch_link/smf.go index bbbb0ee..93dc774 100644 --- a/src/modules/network_element/fetch_link/smf.go +++ b/src/modules/network_element/fetch_link/smf.go @@ -7,9 +7,40 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/utils/fetch" + "be.ems/src/framework/utils/parse" "be.ems/src/modules/network_element/model" ) +// SMFSubNum SMF在线订阅用户数量 只含5G用户数据 +// +// 返回结果 0 +func SMFSubNum(neInfo model.NeInfo) (int64, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/smf/objectType/ueNum", neInfo.IP, neInfo.Port) + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("SMFSubNum Get \"%s\"", neUrl) + logger.Errorf("SMFSubNum %s", errStr) + return 0, fmt.Errorf("NeService SMF API Error") + } + // 序列化结果 {"data":{"ueNum":0}} + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("IMSUeSession Unmarshal %s", err.Error()) + return 0, err + } + + // 固定返回字段,方便前端解析 + var ueNum int64 = 0 + if v, ok := resData["data"]; ok && v != nil { + if num := v.(map[string]any)["ueNum"]; num != nil { + ueNum = parse.Number(num) + } + } + return ueNum, nil +} + // SMFSubInfoList SMF在线订阅用户列表信息 // // 查询参数 {"imsi":"360000100000130","msisdn":"8612300000130","upstate":"Inactive","pageNum":"1"} diff --git a/src/modules/network_element/fetch_link/udm.go b/src/modules/network_element/fetch_link/udm.go index d027f9f..6ad1359 100644 --- a/src/modules/network_element/fetch_link/udm.go +++ b/src/modules/network_element/fetch_link/udm.go @@ -35,5 +35,5 @@ func UDMImportAuth(udmIP string, data map[string]any) (string, error) { if v, ok := resData["code"]; ok && v == "00000" { return strings.TrimSpace(strings.ToLower(resData["message"])), nil } - return "", fmt.Errorf(resData["message"]) + return "", fmt.Errorf("%s", resData["message"]) } diff --git a/src/modules/network_element/model/ne_config.go b/src/modules/network_element/model/ne_config.go index 99ae994..13e2225 100644 --- a/src/modules/network_element/model/ne_config.go +++ b/src/modules/network_element/model/ne_config.go @@ -3,14 +3,15 @@ package model // NeConfig 网元_参数配置可用属性值 type NeConfig struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" binding:"required" gorm:"ne_type"` // 网元类型 - ParamName string `json:"paramName" binding:"required" gorm:"param_name"` // 参数名 - ParamDisplay string `json:"paramDisplay" binding:"required" gorm:"param_display"` // 参数显示名 - ParamType string `json:"paramType" gorm:"param_type"` // 参数类型 list列表单层 array数组多层 - ParamJson string `json:"-" gorm:"param_json"` // accesss属性控制:只读read-only/read/ro 读写read-write - ParamSort int64 `json:"paramSort" gorm:"param_sort"` // 参数排序 - ParamPerms string `json:"paramPerms" gorm:"param_perms"` // 操作权限 get只读 put可编辑 delete可删除 post可新增 - UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间 + NeType string `json:"neType" binding:"required" gorm:"column:ne_type"` // 网元类型 + ParamName string `json:"paramName" binding:"required" gorm:"column:param_name"` // 参数名 + ParamDisplay string `json:"paramDisplay" binding:"required" gorm:"column:param_display"` // 参数显示名 + ParamType string `json:"paramType" gorm:"column:param_type"` // 参数类型 list列表单层 array数组多层 + ParamJson string `json:"-" gorm:"column:param_json"` // accesss属性控制:只读read-only/read/ro 读写read-write + ParamSort int64 `json:"paramSort" gorm:"column:param_sort"` // 参数排序 + ParamPerms string `json:"paramPerms" gorm:"column:param_perms"` // 操作权限 get只读 put可编辑 delete可删除 post可新增 + Visible string `json:"visible" gorm:"column:visible"` // 可见性 默认public 单独网元self + UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间 // ====== 非数据库字段属性 ====== diff --git a/src/modules/network_element/ne_config_test.go b/src/modules/network_element/ne_config_test.go index 6e80c9f..b005977 100644 --- a/src/modules/network_element/ne_config_test.go +++ b/src/modules/network_element/ne_config_test.go @@ -29,7 +29,7 @@ const ( // 配置文件路径 configParamDir = "../../../config/param" // configParamFile = "*" // 目录下全部更新 - configParamFile = "smf_param_config.yaml" // 单文件更新 + configParamFile = "amf_param_config.yaml" // 单文件更新 ) func TestConfig(t *testing.T) { @@ -92,6 +92,7 @@ func saveData(params []map[string]string) { }) // 遍历插入 for _, v := range params { + // 排序 paramSort := v["paramSort"] if len(paramSort) == 0 || paramSort == "" { paramSort = "0" @@ -101,6 +102,12 @@ func saveData(params []map[string]string) { sort = 0 } + // 可见性 默认public + visible := v["visible"] + if len(visible) == 0 || visible == "" { + visible = "public" + } + neConfig := model.NeConfig{ NeType: v["neType"], ParamName: v["paramName"], @@ -108,6 +115,7 @@ func saveData(params []map[string]string) { ParamType: v["paramType"], ParamJson: v["paramJson"], ParamPerms: v["paramPerms"], + Visible: visible, ParamSort: sort, } neConfig.ID = saveDB(neConfig) @@ -215,6 +223,8 @@ func parseParamConfig(data map[string]any) ([]map[string]string, error) { itemMap["paramDisplay"] = iiv.(string) case "sort": itemMap["paramSort"] = fmt.Sprint(iiv) + case "visible": + itemMap["visible"] = fmt.Sprint(iiv) case "perms", "method": itemMap["paramPerms"] = iiv.(string) case "list", "array": // 参数类型为数组 diff --git a/src/modules/network_element/repository/ne_config.go b/src/modules/network_element/repository/ne_config.go index 29ea68f..2ec25cf 100644 --- a/src/modules/network_element/repository/ne_config.go +++ b/src/modules/network_element/repository/ne_config.go @@ -1,259 +1,125 @@ package repository import ( - "strings" "time" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_element/model" ) // 实例化数据层 NeConfig 结构体 -var NewNeConfig = &NeConfig{ - selectSql: `select id, ne_type, param_name, param_display, param_type, param_json, param_sort, param_perms, update_time from ne_config`, - - resultMap: map[string]string{ - "id": "ID", - "ne_type": "NeType", - "param_name": "ParamName", - "param_display": "ParamDisplay", - "param_type": "ParamType", - "param_json": "ParamJson", - "param_sort": "ParamSort", - "param_perms": "ParamPerms", - "update_time": "UpdateTime", - }, -} +var NewNeConfig = &NeConfig{} // NeConfig 网元参数配置可用属性值 数据层处理 -type NeConfig struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} +type NeConfig struct{} -// convertResultRows 将结果记录转实体结果组 -func (r *NeConfig) convertResultRows(rows []map[string]any) []model.NeConfig { - arr := make([]model.NeConfig, 0) - for _, row := range rows { - item := model.NeConfig{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - repo.SetFieldValue(&item, keyMapper, value) - } - } - arr = append(arr, item) - } - return arr -} - -// SelectPage 根据条件分页查询字典类型 -func (r *NeConfig) SelectPage(query map[string]any) map[string]any { +// SelectByPage 分页查询集合 +func (r NeConfig) SelectByPage(query map[string]string) ([]model.NeConfig, int64) { + tx := datasource.DB("").Model(&model.NeConfig{}) // 查询条件拼接 - var conditions []string - var params []any if v, ok := query["neType"]; ok && v != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, v) + tx = tx.Where("ne_type = ?", v) } if v, ok := query["paramName"]; ok && v != "" { - conditions = append(conditions, "param_name = ?") - params = append(params, v) + tx = tx.Where("param_name = ?", v) } - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") + // 查询结果 + var total int64 = 0 + rows := []model.NeConfig{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total } - result := map[string]any{ - "total": 0, - "rows": []model.NeHost{}, - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(id) as 'total' from ne_config" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + // 查询数据分页 + pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error if err != nil { - logger.Errorf("total err => %v", err) - return result + logger.Errorf("query find err => %v", err.Error()) + return rows, total } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := r.selectSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err => %v", err) - return result - } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result + return rows, total } // SelectList 根据实体查询 func (r *NeConfig) SelectList(param model.NeConfig) []model.NeConfig { + tx := datasource.DB("").Model(&model.NeConfig{}) // 查询条件拼接 - var conditions []string - var params []any if param.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, param.NeType) + tx = tx.Where("ne_type = ?", param.NeType) } if param.ParamName != "" { - conditions = append(conditions, "param_name = ?") - params = append(params, param.ParamName) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") + tx = tx.Where("param_name = ?", param.ParamName) } // 查询数据 - querySql := r.selectSql + whereSql + " order by param_sort asc " - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err => %v", err) - } - - // 转换实体 - return r.convertResultRows(results) -} - -// SelectByIds 通过ID查询 -func (r *NeConfig) SelectByIds(ids []string) []model.NeConfig { - placeholder := repo.KeyPlaceholderByQuery(len(ids)) - querySql := r.selectSql + " where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ids) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - logger.Errorf("query err => %v", err) - return []model.NeConfig{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// Insert 新增信息 -func (r *NeConfig) Insert(param model.NeConfig) string { - // 参数拼接 - params := make(map[string]any) - if param.NeType != "" { - params["ne_type"] = param.NeType - } - if param.ParamName != "" { - params["param_name"] = param.ParamName - } - if param.ParamDisplay != "" { - params["param_display"] = param.ParamDisplay - } - if param.ParamType != "" { - params["param_type"] = param.ParamType - } - if param.ParamJson != "" { - params["param_json"] = param.ParamJson - } - params["param_sort"] = param.ParamSort - if param.ParamPerms != "" { - params["param_perms"] = param.ParamPerms - } - params["update_time"] = time.Now().UnixMilli() - - // 构建执行语句 - keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) - sql := "insert into ne_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - db := datasource.DefaultDB() - // 开启事务 - tx := db.Begin() - // 执行插入 - err := tx.Exec(sql, values...).Error - if err != nil { - logger.Errorf("insert row : %v", err.Error()) - tx.Rollback() - return "" - } - // 获取生成的自增 ID - var insertedID string - err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID) - if err != nil { - logger.Errorf("insert last id : %v", err.Error()) - tx.Rollback() - return "" - } - // 提交事务 - tx.Commit() - return insertedID -} - -// Update 修改信息 -func (r *NeConfig) Update(param model.NeConfig) int64 { - // 参数拼接 - params := make(map[string]any) - if param.NeType != "" { - params["ne_type"] = param.NeType - } - if param.ParamName != "" { - params["param_name"] = param.ParamName - } - if param.ParamDisplay != "" { - params["param_display"] = param.ParamDisplay - } - if param.ParamType != "" { - params["param_type"] = param.ParamType - } - if param.ParamJson != "" { - params["param_json"] = param.ParamJson - } - params["param_sort"] = param.ParamSort - if param.ParamPerms != "" { - params["param_perms"] = param.ParamPerms - } - params["update_time"] = time.Now().UnixMilli() - - // 构建执行语句 - keys, values := repo.KeyValueByUpdate(params) - sql := "update ne_config set " + strings.Join(keys, ",") + " where id = ?" - - // 执行更新 - values = append(values, param.ID) - rows, err := datasource.ExecDB("", sql, values) - if err != nil { - logger.Errorf("update row : %v", err.Error()) - return 0 + rows := []model.NeConfig{} + if err := tx.Order("param_sort asc").Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows } return rows } -// DeleteByIds 批量删除信息 -func (r *NeConfig) DeleteByIds(ids []string) int64 { - placeholder := repo.KeyPlaceholderByQuery(len(ids)) - sql := "delete from ne_config where id in (" + placeholder + ")" - parameters := repo.ConvertIdsSlice(ids) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - logger.Errorf("delete err => %v", err) +// SelectByIds 通过ID查询 +func (r *NeConfig) SelectByIds(ids []string) []model.NeConfig { + rows := []model.NeConfig{} + if len(ids) <= 0 { + return rows + } + tx := datasource.DB("").Model(&model.NeConfig{}) + // 构建查询条件 + 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 +} + +// Insert 新增信息 +func (r *NeConfig) Insert(param model.NeConfig) string { + param.UpdateTime = time.Now().UnixMilli() + // 执行插入 + if err := datasource.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return "" + } + return param.ID +} + +// Update 修改信息 +func (r *NeConfig) Update(param model.NeConfig) int64 { + if param.ID == "" { return 0 } - return results + param.UpdateTime = time.Now().UnixMilli() + tx := datasource.DB("").Model(&model.NeConfig{}) + // 构建查询条件 + tx = tx.Where("id = ?", param.ID) + tx = tx.Omit("id") + // 执行更新 + if err := tx.Updates(param).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// DeleteByIds 批量删除信息 +func (r *NeConfig) DeleteByIds(ids []string) int64 { + if len(ids) <= 0 { + return 0 + } + tx := datasource.DB("").Where("id in ?", ids) + if err := tx.Delete(&model.NeConfig{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected } diff --git a/src/modules/network_element/repository/ne_info.go b/src/modules/network_element/repository/ne_info.go index 6e2a5cc..0cf12e5 100644 --- a/src/modules/network_element/repository/ne_info.go +++ b/src/modules/network_element/repository/ne_info.go @@ -34,6 +34,8 @@ var neListSort = []string{ "SMSF", "CBC", "CHF", + "HLR", + "SGWC", } // 实例化数据层 NeInfo 结构体 diff --git a/src/modules/network_element/service/ne_config.go b/src/modules/network_element/service/ne_config.go index f607c0a..7981d0e 100644 --- a/src/modules/network_element/service/ne_config.go +++ b/src/modules/network_element/service/ne_config.go @@ -115,8 +115,8 @@ func (r *NeConfig) SelectNeConfigByNeTypeAndParamName(neType, paramName string) } // SelectNeHostPage 分页查询列表数据 -func (r *NeConfig) SelectPage(query map[string]any) map[string]any { - return r.neConfigRepository.SelectPage(query) +func (r *NeConfig) SelectPage(query map[string]string) ([]model.NeConfig, int64) { + return r.neConfigRepository.SelectByPage(query) } // SelectConfigList 查询列表 diff --git a/src/modules/network_element/service/ne_version.go b/src/modules/network_element/service/ne_version.go index 31aa4ad..d8730bd 100644 --- a/src/modules/network_element/service/ne_version.go +++ b/src/modules/network_element/service/ne_version.go @@ -265,6 +265,7 @@ func (r *NeVersion) operateCommand(action, neType string, neFilePaths []string) omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " "))) // 2s后执行omc相关命令 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm -f /tmp/omc_%s.out \n", action)) cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /tmp/omc_%s.out 2>&1 & \n", strings.Join(omcStrArr, " && "), action)) cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) return okFlagStr, cmdStrArr, nil diff --git a/src/modules/trace/service/trace_task_hlr.go b/src/modules/trace/service/trace_task_hlr.go index 9eee384..791cc12 100644 --- a/src/modules/trace/service/trace_task_hlr.go +++ b/src/modules/trace/service/trace_task_hlr.go @@ -60,7 +60,7 @@ func (r *TraceTaskHlr) DeleteByIds(ids []string) (int64, error) { if len(rows) == len(ids) { // 停止任务 - neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false) + neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "HLR"}, false, false) for _, r := range rows { if r.Status == "0" { continue @@ -98,7 +98,7 @@ func (r *TraceTaskHlr) Start(task model.TraceTaskHlr) (string, error) { } // 发送创建任务 - neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false) + neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "HLR"}, false, false) for _, neInfo := range neInfos { hlrItem := map[string]any{ "neType": neInfo.NeType, @@ -129,7 +129,7 @@ func (r *TraceTaskHlr) Start(task model.TraceTaskHlr) (string, error) { func (r *TraceTaskHlr) Stop(task model.TraceTaskHlr) error { hlrList := []map[string]any{} // 发送停止任务 - neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false) + neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "HLR"}, false, false) for _, neInfo := range neInfos { hlrItem := map[string]any{ "neType": neInfo.NeType, @@ -161,7 +161,7 @@ func (r *TraceTaskHlr) Stop(task model.TraceTaskHlr) error { func (r *TraceTaskHlr) File(traceId, dirPath string) ([]map[string]any, error) { hlrList := []map[string]any{} // 查询所有匹配的网元类型 - neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false) + neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "HLR"}, false, false) if len(neInfos) == 0 { return nil, fmt.Errorf("not found network element") } diff --git a/src/modules/ws/processor/cdr_connect.go b/src/modules/ws/processor/cdr_connect.go index 5cfc777..35d7846 100644 --- a/src/modules/ws/processor/cdr_connect.go +++ b/src/modules/ws/processor/cdr_connect.go @@ -28,10 +28,10 @@ func GetCDRConnectByIMS(requestID string, data any) ([]byte, error) { } query.RmUID = neInfo.RmUID - dataMap := neDataService.NewCDREventIMS.SelectPage(query) + rows, total := neDataService.NewCDREventIMS.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, - "data": dataMap, + "data": map[string]any{"rows": rows, "total": total}, })) return resultByte, err } @@ -53,10 +53,10 @@ func GetCDRConnectBySMF(requestID string, data any) ([]byte, error) { } query.RmUID = neInfo.RmUID - dataMap := neDataService.NewCDREventSMF.SelectPage(query) + rows, total := neDataService.NewCDREventSMF.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, - "data": dataMap, + "data": map[string]any{"rows": rows, "total": total}, })) return resultByte, err } @@ -78,10 +78,10 @@ func GetCDRConnectBySMSC(requestID string, data any) ([]byte, error) { } query.RmUID = neInfo.RmUID - dataMap := neDataService.NewCDREventSMSC.SelectPage(query) + rows, total := neDataService.NewCDREventSMSC.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, - "data": dataMap, + "data": map[string]any{"rows": rows, "total": total}, })) return resultByte, err } diff --git a/src/modules/ws/processor/ue_connect.go b/src/modules/ws/processor/ue_connect.go index f690381..b875e8e 100644 --- a/src/modules/ws/processor/ue_connect.go +++ b/src/modules/ws/processor/ue_connect.go @@ -8,6 +8,7 @@ import ( "be.ems/src/framework/vo/result" neDataModel "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" ) // GetUEConnectByAMF 获取UE会话事件-AMF @@ -20,10 +21,17 @@ func GetUEConnectByAMF(requestID string, data any) ([]byte, error) { return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewUEEventAMF.SelectPage(query) + // 查询网元获取IP + neInfo := neService.NewNeInfo.SelectNeInfoByNeTypeAndNeID("AMF", query.NeID) + if neInfo.NeId != query.NeID || neInfo.IP == "" { + return nil, fmt.Errorf("not fount neId info") + } + query.RmUID = neInfo.RmUID + + rows, total := neDataService.NewUEEventAMF.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, - "data": dataMap, + "data": map[string]any{"rows": rows, "total": total}, })) return resultByte, err } @@ -38,10 +46,17 @@ func GetUEConnectByMME(requestID string, data any) ([]byte, error) { return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewUEEventMME.SelectPage(query) + // 查询网元获取IP + neInfo := neService.NewNeInfo.SelectNeInfoByNeTypeAndNeID("MME", query.NeID) + if neInfo.NeId != query.NeID || neInfo.IP == "" { + return nil, fmt.Errorf("not fount neId info") + } + query.RmUID = neInfo.RmUID + + rows, total := neDataService.NewUEEventMME.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, - "data": dataMap, + "data": map[string]any{"rows": rows, "total": total}, })) return resultByte, err } diff --git a/src/modules/ws/service/ws_send.go b/src/modules/ws/service/ws_send.go index 4d02414..eba535b 100644 --- a/src/modules/ws/service/ws_send.go +++ b/src/modules/ws/service/ws_send.go @@ -28,10 +28,12 @@ const ( GROUP_SMF_CDR = "1006_" // 组号-SMSC_CDR会话事件 1007_neId GROUP_SMSC_CDR = "1007_" - // 组号-AMF_UE会话事件 + // 组号-SGWC_CDR会话事件 1008_neId + GROUP_SGWC_CDR = "1008_" + // 组号-AMF_UE会话事件 1010_neId GROUP_AMF_UE = "1010" // 组号-MME_UE会话事件 1011_neId - GROUP_MME_UE = "1011_" + GROUP_MME_UE = "1011" ) // 实例化服务层 WSSend 结构体