ref: v3变更,,api路由调整,菜单角色分配

This commit is contained in:
TsMask
2025-09-06 17:41:16 +08:00
parent 10cf6bbd2a
commit b8116ce203
99 changed files with 749 additions and 759 deletions

View File

@@ -53,7 +53,7 @@ type AlarmController struct {
// @Security TokenAuth
// @Summary Alarm List
// @Description Alarm List
// @Router /neData/alarm/list [get]
// @Router /ne/data/alarm/list [get]
func (s AlarmController) List(c *gin.Context) {
var query model.AlarmQuery
if err := c.ShouldBindQuery(&query); err != nil {
@@ -229,7 +229,7 @@ func (s AlarmController) CountTop(c *gin.Context) {
// @Security TokenAuth
// @Summary Alarm List Export
// @Description Alarm List Export
// @Router /neData/alarm/export [get]
// @Router /ne/data/alarm/export [get]
func (s AlarmController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制

View File

@@ -38,7 +38,7 @@ type AlarmForwardController struct {
// @Security TokenAuth
// @Summary Alarm Forward Log List
// @Description Alarm Forward Log List
// @Router /neData/alarm/forward/log/list [get]
// @Router /ne/data/data/alarm/forward/log/list [get]
func (s AlarmForwardController) List(c *gin.Context) {
var query model.AlarmForwardLogQuery
if err := c.ShouldBindQuery(&query); err != nil {

View File

@@ -44,7 +44,7 @@ type AlarmLogController struct {
// @Security TokenAuth
// @Summary AlarmLog List
// @Description AlarmLog List
// @Router /neData/alarm/log/list [get]
// @Router /ne/data/alarm/log/list [get]
func (s AlarmLogController) List(c *gin.Context) {
var query model.AlarmLogQuery
if err := c.ShouldBindQuery(&query); err != nil {
@@ -77,7 +77,7 @@ func (s AlarmLogController) List(c *gin.Context) {
// @Security TokenAuth
// @Summary Alarm Event Log List
// @Description Alarm Event Log List
// @Router /neData/alarm/log/event [get]
// @Router /ne/data/alarm/log/event [get]
func (s AlarmLogController) Event(c *gin.Context) {
var query model.AlarmEventQuery
if err := c.ShouldBindQuery(&query); err != nil {

View File

@@ -1,251 +0,0 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 AMFController 结构体
var NewAMF = &AMFController{
neInfoService: neService.NewNeInfo,
ueEventService: neDataService.NewUEEvent,
}
// 网元AMF
//
// PATH /amf
type AMFController struct {
neInfoService *neService.NeInfo // 网元信息服务
ueEventService *neDataService.UEEvent // UE会话事件服务
}
// UE会话列表
//
// GET /ue/list
//
// @Tags ne_data/amf
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only AMF" Enums(AMF)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List
// @Description UE Session List
// @Router /neData/amf/ue/list [get]
func (s *AMFController) UEList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.ueEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UE会话删除
//
// DELETE /ue/:id
//
// @Tags ne_data/amf
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session Deletion
// @Description UE Session Deletion
// @Router /neData/amf/ue/{id} [delete]
func (s *AMFController) UERemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.ueEventService.DeleteByIds("AMF", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// UE会话列表导出
//
// GET /ue/export
//
// @Tags ne_data/amf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List Export
// @Description UE Session List Export
// @Router /neData/amf/ue/export [get]
func (s *AMFController) UEExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.ueEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.ueEventService.ExportAMF(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 接入基站信息列表
//
// GET /nb/list
//
// @Tags ne_data/amf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param id query string false "Base Station ID"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access Base Station Information List
// @Description Access Base Station Information List
// @Router /neData/amf/nb/list [get]
func (s *AMFController) NbInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
NbId string `form:"id"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.AMFNbInfoList(neInfo, map[string]string{
"id": query.NbId,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 接入基站状态信息列表
//
// GET /nb/addrs
//
// @Tags ne_data/amf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access to the base station status information list
// @Description Access to the base station status information list
// @Router /neData/amf/nb/addrs [get]
func (s *AMFController) NbStateList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.AMFGnbStateList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -1,317 +0,0 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
const (
neType = "CBC" // 网元类型
)
// 实例化控制层 CBCController 结构体
var NewCBC = &CBCController{
neInfoService: neService.NewNeInfo,
neCBCMessageService: neDataService.NewCBCMessage,
}
// 网元CBC
type CBCController struct {
neInfoService *neService.NeInfo // 网元信息服务
neCBCMessageService *neDataService.CBCMessage // CBC消息服务
}
func (m *CBCController) List(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.Query("neId")
if neId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
var query model.CBCMessageQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
query.NeType = neType
query.NeId = neId
data, total, err := neDataService.NewCBCMessage.SelectByPage(query)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
// 转换数据格式,确保 MessageJson 正确序列化
processedData := make([]map[string]interface{}, len(data))
for i, msg := range data {
var messageJson interface{}
if len(msg.MessageJson) > 0 {
// 尝试解析为 JSON 对象
if err := json.Unmarshal(msg.MessageJson, &messageJson); err != nil {
// 如果解析失败,就作为字符串
messageJson = string(msg.MessageJson)
}
}
processedData[i] = map[string]interface{}{
"id": msg.Id,
"neType": msg.NeType,
"neId": msg.NeId,
"messageJson": messageJson, // 这里是解析后的 JSON 对象
"status": msg.Status.Enum(),
"detail": msg.Detail,
"createdAt": msg.CreatedAt,
"updatedAt": msg.UpdatedAt,
}
}
c.JSON(200, resp.Ok(gin.H{
"total": total,
"data": processedData,
}))
}
// Update 更新CB消息
func (m *CBCController) Insert(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 绑定请求体
var msg model.CBCMessage
msg.NeType = neType
msg.NeId = c.Query("neId")
msg.Status = model.CBCEventStatusInactive // 默认状态为 INACTIVE
if msg.NeId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
now := time.Now().UnixMilli()
msg.CreatedAt = now
msg.UpdatedAt = now
// 使用 ShouldBindBodyWithJSON 读取请求体
var jsonData interface{}
if err := c.ShouldBindBodyWithJSON(&jsonData); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 将绑定的数据转换为 JSON
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
msg.MessageJson = json.RawMessage(jsonBytes)
if err := neDataService.NewCBCMessage.Insert(msg); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// Update 更新CB消息
func (m *CBCController) Update(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
messageId := c.Param("id")
if messageId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 直接读取body为json.RawMessage
var jsonData interface{}
if err := c.ShouldBindBodyWithJSON(&jsonData); err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 将绑定的数据转换为 JSON
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
messageJson := json.RawMessage(jsonBytes)
if err := neDataService.NewCBCMessage.Update(id, messageJson); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// UpdateStatus 更新CB消息状态
// 这里的 neId 参数是为了兼容性,实际更新状态时不需要使用它
// 但为了保持与原有接口一致,仍然保留该参数
// 如果需要根据 neId 进行特定的逻辑处理,可以在服务层实现
// 但在当前实现中neId 仅用于验证请求的有效性
// 实际的状态更新逻辑不依赖于 neId
// 该接口用于更新 CB 消息的状态,状态值通过查询参数传递
// 例如PUT /:neId/message/status?status=ACTIVE
func (m *CBCController) UpdateStatus(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.Query("neId")
status := c.Param("status")
if neId == "" || status == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
messageId := c.Param("id")
if messageId != "" {
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 如果提供了 messageId则更新特定消息的状态
if err := neDataService.NewCBCMessage.UpdateStatus(id, status); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
return
}
// 如果没有提供 messageId则更新所有消息的状态
if err := neDataService.NewCBCMessage.UpdateStatusByNeId(neId, status); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// Delete 删除CB消息
func (m *CBCController) Delete(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
messageId := c.Param("id")
if messageId == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(messageId, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if err := neDataService.NewCBCMessage.Delete(id); err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// ListById 根据ID获取CB消息
func (m *CBCController) ListById(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 获取路径参数
idStr := c.Param("id")
if idStr == "" {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
data, err := neDataService.NewCBCMessage.SelectById(id)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
if data == nil {
c.JSON(404, resp.CodeMsg(404, i18n.TKey(language, "app.common.err404")))
return
}
// 转换数据格式,确保 MessageJson 正确序列化
var messageJson interface{}
if len(data.MessageJson) > 0 {
// 尝试解析为 JSON 对象
if err := json.Unmarshal(data.MessageJson, &messageJson); err != nil {
// 如果解析失败,就作为字符串
messageJson = string(data.MessageJson)
}
}
processedData := map[string]interface{}{
"id": data.Id,
"neType": data.NeType,
"neId": data.NeId,
"messageJson": messageJson, // 这里是解析后的 JSON 对象
"status": data.Status.Enum(),
"detail": data.Detail,
"createdAt": data.CreatedAt,
"updatedAt": data.UpdatedAt,
}
c.JSON(200, resp.Ok(gin.H{
"data": processedData,
}))
}
func (m *CBCController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var query model.CBCMessageQuery
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if query.PageSize > 10000 {
query.PageSize = 10000
}
// 查询数据
rows, total, err := m.neCBCMessageService.SelectByPage(query)
if err != nil {
c.JSON(500, resp.ErrMsg(err.Error()))
return
}
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("cbc_message_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := m.neCBCMessageService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -1,299 +0,0 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 IMSController 结构体
var NewIMS = &IMSController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREvent,
kpiReportService: neDataService.NewKpiReport,
}
// 网元IMS
//
// PATH /ims
type IMSController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREvent // CDR会话事件服务
kpiReportService *neDataService.KpiReport // 统计信息服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags ne_data/ims
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only IMS" Enums(IMS)
// @Param neId query string true "NE ID" default(001)
// @Param callerParty query string false "callerParty"
// @Param calledParty query string false "calledParty"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/ims/cdr/list [get]
func (s *IMSController) CDRList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags ne_data/ims
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/ims/cdr/{id} [delete]
func (s *IMSController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(442002, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds("IMS", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// GET /cdr/export
//
// @Tags ne_data/ims
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/ims/cdr/export [get]
func (s *IMSController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportIMS(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 在线会话用户数量
//
// GET /session/num
//
// @Tags ne_data/ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Number of online session users
// @Description Number of online session users
// @Router /neData/ims/session/num [get]
func (s *IMSController) UeSessionNum(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
num, err := neFetchlink.IMSUeSessionNum(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(num))
}
// 在线会话用户列表信息
//
// GET /session/list
//
// @Tags ne_data/ims
// @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 Online session user list information
// @Description Online session user list information
// @Router /neData/ims/session/list [get]
func (s *IMSController) UeSessionList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" 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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.IMSUeSessionList(neInfo, map[string]string{
"imsi": query.IMSI,
"msisdn": query.MSISDN,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// KPI 忙时统计
//
// GET /kpi/busy-hour
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param timestamp query int64 false "timestamp"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Busy hour statistics
// @Description Busy hour statistics
// @Router /neData/ims/kpi/busy-hour [get]
func (s IMSController) KPIBusyHour(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
Timestamp int64 `form:"timestamp" binding:"required"` // 时间戳毫秒 年月日返回每小时的总和 年月日时返回该小时的总和
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if query.Timestamp < 1e12 || query.Timestamp > 1e13 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "timestamp format is ms"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
data := s.kpiReportService.IMSBusyHour(neInfo.CoreUID, neInfo.NeUID, query.Timestamp)
c.JSON(200, resp.OkData(data))
}

View File

@@ -44,7 +44,7 @@ type KPIController struct {
// @Security TokenAuth
// @Summary Access to statistical data
// @Description Access to statistical data
// @Router /neData/kpi/data [get]
// @Router /ne/data/kpi/data [get]
func (s KPIController) KPIData(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var querys model.KPIQuery
@@ -78,7 +78,7 @@ func (s KPIController) KPIData(c *gin.Context) {
// @Security TokenAuth
// @Summary Get Statistical Headings
// @Description Get Statistical Headings
// @Router /neData/kpi/title [get]
// @Router /ne/data/kpi/title [get]
func (s KPIController) KPITitle(c *gin.Context) {
neType := c.Query("neType")
if neType == "" {

View File

@@ -46,7 +46,7 @@ type KPICController struct {
// @Security TokenAuth
// @Summary Access to statistical data
// @Description Access to statistical data
// @Router /neData/kpic/data [get]
// @Router /ne/data/kpic/data [get]
func (s KPICController) KPIData(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var querys model.KPICQuery

View File

@@ -1,251 +0,0 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 MMEController 结构体
var NewMME = &MMEController{
neInfoService: neService.NewNeInfo,
ueEventService: neDataService.NewUEEvent,
}
// 网元MME
//
// PATH /mme
type MMEController struct {
neInfoService *neService.NeInfo // 网元信息服务
ueEventService *neDataService.UEEvent // UE会话事件服务
}
// UE会话列表
//
// GET /ue/list
//
// @Tags ne_data/mme
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only MME" Enums(MME)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List
// @Description UE Session List
// @Router /neData/mme/ue/list [get]
func (s *MMEController) UEList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.ueEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UE会话删除
//
// DELETE /ue/:id
//
// @Tags ne_data/mme
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session Deletion
// @Description UE Session Deletion
// @Router /neData/mme/ue/{id} [delete]
func (s *MMEController) UERemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.ueEventService.DeleteByIds("MME", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// UE会话列表导出
//
// GET /ue/export
//
// @Tags ne_data/mme
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List Export
// @Description UE Session List Export
// @Router /neData/mme/ue/export [get]
func (s *MMEController) UEExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.ueEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.ueEventService.ExportMME(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 接入基站信息列表
//
// GET /nb/list
//
// @Tags ne_data/mme
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param id query string false "Base Station ID"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access Base Station Information List
// @Description Access Base Station Information List
// @Router /neData/mme/nb/list [get]
func (s *MMEController) NbInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
NbId string `form:"id"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.MMENbInfoList(neInfo, map[string]string{
"id": query.NbId,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 接入基站状态信息列表
//
// GET /nb/addrs
//
// @Tags ne_data/mme
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access to the base station status information list
// @Description Access to the base station status information list
// @Router /neData/mme/nb/addrs [get]
func (s *MMEController) NbStateList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.MMEEnbStateList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -1,71 +0,0 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 N3IWFController 结构体
var NewN3IWF = &N3IWFController{
neInfoService: neService.NewNeInfo,
}
// 网元N3IWF
//
// PATH /n3iwf
type N3IWFController struct {
neInfoService *neService.NeInfo // 网元信息服务
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags ne_data/n3iwf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/n3iwf/sub/list [get]
func (s N3IWFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.N3IWFSubInfoList(neInfo, map[string]string{
"imsi": query.IMSI,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -1,109 +0,0 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 NSSFController 结构体
var NewNSSF = &NSSFController{
neInfoService: neService.NewNeInfo,
}
// 网元NSSF
//
// PATH /NSSF
type NSSFController struct {
neInfoService *neService.NeInfo // 网元信息服务
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags ne_data/nssf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/nssf/sub/list [get]
func (s NSSFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.NSSFSubInfoList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 可用AMF列表信息
//
// GET /amf/list
//
// @Tags ne_data/nssf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/nssf/amf/list [get]
func (s NSSFController) AvailableList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.NSSFAvailableAMFList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -1,334 +0,0 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/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 /ne/link/pcf/rule/list [get]
func (s PCFController) RuleInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" 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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
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 /ne/link/pcf/rule [post]
func (s PCFController) RuleInfoAdd(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
Num int64 `json:"num"` // 批量添加 大于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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
var err error
if body.Num > 1 { // 批量添加
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 /ne/link/pcf/rule [put]
func (s PCFController) RuleInfoEdit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
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 /ne/link/pcf/rule [delete]
func (s PCFController) RuleInfoRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
var err error
if query.Num > 1 { // 批量删除
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 /ne/link/pcf/rule/export [get]
func (s PCFController) RuleInfoExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" 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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
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 /ne/link/pcf/rule/import [put]
func (s PCFController) RuleInfoImport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" 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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
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))
}

View File

@@ -1,164 +0,0 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 SGWCController 结构体
var NewSGWC = &SGWCController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREvent,
UDMExtendService: neDataService.NewUDMExtend,
}
// 网元SGWC
//
// PATH /sgwc
type SGWCController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREvent // CDR会话事件服务
UDMExtendService *neDataService.UDMExtend // UDM用户信息服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags ne_data/sgwc
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SGWC" Enums(SGWC)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param msisdn query string false "msisdn"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/sgwc/cdr/list [get]
func (s *SGWCController) CDRList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags ne_data/sgwc
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/sgwc/cdr/{id} [delete]
func (s *SGWCController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds("SGWC", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
//
// @Tags ne_data/sgwc
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/sgwc/cdr/export [post]
func (s *SGWCController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportSGWC(rows, fileName)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -1,283 +0,0 @@
package controller
import (
"fmt"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 SMFController 结构体
var NewSMF = &SMFController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREvent,
UDMExtendService: neDataService.NewUDMExtend,
}
// 网元SMF
//
// PATH /smf
type SMFController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREvent // CDR会话事件服务
UDMExtendService *neDataService.UDMExtend // UDM用户信息服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags ne_data/smf
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SMF" Enums(SMF)
// @Param neId query string true "NE ID" default(001)
// @Param subscriberID query string false "subscriberID is IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/smf/cdr/list [get]
func (s *SMFController) CDRList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags ne_data/smf
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/smf/cdr/{id} [delete]
func (s *SMFController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds("SMF", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// GET /cdr/export
//
// @Tags ne_data/smf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/smf/cdr/export [get]
func (s *SMFController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportSMF(rows, fileName)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 在线订阅用户数量
//
// GET /sub/num
//
// @Tags ne_data/smf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Number of online session users
// @Description Number of online session users
// @Router /neData/smf/sub/num [get]
func (s *SMFController) SubUserNum(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
num, err := neFetchlink.SMFSubNum(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(num))
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags ne_data/smf
// @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"
// @Param upstate query string false "upstate"
// @Param pageNum query string true "pageNum" default(50)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/smf/sub/list [get]
func (s *SMFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi"`
MSISDN string `form:"msisdn"`
Upstate string `form:"upstate"`
PageNum string `form:"pageNum"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.SMFSubInfoList(neInfo, map[string]string{
"imsi": query.IMSI,
"msisdn": query.MSISDN,
"upstate": query.Upstate,
"pageNum": query.PageNum,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 对数据进行处理去掉前缀并加入imsi拓展信息
rows := data["rows"].([]any)
if len(rows) > 0 {
arr := &rows
for i := range *arr {
item := (*arr)[i].(map[string]any)
if v, ok := item["imsi"]; ok && v != nil {
imsiStr := v.(string)
imsiStr = strings.TrimPrefix(imsiStr, "imsi-")
item["imsi"] = imsiStr
// 查UDM拓展信息
info := s.UDMExtendService.FindByIMSIAndNeID(neInfo.CoreUID, "%", imsiStr)
item["remark"] = info.Remark
}
if v, ok := item["msisdn"]; ok && v != nil {
item["msisdn"] = strings.TrimPrefix(v.(string), "msisdn-")
}
}
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -1,163 +0,0 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 SMSCController 结构体
var NewSMSC = &SMSCController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREvent,
}
// 网元SMSC
//
// PATH /smsc
type SMSCController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREvent // CDR会话事件服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags ne_data/smsc
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SMSC" Enums(SMSC)
// @Param neId query string true "NE ID" default(001)
// @Param callerParty query string false "callerParty"
// @Param calledParty query string false "calledParty"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/smsc/cdr/list [get]
func (s *SMSCController) CDRList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags ne_data/smsc
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/smsc/cdr/{id} [delete]
func (s *SMSCController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds("SMSC", ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// GET /cdr/export
//
// @Tags ne_data/smsc
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/smsc/cdr/export [get]
func (s *SMSCController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
query := reqctx.QueryMap(c)
// 限制导出数据集
pageSize := parse.Number(query["pageSize"])
if pageSize > 10000 {
query["pageSize"] = "10000"
}
coreUid := c.DefaultQuery("coreUid", "")
neUid := c.DefaultQuery("neUid", "")
if coreUid == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "coreUid or neUid is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(coreUid, neUid)
if neInfo.CoreUID != coreUid || neInfo.NeUID != neUid {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
rows, total := s.cdrEventService.FindByPage(neInfo.NeType, query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportSMSC(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -1,565 +0,0 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neFetchlink "be.ems/src/modules/ne/fetch_link"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMAuthController 结构体
var NewUDMAuth = &UDMAuthController{
udmAuthService: service.NewUDMAuthUser,
neInfoService: neService.NewNeInfo,
}
// UDM鉴权用户
//
// PATH /udm/auth
type UDMAuthController struct {
udmAuthService *service.UDMAuthUser // UDM鉴权信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDM鉴权用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Data Refresh
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
// @Router /ne/link/udm/auth/reset [put]
func (s *UDMAuthController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmAuthService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户列表
//
// GET /list
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User List
// @Description UDM Authentication User List
// @Router /ne/link/udm/auth/list [get]
func (s *UDMAuthController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
rows, total := s.udmAuthService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UDM鉴权用户信息
//
// GET /:neId/:imsi
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param coreUid query string true "NE ID" default(001)
// @Param neUid query string true "NE ID" default(001)
// @Param imsi query string true "IMSI"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Information
// @Description UDM Authentication User Information
// @Router /ne/link/udm/auth [get]
func (s *UDMAuthController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp authdat:imsi=%s", query.IMSI)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Auth Data"))
return
}
// 解析返回的数据
u := s.udmAuthService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, query.IMSI, data)
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, u)
c.JSON(200, resp.OkData(u))
}
// UDM鉴权用户新增
//
// POST /
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Added
// @Description UDM Authentication User Added
// @Router /ne/link/udm/auth [post]
func (s *UDMAuthController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMAuthUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.IMSI == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: imsi is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%d,", body.IMSI, num)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add authdat:imsi=%s,", body.IMSI)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户修改
//
// PUT /
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Modification
// @Description UDM Authenticated User Modification
// @Router /ne/link/udm/auth [put]
func (s *UDMAuthController) Edit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body model.UDMAuthUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if len(body.IMSI) != 15 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: IMSI length is not 15 bits"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("mod authdata:imsi=%s,", body.IMSI)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户删除
//
// DELETE /:neId/:imsi
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Deletion
// @Description UDM Authenticated User Deletion
// @Router /ne/link/udm/auth/{neId}/{value} [delete]
func (s *UDMAuthController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi
Num int64 `form:"num"` // 数量 0可拼接imsi多删除 大于1为批量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 0 {
// 发送MML
cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%d", query.IMSI, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.IMSI, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
resultData := map[string]string{}
for _, imsi := range uniqueIDs {
// 发送MML
cmd := fmt.Sprintf("del authdat:imsi=%s", imsi)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[imsi] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.Delete(neInfo.CoreUID, neInfo.NeUID, imsi)
}
resultData[imsi] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDM鉴权用户导出
//
// GET /export
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Export
// @Description UDM Authenticated User Export
// @Router /ne/link/udm/auth/export [get]
func (s *UDMAuthController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "file type error, only support csv,txt"))
return
}
query := reqctx.QueryMap(c)
rows, total := s.udmAuthService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"})
for _, v := range rows {
opc := v.Opc
if opc == "-" {
opc = ""
}
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
opc := v.Opc
if opc == "-" {
opc = ""
}
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDM鉴权用户导入
//
// POST /import
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Import
// @Description UDM Authenticated User Import
// @Router /ne/link/udm/auth/import [post]
func (s *UDMAuthController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
TypeVal string `json:"typeVal" binding:"required,oneof=default k4"` // default: 默认导入方式, k4: k4类型导入方式
TypeData any `json:"typeData"` // k4类型的数据密钥
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 默认的情况 发送MML
if body.TypeVal == "default" {
cmd := fmt.Sprintf("import authdat:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
}
// K4类型发特定请求
if body.TypeVal == "k4" {
resultMsg, resultErr = neFetchlink.UDMImportAuth(neInfo.IPAddr, map[string]any{
"path": neFilePath, "k4": body.TypeData,
})
}
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmAuthService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmAuthService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -1,546 +0,0 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMSubController 结构体
var NewUDMSub = &UDMSubController{
udmSubService: service.NewUDMSubUser,
neInfoService: neService.NewNeInfo,
}
// UDM签约用户
//
// PATH /udm/sub
type UDMSubController struct {
udmSubService *service.UDMSubUser // UDM签约信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDM签约用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Reload Data
// @Description UDM Subscriber User Reload Data
// @Router /ne/link/udm/sub/reset [put]
func (s *UDMSubController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmSubService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDM签约用户列表
//
// GET /list
//
// @Tags network_data/udm/sub
// @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"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User List
// @Description UDM Subscriber User List
// @Router /ne/link/udm/sub/list [get]
func (s *UDMSubController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
rows, total := s.udmSubService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UDM签约用户信息
//
// GET /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Information
// @Description UDM Subscriber User Information
// @Router /ne/link/udm/sub [get]
func (s *UDMSubController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp udmuser:imsi=%s", query.IMSI)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Subs Data"))
return
}
// 解析返回的数据
u := s.udmSubService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, query.IMSI, data)
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, u)
c.JSON(200, resp.OkData(u))
}
// UDM签约用户新增
//
// POST /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Added
// @Description UDM Subscriber User Added
// @Router /ne/link/udm/sub [post]
func (s *UDMSubController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMSubUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if len(body.IMSI) != 15 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: IMSI length is not 15 bits"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%d,", body.IMSI, body.MSISDN, num)
cmd += s.udmSubService.ParseCommandParams(body)
// 去除msisdn参数避免重复
omemsisdn := fmt.Sprintf(",msisdn=%s,", body.MSISDN)
cmd = strings.Replace(cmd, omemsisdn, ",", 1)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num, body.Remark)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add udmuser:imsi=%s,", body.IMSI)
cmd += s.udmSubService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM签约用户修改
//
// PUT /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Modification
// @Description UDM Subscriber User Modification
// @Router /ne/link/udm/sub [put]
func (s *UDMSubController) Edit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body model.UDMSubUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if len(body.IMSI) != 15 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: IMSI length is not 15 bits"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("mod udmuser:imsi=%s,", body.IMSI)
cmd += s.udmSubService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM签约用户删除
//
// DELETE /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Deletion
// @Description UDM Subscriber User Deletion
// @Router /ne/link/udm/sub [delete]
func (s *UDMSubController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 0 {
// 发送MML
cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%d", query.IMSI, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num, "-(Deleted)-")
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.IMSI, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
resultData := map[string]string{}
for _, imsi := range uniqueIDs {
// 发送MML
cmd := fmt.Sprintf("del udmuser:imsi=%s", imsi)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[imsi] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.Delete(neInfo.CoreUID, neInfo.NeUID, imsi)
}
resultData[imsi] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDM签约用户导出
//
// GET /export
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param msisdn query string false "Msisdn"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Export
// @Description UDM Subscriber User Export
// @Router /ne/link/udm/sub/export [post]
func (s *UDMSubController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "file type error, only support csv,txt"))
return
}
query := reqctx.QueryMap(c)
rows, total := s.udmSubService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"IMSI", "MSISDN", "UeAmbrTpl", "NssaiTpl", "AreaForbiddenTpl", "ServiceAreaRestrictionTpl", "RatRestrictions", "CnTypeRestrictions", "SmfSel", "SmData", "EPSDat"})
for _, v := range rows {
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
data = append(data, []string{v.IMSI, v.MSISDN, v.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
data = append(data, []string{v.IMSI, v.MSISDN, v.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDM签约用户导入
//
// POST /import
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Import
// @Description UDM Subscriber User Import
// @Router /ne/link/udm/sub/import [post]
func (s *UDMSubController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"`
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("import udmuser:path=%s", neFilePath)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmSubService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmSubService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(data))
}

View File

@@ -1,493 +0,0 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMVOIPController 结构体
var NewUDMVOIP = &UDMVOIPController{
udmVOIPService: service.NewUDMVOIPUser,
neInfoService: neService.NewNeInfo,
}
// UDMVOIP用户
//
// PATH /udm/voip
type UDMVOIPController struct {
udmVOIPService *service.UDMVOIPUser // UDMVOIP信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDMVOIP用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Data Refresh
// @Description UDM VOIP User Data List Refresh Synchronization Latest
// @Router /ne/link/udm/voip/reset [put]
func (s *UDMVOIPController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmVOIPService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDMVOIP用户列表
//
// GET /list
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param username query string false "User Name"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User List
// @Description UDM VOIP User List
// @Router /ne/link/udm/voip/list [get]
func (s *UDMVOIPController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
rows, total := s.udmVOIPService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UDMVOIP用户信息
//
// GET /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "User Name"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Information
// @Description UDM VOIP User Information
// @Router /ne/link/udm/voip [get]
func (s *UDMVOIPController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
UserName string `form:"username" binding:"required"` // 用户名
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp voip:username=%s", query.UserName)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No VOIP Data"))
return
}
// 解析返回的数据
u := s.udmVOIPService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, data)
if u.ID > 0 {
s.udmVOIPService.Insert(neInfo.CoreUID, neInfo.NeUID, u.UserName)
c.JSON(200, resp.OkData(u))
return
}
c.JSON(200, resp.ErrMsg("No VOIP Data"))
}
// UDMVOIP用户新增
//
// POST /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Added
// @Description UDM VOIP User Added
// @Router /ne/link/udm/voip [post]
func (s *UDMVOIPController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 1 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMVOIPUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.UserName == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: username is empty"))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa voip:sub_num=%d,start_username=%s,password=%s", num, body.UserName, body.Password)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.UserName, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add voip:username=%s,password=%s", body.UserName, body.Password)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.Insert(neInfo.CoreUID, neInfo.NeUID, body.UserName)
}
c.JSON(200, resp.OkData(data))
}
// UDMVOIP用户删除
//
// DELETE /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "User Name, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Deletion
// @Description UDM VOIP User Deletion
// @Router /ne/link/udm/voip [delete]
func (s *UDMVOIPController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
UserName string `form:"username" binding:"required"` // 用户名
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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 1 {
// 发送MML
cmd := fmt.Sprintf("bde voip:start_username=%s,sub_num=%d", query.UserName, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.UserName, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.UserName, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
resultData := map[string]string{}
for _, v := range uniqueIDs {
// 发送MML
cmd := fmt.Sprintf("del voip:username=%s", v)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[v] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.Delete(neInfo.CoreUID, neInfo.NeUID, v)
}
resultData[v] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDMVOIP用户导出
//
// GET /export
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param username query string false "User Name"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Export
// @Description UDM VOIP User Export
// @Router /ne/link/udm/voip/export [get]
func (s *UDMVOIPController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "file type error, only support csv,txt"))
return
}
query := reqctx.QueryMap(c)
rows, total := s.udmVOIPService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// rows := s.udmVOIPService.SelectList(model.UDMVOIPUser{NeId: neId})
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_voip_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"username", "password"})
for _, v := range rows {
data = append(data, []string{v.UserName, v.Password})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
data = append(data, []string{v.UserName, v.Password})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDMVOIP用户导入
//
// POST /import
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Import
// @Description UDM VOIP User Import
// @Router /ne/link/udm/voip/import [post]
func (s *UDMVOIPController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 发送MML
cmd := fmt.Sprintf("import voip:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmVOIPService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmVOIPService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -1,500 +0,0 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMVolteIMSController 结构体
var NewUDMVolteIMS = &UDMVolteIMSController{
udmVolteIMSService: service.NewUDMVolteIMSUser,
neInfoService: neService.NewNeInfo,
}
// UDMVolteIMS用户
//
// PATH /udm/volte-ims
type UDMVolteIMSController struct {
udmVolteIMSService *service.UDMVolteIMSUser // UDMVolteIMS信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDMVolteIMS用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Data Refresh
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
// @Router /ne/link/udm/volte-ims/reset [put]
func (s *UDMVolteIMSController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmVolteIMSService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDMVolteIMS用户列表
//
// GET /list
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User List
// @Description UDM VolteIMS User List
// @Router /ne/link/udm/volte-ims/list [get]
func (s *UDMVolteIMSController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
rows, total := s.udmVolteIMSService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UDMVolteIMS用户信息
//
// GET /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI"
// @Param msisdn query string true "MSISDN"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Information
// @Description UDM VolteIMS User Information
// @Router /ne/link/udm/volte-ims [get]
func (s *UDMVolteIMSController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi
MSISDN string `form:"msisdn" binding:"required"` // MSISDN
Volte string `form:"volte" binding:"required,oneof=0 1"` // Volte
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp imsuser:imsi=%s,msisdn=%s,volte=%s", query.IMSI, query.MSISDN, query.Volte)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
return
}
// 解析返回的数据
u := s.udmVolteIMSService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, data)
if u.ID > 0 {
s.udmVolteIMSService.InsertByIMSI(neInfo.CoreUID, neInfo.NeUID, query.IMSI)
c.JSON(200, resp.OkData(u))
return
}
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
}
// UDMVolteIMS用户新增
//
// POST /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Added
// @Description UDM VolteIMS User Added If VoIP tag=0, then MSISDN and IMSI need to be the same.
// @Router /ne/link/udm/volte-ims [post]
func (s *UDMVolteIMSController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is less than 0"))
return
}
var body model.UDMVolteIMSUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.IMSI == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: imsi is empty"))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa imsuser:sub_num=%d,start_imsi=%s,start_msisdn=%s,volte=%s,vni=%s", num, body.IMSI, body.MSISDN, body.Tag, body.VNI)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 检查同IMSI下msisdn是否存在
hasMsisdns := s.udmVolteIMSService.Find(model.UDMVolteIMSUser{IMSI: body.IMSI, MSISDN: body.MSISDN, NeUID: neInfo.NeUID})
if len(hasMsisdns) > 0 {
c.JSON(200, resp.ErrMsg("IMSI and MSISDN already exist"))
return
}
// 发送MML
cmd := fmt.Sprintf("add imsuser:imsi=%s,msisdn=%s,volte=%s,vni=%s", body.IMSI, body.MSISDN, body.Tag, body.VNI)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.InsertByIMSI(neInfo.CoreUID, neInfo.NeUID, body.IMSI)
}
c.JSON(200, resp.OkData(data))
}
// UDMVolteIMS用户删除
//
// DELETE /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param imsi query string true "IMSI"
// @Param num query number true "Number of releases, value includes start imsi"
// @Param msisdn query string false "MSISDN"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Batch Deletion
// @Description UDM VolteIMS User Batch Deletion
// @Router /ne/link/udm/volte-ims [delete]
func (s *UDMVolteIMSController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi, 带数量时为批量
MSISDN string `form:"msisdn" binding:"required"` // MSISDN, 带数量时为批量
Tag string `form:"tag" binding:"required,oneof=0 1"` // tag
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(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量更新
if query.Num > 1 {
// 发送MML
cmd := ""
if query.Tag == "0" {
cmd = fmt.Sprintf("bde imsuser:start_msisdn=%s,sub_num=%d,volte=0", query.MSISDN, query.Num)
}
if query.Tag == "1" {
cmd = fmt.Sprintf("bde imsuser:start_imsi=%s,start_msisdn=%s,sub_num=%d,volte=1", query.IMSI, query.MSISDN, query.Num)
}
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("del imsuser:imsi=%s,msisdn=%s,volte=%s", query.IMSI, query.MSISDN, query.Tag)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.Delete(neInfo.CoreUID, neInfo.NeUID, query.IMSI)
}
c.JSON(200, resp.OkData(data))
}
// UDMVolteIMS用户导出
//
// GET /export
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Export
// @Description UDM Authenticated User Export
// @Router /ne/link/udm/volte-ims/export [get]
func (s *UDMVolteIMSController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "file type error, only support csv,txt"))
return
}
query := reqctx.QueryMap(c)
rows, total := s.udmVolteIMSService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_volte_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"IMSI", "MSISDN", "TAG", "VNI"})
for _, v := range rows {
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDMVolteIMS用户导入
//
// POST /import
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Import
// @Description UDM Authenticated User Import
// @Router /ne/link/udm/volte-ims/import [post]
func (s *UDMVolteIMSController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 发送MML
cmd := fmt.Sprintf("import imsuser:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmVolteIMSService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmVolteIMSService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -1,71 +0,0 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neService "be.ems/src/modules/ne/service"
neDataService "be.ems/src/modules/ne_data/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UPFController 结构体
var NewUPF = &UPFController{
neInfoService: neService.NewNeInfo,
kpiReportService: neDataService.NewKpiReport,
}
// 网元UPF
//
// PATH /upf
type UPFController struct {
neInfoService *neService.NeInfo // 网元信息服务
kpiReportService *neDataService.KpiReport // 统计信息服务
}
// 总流量数 N3上行 N6下行
// 单位 字节(Byte)
//
// GET /kpi/flow-total
//
// @Tags network_data/upf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param day query number true "Statistical time a few days before" Enums(0, 7, 30)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Total number of flows N3 upstream N6 downstream
// @Description Total number of flows N3 upstream N6 downstream
// @Router /ne/link/upf/kpi/flow-total [get]
func (s UPFController) KPIFlowTotal(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var querys struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
Day int `form:"day"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if querys.Day < 0 || querys.Day > 30 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "day must be between 0 and 30"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(querys.CoreUID, querys.NeUID)
if neInfo.CoreUID != querys.CoreUID || neInfo.NeUID != querys.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
up, down := s.kpiReportService.UPFTodayFlowFind(neInfo.NeUID, querys.Day)
c.JSON(200, resp.OkData(map[string]int64{"up": up, "down": down}))
}

View File

@@ -1,112 +0,0 @@
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
)
type CBCEventStatus int
// CBCEventStatus CB事件状态枚举
const (
CBCEventStatusNull CBCEventStatus = iota // 未知状态
CBCEventStatusActive
CBCEventStatusInactive
)
func (status CBCEventStatus) Enum() string {
switch status {
case CBCEventStatusNull:
return "NULL"
case CBCEventStatusActive:
return "ACTIVE"
case CBCEventStatusInactive:
return "INACTIVE"
default:
return "UNKNOWN"
}
}
func (status CBCEventStatus) String() string {
return fmt.Sprintf("%d", status)
}
// ParseCBCEventStatus 将字符串转换为 枚举类型
func ParseCBCEventStatus(s string) CBCEventStatus {
if i, err := strconv.Atoi(s); err == nil {
return CBCEventStatus(i)
}
// 如果转换失败,则按名称匹配(忽略大小写)
switch strings.ToUpper(s) {
case "NULL":
return CBCEventStatusNull
case "ACTIVE":
return CBCEventStatusActive
case "INACTIVE":
return CBCEventStatusInactive
case "":
// 如果字符串为空,则返回未知状态
return CBCEventStatusNull
default:
// 默认返回未知状态
return CBCEventStatusNull
}
}
// CBCMessageQuery 查询条件结构体
type CBCMessageQuery struct {
NeType string `form:"neType"` // 网元类型
NeId string `form:"neId"` // 网元ID
EventName string `form:"eventName"` // 事件名称
Status string `form:"status"` // 消息状态
StartTime string `form:"startTime"` // 创建时间范围-起始
EndTime string `form:"endTime"` // 创建时间范围-结束
PageNum int `form:"pageNum" binding:"required"`
PageSize int `form:"pageSize" binding:"required"`
}
// @Description CBCMessage CB消息
type CBCMessage struct {
Id int64 `json:"id" gorm:"column:id"` // CB消息ID
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
NeId string `json:"neId" gorm:"column:ne_id"` // 网元ID
MessageJson json.RawMessage `json:"messageJson" gorm:"column:message_json"` // 消息内容JSON
Status CBCEventStatus `json:"status" gorm:"column:status"` // 消息状态
Detail string `json:"detail" gorm:"column:detail"` // 详情
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间
UpdatedAt int64 `json:"updatedAt" gorm:"column:updated_at"` // 更新时间
}
// TableName 表名称
func (*CBCMessage) TableName() string {
return "cbc_message"
}
// Scan 实现 sql.Scanner 接口,支持从数据库字符串转为 CBCEventStatus
func (s *CBCEventStatus) Scan(value interface{}) error {
switch v := value.(type) {
case string:
*s = ParseCBCEventStatus(v)
return nil
case []byte:
*s = ParseCBCEventStatus(string(v))
return nil
case int64:
*s = CBCEventStatus(v)
return nil
case int:
*s = CBCEventStatus(v)
return nil
default:
return errors.New("unsupported Scan type for CBCEventStatus")
}
}
// Value 实现 driver.Valuer 接口,支持将 CBCEventStatus 存为字符串
func (s CBCEventStatus) Value() (driver.Value, error) {
return s.Enum(), nil
}

View File

@@ -1,17 +0,0 @@
package model
// CDREvent CDR会话对象 cdr_event
type CDREvent struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到的timestamp秒级存储毫秒时间戳
CdrJson string `json:"cdrJSON" gorm:"column:cdr_json"` // data JSON String
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒
}
// TableName 表名称
func (*CDREvent) TableName() string {
return "cdr_event"
}

View File

@@ -1,20 +0,0 @@
package model
// UDMAuthUser UDM鉴权用户 udm_auth
type UDMAuthUser struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid" binding:"required"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type" binding:"required,oneof=UDM"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
Amf string `json:"amf" gorm:"column:amf"` // AMF
Ki string `json:"ki" gorm:"column:ki"` // ki
AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // algoIndex
Opc string `json:"opc" gorm:"column:opc"` // OPC
CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间
}
// TableName 表名称
func (*UDMAuthUser) TableName() string {
return "udm_auth"
}

View File

@@ -1,18 +0,0 @@
package model
// UDMExtend UDM用户IMSI扩展信息 udm_extend
type UDMExtend struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
Remark string `json:"remark" gorm:"column:remark"` // 备注
}
// TableName 表名称
func (*UDMExtend) TableName() string {
return "udm_extend"
}

View File

@@ -1,50 +0,0 @@
package model
// UDMSubUser UDM签约用户 udm_sub
type UDMSubUser struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid" binding:"required"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type" binding:"required,oneof=UDM"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
AmDat string `json:"amDat" gorm:"column:am_dat"` // AmData
UeAmbrTpl string `json:"ambr" gorm:"column:ambr"` // AmData SubUeAMBRTemp
NssaiTpl string `json:"nssai" gorm:"column:nssai"` // AmData SubSNSSAITemp
RatRestrictions string `json:"rat" gorm:"column:rat"` // AmData RAT 0x00:VIRTUAL 0x01:WLAN 0x02:EUTRA 0x03:NR
AreaForbiddenTpl string `json:"arfb" gorm:"column:arfb"` // AmData AreaForbidden
ServiceAreaRestrictionTpl string `json:"sar" gorm:"column:sar"` // AmData serviceAreaRestrictTemp
CnTypeRestrictions string `json:"cnType" gorm:"column:cn_type"` // AmData CNType 0x00:EPC和5GC 0x01:5GC 0x02:EPC 0x03:EPC+5GC
RfspIndex string `json:"rfspIndex" gorm:"column:rfsp_index"` // AmData RfspIndex
SubsRegTime string `json:"regTimer" gorm:"column:reg_timer"` // AmData RegTimer
UeUsageType string `json:"ueUsageType" gorm:"column:ue_usage_type"` // AmData UEUsageType
ActiveTime string `json:"activeTime" gorm:"column:active_time"` // AmData ActiveTime
MicoAllowed string `json:"mico" gorm:"column:mico"` // AmData MICO
OdbPs string `json:"odbPs" gorm:"column:odb_ps"` // AmData ODB_PS 0-all,1-hplmn,2-vplmn
GroupId string `json:"groupId" gorm:"column:group_id"` // AmData GroupId
EpsDat string `json:"epsDat" gorm:"column:eps_dat"` // EpsDat
EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"` // EpsDat epsFlag
EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` // EpsDat epsOdb
HplmnOdb string `json:"hplmnOdb" gorm:"column:hplmn_odb"` // EpsDat hplmnOdb
Ard string `json:"ard" gorm:"column:ard"` // EpsDat Ard
Epstpl string `json:"epstpl" gorm:"column:epstpl"` // EpsDat Epstpl
ContextId string `json:"contextId" gorm:"column:context_id"` // EpsDat ContextId
ApnNum string `json:"apnNum" gorm:"column:apn_mum"` // EpsDat apnNum
ApnContext string `json:"apnContext" gorm:"column:apn_context"` // EpsDat apnContext
StaticIp string `json:"staticIp" gorm:"column:static_ip"` // EpsDat staticIp 指给4G UE分配的静态IP没有可不带此字段名
SmData string `json:"smData" gorm:"column:sm_data"` // smData
SmfSel string `json:"smfSel" gorm:"column:smf_sel"` // smfSel
Cag string `json:"cag" gorm:"column:cag"` // CAG
// ====== 非数据库字段属性 ======
Remark string `json:"remark,omitempty" gorm:"-"` // 备注
}
// TableName 表名称
func (*UDMSubUser) TableName() string {
return "udm_sub"
}

View File

@@ -1,17 +0,0 @@
package model
// UDMVOIPUser UDMVOIP用户 udm_voip
type UDMVOIPUser struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid" binding:"required"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type" binding:"required,oneof=UDM"` // 网元类型
UserName string `json:"username" gorm:"column:username"` // 用户名
Password string `json:"password" gorm:"column:password"` // 密码
}
// TableName 表名称
func (*UDMVOIPUser) TableName() string {
return "udm_voip"
}

View File

@@ -1,19 +0,0 @@
package model
// UDMVolteIMSUser UDMVolteIMS用户 udm_volte_ims
type UDMVolteIMSUser struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid" binding:"required"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type" binding:"required,oneof=UDM"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
Tag string `json:"tag" gorm:"column:tag"` // 0=VoIP, 1=VoLTE
VNI string `json:"vni" gorm:"column:vni"` // VNI
}
// TableName 表名称
func (*UDMVolteIMSUser) TableName() string {
return "udm_volte_ims"
}

View File

@@ -1,18 +0,0 @@
package model
// UEEvent UE会话对象 ue_event
type UEEvent struct {
ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` // 接收到时间
EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型
EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` // data JSON String
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 记录创建存储毫秒
}
// TableName 表名称
func (*UEEvent) TableName() string {
return "ue_event"
}

View File

@@ -4,7 +4,6 @@ import (
"be.ems/src/framework/logger"
"be.ems/src/framework/middleware"
"be.ems/src/framework/middleware/collectlogs"
"be.ems/src/framework/middleware/repeat"
"be.ems/src/modules/ne_data/controller"
"be.ems/src/modules/ne_data/service"
@@ -18,7 +17,7 @@ func Setup(router *gin.Engine) {
// 启动时需要的初始参数
InitLoad()
neDataGroup := router.Group("/neData")
neDataGroup := router.Group("/ne/data")
// 性能统计信息
kpiGroup := neDataGroup.Group("/kpi")
@@ -178,425 +177,6 @@ func Setup(router *gin.Engine) {
)
}
// 网元IMS
imsGroup := neDataGroup.Group("/ims")
{
imsGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewIMS.CDRList,
)
imsGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewIMS.CDRRemove,
)
imsGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewIMS.CDRExport,
)
imsGroup.GET("/session/num",
middleware.AuthorizeUser(nil),
controller.NewIMS.UeSessionNum,
)
imsGroup.GET("/session/list",
middleware.AuthorizeUser(nil),
controller.NewIMS.UeSessionList,
)
imsGroup.GET("/kpi/busy-hour",
middleware.AuthorizeUser(nil),
controller.NewIMS.KPIBusyHour,
)
}
// 网元SMSC
smscGroup := neDataGroup.Group("/smsc")
{
smscGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSMSC.CDRList,
)
smscGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMSC.CDRRemove,
)
smscGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMSC.CDRExport,
)
}
// 网元SMF
smfGroup := neDataGroup.Group("/smf")
{
smfGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSMF.CDRList,
)
smfGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMF.CDRRemove,
)
smfGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMF.CDRExport,
)
smfGroup.GET("/sub/num",
middleware.AuthorizeUser(nil),
controller.NewSMF.SubUserNum,
)
smfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
controller.NewSMF.SubUserList,
)
}
// 网元AMF
amfGroup := neDataGroup.Group("/amf")
{
amfGroup.GET("/ue/list",
middleware.AuthorizeUser(nil),
controller.NewAMF.UEList,
)
amfGroup.DELETE("/ue/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewAMF.UERemove,
)
amfGroup.GET("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewAMF.UEExport,
)
amfGroup.GET("/nb/list",
middleware.AuthorizeUser(nil),
controller.NewAMF.NbInfoList,
)
amfGroup.GET("/nb/addrs",
middleware.AuthorizeUser(nil),
controller.NewAMF.NbStateList,
)
}
// 网元UPF
upfGroup := neDataGroup.Group("/upf")
{
upfGroup.GET("/kpi/flow-total",
middleware.AuthorizeUser(nil),
controller.NewUPF.KPIFlowTotal,
)
}
// 网元N3IWF
n3iwfGroup := neDataGroup.Group("/n3iwf")
{
n3iwfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
controller.NewN3IWF.SubUserList,
)
}
// 网元N3IWF
nssf := controller.NewNSSF
nssfGroup := neDataGroup.Group("/nssf")
{
nssfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
nssf.SubUserList,
)
nssfGroup.GET("/amf/list",
middleware.AuthorizeUser(nil),
nssf.AvailableList,
)
}
// 网元UDM 鉴权用户信息
udmAuthGroup := neDataGroup.Group("/udm/auth")
{
udmAuthGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMAuth.ResetData,
)
udmAuthGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMAuth.List,
)
udmAuthGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMAuth.Info,
)
udmAuthGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Add,
)
udmAuthGroup.PUT("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMAuth.Edit,
)
udmAuthGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Remove,
)
udmAuthGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMAuth.Export,
)
udmAuthGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMAuth.Import,
)
}
// 网元UDM 签约用户信息
udmSubGroup := neDataGroup.Group("/udm/sub")
{
udmSubGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMSub.ResetData,
)
udmSubGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMSub.List,
)
udmSubGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMSub.Info,
)
udmSubGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Add,
)
udmSubGroup.PUT("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMSub.Edit,
)
udmSubGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Remove,
)
udmSubGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMSub.Export,
)
udmSubGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMSub.Import,
)
}
// 网元UDM VOIP用户信息
udmVOIPGroup := neDataGroup.Group("/udm/voip")
{
udmVOIPGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMVOIP.ResetData,
)
udmVOIPGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMVOIP.List,
)
udmVOIPGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMVOIP.Info,
)
udmVOIPGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMVOIP.Add,
)
udmVOIPGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMVOIP.Remove,
)
udmVOIPGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMVOIP.Export,
)
udmVOIPGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMVOIP.Import,
)
}
// 网元UDM VolteIMS用户信息
udmVolteIMSGroup := neDataGroup.Group("/udm/volte-ims")
{
udmVolteIMSGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMVolteIMS.ResetData,
)
udmVolteIMSGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMVolteIMS.List,
)
udmVolteIMSGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMVolteIMS.Info,
)
udmVolteIMSGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMVolteIMS.Add,
)
udmVolteIMSGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMVolteIMS.Remove,
)
udmVolteIMSGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMVolteIMS.Export,
)
udmVolteIMSGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMVolteIMS.Import,
)
}
// 网元MME
mmeGroup := neDataGroup.Group("/mme")
{
mmeGroup.GET("/ue/list",
middleware.AuthorizeUser(nil),
controller.NewMME.UEList,
)
mmeGroup.DELETE("/ue/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewMME.UERemove,
)
mmeGroup.GET("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewMME.UEExport,
)
mmeGroup.GET("/nb/list",
middleware.AuthorizeUser(nil),
controller.NewMME.NbInfoList,
)
mmeGroup.GET("/nb/addrs",
middleware.AuthorizeUser(nil),
controller.NewMME.NbStateList,
)
}
// 网元SGWC
sgwcGroup := neDataGroup.Group("/sgwc")
{
sgwcGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSGWC.CDRList,
)
sgwcGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSGWC.CDRRemove,
)
sgwcGroup.POST("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
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,
)
}
// 网元CBC
cbcGroup := neDataGroup.Group("/cbc")
{
cbcGroup.GET("/message/list",
middleware.AuthorizeUser(nil),
controller.NewCBC.List,
)
cbcGroup.GET("/message/:id",
middleware.AuthorizeUser(nil),
controller.NewCBC.ListById,
)
cbcGroup.POST("/message",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewCBC.Insert,
)
cbcGroup.PUT("/message/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewCBC.Update,
)
cbcGroup.PUT("/message/:id/:status",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewCBC.UpdateStatus,
)
cbcGroup.DELETE("/message/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewCBC.Delete,
)
cbcGroup.GET("/message/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.cbcMessage", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewCBC.Export,
)
}
}
// InitLoad 初始参数

