From 0b51ac719b8bc4d24974b28b83b85d16a7d8ca66 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 30 Apr 2025 17:02:18 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=E7=AD=96=E7=95=A5=E8=A7=84=E5=88=99=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 1 + build/database/std/install/sys_i18n.sql | 2 +- src/modules/network_data/controller/pcf.go | 328 ++++++++++++++++++ src/modules/network_data/network_data.go | 34 ++ src/modules/network_element/fetch_link/pcf.go | 280 +++++++++++++++ 5 files changed, 644 insertions(+), 1 deletion(-) create mode 100644 src/modules/network_data/controller/pcf.go create mode 100644 src/modules/network_element/fetch_link/pcf.go diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index b5341bce..df2f05bb 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -754,6 +754,7 @@ INSERT INTO "sys_i18n" VALUES (674, 'config.sys.user.passwdNotAllowedHistory', ' INSERT INTO "sys_i18n" VALUES (675, 'config.sys.user.passwdNotAllowedHistoryRemark', '创建新密码不等于之前使用的x次中的密码', 'Creating a new password that is not equal to the previously used password in x times'); INSERT INTO "sys_i18n" VALUES (676, 'login.errPasswdHistory', '不允许使用最近密码', 'Recent passwords not allowed'); INSERT INTO "sys_i18n" VALUES (677, 'log.operate.title.oauth2client', 'Oauth2客户端授权', 'Oauth2 Client Authorization'); +INSERT INTO "sys_i18n" VALUES (678, 'log.operate.title.pcfRule', '终端策略规则', 'UE PCC Rule'); INSERT INTO "sys_i18n" VALUES (679, 'dictType.trace_msg_type', '跟踪消息类型', 'Trace Message Type'); INSERT INTO "sys_i18n" VALUES (680, 'dictData.trace_msg_type.0', '请求', 'Request'); INSERT INTO "sys_i18n" VALUES (681, 'dictData.trace_msg_type.1', '响应', 'Response'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 1e317b14..38e80800 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -692,7 +692,7 @@ INSERT INTO `sys_i18n` VALUES (674, 'config.sys.user.passwdNotAllowedHistory', ' INSERT INTO `sys_i18n` VALUES (675, 'config.sys.user.passwdNotAllowedHistoryRemark', '创建新密码不等于之前使用的x次中的密码', 'Creating a new password that is not equal to the previously used password in x times'); INSERT INTO `sys_i18n` VALUES (676, 'login.errPasswdHistory', '不允许使用最近密码', 'Recent passwords not allowed'); INSERT INTO `sys_i18n` VALUES (677, 'log.operate.title.oauth2client', 'Oauth2客户端授权', 'Oauth2 Client Authorization'); --- INSERT INTO `sys_i18n` VALUES (678, 'config.ne.neConfigBackupFTPRemark', '请通过配置文件备份页面进行设置FTP信息', 'Please set the FTP information through the configuration file backup page.'); +INSERT INTO `sys_i18n` VALUES (678, 'log.operate.title.pcfRule', '终端策略规则', 'UE PCC Rule'); INSERT INTO `sys_i18n` VALUES (679, 'dictType.trace_msg_type', '跟踪消息类型', 'Trace Message Type'); INSERT INTO `sys_i18n` VALUES (680, 'dictData.trace_msg_type.0', '请求', 'Request'); INSERT INTO `sys_i18n` VALUES (681, 'dictData.trace_msg_type.1', '响应', 'Response'); diff --git a/src/modules/network_data/controller/pcf.go b/src/modules/network_data/controller/pcf.go new file mode 100644 index 00000000..697746f6 --- /dev/null +++ b/src/modules/network_data/controller/pcf.go @@ -0,0 +1,328 @@ +package controller + +import ( + "fmt" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + neFetchlink "be.ems/src/modules/network_element/fetch_link" + neService "be.ems/src/modules/network_element/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 PCFController 结构体 +var NewPCF = &PCFController{ + neInfoService: neService.NewNeInfo, +} + +// 网元PCF +// +// PATH /pcf +type PCFController struct { + neInfoService *neService.NeInfo // 网元信息服务 +} + +// 策略配置列表 +// +// GET /rule/list +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param imsi query string false "IMSI" +// @Param msisdn query string false "MSISDN" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration List +// @Description Policy Configuration List +// @Router /neData/pcf/rule/list [get] +func (s PCFController) RuleInfoList(c *gin.Context) { + language := reqctx.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 { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.PCFRuleInfo(neInfo, map[string]string{ + "imsi": query.IMSI, + "msisdn": query.MSISDN, + }) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + + c.JSON(200, resp.OkData(data)) +} + +// 策略配置添加 +// +// POST /rule +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration Additions +// @Description Policy Configuration Additions +// @Router /neData/pcf/rule [post] +func (s PCFController) RuleInfoAdd(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body struct { + NeId string `json:"neId" binding:"required"` // 网元ID + Num int64 `json:"num"` // 批量添加,默认0单条,大于1时imsi/msisdn会累加数值 + ParamData map[string]any `json:"paramData" binding:"required"` // 参数数据 + // Imsi string `json:"imsi" binding:"required"` + // Msisdn string `json:"msisdn" binding:"required"` + // Sar string `json:"sar"` // 根据PCF参数配置Service Area Restriction -> Name + // PccRules string `json:"pccRules"` // 根据PCF参数配置PCC Rules -> Rule ID + // QosAudio string `json:"qosAudio"` // 根据PCF参数配置QoS Template -> QoS ID + // QosVideo string `json:"qosVideo"` // 根据PCF参数配置QoS Template -> QoS ID + // SessRules string `json:"sessRules"` // 根据PCF参数配置Session Rules -> Rule ID + // HdrEnrich string `json:"hdrEnrich"` // 根据PCF参数配置Header Enrich Template -> Template Name + // UePolicy string `json:"uePolicy"` // UE策略模板(样例: uep_001) + // Rfsp int64 `json:"rfsp"` // 无线频率选择优先级 + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + var err error + if body.Num > 0 { // 批量添加 + err = neFetchlink.PCFRuleAddBatch(neInfo, body.ParamData, body.Num) + } else { // 单条添加 + err = neFetchlink.PCFRuleAdd(neInfo, body.ParamData) + } + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// 策略配置更新 +// +// PUT /rule +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration Updates +// @Description Policy Configuration Updates +// @Router /neData/pcf/rule [put] +func (s PCFController) RuleInfoEdit(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body struct { + NeId string `json:"neId" binding:"required"` // 网元ID + Num int64 `json:"num"` // 更新数量 + ParamData map[string]any `json:"paramData" binding:"required"` // 参数数据 + // Imsi string `json:"imsi" binding:"required"` + // Msisdn string `json:"msisdn" binding:"required"` + // Sar string `json:"sar"` // 根据PCF参数配置Service Area Restriction -> Name + // PccRules string `json:"pccRules"` // 根据PCF参数配置PCC Rules -> Rule ID + // QosAudio string `json:"qosAudio"` // 根据PCF参数配置QoS Template -> QoS ID + // QosVideo string `json:"qosVideo"` // 根据PCF参数配置QoS Template -> QoS ID + // SessRules string `json:"sessRules"` // 根据PCF参数配置Session Rules -> Rule ID + // HdrEnrich string `json:"hdrEnrich"` // 根据PCF参数配置Header Enrich Template -> Template Name + // UePolicy string `json:"uePolicy"` // UE策略模板(样例: uep_001) + // Rfsp int64 `json:"rfsp"` // 无线频率选择优先级 + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + var err error + if body.Num > 0 { // 批量更新 + err = neFetchlink.PCFRuleUpdateBatch(neInfo, body.ParamData, body.Num) + } else { // 单条更新 + err = neFetchlink.PCFRuleUpdate(neInfo, body.ParamData) + } + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// 策略配置删除 +// +// DELETE /rule +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param imsi query string true "IMSi, batch deletion with quantity" +// @Param num query number false "Number of deletions" +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration Deletion +// @Description Policy Configuration Deletion +// @Router /neData/pcf/rule [delete] +func (s PCFController) RuleInfoRemove(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` // 网元ID + IMSI string `form:"imsi" binding:"required"` // IMSi, 带数量时为批量删除 + Num int64 `form:"num"` // 删除数量 + } + if err := c.ShouldBindQuery(&query); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + var err error + if query.Num > 0 { // 批量删除 + err = neFetchlink.PCFRuleDeleteBatch(neInfo, query.IMSI, query.Num) + } else { // 单条删除 + err = neFetchlink.PCFRuleDelete(neInfo, query.IMSI) + } + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.Ok(nil)) +} + +// 策略配置导出 +// +// GET /rule/export +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param fileType query string true "File Type" default(txt) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration Export +// @Description Policy Configuration Export +// @Router /neData/pcf/rule/export [get] +func (s PCFController) RuleInfoExport(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + FileType string `form:"fileType" binding:"required,oneof=txt"` // 文件类型 + } + if err := c.ShouldBindQuery(&query); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.PCFRuleExport(neInfo, map[string]string{ + "fileType": query.FileType, + }) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.Writer.Header().Set("Content-Disposition", `attachment; filename="pcf_rule_export.txt"`) + c.Data(200, "application/octet-stream", data) +} + +// 策略配置导入 +// +// PUT /rule/import +// +// @Tags network_data/pcf +// @Accept json +// @Produce json +// @Param neId query string true "NE ID" default(001) +// @Param fileType query string true "File Type" default(txt) +// @Param filePath query string true "File Path" default(/tmp/pcfuser.txt) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary Policy Configuration Import +// @Description Policy Configuration Import +// @Router /neData/pcf/rule/import [put] +func (s PCFController) RuleInfoImport(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body struct { + NeId string `json:"neId" binding:"required"` + FileType string `json:"fileType" binding:"required,oneof=txt"` // 文件类型 + FilePath string `json:"filePath" binding:"required"` // 网元端文件所在绝对路径 + } + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询网元信息 + neInfo := s.neInfoService.FindByNeTypeAndNeID("PCF", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + output, err := neFetchlink.PCFRuleImport(neInfo, map[string]any{ + "type": body.FileType, + "filePath": body.FilePath, + }) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.JSON(200, resp.OkMsg(output)) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 3c809701..bab4b2c5 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -476,6 +476,40 @@ func Setup(router *gin.Engine) { controller.NewSGWC.CDRExport, ) } + + // 网元PCF + pcfGroup := neDataGroup.Group("/pcf") + { + pcfGroup.GET("/rule/list", + middleware.AuthorizeUser(nil), + controller.NewPCF.RuleInfoList, + ) + pcfGroup.POST("/rule", + middleware.AuthorizeUser(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewPCF.RuleInfoAdd, + ) + pcfGroup.PUT("/rule", + middleware.AuthorizeUser(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewPCF.RuleInfoEdit, + ) + pcfGroup.DELETE("/rule", + middleware.AuthorizeUser(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewPCF.RuleInfoRemove, + ) + pcfGroup.GET("/rule/export", + middleware.AuthorizeUser(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewPCF.RuleInfoExport, + ) + pcfGroup.PUT("/rule/import", + middleware.AuthorizeUser(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewPCF.RuleInfoImport, + ) + } } // InitLoad 初始参数 diff --git a/src/modules/network_element/fetch_link/pcf.go b/src/modules/network_element/fetch_link/pcf.go new file mode 100644 index 00000000..924cedb9 --- /dev/null +++ b/src/modules/network_element/fetch_link/pcf.go @@ -0,0 +1,280 @@ +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" +) + +// PCFRuleInfo PCF策略配置查询信息 +func PCFRuleInfo(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/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, "&")) + } + + var resData map[string]any + resBytes, err := fetch.Get(neUrl, nil, 60_000) + if err != nil { + errStr := err.Error() + logger.Warnf("PCFRuleInfo Get \"%s\"", neUrl) + logger.Errorf("PCFRuleInfo %s", errStr) + return nil, fmt.Errorf("NeService PCF API Error") + } + + // 序列化结果 + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleInfo 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 +} + +// PCFRuleAdd PCF策略配置添加 +func PCFRuleAdd(neInfo model.NeInfo, data any) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo", neInfo.IP, neInfo.Port) + resBytes, err := fetch.PostJSON(neUrl, data, nil) + if err != nil { + errStr := err.Error() + // 正常 + if strings.HasPrefix(errStr, "201") { + return nil + } + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleAdd Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleAdd Put \"%s\"", neUrl) + logger.Errorf("PCFRuleAdd %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleAddBatch PCF策略配置批量添加 +func PCFRuleAddBatch(neInfo model.NeInfo, data map[string]any, num int64) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d", neInfo.IP, neInfo.Port, num) + resBytes, err := fetch.PostJSON(neUrl, data, nil) + if err != nil { + errStr := err.Error() + // 正常 + if strings.HasPrefix(errStr, "201") { + return nil + } + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleAddBatch Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleAddBatch Put \"%s\"", neUrl) + logger.Errorf("PCFRuleAddBatch %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleUpdate PCF策略配置修改 +func PCFRuleUpdate(neInfo model.NeInfo, data map[string]any) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo", neInfo.IP, neInfo.Port) + resBytes, err := fetch.PutJSON(neUrl, data, nil) + if err != nil { + errStr := err.Error() + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleUpdate Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleUpdate Put \"%s\"", neUrl) + logger.Errorf("PCFRuleUpdate %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleUpdateBatch PCF策略配置批量修改 +func PCFRuleUpdateBatch(neInfo model.NeInfo, data map[string]any, num int64) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d", neInfo.IP, neInfo.Port, num) + resBytes, err := fetch.PutJSON(neUrl, data, nil) + if err != nil { + errStr := err.Error() + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleUpdateBatch Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleUpdateBatch Put \"%s\"", neUrl) + logger.Errorf("PCFRuleUpdateBatch %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleDelete PCF策略配置删除 +func PCFRuleDelete(neInfo model.NeInfo, imsi string) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo?imsi=%s", neInfo.IP, neInfo.Port, imsi) + resBytes, err := fetch.Delete(neUrl, nil) + if err != nil { + errStr := err.Error() + // 正常 + if strings.HasPrefix(errStr, "204") { + return nil + } + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleDelete Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleDelete Delete \"%s\"", neUrl) + logger.Errorf("PCFRuleDelete %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleDeleteBatch PCF策略配置批量删除 +func PCFRuleDeleteBatch(neInfo model.NeInfo, imsi string, num int64) error { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d?imsi=%s", neInfo.IP, neInfo.Port, num, imsi) + resBytes, err := fetch.Delete(neUrl, nil) + if err != nil { + errStr := err.Error() + // 正常 + if strings.HasPrefix(errStr, "204") { + return nil + } + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleDeleteBatch Unmarshal %s", err.Error()) + return err + } + return fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleDeleteBatch Delete \"%s\"", neUrl) + logger.Errorf("PCFRuleDeleteBatch %s", errStr) + return fmt.Errorf("NeService PCF API Error") + } + return nil +} + +// PCFRuleExport PCF策略配置导出 +func PCFRuleExport(neInfo model.NeInfo, data map[string]string) ([]byte, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/file/export", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["fileType"]; ok && v != "" { + query = append(query, fmt.Sprintf("fileType=%s", v)) + } + if len(query) > 0 { + neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&")) + } + + resBytes, err := fetch.Get(neUrl, nil, 30_000) + if err != nil { + logger.Warnf("PCFRuleExport Get \"%s\"", neUrl) + logger.Errorf("PCFRuleExport %s", err.Error()) + return nil, fmt.Errorf("NeService PCF API Error") + } + return resBytes, nil +} + +// PCFRuleImport PCF策略配置导入 +func PCFRuleImport(neInfo model.NeInfo, data map[string]any) (string, error) { + neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/file/import", neInfo.IP, neInfo.Port) + resBytes, err := fetch.PutJSON(neUrl, data, nil) + var resData map[string]any + if err != nil { + errStr := err.Error() + // 错误结果 + if strings.HasPrefix(errStr, "400") { + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleDeleteBatch Unmarshal %s", err.Error()) + return "", err + } + return "", fmt.Errorf("%s", resData["cause"]) + } + + logger.Warnf("PCFRuleImport Put \"%s\"", neUrl) + logger.Errorf("PCFRuleImport %s", errStr) + return "", fmt.Errorf("NeService PCF API Error") + } + + // 200 成功无数据时 + if len(resBytes) == 0 { + return "", nil + } + + // 序列化结果 + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("PCFRuleImport Unmarshal %s", err.Error()) + return "", err + } + return fmt.Sprint(resData["data"]), nil +} From 16eea969ed1935b4076ee5236077a43da1ef82ab Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 30 Apr 2025 17:02:47 +0800 Subject: [PATCH 02/13] =?UTF-8?q?fix:=20=E7=BD=91=E5=85=83=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=B0=E5=A2=9E=E5=87=BD=E6=95=B0=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_element/controller/ne_config.go | 2 +- src/modules/network_element/fetch_link/ne_config.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/network_element/controller/ne_config.go b/src/modules/network_element/controller/ne_config.go index fc6447f4..f3a247b8 100644 --- a/src/modules/network_element/controller/ne_config.go +++ b/src/modules/network_element/controller/ne_config.go @@ -335,7 +335,7 @@ func (s NeConfigController) DataAdd(c *gin.Context) { } // 网元直连 - resData, err := neFetchlink.NeConfigInstall(neInfo, body.ParamName, body.Loc, body.ParamData) + resData, err := neFetchlink.NeConfigAdd(neInfo, body.ParamName, body.Loc, body.ParamData) if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return diff --git a/src/modules/network_element/fetch_link/ne_config.go b/src/modules/network_element/fetch_link/ne_config.go index 4ede67e4..6128411d 100644 --- a/src/modules/network_element/fetch_link/ne_config.go +++ b/src/modules/network_element/fetch_link/ne_config.go @@ -109,19 +109,19 @@ func NeConfigUpdate(neInfo model.NeInfo, paramName, loc string, data map[string] return resData, nil } -// NeConfigInstall 网元配置新增 array -func NeConfigInstall(neInfo model.NeInfo, paramName, loc string, data map[string]any) (map[string]any, error) { +// NeConfigAdd 网元配置新增 array +func NeConfigAdd(neInfo model.NeInfo, paramName, loc string, data map[string]any) (map[string]any, error) { // 网元参数配置新增(array) neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s?loc=%v", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType), paramName, loc) resBytes, err := fetch.PostJSON(neUrl, data, nil) var resData map[string]any if err != nil { errStr := err.Error() - logger.Warnf("NeConfigInfoAdd Post \"%s\"", neUrl) + logger.Warnf("NeConfigAdd Post \"%s\"", neUrl) if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") { return resData, nil } - logger.Errorf("NeConfigInfoAdd %s", errStr) + logger.Errorf("NeConfigAdd %s", errStr) return nil, fmt.Errorf("NeService Config Add API Error") } @@ -133,7 +133,7 @@ func NeConfigInstall(neInfo model.NeInfo, paramName, loc string, data map[string // 序列化结果 err = json.Unmarshal(resBytes, &resData) if err != nil { - logger.Errorf("NeConfigInfoAdd Unmarshal %s", err.Error()) + logger.Errorf("NeConfigAdd Unmarshal %s", err.Error()) return nil, err } return resData, nil From cc805d5dbb519d51c710c4b790d7f3eda35bc6a1 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 30 Apr 2025 17:53:01 +0800 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20=E6=8D=95=E8=8E=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=97=B6=E8=B7=B3=E8=BF=87=E5=BB=B6=E8=BF=9F=E8=B6=85?= =?UTF-8?q?=E8=BF=871=E6=AF=AB=E7=A7=92=E7=9A=84=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/trace/service/packet.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/trace/service/packet.go b/src/modules/trace/service/packet.go index 4c705374..856b63ac 100644 --- a/src/modules/trace/service/packet.go +++ b/src/modules/trace/service/packet.go @@ -203,7 +203,9 @@ func (s *Packet) capturePacketSource(taskInfo *Task) { if packet == nil { continue } - if packet.Metadata().Timestamp.Before(time.Now()) { + // 如果延迟超过1毫秒跳过 + timeDiff := time.Since(packet.Metadata().Timestamp) + if timeDiff > time.Millisecond { continue } From af60a4bc08383798f7f37da89a37b93fedd299ef Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 30 Apr 2025 18:18:59 +0800 Subject: [PATCH 04/13] =?UTF-8?q?chore:=20=E5=8F=91=E5=B8=83=E7=89=88?= =?UTF-8?q?=E6=9C=AC=202.2504.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 567 +++++---------------------------------------------- 1 file changed, 55 insertions(+), 512 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d7aae1b..97ac4a43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # 版本发布日志 +## 2.2504.4-20250430 + +- 修复 捕获数据时跳过延迟超过1毫秒的包 +- 修复 网元配置新增函数命名 +- 新增 新增终端策略规则接口 +- 新增 新增客户端授权管理和开放接口 +- 更新 更新omc自定义版权信息和系统名称 +- 新增 增加获取服务器时间接口 +- 修复 修复IMS导出中呼叫结果的处理逻辑 +- 修复 网元首圈状态检查离线时获取更新激活码 +- 新增 IMS导出功能增加呼叫结果和原因字段 +- 修复 首次引导tokan未记录 +- 更新 更新多语言表中的版权信息和系统名称为2025年版本 +- 重构 server configuration and update certificate handling +- 重构 error handling in system and trace controllers +- 新增 Implement Oauth2 login log service and repository +- 修复 UDMVolte用户特殊VoIP数据 +- 修复 调度日志消息长度限制至2000字符 +- 更新 更新数据库初始语句 +- 重构 添加定时导出UDM数据备份任务,优化CDR导出删除任务 +- 优化 UDM数据导出代码格式 +- 新增 统一备份数据发送ftp配置功能接口 +- 移除 无用go-cache封装 +- 新增 添加对本地文件的操作接口 +- 修复 移除网元备份文件ftp改用统一ftp配置 +- 新增 添加udm-voip/volte功能接口 +- 修复 网元主机title唯一导致冲突5002修改失败 +- 修复 更新日志文件路径,修正sshsvc配置 +- 修复 更新Deb和Rpm安装部分说明 +- 新增 更新依赖并重构应用引擎初始化逻辑, 支持Grafana +- 新增 新增告警导出接口 +- 更新 依赖库版本,指定go mod 1.24.0 +- 修复 IMS-CDR原因码字典补充 +- 修复 ws连接异常中断问题 +- 修复 网元主机title唯一导致冲突5002修改失败 +- 新增 配置控制首次登录密码修改 +- 修复 接口相应Err错误信息输出 +- 新增 信令跟踪功能接口定义 +- 更新 重构网元跟踪任务功能 +- 重构 网元跟踪任务功能 +- 重构 packet跟踪解析 +- 修复 网元重启命令改用systemctl +- 修复 注释掉测量数据插入逻辑 +- 新增 添加网元配置文件备份的FTP配置管理功能 +- 新增 mml补充UDM特殊命令处理 +- 修复 增加密码策略最小长度验证 +- 修复 超管账号跳过强制改密码 +- 修复 更新restagent为omc +- 更新 用户初始化admin属性设置错误 +- 更新 网元初始化默认只放OMC +- 新增 添加UDM融合AUSF的鉴权成功和请求次数指标 +- 修复 网元巡检告警检查创建时间不为0的 +- 更新 密码不允许使用最近修改的密码数据参数 +- 新增 密码不允许使用最近修改的密码功能 + ## 2.2503.4-20250331 - 重构 项目目录结构 @@ -18,515 +73,3 @@ - 新增 密码强度校验/密码过期时间功能 - 新增 密码不允许使用最近修改的密码功能 - 修复 网元巡检告警检查创建时间不为0的 - -## 2.2503.2-20250314 - -- 更新 SMSC CDR原因值字典翻译 -- 修复 用户新增部门parentId必填问题 -- 更新 自定义指标title的状态字段 -- 更新 AMF参数配置systemFeatOpt -- 优化 生产环境关闭GORM日志输出 -- 更新 配置文件数据库地址 - -## 2.2503.1-20250308 - -- 重构 优化UPF流量统计逻辑 -- 新增 字典数据重新加载附加多语言缓存 -- 新增 更新程序 --sqlPath 配置选项支持添加SQL导入功能 -- 修复 移除sys_dict_type表中的冗余唯一索引 -- 修复 网元状态更新带时间变化 -- 修复 网元安装Para5G参数读取nil和终端终止符判断 -- 修复 调整批量添加操作的批次大小为500,避免内存占用过大兼容轻量版本的操作 -- 修复 UDM数据IMSI勾选导出参数处理问题 -- 修复 读取kvdb数据截取IMSI数据验证逻辑,确保正确处理前缀和长度 -- 优化 修改ne_alarm_state_check任务的执行间隔为30秒 -- 优化 告警转发邮件优化 -- 优化 更新WebSocket组ID格式,移除冗余下划线 -- 优化 看板菜单权限控制部分显示 -- 优化 默认配置文件调整 -- 优化 查询like使用字符串拼接替代concat - -## 2.2502.4-20250228 - -- 重构 轻量化适配 - -## 2.2502.3-20250221 - -- 重构 数据库表结构变更 -- 重构 删除冗余常量文件并整合常量定义 -- 重构 更新多个模块以支持新的数据结构 -- 重构 更新依赖项,移除过时的库并添加新库 -- 重构 更新表索引命名 -- 修复 兼容3G的SGWC字段 - -## 2.2502.1-20250208 - -- 新增 基站状态记录上报和导出功能 -- 修复 IMS-CDR导出表头字段信息调整 -- 优化 监控接口/load和/system-info和/cache去除权限标识限制 -- 修复 本地免密认证端口去除限制22 -- 更新 swagger注释信息 - -## 2.2501.4-20250124 - -- 新增 日志备份文件同步FTP功能 -- 新增 调度任务-日志备份文件同步FTP功能 -- 新增 swagger接口文档版本1.0.8 -- 修复 网元主机title命名_随机4位 -- 修复 SSH工具远程复制文件夹创建 -- 修复 CDR网元数据查询结构体限定neType范围 -- 修复 网元直连SMF会话pageNum类型转换 -- 新增 MME参数配置项enbList,补充MME基站状态接口 -- 优化 自定义指标title公式,菜单基站在线页面隐藏 -- 优化 关闭接口加密功能 - -## 2.2501.3-20250117 - -- 优化 自定义指标数据查询值float64保留3为小数 -- 优化 网元状态字典映射Online改为Active -- 优化 暴露参数cryptoApi-用户接口加密 -- 更新 AMF配置可选属性gnbList隐藏 -- 新增 SMF-CDR搜索条件添加DNN - -## 2.2501.2-20250111 - -- 新增 角色admin添加基站状态菜单 -- 新增 接入swagger功能 -- 新增 网元状态3待机判断standby,类型字典数据 -- 更新 MME参数配置可选属性 -- 优化 配置文件加载,配置序列结构体到be.ems/lib/config -- 移除 captrace/data2html/crontask程序 -- 移除 upgvue3脚本文件,旧代码lib/core,旧代码假系统数据库备份 - -## 2.2501.1-20250103 - -- 新增 菜单-基站状态页面路由,定义接口功能 -- 更新 AMF/MME参数配置映射文件 -- 修复 网元安装MME补充hss域名到hosts - -## 2.2412.4-20241228 - -- 新增 菜单页面-SMF 用户使用数据流量报表 -- 新增 CDR 删除权限标识 cdr:ne:remove -- 新增 初始自定义指标 title -- 新增 AMF 基站状态查询接口,更新 AMF 配置项 gnbList -- 修复 SMF-CDR/SGWC-CDR 导出表格流量进行累加不分组显示 -- 修复 UDM 签约用户备注信息对应 IMSI 唯一 -- 修复 omc 升级日志输出文件权限写入问题 -- 修复 网元配置数据查询无 data 时默认返回空数组占位 -- 优化 配置文件读取错误显示中文问题 -- 优化 OMC 网元状态默认参数空时用“-”表示 -- 优化 AMF-UE 上报数据格式统一结构,UE 事件 AMF/MME 区分网元查询 - -## 2.2412.3-20241220 - -- 新增 直连网元请求带 UA 标识 OMC/version -- 新增 网元直连接口补充 AMF/SMF/MME/IMS -- 新增 CDR-SGWC 表定义,SGWC 参数配置可选属性 -- 新增 CDR 接收 SGWC 并推送, 数据功能接口, 菜单命名 SGWC-漫游数据 -- 优化 网元配置可选参数接口 - -## 2.2412.2-20241213 - -- 新增 网元信息通过 neType 查询函数 -- 新增 网元类型 HLR 跟踪查询类型 HLR,添加 HLR KPI 指标项数据 -- 修复 网元安装 redis 依赖包 bind 为 0.0.0.0 -- 修复 UDM 签约 cag 参数允许为空 -- 修复 custom indicator exist issue - -## 2.2412.1-20241209 - -- 修复 GetHashBatch 检查索引是否越界 -- 修复 网元备份 SMSC 配置文件 -- 修复 UDM 签约批量添加 msisdn 和 start_msisdn 识别导致数据一致 - -## 2.2411.4-20241130 - -- 新增 系统用户免登录认证,默认为 admin 操作所有接口 -- 新增 Para5G 参数 UPF 新增填写 N3 N6 网卡名 - -## 2.2411.3-20241123 - -- 修复 SMSC 安装 host 重复 -- 修复 字典多语言翻译 Multi-language - Chinese - -## 2.2411.2-20241115 - -- 新增 支持 aarch64 平台软件包 iperf v2 -- 新增 定时 UDM 数据加载每 12 小时一次 -- 修复 网元软件包升级时 rpm 同版本号强制安装 -- 更新 初始系统用户默认信息,手机号长度 32 位,系统菜单显示指标报表 - -## 2.2411.1-20241108 - -- 新增 iperf 支持 v2 的版本操作 -- 新增 网元主机添加 redis 连接终端控制 -- 更新 UDM 用户数据表索引更新 -- 更新 网元快速安装配置 UPF 网卡名和驱动类型参数 - -## 2.2410.4-20241102 - -- 新增 直连网元信息取得 hostname/os 属性值 -- 新增 UDM 鉴权签约 imsi 多查询 -- 更新 更新系统菜单新增关键指标概览 -- 更新 定时任务周期同步更新 UDM 用户数据 -- 更新 AMF/SMF 参数配置项数据 -- 修复 SMSC 安装时关联修改 IMS 和 UDM 配置 - -## 2.2410.3-20241018 - -- 新增 网元主机支持 redis 配置项 -- 新增 菜单功能 iperf3/ping 网络测试工具 -- 更新 抓包文件支持查看内容 -- 更新 初始网元相关表字段数据变更 -- 更新 UDM 用户数据按查询条件导出 - -## 2.2410.1-20241012 - -- 新增 系统菜单新增工具栏目,网元 SSH,网络测试,网络探针 -- 更新 UDM 签约数据表,同步数据支持 MICO 和 RAT 操作修改 -- 优化 MML 命令连接改为网元信息配置 telnet -- 更新 SMSC、AMF 参数配置数据 -- 更新 定时清除到导出文件缓存 - -## 2.2409.4-20240927 - -- 新增 跟踪任务 pcap 文件获取接口 -- 优化 socket 消息接收,跟踪任务推送 ws -- 修复 历史告警同步判断存在错误 -- 优化 redis 数据 scan 数调整 1000 -- 修复 SMF 在线订阅用户列表接口地址错误 -- 修复 多语言 SMSC 原因 0 表示未知 -- 新增 网元版本列表主动检查服务状态的版本 -- 更新 UDM 用户数据表字段 - -## 2.2409.3-20240920 - -- 修复 字典多语言序号重复问题 -- 更新 UDM 用户数据表,SMSC 参数配置属性,字典数据和跟踪相关表 -- 新增 跟踪任务 HLR 免登录接口 -- 新增 跟踪任务相关接口初始化,跟踪任务新增非 201/400 时接收信息 -- 修复 抓包文件下载 zip 时目录同名导致删除压缩无内容 - -## 2.2409.1-20240909 - -- 新增 告警前转的两个接口 email 前转和短信前转的系统参数,采用了和网元统一的参数配置方式, -- 优化 修改了 dpkg 和 rpm 包安装后的运行脚本,支持通过环境变量传入参数,并判断传入参数调用 setomc.sh 安装/升级数据库,命令格式:M_PARAM=upgrade C_PARAM=ba dpkg -I xxxx.deb,如果不传入参数则和以前相同 -- 调整的 dpkg 和 rpm 包安装的运行脚本中停止 omc 服务的顺序,解决了 omc 安装包在前端界面自升级时出现无法自动刷新的问题 - -## 2.2408.5-20240831 - -- 修复 系统信息读取磁盘获取超时导致返回空数组 -- 优化 缓存信息安全清理排除登录用户身份和验证码信息 -- 新增 KPI 自定义指标功能接口 -- 新增 日志数据导出文件查看功能接口 - -## 2.2408.4-20240823 - -- 优化 网元端文件目录/tmp/omc 上传 push 下载 pull -- 新增 网元文件操作可删除本地临时文件 -- 新增 系统菜单-信令抓包文件 -- 新增 KPI 添加 CBC -- 更新 CBC 参数配置可选属性 - -## 2.2408.3-20240816 - -- 新增 中间件-接口加解密,配合前端 CryptoJS 加解密 -- 新增 KPI 添加 SMSC -- 更新 IMS 参数配置可选属性 - -## 2.2408.2-20240809 - -- 新增 SMSC-CDR 功能接口 -- 新增 文件内容实时查看功能接口 -- 修复 WS 模块连接断开,存在 goroutenue 逃逸问题 - -## 2.2408.1-20240802 - -- 修复 菜单网元公共配置移除 -- 修复 关闭启动时默认 127.0.0..1 的 IP 绑定 -- 移除 kvdb 相关信息 -- 优化 导出数据根据查询条件导出 Execl - -## 2.2407.4-20240727 - -- 新增 网元配置备份功能 -- 新增 UDM 鉴权文件导入 K4 文件支持 -- 更新 对使用手册/官网进行按钮级限制 -- 修复 KPI 上报推送到对应网元,查询改用时间戳 -- 修复 IMS CDR RecordType 查询语法处理,兼容 mariadb 数据库 - -## 2.2407.3-20240716 - -- 更新 参数配置 AMF 参数配置 system -- 更新 参数配置 UPF 参数属性 dataForwarderCommon -- 修复 移除 omc 脚本命令前的 sudo - -## 2.2407.2-20240712 - -- 修复 网元版本安装 MME 写入 host 文件 ip 错误 -- 修复 支持 kvdb 依赖包安装,默认带的 adb 改为 kvdb -- 修复 网元版本安装命令终止符判断#$ -- 更新 CNType0 表示禁止接入 NA -- 修复 文件复制到本地时创建文件目录避免路径错误 - -## 2.2407.1-20240704 - -- 修复 网元版本安装 MME 修改 S6A 地址为 MME_IP -- 修复 网元公共参数 n3/n6IP 不携带/子网掩码处理异常 -- 更新 初始网元主机用 omcuser/a9tU53r 用密码登录方式 -- 更新 omc/log/内的 level 为 warn -- 更新 MML-OMC 隐藏 NBI 配置项 -- 更新 多语言 UE 事件改为终端事件/CNType 改 5G&4G -- 更新 多语言 CDR 翻译命名 Voice CDR / Data CDR - -## 2.2406.4-20240627 - -- 更新 关闭 crontask 任务异常 TaskHandShakeToNF -- 更新 参数配置 IMS 参数 DS System -- 更新 参数配置 MME 默认参数属性 -- 更新 字典多语言翻译,部门/系统名/初始密码备注 -- 修复 网元许可检查状态响应 nil 字符串 -- 修复 MML-UPF 标准版 5002 数据行约有 400+ -- 优化 UDM CN Type 可选类型字典数据 -- 移除 ims 命令执行的 sudo 前缀 - -## 2.2406.3-20240619 - -- 更新 参数配置 MME 参数默认值 -- 修复 角色数据权限范围配置示例系统日志区分 -- 优化 接口操作日志敏感属性掩码 token 头 -- 优化 用户岗位编辑权限 -- 优化 UE 事件 MME 类型结果保持和 AMF 一致 -- 移除 mmeUE 事件类型的字典数据 - -## 2.2406.2-20240617 - -- 修复 总览仪表盘用户活动数据不显示问题 -- 修复 旧 Session 过期查询 CPU 占用率过高 -- 优化 SMF 参数配置支持 cdr 相关配置 -- 优化 UDM 鉴权签约数据获取和重加载的速度 -- 修复 抓包操作失败 ssh 异常问题 - -## 2.2406.1-20240612 - -- 新增 快速开站和网元快速安装功能 -- 新增 SMF CDR 数据列表查询展示 -- 新增 IMS CDR 和 AMF UE 数据支持导出到表格文件 -- 优化 UPF、MME、IMS、SMF 参数配置项 -- 优化 软件管理和许可证管理功能页面 -- 修复 网元日志文件读取下载失败问题 - -## 2.2405.1-20240511 - -- 优化 使用新的黄金指标数据表查询统计 kpi -- 新增 支持网元 SMSC,包含状态,参数配置 -- 优化 SMF 参数配置增加新的项 -- 优化 删除残留的老的菜单项 - -## 2.2404.6-20240430 - -- 优化 网元状态信息表的记录修改为只保留一天 duration=1 -- 优化 删除过期记录的调度任务增加参数 sessFlag,true:使用 session 模式进行删除,false 或者不带该参数:不使用 session 模式删除(可加快速度) - -## 2.2404.5-20240426 - -- 优化 adb 升级目录切换,安装升级时替换/usr/local/etc/adb/adb.conf 的 replica-read-only 只读属性为 no,增加 masterauth 密码行 -- 修复 网元状态异常时如果网元的状态记录被完全清空导致无法产生 10000 的网元状态异常告警 -- 优化 后端增加 SMF 在线用户状态 Up State 的处理,修改查询接口,增加查询参数 upstate={Inactive/Active} -- 优化 告警短信前转,增加短信方式选择配置项,可使用短信云服务和短信中心模式,告警前转日志增加前转接口字段 -- 优化 重构黄金指标存储表,优化为将所有 kpiid 存储在一条记录,同时分网元存储不同的表如 kpi_report_amf,上周发布的版本黄金指标发送到原表和新的表,前端还未实现从新表获取统计数据 - -## 2.2404.4-20240419 - -- 优化 隐藏性能统计和跟踪的任务和数据菜单项 -- 修复 网管上 OMC 自升级数据库后重启 OMC 服务进程 -- 修复 OMC 网元操作重启失败 -- 优化 产品化共性问题,adb(redis)增加密码保护 -- 修复 调度任务获取网元状态任务失败 -- 优化 UPF 标准版的 MML 输出内容完整性, restconf.yaml 配置文件增加了 MML 配置项 -- 新增 合入 PCF 和 UDM 的参数配置,新增 plmn list 参数配置项 -- 修复 网元 license 上传时如果遇到网元没有 system.ini 文件时失败的问题 -- 优化 adb 安装目录变化:1. 判断/usr/local/bin/adb-server 存在时,则 OMC 不安装 adb, 2.判断/usr/local/bin/adb-server 不存在时,安装 adb 至新的路径,并判断老的 adb 是否存在,如果存在则拷贝/usr/local/db/bin/conf/dump.rdb 至/usr/local/etc/adb,修改/usr/local/db 目录为/usr/local/adb.old -- 优化 安装过程会将/usr/local/omc/etc 目录下的配置文件备份为.bak, 然后将/usr/local/omc/etc/default 目录下的配置文件拷贝至/usr/local/omc/etc 目录 -- 新增 支持告警通过短信中心的短信前转功能需求,配置项是 restconf.yaml 的 alarm.smsc - -## 2.2404.3-20240412 - -- 新增 IMS 参数配置增加 plmn 和 dialplan -- 新增 IMS KPI 黄金指标项支持 -- 优化 网元 UDM/AMF/MME/MOCNGW 的默认 plmn 和 dnn 的值 -- 新增 monitor 菜单项下增加话单(CDR)和事件(Event) -- 优化 restconf.yaml 和 capconf.yaml 的 gtp 默认端口统一改为 32152 -- 修复 部分修复 upf 标准版的 MML 命令输出内容,输出的内容和一般控制台窗口输出有差异,内容较多时会有--more--,后续需进一步优化 - -## 2.2404.1-20240402 - -- 新增 网元安装软包管理相关接口 -- 优化 网元安装授权流程相关接口操作 -- 优化 操作日志旧接口的网元参数配置多语言翻译 -- 修复 多语言翻译值转化 key 进行查询 -- 增加 MOCNGW 网元 KPI 和参数配置 -- 修复 时区问题,西半球时区出现时区格式转换错误,增加 database 配置项 connParam 用于配置数据库连接参数 -- 修复 配置文件配置多个指定 IP 地址时启动时会导致绑定 127.0.0.1 地址失败 -- 优化 升级脚本不再覆盖原有调度任务 2.2404.1-20240402 -- 新增 网元安装软包管理相关接口 -- 优化 网元安装授权流程相关接口操作 -- 优化 操作日志旧接口的网元参数配置多语言翻译 -- 修复 多语言翻译值转化 key 进行查询 -- 增加 MOCNGW 网元 KPI 和参数配置 -- 修复 时区问题,西半球时区出现时区格式转换错误,增加 database 配置项 connParam 用于配置数据库连接参数 -- 修复 配置文件配置多个指定 IP 地址时启动时会导致绑定 127.0.0.1 地址失败 -- 优化 升级脚本不再覆盖原有调度任务 - -## 2.2403.2-20240327 - -- 修复 OMC MML 翻译错误 -- 优化 判断 redis 数据库是否安装,如果已安装不再安装且不会提示错误 - -## 2.2403.1-20240321 - -- 新增 telnet 连接包工具 -- 新增 终端主机配置接口 -- 新增 终端主机命令接口 -- 新增 网元信息相关绑定主机接口,支持网元信息查询带主机信息查询 -- 新增 网元主机命令多语言字典接口提示和相关枚举翻译 -- 新增 ws 模块新增 ssh 和 telnet 类型连接 -- 新增 网元直连接口声明-网元配置对端网管信息 -- 新增 网元软件包信息/网元版本信息接口 -- 新增 网元主机 SSH 方式检查服务器环境接口 -- 新增 网元数据 CDR 和 UE 事件接口新增查询和删除,补充翻译 -- 新增 多处字典数据和页面菜单多语言翻译 -- 新增 网元信息接口对应页面菜单添加数据库脚本信息 -- 新增 网元版本基础接口/网元软件包基础接口 -- 修复 查询 SQL 结果 map 属性值转换导致的空字符 -- 修复 OMC 网元配置 omcNeConfig 接口覆盖 -- 修复 网元列表查询同步更新网元状态,操作同步更新/删除主机记录 -- 修复 SSH 对象序列化属性值不匹配 -- 修复 移除网元状态过滤判断 status in ('0','3') -- 修复 UE-PCF 接口超时时间 1m -- 优化 操作日志私钥 passPhrase 字段掩码\* -- 优化 ssh 包移除写入命令回车补位,移除读取等待 300s -- 优化 网元状态直连查询超时时间 250ms -- 优化 请求工具 PUT、POST 的超时时间设为 3s -- 优化 日志记录多层结构敏感属性字段进行掩码\* -- 优化 网元信息缓存 redis,UPF 总流量缓存数据小于 2 分钟重新缓存 -- 优化 网元列表状态在线时下发配置检查更新状态(3-待下发) -- 优化 网元版本表注释/网元软件包表注释 -- 修复告警手工同步问题 -- 修复增加网元时网元偶发丢失问题 -- 增加 upf 5002 的 telnet mml 接口,不过由于 UPF 只支持 localhost 登录,所以目前暂不可用 -- 修改默认侦听端口 33030 - -## 2.2402.6-20240222 - -- 删除 删除网元功能模块内性能指标控制路由函数 -- 优化 网元文件上传都放到 tmp 目录下 -- 优化 移动 cmd 包 -- 新增 加密 AES 包和 ssh 连接包 -- 优化 日志文件命名格式 log.2006-01-02 -- License 上传不再重启网元服务进程 -- MML 多条命令遇到执行失败时不再直接中断返回 -- UE 的所有功能菜单不再进行缓存 -- 发布的安装包清除了历史编译产生的前端 index.xxxx.js 文件 - -## 2.2402.5-20240205 - -- 新增 获取接口 UPF 总流量数 N3 上行 N6 下行数据 -- 优化 黄金指标 5s 数据获取 -- 优化 KPI 对 SMF5G 实时 PDU 会话数取最后一项不累加求和 -- 修复 ws 客户端读写保护/GroupID 调整,消息无消费 chan 溢出自动关闭 -- 新增 ws 支持 upf_tf 类型信息获取 UPF-总流量数 -- 新增 ws 支持网元状态查询 -- 修复 ws 处理接收发送 CDR 呼叫类型 MTC 推送 -- 新增 字典用户事件类型多语言翻译补充 -- 新增 支持 HTTP 2.0 服务请求 -- 修复 OMC 数据脚本,更新字典数据、拓扑数据 -- 优化 更新 gold_kpi 索引 -- 新增 系统菜单开启缓存信息和管理列表 -- 优化 参数配置表升级 sql -- 优化 网元类型缓存,缓存 10 分钟 UPF 总流量查询 -- 修复 CDR 事件推送类型 MOC/MOSM -- 优化 字典多语言补充 calltype sip202 -- 优化 CDR 事件推送类型 MOC/MTSM,查询支持 RecordType - -## 2.2401.4-20240130 - -- 调整数据库表升级脚本,字典和菜单目录的表在升级时不再全表重置,修复升级时会重置版权信息的中英文系统配置项 -- 更新了 UDM 的参数配置,修改了 ambr 速率默认值,加了空格。并且不限制中间有空格 - -## 2.2401.3-20240124 - -- OMC 自升级脚本增加执行 setomc.sh 的动作,修复 OMC 在网管升级时只解包没有升级数据库的过程 -- 黄金指标的数据表增加字段 granularity,用于计算颗粒度:granularity=endtime-starttime (s), 网元发送指标数据计算出的颗粒度值不一定是 5 或者 60 -- 由于 5 秒上报黄金指标,数据量增加,调度任务保留黄金指标的时长缩短至 3 天 -- 增加接收 IMS 上报的 CDR event 记录并保存到数据库表 cdr_event -- 增加接收 AMF 上报的 UE event 记录并保存至表 ue_event -- 此版本包含 2.2401.3-20240120 的修改,2.2401.3-20240120 版本废弃 - -## 2.2401.3-20240120 (discard) - -- 重构 抓包功能接口,支持开始到结束的控制,忽略抓包任务默认超时 30 分钟 -- 新增 配置参数验证码类型,字典数据补充多语言翻译 -- 优化 OMC 网元状态接口响应数据,兼容其他网元转发响应 -- IMS 软件升级安装通过脚本 expect 进行交互控制,默认输入 n -- 增加 OMC 软件自升级的功能,该版本的升级仍需在 ssh 控制台进行,在该版本的网管可对当前版本和后续版本进行升级安装 -- 增加两个脚本文件:/usr/local/omc/bin/actpkg.sh 和 rbkpkg.sh, 用于所有网元的升级和回退过程控制,修改激活和回退过程,实现所有网元包含 OMC 通过脚本进行,网元需要安装 expect 软件,否则会返回 99 错误码,在脚本文件中可控制交互输入(y/n)和超时时长 -- 修改终端(UE)菜单的 N3IWF Online User/NSSF Subscription Info/NSSF Available AMFs 默认为隐藏状态,即新安装/从无该项功能升级时为隐藏状态,对已有该菜单项的环境不做修改,如果需要显示或隐藏,可以在 System->Menu Management-UE 里边编辑菜单项为显示或隐藏 - -## 2.2401.2-20240112 - -- 修改 OMC 发布包 dpkg 安装脚本,不再覆盖已存在的 logo -- 增加 NSSF 的在线订阅数和注册 AMF 的功能 -- 整理菜单项和新增菜单项,trace 移到 monitor,monitor 分出 alam/topology/trace 三个菜单子目录 -- https 增加 clientAuthType 配置参数,更新 omc-ca.crt, omc-server.crt, omc-server.key 的根密钥,公钥,私钥 -- 修复 UDM 系统 MML 命令 help 输出信息过长导致乱码的问题,增加配置项 deadLine,用于配置 MML 操作时读写的超时时长 -- 导入 AMF,SMF,NSSF,MME 的自定义黄金指标项 -- 更新 amf,smf,upf,nssf 网元的参数配置的 comment 提示 -- 新增 拓扑图组数据新增 5gc 组网图排列展示 -- 优化 多语言数据在更新情况下改变原字典数据,后续放弃维护 csv 文件 -- 修复 调度任务日志在多语言情况下查询无数据问题 -- 修复 UPF 抓包异常提示 - -## 2.2401.1-20240105 - -- 新增 拓扑图组菜单,对应多语言字典数据补充 -- 新增 拓扑关系图数据表 -- 新增 拓扑关系数据相关接口 -- 优化 拓扑网元状态数据结构体调整,直连超时 200 毫秒 -- 定制化步骤只在 install 模式下执行, 新增-m skip 模式和-c agt 的定制化过程,skip 模式可跳过数据库安装或者升级过程,进行定制化过程,agt 定制化将初始化为 AGrandTech 界面信息 -- 修复 OMC 网元修改自身信息时打开同步开关失败问题 -- 修复网元状态巡检任务产生的告警编号为 0 的问题,修复周期获取网元状态信息任务失效问题 -- 网元启动时将上报告警编号 9000 的事件告警(部分网元已实现) -- MML 部分 UDM 操作 bad authdat 修改为 baa authdat, bad udmuser 修改为 baa udmuser -- SMF, UDM, PCF, NRF, AUSF 网元的参数配置文件 comment 字段提示信息进行整改 - -## 2.2312.10-20231229 - -- 增加 OMC 与 NSSF 的 Available AMFs 和 Subscription 的查询接口代码, NSSF 的代码未完成,暂未联调,菜单未开放 -- 确定序列号(SN)方案,增加网元状态在异常情况下可显示序列号和版本号(通过保存在 ne_state 的网元状态信息获取,且 ne_state 表中必须有 3 天内的网元状态数据) -- 调整优化获取网元状态命令的超时时长,优化网元状态主页的等待时间 -- BA 需求:增加网元在新增和修改时配置数据同步至网元的开关功能 -- 增加调度任务:删除过期网元状态信息 -- 移植调度任务:原有 crontask 的周期获取网元状态信息 -- 移植调度任务:原有 crontask 的检测网元状态异常并产生和消除告警的定时任务 -- 开放 IMS 的 MML 命令 -- 移除 installOMC.sh 脚本 -- 新增 支持 UDM 用户数据删除多个 imsi -- 修复 调度任务日志查询记录数据重复问题 -- 修复 角色状态变更导致菜单管理删除问题 - -## 2.2312.9-20231222 - -- 新增 性能 KPI 统计数据获取接口 -- 新增 网元日志列表获取接口 -- 新增 PCF 用户策略控制交互接口 -- 修复 UDM 用户数据导入 imsi 空值异常错误 -- 修复 列表数据分页最大页面数导致的读取数据不全问题 -- 修复 调度任务日志查询全部数据接口异常 -- 优化 UDM 用户数据同步信息及时更新 -- 优化 获取网元状态接口请求耗时过长 -- 优化 用户管理导入支持预先分别角色权限 -- 增加 setomc.sh 脚本,命令行格式:setomc.sh -m {install/upgrade/upgvue3} -c {BA/...}, -m 参数调用了 importdb.sh, -c 参数加"BA"表示设置 BA 的定制化 OMC 配置, 默认不执行定制化过程 -- 暂时屏蔽 IMS 网元的 MML 命令 -- UDM 签约用户数据增加/批量增加 MML 的字段 4G static IP 改为非必选 From bab9298adbe2f817ce972297b1e0dc9898455acf Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 30 Apr 2025 18:51:22 +0800 Subject: [PATCH 05/13] =?UTF-8?q?fix:=20=E6=8D=95=E8=8E=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=97=B6=E8=B7=B3=E8=BF=87=E5=BB=B6=E8=BF=9F=E8=B6=85?= =?UTF-8?q?=E8=BF=871=E7=A7=92=E7=9A=84=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/trace/service/packet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/trace/service/packet.go b/src/modules/trace/service/packet.go index 856b63ac..5b92be60 100644 --- a/src/modules/trace/service/packet.go +++ b/src/modules/trace/service/packet.go @@ -203,9 +203,9 @@ func (s *Packet) capturePacketSource(taskInfo *Task) { if packet == nil { continue } - // 如果延迟超过1毫秒跳过 + // 如果延迟超过1秒跳过 timeDiff := time.Since(packet.Metadata().Timestamp) - if timeDiff > time.Millisecond { + if timeDiff > time.Second { continue } From e4dc70548d37554458d5a4cb403bf4391fc979da Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 6 May 2025 11:30:41 +0800 Subject: [PATCH 06/13] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=8E=B7?= =?UTF-8?q?=E5=8F=96OMC=E7=8A=B6=E6=80=81=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/state/getstate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/state/getstate.go b/features/state/getstate.go index 40cb1a3b..9e7519e3 100644 --- a/features/state/getstate.go +++ b/features/state/getstate.go @@ -932,7 +932,7 @@ func GetEMSState(ip string) *SysState { DbInfo: dbInfo, IpAddr: ipAddrs, Port: port, - Version: global.Version, + Version: cfg.Version, Capability: CapabilityInt, SerialNum: snStr, ExpiryDate: expiryDateStr, From 7592c8c4d593a244e1fd250939f04c29958aa013 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 7 May 2025 15:49:22 +0800 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20=E6=A0=B9=E6=8D=AE=E7=BD=91?= =?UTF-8?q?=E5=85=83=E6=98=BE=E7=A4=BA=E7=89=B9=E6=9C=89=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E5=85=83=E4=BF=A1=E6=81=AF=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_menu.sql | 38 ++++++++++++------------ build/database/std/install/sys_menu.sql | 38 ++++++++++++------------ src/modules/system/model/vo/router.go | 13 ++++---- src/modules/system/service/sys_menu.go | 6 ++++ 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/build/database/lite/install/sys_menu.sql b/build/database/lite/install/sys_menu.sql index 155e48b7..ec23cc0c 100644 --- a/build/database/lite/install/sys_menu.sql +++ b/build/database/lite/install/sys_menu.sql @@ -109,18 +109,18 @@ INSERT INTO "sys_menu" VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', ' INSERT INTO "sys_menu" VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm:auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm:voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2003, 'menu.neData.udmVolte', 5, 7, 'udm-volte', 'neData/udm-volte/index', '1', '0', 'M', '1', '1', 'udm:volte:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2004, 'menu.neData.imsSub', 5, 9, 'ims-sub', 'neData/ims-sub/index', '1', '0', 'M', '1', '1', 'ims:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2005, 'menu.neData.smfSub', 5, 12, 'smf-sub', 'neData/smf-sub/index', '1', '0', 'M', '1', '1', 'smf:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2006, 'menu.neData.baseOnline', 5, 15, 'base-online', 'neData/base-online/index', '1', '0', 'M', '0', '1', 'amf,mme:base-online:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2007, 'menu.neData.baseStation', 5, 18, 'base-station', 'neData/base-station/index', '1', '0', 'M', '1', '1', 'amf,mme:base-station:list', 'icon-fenxiang', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2008, 'menu.ueUser.n3iwf', 5, 20, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'neUser:n3iwf:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2009, 'menu.neData.pcfSub', 5, 24, 'pcf-sub', 'neData/pcf-sub/index', '1', '0', 'M', '1', '1', 'pcf:sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2010, 'menu.neUser.nssf', 5, 26, 'nssf', 'neUser/nssf/index', '1', '0', 'M', '0', '1', 'neUser:nssf:index', 'icon-daimayingyong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2011, 'menu.neUser.nssfAmf', 5, 28, 'nssfAmf', 'neUser/nssfAmf/index', '1', '0', 'M', '0', '1', 'neUser:nssfAmf:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2003, 'menu.neData.udmVolte', 5, 7, 'udm-volte', 'neData/udm-volte/index', '1', '0', 'M', '1', '1', 'udm+ims#volte:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2004, 'menu.neData.imsSub', 5, 9, 'ims-sub', 'neData/ims-sub/index', '1', '0', 'M', '1', '1', 'ims#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2005, 'menu.neData.smfSub', 5, 12, 'smf-sub', 'neData/smf-sub/index', '1', '0', 'M', '1', '1', 'smf#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2006, 'menu.neData.baseOnline', 5, 15, 'base-online', 'neData/base-online/index', '1', '0', 'M', '0', '1', 'amf,mme#base-online:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2007, 'menu.neData.baseStation', 5, 18, 'base-station', 'neData/base-station/index', '1', '0', 'M', '1', '1', 'amf,mme#base-station:list', 'icon-fenxiang', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2008, 'menu.ueUser.n3iwf', 5, 20, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'n3iwf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2009, 'menu.neData.pcfSub', 5, 24, 'pcf-sub', 'neData/pcf-sub/index', '1', '0', 'M', '1', '1', 'pcf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2010, 'menu.neUser.nssf', 5, 26, 'nssf', 'neUser/nssf/index', '1', '0', 'M', '0', '1', 'nssf#sub:index', 'icon-daimayingyong', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2011, 'menu.neUser.nssfAmf', 5, 28, 'nssfAmf', 'neUser/nssfAmf/index', '1', '0', 'M', '0', '1', 'nssf#sub:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2083, 'menu.trace', 2087, 30, 'traceManage', '', '1', '0', 'D', '1', '1', '', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.traceRemark'); INSERT INTO "sys_menu" VALUES (2084, 'menu.trace.task', 2083, 1, 'task', 'traceManage/task/index', '1', '0', 'M', '1', '1', 'traceManage:task:index', 'icon-chexiao', '0', 'system', 1728641403588, 'system', 1744453890548, 'menu.trace.taskRemark'); INSERT INTO "sys_menu" VALUES (2085, 'menu.trace.taskData', 2083, 4, 'task/inline/data', 'traceManage/task/data', '1', '0', 'M', '0', '1', 'traceManage:task:data', '#', '0', 'system', 1728641403588, 'system', 1744453921381, ''); @@ -148,13 +148,13 @@ INSERT INTO "sys_menu" VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlMa INSERT INTO "sys_menu" VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.udmRemark'); INSERT INTO "sys_menu" VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '1', '1', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.setRemark'); INSERT INTO "sys_menu" VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.mml.omcRemark'); -INSERT INTO "sys_menu" VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.securityRemark'); INSERT INTO "sys_menu" VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemSetRemark'); INSERT INTO "sys_menu" VALUES (2115, 'menu.system.systemResource', 1, 6, 'monitor', 'monitor/monitor/index', '1', '1', 'M', '1', '1', 'monitor:monitor:info', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.systemResourceRemark'); INSERT INTO "sys_menu" VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2122, 'menu.system.setting.i18n', 2114, 1, '', '', '1', '1', 'B', '1', '1', 'system:setting:i18n', '#', '0', 'system', 1728641403588, 'system', 1728641403588, 'menu.system.setting.i18nRemark'); INSERT INTO "sys_menu" VALUES (2123, 'menu.log.neFile', 2089, 9, 'neFile', 'ne/neFile/index', '1', '0', 'M', '1', '1', 'ne:neFile:index', 'icon-tubiaohuizhi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -165,11 +165,11 @@ INSERT INTO "sys_menu" VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', ' INSERT INTO "sys_menu" VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'dashboard:amfUE:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -178,8 +178,8 @@ INSERT INTO "sys_menu" VALUES (2144, 'menu.ne.neSoftware', 4, 23, 'neSoftware', INSERT INTO "sys_menu" VALUES (2145, 'menu.ne.neVersion', 4, 26, 'neVersion', 'ne/neVersion/index', '1', '0', 'M', '1', '1', 'ne:neVersion:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2146, 'menu.ne.neConfig', 4, 28, 'neConfig', 'ne/neConfig/index', '1', '0', 'M', '1', '1', 'ne:neConfig:list', 'icon-wofaqi', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2147, 'menu.fault.event', 2129, 3, 'event', 'faultManage/event/index', '1', '0', 'M', '1', '1', 'faultManage:event:index', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2148, 'menu.dashboard.smfCDR', 2140, 6, 'smfCDR', 'dashboard/smfCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2149, 'menu.dashboard.mmeUE', 2141, 5, 'mmeUE', 'dashboard/mmeUE/index', '1', '0', 'M', '1', '1', 'dashboard:mmeUE:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2148, 'menu.dashboard.smfCDR', 2140, 6, 'smfCDR', 'dashboard/smfCDR/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2149, 'menu.dashboard.mmeUE', 2141, 5, 'mmeUE', 'dashboard/mmeUE/index', '1', '0', 'M', '1', '1', 'mme#ue:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2150, 'menu.system.user.editPost', 100, 9, '', '', '1', '1', 'B', '1', '1', 'system:user:editPost', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2151, 'menu.system.setting.doc', 2114, 2, '', '', '1', '1', 'B', '1', '1', 'system:setting:doc', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2152, 'menu.system.setting.official', 2114, 3, '', '', '1', '1', 'B', '1', '1', 'system:setting:official', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); @@ -187,7 +187,7 @@ INSERT INTO "sys_menu" VALUES (2153, 'menu.system.setting.lock', 2114, 4, '', '' INSERT INTO "sys_menu" VALUES (2154, 'menu.ne.neConfigBackup', 4, 29, 'neConfigBackup', 'ne/neConfigBackup/index', '1', '0', 'M', '1', '1', 'ne:neConfigBackup:list', 'icon-fuzhidaima', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2155, 'menu.common.delete', 2154, 1, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:remove', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2156, 'menu.common.edit', 2154, 2, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:edit', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); -INSERT INTO "sys_menu" VALUES (2157, 'menu.dashboard.smscCDR', 2140, 9, 'smscCDR', 'dashboard/smscCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); +INSERT INTO "sys_menu" VALUES (2157, 'menu.dashboard.smscCDR', 2140, 9, 'smscCDR', 'dashboard/smscCDR/index', '1', '0', 'M', '1', '1', 'smsc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2158, 'menu.trace.pcapFile', 2083, 12, 'pcap/inline/file', 'traceManage/pcap/file', '1', '0', 'M', '0', '1', 'traceManage:pcap:index', '#', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2159, 'menu.log.exportFile', 2089, 100, 'exportFile', 'logManage/exportFile/index', '1', '0', 'M', '1', '1', 'logManage:exportFile:index', 'icon-wenjian', '0', 'system', 1728641403588, 'system', 1728641403588, ''); INSERT INTO "sys_menu" VALUES (2160, 'menu.perf.kpiCReport', 2099, 100, 'kpiCReport', 'perfManage/kpiCReport/index', '1', '0', 'M', '1', '1', 'perfManage:kpiCReport:index', 'icon-tubiaoku', '0', 'system', 1728641403588, 'system', 1728641403588, ''); diff --git a/build/database/std/install/sys_menu.sql b/build/database/std/install/sys_menu.sql index 5c1f8239..81587d33 100644 --- a/build/database/std/install/sys_menu.sql +++ b/build/database/std/install/sys_menu.sql @@ -112,18 +112,18 @@ INSERT INTO `sys_menu` VALUES (1053, 'menu.common.edit', 116, 3, '#', '', '1', ' INSERT INTO `sys_menu` VALUES (1054, 'menu.common.delete', 116, 4, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (1055, 'menu.common.edit', 116, 5, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (1056, 'menu.common.export', 116, 6, '#', '', '1', '1', 'B', '1', '1', 'monitor:job:export', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm:auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm:voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2003, 'menu.neData.udmVolte', 5, 7, 'udm-volte', 'neData/udm-volte/index', '1', '0', 'M', '1', '1', 'udm:volte:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2004, 'menu.neData.imsSub', 5, 9, 'ims-sub', 'neData/ims-sub/index', '1', '0', 'M', '1', '1', 'ims:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2005, 'menu.neData.smfSub', 5, 12, 'smf-sub', 'neData/smf-sub/index', '1', '0', 'M', '1', '1', 'smf:sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2006, 'menu.neData.baseOnline', 5, 15, 'base-online', 'neData/base-online/index', '1', '0', 'M', '0', '1', 'amf,mme:base-online:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2007, 'menu.neData.baseStation', 5, 18, 'base-station', 'neData/base-station/index', '1', '0', 'M', '1', '1', 'amf,mme:base-station:list', 'icon-fenxiang', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2008, 'menu.ueUser.n3iwf', 5, 20, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'neUser:n3iwf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2009, 'menu.neData.pcfSub', 5, 24, 'pcf-sub', 'neData/pcf-sub/index', '1', '0', 'M', '1', '1', 'pcf:sub:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2010, 'menu.neUser.nssf', 5, 26, 'nssf', 'neUser/nssf/index', '1', '0', 'M', '0', '1', 'neUser:nssf:index', 'icon-daimayingyong', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2011, 'menu.neUser.nssfAmf', 5, 28, 'nssfAmf', 'neUser/nssfAmf/index', '1', '0', 'M', '0', '1', 'neUser:nssfAmf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2000, 'menu.neData.udmAuth', 5, 1, 'udm-auth', 'neData/udm-auth/index', '1', '1', 'M', '1', '1', 'udm#auth:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2001, 'menu.neData.udmSub', 5, 3, 'udm-sub', 'neData/udm-sub/index', '1', '1', 'M', '1', '1', 'udm#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2002, 'menu.neData.udmVOIP', 5, 5, 'udm-voip', 'neData/udm-voip/index', '1', '0', 'M', '1', '1', 'udm#voip:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2003, 'menu.neData.udmVolte', 5, 7, 'udm-volte', 'neData/udm-volte/index', '1', '0', 'M', '1', '1', 'udm+ims#volte:list', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2004, 'menu.neData.imsSub', 5, 9, 'ims-sub', 'neData/ims-sub/index', '1', '0', 'M', '1', '1', 'ims#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2005, 'menu.neData.smfSub', 5, 12, 'smf-sub', 'neData/smf-sub/index', '1', '0', 'M', '1', '1', 'smf#sub:index', 'icon-xiangmuchengyuan', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2006, 'menu.neData.baseOnline', 5, 15, 'base-online', 'neData/base-online/index', '1', '0', 'M', '0', '1', 'amf,mme#base-online:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2007, 'menu.neData.baseStation', 5, 18, 'base-station', 'neData/base-station/index', '1', '0', 'M', '1', '1', 'amf,mme#base-station:list', 'icon-fenxiang', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2008, 'menu.ueUser.n3iwf', 5, 20, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'n3iwf#sub:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2009, 'menu.neData.pcfSub', 5, 24, 'pcf-sub', 'neData/pcf-sub/index', '1', '0', 'M', '1', '1', 'pcf#sub:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2010, 'menu.neUser.nssf', 5, 26, 'nssf', 'neUser/nssf/index', '1', '0', 'M', '0', '1', 'nssf#sub:index', 'icon-daimayingyong', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2011, 'menu.neUser.nssfAmf', 5, 28, 'nssfAmf', 'neUser/nssfAmf/index', '1', '0', 'M', '0', '1', 'nssf#sub:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2083, 'menu.trace', 2087, 30, 'traceManage', '', '1', '0', 'D', '1', '1', '', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.traceRemark'); INSERT INTO `sys_menu` VALUES (2084, 'menu.trace.task', 2083, 1, 'task', 'traceManage/task/index', '1', '0', 'M', '1', '1', 'traceManage:task:index', 'icon-chexiao', '0', 'system', 1728641403588, 'system', 1744453890548, 'menu.trace.taskRemark'); INSERT INTO `sys_menu` VALUES (2085, 'menu.trace.taskData', 2083, 4, 'task/inline/data', 'traceManage/task/data', '1', '0', 'M', '0', '1', 'traceManage:task:data', '#', '0', 'system', 1728641403588, 'system', 1744453921381, ''); @@ -151,13 +151,13 @@ INSERT INTO `sys_menu` VALUES (2108, 'menu.mml.ne', 2107, 1, 'neOperate', 'mmlMa INSERT INTO `sys_menu` VALUES (2109, 'menu.mml.udm', 2107, 2, 'udmOperate', 'mmlManage/udmOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:udmOperate:index', 'icon-gonggaodayi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.udmRemark'); INSERT INTO `sys_menu` VALUES (2110, 'menu.mml.set', 2107, 4, 'mmlSet', 'mmlManage/mmlSet/index', '1', '0', 'M', '1', '1', 'mmlManage:mmlSet:index', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.setRemark'); INSERT INTO `sys_menu` VALUES (2111, 'menu.mml.omc', 2107, 3, 'omcOperate', 'mmlManage/omcOperate/index', '1', '1', 'M', '1', '1', 'mmlManage:omcOperate:index', 'icon-huizhiguize', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.mml.omcRemark'); -INSERT INTO `sys_menu` VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2112, 'menu.dashboard.sgwcCDR', 2140, 12, 'sgwcCDR', 'dashboard/sgwcCDR/index', '1', '0', 'M', '1', '1', 'sgwc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2113, 'menu.security', 0, 14, 'security', '', '1', '0', 'D', '1', '1', '', 'icon-suofang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.securityRemark'); INSERT INTO `sys_menu` VALUES (2114, 'menu.system.systemSet', 1, 60, 'setting', 'system/setting/index', '1', '1', 'M', '1', '1', 'system:setting:index', 'icon-piliang', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemSetRemark'); INSERT INTO `sys_menu` VALUES (2115, 'menu.system.systemResource', 1, 6, 'monitor', 'monitor/monitor/index', '1', '1', 'M', '1', '1', 'monitor:monitor:info', 'icon-soutubiao', '0', 'system', 1728641403588,'system', 1728641403588, 'menu.system.systemResourceRemark'); INSERT INTO `sys_menu` VALUES (2116, 'menu.dashboard.smscCDR.content', 2157, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:smsc:content', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2117, 'menu.common.delete', 2140, 1, '', '', '1', '1', 'B', '1', '1', 'cdr:ne:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2118, 'menu.dashboard.smfCDRByIMSI', 2140, 7, 'smfCDRByIMSI', 'dashboard/smfCDRByIMSI/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-gerenzhanghu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -- INSERT INTO `sys_menu` VALUES (2119, 'menu.ueUser.n3iwf', 5, 8, 'n3iwf', 'neUser/n3iwf/index', '1', '0', 'M', '0', '1', 'neUser:n3iwf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -- INSERT INTO `sys_menu` VALUES (2120, 'menu.ueUser.pcf', 5, 9, 'pcf', 'neUser/pcf/index', '1', '0', 'M', '1', '1', 'neUser:pcf:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2121, 'menu.system.user.editRole', 100, 8, '', '', '1', '1', 'B', '1', '1', 'system:user:editRole', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -172,11 +172,11 @@ INSERT INTO `sys_menu` VALUES (2129, 'menu.alarm', 2087, 20, 'alarm', '', '1', ' INSERT INTO `sys_menu` VALUES (2130, 'menu.topology', 2087, 10, 'topology', '', '1', '0', 'D', '1', '1', '', 'icon-anzhuo', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2131, 'menu.dashboard', 2087, 15, 'dashboard', '', '1', '0', 'D', '1', '1', '', 'icon-soutubiao', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2132, 'menu.dashboard.overview', 2131, 1, 'overview', 'dashboard/overview/index', '1', '0', 'M', '1', '1', 'dashboard:overview:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2133, 'menu.dashboard.imsCDR', 2140, 3, 'imsCDR', 'dashboard/imsCDR/index', '1', '0', 'M', '1', '1', 'ims#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2135, 'menu.ne.neHost', 4, 15, 'neHost', 'ne/neHost/index', '1', '1', 'M', '1', '0', 'ne:neHost:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2136, 'menu.ne.neHostCommand', 4, 18, 'neHostCommand', 'ne/neHostCommand/index', '1', '0', 'M', '1', '0', 'ne:neHostCommand:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2137, 'menu.ne.neInfo', 4, 10, 'neInfo', 'ne/neInfo/index', '1', '0', 'M', '1', '1', 'ne:neInfo:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'dashboard:amfUE:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2138, 'menu.dashboard.amfUE', 2141, 1, 'amfUE', 'dashboard/amfUE/index', '1', '0', 'M', '1', '1', 'amf#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2140, 'menu.monitor.cdr', 2089, 10, 'cdr', '', '1', '0', 'D', '1', '1', '', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2141, 'menu.monitor.event', 2089, 20, 'event', '', '1', '0', 'D', '1', '1', '', 'icon-gengduo', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2142, 'menu.ne.neQuickSetup', 4, 40, 'neQuickSetup', 'ne/neQuickSetup/index', '1', '1', 'M', '1', '1', 'ne:neQuickSetup:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -185,8 +185,8 @@ INSERT INTO `sys_menu` VALUES (2144, 'menu.ne.neSoftware', 4, 23, 'neSoftware', INSERT INTO `sys_menu` VALUES (2145, 'menu.ne.neVersion', 4, 26, 'neVersion', 'ne/neVersion/index', '1', '0', 'M', '1', '1', 'ne:neVersion:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2146, 'menu.ne.neConfig', 4, 28, 'neConfig', 'ne/neConfig/index', '1', '0', 'M', '1', '1', 'ne:neConfig:list', 'icon-wofaqi', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2147, 'menu.fault.event', 2129, 3, 'event', 'faultManage/event/index', '1', '0', 'M', '1', '1', 'faultManage:event:index', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2148, 'menu.dashboard.smfCDR', 2140, 6, 'smfCDR', 'dashboard/smfCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2149, 'menu.dashboard.mmeUE', 2141, 5, 'mmeUE', 'dashboard/mmeUE/index', '1', '0', 'M', '1', '1', 'dashboard:mmeUE:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2148, 'menu.dashboard.smfCDR', 2140, 6, 'smfCDR', 'dashboard/smfCDR/index', '1', '0', 'M', '1', '1', 'smf#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2149, 'menu.dashboard.mmeUE', 2141, 5, 'mmeUE', 'dashboard/mmeUE/index', '1', '0', 'M', '1', '1', 'mme#ue:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2150, 'menu.system.user.editPost', 100, 9, '', '', '1', '1', 'B', '1', '1', 'system:user:editPost', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2151, 'menu.system.setting.doc', 2114, 2, '', '', '1', '1', 'B', '1', '1', 'system:setting:doc', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2152, 'menu.system.setting.official', 2114, 3,'', '', '1', '1', 'B', '1', '1', 'system:setting:official', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); @@ -194,7 +194,7 @@ INSERT INTO `sys_menu` VALUES (2153, 'menu.system.setting.lock', 2114, 4, '', '' INSERT INTO `sys_menu` VALUES (2154, 'menu.ne.neConfigBackup', 4, 29, 'neConfigBackup', 'ne/neConfigBackup/index', '1', '0', 'M', '1', '1', 'ne:neConfigBackup:list', 'icon-fuzhidaima', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2155, 'menu.common.delete', 2154, 1, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:remove', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2156, 'menu.common.edit', 2154, 2, '#', '', '1', '1', 'B', '1', '1', 'ne:neConfigBackup:edit', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); -INSERT INTO `sys_menu` VALUES (2157, 'menu.dashboard.smscCDR', 2140, 9, 'smscCDR', 'dashboard/smscCDR/index', '1', '0', 'M', '1', '1', 'dashboard:cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); +INSERT INTO `sys_menu` VALUES (2157, 'menu.dashboard.smscCDR', 2140, 9, 'smscCDR', 'dashboard/smscCDR/index', '1', '0', 'M', '1', '1', 'smsc#cdr:index', 'icon-paixu', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2158, 'menu.trace.pcapFile', 2083, 12, 'pcap/inline/file', 'traceManage/pcap/file', '1', '0', 'M', '0', '1', 'traceManage:pcap:index', '#', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2159, 'menu.log.exportFile', 2089, 100, 'exportFile', 'logManage/exportFile/index', '1', '0', 'M', '1', '1', 'logManage:exportFile:index', 'icon-wenjian', '0', 'system', 1728641403588,'system', 1728641403588, ''); INSERT INTO `sys_menu` VALUES (2160, 'menu.perf.kpiCReport', 2099, 100, 'kpiCReport', 'perfManage/kpiCReport/index', '1', '0', 'M', '1', '1', 'perfManage:kpiCReport:index', 'icon-tubiaoku', '0', 'system', 1728641403588,'system', 1728641403588, ''); diff --git a/src/modules/system/model/vo/router.go b/src/modules/system/model/vo/router.go index ccfe366c..63a83418 100644 --- a/src/modules/system/model/vo/router.go +++ b/src/modules/system/model/vo/router.go @@ -12,10 +12,11 @@ type Router struct { // RouterMeta 路由元信息对象 type RouterMeta struct { - Title string `json:"title"` // 设置该菜单在侧边栏和面包屑中展示的名字 - Icon string `json:"icon"` // 设置该菜单的图标 - Cache bool `json:"cache"` // 设置为true,则不会被 缓存 - Target string `json:"target"` // 内链地址(http(s)://开头), 打开目标位置 '_blank' | '_self' | '' - HideChildInMenu bool `json:"hideChildInMenu"` // 在菜单中隐藏子节点 - HideInMenu bool `json:"hideInMenu"` // 在菜单中隐藏自己和子节点 + Title string `json:"title"` // 设置该菜单在侧边栏和面包屑中展示的名字 + Icon string `json:"icon"` // 设置该菜单的图标 + Cache bool `json:"cache"` // 设置为true,则不会被 缓存 + Target string `json:"target"` // 内链地址(http(s)://开头), 打开目标位置 '_blank' | '_self' | '' + HideChildInMenu bool `json:"hideChildInMenu"` // 在菜单中隐藏子节点 + HideInMenu bool `json:"hideInMenu"` // 在菜单中隐藏自己和子节点 + NeType []string `json:"neType,omitempty"` // 网元类型,默认全部,有指定类型的,需要添加网元才会显示 } diff --git a/src/modules/system/service/sys_menu.go b/src/modules/system/service/sys_menu.go index 10af417d..14f01061 100644 --- a/src/modules/system/service/sys_menu.go +++ b/src/modules/system/service/sys_menu.go @@ -329,6 +329,12 @@ func (s SysMenu) getRouteMeta(sysMenu model.SysMenu) vo.RouterMeta { meta.Target = "_blank" } + // 网元类型菜单显示权限 + if strings.Contains(sysMenu.Perms, "#") { + firstIndex := strings.Index(sysMenu.Perms, "#") + meta.NeType = strings.Split(strings.ToUpper(sysMenu.Perms[:firstIndex]), ",") + } + return meta } From 8fe41b136fd28067eb966b06514f3426c617c288 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 11:36:43 +0800 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20=E7=BD=91=E5=85=83=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7=E5=AE=B9=E9=87=8F?= =?UTF-8?q?=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/ne_license.sql | 7 ++++--- build/database/std/install/ne_license.sql | 18 ++---------------- .../network_element/controller/ne_license.go | 9 ++++++--- .../network_element/model/ne_license.go | 1 + 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/build/database/lite/install/ne_license.sql b/build/database/lite/install/ne_license.sql index a83ba824..37480406 100644 --- a/build/database/lite/install/ne_license.sql +++ b/build/database/lite/install/ne_license.sql @@ -8,14 +8,15 @@ CREATE TABLE "ne_license" ( "ne_id" text(32) NOT NULL, "activation_request_code" text(255) NOT NULL, "license_path" text(255), + "capability" integer, "serial_num" text(32), "expiry_date" text(32), "status" text(32), "remark" text(255), "create_by" text(50), - "create_time" integer(20), + "create_time" integer, "update_by" text(50), - "update_time" integer(20), + "update_time" integer, PRIMARY KEY ("id") ); @@ -31,4 +32,4 @@ ON "ne_license" ( -- ---------------------------- -- Records of ne_license -- ---------------------------- -INSERT INTO "ne_license" VALUES (1, 'OMC', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); +INSERT INTO "ne_license" VALUES (1, 'OMC', '001', '', '', 0, '', '', '0', '', 'system', 1713928436971, '', 0); diff --git a/build/database/std/install/ne_license.sql b/build/database/std/install/ne_license.sql index 6bae442b..b5414da5 100644 --- a/build/database/std/install/ne_license.sql +++ b/build/database/std/install/ne_license.sql @@ -13,6 +13,7 @@ CREATE TABLE `ne_license` ( `ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '网元ID', `activation_request_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '激活申请代码', `license_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '激活授权文件', + `capability` bigint DEFAULT '0' COMMENT '用户容量', `serial_num` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '序列号', `expiry_date` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '许可证到期日期', `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '状态 0无效 1有效', @@ -26,22 +27,7 @@ CREATE TABLE `ne_license` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网元_授权激活信息'; -- 初始数据对应网元 -INSERT INTO `ne_license` VALUES (1, 'OMC', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (2, 'IMS', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (3, 'AMF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (4, 'AUSF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (5, 'UDM', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (6, 'SMF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (7, 'PCF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (8, 'NSSF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (9, 'NRF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (10, 'UPF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (11, 'LMF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (12, 'NEF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (13, 'MME', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (14, 'N3IWF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (14, 'N3IWF', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_license` VALUES (15, 'SMSC', '001', '', '', '', '', '0', '', 'system', 1713928436971, '', 0); +INSERT INTO `ne_license` VALUES (1, 'OMC', '001', '', '', 0, '', '', '0', '', 'system', 1713928436971, '', 0); SET FOREIGN_KEY_CHECKS=1; diff --git a/src/modules/network_element/controller/ne_license.go b/src/modules/network_element/controller/ne_license.go index 92a37ba8..64bc1a84 100644 --- a/src/modules/network_element/controller/ne_license.go +++ b/src/modules/network_element/controller/ne_license.go @@ -156,6 +156,7 @@ func (s *NeLicenseController) Code(c *gin.Context) { if licensePath != "" { neLicense.LicensePath = licensePath } else { + neLicense.Capability = 0 neLicense.SerialNum = "" neLicense.ExpiryDate = "" neLicense.Status = "0" @@ -259,6 +260,7 @@ func (s *NeLicenseController) State(c *gin.Context) { } if neState, err := neFetchlink.NeState(neInfo); err == nil && neState["sn"] != nil { neLicense.Status = "1" + neLicense.Capability = parse.Number(neState["capability"]) neLicense.SerialNum = fmt.Sprint(neState["sn"]) neLicense.ExpiryDate = fmt.Sprint(neState["expire"]) } else { @@ -274,9 +276,10 @@ func (s *NeLicenseController) State(c *gin.Context) { s.neLicenseService.Update(neLicense) if neLicense.Status == "1" { - c.JSON(200, resp.OkData(map[string]string{ - "sn": neLicense.SerialNum, - "expire": neLicense.ExpiryDate, + c.JSON(200, resp.OkData(map[string]any{ + "capability": neLicense.Capability, + "sn": neLicense.SerialNum, + "expire": neLicense.ExpiryDate, })) return } diff --git a/src/modules/network_element/model/ne_license.go b/src/modules/network_element/model/ne_license.go index 9b98c39f..016593b6 100644 --- a/src/modules/network_element/model/ne_license.go +++ b/src/modules/network_element/model/ne_license.go @@ -7,6 +7,7 @@ type NeLicense struct { NeId string `json:"neId" gorm:"column:ne_id" binding:"required"` // 网元ID ActivationRequestCode string `json:"activationRequestCode" gorm:"column:activation_request_code"` // 激活申请代码 LicensePath string `json:"licensePath" gorm:"column:license_path"` // 激活授权文件 + Capability int64 `json:"capability" gorm:"column:capability"` // 用户容量 SerialNum string `json:"serialNum" gorm:"column:serial_num"` // 序列号 ExpiryDate string `json:"expiryDate" gorm:"column:expiry_date"` // 许可证到期日期 Status string `json:"status" gorm:"column:status"` // 状态 0无效 1有效 From 774c865e97284261757c22dd691de9776431d135 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 11:49:28 +0800 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=E7=BD=91=E5=85=83=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=AE=B0=E5=BD=95=E5=86=85=E5=AD=98/CPU/=E7=A3=81?= =?UTF-8?q?=E7=9B=98=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/ne_state.sql | 14 ++- build/database/std/install/ne_state.sql | 23 ++-- .../network_data/controller/all_ne_state.go | 59 ++++++++++ src/modules/network_data/model/ne_state.go | 35 ++++++ src/modules/network_data/network_data.go | 9 ++ .../network_data/repository/nb_state.go | 5 +- .../network_data/repository/ne_state.go | 110 ++++++++++++++++++ src/modules/network_data/service/ne_state.go | 31 +++++ 8 files changed, 267 insertions(+), 19 deletions(-) create mode 100644 src/modules/network_data/controller/all_ne_state.go create mode 100644 src/modules/network_data/model/ne_state.go create mode 100644 src/modules/network_data/repository/ne_state.go create mode 100644 src/modules/network_data/service/ne_state.go diff --git a/build/database/lite/install/ne_state.sql b/build/database/lite/install/ne_state.sql index 7ddea274..08a6528b 100644 --- a/build/database/lite/install/ne_state.sql +++ b/build/database/lite/install/ne_state.sql @@ -7,13 +7,15 @@ CREATE TABLE "ne_state" ( "ne_type" text(16), "ne_id" text(32), "version" text(16), - "capability" text(64), + "capability" integer, "serial_num" text(16), "expiry_date" text(10), - "cpu_usage" text, - "mem_usage" text, - "disk_space" text, - "timestamp" integer(20), + "sys_cpu_usage" integer, + "sys_mem_usage" integer, + "sys_disk_usage" integer, + "nf_cpu_usage" integer, + "nf_mem_used" integer, + "create_time" integer, PRIMARY KEY ("id") ); @@ -24,7 +26,7 @@ CREATE INDEX "idx_type_id_time" ON "ne_state" ( "ne_type" ASC, "ne_id" ASC, - "timestamp" ASC + "create_time" ASC ); -- ---------------------------- diff --git a/build/database/std/install/ne_state.sql b/build/database/std/install/ne_state.sql index 844650fb..6d44ed7e 100644 --- a/build/database/std/install/ne_state.sql +++ b/build/database/std/install/ne_state.sql @@ -5,21 +5,22 @@ SET FOREIGN_KEY_CHECKS = 0; -- Table structure for table `ne_state` -- DROP TABLE IF EXISTS `ne_state`; - CREATE TABLE `ne_state` ( `id` int NOT NULL AUTO_INCREMENT, `ne_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', `ne_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', - `version` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', - `capability` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', - `serial_num` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', - `expiry_date` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '', - `cpu_usage` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT 'json信息', - `mem_usage` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT 'json信息', - `disk_space` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT 'json信息', - `timestamp` bigint DEFAULT '0' COMMENT '创建时间', + `version` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '版本', + `capability` bigint DEFAULT '0' COMMENT '用户容量', + `serial_num` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '序列号', + `expiry_date` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '许可证到期日期', + `sys_cpu_usage` float DEFAULT '0' COMMENT 'cpu使用率-sys', + `sys_mem_usage` float DEFAULT '0' COMMENT '内存使用率-sys', + `sys_disk_usage` float DEFAULT '0' COMMENT '磁盘使用率-sys', + `nf_cpu_usage` float DEFAULT '0' COMMENT 'cpu使用率-nf', + `nf_mem_used` bigint DEFAULT '0' COMMENT '内存使用KB-nf', + `create_time` bigint DEFAULT '0' COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, - KEY `idx_type_id_time` (`ne_type`,`ne_id`,`timestamp`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网元_状态记录'; + KEY `idx_type_id_time` (`ne_type`,`ne_id`,`create_time`) USING BTREE COMMENT 'idx_state_ne_type_id_at' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网元_状态记录内存/CPU/磁盘'; SET FOREIGN_KEY_CHECKS=1; diff --git a/src/modules/network_data/controller/all_ne_state.go b/src/modules/network_data/controller/all_ne_state.go new file mode 100644 index 00000000..66862313 --- /dev/null +++ b/src/modules/network_data/controller/all_ne_state.go @@ -0,0 +1,59 @@ +package controller + +import ( + "fmt" + + "github.com/gin-gonic/gin" + + "be.ems/src/framework/resp" + "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" +) + +// 实例化控制层 NEStateController 结构体 +var NewNEState = &NEStateController{ + neInfoService: neService.NewNeInfo, + neStateService: neDataService.NewNEState, +} + +// 网元状态记录 +// +// PATH /ne-state +type NEStateController struct { + neInfoService *neService.NeInfo // 网元信息服务 + neStateService *neDataService.NEState // 网元状态服务 +} + +// 网元状态记录-内存/CPU/磁盘列表 +// +// GET /list +// +// @Tags network_data +// @Accept json +// @Produce json +// @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) default(AMF) +// @Param neId query string true "NE ID" default(001) +// @Param pageNum query number true "pageNum" default(1) +// @Param pageSize query number true "pageSize" default(10) +// @Param startTime query number false "Start time (timestamped milliseconds)" default(1729162507596) +// @Param endTime query number false "End time (timestamped milliseconds)" default(1729164187611) +// @Param sortField query string false "Sort fields, fill in result fields" Enums(id,create_time) default(id) +// @Param sortOrder query string false "Sort by ascending or descending order" Enums(asc,desc) default(asc) +// @Success 200 {object} object "Response Results" +// @Security TokenAuth +// @Summary NE Status Record - Memory/CPU/Disk List +// @Description NE Status Record - Memory/CPU/Disk List +// @Router /ne-state/list [get] +func (s NEStateController) List(c *gin.Context) { + var query model.NEStateQuery + if err := c.ShouldBindQuery(&query); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(422001, errMsgs)) + return + } + + // 查询数据 + rows, total := s.neStateService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} diff --git a/src/modules/network_data/model/ne_state.go b/src/modules/network_data/model/ne_state.go new file mode 100644 index 00000000..b875f58f --- /dev/null +++ b/src/modules/network_data/model/ne_state.go @@ -0,0 +1,35 @@ +package model + +// NEState 网元状态记录表 ne_state +type NEState struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeId string `json:"neId" gorm:"column:ne_id"` + Version string `json:"version" gorm:"column:version"` // 版本 + Capability int64 `json:"capability" gorm:"column:capability"` // 用户容量 + SerialNum string `json:"serialNum" gorm:"column:serial_num"` // 序列号 + ExpiryDate string `json:"expiryDate" gorm:"column:expiry_date"` // 许可证到期日期 + SysCpuUsage float64 `json:"sysCpuUsage" gorm:"column:sys_cpu_usage"` // cpu使用率-sys + SysMemUsage float64 `json:"sysMemUsage" gorm:"column:sys_mem_usage"` // 内存使用率-sys + SysDiskUsage float64 `json:"sysDiskUsage" gorm:"column:sys_disk_usage"` // 磁盘使用率-sys + NfCpuUsage float64 `json:"nfCpuUsage" gorm:"column:nf_cpu_usage"` // cpu使用率-nf + NfMemUsed int64 `json:"nfMemUsed" gorm:"column:nf_mem_used"` // 内存使用KB-nf + CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间 +} + +// TableName 表名称 +func (*NEState) TableName() string { + return "ne_state" +} + +// NEStateQuery 查询参数结构体 +type NEStateQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` + NeID string `json:"neId" form:"neId" binding:"required"` + PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` + PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` + BeginTime string `json:"beginTime" form:"beginTime"` + EndTime string `json:"endTime" form:"endTime"` + SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=id create_time"` // 排序字段,填写结果字段 + SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index bab4b2c5..d0a68959 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -84,6 +84,15 @@ func Setup(router *gin.Engine) { ) } + // 网元状态记录信息 + neStateGroup := neDataGroup.Group("/ne-state") + { + neStateGroup.GET("/list", + middleware.AuthorizeUser(nil), + controller.NewNEState.List, + ) + } + // 基站状态历史记录信息 含AMF/MME nbStateGroup := neDataGroup.Group("/nb-state") { diff --git a/src/modules/network_data/repository/nb_state.go b/src/modules/network_data/repository/nb_state.go index 0c3fa1ed..6faf437c 100644 --- a/src/modules/network_data/repository/nb_state.go +++ b/src/modules/network_data/repository/nb_state.go @@ -5,6 +5,7 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" "be.ems/src/modules/network_data/model" ) @@ -35,14 +36,14 @@ func (r NBState) SelectByPage(query model.NBStateQuery) ([]model.NBState, int64) if len(startTime) == 10 { startTime = startTime + "000" } - tx = tx.Where("create_time >= ?", startTime) + tx = tx.Where("time >= ?", date.ParseDateToStr(startTime, date.YYYY_MM_DDTHH_MM_SSZ)) } if query.EndTime != "" { endTime := query.EndTime if len(endTime) == 10 { endTime = endTime + "999" } - tx = tx.Where("create_time <= ?", endTime) + tx = tx.Where("time <= ?", date.ParseDateToStr(endTime, date.YYYY_MM_DDTHH_MM_SSZ)) } // 查询结果 diff --git a/src/modules/network_data/repository/ne_state.go b/src/modules/network_data/repository/ne_state.go new file mode 100644 index 00000000..05f48a8f --- /dev/null +++ b/src/modules/network_data/repository/ne_state.go @@ -0,0 +1,110 @@ +package repository + +import ( + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 NEState 结构体 +var NewNEState = &NEState{} + +// NEState 网元状态记录表 数据层处理 +type NEState struct{} + +// SelectByPage 分页查询集合 +func (r NEState) SelectByPage(query model.NEStateQuery) ([]model.NEState, int64) { + tx := db.DB("").Model(&model.NEState{}) + // 查询条件拼接 + if query.NeType != "" { + tx = tx.Where("ne_type = ?", query.NeType) + } + if query.NeID != "" { + tx = tx.Where("ne_id = ?", query.NeID) + } + if query.BeginTime != "" { + startTime := query.BeginTime + if len(startTime) == 10 { + startTime = startTime + "000" + } + tx = tx.Where("create_time >= ?", startTime) + } + if query.EndTime != "" { + endTime := query.EndTime + if len(endTime) == 10 { + endTime = endTime + "999" + } + tx = tx.Where("create_time <= ?", endTime) + } + + // 查询结果 + var total int64 = 0 + rows := []model.NEState{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 排序 + if query.SortField != "" { + sortField := query.SortField + if query.SortOrder == "desc" { + sortField = sortField + " desc" + } + tx = tx.Order(sortField) + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query.PageNum, query.PageSize) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows, total + } + return rows, total +} + +// SelectByIds 通过ID查询 +func (r NEState) SelectByIds(ids []string) []model.NEState { + rows := []model.NEState{} + if len(ids) <= 0 { + return rows + } + tx := db.DB("").Model(&model.NEState{}) + // 构建查询条件 + 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 +} + +// DeleteByTime 删除信息 +func (r NEState) DeleteByTime(ltTime int64) int64 { + if ltTime <= 0 { + return 0 + } + tx := db.DB("").Where("create_time < ?", ltTime) + if err := tx.Delete(&model.NEState{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// Insert 新增信息 +func (r NEState) Insert(param model.NEState) int64 { + param.CreateTime = time.Now().UnixMilli() + // 执行插入 + if err := db.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} diff --git a/src/modules/network_data/service/ne_state.go b/src/modules/network_data/service/ne_state.go new file mode 100644 index 00000000..be467f18 --- /dev/null +++ b/src/modules/network_data/service/ne_state.go @@ -0,0 +1,31 @@ +package service + +import ( + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" +) + +// 实例化数据层 NEState 结构体 +var NewNEState = &NEState{ + neStateRepository: repository.NewNEState, +} + +// NEState 网元状态记录表 服务层处理 +type NEState struct { + neStateRepository *repository.NEState // 网元状态记录信息 +} + +// FindByPage 根据条件分页查询 +func (r NEState) FindByPage(query model.NEStateQuery) ([]model.NEState, int64) { + return r.neStateRepository.SelectByPage(query) +} + +// Insert 插入数据 +func (r NEState) Insert(item model.NEState) int64 { + return r.neStateRepository.Insert(item) +} + +// DeleteByTime 删除数据 +func (r NEState) DeleteByTime(ltTime int64) int64 { + return r.neStateRepository.DeleteByTime(ltTime) +} From 8c663f1e185d86f6d54e5ee9762cc5fbb3847d1a Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 11:51:21 +0800 Subject: [PATCH 10/13] =?UTF-8?q?fix:=20CDR=E6=95=B0=E6=8D=AE=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=B7=BB=E5=8A=A0=E7=BD=91=E5=85=83=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/ne_info.sql | 2 +- build/database/lite/install/ne_version.sql | 4 +- build/database/std/install/ne_host.sql | 30 --------------- build/database/std/install/ne_info.sql | 16 +------- build/database/std/install/ne_version.sql | 14 ------- .../network_data/repository/cdr_event_ims.go | 4 +- .../network_data/service/cdr_event_ims.go | 38 ++++++++++--------- .../network_data/service/cdr_event_smf.go | 1 - .../network_data/service/cdr_event_smsc.go | 26 +++++++------ .../network_element/controller/ne_info.go | 18 ++++++--- 10 files changed, 52 insertions(+), 101 deletions(-) diff --git a/build/database/lite/install/ne_info.sql b/build/database/lite/install/ne_info.sql index a4962be9..045f1ec0 100644 --- a/build/database/lite/install/ne_info.sql +++ b/build/database/lite/install/ne_info.sql @@ -37,4 +37,4 @@ ON "ne_info" ( -- ---------------------------- -- Records of ne_info -- ---------------------------- -INSERT INTO "ne_info" VALUES (1, 'OMC', '001', '4400HXOMC001', 'OMC_001', '172.16.5.100', 33030, 'PNF', 'AreaNet', '-', '-', '-', '1,2', 0, '', 'system', 1713928436971, '', 0); +INSERT INTO "ne_info" VALUES (1, 'OMC', '001', '4400HXOMC001', 'OMC_001', '127.0.0.1', 33030, 'PNF', 'AreaNet', '-', '-', '-', '1,2', 0, '', 'system', 1713928436971, '', 0); diff --git a/build/database/lite/install/ne_version.sql b/build/database/lite/install/ne_version.sql index 8b3cb4f9..45df6d5e 100644 --- a/build/database/lite/install/ne_version.sql +++ b/build/database/lite/install/ne_version.sql @@ -17,9 +17,9 @@ CREATE TABLE "ne_version" ( "new_path" text(255), "status" text(16), "create_by" text(50), - "create_time" integer(20), + "create_time" integer, "update_by" text(50), - "update_time" integer(20), + "update_time" integer, PRIMARY KEY ("id") ); diff --git a/build/database/std/install/ne_host.sql b/build/database/std/install/ne_host.sql index 0e699b7f..03322c99 100644 --- a/build/database/std/install/ne_host.sql +++ b/build/database/std/install/ne_host.sql @@ -32,36 +32,6 @@ CREATE TABLE `ne_host` ( -- 初始数据对应网元 INSERT INTO `ne_host` VALUES (1, 'ssh', '1', 'OMC_001_22', '127.0.0.1', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); INSERT INTO `ne_host` VALUES (2, 'telnet', '1', 'OMC_001_4100', '127.0.0.1', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (3, 'ssh', '1', 'IMS_001_22', '172.16.5.110', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (4, 'telnet', '1', 'IMS_001_4100', '172.16.5.110', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (5, 'ssh', '1', 'AMF_001_22', '172.16.5.120', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (6, 'telnet', '1', 'AMF_001_4100', '172.16.5.120', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (7, 'ssh', '1', 'AUSF_001_22', '172.16.5.130', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (8, 'telnet', '1', 'AUSF_001_4100', '172.16.5.130', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (9, 'ssh', '1', 'UDM_001_22', '172.16.5.140', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (10, 'telnet', '1', 'UDM_001_4100', '172.16.5.140', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (11, 'redis', '1', 'UDM_001_6379', '172.16.5.140', 6379, 'udmdb', '0', 'nO3fEhtuKuBkQE5ozsUhNfzn02vhnyxYTEiPn2CIlr4=', '', '', '0', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (12, 'ssh', '1', 'SMF_001_22', '172.16.5.150', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (13, 'telnet', '1', 'SMF_001_4100', '172.16.5.150', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (14, 'ssh', '1', 'PCF_001_22', '172.16.5.160', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (15, 'telnet', '1', 'PCF_001_4100', '172.16.5.160', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (16, 'ssh', '1', 'NSSF_001_22', '172.16.5.170', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (17, 'telnet', '1', 'NSSF_001_4100', '172.16.5.170', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (18, 'ssh', '1', 'NRF_001_22', '172.16.5.180', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (19, 'telnet', '1', 'NRF_001_4100', '172.16.5.180', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (20, 'ssh', '1', 'UPF_001_22', '172.16.5.190', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (21, 'telnet', '1', 'UPF_001_4100', '172.16.5.190', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (22, 'telnet', '1', 'UPF_001_5002', '172.16.5.190', 5002, 'admin', '0', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (23, 'ssh', '1', 'LMF_001_22', '172.16.5.200', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (24, 'telnet', '1', 'LMF_001_4100', '172.16.5.200', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (25, 'ssh', '1', 'NEF_001_22', '172.16.5.210', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (26, 'telnet', '1', 'NEF_001_4100', '172.16.5.210', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (27, 'ssh', '1', 'MME_001_22', '172.16.5.220', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (28, 'telnet', '1', 'MME_001_4100', '172.16.5.220', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (29, 'ssh', '1', 'N3IWF_001_22', '172.16.5.230', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (30, 'telnet', '1', 'N3IWF_001_4100', '172.16.5.230', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (31, 'ssh', '1', 'SMSC_001_22', '172.16.5.240', 22, 'omcuser', '2', '', '', '', '', '', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_host` VALUES (32, 'telnet', '1', 'SMSC_001_4100', '172.16.5.240', 4100, 'admin', '0', 'NUBonCin4GZgl7o12YjeClE8ToQmYp9KWdhMjSNxc2M=', '', '', '', '', 'system', 1729063407329, '', 0); SET FOREIGN_KEY_CHECKS=1; diff --git a/build/database/std/install/ne_info.sql b/build/database/std/install/ne_info.sql index 0f8fc6ea..01dcda0d 100644 --- a/build/database/std/install/ne_info.sql +++ b/build/database/std/install/ne_info.sql @@ -32,21 +32,7 @@ CREATE TABLE `ne_info` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网元_基础信息表 关联对应版本、授权、主机'; -- 初始网元数据 -INSERT INTO `ne_info` VALUES (1, 'OMC', '001', '4400HXOMC001', 'OMC_001', '172.16.5.100', 33030, 'PNF', 'AreaNet', '-', '-', '-', '1,2', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (2, 'IMS', '001', '4400HXIMS001', 'IMS_001', '172.16.5.110', 33030, 'PNF', 'AreaNet', '-', '-', '-', '3,4', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (3, 'AMF', '001', '4400HXAMF001', 'AMF_001', '172.16.5.120', 33030, 'PNF', 'AreaNet', '-', '-', '', '5,6', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (4, 'AUSF', '001', '4400HXAUSF001', 'AUSF_001', '172.16.5.130', 33030, 'PNF', 'AreaNet', '-', '-', '', '7,8', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (5, 'UDM', '001', '4400HXUDM001', 'UDM_001', '172.16.5.140', 33030, 'PNF', 'AreaNet', '-', '-', '-', '9,10,11', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (6, 'SMF', '001', '4400HXSMF001', 'SMF_001', '172.16.5.150', 33030, 'PNF', 'AreaNet', '-', '-', '-', '12,13', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (7, 'PCF', '001', '4400HXPCF001', 'PCF_001', '172.16.5.160', 33030, 'PNF', 'AreaNet', '-', '-', '-', '14,15', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (8, 'NSSF', '001', '4400HXNSSF001', 'NSSF_001', '172.16.5.170', 33030, 'PNF', 'AreaNet', '-', '-', '-', '16,17', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (9, 'NRF', '001', '4400HXNRF001', 'NRF_001', '172.16.5.180', 33030, 'PNF', 'AreaNet', '-', '-', '-', '18,19', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (10, 'UPF', '001', '4400HXUPF001', 'UPF_001', '172.16.5.190', 33030, 'PNF', 'AreaNet', '-', '-', '', '20,21,22', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (11, 'LMF', '001', '4400HXLMF001', 'LMF_001', '172.16.5.200', 33030, 'PNF', 'AreaNet', '-', '-', '-', '23,24', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (12, 'NEF', '001', '4400HXNEF001', 'NEF_001', '172.16.5.210', 33030, 'PNF', 'AreaNet', '-', '-', '-', '25,26', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (13, 'MME', '001', '4400HXMME001', 'MME_001', '172.16.5.220', 33030, 'PNF', 'AreaNet', '-', '-', '', '27,28', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (14, 'N3IWF', '001', '4400HXN3IWF001', 'N3IWF_001', '172.16.5.230', 33030, 'PNF', 'AreaNet', '-', '-', '', '29,30', 0, '', 'system', 1713928436971, '', 0); --- INSERT INTO `ne_info` VALUES (15, 'SMSC', '001', '4400HXSMSC001', 'SMSC_001', '172.16.5.240', 33030, 'PNF', 'AreaNet', '-', '-', '', '31,32', 0, '', 'system', 1713928436971, '', 0); +INSERT INTO `ne_info` VALUES (1, 'OMC', '001', '4400HXOMC001', 'OMC_001', '127.0.0.1', 33030, 'PNF', 'AreaNet', '-', '-', '-', '1,2', 0, '', 'system', 1713928436971, '', 0); SET FOREIGN_KEY_CHECKS=1; diff --git a/build/database/std/install/ne_version.sql b/build/database/std/install/ne_version.sql index 4d281389..75d06258 100644 --- a/build/database/std/install/ne_version.sql +++ b/build/database/std/install/ne_version.sql @@ -31,20 +31,6 @@ CREATE TABLE `ne_version` ( -- 初始数据对应网元 INSERT INTO `ne_version` VALUES (1, 'OMC', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (2, 'IMS', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (3, 'AMF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (4, 'AUSF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (5, 'UDM', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (6, 'SMF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (7, 'PCF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (8, 'NSSF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (9, 'NRF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (10, 'UPF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (11, 'LMF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (12, 'NEF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (13, 'MME', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (14, 'N3IWF', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); --- INSERT INTO `ne_version` VALUES (15, 'SMSC', '001', '', '', '', '', '', '', '', '', '', '0', 'system', 1729063407329, '', 0); SET FOREIGN_KEY_CHECKS=1; diff --git a/src/modules/network_data/repository/cdr_event_ims.go b/src/modules/network_data/repository/cdr_event_ims.go index de14e4a6..814bd83d 100644 --- a/src/modules/network_data/repository/cdr_event_ims.go +++ b/src/modules/network_data/repository/cdr_event_ims.go @@ -26,10 +26,10 @@ func (r CDREventIMS) SelectByPage(query model.CDREventIMSQuery) ([]model.CDREven tx = tx.Where("rm_uid = ?", query.RmUID) } if query.BeginTime != 0 { - tx = tx.Where("timestamp >= ?", query.BeginTime) + tx = tx.Where("created_at >= ?", query.BeginTime) } if query.EndTime != 0 { - tx = tx.Where("timestamp <= ?", query.EndTime) + tx = tx.Where("created_at <= ?", query.EndTime) } if query.CallerParty != "" { tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') = ?", query.CallerParty) diff --git a/src/modules/network_data/service/cdr_event_ims.go b/src/modules/network_data/service/cdr_event_ims.go index 1c92d397..30ad78a8 100644 --- a/src/modules/network_data/service/cdr_event_ims.go +++ b/src/modules/network_data/service/cdr_event_ims.go @@ -51,15 +51,16 @@ func (r CDREventIMS) ExportXlsx(rows []model.CDREventIMS, fileName, language str // 第一行表头标题 headerCells := map[string]string{ "A1": "ID", - "B1": "Record Behavior", - "C1": "Type", - "D1": "Caller", - "E1": "Called", - "F1": "Duration", - "G1": "Result Code", - "H1": "Result Cause", - "I1": "Call Start Time", - "J1": "Hangup Time", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Type", + "E1": "Caller", + "F1": "Called", + "G1": "Duration", + "H1": "Result Code", + "I1": "Result Cause", + "J1": "Call Start Time", + "K1": "Hangup Time", } // 读取字典数据 CDR SIP响应代码类别类型 dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code") @@ -154,15 +155,16 @@ func (r CDREventIMS) ExportXlsx(rows []model.CDREventIMS, fileName, language str 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: callCause, - "I" + idx: seizureTimeStr, - "J" + idx: releaseTimeStr, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: callTypeLable, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: duration, + "H" + idx: callResult, + "I" + idx: callCause, + "J" + idx: seizureTimeStr, + "K" + idx: releaseTimeStr, }) } diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go index 14b229a3..cb5bc7fb 100644 --- a/src/modules/network_data/service/cdr_event_smf.go +++ b/src/modules/network_data/service/cdr_event_smf.go @@ -72,7 +72,6 @@ func (r CDREventSMF) ExportXlsx(rows []model.CDREventSMF, fileName string) (stri } // 从第二行开始的数据 dataCells := make([]map[string]any, 0) - for i, row := range rows { idx := strconv.Itoa(i + 2) // 解析 JSON 字符串为 map diff --git a/src/modules/network_data/service/cdr_event_smsc.go b/src/modules/network_data/service/cdr_event_smsc.go index 01ed2bac..99006c31 100644 --- a/src/modules/network_data/service/cdr_event_smsc.go +++ b/src/modules/network_data/service/cdr_event_smsc.go @@ -51,12 +51,13 @@ func (r CDREventSMSC) ExportXlsx(rows []model.CDREventSMSC, fileName, language s // 第一行表头标题 headerCells := map[string]string{ "A1": "ID", - "B1": "Record Behavior", - "C1": "Service Type", - "D1": "Caller", - "E1": "Called", - "F1": "Result", - "G1": "Time", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Service Type", + "E1": "Caller", + "F1": "Called", + "G1": "Result", + "H1": "Time", } // 读取字典数据 CDR 原因码 dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code") @@ -121,12 +122,13 @@ func (r CDREventSMSC) ExportXlsx(rows []model.CDREventSMSC, fileName, language s 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, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: serviceType, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: callResult, + "H" + idx: timeStr, }) } diff --git a/src/modules/network_element/controller/ne_info.go b/src/modules/network_element/controller/ne_info.go index 133dd782..5786227d 100644 --- a/src/modules/network_element/controller/ne_info.go +++ b/src/modules/network_element/controller/ne_info.go @@ -397,13 +397,16 @@ func (s NeInfoController) Add(c *gin.Context) { if v, ok := body.ServerState["version"]; ok && v != nil { neVersion.Name = "-" neVersion.Path = "-" - neVersion.Version = v.(string) + neVersion.Version = fmt.Sprint(v) + } + if v, ok := body.ServerState["capability"]; ok && v != nil { + neLicense.Capability = parse.Number(v) } if v, ok := body.ServerState["sn"]; ok && v != nil { - neLicense.SerialNum = v.(string) + neLicense.SerialNum = fmt.Sprint(v) } if v, ok := body.ServerState["expire"]; ok && v != nil { - neLicense.ExpiryDate = v.(string) + neLicense.ExpiryDate = fmt.Sprint(v) neLicense.Status = "1" } } @@ -495,14 +498,17 @@ func (s NeInfoController) Edit(c *gin.Context) { if v, ok := body.ServerState["version"]; ok && v != nil { neVersion.Name = "-" neVersion.Path = "-" - neVersion.Version = v.(string) + neVersion.Version = fmt.Sprint(v) neVersion.UpdateBy = loginUserName } + if v, ok := body.ServerState["capability"]; ok && v != nil { + neLicense.Capability = parse.Number(v) + } if v, ok := body.ServerState["sn"]; ok && v != nil { - neLicense.SerialNum = v.(string) + neLicense.SerialNum = fmt.Sprint(v) } if v, ok := body.ServerState["expire"]; ok && v != nil { - neLicense.ExpiryDate = v.(string) + neLicense.ExpiryDate = fmt.Sprint(v) neLicense.Status = "1" neLicense.UpdateBy = loginUserName } From ad6626e67b9e0ce35a72ef44828d8b6df4350f7d Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 11:53:24 +0800 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20Execl=E8=AF=BB=E5=86=99=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/utils/file/excel.go | 158 +++++++++++++++------- src/modules/system/controller/sys_user.go | 2 +- 2 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/framework/utils/file/excel.go b/src/framework/utils/file/excel.go index 2d52683c..b19676ec 100644 --- a/src/framework/utils/file/excel.go +++ b/src/framework/utils/file/excel.go @@ -37,55 +37,6 @@ func TransferExeclUploadFile(file *multipart.FileHeader) (string, error) { return filepath.ToSlash(writePathFile), nil } -// 表格读取数据 -// -// filePath 文件路径地址 -// -// sheetName 工作簿名称, 空字符默认Sheet1 -func ReadSheet(filePath, sheetName string) ([]map[string]string, error) { - data := make([]map[string]string, 0) - // 打开 Excel 文件 - f, err := excelize.OpenFile(filePath) - if err != nil { - return data, err - } - defer func() { - if err := f.Close(); err != nil { - logger.Errorf("ReadSheet to close worksheet file : %v", err) - } - }() - - // 检查工作簿是否存在 - if sheetName == "" { - sheetName = "Sheet1" - } - if visible, _ := f.GetSheetVisible(sheetName); !visible { - return data, fmt.Errorf("failed to read workbook %s", sheetName) - } - - // 获取工作簿记录 - rows, err := f.GetRows(sheetName) - if err != nil { - return data, err - } - - for i, row := range rows { - // 跳过第一行 - if i == 0 { - continue - } - // 遍历每个单元格 - rowData := map[string]string{} - for columnIndex, cellValue := range row { - columnName, _ := excelize.ColumnNumberToName(columnIndex + 1) - rowData[columnName] = cellValue - } - - data = append(data, rowData) - } - return data, nil -} - // 表格写入数据 // // headerCells 第一行表头标题 "A1":"?" @@ -152,3 +103,112 @@ func WriteSheet(headerCells map[string]string, dataCells []map[string]any, fileN } return saveFilePath, nil } + +// WriterFileExecl 写入xlsx文件 +// +// 例如: +// headerCells := map[string]string{"A1": "姓名", "B1": "年龄", "C1": "城市"} +// +// dataCells := []map[string]any{ +// {"A2": "1", "B2": "2", "C2": "3"}, +// } +// +// filePath := "example.xlsx" +// err := file.WriterFileExecl(headerCells, dataCells, filePath, "Sheet1") +func WriterFileExecl(headerCells map[string]string, dataCells []map[string]any, filePath, sheetName string) error { + f := excelize.NewFile() + defer func() { + if err := f.Close(); err != nil { + logger.Errorf("WriterFileExecl to close worksheet file: %v", err) + } + }() + + // 创建一个工作表 + if sheetName == "" { + sheetName = "Sheet1" + } + index, err := f.NewSheet(sheetName) + if err != nil { + return fmt.Errorf("failed to create worksheet %v", err) + } + // 设置工作簿的默认工作表 + f.SetActiveSheet(index) + + // 首个和最后key名称 + firstKey := "A" + lastKey := "B" + + // 第一行表头标题 + for key, title := range headerCells { + f.SetCellValue(sheetName, key, title) + if key[:1] > lastKey { + lastKey = key[:1] + } + } + + // 设置工作表上宽度为 20 + f.SetColWidth(sheetName, firstKey, lastKey, 20) + + // 从第二行开始的数据 + for _, cell := range dataCells { + for key, value := range cell { + f.SetCellValue(sheetName, key, value) + } + } + + // 创建文件目录 + if err := os.MkdirAll(filepath.Dir(filePath), 0775); err != nil { + return fmt.Errorf("failed to create save file %v", err) + } + + // 根据指定路径保存文件 + if err := f.SaveAs(filePath); err != nil { + return fmt.Errorf("failed to save worksheet %v", err) + } + return nil +} + +// ReadFileExecl 读取xlsx文件 转换数组数据 +func ReadFileExecl(filePath, sheetName string) ([]map[string]string, error) { + data := make([]map[string]string, 0) + // 打开 Excel 文件 + f, err := excelize.OpenFile(filePath) + if err != nil { + return data, err + } + defer func() { + if err := f.Close(); err != nil { + logger.Errorf("ReadSheet to close worksheet file : %v", err) + } + }() + + // 检查工作簿是否存在 + if sheetName == "" { + sheetName = "Sheet1" + } + if visible, _ := f.GetSheetVisible(sheetName); !visible { + return data, fmt.Errorf("failed to read workbook %s", sheetName) + } + + // 获取工作簿记录 + rows, err := f.GetRows(sheetName) + if err != nil { + return data, err + } + + for i, row := range rows { + // 跳过第一行 + if i == 0 { + continue + } + // 遍历每个单元格 + rowData := map[string]string{} + for columnIndex, cellValue := range row { + columnName, _ := excelize.ColumnNumberToName(columnIndex + 1) + rowData[columnName] = cellValue + } + + data = append(data, rowData) + } + return data, nil +} diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index 22c12b18..84961a9d 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -655,7 +655,7 @@ func (s *SysUserController) Import(c *gin.Context) { // 表格文件绝对地址 filePath := file.ParseUploadFileAbsPath(body.FilePath) // 读取表格数据 - rows, err := file.ReadSheet(filePath, "") + rows, err := file.ReadFileExecl(filePath, "") if err != nil { c.JSON(200, resp.ErrMsg(err.Error())) return From 4989f45a03feb77d130e3a4956e888304825900a Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 11:54:56 +0800 Subject: [PATCH 12/13] =?UTF-8?q?fix:=20=E5=91=8A=E8=AD=A6=E6=B8=85?= =?UTF-8?q?=E9=99=A4=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84AlarmCode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 4 ++++ src/framework/constants/alarm.go | 8 ++++++-- src/modules/network_data/service/alarm.go | 11 ++++++++++- src/modules/ws/service/ws_send.go | 4 +++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 831963f5..a4dfcd0d 100644 --- a/main.go +++ b/main.go @@ -74,6 +74,10 @@ var wg sync.WaitGroup // @tag.description network data udm authentication interface // @tag.name network_data/udm/sub // @tag.description network data udm subscriber interface +// @tag.name network_data/udm/voip +// @tag.description network data udm voip interface +// @tag.name network_data/udm/volte-ims +// @tag.description network data udm volte interface // @tag.name network_data/upf // @tag.description network data upf interface // diff --git a/src/framework/constants/alarm.go b/src/framework/constants/alarm.go index e07f5067..f22c8e2d 100644 --- a/src/framework/constants/alarm.go +++ b/src/framework/constants/alarm.go @@ -2,8 +2,12 @@ package constants // 告警 alarmCode 常量 const ( - // ALARM_STATE_CHECK 告警-状态检查 - ALARM_STATE_CHECK = 10000 // ALARM_EVENT_REBOOT 事件-网元重启 ALARM_EVENT_REBOOT = 9000 + // ALARM_STATE_CHECK 告警-状态检查 + ALARM_STATE_CHECK = 10000 + // ALARM_RAM_CPU_CHECK 告警-内存/CPU/磁盘检查 + ALARM_CMD_CHECK = 10001 + // ALARM_LICENSE_CHECK 告警-网元License到期检查 + ALARM_LICENSE_CHECK = 10002 ) diff --git a/src/modules/network_data/service/alarm.go b/src/modules/network_data/service/alarm.go index a7fcd286..bb98a45a 100644 --- a/src/modules/network_data/service/alarm.go +++ b/src/modules/network_data/service/alarm.go @@ -77,7 +77,7 @@ func (r Alarm) AlarmClearByIds(ids []int64, clearUser string) (int64, error) { var rows int64 = 0 for _, v := range arr { // 状态检查AlarmCode变更告警ID - if v.AlarmCode == constants.ALARM_STATE_CHECK { + if v.AlarmCode == constants.ALARM_STATE_CHECK || v.AlarmCode == constants.ALARM_CMD_CHECK || v.AlarmCode == constants.ALARM_LICENSE_CHECK { v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) } v.AlarmStatus = "0" @@ -120,6 +120,15 @@ func (r Alarm) AlarmAckByIds(ids []int64, ackUser string, ackState bool) (int64, return 0, fmt.Errorf("ack fail") } +// InsertAndForword 新增信息并转发通知 +func (s Alarm) InsertAndForword(param model.Alarm) int64 { + rows := s.alarmRepository.Insert(param) + if rows > 0 { + // 转发通知 TODO + } + return rows +} + // ExportXlsx 导出数据到 xlsx 文件 func (r Alarm) ExportXlsx(rows []model.Alarm, fileName, language, alarmStatus string) (string, error) { // 第一行表头标题 diff --git a/src/modules/ws/service/ws_send.go b/src/modules/ws/service/ws_send.go index 3cf88541..adcccaef 100644 --- a/src/modules/ws/service/ws_send.go +++ b/src/modules/ws/service/ws_send.go @@ -16,6 +16,8 @@ const ( GROUP_TRACE_NE = "2" // 组号-信令跟踪Packet 4_taskNo GROUP_TRACE_PACKET = "4" + // 组号-网元状态 8_neType_neId + GROUP_NE_STATE = "8" // 组号-指标通用 10_neType_neId GROUP_KPI = "10" // 组号-自定义KPI指标 20_neType_neId @@ -34,7 +36,7 @@ const ( GROUP_MME_UE = "1011" // 组号-告警 2000_neType_neId GROUP_ALARM = "2000" - // 组号-告警事件 2000_neType_neId + // 组号-告警事件 2002_neType_neId GROUP_ALARM_EVENT = "2002" ) From 448c705f86d0bd79c317dbd65e09289a360a866b Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 9 May 2025 14:21:23 +0800 Subject: [PATCH 13/13] =?UTF-8?q?feat:=20=E8=B0=83=E5=BA=A6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=AF=BC=E5=87=BAcdr/log/=E5=91=8A=E8=AD=A6=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E7=BD=91=E5=85=83cpu/liencse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/database/lite/install/sys_i18n.sql | 90 +- build/database/lite/install/sys_job.sql | 26 +- build/database/std/install/sys_i18n.sql | 18 +- build/database/std/install/sys_job.sql | 30 +- .../backup_export_cdr/backup_export_cdr.go | 1427 +++++++++++++++++ .../backup_export_log/backup_export_log.go | 358 +++++ .../ne_alarm_state_check.go | 20 +- .../ne_alarm_state_check_cmd.go | 288 ++++ .../ne_alarm_state_check_license.go | 213 +++ src/modules/crontask/processor/processor.go | 13 + 10 files changed, 2440 insertions(+), 43 deletions(-) create mode 100644 src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go create mode 100644 src/modules/crontask/processor/backup_export_log/backup_export_log.go create mode 100644 src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go create mode 100644 src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go diff --git a/build/database/lite/install/sys_i18n.sql b/build/database/lite/install/sys_i18n.sql index df2f05bb..2d9c4fe9 100644 --- a/build/database/lite/install/sys_i18n.sql +++ b/build/database/lite/install/sys_i18n.sql @@ -5,8 +5,8 @@ DROP TABLE IF EXISTS "sys_i18n"; CREATE TABLE "sys_i18n" ( "id" integer NOT NULL, "key_lable" text(255) NOT NULL, - "value_zh" text(255), - "value_en" text(255), + "value_zh" text(2048), + "value_en" text(2048), PRIMARY KEY ("id") ); @@ -710,6 +710,12 @@ INSERT INTO "sys_i18n" VALUES (638, 'job.backup_export_table_cdr_event_ims', ' INSERT INTO "sys_i18n" VALUES (639, 'job.backup_export_table_cdr_event_smf', '备份-数据话单表定期导出', 'Backup-Regular Export of data sheet tables'); INSERT INTO "sys_i18n" VALUES (640, 'cache.name.oauth2_codes', '客户端授权码', 'Oauth2 Client Code'); INSERT INTO "sys_i18n" VALUES (641, 'cache.name.oauth2_devices', '客户端令牌', 'Oauth2 Token'); +INSERT INTO "sys_i18n" VALUES (642, 'job.backup_export_cdr', '备份-CDR数据定期导出', 'Backup-Periodic export of CDR Data'); +INSERT INTO "sys_i18n" VALUES (643, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc +fileType: 文件类型 csv/xlsx +hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc +fileType: file type csv/xlsx +hour: data time from the hour before the task execution time'); INSERT INTO "sys_i18n" VALUES (644, 'menu.log.exportFile', '导出文件', 'Exported File'); INSERT INTO "sys_i18n" VALUES (645, 'menu.perf.kpiCReport', '自定义指标数据', 'Custom Indicator Data'); INSERT INTO "sys_i18n" VALUES (646, 'menu.trace.taskHLR', 'HLR 跟踪任务', 'HLR Trace Task'); @@ -821,7 +827,7 @@ storeNum: retention number, default retention 7'); INSERT INTO "sys_i18n" VALUES (726, 'job.backup_export_udm', '备份-UDM数据定期导出', 'Backup-Periodic export of UDM Data'); INSERT INTO "sys_i18n" VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte fileType: 文件类型 csv/txt', 'Backup-Periodic export of dataType: type support auth/sub/voip/volte -fileType: file type csv/txtUDM Data'); +fileType: file type csv/txt'); INSERT INTO "sys_i18n" VALUES (728, 'dictData.cdr_sip_code_cause.0', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO "sys_i18n" VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常通话清除', 'Normal Call Clearing'); INSERT INTO "sys_i18n" VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); @@ -844,3 +850,81 @@ INSERT INTO "sys_i18n" VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其 INSERT INTO "sys_i18n" VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 明确拒绝通话', 'MT explicitly rejected the call'); INSERT INTO "sys_i18n" VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO "sys_i18n" VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); +INSERT INTO "sys_i18n" VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); +INSERT INTO "sys_i18n" VALUES (751, 'job.backup_export_log_remark', 'dataType: 类型支持 operate/login +fileType: 文件类型 csv/xlsx +hour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support operate/login +fileType: file type csv/xlsx +hour: data time from the hour before the task execution time'); +INSERT INTO "sys_i18n" VALUES (752, 'job.ne_alarm_state_check_cmd', '网元告警-内存/CPU/磁盘检查', 'NE Alarm-Memory/CPU/Disk Checks'); +INSERT INTO "sys_i18n" VALUES (753, 'job.ne_alarm_state_check_cmd_remark', '检查网元的内存/CPU/磁盘检查健康状况,在出现过阈值时发出警报。 + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: 告警补充信息 +cpuUseGt: CPU使用率大于, 范围0~100% +memUseGt: 内存使用率大于, 范围0~100% +diskUseGt: 磁盘使用率大于, 范围0~100%', 'Checks the memory/CPU/disk check health of the network element and sends alerts when thresholds are crossed. + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: Additional information on alarms +cpuUseGt: CPU utilization greater than, range 0 to 100% +memUseGt: Memory utilization greater than, range 0 to 100% +diskUseGt: Disk utilization greater than, range 0 to 100%'); +INSERT INTO "sys_i18n" VALUES (754, 'job.ne_alarm_state_check_license', '网元告警-License到期检查', 'NE Alarm-License Expire Check'); +INSERT INTO "sys_i18n" VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。 + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: 告警补充信息 +dayLt: 天数小于,默认30天', 'Checks if the network element is License is about to expire and sends an alert if a threshold is crossed. + +Alarm type: +CommunicationAlarm=1 +EquipmentAlarm=2 +ProcessingFailure=3 +EnvironmentalAlarm=4 +QualityOfServiceAlarm=5 + +Severity: +Critical=1 +Major=2 +Minor=3 +Warning=4 + +AddInfo: Additional information on alarms +dayLt: Days less than, default 30 days'); diff --git a/build/database/lite/install/sys_job.sql b/build/database/lite/install/sys_job.sql index 6a0b9a52..1c9a85b4 100644 --- a/build/database/lite/install/sys_job.sql +++ b/build/database/lite/install/sys_job.sql @@ -34,16 +34,18 @@ ON "sys_job" ( -- Records of sys_job -- ---------------------------- INSERT INTO "sys_job" VALUES (1, 'job.monitor_sys_resource', 'SYSTEM', 'monitor_sys_resource', '{"interval":5}', '0 0/5 * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.monitor_sys_resource_remark'); -INSERT INTO "sys_job" VALUES (2, 'job.ne_config_backup', 'SYSTEM', 'ne_config_backup', '', '0 30 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_config_backup_remark'); INSERT INTO "sys_job" VALUES (3, 'job.ne_data_udm', 'SYSTEM', 'ne_data_udm', '', '0 0 0/12 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, ''); -INSERT INTO "sys_job" VALUES (4, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{"alarmTitle":"NE State Check Alarm","alarmType":"2","origSeverity":"2","specificProblem":"alarm cause: the system state of target NE has not been received","specificProblemId":"AC10000","addInfo":""}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); -INSERT INTO "sys_job" VALUES (5, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{"storeDays":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); -INSERT INTO "sys_job" VALUES (6, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{"storeDays":7,"neList":["IMS","AMF","UDM","UPF","MME","SMSC","SMF","MME"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); -INSERT INTO "sys_job" VALUES (7, 'job.delete_ne_config_backup', 'SYSTEM', 'delete_ne_config_backup', '{"storeDays":7,"storeNum":7}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_ne_config_backup_remark'); -INSERT INTO "sys_job" VALUES (21, 'job.backup_export_table_sys_log_operate', 'SYSTEM', 'backup_export_table', '{"hour":1,"columns":["id","title","business_type","opera_by","opera_url_method","opera_url","opera_ip","status","opera_time","cost_time"],"tableName":"sys_log_operate","backupPath":"/log/operate_log"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_sys_log_operate_remark'); -INSERT INTO "sys_job" VALUES (22, 'job.backup_export_table_cdr_event_ims', 'SYSTEM', 'backup_export_table', '{"hour":1,"columns":["id","record_type","call_type","caller_party","called_party","call_duration","cause","seizure_time","release_time"],"tableName":"cdr_event_ims","backupPath":"/cdr/ims_cdr"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_ims_remark'); -INSERT INTO "sys_job" VALUES (23, 'job.backup_export_table_cdr_event_smf', 'SYSTEM', 'backup_export_table', '{"hour":1,"columns":["id","charging_id","subscription_id_data","subscription_id_type","data_volume_uplink","data_volume_downlink","data_total_volume","invocation_timestamp","user_identifier","ssc_mode","dnn_id","pdu_type","rat_type","pdu_ipv4","pdu_ipv6","network_function_ipv4_address","record_nfId","record_type","record_opening_time"],"tableName":"cdr_event_smf","backupPath":"/cdr/smf_cdr"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smf_remark'); -INSERT INTO "sys_job" VALUES (24, 'job.backup_export_table_cdr_event_smsc', 'SYSTEM', 'backup_export_table', '{"hour":1,"columns":["id","record_type","service_type","caller_party","called_party","result","update_time"],"tableName":"cdr_event_smsc","backupPath":"/cdr/smsc_cdr"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smsc_remark'); -INSERT INTO "sys_job" VALUES (25, 'job.backup_export_table_cdr_event_sgwc', 'SYSTEM', 'backup_export_table', '{"hour":1,"columns":["charging_id","served_imsi","served_msisdn","data_volume_gprs_uplink","data_volume_gprs_downlink","duration","invocation_timestamp","pgw_address_used","sgw_address","rat_type","pdp_pdn_type","served_pdppdn_address","serving_node_address","serving_node_type","access_point_name_ni","cause_for_rec_closing","record_sequence_number","local_record_sequence_number","record_type","record_opening_time"],"tableName":"cdr_event_sgwc","backupPath":"/cdr/sgwc_cdr"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_sgwc_remark'); -INSERT INTO "sys_job" VALUES (26, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{"backupPath":"/log/operate_log","storeDays":30,"storeNum":7},{"backupPath":"/cdr/ims_cdr","storeDays":30},{"backupPath":"/cdr/smf_cdr","storeDays":30},{"backupPath":"/cdr/smsc_cdr","storeDays":30},{"backupPath":"/cdr/sgwc_cdr","storeDays":30},{"backupPath":"/udm_data/auth","storeDays":30},{"backupPath":"/udm_data/sub","storeDays":30},{"backupPath":"/udm_data/voip","storeDays":30},{"backupPath":"/udm_data/volte","storeDays":30}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); -INSERT INTO "sys_job" VALUES (27, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{"dataType":["auth","sub","voip","volte"],"fileType":"txt"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); +INSERT INTO "sys_job" VALUES (6, 'job.ne_config_backup', 'SYSTEM', 'ne_config_backup', '', '0 30 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_config_backup_remark'); + +INSERT INTO "sys_job" VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'delete_ne_config_backup', '{"storeDays":7,"storeNum":7}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_ne_config_backup_remark'); +INSERT INTO "sys_job" VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{"storeDays":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); +INSERT INTO "sys_job" VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{"storeDays":7,"neList":["IMS","AMF","UDM","UPF","MME","SMSC","SMF","MME"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); + +INSERT INTO "sys_job" VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{"alarmTitle":"NE State Check Alarm","alarmType":"2","origSeverity":"2","specificProblem":"alarm cause: the system state of target NE has not been received","specificProblemId":"AC10000","addInfo":""}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +INSERT INTO "sys_job" VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{"alarmTitle":"NE State Check Alarm CPU/Menory/Disk","alarmType":"2","origSeverity":"2","specificProblem":"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold","specificProblemId":"AC10100","addInfo":"","cpuUseGt":70,"memUseGt":70,"diskUseGt":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +INSERT INTO "sys_job" VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{"alarmTitle":"NE State Check Alarm License","alarmType":"2","origSeverity":"2","specificProblem":"Alarm Cause: License received from target NE is about to expire","specificProblemId":"AC10200","addInfo":"","dayLt":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); + +INSERT INTO "sys_job" VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{"backupPath":"/udm_data/auth","storeDays":30},{"backupPath":"/udm_data/sub","storeDays":30},{"backupPath":"/udm_data/voip","storeDays":30},{"backupPath":"/udm_data/volte","storeDays":30},{"backupPath":"/cdr/ims_cdr_event","storeDays":30},{"backupPath":"/cdr/smsc_cdr_event","storeDays":30},{"backupPath":"/cdr/smf_cdr_event","storeDays":30},{"backupPath":"/cdr/sgwc_cdr_event","storeDays":30},{"backupPath":"/log/sys_log_operate","storeDays":30,"storeNum":7},{"backupPath":"/log/sys_log_login","storeDays":30,"storeNum":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); +INSERT INTO "sys_job" VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{"dataType":["auth","sub","voip","volte"],"fileType":"txt"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); +INSERT INTO "sys_job" VALUES (32, 'job.backup_export_cdr', 'SYSTEM', 'backup_export_cdr', '{"dataType":["ims","smf","sgwc","smsc"],"fileType":"xlsx","hour":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_cdr_remark'); +INSERT INTO "sys_job" VALUES (33, 'job.backup_export_log', 'SYSTEM', 'backup_export_log', '{"dataType":["operate","login"],"fileType":"xlsx","hour":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_log_remark'); diff --git a/build/database/std/install/sys_i18n.sql b/build/database/std/install/sys_i18n.sql index 38e80800..3a82c2f4 100644 --- a/build/database/std/install/sys_i18n.sql +++ b/build/database/std/install/sys_i18n.sql @@ -6,8 +6,8 @@ DROP TABLE IF EXISTS `sys_i18n`; CREATE TABLE `sys_i18n` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', `key_lable` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '多语言属性名', - `value_zh` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '中文', - `value_en` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '英文', + `value_zh` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '中文', + `value_en` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '-' COMMENT '英文', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统_多语言'; @@ -295,7 +295,7 @@ INSERT INTO `sys_i18n` VALUES (277, 'config..export.key', '参数键名', 'Confi INSERT INTO `sys_i18n` VALUES (278, 'config..export.value', '参数键值', 'Config Value'); INSERT INTO `sys_i18n` VALUES (279, 'config..export.type', '系统内置', 'Built In'); INSERT INTO `sys_i18n` VALUES (280, 'config..export.remark', '参数说明', 'Config Description'); -INSERT INTO `sys_i18n` VALUES (281, 'config.sys.titleValue', '5G Core Network', 'Core Network'); +INSERT INTO `sys_i18n` VALUES (281, 'config.sys.titleValue', 'Core Network', 'Core Network'); INSERT INTO `sys_i18n` VALUES (282, 'config.sys.copyrightValue', 'Copyright ©2025 Core Network', 'Copyright ©2025 Core Network'); INSERT INTO `sys_i18n` VALUES (283, 'config.noData', '没有可访问参数配置数据!', 'No parameter configuration data is accessible!'); INSERT INTO `sys_i18n` VALUES (284, 'config.errKey', '无效 key', 'Invalid key'); @@ -656,8 +656,8 @@ INSERT INTO `sys_i18n` VALUES (638, 'job.backup_export_table_cdr_event_ims', ' INSERT INTO `sys_i18n` VALUES (639, 'job.backup_export_table_cdr_event_smf', '备份-数据话单表定期导出', 'Backup-Regular Export of data sheet tables'); INSERT INTO `sys_i18n` VALUES (640, 'cache.name.oauth2_codes', '客户端授权码', 'Oauth2 Client Code'); INSERT INTO `sys_i18n` VALUES (641, 'cache.name.oauth2_devices', '客户端令牌', 'Oauth2 Token'); --- INSERT INTO `sys_i18n` VALUES (642, 'table.cdr_event_smf', '数据话单', 'Data CDR'); --- INSERT INTO `sys_i18n` VALUES (643, 'table.cdr_event_smsc', '短信话单', 'SMS CDR'); +INSERT INTO `sys_i18n` VALUES (642, 'job.backup_export_cdr', '备份-CDR数据定期导出', 'Backup-Periodic export of CDR Data'); +INSERT INTO `sys_i18n` VALUES (643, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc\nfileType: 文件类型 csv/xlsx\nhour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc\nfileType: file type csv/xlsx\nhour: data time from the hour before the task execution time'); INSERT INTO `sys_i18n` VALUES (644, 'menu.log.exportFile', '导出文件', 'Exported File'); INSERT INTO `sys_i18n` VALUES (645, 'menu.perf.kpiCReport', '自定义指标数据', 'Custom Indicator Data'); INSERT INTO `sys_i18n` VALUES (646, 'menu.trace.taskHLR', 'HLR 跟踪任务', 'HLR Trace Task'); @@ -741,7 +741,7 @@ INSERT INTO `sys_i18n` VALUES (723, 'job.backup_export_table_cdr_event_smsc_rema INSERT INTO `sys_i18n` VALUES (724, 'job.backup_export_table_cdr_event_sgwc_remark', 'hour: 数据时间从任务执行时间前的小时数\ntableName: 数据表名\ncolumns: 支持字段\nbackupPath: 备份输出路径 /usr/local/omc/backup/{backupPath}', 'hour: data time from the hour before the task execution time \ntableName: data table name \ncolumns: support fields \nbackupPath: backup output path /usr/local/omc/backup/{backupPath}'); INSERT INTO `sys_i18n` VALUES (725, 'job.backup_remove_file_remark', 'backupPath: 备份路径 /usr/local/omc/backup/{backupPath}\nstoreDays: 保留天数\nstoreNum: 保留数量,默认保留7', 'backupPath: backup path /usr/local/omc/backup/{backupPath}\nstoreDays: retention days\nstoreNum: retention number, default retention 7'); INSERT INTO `sys_i18n` VALUES (726, 'job.backup_export_udm', '备份-UDM数据定期导出', 'Backup-Periodic export of UDM Data'); -INSERT INTO `sys_i18n` VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte\nfileType: 文件类型 csv/txt', 'Backup-Periodic export of dataType: type support auth/sub/voip/volte\nfileType: file type csv/txtUDM Data'); +INSERT INTO `sys_i18n` VALUES (727, 'job.backup_export_udm_remark', 'dataType: 类型支持 auth/sub/voip/volte\nfileType: 文件类型 csv/txt', 'Backup-Periodic export of dataType: type support auth/sub/voip/volte\nfileType: file type csv/txt'); INSERT INTO `sys_i18n` VALUES (728, 'dictData.cdr_sip_code_cause.0', '因其他原因呼叫失败', 'Call failure for other reason'); INSERT INTO `sys_i18n` VALUES (729, 'dictData.cdr_sip_code_cause.200', '正常通话清除', 'Normal Call Clearing'); INSERT INTO `sys_i18n` VALUES (730, 'dictData.cdr_sip_code_cause.202', '申请已被接受处理,但尚未完成 ', 'The request has been accepted for processing, but it hasn it completed yet'); @@ -764,5 +764,11 @@ INSERT INTO `sys_i18n` VALUES (746, 'dictData.cdr_sip_code_cause.580', '因其 INSERT INTO `sys_i18n` VALUES (747, 'dictData.cdr_sip_code_cause.603', 'MT 明确拒绝通话', 'MT explicitly rejected the call'); INSERT INTO `sys_i18n` VALUES (748, 'dictData.cdr_sip_code_cause.606', '呼叫已到达用户设备,但会话设置的某些部分不可接受', 'The call reached the user’s device, but some parts of the session setup weren it acceptable'); INSERT INTO `sys_i18n` VALUES (749, 'dictType.cdr_sip_code_cause', 'IMS-Voice-SIP响应代码类别类型原因', 'IMS-Voice-SIP Response Code Category Type Cause'); +INSERT INTO `sys_i18n` VALUES (750, 'job.backup_export_log', '备份-日志数据定期导出', 'Backup-Periodic export of Log Data'); +INSERT INTO `sys_i18n` VALUES (751, 'job.backup_export_log_remark', 'dataType: 类型支持 operate/login\nfileType: 文件类型 csv/xlsx\nhour: 数据时间从任务执行时间前的小时数', 'Backup-Periodic export of dataType: type support operate/login\nfileType: file type csv/xlsx\nhour: data time from the hour before the task execution time'); +INSERT INTO `sys_i18n` VALUES (752, 'job.ne_alarm_state_check_cmd', '网元告警-内存/CPU/磁盘检查', 'NE Alarm-Memory/CPU/Disk Checks'); +INSERT INTO `sys_i18n` VALUES (753, 'job.ne_alarm_state_check_cmd_remark', '检查网元的内存/CPU/磁盘检查健康状况,在出现过阈值时发出警报。\r\n\r\nAlarm type:\r\nCommunicationAlarm=1\r\nEquipmentAlarm=2\r\nProcessingFailure=3\r\nEnvironmentalAlarm=4\r\nQualityOfServiceAlarm=5\r\n\r\nSeverity:\r\nCritical=1\r\nMajor=2\r\nMinor=3\r\nWarning=4\r\n\r\nAddInfo: 告警补充信息\r\ncpuUseGt: CPU使用率大于, 范围0~100%\r\nmemUseGt: 内存使用率大于, 范围0~100%\r\ndiskUseGt: 磁盘使用率大于, 范围0~100%', 'Checks the memory/CPU/disk check health of the network element and sends alerts when thresholds are crossed.\n\nAlarm type:\nCommunicationAlarm=1\nEquipmentAlarm=2\nProcessingFailure=3\nEnvironmentalAlarm=4\nQualityOfServiceAlarm=5\n\nSeverity:\nCritical=1\nMajor=2\nMinor=3\nWarning=4\r\n\r\nAddInfo: Additional information on alarms\r\ncpuUseGt: CPU utilization greater than, range 0 to 100%\r\nmemUseGt: Memory utilization greater than, range 0 to 100%\r\ndiskUseGt: Disk utilization greater than, range 0 to 100%'); +INSERT INTO `sys_i18n` VALUES (754, 'job.ne_alarm_state_check_license', '网元告警-License到期检查', 'NE Alarm-License Expire Check'); +INSERT INTO `sys_i18n` VALUES (755, 'job.ne_alarm_state_check_license_remark', '检查网元的License是否即将到期,在出现过阈值时发出警报。\r\n\r\nAlarm type:\r\nCommunicationAlarm=1\r\nEquipmentAlarm=2\r\nProcessingFailure=3\r\nEnvironmentalAlarm=4\r\nQualityOfServiceAlarm=5\r\n\r\nSeverity:\r\nCritical=1\r\nMajor=2\r\nMinor=3\r\nWarning=4\r\n\r\nAddInfo: 告警补充信息\r\ndayLt: 天数小于,默认30天', 'Checks if the network element is License is about to expire and sends an alert if a threshold is crossed.\n\nAlarm type:\nCommunicationAlarm=1\nEquipmentAlarm=2\nProcessingFailure=3\nEnvironmentalAlarm=4\nQualityOfServiceAlarm=5\n\nSeverity:\nCritical=1\nMajor=2\nMinor=3\nWarning=4\r\n\r\nAddInfo: Additional information on alarms\r\ndayLt: Days less than, default 30 days'); -- Dump completed on 2025-02-14 15:26:56 diff --git a/build/database/std/install/sys_job.sql b/build/database/std/install/sys_job.sql index aa0f534e..ae856654 100644 --- a/build/database/std/install/sys_job.sql +++ b/build/database/std/install/sys_job.sql @@ -29,20 +29,26 @@ CREATE TABLE `sys_job` ( -- Records of sys_job -- ---------------------------- INSERT INTO `sys_job` VALUES (1, 'job.monitor_sys_resource', 'SYSTEM', 'monitor_sys_resource', '{\"interval\":5}', '0 0/5 * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.monitor_sys_resource_remark'); -INSERT INTO `sys_job` VALUES (2, 'job.ne_config_backup', 'SYSTEM', 'ne_config_backup', '', '0 30 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_config_backup_remark'); INSERT INTO `sys_job` VALUES (3, 'job.ne_data_udm', 'SYSTEM', 'ne_data_udm', '', '0 0 0/12 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, ''); -INSERT INTO `sys_job` VALUES (4, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); -INSERT INTO `sys_job` VALUES (5, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{\"storeDays\":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); -INSERT INTO `sys_job` VALUES (6, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{\"storeDays\":7,\"neList\":[\"IMS\",\"AMF\",\"UDM\",\"UPF\",\"MME\",\"SMSC\",\"SMF\",\"MME\"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); -INSERT INTO `sys_job` VALUES (7, 'job.delete_ne_config_backup', 'SYSTEM', 'delete_ne_config_backup', '{\"storeDays\":7,\"storeNum\":7}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_ne_config_backup_remark'); +INSERT INTO `sys_job` VALUES (6, 'job.ne_config_backup', 'SYSTEM', 'ne_config_backup', '', '0 30 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_config_backup_remark'); -INSERT INTO `sys_job` VALUES (21, 'job.backup_export_table_sys_log_operate', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"title\",\"business_type\",\"opera_by\",\"opera_url_method\",\"opera_url\",\"opera_ip\",\"status\",\"opera_time\",\"cost_time\"],\"tableName\":\"sys_log_operate\",\"backupPath\":\"/log/operate_log\"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_sys_log_operate_remark'); -INSERT INTO `sys_job` VALUES (22, 'job.backup_export_table_cdr_event_ims', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"record_type\",\"call_type\",\"caller_party\",\"called_party\",\"call_duration\",\"cause\",\"seizure_time\",\"release_time\"],\"tableName\":\"cdr_event_ims\",\"backupPath\":\"/cdr/ims_cdr\"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_ims_remark'); -INSERT INTO `sys_job` VALUES (23, 'job.backup_export_table_cdr_event_smf', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"charging_id\",\"subscription_id_data\",\"subscription_id_type\",\"data_volume_uplink\",\"data_volume_downlink\",\"data_total_volume\",\"invocation_timestamp\",\"user_identifier\",\"ssc_mode\",\"dnn_id\",\"pdu_type\",\"rat_type\",\"pdu_ipv4\",\"pdu_ipv6\",\"network_function_ipv4_address\",\"record_nfId\",\"record_type\",\"record_opening_time\"],\"tableName\":\"cdr_event_smf\",\"backupPath\":\"/cdr/smf_cdr\"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smf_remark'); -INSERT INTO `sys_job` VALUES (24, 'job.backup_export_table_cdr_event_smsc', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"record_type\",\"service_type\",\"caller_party\",\"called_party\",\"result\",\"update_time\"],\"tableName\":\"cdr_event_smsc\",\"backupPath\":\"/cdr/smsc_cdr\"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smsc_remark'); -INSERT INTO `sys_job` VALUES (25, 'job.backup_export_table_cdr_event_sgwc', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"charging_id\",\"served_imsi\",\"served_msisdn\",\"data_volume_gprs_uplink\",\"data_volume_gprs_downlink\",\"duration\",\"invocation_timestamp\",\"pgw_address_used\",\"sgw_address\",\"rat_type\",\"pdp_pdn_type\",\"served_pdppdn_address\",\"serving_node_address\",\"serving_node_type\",\"access_point_name_ni\",\"cause_for_rec_closing\",\"record_sequence_number\",\"local_record_sequence_number\",\"record_type\",\"record_opening_time\"],\"tableName\":\"cdr_event_sgwc\",\"backupPath\":\"/cdr/sgwc_cdr\"}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_sgwc_remark'); -INSERT INTO `sys_job` VALUES (26, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{\"backupPath\":\"/log/operate_log\",\"storeDays\":30,\"storeNum\":7},{\"backupPath\":\"/cdr/ims_cdr\",\"storeDays\":30},{\"backupPath\":\"/cdr/smf_cdr\",\"storeDays\":30},{\"backupPath\":\"/cdr/smsc_cdr\",\"storeDays\":30},{\"backupPath\":\"/cdr/sgwc_cdr\",\"storeDays\":30},{\"backupPath\":\"/udm_data/auth\",\"storeDays\":30},{\"backupPath\":\"/udm_data/sub\",\"storeDays\":30},{\"backupPath\":\"/udm_data/voip\",\"storeDays\":30},{\"backupPath\":\"/udm_data/volte\",\"storeDays\":30}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839,'job.backup_remove_file_remark'); -INSERT INTO `sys_job` VALUES (27, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{\"dataType\":[\"auth\",\"sub\",\"voip\",\"volte\"],\"fileType\":\"txt\"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); +INSERT INTO `sys_job` VALUES (10, 'job.delete_ne_config_backup', 'SYSTEM', 'delete_ne_config_backup', '{\"storeDays\":7,\"storeNum\":7}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_ne_config_backup_remark'); +INSERT INTO `sys_job` VALUES (11, 'job.delete_alarm_record', 'SYSTEM', 'delete_alarm_record', '{\"storeDays\":7}', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_alarm_record_remark'); +INSERT INTO `sys_job` VALUES (12, 'job.delete_kpi_record', 'SYSTEM', 'delete_kpi_record', '{\"storeDays\":7,\"neList\":[\"IMS\",\"AMF\",\"UDM\",\"UPF\",\"MME\",\"SMSC\",\"SMF\",\"MME\"]}', '0 20 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.delete_kpi_record_remark'); + +INSERT INTO `sys_job` VALUES (20, 'job.ne_alarm_state_check', 'SYSTEM', 'ne_alarm_state_check', '{\"alarmTitle\":\"NE State Check Alarm\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"alarm cause: the system state of target NE has not been received\",\"specificProblemId\":\"AC10000\",\"addInfo\":\"\"}', '0/30 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_remark'); +INSERT INTO `sys_job` VALUES (21, 'job.ne_alarm_state_check_cmd', 'SYSTEM', 'ne_alarm_state_check_cmd', '{\"alarmTitle\":\"NE State Check Alarm CPU/Menory/Disk\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold\",\"specificProblemId\":\"AC10100\",\"addInfo\":\"\",\"cpuUseGt\":70,\"memUseGt\":70,\"diskUseGt\":70}', '0/15 * * * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_cmd_remark'); +INSERT INTO `sys_job` VALUES (22, 'job.ne_alarm_state_check_license', 'SYSTEM', 'ne_alarm_state_check_license', '{\"alarmTitle\":\"NE State Check Alarm License\",\"alarmType\":\"2\",\"origSeverity\":\"2\",\"specificProblem\":\"Alarm Cause: License received from target NE is about to expire\",\"specificProblemId\":\"AC10200\",\"addInfo\":\"\",\"dayLt\":7}', '0 5 0 * * ?', '3', '0', '1', '0', 'system', 1698478134839, 'system', 1698478134839, 'job.ne_alarm_state_check_license_remark'); + +INSERT INTO `sys_job` VALUES (30, 'job.backup_remove_file', 'SYSTEM', 'backup_remove_file', '[{\"backupPath\":\"/udm_data/auth\",\"storeDays\":30},{\"backupPath\":\"/udm_data/sub\",\"storeDays\":30},{\"backupPath\":\"/udm_data/voip\",\"storeDays\":30},{\"backupPath\":\"/udm_data/volte\",\"storeDays\":30},{\"backupPath\":\"/cdr/ims_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smsc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/smf_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/cdr/sgwc_cdr_event\",\"storeDays\":30},{\"backupPath\":\"/log/sys_log_operate\",\"storeDays\":30,\"storeNum\":7},{\"backupPath\":\"/log/sys_log_login\",\"storeDays\":30,\"storeNum\":7}]', '0 10 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_remove_file_remark'); +INSERT INTO `sys_job` VALUES (31, 'job.backup_export_udm', 'SYSTEM', 'backup_export_udm', '{\"dataType\":[\"auth\",\"sub\",\"voip\",\"volte\"],\"fileType\":\"txt\"}', '0 35 0 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_udm_remark'); +INSERT INTO `sys_job` VALUES (32, 'job.backup_export_cdr', 'SYSTEM', 'backup_export_cdr', '{\"dataType\":[\"ims\",\"smf\",\"sgwc\",\"smsc\"],\"fileType\":\"xlsx\",\"hour\":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_cdr_remark'); +INSERT INTO `sys_job` VALUES (33, 'job.backup_export_log', 'SYSTEM', 'backup_export_log', '{\"dataType\":[\"operate\",\"login\"],\"fileType\":\"xlsx\",\"hour\":1}', '0 0 0/1 * * ?', '3', '0', '1', '1', 'system', 1698478134839, 'supervisor', 1745481169354, 'job.backup_export_log_remark'); +-- INSERT INTO `sys_job` VALUES (34, 'job.backup_export_table_sys_log_operate', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"title\",\"business_type\",\"opera_by\",\"opera_url_method\",\"opera_url\",\"opera_ip\",\"status\",\"opera_time\",\"cost_time\"],\"tableName\":\"sys_log_operate\",\"backupPath\":\"/log/operate_log\"}', '0 0 0/1 * * ?', '3', '0', '0', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_sys_log_operate_remark'); +-- INSERT INTO `sys_job` VALUES (35, 'job.backup_export_table_cdr_event_ims', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"record_type\",\"call_type\",\"caller_party\",\"called_party\",\"call_duration\",\"cause\",\"seizure_time\",\"release_time\"],\"tableName\":\"cdr_event_ims\",\"backupPath\":\"/cdr/ims_cdr\"}', '0 0 0/1 * * ?', '3', '0', '0', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_ims_remark'); +-- INSERT INTO `sys_job` VALUES (36, 'job.backup_export_table_cdr_event_smf', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"charging_id\",\"subscription_id_data\",\"subscription_id_type\",\"data_volume_uplink\",\"data_volume_downlink\",\"data_total_volume\",\"invocation_timestamp\",\"user_identifier\",\"ssc_mode\",\"dnn_id\",\"pdu_type\",\"rat_type\",\"pdu_ipv4\",\"pdu_ipv6\",\"network_function_ipv4_address\",\"record_nfId\",\"record_type\",\"record_opening_time\"],\"tableName\":\"cdr_event_smf\",\"backupPath\":\"/cdr/smf_cdr\"}', '0 0 0/1 * * ?', '3', '0', '0', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smf_remark'); +-- INSERT INTO `sys_job` VALUES (37, 'job.backup_export_table_cdr_event_smsc', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"id\",\"record_type\",\"service_type\",\"caller_party\",\"called_party\",\"result\",\"update_time\"],\"tableName\":\"cdr_event_smsc\",\"backupPath\":\"/cdr/smsc_cdr\"}', '0 0 0/1 * * ?', '3', '0', '0', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_smsc_remark'); +-- INSERT INTO `sys_job` VALUES (38, 'job.backup_export_table_cdr_event_sgwc', 'SYSTEM', 'backup_export_table', '{\"hour\":1,\"columns\":[\"charging_id\",\"served_imsi\",\"served_msisdn\",\"data_volume_gprs_uplink\",\"data_volume_gprs_downlink\",\"duration\",\"invocation_timestamp\",\"pgw_address_used\",\"sgw_address\",\"rat_type\",\"pdp_pdn_type\",\"served_pdppdn_address\",\"serving_node_address\",\"serving_node_type\",\"access_point_name_ni\",\"cause_for_rec_closing\",\"record_sequence_number\",\"local_record_sequence_number\",\"record_type\",\"record_opening_time\"],\"tableName\":\"cdr_event_sgwc\",\"backupPath\":\"/cdr/sgwc_cdr\"}', '0 0 0/1 * * ?', '3', '0', '0', '1', 'system', 1698478134839, 'system', 1698478134839, 'job.backup_export_table_cdr_event_sgwc_remark'); SET FOREIGN_KEY_CHECKS = 1; diff --git a/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go new file mode 100644 index 00000000..c04b6781 --- /dev/null +++ b/src/modules/crontask/processor/backup_export_cdr/backup_export_cdr.go @@ -0,0 +1,1427 @@ +package backup_export_cdr + +import ( + "encoding/json" + "fmt" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" + + "be.ems/src/framework/cron" + "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" + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neModel "be.ems/src/modules/network_element/model" + neService "be.ems/src/modules/network_element/service" + systemService "be.ems/src/modules/system/service" +) + +var NewProcessor = &BackupExportCDRProcessor{ + count: 0, + backupService: neDataService.NewBackup, + sysDictService: systemService.NewSysDictData, + neInfoService: neService.NewNeInfo, + imsCDREventService: neDataService.NewCDREventIMS, + smscCDREventService: neDataService.NewCDREventSMSC, + smfCDREventService: neDataService.NewCDREventSMF, + sgwcCDREventService: neDataService.NewCDREventSGWC, +} + +// BackupExportCDR 队列任务处理 +type BackupExportCDRProcessor struct { + count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + sysDictService *systemService.SysDictData // 字典类型数据服务 + neInfoService *neService.NeInfo // 网元信息服务 + imsCDREventService *neDataService.CDREventIMS // IMS-CDR会话事件服务 + smscCDREventService *neDataService.CDREventSMSC // SMSC-CDR会话事件服务 + smfCDREventService *neDataService.CDREventSMF // SMF-CDR会话事件服务 + sgwcCDREventService *neDataService.CDREventSGWC // SGWC-CDR会话事件服务 +} + +func (s *BackupExportCDRProcessor) Execute(data any) (any, error) { + s.count++ // 执行次数加一 + options := data.(cron.JobData) + sysJob := options.SysJob + logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count) + // 返回结果,用于记录执行结果 + result := map[string]any{ + "count": s.count, + } + + var params struct { + DataType []string `json:"dataType"` // 类型支持 ims/smsc/smf/sgwc + FileType string `json:"fileType"` // 文件类型 csv/xlsx + Hour int `json:"hour"` // 数据时间从任务执行时间前的小时数 + } + if err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms); err != nil { + return nil, err + } + if !(params.FileType == "csv" || params.FileType == "xlsx") { + return nil, fmt.Errorf("file type error, only support csv,xlsx") + } + + for _, v := range params.DataType { + switch v { + case "ims": + neList := s.neInfoService.Find(neModel.NeInfo{NeType: "IMS"}, false, false) + for _, ne := range neList { + result[ne.NeName] = s.exportIMS(params.Hour, ne.RmUID, params.FileType) + } + case "smsc": + neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMSC"}, false, false) + for _, ne := range neList { + result[ne.NeName] = s.exportSMSC(params.Hour, ne.RmUID, params.FileType) + } + case "smf": + neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SMF"}, false, false) + for _, ne := range neList { + result[ne.NeName] = s.exportSMF(params.Hour, ne.RmUID, params.FileType) + } + case "sgwc": + neList := s.neInfoService.Find(neModel.NeInfo{NeType: "SGWC"}, false, false) + for _, ne := range neList { + result[ne.NeName] = s.exportSGWC(params.Hour, ne.RmUID, params.FileType) + } + } + } + + // 返回结果,用于记录执行结果 + return result, nil +} + +// exportIMS 导出IMS-CDR会话事件数据 +func (s BackupExportCDRProcessor) exportIMS(hour int, rmUID, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + language := "en" + query := neDataModel.CDREventIMSQuery{ + SortField: "timestamp", + SortOrder: "asc", + RmUID: rmUID, + BeginTime: start.UnixMilli(), + EndTime: end.UnixMilli(), + PageNum: 1, + PageSize: 30000, + } + rows, total := s.imsCDREventService.FindByPage(query) + if total == 0 { + return "no data" + } + + // 导出文件名称 + fileName := fmt.Sprintf("ims_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/ims_cdr_event", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + "ID", + "NE Name", + "Record Behavior", + "Type", + "Caller", + "Called", + "Duration", + "Result Code", + "Result Cause", + "Call Start Time", + "Hangup Time", + }, + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := s.sysDictService.FindByType("cdr_sip_code") + // 读取字典数据 CDR SIP响应代码类别类型原因 + dictCDRSipCodeCause := s.sysDictService.FindByType("cdr_sip_code_cause") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := s.sysDictService.FindByType("cdr_call_type") + for _, row := range rows { + // 解析 JSON 字符串为 map + var cdrJSON map[string]any + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DataValue { + callTypeLable = i18n.TKey(language, v.DataLabel) + break + } + } + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprintf("%ds", parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Other" + callCause := "Call failure for other reason" + if callType == "sms" { + callResult = "Success" + callCause = "Normal Send" + } else { + if v, ok := cdrJSON["cause"]; ok && v != nil { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DataValue { + callResult = i18n.TKey(language, v.DataLabel) + break + } + } + for _, v := range dictCDRSipCodeCause { + if cause == v.DataValue { + callCause = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + // 呼叫时间 + seizureTimeStr := "" + if v, ok := cdrJSON["seizureTime"]; ok && v != nil { + if seizureTime := parse.Number(v); seizureTime > 0 { + seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + seizureTimeStr = v.(string) + } + } + // 挂断时间 + releaseTimeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + releaseTimeStr = v.(string) + } + } + + data = append(data, []string{ + fmt.Sprint(row.ID), + row.NeName, + recordType, + callTypeLable, + caller, + called, + duration, + callResult, + callCause, + seizureTimeStr, + releaseTimeStr, + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Type", + "E1": "Caller", + "F1": "Called", + "G1": "Duration", + "H1": "Result Code", + "I1": "Result Cause", + "J1": "Call Start Time", + "K1": "Hangup Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := s.sysDictService.FindByType("cdr_sip_code") + // 读取字典数据 CDR SIP响应代码类别类型原因 + dictCDRSipCodeCause := s.sysDictService.FindByType("cdr_sip_code_cause") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := s.sysDictService.FindByType("cdr_call_type") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]any + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DataValue { + callTypeLable = i18n.TKey(language, v.DataLabel) + break + } + } + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprintf("%ds", parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Other" + callCause := "Call failure for other reason" + if callType == "sms" { + callResult = "Success" + callCause = "Normal Send" + } else { + if v, ok := cdrJSON["cause"]; ok && v != nil { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DataValue { + callResult = i18n.TKey(language, v.DataLabel) + break + } + } + for _, v := range dictCDRSipCodeCause { + if cause == v.DataValue { + callCause = i18n.TKey(language, v.DataLabel) + break + } + } + } + } + // 呼叫时间 + seizureTimeStr := "" + if v, ok := cdrJSON["seizureTime"]; ok && v != nil { + if seizureTime := parse.Number(v); seizureTime > 0 { + seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + seizureTimeStr = v.(string) + } + } + // 挂断时间 + releaseTimeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + releaseTimeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: callTypeLable, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: duration, + "H" + idx: callResult, + "I" + idx: callCause, + "J" + idx: seizureTimeStr, + "K" + idx: releaseTimeStr, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} + +// exportSMSC 导出SMSC-CDR会话事件数据 +func (s BackupExportCDRProcessor) exportSMSC(hour int, rmUID, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + language := "en" + query := neDataModel.CDREventSMSCQuery{ + SortField: "timestamp", + SortOrder: "asc", + RmUID: rmUID, + BeginTime: start.UnixMilli(), + EndTime: end.UnixMilli(), + PageNum: 1, + PageSize: 30000, + } + rows, total := s.smscCDREventService.FindByPage(query) + if total == 0 { + return "no data" + } + + // 导出文件名称 + fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/smsc_cdr_event", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + "ID", + "NE Name", + "Record Behavior", + "Service Type", + "Caller", + "Called", + "Result", + "Time", + }, + } + // 读取字典数据 CDR 原因码 + dictCDRCauseCode := s.sysDictService.FindByType("cdr_cause_code") + for _, row := range rows { + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 服务类型 + serviceType := "" + if v, ok := cdrJSON["serviceType"]; ok && v != nil { + serviceType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫结果 0失败,1成功 + callResult := "Fail" + if v, ok := cdrJSON["result"]; ok && v != nil { + resultVal := parse.Number(v) + if resultVal == 1 { + callResult = "Success" + } + } + // 结果原因 + if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { + cause := fmt.Sprint(v) + for _, v := range dictCDRCauseCode { + if cause == v.DataValue { + callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["updateTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + timeStr = v.(string) + } + } + + data = append(data, []string{ + fmt.Sprint(row.ID), + row.NeName, + recordType, + serviceType, + caller, + called, + callResult, + timeStr, + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Record Behavior", + "D1": "Service Type", + "E1": "Caller", + "F1": "Called", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR 原因码 + dictCDRCauseCode := s.sysDictService.FindByType("cdr_cause_code") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 服务类型 + serviceType := "" + if v, ok := cdrJSON["serviceType"]; ok && v != nil { + serviceType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫结果 0失败,1成功 + callResult := "Fail" + if v, ok := cdrJSON["result"]; ok && v != nil { + resultVal := parse.Number(v) + if resultVal == 1 { + callResult = "Success" + } + } + // 结果原因 + if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" { + cause := fmt.Sprint(v) + for _, v := range dictCDRCauseCode { + if cause == v.DataValue { + callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel)) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["updateTime"]; ok && v != nil { + if releaseTime := parse.Number(v); releaseTime > 0 { + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } else { + timeStr = v.(string) + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: recordType, + "D" + idx: serviceType, + "E" + idx: caller, + "F" + idx: called, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} + +// exportSMF 导出SMF-CDR会话事件数据 +func (s BackupExportCDRProcessor) exportSMF(hour int, rmUID, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + query := neDataModel.CDREventSMFQuery{ + SortField: "timestamp", + SortOrder: "asc", + RmUID: rmUID, + BeginTime: start.UnixMilli(), + EndTime: end.UnixMilli(), + PageNum: 1, + PageSize: 30000, + } + rows, total := s.smfCDREventService.FindByPage(query) + if total == 0 { + return "no data" + } + + // 导出文件名称 + fileName := fmt.Sprintf("smf_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/smf_cdr_event", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + "ID", + "Charging ID", + "NE Name", + "Resource Unique ID", + "Subscriber ID Data", + "Subscriber ID Type", + "Data Volume Uplink", + "Data Volume Downlink", + "Data Total Volume", + "Duration", + "Invocation Time", + "User Identifier", + "SSC Mode", + "DNN ID", + "PDU Type", + "RAT Type", + "PDU IPv4 Address", + "Network Function IPv4", + "PDU IPv6 Address Swith Prefix", + "Record Network Function ID", + "Record Type", + "Record Opening Time", + }, + } + for _, row := range rows { + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + + // 网络功能 IPv4 地址 + networkFunctionIPv4Address := "" + if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { + if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { + networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) + } + } + + // 数据量上行链路 + var dataVolumeUplink int64 = 0 + // 数据量下行链路 + var dataVolumeDownlink int64 = 0 + // 数据总量 + var dataTotalVolume int64 = 0 + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink += parse.Number(dup) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink += parse.Number(ddown) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume += parse.Number(dt) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + User_Identifier := "" + SSC_Mode := "" + RAT_Type := "" + DNN_ID := "" + PDU_Type := "" + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + } + + // 记录网络参数ID + recordNFID := "" + if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { + recordNFID = v.(string) + } + + //记录开始时间 + recordOpeningTime := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + recordOpeningTime = v.(string) + } + + //记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + + data = append(data, []string{ + fmt.Sprint(row.ID), + chargingID, + row.NeName, + row.RmUid, + subscriptionIDData, + subscriptionIDType, + fmt.Sprint(dataVolumeUplink), + fmt.Sprint(dataVolumeDownlink), + fmt.Sprint(dataTotalVolume), + duration, + invocationTimestamp, + User_Identifier, + SSC_Mode, + DNN_ID, + PDU_Type, + RAT_Type, + PDU_IPv4, + networkFunctionIPv4Address, + PDU_IPv6, + recordNFID, + recordType, + recordOpeningTime, + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Charging ID", + "C1": "NE Name", + "D1": "Resource Unique ID", + "E1": "Subscriber ID Data", + "F1": "Subscriber ID Type", + "G1": "Data Volume Uplink", + "H1": "Data Volume Downlink", + "I1": "Data Total Volume", + "J1": "Duration", + "K1": "Invocation Time", + "L1": "User Identifier", + "M1": "SSC Mode", + "N1": "DNN ID", + "O1": "PDU Type", + "P1": "RAT Type", + "Q1": "PDU IPv4 Address", + "R1": "Network Function IPv4", + "S1": "PDU IPv6 Address Swith Prefix", + "T1": "Record Network Function ID", + "U1": "Record Type", + "V1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + + // 网络功能 IPv4 地址 + networkFunctionIPv4Address := "" + if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil { + if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil { + networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string) + } + } + + // 数据量上行链路 + var dataVolumeUplink int64 = 0 + // 数据量下行链路 + var dataVolumeDownlink int64 = 0 + // 数据总量 + var dataTotalVolume int64 = 0 + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink += parse.Number(dup) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink += parse.Number(ddown) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume += parse.Number(dt) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + User_Identifier := "" + SSC_Mode := "" + RAT_Type := "" + DNN_ID := "" + PDU_Type := "" + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + } + + // 记录网络参数ID + recordNFID := "" + if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil { + recordNFID = v.(string) + } + + //记录开始时间 + recordOpeningTime := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + recordOpeningTime = v.(string) + } + + //记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: chargingID, + "C" + idx: row.NeName, + "D" + idx: row.RmUid, + "E" + idx: subscriptionIDData, + "F" + idx: subscriptionIDType, + "G" + idx: dataVolumeUplink, + "H" + idx: dataVolumeDownlink, + "I" + idx: dataTotalVolume, + "J" + idx: duration, + "K" + idx: invocationTimestamp, + "L" + idx: User_Identifier, + "M" + idx: SSC_Mode, + "N" + idx: DNN_ID, + "O" + idx: PDU_Type, + "P" + idx: RAT_Type, + "Q" + idx: PDU_IPv4, + "R" + idx: networkFunctionIPv4Address, + "S" + idx: PDU_IPv6, + "T" + idx: recordNFID, + "U" + idx: recordType, + "V" + idx: recordOpeningTime, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} + +// exportSGWC 导出SGWC-CDR会话事件数据 +func (s BackupExportCDRProcessor) exportSGWC(hour int, rmUID, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + query := neDataModel.CDREventSGWCQuery{ + SortField: "timestamp", + SortOrder: "asc", + RmUID: rmUID, + BeginTime: start.UnixMilli(), + EndTime: end.UnixMilli(), + PageNum: 1, + PageSize: 30000, + } + rows, total := s.sgwcCDREventService.FindByPage(query) + if total == 0 { + return "no data" + } + + // 导出文件名称 + fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/cdr/sgwc_cdr_event", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + "ID", + "NE Name", + "Resource Unique ID", + "Charging ID", + "IMSI", + "MSISDN", + "GPRS Uplink", + "GPRS Downlink", + "Duration", + "Invocation Time", + "PGW Address", + "SGW Address", + "RAT Type", + "PDPPDN Type", + "PDPPDN Address", + "Node Address", + "Node Type", + "Record Access Point Name NI", + "Record Cause For Rec Closing", + "Record Sequence Number", + "Local Record Sequence Number", + "Record Type", + "Record Opening Time", + }, + } + for _, row := range rows { + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // IMSI + servedIMSI := "" + if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { + servedIMSI = fmt.Sprint(v) + } + // MSISDN + servedMSISDN := "" + if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { + servedMSISDN = fmt.Sprint(v) + } + // pGWAddressUsed + pGWAddressUsed := "" + if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + data[0][10] = "PGW Address" + } + if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + data[0][10] = "GGSN Address" + } + // sGWAddress + sGWAddress := "" + if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + data[0][11] = "SGW Address" + } + if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + data[0][11] = "SGSN Address" + } + // recordType + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = fmt.Sprint(v) + } + // rATType + rATType := "" + if v, ok := cdrJSON["rATType"]; ok && v != nil { + rATType = fmt.Sprint(v) + } + // pdpPDNType + pdpPDNType := "" + if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { + pdpPDNType = fmt.Sprint(v) + } + // servedPDPPDNAddress + servedPDPPDNAddress := "" + if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { + servedPDPPDNAddress = fmt.Sprint(v) + } + // servedPDPPDNAddress + servingNodeAddress := []string{} + if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { + for _, v := range v.([]any) { + servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) + } + } + // servingNodeType + servingNodeType := []string{} + if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { + for _, v := range v.([]any) { + if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { + servingNodeType = append(servingNodeType, fmt.Sprint(v)) + } + } + } + // accessPointNameNI + accessPointNameNI := "" + if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { + accessPointNameNI = fmt.Sprint(v) + } + // causeForRecClosing + causeForRecClosing := "" + if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { + causeForRecClosing = fmt.Sprint(v) + } + // recordSequenceNumber + recordSequenceNumber := "" + if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { + recordSequenceNumber = fmt.Sprint(v) + } + // localRecordSequenceNumber + localRecordSequenceNumber := "" + if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { + localRecordSequenceNumber = fmt.Sprint(v) + } + // 数据量上行链路 + var dataVolumeGPRSUplink int64 = 0 + // 数据量下行链路 + var dataVolumeGPRSDownlink int64 = 0 + if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { + dataVolumeGPRSUplink = parse.Number(dup) + } + if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { + dataVolumeGPRSDownlink = parse.Number(ddown) + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + invocationTimestamp = v.(string) + } + + data = append(data, []string{ + fmt.Sprint(row.ID), + row.NeName, + row.RmUid, + chargingID, + servedIMSI, + servedMSISDN, + fmt.Sprint(dataVolumeGPRSUplink), + fmt.Sprint(dataVolumeGPRSDownlink), + duration, + invocationTimestamp, + pGWAddressUsed, + sGWAddress, + rATType, + pdpPDNType, + servedPDPPDNAddress, + strings.Join(servingNodeAddress, ","), + strings.Join(servingNodeType, ","), + accessPointNameNI, + causeForRecClosing, + recordSequenceNumber, + localRecordSequenceNumber, + recordType, + invocationTimestamp, + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "NE Name", + "C1": "Resource Unique ID", + "D1": "Charging ID", + "E1": "IMSI", + "F1": "MSISDN", + "G1": "GPRS Uplink", + "H1": "GPRS Downlink", + "I1": "Duration", + "J1": "Invocation Time", + "K1": "PGW Address", + "L1": "SGW Address", + "M1": "RAT Type", + "N1": "PDPPDN Type", + "O1": "PDPPDN Address", + "P1": "Node Address", + "Q1": "Node Type", + "R1": "Record Access Point Name NI", + "S1": "Record Cause For Rec Closing", + "T1": "Record Sequence Number", + "U1": "Local Record Sequence Number", + "V1": "Record Type", + "W1": "Record Opening Time", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // IMSI + servedIMSI := "" + if v, ok := cdrJSON["servedIMSI"]; ok && v != nil { + servedIMSI = fmt.Sprint(v) + } + // MSISDN + servedMSISDN := "" + if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil { + servedMSISDN = fmt.Sprint(v) + } + // pGWAddressUsed + pGWAddressUsed := "" + if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "PGW Address" + } + if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil { + pGWAddressUsed = fmt.Sprint(v) + headerCells["K1"] = "GGSN Address" + } + // sGWAddress + sGWAddress := "" + if v, ok := cdrJSON["sGWAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGW Address" + } + if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil { + sGWAddress = fmt.Sprint(v) + headerCells["L1"] = "SGSN Address" + } + // recordType + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = fmt.Sprint(v) + } + // rATType + rATType := "" + if v, ok := cdrJSON["rATType"]; ok && v != nil { + rATType = fmt.Sprint(v) + } + // pdpPDNType + pdpPDNType := "" + if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil { + pdpPDNType = fmt.Sprint(v) + } + // servedPDPPDNAddress + servedPDPPDNAddress := "" + if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil { + servedPDPPDNAddress = fmt.Sprint(v) + } + // servedPDPPDNAddress + servingNodeAddress := []string{} + if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil { + for _, v := range v.([]any) { + servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v)) + } + } + // servingNodeType + servingNodeType := []string{} + if v, ok := cdrJSON["servingNodeType"]; ok && v != nil { + for _, v := range v.([]any) { + if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil { + servingNodeType = append(servingNodeType, fmt.Sprint(v)) + } + } + } + // accessPointNameNI + accessPointNameNI := "" + if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil { + accessPointNameNI = fmt.Sprint(v) + } + // causeForRecClosing + causeForRecClosing := "" + if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil { + causeForRecClosing = fmt.Sprint(v) + } + // recordSequenceNumber + recordSequenceNumber := "" + if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil { + recordSequenceNumber = fmt.Sprint(v) + } + // localRecordSequenceNumber + localRecordSequenceNumber := "" + if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil { + localRecordSequenceNumber = fmt.Sprint(v) + } + // 数据量上行链路 + var dataVolumeGPRSUplink int64 = 0 + // 数据量下行链路 + var dataVolumeGPRSDownlink int64 = 0 + if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk { + dataVolumeGPRSUplink = parse.Number(dup) + } + if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk { + dataVolumeGPRSDownlink = parse.Number(ddown) + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil { + invocationTimestamp = v.(string) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.NeName, + "C" + idx: row.RmUid, + "D" + idx: chargingID, + "E" + idx: servedIMSI, + "F" + idx: servedMSISDN, + "G" + idx: dataVolumeGPRSUplink, + "H" + idx: dataVolumeGPRSDownlink, + "I" + idx: duration, + "J" + idx: invocationTimestamp, + "K" + idx: pGWAddressUsed, + "L" + idx: sGWAddress, + "M" + idx: rATType, + "N" + idx: pdpPDNType, + "O" + idx: servedPDPPDNAddress, + "P" + idx: strings.Join(servingNodeAddress, ","), + "Q" + idx: strings.Join(servingNodeType, ","), + "R" + idx: accessPointNameNI, + "S" + idx: causeForRecClosing, + "T" + idx: recordSequenceNumber, + "U" + idx: localRecordSequenceNumber, + "V" + idx: recordType, + "W" + idx: invocationTimestamp, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export sgec cdr err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "cdr"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} diff --git a/src/modules/crontask/processor/backup_export_log/backup_export_log.go b/src/modules/crontask/processor/backup_export_log/backup_export_log.go new file mode 100644 index 00000000..6d7d6509 --- /dev/null +++ b/src/modules/crontask/processor/backup_export_log/backup_export_log.go @@ -0,0 +1,358 @@ +package backup_export_log + +import ( + "encoding/json" + "fmt" + "path/filepath" + "runtime" + "strconv" + "time" + + "be.ems/src/framework/cron" + "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/file" + neDataService "be.ems/src/modules/network_data/service" + systemModel "be.ems/src/modules/system/model" + systemService "be.ems/src/modules/system/service" +) + +var NewProcessor = &BackupExportLogProcessor{ + count: 0, + backupService: neDataService.NewBackup, + sysLogLoginService: systemService.NewSysLogLogin, + sysOperateService: systemService.NewSysLogOperate, +} + +// BackupExportLog 队列任务处理 +type BackupExportLogProcessor struct { + count int // 执行次数 + backupService *neDataService.Backup // 备份相关服务 + sysLogLoginService *systemService.SysLogLogin // 系统登录日志服务 + sysOperateService *systemService.SysLogOperate // 系统操作日志服务 +} + +func (s *BackupExportLogProcessor) Execute(data any) (any, error) { + s.count++ // 执行次数加一 + options := data.(cron.JobData) + sysJob := options.SysJob + logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count) + // 返回结果,用于记录执行结果 + result := map[string]any{ + "count": s.count, + } + + var params struct { + DataType []string `json:"dataType"` // 类型支持 operate/login + FileType string `json:"fileType"` // 文件类型 csv/xlsx + Hour int `json:"hour"` // 数据时间从任务执行时间前的小时数 + } + if err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms); err != nil { + return nil, err + } + if !(params.FileType == "csv" || params.FileType == "xlsx") { + return nil, fmt.Errorf("file type error, only support csv,xlsx") + } + + for _, v := range params.DataType { + switch v { + case "operate": + result[v] = s.exportOperate(params.Hour, params.FileType) + case "login": + result[v] = s.exportLogin(params.Hour, params.FileType) + } + } + + // 返回结果,用于记录执行结果 + return result, nil +} + +// exportOperate 导出系统操作日志数据 +func (s BackupExportLogProcessor) exportOperate(hour int, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + language := "en" + query := map[string]string{ + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": "1", + "pageSize": "30000", + } + rows, total := s.sysOperateService.FindByPage(query, "") + if total == 0 { + return "no data" + } + + // 闭包函数处理多语言 + converI18n := func(language string, arr *[]systemModel.SysLogOperate) { + for i := range *arr { + (*arr)[i].Title = i18n.TKey(language, (*arr)[i].Title) + (*arr)[i].OperaLocation = i18n.TKey(language, (*arr)[i].OperaLocation) + } + } + converI18n(language, &rows) + + // 导出文件名称 + fileName := fmt.Sprintf("sys_log_operate_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_operate", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + // 业务类型 + businessTypeFunc := func(v string) string { + businessType := "" + switch v { + case "0": + // 业务操作类型-其它 + businessType = i18n.TKey(language, "dictData.operType.other") + case "1": + // 业务操作类型-新增 + businessType = i18n.TKey(language, "dictData.operType.add") + case "2": + // 业务操作类型-修改 + businessType = i18n.TKey(language, "dictData.operType.edit") + case "3": + // 业务操作类型-删除 + businessType = i18n.TKey(language, "dictData.operType.delete") + case "4": + // 业务操作类型-授权 + businessType = i18n.TKey(language, "dictData.operType.auth") + case "5": + // 业务操作类型-导出 + businessType = i18n.TKey(language, "dictData.operType.export") + case "6": + // 业务操作类型-导入 + businessType = i18n.TKey(language, "dictData.operType.import") + case "7": + // 业务操作类型-强退 + businessType = i18n.TKey(language, "dictData.operType.forced quit") + case "8": + // 业务操作类型-清空数据 + businessType = i18n.TKey(language, "dictData.operType.clear") + } + return businessType + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + i18n.TKey(language, "log.operate.export.id"), + i18n.TKey(language, "log.operate.export.title"), + i18n.TKey(language, "log.operate.export.businessType"), + i18n.TKey(language, "log.operate.export.operName"), + i18n.TKey(language, "log.operate.export.method"), + i18n.TKey(language, "log.operate.export.ip"), + i18n.TKey(language, "log.operate.export.status"), + i18n.TKey(language, "log.operate.export.operTime"), + i18n.TKey(language, "log.operate.export.costTime"), + }, + } + for _, row := range rows { + // 业务类型 + businessType := businessTypeFunc(row.BusinessType) + + // 状态 + statusValue := i18n.TKey(language, "dictData.fail") + if row.StatusFlag == "1" { + statusValue = i18n.TKey(language, "dictData.success") + } + data = append(data, []string{ + fmt.Sprint(row.ID), + row.Title, + businessType, + row.OperaBy, + row.OperaUrlMethod, + row.OperaIp, + statusValue, + date.ParseDateToStr(row.OperaTime, date.YYYY_MM_DDTHH_MM_SSZ), + fmt.Sprint(row.CostTime), + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": i18n.TKey(language, "log.operate.export.id"), + "B1": i18n.TKey(language, "log.operate.export.title"), + "C1": i18n.TKey(language, "log.operate.export.businessType"), + "D1": i18n.TKey(language, "log.operate.export.operName"), + "E1": i18n.TKey(language, "log.operate.export.method"), + "F1": i18n.TKey(language, "log.operate.export.ip"), + "G1": i18n.TKey(language, "log.operate.export.status"), + "H1": i18n.TKey(language, "log.operate.export.operTime"), + "I1": i18n.TKey(language, "log.operate.export.costTime"), + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 业务类型 + businessType := businessTypeFunc(row.BusinessType) + + // 状态 + statusValue := i18n.TKey(language, "dictData.fail") + if row.StatusFlag == "1" { + statusValue = i18n.TKey(language, "dictData.success") + } + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.Title, + "C" + idx: businessType, + "D" + idx: row.OperaBy, + "E" + idx: row.OperaUrlMethod, + "F" + idx: row.OperaIp, + "G" + idx: statusValue, + "H" + idx: date.ParseDateToStr(row.OperaTime, date.YYYY_MM_DDTHH_MM_SSZ), + "I" + idx: row.CostTime, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export operate log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "log"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} + +// exportLogin 导出系统登录日志数据 +func (s BackupExportLogProcessor) exportLogin(hour int, fileType string) string { + // 前 hour 小时 + now := time.Now() + end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) + start := end.Add(-time.Duration(hour) * time.Hour) + + language := "en" + query := map[string]string{ + "beginTime": fmt.Sprint(start.UnixMilli()), + "endTime": fmt.Sprint(end.UnixMilli()), + "pageNum": "1", + "pageSize": "30000", + } + rows, total := s.sysLogLoginService.FindByPage(query, "") + if total == 0 { + return "no data" + } + + // 闭包函数处理多语言 + converI18n := func(language string, arr *[]systemModel.SysLogLogin) { + for i := range *arr { + (*arr)[i].LoginLocation = i18n.TKey(language, (*arr)[i].LoginLocation) + (*arr)[i].OS = i18n.TKey(language, (*arr)[i].OS) + (*arr)[i].Browser = i18n.TKey(language, (*arr)[i].Browser) + (*arr)[i].Msg = i18n.TKey(language, (*arr)[i].Msg) + } + } + converI18n(language, &rows) + + // 导出文件名称 + fileName := fmt.Sprintf("sys_log_login_export_%d_%s.%s", len(rows), date.ParseDateToStr(end, date.YYYYMMDDHHMMSS), fileType) + filePath := filepath.Join(s.backupService.BACKUP_DIR, "/log/sys_log_login", fileName) + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + + if fileType == "csv" { + // 转换数据 + data := [][]string{ + { + i18n.TKey(language, "log.login.export.id"), + i18n.TKey(language, "log.login.export.userName"), + i18n.TKey(language, "log.login.export.ip"), + i18n.TKey(language, "log.login.export.location"), + i18n.TKey(language, "log.login.export.os"), + i18n.TKey(language, "log.login.export.browser"), + i18n.TKey(language, "log.login.export.status"), + i18n.TKey(language, "log.login.export.time"), + i18n.TKey(language, "log.login.export.msg"), + }, + } + for _, row := range rows { + // 状态 + statusValue := i18n.TKey(language, "dictData.fail") + if row.StatusFlag == "1" { + statusValue = i18n.TKey(language, "dictData.success") + } + data = append(data, []string{ + fmt.Sprint(row.ID), + row.UserName, + row.LoginIp, + row.LoginLocation, + row.OS, + row.Browser, + statusValue, + date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ), + row.Msg, + }) + } + // 输出到文件 + if err := file.WriterFileCSV(data, filePath); err != nil { + logger.Errorf("export login log err => %v", err.Error()) + return "export err" + } + } + + if fileType == "xlsx" { + // 第一行表头标题 + headerCells := map[string]string{ + "A1": i18n.TKey(language, "log.login.export.id"), + "B1": i18n.TKey(language, "log.login.export.userName"), + "C1": i18n.TKey(language, "log.login.export.ip"), + "D1": i18n.TKey(language, "log.login.export.location"), + "E1": i18n.TKey(language, "log.login.export.os"), + "F1": i18n.TKey(language, "log.login.export.browser"), + "G1": i18n.TKey(language, "log.login.export.status"), + "H1": i18n.TKey(language, "log.login.export.time"), + "I1": i18n.TKey(language, "log.login.export.msg"), + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 状态 + statusValue := i18n.TKey(language, "dictData.fail") + if row.StatusFlag == "1" { + statusValue = i18n.TKey(language, "dictData.success") + } + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: row.UserName, + "C" + idx: row.LoginIp, + "D" + idx: row.LoginLocation, + "E" + idx: row.OS, + "F" + idx: row.Browser, + "G" + idx: statusValue, + "H" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ), + "I" + idx: row.Msg, + }) + } + // 导出数据表格 + if err := file.WriterFileExecl(headerCells, dataCells, filePath, ""); err != nil { + logger.Errorf("export login log err => %v", err.Error()) + return "export err" + } + } + + // 上传到FTP服务器 + if err := s.backupService.FTPPushFile(filePath, "log"); err != nil { + return "ok, ftp err:" + err.Error() + } + return "ok" +} diff --git a/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go b/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go index f74a3d1b..f2d6e9a7 100644 --- a/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go +++ b/src/modules/crontask/processor/ne_alarm_state_check/ne_alarm_state_check.go @@ -88,13 +88,13 @@ func (s *NeAlarmStateCheckProcessor) Execute(data any) (any, error) { // 在线且状态为活动告警 if isOnline && alarmStatus == "1" { // 进行清除 - newAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) + clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) if err != nil { result[neTypeAndId] = err.Error() continue } groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) - s.wsSendService.ByGroupID(groupID, newAlarm) + s.wsSendService.ByGroupID(groupID, clearAlarm) result[neTypeAndId] = "alarm clear" } @@ -151,19 +151,19 @@ func (s NeAlarmStateCheckProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParam AlarmTitle: v.AlarmTitle, AlarmCode: constants.ALARM_STATE_CHECK, EventTime: lastTime, - AlarmType: "2", - OrigSeverity: "2", - PerceivedSeverity: "2", + AlarmType: v.AlarmType, + OrigSeverity: v.OrigSeverity, + PerceivedSeverity: v.OrigSeverity, ObjectUid: neInfo.RmUID, - ObjectName: "SystemManagement;Heartbeat", - ObjectType: "SystemState", - LocationInfo: "SystemManagement.State: NE Heartbeat", - AlarmStatus: "1", + ObjectName: "NE State", + ObjectType: "state", + LocationInfo: "NE State: Heartbeat", + AlarmStatus: "1", // 活动告警 SpecificProblem: v.SpecificProblem, SpecificProblemId: v.SpecificProblemID, AddInfo: v.AddInfo, } - insertId := s.alarmService.Insert(alarm) + insertId := s.alarmService.InsertAndForword(alarm) if insertId > 0 { alarm.ID = insertId return alarm, nil diff --git a/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go new file mode 100644 index 00000000..20017f66 --- /dev/null +++ b/src/modules/crontask/processor/ne_alarm_state_check_cmd/ne_alarm_state_check_cmd.go @@ -0,0 +1,288 @@ +package ne_alarm_state_check_cmd + +import ( + "encoding/json" + "fmt" + "sort" + "strconv" + "strings" + "time" + + "be.ems/src/framework/constants" + "be.ems/src/framework/cron" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neModel "be.ems/src/modules/network_element/model" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +var NewProcessor = &NeAlarmStateCheckCMDProcessor{ + neConfigBackupService: neService.NewNeConfigBackup, + neInfoService: neService.NewNeInfo, + neStateService: neDataService.NewNEState, + alarmService: neDataService.NewAlarm, + wsSendService: wsService.NewWSSend, + count: 0, +} + +// NeAlarmStateCheckCMDProcessor 网元告警内存/CPU/磁盘检查 +type NeAlarmStateCheckCMDProcessor struct { + neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务 + neInfoService *neService.NeInfo // 网元信息服务 + neStateService *neDataService.NEState // 网元状态信息服务 + alarmService *neDataService.Alarm // 告警信息服务 + wsSendService *wsService.WSSend // ws发送服务 + count int // 执行次数 + +} + +// alarmParams 告警参数 +type alarmParams struct { + AlarmTitle string `json:"alarmTitle"` // NE State Check Alarm CPU/Menory/Disk + AlarmType string `json:"alarmType"` // EquipmentAlarm=2 + OrigSeverity string `json:"origSeverity"` // Major=2 + SpecificProblem string `json:"specificProblem"` // Alarm Cause: CPU/Menory/Disk status received from target NE reaches the threshold + SpecificProblemID string `json:"specificProblemId"` // AC10100 + AddInfo string `json:"addInfo"` // 告警补充信息 + CPUUseGt int64 `json:"cpuUseGt"` // CPU使用率大于, 范围0~100% + MemUseGt int64 `json:"memUseGt"` // 内存使用率大于, 范围0~100% + DiskUseGt int64 `json:"diskUseGt"` // 磁盘使用率大于, 范围0~100% + + // === 非参数字段 === + AlarmId string // 告警ID +} + +func (s *NeAlarmStateCheckCMDProcessor) Execute(data any) (any, error) { + s.count++ // 执行次数加一 + options := data.(cron.JobData) + sysJob := options.SysJob + logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count) + // 返回结果,用于记录执行结果 + result := map[string]any{ + "count": s.count, + } + + // 读取参数值 + var params alarmParams + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err != nil { + return nil, fmt.Errorf("json params err: %v", err) + } + // 检查使用率 + if params.CPUUseGt > 100 || params.CPUUseGt < 0 { + return nil, fmt.Errorf("cpuUseGt must be between 0 and 100") + } + if params.MemUseGt > 100 || params.MemUseGt < 0 { + return nil, fmt.Errorf("memUseGt must be between 0 and 100") + } + if params.DiskUseGt > 100 || params.DiskUseGt < 0 { + return nil, fmt.Errorf("diskUseGt must be between 0 and 100") + } + + neList := s.neInfoService.Find(neModel.NeInfo{}, true, false) + for _, neInfo := range neList { + if neInfo.CreateTime == 0 { + continue + } + + // 网元在线状态 + isOnline := parse.Boolean(neInfo.ServerState["online"]) + if !isOnline { + continue + } + + // 检查状态 + err := s.serverState(neInfo.ServerState, params.CPUUseGt, params.MemUseGt, params.DiskUseGt) + if err == nil { + continue + } + + neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) + // 告警ID + params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_CMD_CHECK, neInfo.CreateTime) + // 检查网元告警ID是否唯一 + alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + AlarmId: params.AlarmId, + }) + // 告警状态, 存在的需要手动清除 + alarmStatus := "" + if len(alarmIdArr) > 0 { + alarmStatus = fmt.Sprint(alarmIdArr[0].AlarmStatus) + } + // 活动告警进行清除 + if alarmStatus == "1" { + clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) + if err != nil { + result[neTypeAndId] = err.Error() + continue + } + groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) + s.wsSendService.ByGroupID(groupID, clearAlarm) + result[neTypeAndId] = "alarm clear" + alarmStatus = "" // 标记为未记录再次发起新告警 + } + // 未记录 + if alarmStatus == "" { + addInfo := params.AddInfo + if params.AddInfo != "" { + params.AddInfo = params.AddInfo + ", " + err.Error() + } else { + params.AddInfo = err.Error() + } + // 进行新增 + newAlarm, err := s.alarmNew(neInfo, params) + params.AddInfo = addInfo // 恢复附加信息 + if err != nil { + result[neTypeAndId] = err.Error() + continue + } + groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) + s.wsSendService.ByGroupID(groupID, newAlarm) + result[neTypeAndId] = "alarm new" + } + } + + // 返回结果,用于记录执行结果 + return result, nil +} + +// serverState 网元状态 +func (s NeAlarmStateCheckCMDProcessor) serverState(state map[string]any, cpuUseGt, memUseGt, diskUseGt int64) error { + // 网元CPU使用率 + var nfCpuUsage float64 = 0 + // CPU使用率 + var sysCpuUsage float64 = 0 + if state["cpu"] != nil { + cpu := state["cpu"].(map[string]any) + v := parse.Number(cpu["sysCpuUsage"]) + sysCpuUsage = float64(v) / 100 + nfv := parse.Number(cpu["nfCpuUsage"]) + nfCpuUsage = float64(nfv) / 100 + } + + // 网元内存使用KB + var nfMemUsed int64 = 0 + // 内存使用率 + var sysMemUsage float64 = 0 + if state["mem"] != nil { + mem := state["mem"].(map[string]any) + v := parse.Number(mem["sysMemUsage"]) + sysMemUsage = float64(v) / 100 + nfMemUsed = parse.Number(mem["nfUsedMem"]) + } + + // 磁盘使用率 + var sysDiskUsage float64 = 0 + if state["disk"] != nil { + mem := state["disk"].(map[string]any) + disks := mem["partitionInfo"].([]any) + sort.Slice(disks, func(i, j int) bool { + iUsed := parse.Number(disks[i].(map[string]any)["used"]) + jUsed := parse.Number(disks[j].(map[string]any)["used"]) + return iUsed > jUsed + }) + disk := disks[0].(map[string]any) + total := parse.Number(disk["total"]) + used := parse.Number(disk["used"]) + sysDiskUsage = (float64(used) / float64(total)) * 100 + sysDiskUsage, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", sysDiskUsage), 64) + } + + // 插入网元状态记录 + neState := neDataModel.NEState{ + NeType: fmt.Sprint(state["neType"]), + NeId: fmt.Sprint(state["neId"]), + Version: fmt.Sprint(state["version"]), + Capability: parse.Number(state["capability"]), + SerialNum: fmt.Sprint(state["sn"]), + ExpiryDate: fmt.Sprint(state["expire"]), + SysCpuUsage: sysCpuUsage, + SysMemUsage: sysMemUsage, + SysDiskUsage: sysDiskUsage, + NfCpuUsage: nfCpuUsage, + NfMemUsed: nfMemUsed, + CreateTime: parse.Number(state["refreshTime"]), + } + s.neStateService.Insert(neState) + // 删除网元状态记录7天前 + s.neStateService.DeleteByTime(time.Now().UnixMilli() - 7*24*60*60*1000) + // 推送ws消息 + groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_NE_STATE, neState.NeType, neState.NeId) + s.wsSendService.ByGroupID(groupID, neState) + + // 检查CPU/Menory/Disk使用率 + warnMsg := []string{} + if int64(sysCpuUsage) >= cpuUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("cpu usage %.2f%%", sysCpuUsage)) + } + if int64(sysMemUsage) >= memUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("memory usage %.2f%%", sysMemUsage)) + } + if int64(sysDiskUsage) >= diskUseGt { + warnMsg = append(warnMsg, fmt.Sprintf("disk usage %.2f%%", sysDiskUsage)) + } + if len(warnMsg) > 0 { + return fmt.Errorf("greater than %s", strings.Join(warnMsg, ", ")) + } + return nil +} + +// alarmClear 清除告警 +func (s NeAlarmStateCheckCMDProcessor) alarmClear(neInfo neModel.NeInfo, v neDataModel.Alarm) (neDataModel.Alarm, error) { + // 变更告警ID为告警清除ID + v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) + v.AlarmStatus = "0" + // 告警清除 + v.ClearType = 1 + v.ClearTime = neInfo.UpdateTime + v.ClearUser = "system" + rows := s.alarmService.Update(v) + if rows > 0 { + return v, nil + } + return neDataModel.Alarm{}, fmt.Errorf("clear alarm fail") +} + +// alarmNew 新增告警 +func (s NeAlarmStateCheckCMDProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParams) (neDataModel.Alarm, error) { + // seq 告警序号 + lastSeq := s.alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) + lastTime := neInfo.UpdateTime // 网元最后更新时间 + if lastTime < neInfo.CreateTime { + lastTime = time.Now().UnixMilli() + } + alarm := neDataModel.Alarm{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + NeName: neInfo.NeName, + Province: neInfo.Province, + PvFlag: neInfo.PvFlag, + AlarmSeq: lastSeq + 1, + AlarmId: v.AlarmId, + AlarmTitle: v.AlarmTitle, + AlarmCode: constants.ALARM_CMD_CHECK, + EventTime: lastTime, + AlarmType: v.AlarmType, + OrigSeverity: v.OrigSeverity, + PerceivedSeverity: v.OrigSeverity, + ObjectUid: neInfo.RmUID, + ObjectName: "NE CPU/Menory/Disk", + ObjectType: "cmd", + LocationInfo: "NE CPU/Menory/Disk: Heartbeat", + AlarmStatus: "1", // 活动告警 + SpecificProblem: v.SpecificProblem, + SpecificProblemId: v.SpecificProblemID, + AddInfo: v.AddInfo, + } + insertId := s.alarmService.InsertAndForword(alarm) + if insertId > 0 { + alarm.ID = insertId + return alarm, nil + } + return neDataModel.Alarm{}, fmt.Errorf("new alarm fail") +} diff --git a/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go new file mode 100644 index 00000000..57d6d5ae --- /dev/null +++ b/src/modules/crontask/processor/ne_alarm_state_check_license/ne_alarm_state_check_license.go @@ -0,0 +1,213 @@ +package ne_alarm_state_check_license + +import ( + "encoding/json" + "fmt" + "time" + + "be.ems/src/framework/constants" + "be.ems/src/framework/cron" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + + neDataModel "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neModel "be.ems/src/modules/network_element/model" + neService "be.ems/src/modules/network_element/service" + wsService "be.ems/src/modules/ws/service" +) + +var NewProcessor = &NeAlarmStateCheckLicenseProcessor{ + neConfigBackupService: neService.NewNeConfigBackup, + neInfoService: neService.NewNeInfo, + alarmService: neDataService.NewAlarm, + wsSendService: wsService.NewWSSend, + count: 0, +} + +// NeAlarmStateCheckLicenseProcessor 网元告警License到期检查 +type NeAlarmStateCheckLicenseProcessor struct { + neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务 + neInfoService *neService.NeInfo // 网元信息服务 + alarmService *neDataService.Alarm // 告警信息服务 + wsSendService *wsService.WSSend // ws发送服务 + count int // 执行次数 +} + +// alarmParams 告警参数 +type alarmParams struct { + AlarmTitle string `json:"alarmTitle"` // NE State Check Alarm License + AlarmType string `json:"alarmType"` // EquipmentAlarm=2 + OrigSeverity string `json:"origSeverity"` // Major=2 + SpecificProblem string `json:"specificProblem"` // Alarm Cause: License received from target NE is about to expire + SpecificProblemID string `json:"specificProblemId"` // AC10200 + AddInfo string `json:"addInfo"` // 告警补充信息 + DayLt int64 `json:"dayLt"` // 天数小于,默认30天 + + // === 非参数字段 === + AlarmId string // 告警ID +} + +func (s *NeAlarmStateCheckLicenseProcessor) Execute(data any) (any, error) { + s.count++ // 执行次数加一 + options := data.(cron.JobData) + sysJob := options.SysJob + logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count) + // 返回结果,用于记录执行结果 + result := map[string]any{ + "count": s.count, + } + + // 读取参数值 + var params alarmParams + err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms) + if err != nil { + return nil, fmt.Errorf("json params err: %v", err) + } + // 检查参数值 + if params.DayLt == 0 { + params.DayLt = 30 + } + + neList := s.neInfoService.Find(neModel.NeInfo{}, true, false) + for _, neInfo := range neList { + if neInfo.CreateTime == 0 { + continue + } + + // 网元在线状态 + isOnline := parse.Boolean(neInfo.ServerState["online"]) + if !isOnline { + continue + } + + // 检查状态 + err := s.serverState(neInfo.ServerState, params.DayLt) + if err == nil { + continue + } + if params.AddInfo != "" { + params.AddInfo = params.AddInfo + ", " + err.Error() + } else { + params.AddInfo = err.Error() + } + + neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) + // 告警ID + params.AlarmId = fmt.Sprintf("%d%d", constants.ALARM_LICENSE_CHECK, neInfo.CreateTime) + // 检查网元告警ID是否唯一 + alarmIdArr := s.alarmService.Find(neDataModel.Alarm{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + AlarmId: params.AlarmId, + }) + // 告警状态, 存在的需要手动清除 + alarmStatus := "" + if len(alarmIdArr) > 0 { + alarmStatus = fmt.Sprint(alarmIdArr[0].AlarmStatus) + } + // 活动告警进行清除 + if alarmStatus == "1" { + clearAlarm, err := s.alarmClear(neInfo, alarmIdArr[0]) + if err != nil { + result[neTypeAndId] = err.Error() + continue + } + groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) + s.wsSendService.ByGroupID(groupID, clearAlarm) + result[neTypeAndId] = "alarm clear" + alarmStatus = "" // 标记为未记录再次发起新告警 + } + // 未记录 + if alarmStatus == "" { + // 进行新增 + newAlarm, err := s.alarmNew(neInfo, params) + if err != nil { + result[neTypeAndId] = err.Error() + continue + } + groupID := fmt.Sprintf("%s_%s_%s", wsService.GROUP_ALARM, neInfo.NeType, neInfo.NeId) + s.wsSendService.ByGroupID(groupID, newAlarm) + result[neTypeAndId] = "alarm new" + } + } + + // 返回结果,用于记录执行结果 + return result, nil +} + +// serverState 网元状态 +func (s NeAlarmStateCheckLicenseProcessor) serverState(state map[string]any, dayLt int64) error { + expire := fmt.Sprint(state["expire"]) + if expire == "" || expire == "" || expire == "2099-12-31" { + return nil + } + + // 解析过期时间 + expireTime, err := time.Parse("2006-01-02", expire) + if err != nil { + return fmt.Errorf("parse expire time error: %v", err) + } + + // 计算距离天数 + daysLeft := int64(time.Since(expireTime).Hours() / 24) + if daysLeft < dayLt { + return fmt.Errorf("license will expire in %d days", daysLeft) + } + return nil +} + +// alarmClear 清除告警 +func (s NeAlarmStateCheckLicenseProcessor) alarmClear(neInfo neModel.NeInfo, v neDataModel.Alarm) (neDataModel.Alarm, error) { + // 变更告警ID为告警清除ID + v.AlarmId = fmt.Sprintf("%d%d", v.AlarmCode, v.EventTime) + v.AlarmStatus = "0" + // 告警清除 + v.ClearType = 1 + v.ClearTime = neInfo.UpdateTime + v.ClearUser = "system" + rows := s.alarmService.Update(v) + if rows > 0 { + return v, nil + } + return neDataModel.Alarm{}, fmt.Errorf("clear alarm fail") +} + +// alarmNew 新增告警 +func (s NeAlarmStateCheckLicenseProcessor) alarmNew(neInfo neModel.NeInfo, v alarmParams) (neDataModel.Alarm, error) { + // seq 告警序号 + lastSeq := s.alarmService.FindAlarmSeqLast(neInfo.NeType, neInfo.NeId) + lastTime := neInfo.UpdateTime // 网元最后更新时间 + if lastTime < neInfo.CreateTime { + lastTime = time.Now().UnixMilli() + } + alarm := neDataModel.Alarm{ + NeType: neInfo.NeType, + NeId: neInfo.NeId, + NeName: neInfo.NeName, + Province: neInfo.Province, + PvFlag: neInfo.PvFlag, + AlarmSeq: lastSeq + 1, + AlarmId: v.AlarmId, + AlarmTitle: v.AlarmTitle, + AlarmCode: constants.ALARM_LICENSE_CHECK, + EventTime: lastTime, + AlarmType: v.AlarmType, + OrigSeverity: v.OrigSeverity, + PerceivedSeverity: v.OrigSeverity, + ObjectUid: neInfo.RmUID, + ObjectName: "NE License", + ObjectType: "license", + LocationInfo: "NE License: Heartbeat", + AlarmStatus: "1", // 活动告警 + SpecificProblem: v.SpecificProblem, + SpecificProblemId: v.SpecificProblemID, + AddInfo: v.AddInfo, + } + insertId := s.alarmService.InsertAndForword(alarm) + if insertId > 0 { + alarm.ID = insertId + return alarm, nil + } + return neDataModel.Alarm{}, fmt.Errorf("new alarm fail") +} diff --git a/src/modules/crontask/processor/processor.go b/src/modules/crontask/processor/processor.go index bc2e4f78..c4e203cf 100644 --- a/src/modules/crontask/processor/processor.go +++ b/src/modules/crontask/processor/processor.go @@ -2,6 +2,8 @@ package processor import ( "be.ems/src/framework/cron" + processorBackupExportCDR "be.ems/src/modules/crontask/processor/backup_export_cdr" + processorBackupExportLog "be.ems/src/modules/crontask/processor/backup_export_log" processorBackupExportTable "be.ems/src/modules/crontask/processor/backup_export_table" processorBackupExportUDM "be.ems/src/modules/crontask/processor/backup_export_udm" processorBackupRemoveFile "be.ems/src/modules/crontask/processor/backup_remove_file" @@ -11,6 +13,8 @@ import ( processorDeleteNeConfigBackup "be.ems/src/modules/crontask/processor/delete_ne_config_backup" processorMonitorSysResource "be.ems/src/modules/crontask/processor/monitor_sys_resource" processorNeAlarmStateCheck "be.ems/src/modules/crontask/processor/ne_alarm_state_check" + processorNeAlarmStateCheckCMD "be.ems/src/modules/crontask/processor/ne_alarm_state_check_cmd" + processorNeAlarmStateCheckLicense "be.ems/src/modules/crontask/processor/ne_alarm_state_check_license" processorNeConfigBackup "be.ems/src/modules/crontask/processor/ne_config_backup" processorNeDataUDM "be.ems/src/modules/crontask/processor/ne_data_udm" ) @@ -23,8 +27,13 @@ func InitCronQueue() { cron.CreateQueue("ne_config_backup", processorNeConfigBackup.NewProcessor) // 网元数据-UDM用户数据同步 cron.CreateQueue("ne_data_udm", processorNeDataUDM.NewProcessor) + // 网元告警-状态检查 cron.CreateQueue("ne_alarm_state_check", processorNeAlarmStateCheck.NewProcessor) + // 网元告警-内存/CPU/磁盘检查 + cron.CreateQueue("ne_alarm_state_check_cmd", processorNeAlarmStateCheckCMD.NewProcessor) + // 网元告警-License到期检查 + cron.CreateQueue("ne_alarm_state_check_license", processorNeAlarmStateCheckLicense.NewProcessor) // 删除-表内数据记录 cron.CreateQueue("delete_data_record", processorDeleteDataRecord.NewProcessor) @@ -41,4 +50,8 @@ func InitCronQueue() { cron.CreateQueue("backup_remove_file", processorBackupRemoveFile.NewProcessor) // 备份-导出UDM用户数据 cron.CreateQueue("backup_export_udm", processorBackupExportUDM.NewProcessor) + // 备份-导出CDR数据 + cron.CreateQueue("backup_export_cdr", processorBackupExportCDR.NewProcessor) + // 备份-导出Log数据 + cron.CreateQueue("backup_export_log", processorBackupExportLog.NewProcessor) }