From 305a969d7d05fdb6ebe21cc20cc7a74b1cafb4fd Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 7 Jun 2024 19:47:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ISMF=E7=9A=84CDR=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=BB=A3=E7=A0=81=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/smf.go | 115 +++++++++-- .../network_data/model/cdr_event_smf.go | 5 +- .../network_data/repository/cdr_event_smf.go | 15 ++ .../repository/cdr_event_smf.impl.go | 185 ++++++++++++++++++ .../network_data/service/cdr_event_smf.go | 12 ++ .../service/cdr_event_smf.impl.go | 37 ++++ 6 files changed, 354 insertions(+), 15 deletions(-) create mode 100644 src/modules/network_data/repository/cdr_event_smf.go create mode 100644 src/modules/network_data/repository/cdr_event_smf.impl.go create mode 100644 src/modules/network_data/service/cdr_event_smf.go create mode 100644 src/modules/network_data/service/cdr_event_smf.impl.go diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index ee3ddb95..a40e6680 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -1,10 +1,13 @@ package controller import ( + "fmt" "strings" + "time" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" @@ -13,20 +16,20 @@ import ( "github.com/gin-gonic/gin" ) -// 实例化控制层 IMSController 结构体 +// 实例化控制层 SMFController 结构体 var NewSMFController = &SMFController{ neInfoService: neService.NewNeInfoImpl, - cdrEventService: neDataService.NewSMFCDREventImpl, + cdrEventService: neDataService.NewCDREventSMFImpl, } -// 网元IMS +// 网元SMF // -// PATH /ims +// PATH /smf type SMFController struct { // 网元信息服务 neInfoService neService.INeInfo - // SMF CDR会话事件服务 - cdrEventService neDataService.SMFCDREvent + // CDR会话事件服务 + cdrEventService neDataService.ICDREventSMF } // CDR会话列表 @@ -34,19 +37,19 @@ type SMFController struct { // GET /cdr/list func (s *SMFController) CDRList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.SMFCDREventQuery + var querys model.CDREventSMFQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -78,3 +81,89 @@ func (s *SMFController) CDRRemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *SMFController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + // querys := ctx.BodyJSONMap(c) + var querys model.CDREventSMFQuery + + data := s.cdrEventService.SelectPage(querys) + if data["total"].(int64) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventSMF) + + // 导出文件名称 + fileName := fmt.Sprintf("user_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": i18n.TKey(language, "user.export.id"), + "B1": i18n.TKey(language, "user.export.name"), + "C1": i18n.TKey(language, "user.export.nick"), + "D1": i18n.TKey(language, "user.export.role"), + "E1": i18n.TKey(language, "user.export.deptName"), + "F1": i18n.TKey(language, "user.export.loginIP"), + "G1": i18n.TKey(language, "user.export.loginDate"), + "H1": i18n.TKey(language, "user.export.status"), + // "F1": i18n.TKey(language, "user.export.sex"), + // "E1": i18n.TKey(language, "user.export.phone"), + // "D1": i18n.TKey(language, "user.export.email"), + // "I1": i18n.TKey(language, "user.export.deptID"), + // "K1": i18n.TKey(language, "user.export.deptLeader"), + } + // 读取用户性别字典数据 + // dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + // for i, row := range rows { + // idx := strconv.Itoa(i + 2) + // // 用户性别 + // // sysUserSex := row.Sex + // // for _, v := range dictSysUserSex { + // // if row.Sex == v.DictValue { + // // sysUserSex = i18n.TKey(language, v.DictLabel) + // // break + // // } + // // } + // // 帐号状态 + // statusValue := i18n.TKey(language, "dictData.disable") + // if row.Status == "1" { + // statusValue = i18n.TKey(language, "dictData.normal") + // } + // // 用户角色, 默认导出首个 + // userRole := "" + // if len(row.Roles) > 0 { + // userRole = i18n.TKey(language, row.Roles[0].RoleName) + // } + // dataCells = append(dataCells, map[string]any{ + // "A" + idx: row.UserID, + // "B" + idx: row.UserName, + // "C" + idx: row.NickName, + // "D" + idx: userRole, + // "E" + idx: row.Dept.DeptName, + // "F" + idx: row.LoginIP, + // "G" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS), + // "H" + idx: statusValue, + // // "E" + idx: row.PhoneNumber, + // // "F" + idx: sysUserSex, + // // "D" + idx: row.Email, + // // "I" + idx: row.Dept.DeptID, + // // "K" + idx: row.Dept.Leader, + // }) + // } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go index 0234f91c..e1b6f243 100644 --- a/src/modules/network_data/model/cdr_event_smf.go +++ b/src/modules/network_data/model/cdr_event_smf.go @@ -2,7 +2,7 @@ package model import "time" -// CDREvent CDR会话对象 cdr_event_smf +// CDREventSMF CDR会话对象SMF cdr_event_smf type CDREventSMF struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` @@ -20,7 +20,8 @@ type CDREventSMF struct { CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } -type SMFCDREventQuery struct { +// CDREventSMFQuery CDR会话对象SMF查询参数结构体 +type CDREventSMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // SMF NeID string `json:"neId" form:"neId" binding:"required"` RmUID string `json:"rmUID" form:"rmUID"` diff --git a/src/modules/network_data/repository/cdr_event_smf.go b/src/modules/network_data/repository/cdr_event_smf.go new file mode 100644 index 00000000..1a950a29 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.go @@ -0,0 +1,15 @@ +package repository + +import "be.ems/src/modules/network_data/model" + +// CDR会话事件SMF 数据层接口 +type ICDREventSMF interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMFQuery) map[string]any + + // SelectByIds 通过ID查询 + SelectByIds(cdrIds []string) []model.CDREventSMF + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) int64 +} diff --git a/src/modules/network_data/repository/cdr_event_smf.impl.go b/src/modules/network_data/repository/cdr_event_smf.impl.go new file mode 100644 index 00000000..501a7ae8 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.impl.go @@ -0,0 +1,185 @@ +package repository + +import ( + "fmt" + "strings" + + "be.ems/src/framework/datasource" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/repo" + "be.ems/src/modules/network_data/model" +) + +// 实例化数据层 CDREventSMFImpl 结构体 +var NewCDREventSMFImpl = &CDREventSMFImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_name": "NeName", + "rm_uid": "RmUID", + "timestamp": "Timestamp", + "record_type": "RecordType", + "charging_id": "ChargingID", + "subscriber_id": "SubscriberID", + "duration": "Duration", + "data_volume_uplink": "DataVolumeUplink", + "data_volume_downlink": "DataVolumeDownlink", + "data_total_volume": "DataTotalVolume", + "pdu_address": "PDUAddress", + "created_at": "CreatedAt", + }, +} + +// CDREventSMFImpl CDR会话事件 数据层处理 +type CDREventSMFImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *CDREventSMFImpl) convertResultRows(rows []map[string]any) []model.CDREventSMF { + arr := make([]model.CDREventSMF, 0) + for _, row := range rows { + item := model.CDREventSMF{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询 +func (r *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if querys.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, querys.NeType) + } + if querys.RmUID != "" { + conditions = append(conditions, "rm_uid = ?") + params = append(params, querys.RmUID) + } + if querys.StartTime != "" { + conditions = append(conditions, "timestamp >= ?") + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) + } + if querys.EndTime != "" { + conditions = append(conditions, "timestamp <= ?") + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) + } + if querys.RecordType != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") + params = append(params, querys.RecordType) + } + if querys.SubscriberID != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?") + params = append(params, querys.SubscriberID) + } + // if querys.RecordType != "" { + // recordTypes := strings.Split(querys.RecordType, ",") + // placeholder := repo.KeyPlaceholderByQuery(len(recordTypes)) + // conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder)) + // for _, recordType := range recordTypes { + // params = append(params, recordType) + // } + // } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.CDREventSMF{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from cdr_event_smf" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + orderSql := "" + if querys.SortField != "" { + sortSql := querys.SortField + if querys.SortOrder != "" { + if querys.SortOrder == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectByIds 通过ID查询 +func (r *CDREventSMFImpl) SelectByIds(cdrIds []string) []model.CDREventSMF { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.CDREventSMF{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + sql := "delete from cdr_event_smf where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go new file mode 100644 index 00000000..1e55a690 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smf.go @@ -0,0 +1,12 @@ +package service + +import "be.ems/src/modules/network_data/model" + +// CDR会话事件SMF 服务层接口 +type ICDREventSMF interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMFQuery) map[string]any + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) (int64, error) +} diff --git a/src/modules/network_data/service/cdr_event_smf.impl.go b/src/modules/network_data/service/cdr_event_smf.impl.go new file mode 100644 index 00000000..09d2e48a --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smf.impl.go @@ -0,0 +1,37 @@ +package service + +import ( + "fmt" + + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" +) + +var NewCDREventSMFImpl = &CDREventSMFImpl{ + cdrEventRepository: repository.NewCDREventSMFImpl, +} + +type CDREventSMFImpl struct { + // CDR会话事件数据信息 + cdrEventRepository repository.ICDREventSMF +} + +func (r *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any { + return r.cdrEventRepository.SelectPage(querys) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) (int64, error) { + // 检查是否存在 + ids := r.cdrEventRepository.SelectByIds(cdrIds) + if len(ids) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(ids) == len(cdrIds) { + rows := r.cdrEventRepository.DeleteByIds(cdrIds) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +}