Files
be.ems/src/modules/network_data/service/cdr_event_ims.go
2025-09-22 11:22:28 +08:00

336 lines
9.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"encoding/json"
"fmt"
"strconv"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
sysService "be.ems/src/modules/system/service"
)
// 实例化数据层 CDREventIMS 结构体
var NewCDREventIMS = &CDREventIMS{
cdrEventIMSRepository: repository.NewCDREventIMS,
}
// CDREventImpl CDR会话事件IMS 服务层处理
type CDREventIMS struct {
cdrEventIMSRepository *repository.CDREventIMS // CDR会话事件数据信息
}
// SelectPage 根据条件分页查询
func (r *CDREventIMS) SelectPageMT(querys model.CDREventIMSQuery) map[string]any {
return r.cdrEventIMSRepository.SelectPage(querys)
}
// SelectPage 根据条件分页查询
func (r *CDREventIMS) SelectPage(querys model.CDREventIMSQuery) ([]model.CDREventIMS, int64) {
return r.cdrEventIMSRepository.SelectByPage(querys)
}
// DeleteByIds 批量删除信息
func (r *CDREventIMS) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventIMSRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventIMSRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
// ExportXlsx 导出数据到 xlsx 文件
func (r CDREventIMS) ExportXlsx(rows []model.CDREventIMS, fileName, language string) (string, error) {
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "Record Behavior",
"C1": "Type",
"D1": "Caller",
"E1": "Called",
"F1": "Duration",
"G1": "Result Code",
"H1": "Result Cause",
"I1": "MOS Average",
"J1": "Call Connection Time",
"K1": "Call Start Time",
"L1": "Hangup Time",
}
// 读取字典数据 CDR SIP响应代码类别类型
dictCDRSipCode := sysService.NewSysDictData.SelectDictDataByType("cdr_sip_code")
dictCDRSipCodeCause := sysService.NewSysDictData.SelectDictDataByType("cdr_sip_code_cause")
// 读取字典数据 CDR 呼叫类型
dictCDRCallType := sysService.NewSysDictData.SelectDictDataByType("cdr_call_type")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 记录类型
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = v.(string)
}
// 呼叫类型
callType := "sms"
callTypeLable := "SMS"
if v, ok := cdrJSON["callType"]; ok && v != nil {
callType = v.(string)
for _, v := range dictCDRCallType {
if callType == v.DictValue {
callTypeLable = i18n.TKey(language, v.DictLabel)
break
}
}
}
// 被叫
called := ""
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
called = v.(string)
}
// 主叫
caller := ""
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
caller = v.(string)
}
// 时长
duration := "-"
if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
duration = fmt.Sprintf("%ds", parse.Number(v))
}
// 呼叫结果 非短信都有code作为结果 sms短信都ok
// 呼叫结果 非短信都有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.DictValue {
callResult = i18n.TKey(language, v.DictLabel)
break
}
}
for _, v := range dictCDRSipCodeCause {
if cause == v.DictValue {
callCause = i18n.TKey(language, v.DictLabel)
break
}
}
}
}
// 呼叫时间
seizureTimeStr := ""
if v, ok := cdrJSON["seizureTime"]; ok && v != nil {
if seizureTime := parse.Number(v); seizureTime > 0 {
seizureTimeStr = date.ParseDateToStr(seizureTime, date.YYYY_MM_DD_HH_MM_SS_GMT_TZ)
} 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_DD_HH_MM_SS_GMT_TZ)
} else {
releaseTimeStr = v.(string)
}
}
// 通话质量
var mosAverage int64 = 0
if v, ok := cdrJSON["mosAverage"]; ok && v != nil && callType != "sms" {
mosAverage = parse.Number(v)
}
// 通话连接时间
callConnectionTime := "-"
if v, ok := cdrJSON["callConnectionTime"]; ok && v != nil && callType != "sms" {
callConnectionTime = fmt.Sprintf("%ds", parse.Number(v))
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: recordType,
"C" + idx: callTypeLable,
"D" + idx: caller,
"E" + idx: called,
"F" + idx: duration,
"G" + idx: callResult,
"H" + idx: callCause,
"I" + idx: mosAverage,
"J" + idx: callConnectionTime,
"K" + idx: seizureTimeStr,
"L" + idx: releaseTimeStr,
})
}
// 导出数据表格
return file.WriteSheet(headerCells, dataCells, fileName, "")
}
// CDRMOSHour CDR MOS 统计
func (r CDREventIMS) CDRMOSHour(rmUID string, timestamp int64) []map[string]any {
t := time.UnixMilli(timestamp)
beginTime := t
endTime := t
// 检查时分秒是否都为零
if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 {
// 获取当天起始时间00:00:00
beginTime = t.Truncate(time.Hour)
// 计算当天结束时间23:59:59
endTime = beginTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
} else {
// 起始时间:当前小时的 00 分 00 秒
beginTime = t.Truncate(time.Hour)
// 结束时间:当前小时的 59 分 59 秒 999 毫秒
endTime = beginTime.Add(time.Hour - time.Millisecond)
}
querys := model.CDREventIMSQuery{
RmUID: rmUID,
RecordType: "MOC",
StartTime: beginTime.Unix(),
EndTime: endTime.Unix(),
}
rows := r.cdrEventIMSRepository.Select(querys)
// 创建一个map来存储按时间段合并后的数据
timeGroup := make(map[int64]map[string]float64)
// 遍历每个数据项
for _, row := range rows {
// 将毫秒时间戳转换为小时级时间戳(保留到小时的起始毫秒)
timeHour := row.Timestamp / 3600 * 3600 // 1小时 = 3600000毫秒
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON)
if err != nil {
logger.Warnf("Unmarshal JSON: %s", err.Error())
continue
}
// 记录类型
var mosAverage float64 = 0
if v, ok := cdrJSON["mosAverage"]; ok && v != nil {
mosAverage = v.(float64)
} else {
continue
}
// 合并到对应的小时段
if _, exists := timeGroup[timeHour]; !exists {
timeGroup[timeHour] = map[string]float64{
"total": 0,
"mosSum": 0,
}
}
timeGroup[timeHour]["total"] += 1
timeGroup[timeHour]["mosSum"] += mosAverage
}
// 时间组合输出
data := make([]map[string]any, 0, len(timeGroup))
for hour, sums := range timeGroup {
data = append(data, map[string]any{
"timeGroup": fmt.Sprintf("%d", hour),
"total": sums["total"],
"mosSum": float64(int(sums["mosSum"]*100)) / 100,
"mosAvg": float64(int(sums["mosSum"]/sums["total"]*100)) / 100,
})
}
return data
}
// CDRCCTHour CDR CCT 统计
func (r CDREventIMS) CDRCCTHour(rmUID string, timestamp int64) []map[string]any {
t := time.UnixMilli(timestamp)
beginTime := t
endTime := t
// 检查时分秒是否都为零
if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 {
// 获取当天起始时间00:00:00
beginTime = t.Truncate(time.Hour)
// 计算当天结束时间23:59:59
endTime = beginTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
} else {
// 起始时间:当前小时的 00 分 00 秒
beginTime = t.Truncate(time.Hour)
// 结束时间:当前小时的 59 分 59 秒 999 毫秒
endTime = beginTime.Add(time.Hour - time.Millisecond)
}
querys := model.CDREventIMSQuery{
RmUID: rmUID,
RecordType: "MOC",
StartTime: beginTime.Unix(),
EndTime: endTime.Unix(),
}
rows := r.cdrEventIMSRepository.Select(querys)
// 创建一个map来存储按时间段合并后的数据
timeGroup := make(map[int64]map[string]float64)
// 遍历每个数据项
for _, row := range rows {
// 将毫秒时间戳转换为小时级时间戳(保留到小时的起始毫秒)
timeHour := row.Timestamp / 3600 * 3600 // 1小时 = 3600000毫秒
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON)
if err != nil {
logger.Warnf("Unmarshal JSON: %s", err.Error())
continue
}
// 记录类型
var callConnectionTime float64 = 0
if v, ok := cdrJSON["callConnectionTime"]; ok && v != nil {
callConnectionTime = v.(float64)
} else {
continue
}
// 合并到对应的小时段
if _, exists := timeGroup[timeHour]; !exists {
timeGroup[timeHour] = map[string]float64{
"total": 0,
"cctSum": 0,
}
}
timeGroup[timeHour]["total"] += 1
timeGroup[timeHour]["cctSum"] += callConnectionTime
}
// 时间组合输出
data := make([]map[string]any, 0, len(timeGroup))
for hour, sums := range timeGroup {
data = append(data, map[string]any{
"timeGroup": fmt.Sprintf("%d", hour),
"total": sums["total"],
"cctSum": float64(int(sums["cctSum"]*100)) / 100,
"cctAvg": float64(int(sums["cctSum"]/sums["total"]*100)) / 100,
})
}
return data
}