View File

@@ -1,273 +0,0 @@
package repository
import (
"encoding/json"
"fmt"
"time"
"be.ems/src/framework/database/db"
"be.ems/src/modules/ne_data/model"
"gorm.io/gorm"
)
// 实例化数据层 UEEvent 结构体
var NewCBCMessage = &CBCMessage{}
// UEEvent UE会话事件 数据层处理
type CBCMessage struct{}
// SelectCBCMessage 根据条件分页查询CB消息
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
var msg []model.CBCMessage
var total int64
tx := db.DB("").Table("cbc_message")
if query.NeType != "" {
tx = tx.Where("ne_type = ?", query.NeType)
}
if query.NeId != "" {
tx = tx.Where("ne_id = ?", query.NeId)
}
if query.EventName != "" {
tx = tx.Where("JSON_EXTRACT(message_json, '$.eventName') = ?", query.EventName)
}
if query.Status != "" {
tx = tx.Where("status = ?", query.Status)
}
var startMicro, endMicro int64
var err error
if query.StartTime != "" {
startMicro, err = parseTimeToMilli(query.StartTime)
if err != nil {
return nil, 0, fmt.Errorf("invalid start time: %w", err)
}
}
if query.EndTime != "" {
endMicro, err = parseTimeToMilli(query.EndTime)
if err != nil {
return nil, 0, fmt.Errorf("invalid end time: %w", err)
}
}
if startMicro > 0 && endMicro > 0 {
tx = tx.Where("created_at BETWEEN ? AND ?", startMicro, endMicro)
} else if startMicro > 0 {
tx = tx.Where("created_at >= ?", startMicro)
} else if endMicro > 0 {
tx = tx.Where("created_at <= ?", endMicro)
}
// 统计总数
if err := tx.Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
}
// 分页查询
offset := (query.PageNum - 1) * query.PageSize
if err := tx.Limit(query.PageSize).Offset(offset).Order("created_at desc").Find(&msg).Error; err != nil {
return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
}
return msg, int(total), nil
}
// SelectCBCMessageByPage 分页查询CB消息
// @Description 分页查询CB消息
// @param page 页码
// @param pageSize 每页大小
// @return []model.CBCMessage CB消息列表
// @return int 总记录数
// @return error 错误信息
// @example
// SelectByPage(1, 10)
// func (s *CBCMessage) SelectByPage(pageNum int, pageSize int) ([]model.CBCMessage, int, error) {
// var tickets []model.CBCMessage
// var total int64
// // 统计总数
// if err := db.DB("").Table("cbc_message").Count(&total).Error; err != nil {
// return nil, 0, fmt.Errorf("failed to count CBC message: %w", err)
// }
// // 分页查询
// offset := (pageNum - 1) * pageSize
// if err := db.DB("").Table("cbc_message").
// Limit(pageSize).
// Offset(offset).
// Find(&tickets).Error; err != nil {
// return nil, 0, fmt.Errorf("failed to select CBC message: %w", err)
// }
// return tickets, int(total), nil
// }
// InsertCBCMessage 插入CB消息
// @Description 插入CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// CBCMessage.InsertCBCMessage(msg)
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
msg.CreatedAt = time.Now().UnixMilli()
// 这里可以使用ORM或其他方式将ticket插入到数据库中
if err := db.DB("").Table("cbc_message").Create(&msg).Error; err != nil {
return fmt.Errorf("failed to insert CBC message: %w", err)
}
return nil
}
// SelectCBCMessageById 根据工单ID查询CB消息
// @Description 根据工单ID查询CB消息
// @param id 工单ID
// @return *model.CBCMessage CB消息对象
// @return error 错误信息
// @example
// CBCMessage.SelectCBCMessageById(12345)
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
var msg model.CBCMessage
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
First(&msg).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, fmt.Errorf("failed to select CBC message: %w", err)
}
return &msg, nil
}
// SelectByEventName 根据事件名称查询CB消息
func (s *CBCMessage) SelectByEventName(eventName string) (*model.CBCMessage, error) {
var msg model.CBCMessage
if err := db.DB("").Table("cbc_message").
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
First(&msg).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return &msg, nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// mfCBCMessageService.UpdateCBCMessage(msg)
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) (*model.CBCMessage, error) {
var msg model.CBCMessage
now := time.Now().UnixMilli()
err := db.DB("").Transaction(func(tx *gorm.DB) error {
// 在事务中更新
if err := tx.Table("cbc_message").
Where("id = ?", id).
Updates(map[string]any{
"message_json": messageJson,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
// 在事务中查询更新后的记录
if err := tx.Table("cbc_message").
Where("id = ?", id).
First(&msg).Error; err != nil {
return fmt.Errorf("failed to fetch updated CBC message: %w", err)
}
return nil
})
if err != nil {
return nil, err
}
return &msg, nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// UpdateCBCMessageDetail(msg)
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
now := time.Now().UnixMilli()
if err := db.DB("").Table("cbc_message").
Where("JSON_EXTRACT(message_json, '$.eventName') = ?", eventName).
Updates(map[string]any{
"detail": detail,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
return nil
}
// DeleteCBCMessage 删除CB消息
// @Description 删除CB消息
// @param id 工单ID
// @return error 错误信息
// @example
// DeleteCBCMessage(12345)
func (s *CBCMessage) Delete(id int64) error {
// 执行删除操作
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
Delete(&model.CBCMessage{}).Error; err != nil {
return fmt.Errorf("failed to delete CBC message: %w", err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatus(id int64, status model.CBCEventStatus) error {
// 更新数据库状态
now := time.Now().UnixMilli()
if err := db.DB("").Table("cbc_message").
Where("id = ?", id).
Updates(map[string]interface{}{
"status": status,
"updated_at": now,
}).Error; err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
return nil
}
// Select 查询所有CB消息
func (s *CBCMessage) Select(msgs *[]model.CBCMessage) error {
if err := db.DB("").Table("cbc_message").Find(&msgs).Error; err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
return nil
}
// SelectByNeId 根据网元ID查询CB消息
func (s *CBCMessage) SelectByNeId(neId string, msgs *[]model.CBCMessage) error {
if err := db.DB("").Table("cbc_message").Where("ne_id = ?", neId).Find(&msgs).Error; err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
return nil
}
// 假设 query.StartTime 和 query.EndTime 是 "2006-01-02 15:04:05" 格式字符串
func parseTimeToMilli(ts string) (int64, error) {
if ts == "" {
return 0, nil
}
t, err := time.ParseInLocation("2006-01-02 15:04:05", ts, time.Local)
if err != nil {
return 0, err
}
return t.UnixMilli(), nil
}

View File

@@ -1,209 +0,0 @@
package repository
import (
"fmt"
"sort"
"strings"
"time"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 CDREvent 结构体
var NewCDREvent = &CDREvent{}
// CDREvent CDR会话事件 数据层处理
type CDREvent struct{}
// SelectByPage 分页查询集合
func (r CDREvent) SelectByPage(neType string, query map[string]string) ([]model.CDREvent, int64) {
// 表名
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Model(&model.CDREvent{})
// 查询条件拼接
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["beginTime"]; ok && v != "" {
if len(v) == 10 {
v = v + "000"
}
tx = tx.Where("created_at >= ?", v)
}
if v, ok := query["endTime"]; ok && v != "" {
if len(v) == 10 {
v = v + "000"
}
tx = tx.Where("created_at <= ?", v)
}
// 各个网元特殊查询条件
switch neType {
case "SMSC":
if v, ok := query["callerParty"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["calledParty"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["recordType"]; ok && v != "" {
recordTypes := strings.Split(v, ",")
var querytrArr []string
for _, recordType := range recordTypes {
querytrArr = append(querytrArr, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') = '%s'", recordType))
}
tx = tx.Where(fmt.Sprintf("( %s )", strings.Join(querytrArr, " OR ")))
}
case "SMF":
if v, ok := query["recordType"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.recordType') = ?", v)
}
if v, ok := query["subscriberID"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["dnn"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.dNNID') = ?", v)
}
case "SGWC":
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedIMSI') like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["msisdn"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.servedMSISDN') like ?", fmt.Sprintf("%%%s%%", v))
}
case "IMS":
if v, ok := query["callerParty"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.callerParty') like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["calledParty"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(cdr_json, '$.calledParty') like ?", fmt.Sprintf("%%%s%%", v))
}
}
var total int64 = 0
rows := []model.CDREvent{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
if pageNum == 0 && pageSize > int(total) {
pageSize = int(total)
}
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortField := v
sortOrder := "asc"
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortOrder = "desc"
} else {
sortOrder = "asc"
}
}
sort.SliceStable(rows, func(i, j int) bool {
// 支持的排序字段映射
fieldGetters := map[string]func(*model.CDREvent) any{
"id": func(row *model.CDREvent) any { return row.ID },
"timestamp": func(row *model.CDREvent) any { return row.Timestamp },
// 可添加更多支持的字段
}
// 获取字段 getter 函数
getter, ok := fieldGetters[sortField]
if !ok {
// 非法字段使用默认排序id升序
return rows[i].ID < rows[j].ID
}
// 获取比较值
valI, valJ := getter(&rows[i]), getter(&rows[j])
// 根据字段类型进行比较
switch v := valI.(type) {
case int64:
if sortOrder == "desc" {
return v > valJ.(int64)
}
return v < valJ.(int64)
case string:
if sortOrder == "desc" {
return v > valJ.(string)
}
return v < valJ.(string)
default:
// 不支持的字段类型,使用默认排序
return rows[i].ID < rows[j].ID
}
})
}
return rows, total
}
// SelectByIds 通过ID查询
func (r CDREvent) SelectByIds(neType string, ids []int64) []model.CDREvent {
rows := []model.CDREvent{}
if len(ids) <= 0 {
return rows
}
// 表名
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Model(&model.CDREvent{})
// 构建查询条件
tx = tx.Where("id in ?", ids)
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
return rows
}
return rows
}
// DeleteByIds 批量删除信息
func (r CDREvent) DeleteByIds(neType string, ids []int64) int64 {
if len(ids) <= 0 {
return 0
}
// 表名
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Where("id in ?", ids)
if err := tx.Delete(&model.CDREvent{}).Error; err != nil {
logger.Errorf("delete err => %v", err.Error())
return 0
}
return tx.RowsAffected
}
// Insert 新增信息 返回新增数据ID
func (r CDREvent) Insert(param model.CDREvent) int64 {
if param.NeType == "" {
return 0
}
if param.CreatedAt == 0 {
param.CreatedAt = time.Now().UnixMilli()
}
// 表名
tableName := fmt.Sprintf("cdr_event_%s", strings.ToLower(param.NeType))
// 执行插入
if err := db.DB("").Table(tableName).Create(&param).Error; err != nil {
logger.Errorf("insert err => %v", err.Error())
return 0
}
return param.ID
}

View File

@@ -1,149 +0,0 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UDMAuthUser 结构体
var NewUDMAuthUser = &UDMAuthUser{}
// UDMAuthUser UDM鉴权信息表 数据层处理
type UDMAuthUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMAuthUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMAuthUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_auth", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", coreUid, neUid).Unscoped().Delete(&model.UDMAuthUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r *UDMAuthUser) SelectPage(query map[string]string) ([]model.UDMAuthUser, int64) {
tx := db.DB("").Model(&model.UDMAuthUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMAuthUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return rows, total
}
// SelectList 根据实体查询
func (r *UDMAuthUser) SelectList(u model.UDMAuthUser) []model.UDMAuthUser {
tx := db.DB("").Model(&model.UDMAuthUser{})
// 查询条件拼接
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMAuthUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSI 通过imsi查询
func (r *UDMAuthUser) SelectByIMSI(coreUid, neUid, imsi string) model.UDMAuthUser {
tx := db.DB("").Model(&model.UDMAuthUser{})
item := model.UDMAuthUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r *UDMAuthUser) Inserts(uArr []model.UDMAuthUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体
func (r *UDMAuthUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMAuthUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMAuthUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMAuthUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -1,130 +0,0 @@
package repository
import (
"fmt"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UDMExtend 结构体
var NewUDMExtend = &UDMExtend{}
// UDMExtend UDM鉴权信息表 数据层处理
type UDMExtend struct{}
// SelectByPage 分页查询集合
func (r UDMExtend) SelectByPage(query map[string]string) ([]model.UDMExtend, int64) {
tx := db.DB("").Model(&model.UDMExtend{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
// 查询结果
var total int64 = 0
rows := []model.UDMExtend{}
// 查询数量为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortField := v
if o, ok := query["sortOrder"]; ok && o != "" {
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
}
// SelectList 根据实体查询
func (r *UDMExtend) SelectList(u model.UDMExtend) []model.UDMExtend {
tx := db.DB("").Model(&model.UDMExtend{})
// 构建查询条件
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
tx = tx.Order("imsi asc")
// 查询数据
rows := []model.UDMExtend{}
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
return rows
}
return rows
}
// SelectByIMSI 通过imsi查询 neUid为%时模糊imsi查询
func (r *UDMExtend) SelectByIMSI(coreUid, neUid, imsi string) model.UDMExtend {
tx := db.DB("").Model(&model.UDMExtend{})
// 查询条件拼接
if neUid == "%" {
tx = tx.Where("core_uid = ?", coreUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsi))
} else {
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
}
// 查询数据
rows := []model.UDMExtend{}
if err := tx.Limit(1).Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
}
if len(rows) > 0 {
return rows[0]
}
return model.UDMExtend{}
}
// Insert 批量添加
func (r *UDMExtend) Inserts(uArr []model.UDMExtend) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体 neUid为%时模糊imsi前缀
func (r *UDMExtend) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
// 查询条件拼接
if neUid == "%" {
tx = tx.Where("core_uid = ?", coreUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsi))
} else {
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
}
tx = tx.Delete(&model.UDMExtend{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -1,151 +0,0 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UDMSubUser 结构体
var NewUDMSub = &UDMSubUser{}
// UDMSubUser UDM签约信息表 数据层处理
type UDMSubUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMSubUser) ClearAndInsert(coreUid, neUid string, u []model.UDMSubUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_sub", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", neUid).Unscoped().Delete(&model.UDMSubUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(u)
}
// SelectPage 根据条件分页查询字典类型
func (r *UDMSubUser) SelectPage(query map[string]string) ([]model.UDMSubUser, int64) {
tx := db.DB("").Model(&model.UDMSubUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["msisdn"]; ok && v != "" {
tx = tx.Where("msisdn like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMSubUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return rows, total
}
// SelectList 根据实体查询
func (r *UDMSubUser) SelectList(u model.UDMSubUser) []model.UDMSubUser {
tx := db.DB("").Model(&model.UDMSubUser{})
// 查询条件拼接
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMSubUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSIAndNeID 通过imsi查询
func (r *UDMSubUser) SelectByIMSI(coreUid, neUid, imsi string) model.UDMSubUser {
tx := db.DB("").Model(&model.UDMSubUser{})
item := model.UDMSubUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r *UDMSubUser) Inserts(uArr []model.UDMSubUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// DeleteByIMSI 删除实体
func (r *UDMSubUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMSubUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMSubUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMSubUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -1,151 +0,0 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UDMVOIPUser 结构体
var NewUDMVOIPUser = &UDMVOIPUser{}
// UDMVOIPUser UDMVOIP用户信息表 数据层处理
type UDMVOIPUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r UDMVOIPUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMVOIPUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_voip", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", coreUid, neUid).Unscoped().Delete(&model.UDMVOIPUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r UDMVOIPUser) SelectPage(query map[string]string) ([]model.UDMVOIPUser, int64) {
tx := db.DB("").Model(&model.UDMVOIPUser{})
// 查询条件拼接
if v, ok := query["username"]; ok && v != "" {
tx = tx.Where("username like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["usernames"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("username in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMVOIPUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
} else {
tx = tx.Order("username asc")
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return rows, total
}
// SelectList 根据实体查询
func (r UDMVOIPUser) SelectList(u model.UDMVOIPUser) []model.UDMVOIPUser {
tx := db.DB("").Model(&model.UDMVOIPUser{})
// 查询条件拼接
if u.UserName != "" {
tx = tx.Where("username = ?", u.UserName)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMVOIPUser{}
if err := tx.Order("username asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByUserName 通过username查询
func (r UDMVOIPUser) SelectByUserName(coreUid, neUid, username string) model.UDMVOIPUser {
tx := db.DB("").Model(&model.UDMVOIPUser{})
item := model.UDMVOIPUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username = ?", username)
// 查询数据
if err := tx.Order("username asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r UDMVOIPUser) Inserts(uArr []model.UDMVOIPUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// DeleteByUserName 删除实体
func (r UDMVOIPUser) DeleteByUserName(coreUid, neUid, username string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username = ?", username)
tx.Delete(&model.UDMVOIPUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByUserName 删除前缀匹配的实体
func (r UDMVOIPUser) DeletePrefixByUserName(coreUid, neUid, usernamePrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username like ?", fmt.Sprintf("%s%%", usernamePrefix))
tx.Delete(&model.UDMVOIPUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByUserName err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -1,163 +0,0 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UDMVolteIMSUser 结构体
var NewUDMVolteIMSUser = &UDMVolteIMSUser{}
// UDMVolteIMSUser UDMVOIP用户信息表 数据层处理
type UDMVolteIMSUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r UDMVolteIMSUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMVolteIMSUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_volte_ims", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", coreUid, neUid).Unscoped().Delete(&model.UDMVolteIMSUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r UDMVolteIMSUser) SelectPage(query map[string]string) ([]model.UDMVolteIMSUser, int64) {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["msisdn"]; ok && v != "" {
tx = tx.Where("msisdn like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["tag"]; ok && v != "" {
tx = tx.Where("tag = ?", v)
}
if v, ok := query["vni"]; ok && v != "" {
tx = tx.Where("vni like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMVolteIMSUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
} else {
tx = tx.Order("imsi asc")
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return rows, total
}
// SelectList 根据实体查询
func (r UDMVolteIMSUser) SelectList(u model.UDMVolteIMSUser) []model.UDMVolteIMSUser {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
// 查询条件拼接
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.Tag != "" {
tx = tx.Where("tag = ?", u.Tag)
}
// 查询数据
arr := []model.UDMVolteIMSUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSIAndMSISDN 通过imsi,msisdn查询
func (r UDMVolteIMSUser) SelectByIMSIAndMSISDN(coreUid, neUid, imsi, msisdn string) model.UDMVolteIMSUser {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
item := model.UDMVolteIMSUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ? and msisdn = ?", imsi, msisdn)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r UDMVolteIMSUser) Inserts(uArr []model.UDMVolteIMSUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体
func (r UDMVolteIMSUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMVolteIMSUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r UDMVolteIMSUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMVolteIMSUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -1,171 +0,0 @@
package repository
import (
"fmt"
"sort"
"strings"
"time"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/ne_data/model"
)
// 实例化数据层 UEEvent 结构体
var NewUEEvent = &UEEvent{}
// UEEvent UE会话事件 数据层处理
type UEEvent struct{}
// SelectByPage 分页查询集合
func (r UEEvent) SelectByPage(neType string, query map[string]string) ([]model.UEEvent, int64) {
// 表名
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Model(&model.CDREvent{})
// 查询条件拼接
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["beginTime"]; ok && v != "" {
if len(v) == 10 {
v = v + "000"
}
tx = tx.Where("created_at >= ?", v)
}
if v, ok := query["endTime"]; ok && v != "" {
if len(v) == 10 {
v = v + "000"
}
tx = tx.Where("created_at <= ?", v)
}
if v, ok := query["eventType"]; ok && v != "" {
eventTypes := strings.Split(v, ",")
tx = tx.Where("event_type in ?", eventTypes)
}
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("JSON_EXTRACT(event_json, '$.imsi') like ?", fmt.Sprintf("%%%s%%", v))
}
// 查询结果
var total int64 = 0
rows := []model.UEEvent{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortField := v
sortOrder := "asc"
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortOrder = "desc"
} else {
sortOrder = "asc"
}
}
sort.SliceStable(rows, func(i, j int) bool {
// 支持的排序字段映射
fieldGetters := map[string]func(*model.UEEvent) any{
"id": func(row *model.UEEvent) any { return row.ID },
"timestamp": func(row *model.UEEvent) any { return row.CreatedAt },
"createdAt": func(row *model.UEEvent) any { return row.CreatedAt },
// 可添加更多支持的字段
}
// 获取字段 getter 函数
getter, ok := fieldGetters[sortField]
if !ok {
// 非法字段使用默认排序id升序
return rows[i].ID < rows[j].ID
}
// 获取比较值
valI, valJ := getter(&rows[i]), getter(&rows[j])
// 根据字段类型进行比较
switch v := valI.(type) {
case int64:
if sortOrder == "desc" {
return v > valJ.(int64)
}
return v < valJ.(int64)
case string:
if sortOrder == "desc" {
return v > valJ.(string)
}
return v < valJ.(string)
default:
// 不支持的字段类型,使用默认排序
return rows[i].ID < rows[j].ID
}
})
}
return rows, total
}
// SelectByIds 通过ID查询
func (r UEEvent) SelectByIds(neType string, ids []int64) []model.UEEvent {
rows := []model.UEEvent{}
if len(ids) <= 0 {
return rows
}
// 表名
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Model(&model.UEEvent{})
// 构建查询条件
tx = tx.Where("id in ?", ids)
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
return rows
}
return rows
}
// DeleteByIds 批量删除信息
func (r UEEvent) DeleteByIds(neType string, ids []int64) int64 {
if len(ids) <= 0 {
return 0
}
// 表名
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
tx := db.DB("").Table(tableName).Where("id in ?", ids)
if err := tx.Delete(&model.UEEvent{}).Error; err != nil {
logger.Errorf("delete err => %v", err.Error())
return 0
}
return tx.RowsAffected
}
// Insert 新增信息 返回新增数据ID
func (r UEEvent) Insert(param model.UEEvent) int64 {
if param.NeType == "" {
return 0
}
if param.CreatedAt == 0 {
param.CreatedAt = time.Now().UnixMilli()
}
// 表名
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(param.NeType))
// 执行插入
if err := db.DB("").Table(tableName).Create(&param).Error; err != nil {
logger.Errorf("insert err => %v", err.Error())
return 0
}
return param.ID
}

View File

@@ -1,453 +0,0 @@
package service
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/file"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
"gorm.io/gorm"
)
// 实例化数据层 CBCMessage 结构体
var NewCBCMessage = &CBCMessage{
cbcMessageRepository: repository.NewCBCMessage,
}
// CBCMessage CB消息 服务层处理
type CBCMessage struct {
cbcMessageRepository *repository.CBCMessage // UE会话事件数据信息
}
// SelectByPage 根据条件分页查询CB消息
func (s *CBCMessage) SelectByPage(query model.CBCMessageQuery) ([]model.CBCMessage, int, error) {
return s.cbcMessageRepository.SelectByPage(query)
}
// SelectCBCMessageById 根据工单ID查询CB消息
// @Description 根据工单ID查询CB消息
// @param id 工单ID
// @return *model.CBCMessage CB消息对象
// @return error 错误信息
// @example
// CBCMessage.SelectCBCMessageById(12345)
func (s *CBCMessage) SelectById(id int64) (*model.CBCMessage, error) {
return s.cbcMessageRepository.SelectById(id)
}
func (s *CBCMessage) Insert(msg model.CBCMessage) error {
// 解析messageJson获取eventName
var messageData map[string]interface{}
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
// 提取eventName
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName is required in message_json")
}
// 检查是否已存在相同的eventName
var err error
var existingMsg *model.CBCMessage
if existingMsg, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
return fmt.Errorf("failed to check existing CBC message: %w", err)
}
if existingMsg != nil {
return fmt.Errorf("CBC message with eventName '%s' already exists for neType '%s' and neId '%s'",
eventName, existingMsg.NeType, existingMsg.NeId)
}
return s.cbcMessageRepository.Insert(msg)
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// mfCBCMessageService.UpdateCBCMessage(msg)
func (s *CBCMessage) Update(id int64, messageJson json.RawMessage) error {
// 解析messageJson获取eventName
var messageData map[string]interface{}
if err := json.Unmarshal(messageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
// 提取eventName
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName is required in message_json")
}
// 检查是否已存在相同的eventName
var err error
if _, err = s.cbcMessageRepository.SelectByEventName(eventName); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("no existing CBC message found with eventName: %s", eventName)
}
return fmt.Errorf("failed to query existing CBC message: %w", err)
}
// 如果存在,更新记录
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.Update(id, messageJson); err != nil {
return fmt.Errorf("failed to update CBC message: %w", err)
}
// 如果状态是ACTIVE发送更新请求
if msg.Status == model.CBCEventStatusActive {
if err := s.sendUpdateRequest(*msg); err != nil {
return fmt.Errorf("failed to send update request: %w", err)
}
}
return nil
}
// UpdateCBCMessage 更新CB消息
// @Description 更新CB消息
// @param msg CB消息对象
// @return error 错误信息
// @example
// UpdateCBCMessageDetail(msg)
func (s *CBCMessage) UpdateDetail(eventName, detail string) error {
if err := s.cbcMessageRepository.UpdateDetail(eventName, detail); err != nil {
return fmt.Errorf("failed to update CBC message detail: %w", err)
}
return nil
}
// DeleteCBCMessage 删除CB消息
// @Description 删除CB消息
// @param id 工单ID
// @return error 错误信息
// @example
// mfCBCMessageService.DeleteCBCMessage(12345)
func (s *CBCMessage) Delete(id int64) error {
// 先查询记录状态
var err error
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("CBC message with ID %d not found", id)
}
return fmt.Errorf("failed to query CBC message: %w", err)
}
// 检查状态是否为ACTIVE
if msg.Status == model.CBCEventStatusActive {
return fmt.Errorf("cannot delete an active CBC message (ID: %d)", id)
}
// 执行删除操作
if err := s.cbcMessageRepository.Delete(id); err != nil {
return fmt.Errorf("failed to delete CBC message: %w", err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatus(id int64, status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
var err error
var msg *model.CBCMessage
if msg, err = s.cbcMessageRepository.SelectById(id); err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("CBC message with ID %d not found", id)
}
return fmt.Errorf("failed to query CBC message: %w", err)
}
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
return fmt.Errorf("CBC message status is already %s", newStatus.Enum())
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(*msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateStatusByNeId(neId string, status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
msgs := make([]model.CBCMessage, 0)
if err := s.cbcMessageRepository.SelectByNeId(neId, &msgs); err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
for _, msg := range msgs {
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
continue // 状态没有变化,跳过
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
}
return nil
}
// UpdateCBCMessageStatus 更新CB消息状态
// @Description 更新CB消息状态并根据状态变化发送相应的HTTP请求
// @param status 新状态
// @return error 错误信息
func (s *CBCMessage) UpdateAllStatus(status string) error {
newStatus := model.ParseCBCEventStatus(status)
// 查询所有需要更新的记录
msgs := make([]model.CBCMessage, 0)
if err := s.cbcMessageRepository.Select(&msgs); err != nil {
return fmt.Errorf("failed to query CB messages: %w", err)
}
for _, msg := range msgs {
oldStatus := msg.Status
// 检查状态是否发生变化
if oldStatus == newStatus {
continue // 状态没有变化,跳过
}
// 更新数据库状态
if err := s.cbcMessageRepository.UpdateStatus(msg.Id, newStatus); err != nil {
return fmt.Errorf("failed to update CBC message status: %w", err)
}
// 根据状态变化发送HTTP请求
if err := s.handleStatusChange(msg, oldStatus, newStatus); err != nil {
// 记录错误但不中断处理其他消息
fmt.Printf("Failed to handle status change for message %d: %v\n", msg.Id, err)
}
}
return nil
}
// ExportXlsx 导出数据到 xlsx 文件
func (r CBCMessage) ExportXlsx(rows []model.CBCMessage, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": i18n.TKey(language, "alarm.export.alarmType"),
"B1": i18n.TKey(language, "alarm.export.origSeverity"),
"C1": i18n.TKey(language, "alarm.export.alarmTitle"),
"D1": i18n.TKey(language, "alarm.export.eventTime"),
"E1": i18n.TKey(language, "alarm.export.alarmId"),
"F1": i18n.TKey(language, "alarm.export.alarmCode"),
"G1": i18n.TKey(language, "ne.common.neType"),
"H1": i18n.TKey(language, "ne.common.neName"),
"I1": i18n.TKey(language, "ne.common.neId"),
}
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
cells := map[string]any{
"A" + idx: row.NeType,
"B" + idx: row.NeId,
"C" + idx: row.MessageJson, // 这里假设 MessageJson 已经是字符串格式
"D" + idx: row.Status.Enum(),
"E" + idx: row.Detail,
"F" + idx: time.UnixMilli(row.CreatedAt).Format(time.RFC3339),
"G" + idx: time.UnixMilli(row.UpdatedAt).Format(time.RFC3339),
}
dataCells = append(dataCells, cells)
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// handleStatusChange 处理状态变化时的HTTP请求
func (s *CBCMessage) handleStatusChange(msg model.CBCMessage, oldStatus, newStatus model.CBCEventStatus) error {
// 从NULL/INACTIVE状态修改为ACTIVE
if (oldStatus == model.CBCEventStatusNull || oldStatus == model.CBCEventStatusInactive) &&
newStatus == model.CBCEventStatusActive {
return s.sendActivateRequest(msg)
}
// 从ACTIVE更改为INACTIVE状态
if oldStatus == model.CBCEventStatusActive && newStatus == model.CBCEventStatusInactive {
return s.sendDeactivateRequest(msg)
}
return nil
}
// getCBCNetworkElement 获取CBC网元的IP和端口信息
// 这个方法需要根据你的实际网元管理系统来实现
func (s *CBCMessage) getCBCNetworkElement(neId string) (string, int64, error) {
// 查询网元信息
neInfo := neService.NewNeInfo.FindByCoreUidAndNeUid("CBC", neId)
if neInfo.IPAddr == "" {
return "", 0, fmt.Errorf("CBC network element not found for neId: %s", neId)
}
return neInfo.IPAddr, neInfo.Port, nil
}
// CBCHTTPClient CBC网元HTTP客户端
type CBCHTTPClient struct {
client *http.Client
baseURL string
}
// NewCBCHTTPClient 创建CBC HTTP客户端
func NewCBCHTTPClient(baseURL string) *CBCHTTPClient {
return &CBCHTTPClient{
client: &http.Client{
Timeout: 10 * time.Second,
},
baseURL: baseURL,
}
}
// PostMessage 发送POST请求创建消息
func (c *CBCHTTPClient) PostMessage(messageData []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
return c.sendRequest("POST", url, messageData)
}
// PutMessage 发送PUT请求更新消息
func (c *CBCHTTPClient) PutMessage(messageData []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
return c.sendRequest("PUT", url, messageData)
}
// DeleteMessage 发送DELETE请求删除消息
func (c *CBCHTTPClient) DeleteMessage(eventName string, deletePayload []byte) error {
url := fmt.Sprintf("%s/api/v1/cbe/message/%s", c.baseURL, eventName)
return c.sendRequest("DELETE", url, deletePayload)
}
// sendRequest 发送HTTP请求
func (c *CBCHTTPClient) sendRequest(method, url string, body []byte) error {
req, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("failed to create %s request: %w", method, err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("failed to send %s request: %w", method, err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("%s request failed with status: %d, body: %s",
method, resp.StatusCode, string(body))
}
return nil
}
// 在CBCMessageService中添加方法
func (s *CBCMessage) getCBCHTTPClient(neId string) (*CBCHTTPClient, error) {
cbcIP, cbcPort, err := s.getCBCNetworkElement(neId)
if err != nil {
return nil, fmt.Errorf("failed to get CBC network element info: %w", err)
}
baseURL := fmt.Sprintf("http://%s:%d", cbcIP, cbcPort)
return NewCBCHTTPClient(baseURL), nil
}
// 重构后的激活请求
func (s *CBCMessage) sendActivateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
// 直接使用 MessageJson 发送POST请求
return client.PostMessage(msg.MessageJson)
}
// 重构后的更新请求
func (s *CBCMessage) sendUpdateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
// 直接使用 MessageJson 发送POST请求
return client.PostMessage(msg.MessageJson)
}
// 重构后的停用请求
func (s *CBCMessage) sendDeactivateRequest(msg model.CBCMessage) error {
client, err := s.getCBCHTTPClient(msg.NeId)
if err != nil {
return err
}
// 解析和构造删除载荷的逻辑保持不变
var messageData map[string]interface{}
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
return fmt.Errorf("failed to parse message_json: %w", err)
}
eventName, ok := messageData["eventName"].(string)
if !ok || eventName == "" {
return fmt.Errorf("eventName not found in message_json")
}
deletePayload := make(map[string]interface{})
if messageIdProfile, exists := messageData["messageIdProfile"]; exists {
deletePayload["messageIdProfile"] = messageIdProfile
}
if warningAreaList, exists := messageData["warningAreaList"]; exists {
deletePayload["warningAreaList"] = warningAreaList
}
payloadBytes, err := json.Marshal(deletePayload)
if err != nil {
return fmt.Errorf("failed to marshal delete payload: %w", err)
}
return client.DeleteMessage(eventName, payloadBytes)
}

View File

@@ -1,645 +0,0 @@
package service
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
sysService "be.ems/src/modules/system/service"
)
// 实例化数据层 CDREvent 结构体
var NewCDREvent = &CDREvent{
cdrEventRepository: repository.NewCDREvent,
}
// CDREvent CDR会话事件 服务层处理
type CDREvent struct {
cdrEventRepository *repository.CDREvent // CDR会话事件数据信息
}
// FindByPage 根据条件分页查询
func (r CDREvent) FindByPage(neType string, query map[string]string) ([]model.CDREvent, int64) {
return r.cdrEventRepository.SelectByPage(neType, query)
}
// DeleteByIds 批量删除信息
func (r CDREvent) DeleteByIds(neType string, ids []int64) (int64, error) {
// 检查是否存在
rows := r.cdrEventRepository.SelectByIds(neType, ids)
if len(rows) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(rows) == len(ids) {
rows := r.cdrEventRepository.DeleteByIds(neType, ids)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
// Insert 新增信息
func (s CDREvent) Insert(param model.CDREvent) int64 {
return s.cdrEventRepository.Insert(param)
}
// ExportSMSC 导出数据到 xlsx 文件
func (r CDREvent) ExportSMSC(rows []model.CDREvent, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "NE Name",
"C1": "Record Behavior",
"D1": "Service Type",
"E1": "Caller",
"F1": "Called",
"G1": "Result",
"H1": "Time",
}
// 读取字典数据 CDR 原因码
dictCDRCauseCode := sysService.NewSysDictData.FindByType("cdr_cause_code")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 记录类型
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = v.(string)
}
// 服务类型
serviceType := ""
if v, ok := cdrJSON["serviceType"]; ok && v != nil {
serviceType = v.(string)
}
// 被叫
called := ""
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
called = v.(string)
}
// 主叫
caller := ""
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
caller = v.(string)
}
// 呼叫结果 0失败1成功
callResult := "Fail"
if v, ok := cdrJSON["result"]; ok && v != nil {
resultVal := parse.Number(v)
if resultVal == 1 {
callResult = "Success"
}
}
// 结果原因
if v, ok := cdrJSON["cause"]; ok && v != nil && callResult == "Fail" {
cause := fmt.Sprint(v)
for _, v := range dictCDRCauseCode {
if cause == v.DataValue {
callResult = fmt.Sprintf("%s, %s", callResult, i18n.TKey(language, v.DataLabel))
break
}
}
}
// 取时间
timeStr := ""
if v, ok := cdrJSON["updateTime"]; ok && v != nil {
if releaseTime := parse.Number(v); releaseTime > 0 {
timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
} else {
timeStr = v.(string)
}
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: row.NeUID,
"C" + idx: recordType,
"D" + idx: serviceType,
"E" + idx: caller,
"F" + idx: called,
"G" + idx: callResult,
"H" + idx: timeStr,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// ExportSMF 导出数据到 xlsx 文件
func (r CDREvent) ExportSMF(rows []model.CDREvent, fileName string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "Charging ID",
"C1": "NE Name",
"D1": "Resource Unique ID",
"E1": "Subscriber ID Data",
"F1": "Subscriber ID Type",
"G1": "Data Volume Uplink",
"H1": "Data Volume Downlink",
"I1": "Data Total Volume",
"J1": "Duration",
"K1": "Invocation Time",
"L1": "User Identifier",
"M1": "SSC Mode",
"N1": "DNN ID",
"O1": "PDU Type",
"P1": "RAT Type",
"Q1": "PDU IPv4 Address",
"R1": "Network Function IPv4",
"S1": "PDU IPv6 Address Swith Prefix",
"T1": "Record Network Function ID",
"U1": "Record Type",
"V1": "Record Opening Time",
}
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 计费ID
chargingID := ""
if v, ok := cdrJSON["chargingID"]; ok && v != nil {
chargingID = fmt.Sprint(parse.Number(v))
}
// 订阅 ID 类型
subscriptionIDType := "-"
// 订阅 ID 数据
subscriptionIDData := "-"
if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil {
if sub, subOk := v.(map[string]any); subOk && sub != nil {
subscriptionIDType = sub["subscriptionIDType"].(string)
subscriptionIDData = sub["subscriptionIDData"].(string)
}
}
// 网络功能 IPv4 地址
networkFunctionIPv4Address := ""
if v, ok := cdrJSON["nFunctionConsumerInformation"]; ok && v != nil {
if conInfo, conInfoOk := v.(map[string]any); conInfoOk && conInfo != nil {
networkFunctionIPv4Address = conInfo["networkFunctionIPv4Address"].(string)
}
}
// 数据量上行链路
var dataVolumeUplink int64 = 0
// 数据量下行链路
var dataVolumeDownlink int64 = 0
// 数据总量
var dataTotalVolume int64 = 0
if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil {
usageList := v.([]any)
if len(usageList) > 0 {
for _, used := range usageList {
usedUnit := used.(map[string]any)
usedUnitList := usedUnit["usedUnitContainer"].([]any)
if len(usedUnitList) > 0 {
for _, data := range usedUnitList {
udata := data.(map[string]any)
if dup, dupOk := udata["dataVolumeUplink"]; dupOk {
dataVolumeUplink += parse.Number(dup)
}
if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk {
dataVolumeDownlink += parse.Number(ddown)
}
if dt, dtOk := udata["dataTotalVolume"]; dtOk {
dataTotalVolume += parse.Number(dt)
}
}
}
}
}
}
// 时长
duration := "-"
if v, ok := cdrJSON["duration"]; ok && v != nil {
duration = fmt.Sprint(parse.Number(v))
}
// 调用时间
invocationTimestamp := ""
if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil {
invocationTimestamp = v.(string)
}
// 记录打开时间
User_Identifier := ""
SSC_Mode := ""
RAT_Type := ""
DNN_ID := ""
PDU_Type := ""
PDU_IPv4 := ""
PDU_IPv6 := ""
if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil {
pduInfo := v.(map[string]any)
if v, ok := pduInfo["userIdentifier"]; ok && v != nil {
User_Identifier = v.(string)
}
if v, ok := pduInfo["sSCMode"]; ok && v != nil {
SSC_Mode = v.(string)
}
if v, ok := pduInfo["rATType"]; ok && v != nil {
RAT_Type = v.(string)
}
if v, ok := pduInfo["dNNID"]; ok && v != nil {
DNN_ID = v.(string)
}
if v, ok := pduInfo["pDUType"]; ok && v != nil {
PDU_Type = v.(string)
}
if v, ok := pduInfo["pDUAddress"]; ok && v != nil {
pDUAddress := v.(map[string]any)
if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil {
PDU_IPv4 = addr.(string)
}
if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil {
PDU_IPv6 = addr.(string)
}
}
}
// 记录网络参数ID
recordNFID := ""
if v, ok := cdrJSON["recordingNetworkFunctionID"]; ok && v != nil {
recordNFID = v.(string)
}
//记录开始时间
recordOpeningTime := ""
if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
recordOpeningTime = v.(string)
}
//记录类型
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = v.(string)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: chargingID,
"C" + idx: row.CoreUID,
"D" + idx: row.NeUID,
"E" + idx: subscriptionIDData,
"F" + idx: subscriptionIDType,
"G" + idx: dataVolumeUplink,
"H" + idx: dataVolumeDownlink,
"I" + idx: dataTotalVolume,
"J" + idx: duration,
"K" + idx: invocationTimestamp,
"L" + idx: User_Identifier,
"M" + idx: SSC_Mode,
"N" + idx: DNN_ID,
"O" + idx: PDU_Type,
"P" + idx: RAT_Type,
"Q" + idx: PDU_IPv4,
"R" + idx: networkFunctionIPv4Address,
"S" + idx: PDU_IPv6,
"T" + idx: recordNFID,
"U" + idx: recordType,
"V" + idx: recordOpeningTime,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// ExportSGWC 导出数据到 xlsx 文件
func (r CDREvent) ExportSGWC(rows []model.CDREvent, fileName string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "NE Name",
"C1": "Resource Unique ID",
"D1": "Charging ID",
"E1": "IMSI",
"F1": "MSISDN",
"G1": "GPRS Uplink",
"H1": "GPRS Downlink",
"I1": "Duration",
"J1": "Invocation Time",
"K1": "PGW Address",
"L1": "SGW Address",
"M1": "RAT Type",
"N1": "PDPPDN Type",
"O1": "PDPPDN Address",
"P1": "Node Address",
"Q1": "Node Type",
"R1": "Record Access Point Name NI",
"S1": "Record Cause For Rec Closing",
"T1": "Record Sequence Number",
"U1": "Local Record Sequence Number",
"V1": "Record Type",
"W1": "Record Opening Time",
}
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 计费ID
chargingID := ""
if v, ok := cdrJSON["chargingID"]; ok && v != nil {
chargingID = fmt.Sprint(parse.Number(v))
}
// IMSI
servedIMSI := ""
if v, ok := cdrJSON["servedIMSI"]; ok && v != nil {
servedIMSI = fmt.Sprint(v)
}
// MSISDN
servedMSISDN := ""
if v, ok := cdrJSON["servedMSISDN"]; ok && v != nil {
servedMSISDN = fmt.Sprint(v)
}
// pGWAddressUsed
pGWAddressUsed := ""
if v, ok := cdrJSON["pGWAddressUsed"]; ok && v != nil {
pGWAddressUsed = fmt.Sprint(v)
headerCells["K1"] = "PGW Address"
}
if v, ok := cdrJSON["GGSNAddress"]; ok && v != nil {
pGWAddressUsed = fmt.Sprint(v)
headerCells["K1"] = "GGSN Address"
}
// sGWAddress
sGWAddress := ""
if v, ok := cdrJSON["sGWAddress"]; ok && v != nil {
sGWAddress = fmt.Sprint(v)
headerCells["L1"] = "SGW Address"
}
if v, ok := cdrJSON["SGSNAddress"]; ok && v != nil {
sGWAddress = fmt.Sprint(v)
headerCells["L1"] = "SGSN Address"
}
// recordType
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = fmt.Sprint(v)
}
// rATType
rATType := ""
if v, ok := cdrJSON["rATType"]; ok && v != nil {
rATType = fmt.Sprint(v)
}
// pdpPDNType
pdpPDNType := ""
if v, ok := cdrJSON["pdpPDNType"]; ok && v != nil {
pdpPDNType = fmt.Sprint(v)
}
// servedPDPPDNAddress
servedPDPPDNAddress := ""
if v, ok := cdrJSON["servedPDPPDNAddress"]; ok && v != nil {
servedPDPPDNAddress = fmt.Sprint(v)
}
// servedPDPPDNAddress
servingNodeAddress := []string{}
if v, ok := cdrJSON["servingNodeAddress"]; ok && v != nil {
for _, v := range v.([]any) {
servingNodeAddress = append(servingNodeAddress, fmt.Sprint(v))
}
}
// servingNodeType
servingNodeType := []string{}
if v, ok := cdrJSON["servingNodeType"]; ok && v != nil {
for _, v := range v.([]any) {
if v, ok := v.(map[string]any)["servingNodeType"]; ok && v != nil {
servingNodeType = append(servingNodeType, fmt.Sprint(v))
}
}
}
// accessPointNameNI
accessPointNameNI := ""
if v, ok := cdrJSON["accessPointNameNI"]; ok && v != nil {
accessPointNameNI = fmt.Sprint(v)
}
// causeForRecClosing
causeForRecClosing := ""
if v, ok := cdrJSON["causeForRecClosing"]; ok && v != nil {
causeForRecClosing = fmt.Sprint(v)
}
// recordSequenceNumber
recordSequenceNumber := ""
if v, ok := cdrJSON["recordSequenceNumber"]; ok && v != nil {
recordSequenceNumber = fmt.Sprint(v)
}
// localRecordSequenceNumber
localRecordSequenceNumber := ""
if v, ok := cdrJSON["localRecordSequenceNumber"]; ok && v != nil {
localRecordSequenceNumber = fmt.Sprint(v)
}
// 数据量上行链路
var dataVolumeGPRSUplink int64 = 0
// 数据量下行链路
var dataVolumeGPRSDownlink int64 = 0
if v, ok := cdrJSON["listOfTrafficVolumes"]; ok && v != nil {
usageList := v.([]any)
if len(usageList) > 0 {
for _, used := range usageList {
usedUnit := used.(map[string]any)
if dup, dupOk := usedUnit["dataVolumeGPRSUplink"]; dupOk {
dataVolumeGPRSUplink = parse.Number(dup)
}
if ddown, ddownOk := usedUnit["dataVolumeGPRSDownlink"]; ddownOk {
dataVolumeGPRSDownlink = parse.Number(ddown)
}
}
}
}
// 时长
duration := "-"
if v, ok := cdrJSON["duration"]; ok && v != nil {
duration = fmt.Sprint(parse.Number(v))
}
// 调用时间
invocationTimestamp := ""
if v, ok := cdrJSON["recordOpeningTime"]; ok && v != nil {
invocationTimestamp = v.(string)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: row.NeUID,
"C" + idx: row.CoreUID,
"D" + idx: chargingID,
"E" + idx: servedIMSI,
"F" + idx: servedMSISDN,
"G" + idx: dataVolumeGPRSUplink,
"H" + idx: dataVolumeGPRSDownlink,
"I" + idx: duration,
"J" + idx: invocationTimestamp,
"K" + idx: pGWAddressUsed,
"L" + idx: sGWAddress,
"M" + idx: rATType,
"N" + idx: pdpPDNType,
"O" + idx: servedPDPPDNAddress,
"P" + idx: strings.Join(servingNodeAddress, ","),
"Q" + idx: strings.Join(servingNodeType, ","),
"R" + idx: accessPointNameNI,
"S" + idx: causeForRecClosing,
"T" + idx: recordSequenceNumber,
"U" + idx: localRecordSequenceNumber,
"V" + idx: recordType,
"W" + idx: invocationTimestamp,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// ExportIMS 导出数据到 xlsx 文件
func (r CDREvent) ExportIMS(rows []model.CDREvent, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "NE Name",
"C1": "Record Behavior",
"D1": "Type",
"E1": "Caller",
"F1": "Called",
"G1": "Duration",
"H1": "Result Code",
"I1": "Result Cause",
"J1": "Call Start Time",
"K1": "Hangup Time",
}
// 读取字典数据 CDR SIP响应代码类别类型
dictCDRSipCode := sysService.NewSysDictData.FindByType("cdr_sip_code")
// 读取字典数据 CDR SIP响应代码类别类型原因
dictCDRSipCodeCause := sysService.NewSysDictData.FindByType("cdr_sip_code_cause")
// 读取字典数据 CDR 呼叫类型
dictCDRCallType := sysService.NewSysDictData.FindByType("cdr_call_type")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]any
err := json.Unmarshal([]byte(row.CdrJson), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 记录类型
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = v.(string)
}
// 呼叫类型
callType := "sms"
callTypeLable := "SMS"
if v, ok := cdrJSON["callType"]; ok && v != nil {
callType = v.(string)
for _, v := range dictCDRCallType {
if callType == v.DataValue {
callTypeLable = i18n.TKey(language, v.DataLabel)
break
}
}
}
// 被叫
called := ""
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
called = v.(string)
}
// 主叫
caller := ""
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
caller = v.(string)
}
// 时长
duration := "-"
if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
duration = fmt.Sprintf("%ds", parse.Number(v))
}
// 呼叫结果 非短信都有code作为结果 sms短信都ok
callResult := "Other"
callCause := "Call failure for other reason"
if callType == "sms" {
callResult = "Success"
callCause = "Normal Send"
} else {
if v, ok := cdrJSON["cause"]; ok && v != nil {
cause := fmt.Sprint(v)
for _, v := range dictCDRSipCode {
if cause == v.DataValue {
callResult = i18n.TKey(language, v.DataLabel)
break
}
}
for _, v := range dictCDRSipCodeCause {
if cause == v.DataValue {
callCause = i18n.TKey(language, v.DataLabel)
break
}
}
}
}
// 呼叫时间
seizureTimeStr := ""
if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
if seizureTime := parse.Number(v); seizureTime > 0 {
seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DDTHH_MM_SSZ)
} else {
seizureTimeStr = v.(string)
}
}
// 挂断时间
releaseTimeStr := ""
if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
if releaseTime := parse.Number(v); releaseTime > 0 {
releaseTimeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
} else {
releaseTimeStr = v.(string)
}
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: row.NeUID,
"C" + idx: recordType,
"D" + idx: callTypeLable,
"E" + idx: caller,
"F" + idx: called,
"G" + idx: duration,
"H" + idx: callResult,
"I" + idx: callCause,
"J" + idx: seizureTimeStr,
"K" + idx: releaseTimeStr,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}

View File

@@ -1,215 +0,0 @@
package service
import (
"fmt"
"strconv"
"strings"
"time"
"be.ems/src/framework/database/redis"
"be.ems/src/framework/utils/date"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
)
// 实例化服务层 UDMAuthUser 结构体
var NewUDMAuthUser = &UDMAuthUser{
udmAuthRepository: repository.NewUDMAuthUser,
}
// UDM鉴权信息 服务层处理
type UDMAuthUser struct {
// UDM鉴权信息数据信息
udmAuthRepository *repository.UDMAuthUser
}
// dataByRedis UDM鉴权用户 db:0 中 ausf:*
func (r *UDMAuthUser) dataByRedis(coreUid, neUid, imsi string) []model.UDMAuthUser {
arr := []model.UDMAuthUser{}
key := fmt.Sprintf("ausf:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
ausfArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, ausfArr)
if err != nil {
return arr
}
for k, m := range mkv {
if len(k) != 20 {
continue
}
// 跳过-号数据 ausf:360000100000130
imsi, hasPrefix := strings.CutPrefix(k, "ausf:")
if strings.Contains(imsi, "-") || !hasPrefix {
continue
}
amf := ""
if v, ok := m["amf"]; ok {
amf = strings.Replace(v, "\r\n", "", 1)
}
// 创建时间
var createTime int64 = 0
if v, ok := m["create_time"]; ok {
t := date.ParseStrToDate(v, time.RFC3339)
createTime = t.UnixMilli()
} else {
createTime = time.Now().UnixMilli()
}
a := model.UDMAuthUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
IMSI: imsi,
Amf: amf,
Ki: m["ki"],
AlgoIndex: m["algo"],
Opc: m["opc"],
CreateTime: createTime,
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
func (r *UDMAuthUser) ResetData(coreUid, neUid string) int64 {
authArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmAuthRepository.ClearAndInsert(coreUid, neUid, authArr)
return int64(len(authArr))
}
// ParseInfo 解析单个用户imsi鉴权信息 data从命令MML得到的结果
func (r *UDMAuthUser) ParseInfo(coreUid, neUid, imsi string, data map[string]string) model.UDMAuthUser {
u := r.udmAuthRepository.SelectByIMSI(coreUid, neUid, imsi)
u.CoreUID = coreUid
u.NeUID = neUid
u.NeType = "UDM"
// 用于更新
u.Amf = data["amf"]
u.Ki = data["ki"]
u.AlgoIndex = data["algo"]
u.Opc = data["opc"]
return u
}
// FindByPage 分页查询数据库
func (r *UDMAuthUser) FindByPage(query map[string]string) ([]model.UDMAuthUser, int64) {
return r.udmAuthRepository.SelectPage(query)
}
// Find 查询数据库
func (r *UDMAuthUser) Find(u model.UDMAuthUser) []model.UDMAuthUser {
return r.udmAuthRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度0或者32
func (r *UDMAuthUser) Insert(coreUid, neUid string, u model.UDMAuthUser) int64 {
uArr := r.dataByRedis(coreUid, neUid, u.IMSI)
if len(uArr) > 0 {
r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, u.IMSI)
return r.udmAuthRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r *UDMAuthUser) InsertData(coreUid, neUid, dataType string, data any) int64 {
// imsi截取前缀,重新获取部分数据
prefixes := make(map[string]struct{})
if dataType == "csv" {
for _, v := range data.([]map[string]string) {
imsi := v["imsi"]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
if dataType == "txt" {
for _, v := range data.([][]string) {
imsi := v[0]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
// 根据前缀重新加载插入
var num int64 = 0
for prefix := range prefixes {
// 直接删除前缀的记录
r.udmAuthRepository.DeletePrefixByIMSI(coreUid, neUid, prefix)
// keys ausf:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmAuthRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r *UDMAuthUser) Delete(coreUid, neUid, imsi string) int64 {
return r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
func (r *UDMAuthUser) LoadData(coreUid, neUid, imsi string, num int64) {
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
// 删除原数据
r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyIMSI)
if len(arr) < 1 {
continue
}
r.udmAuthRepository.Inserts(arr)
}
}
// ParseCommandParams 解析数据组成命令参数 ki=xx,xx=xx,...
func (r *UDMAuthUser) ParseCommandParams(item model.UDMAuthUser) string {
var conditions []string
if item.Ki != "" {
conditions = append(conditions, fmt.Sprintf("ki=%s", item.Ki))
}
if item.Amf != "" {
conditions = append(conditions, fmt.Sprintf("amf=%s", item.Amf))
}
if item.AlgoIndex != "" {
conditions = append(conditions, fmt.Sprintf("algo=%s", item.AlgoIndex))
}
if item.Opc != "" {
conditions = append(conditions, fmt.Sprintf("opc=%s", item.Opc))
}
return strings.Join(conditions, ",")
}

View File

@@ -1,33 +0,0 @@
package service
import (
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
)
// 实例化服务层 UDMExtend 结构体
var NewUDMExtend = &UDMExtend{
UDMExtendRepository: repository.NewUDMExtend,
}
// UDM用户IMSI拓展信息 服务层处理
type UDMExtend struct {
// UDM用户IMSI信息数据信息
UDMExtendRepository *repository.UDMExtend
}
// FindByIMSIAndNeID 通过IMSI和网元标识查询信息 neId为%时模糊imsi查询
func (r UDMExtend) FindByIMSIAndNeID(coreUid, neUid, imsi string) model.UDMExtend {
return r.UDMExtendRepository.SelectByIMSI(coreUid, neUid, imsi)
}
// Save 新增或修改信息
func (r UDMExtend) Save(u model.UDMExtend) bool {
r.UDMExtendRepository.DeleteByIMSI(u.CoreUID, u.NeUID, u.IMSI)
return r.UDMExtendRepository.Inserts([]model.UDMExtend{u}) > 0
}
// Delete 删除信息 neId为%时模糊imsi查询
func (r UDMExtend) Delete(coreUid, neUid, imsi string) int64 {
return r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, imsi)
}

View File

@@ -1,378 +0,0 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
)
// 实例化服务层 UDMSubUser 结构体
var NewUDMSubUser = &UDMSubUser{
udmSubRepository: repository.NewUDMSub,
UDMExtendRepository: repository.NewUDMExtend,
}
// UDM签约信息 服务层处理
type UDMSubUser struct {
udmSubRepository *repository.UDMSubUser // UDM签约信息数据信息
UDMExtendRepository *repository.UDMExtend // UDM用户IMSI信息数据信息
}
// dataByRedis UDM签约用户 db:0 中 udm-sd:*
func (r *UDMSubUser) dataByRedis(coreUid, neUid, imsi string) []model.UDMSubUser {
arr := []model.UDMSubUser{}
key := fmt.Sprintf("udm-sd:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
udmsdArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, udmsdArr)
if err != nil {
return arr
}
for k, m := range mkv {
if len(k) != 22 {
continue
}
// 跳过-号数据 udm-sd:360000100000130
imsi, hasPrefix := strings.CutPrefix(k, "udm-sd:")
if strings.Contains(imsi, "-") || !hasPrefix {
continue
}
a := model.UDMSubUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
IMSI: imsi, // udm-sd:360000100000130
MSISDN: m["gpsi"], // 8612300000130
SmfSel: m["smf-sel"], // def_snssai
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
Cag: m["cag"], // def_cag
}
// def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,-
if v, ok := m["am-dat"]; ok {
arr := strings.Split(v, ",")
a.AmDat = v
a.UeAmbrTpl = arr[0]
a.NssaiTpl = arr[1]
a.RatRestrictions = arr[2]
a.AreaForbiddenTpl = arr[3]
a.ServiceAreaRestrictionTpl = arr[4]
a.CnTypeRestrictions = arr[5]
a.RfspIndex = arr[6]
a.SubsRegTime = arr[7]
a.UeUsageType = arr[8]
a.ActiveTime = arr[9]
a.MicoAllowed = "0" // arr[10]
a.OdbPs = "1" // arr[11]
a.GroupId = "-" // arr[12]
if len(arr) > 10 {
a.MicoAllowed = arr[10]
}
if len(arr) > 11 {
a.OdbPs = arr[11]
}
if len(arr) > 12 && arr[12] != "-" {
a.GroupId = arr[12]
}
}
// 1,64,24,65,def_eps,1,2,010200000000,-
if v, ok := m["eps-dat"]; ok {
arr := strings.Split(v, ",")
// 跳过非常规数据
if len(arr) > 9 {
continue
}
a.EpsDat = v
a.EpsFlag = arr[0]
a.EpsOdb = arr[1]
a.HplmnOdb = arr[2]
a.Ard = arr[3]
a.Epstpl = arr[4]
a.ContextId = arr[5]
a.ApnNum = arr[6] // 导入和导出不用
a.ApnContext = arr[7]
if len(arr) >= 9 {
a.StaticIp = arr[8]
}
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
func (r *UDMSubUser) ResetData(coreUid, neUid string) int64 {
subArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmSubRepository.ClearAndInsert(coreUid, neUid, subArr)
return int64(len(subArr))
}
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
func (r *UDMSubUser) ParseInfo(coreUid, neUid, imsi string, data map[string]string) model.UDMSubUser {
u := r.udmSubRepository.SelectByIMSI(coreUid, neUid, imsi)
cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64) // 0x03(EPC|5GC)
rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64) // 0x00(VIRTUAL|WLAN|EUTRA|NR)
msisdn := data["MSISDN"]
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
msisdn = msisdn[:imsMsisdnLen]
}
// 用于更新
u.CoreUID = coreUid
u.NeUID = neUid
u.NeType = "UDM"
u.IMSI = imsi
u.MSISDN = msisdn
u.UeAmbrTpl = data["AMBR"]
u.NssaiTpl = data["NSSAI"]
u.AreaForbiddenTpl = data["AreaForbidden"]
u.ServiceAreaRestrictionTpl = data["ServiceAreaRestriction"]
u.CnTypeRestrictions = fmt.Sprint(cnType)
u.RatRestrictions = fmt.Sprint(rat)
u.MicoAllowed = data["MICO"]
u.SmData = data["SM-Data(snssai+dnn[1..n])"]
u.SmfSel = data["Smf-Selection"]
u.Cag = data["cag"]
// 1,64,24,65,def_eps,1,2,010200000000,-
if v, ok := data["EPS-Data"]; ok {
u.EpsDat = v
arr := strings.Split(v, ",")
u.EpsFlag = arr[0]
u.EpsOdb = arr[1]
u.HplmnOdb = arr[2]
u.Ard = arr[3]
u.Epstpl = arr[4]
u.ContextId = arr[5]
u.ApnNum = arr[6] // 导入和导出不用
u.ApnContext = arr[7]
u.StaticIp = arr[8]
}
// 补充用户拓展信息
info := r.UDMExtendRepository.SelectByIMSI(coreUid, neUid, imsi)
if info.IMSI == imsi {
u.Remark = info.Remark
}
return u
}
// FindByPage 分页查询数据库
func (r *UDMSubUser) FindByPage(query map[string]string) ([]model.UDMSubUser, int64) {
return r.udmSubRepository.SelectPage(query)
}
// Find 查询数据库
func (r *UDMSubUser) Find(u model.UDMSubUser) []model.UDMSubUser {
return r.udmSubRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度0或者32
func (r *UDMSubUser) Insert(coreUid, neUid string, u model.UDMSubUser) int64 {
uArr := r.dataByRedis(coreUid, neUid, u.IMSI)
if len(uArr) > 0 {
r.udmSubRepository.DeleteByIMSI(coreUid, neUid, u.IMSI)
// 新增到拓展信息
if u.Remark != "" {
r.UDMExtendRepository.DeleteByIMSI(coreUid, "%", u.IMSI)
r.UDMExtendRepository.Inserts([]model.UDMExtend{{
CoreUID: u.CoreUID,
NeUID: u.NeUID,
NeType: u.NeType,
IMSI: u.IMSI,
MSISDN: u.MSISDN,
Remark: u.Remark,
}})
}
return r.udmSubRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r *UDMSubUser) InsertData(coreUid, neUid, dataType string, data any) int64 {
// imsi截取前缀,重新获取部分数据
prefixes := make(map[string]struct{})
if dataType == "csv" {
for _, v := range data.([]map[string]string) {
imsi := v["imsi"]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
if dataType == "txt" {
for _, v := range data.([][]string) {
imsi := v[0]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
// 根据前缀重新加载插入
var num int64 = 0
for prefix := range prefixes {
// keys udm-sd:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
r.udmSubRepository.DeletePrefixByIMSI(coreUid, neUid, prefix)
num += r.udmSubRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r *UDMSubUser) Delete(coreUid, neUid, imsi string) int64 {
// 删除拓展信息
r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, imsi)
return r.udmSubRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
// remark不为空则新增到拓展信息删除标记为-(Deleted)-
func (r *UDMSubUser) LoadData(coreUid, neUid, imsi string, num int64, remark string) {
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
// 删除原数据
r.udmSubRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
if remark == "-(Deleted)-" {
r.UDMExtendRepository.DeleteByIMSI(coreUid, "%", keyIMSI)
}
// 加载数据,删除标记为-(Deleted)-加载为空不插入
arr := r.dataByRedis(coreUid, neUid, keyIMSI)
if len(arr) < 1 {
continue
}
r.udmSubRepository.Inserts(arr)
// 拓展信息
if remark != "" {
uarr := make([]model.UDMExtend, 0, len(arr))
for _, v := range arr {
uarr = append(uarr, model.UDMExtend{
CoreUID: v.CoreUID,
NeUID: v.NeUID,
NeType: v.NeType,
IMSI: v.IMSI,
MSISDN: v.MSISDN,
Remark: remark,
})
}
r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
r.UDMExtendRepository.Inserts(uarr)
}
}
}
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
func (r *UDMSubUser) ParseCommandParams(item model.UDMSubUser) string {
var conditions []string
if item.MSISDN != "" {
conditions = append(conditions, fmt.Sprintf("msisdn=%s", item.MSISDN))
}
// AmData
if item.UeAmbrTpl != "" {
conditions = append(conditions, fmt.Sprintf("ambr=%s", item.UeAmbrTpl))
}
if item.NssaiTpl != "" {
conditions = append(conditions, fmt.Sprintf("nssai=%s", item.NssaiTpl))
}
if item.AreaForbiddenTpl != "" {
conditions = append(conditions, fmt.Sprintf("arfb=%s", item.AreaForbiddenTpl))
}
if item.ServiceAreaRestrictionTpl != "" {
conditions = append(conditions, fmt.Sprintf("sar=%s", item.ServiceAreaRestrictionTpl))
}
if item.RatRestrictions != "" {
conditions = append(conditions, fmt.Sprintf("rat=%s", item.RatRestrictions))
}
if item.CnTypeRestrictions != "" {
conditions = append(conditions, fmt.Sprintf("cn=%s", item.CnTypeRestrictions))
}
if item.RfspIndex != "" {
conditions = append(conditions, fmt.Sprintf("rfsp=%s", item.RfspIndex))
}
if item.UeUsageType != "" {
conditions = append(conditions, fmt.Sprintf("usagetype=%s", item.UeUsageType))
}
if item.MicoAllowed != "" {
conditions = append(conditions, fmt.Sprintf("mico=%s", item.MicoAllowed))
}
// EpsDat
// if item.EpsDat != "" {
// conditions = append(conditions, fmt.Sprintf("eps_dat=%s", item.EpsDat))
// }
if item.EpsFlag != "" {
conditions = append(conditions, fmt.Sprintf("eps_flag=%s", item.EpsFlag))
}
if item.EpsOdb != "" {
conditions = append(conditions, fmt.Sprintf("eps_odb=%s", item.EpsOdb))
}
if item.HplmnOdb != "" {
conditions = append(conditions, fmt.Sprintf("hplmn_odb=%s", item.HplmnOdb))
}
if item.Epstpl != "" {
conditions = append(conditions, fmt.Sprintf("epstpl=%s", item.Epstpl))
}
if item.Ard != "" {
conditions = append(conditions, fmt.Sprintf("ard=%s", item.Ard))
}
if item.ContextId != "" {
conditions = append(conditions, fmt.Sprintf("context_id=%s", item.ContextId))
}
if item.ApnContext != "" {
conditions = append(conditions, fmt.Sprintf("apn_context=%s", item.ApnContext))
}
// static_ip指给4G UE分配的静态IP没有可不带此字段名批量添加IP会自动递增
if item.StaticIp != "" {
conditions = append(conditions, fmt.Sprintf("static_ip=%s", item.StaticIp))
}
// 其他
if item.SmfSel != "" {
conditions = append(conditions, fmt.Sprintf("smf_sel=%s", item.SmfSel))
}
if item.SmData != "" {
conditions = append(conditions, fmt.Sprintf("sm_data=%s", item.SmData))
}
conditions = append(conditions, fmt.Sprintf("cag=%s", item.Cag))
return strings.Join(conditions, ",")
}

View File

@@ -1,175 +0,0 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
)
// 实例化服务层 UDMVOIPUser 结构体
var NewUDMVOIPUser = &UDMVOIPUser{
udmVOIPRepository: repository.NewUDMVOIPUser,
}
// UDMVOIP信息 服务层处理
type UDMVOIPUser struct {
// UDMVOIP信息数据信息
udmVOIPRepository *repository.UDMVOIPUser
}
// dataByRedis UDMVOIP用户 db:0 中 voip:*
func (r UDMVOIPUser) dataByRedis(coreUid, neUid, username string) []model.UDMVOIPUser {
arr := []model.UDMVOIPUser{}
key := fmt.Sprintf("voip:%s", username)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
voipArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, voipArr)
if err != nil {
return arr
}
for k, m := range mkv {
// 跳过-号数据 voip:360000100000130
username, hasPrefix := strings.CutPrefix(k, "voip:")
if strings.Contains(username, "-") || !hasPrefix {
continue
}
a := model.UDMVOIPUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
UserName: username,
Password: m["password"],
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置VOIP用户数据清空数据库重新同步Redis数据
func (r UDMVOIPUser) ResetData(coreUid, neUid string) int64 {
arr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmVOIPRepository.ClearAndInsert(coreUid, neUid, arr)
return int64(len(arr))
}
// ParseInfo 解析单个用户userName信息 data从命令MML得到的结果
func (r UDMVOIPUser) ParseInfo(coreUid, neUid string, data map[string]string) model.UDMVOIPUser {
u := model.UDMVOIPUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
UserName: data["username"],
Password: data["password"],
}
// 赋予ID
item := r.udmVOIPRepository.SelectByUserName(coreUid, neUid, u.UserName)
if item.ID > 0 {
u.ID = item.ID
}
return u
}
// FindByPage 分页查询数据库
func (r UDMVOIPUser) FindByPage(query map[string]string) ([]model.UDMVOIPUser, int64) {
return r.udmVOIPRepository.SelectPage(query)
}
// Find 查询数据库
func (r UDMVOIPUser) Find(u model.UDMVOIPUser) []model.UDMVOIPUser {
return r.udmVOIPRepository.SelectList(u)
}
// Insert 从数据中读取后删除username再存入数据库
func (r UDMVOIPUser) Insert(coreUid, neUid string, username string) int64 {
uArr := r.dataByRedis(coreUid, neUid, username)
if len(uArr) > 0 {
r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, username)
return r.udmVOIPRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r UDMVOIPUser) InsertData(coreUid, neUid, dataType string, data any) int64 {
// imsi截取前缀,重新获取部分数据
prefixes := make(map[string]struct{})
if dataType == "csv" {
for _, v := range data.([]map[string]string) {
username := v["username"]
if len(username) < 4 {
continue
}
prefix := username[:len(username)-3]
prefixes[prefix] = struct{}{}
}
}
if dataType == "txt" {
for _, v := range data.([][]string) {
username := v[0]
if len(username) < 4 {
continue
}
prefix := username[:len(username)-3]
prefixes[prefix] = struct{}{}
}
}
// 根据前缀重新加载插入
var num int64 = 0
for prefix := range prefixes {
// 直接删除前缀的记录
r.udmVOIPRepository.DeletePrefixByUserName(coreUid, neUid, prefix)
// keys voip:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmVOIPRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r UDMVOIPUser) Delete(coreUid, neUid, username string) int64 {
return r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, username)
}
// LoadData 重新加载从username开始num的数据
func (r UDMVOIPUser) LoadData(coreUid, neUid, username string, num int64) {
startUserName, _ := strconv.ParseInt(username, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyUserName := fmt.Sprintf("%d", startUserName+i)
// 删除原数据
r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, keyUserName)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyUserName)
if len(arr) < 1 {
continue
}
r.udmVOIPRepository.Inserts(arr)
}
}

View File

@@ -1,199 +0,0 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/ne/service"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
)
// 实例化服务层 UDMVolteIMSUser 结构体
var NewUDMVolteIMSUser = &UDMVolteIMSUser{
udmVolteIMSRepository: repository.NewUDMVolteIMSUser,
}
// UDMVolteIMS信息 服务层处理
type UDMVolteIMSUser struct {
// UDMVolteIMS信息数据信息
udmVolteIMSRepository *repository.UDMVolteIMSUser
}
// dataByRedis UDMVolteIMS用户 db:0 中 volte:*
func (r UDMVolteIMSUser) dataByRedis(coreUid, neUid, imsi string) []model.UDMVolteIMSUser {
arr := []model.UDMVolteIMSUser{}
key := fmt.Sprintf("volte:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
volteArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, volteArr)
if err != nil {
return arr
}
for k, m := range mkv {
// volte:360000100000130:8612300000130
keys := strings.Split(k, ":")
if len(keys) != 3 {
continue
}
// "110011200004217@ims.mnc001.mcc110.3gppnetwork.org"
vni := ""
impiParts := strings.Split(m["impi"], "@")
if len(impiParts) > 1 {
vni = impiParts[1]
}
a := model.UDMVolteIMSUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
IMSI: keys[1],
MSISDN: keys[2],
Tag: m["tag"], // volte = tag
VNI: vni,
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置VolteIMS用户数据清空数据库重新同步Redis数据
func (r UDMVolteIMSUser) ResetData(coreUid, neUid string) int64 {
authArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmVolteIMSRepository.ClearAndInsert(coreUid, neUid, authArr)
return int64(len(authArr))
}
// ParseInfo 解析单个用户imsi信息 data从命令MML得到的结果
func (r UDMVolteIMSUser) ParseInfo(coreUid, neUid string, data map[string]string) model.UDMVolteIMSUser {
// "110011200004217@ims.mnc001.mcc110.3gppnetwork.org"
vni := ""
impiParts := strings.Split(data["impi"], "@")
if len(impiParts) > 1 {
vni = impiParts[1]
}
if vni == "" {
return model.UDMVolteIMSUser{}
}
u := model.UDMVolteIMSUser{
CoreUID: coreUid,
NeUID: neUid,
IMSI: data["imsi"],
MSISDN: data["msisdn"],
Tag: data["volte_tag"],
VNI: vni,
}
// 赋予ID
item := r.udmVolteIMSRepository.SelectByIMSIAndMSISDN(coreUid, neUid, u.IMSI, u.MSISDN)
if item.ID > 0 {
u.ID = item.ID
}
return u
}
// FindByPage 分页查询数据库
func (r UDMVolteIMSUser) FindByPage(query map[string]string) ([]model.UDMVolteIMSUser, int64) {
return r.udmVolteIMSRepository.SelectPage(query)
}
// Find 查询数据库
func (r UDMVolteIMSUser) Find(u model.UDMVolteIMSUser) []model.UDMVolteIMSUser {
return r.udmVolteIMSRepository.SelectList(u)
}
// InsertByIMSI 从数据中读取后删除imsi再存入数据库
// imsi长度15
func (r UDMVolteIMSUser) InsertByIMSI(coreUid, neUid, imsi string) int64 {
uArr := r.dataByRedis(coreUid, neUid, imsi+":*")
if len(uArr) > 0 {
r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, imsi)
return r.udmVolteIMSRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r UDMVolteIMSUser) InsertData(coreUid, neUid, dataType string, data any) int64 {
// imsi截取前缀,重新获取部分数据
prefixes := make(map[string]struct{})
if dataType == "csv" {
for _, v := range data.([]map[string]string) {
imsi := v["imsi"]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
if dataType == "txt" {
for _, v := range data.([][]string) {
imsi := v[0]
if len(imsi) < 6 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
}
// 根据前缀重新加载插入
var num int64 = 0
for prefix := range prefixes {
// 直接删除前缀的记录
r.udmVolteIMSRepository.DeletePrefixByIMSI(coreUid, neUid, prefix)
// keys voip:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmVolteIMSRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r UDMVolteIMSUser) Delete(coreUid, neUid, imsi string) int64 {
return r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
func (r UDMVolteIMSUser) LoadData(coreUid, neUid, imsiOrMsisdn string, num int64) {
startIMSIOrMsisdn, _ := strconv.ParseInt(imsiOrMsisdn, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%015d", startIMSIOrMsisdn+i)
if !strings.HasPrefix(imsiOrMsisdn, "0") {
keyIMSI = fmt.Sprintf("%d", startIMSIOrMsisdn+i)
}
// 删除原数据
r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyIMSI+":*")
if len(arr) < 1 {
continue
}
r.udmVolteIMSRepository.Inserts(arr)
}
}

View File

@@ -1,229 +0,0 @@
package service
import (
"encoding/json"
"fmt"
"strconv"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/ne_data/model"
"be.ems/src/modules/ne_data/repository"
sysService "be.ems/src/modules/system/service"
"github.com/tsmask/go-oam"
)
// 实例化数据层 UEEvent 结构体
var NewUEEvent = &UEEvent{
ueEventRepository: repository.NewUEEvent,
}
// UEEvent UE会话事件 服务层处理
type UEEvent struct {
ueEventRepository *repository.UEEvent // UE会话事件数据信息
}
// FindByPage 根据条件分页查询
func (r UEEvent) FindByPage(neType string, query map[string]string) ([]model.UEEvent, int64) {
return r.ueEventRepository.SelectByPage(neType, query)
}
// DeleteByIds 批量删除信息
func (r UEEvent) DeleteByIds(neType string, ids []int64) (int64, error) {
// 检查是否存在
rows := r.ueEventRepository.SelectByIds(neType, ids)
if len(rows) <= 0 {
return 0, fmt.Errorf("no data")
}
if len(rows) == len(ids) {
rows := r.ueEventRepository.DeleteByIds(neType, ids)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
// Insert 新增信息
func (r UEEvent) Insert(param model.UEEvent) int64 {
return r.ueEventRepository.Insert(param)
}
// ExportAMF 导出数据到 xlsx 文件
func (r UEEvent) ExportAMF(rows []model.UEEvent, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "IMSI",
"C1": "Event Type",
"D1": "Result",
"E1": "Time",
}
// 读取字典数据 UE 事件类型
dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type")
// 读取字典数据 UE 事件认证代码类型
dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code")
// 读取字典数据 UE 事件CM状态
dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var eventJSON map[string]interface{}
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
if err != nil {
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
continue
}
// 取IMSI
imsi := ""
if v, ok := eventJSON["imsi"]; ok && v != nil {
imsi = v.(string)
}
// 取类型
eventType := ""
for _, v := range dictUEEventType {
if row.EventType == v.DataValue {
eventType = i18n.TKey(language, v.DataLabel)
break
}
}
// 取结果
eventResult := ""
// 取时间
timeStr := ""
if row.EventType == oam.UENB_TYPE_AUTH {
if v, ok := eventJSON["authTime"]; ok && v != nil {
timeStr = v.(string)
}
if v, ok := eventJSON["authCode"]; ok && v != nil {
eventResult = v.(string)
for _, v := range dictUEAauthCode {
if eventResult == v.DataValue {
eventResult = i18n.TKey(language, v.DataLabel)
break
}
}
}
}
if row.EventType == oam.UENB_TYPE_DETACH {
if v, ok := eventJSON["detachTime"]; ok && v != nil {
timeStr = v.(string)
}
eventResult = "Success"
}
if row.EventType == oam.UENB_TYPE_CM {
if v, ok := eventJSON["changeTime"]; ok && v != nil {
timeStr = v.(string)
}
if v, ok := eventJSON["status"]; ok && v != nil {
eventResult = fmt.Sprint(v)
for _, v := range dictUEEventCmState {
if eventResult == v.DataValue {
eventResult = i18n.TKey(language, v.DataLabel)
break
}
}
}
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: imsi,
"C" + idx: eventType,
"D" + idx: eventResult,
"E" + idx: timeStr,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// ExportMME 导出数据到 xlsx 文件
func (r UEEvent) ExportMME(rows []model.UEEvent, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "IMSI",
"C1": "Event Type",
"D1": "Result",
"E1": "Time",
}
// 读取字典数据 UE 事件类型
dictUEEventType := sysService.NewSysDictData.FindByType("ue_event_type")
// 读取字典数据 UE 事件认证代码类型
dictUEAauthCode := sysService.NewSysDictData.FindByType("ue_auth_code")
// 读取字典数据 UE 事件CM状态
dictUEEventCmState := sysService.NewSysDictData.FindByType("ue_event_cm_state")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var eventJSON map[string]interface{}
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
if err != nil {
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
continue
}
// 取IMSI
imsi := ""
if v, ok := eventJSON["imsi"]; ok && v != nil {
imsi = v.(string)
}
// 取类型
eventType := row.EventType
for _, v := range dictUEEventType {
if row.EventType == v.DataValue {
eventType = i18n.TKey(language, v.DataLabel)
break
}
}
// 取结果
eventResult := ""
if v, ok := eventJSON["result"]; ok && v != nil {
eventResult = v.(string)
if row.EventType == oam.UENB_TYPE_AUTH {
for _, v := range dictUEAauthCode {
if eventResult == v.DataValue {
eventResult = i18n.TKey(language, v.DataLabel)
break
}
}
}
if row.EventType == oam.UENB_TYPE_CM {
for _, v := range dictUEEventCmState {
if eventResult == v.DataValue {
eventResult = i18n.TKey(language, v.DataLabel)
break
}
}
}
}
// 取时间
timeStr := ""
if v, ok := eventJSON["timestamp"]; ok && v != nil {
rowTime := parse.Number(v)
timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: imsi,
"C" + idx: eventType,
"D" + idx: eventResult,
"E" + idx: timeStr,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}

View File

@@ -1,54 +0,0 @@
package ne_data
import (
"crypto/des"
"errors"
"testing"
)
// UDM K4加密
func encrypt(origData, key []byte) ([]byte, error) {
if len(origData) < 1 || len(key) < 1 {
return nil, errors.New("wrong data or key")
}
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
bs := block.BlockSize()
if len(origData)%bs != 0 {
return nil, errors.New("wrong padding")
}
out := make([]byte, len(origData))
dst := out
for len(origData) > 0 {
block.Encrypt(dst, origData[:bs])
origData = origData[bs:]
dst = dst[bs:]
}
return out, nil
}
func TestEncrypt(t *testing.T) {
// key := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}
// 0123456789abcdef
// ki := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}
// 0123456789abcdef0123456789abcdef
// k4 password
key := []byte{0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34}
// 1234123412341234
// k4 crypt ki
ki := []byte{0x80, 0x5D, 0xAD, 0xC6, 0xE8, 0xA5, 0x4A, 0x0D, 0x59, 0xD6, 0x22, 0xC7, 0xA0, 0x4D, 0x08, 0xE0}
// 805DADC6E8A54A0D59D622C7A04D08E0
kis, err := encrypt(ki, key)
// 加密后的放导入导入文件里ki
t.Errorf("kis: %x\n", kis)
// 3e479135bb16f45dc874a18831b54d71
t.Errorf("err: %v\n", err)
}