feat: add send_stats table
This commit is contained in:
@@ -69,6 +69,7 @@ func Setup() {
|
|||||||
&models.HostedMessage{},
|
&models.HostedMessage{},
|
||||||
&models.LoginLog{},
|
&models.LoginLog{},
|
||||||
&models.Template{},
|
&models.Template{},
|
||||||
|
&models.SendStats{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"message-nest/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendStats 发送统计表
|
||||||
|
type SendStats struct {
|
||||||
|
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||||
|
TaskID *uint `json:"task_id" gorm:"type:bigint unsigned;index:idx_task_type_day_status"`
|
||||||
|
TaskType string `json:"task_type" gorm:"type:varchar(20);default:'task';index:idx_task_type_day_status;comment:'任务类型:task-发信任务,template-模板任务'"`
|
||||||
|
Day string `json:"day" gorm:"type:varchar(10);index:idx_task_type_day_status;index:idx_day_status"`
|
||||||
|
Status string `json:"status" gorm:"type:varchar(20);index:idx_task_type_day_status;index:idx_day_status"`
|
||||||
|
Num int64 `json:"num" gorm:"type:bigint;default:0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendStatsData 首页统计数据结构
|
||||||
|
type SendStatsData struct {
|
||||||
|
TodaySuccNum int64 `json:"today_succ_num"`
|
||||||
|
TodayFailedNum int64 `json:"today_failed_num"`
|
||||||
|
TodayTotalNum int64 `json:"today_total_num"`
|
||||||
|
TotalSuccNum int64 `json:"total_succ_num"`
|
||||||
|
TotalFailedNum int64 `json:"total_failed_num"`
|
||||||
|
TotalNum int64 `json:"total_num"`
|
||||||
|
DailyStats []DailyStatsData `json:"daily_stats"`
|
||||||
|
StatusStats []StatusStatsData `json:"status_stats"`
|
||||||
|
TaskTypeStats []TaskTypeStatsData `json:"task_type_stats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyStatsData 每日统计数据
|
||||||
|
type DailyStatsData struct {
|
||||||
|
Day string `json:"day"`
|
||||||
|
SuccNum int64 `json:"succ_num"`
|
||||||
|
FailedNum int64 `json:"failed_num"`
|
||||||
|
TotalNum int64 `json:"total_num"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusStatsData 状态统计数据
|
||||||
|
type StatusStatsData struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Num int64 `json:"num"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TaskTypeStatsData 任务类型统计数据
|
||||||
|
type TaskTypeStatsData struct {
|
||||||
|
TaskType string `json:"task_type"`
|
||||||
|
Num int64 `json:"num"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSendStatsData 获取发送统计数据
|
||||||
|
func GetSendStatsData(days int) (SendStatsData, error) {
|
||||||
|
var result SendStatsData
|
||||||
|
statsTable := GetSchema(SendStats{})
|
||||||
|
currDay := util.GetNowTimeStr()[:10]
|
||||||
|
|
||||||
|
// 今日统计
|
||||||
|
todayQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS today_succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS today_failed_num,
|
||||||
|
SUM(num) AS today_total_num
|
||||||
|
`).
|
||||||
|
Where("day = ?", currDay)
|
||||||
|
|
||||||
|
todayQuery.Scan(&result)
|
||||||
|
|
||||||
|
// 总计统计
|
||||||
|
totalQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS total_succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS total_failed_num,
|
||||||
|
SUM(num) AS total_num
|
||||||
|
`)
|
||||||
|
|
||||||
|
totalQuery.Scan(&result)
|
||||||
|
|
||||||
|
// 最近N天每日统计
|
||||||
|
if days > 0 {
|
||||||
|
now := util.GetNowTime()
|
||||||
|
past := now.AddDate(0, 0, -days)
|
||||||
|
pastDate := past.Format("2006-01-02")
|
||||||
|
|
||||||
|
var dailyStats []DailyStatsData
|
||||||
|
dailyQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
day,
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS failed_num,
|
||||||
|
SUM(num) AS total_num
|
||||||
|
`).
|
||||||
|
Where("day >= ?", pastDate).
|
||||||
|
Group("day").
|
||||||
|
Order("day DESC")
|
||||||
|
|
||||||
|
dailyQuery.Scan(&dailyStats)
|
||||||
|
result.DailyStats = dailyStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态分布统计
|
||||||
|
var statusStats []StatusStatsData
|
||||||
|
statusQuery := db.Table(statsTable).
|
||||||
|
Select("status, SUM(num) AS num").
|
||||||
|
Group("status").
|
||||||
|
Order("num DESC")
|
||||||
|
|
||||||
|
statusQuery.Scan(&statusStats)
|
||||||
|
result.StatusStats = statusStats
|
||||||
|
|
||||||
|
// 任务类型分布统计
|
||||||
|
var taskTypeStats []TaskTypeStatsData
|
||||||
|
taskTypeQuery := db.Table(statsTable).
|
||||||
|
Select("task_type, SUM(num) AS num").
|
||||||
|
Group("task_type").
|
||||||
|
Order("num DESC")
|
||||||
|
|
||||||
|
taskTypeQuery.Scan(&taskTypeStats)
|
||||||
|
result.TaskTypeStats = taskTypeStats
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSendStatsByTask 获取指定任务的统计数据
|
||||||
|
func GetSendStatsByTask(taskID uint, days int) (SendStatsData, error) {
|
||||||
|
var result SendStatsData
|
||||||
|
statsTable := GetSchema(SendStats{})
|
||||||
|
currDay := util.GetNowTimeStr()[:10]
|
||||||
|
|
||||||
|
// 今日统计
|
||||||
|
todayQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS today_succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS today_failed_num,
|
||||||
|
SUM(num) AS today_total_num
|
||||||
|
`).
|
||||||
|
Where("day = ? AND task_id = ?", currDay, taskID)
|
||||||
|
|
||||||
|
todayQuery.Scan(&result)
|
||||||
|
|
||||||
|
// 总计统计
|
||||||
|
totalQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS total_succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS total_failed_num,
|
||||||
|
SUM(num) AS total_num
|
||||||
|
`).
|
||||||
|
Where("task_id = ?", taskID)
|
||||||
|
|
||||||
|
totalQuery.Scan(&result)
|
||||||
|
|
||||||
|
// 最近N天每日统计
|
||||||
|
if days > 0 {
|
||||||
|
now := util.GetNowTime()
|
||||||
|
past := now.AddDate(0, 0, -days)
|
||||||
|
pastDate := past.Format("2006-01-02")
|
||||||
|
|
||||||
|
var dailyStats []DailyStatsData
|
||||||
|
dailyQuery := db.Table(statsTable).
|
||||||
|
Select(`
|
||||||
|
day,
|
||||||
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS succ_num,
|
||||||
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS failed_num,
|
||||||
|
SUM(num) AS total_num
|
||||||
|
`).
|
||||||
|
Where("day >= ? AND task_id = ?", pastDate, taskID).
|
||||||
|
Group("day").
|
||||||
|
Order("day DESC")
|
||||||
|
|
||||||
|
dailyQuery.Scan(&dailyStats)
|
||||||
|
result.DailyStats = dailyStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态分布统计
|
||||||
|
var statusStats []StatusStatsData
|
||||||
|
statusQuery := db.Table(statsTable).
|
||||||
|
Select("status, SUM(num) AS num").
|
||||||
|
Where("task_id = ?", taskID).
|
||||||
|
Group("status").
|
||||||
|
Order("num DESC")
|
||||||
|
|
||||||
|
statusQuery.Scan(&statusStats)
|
||||||
|
result.StatusStats = statusStats
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncrementSendStats 增加发送统计(用于实时更新统计数据)
|
||||||
|
func IncrementSendStats(taskID *uint, taskType string, day string, status string, num int64) error {
|
||||||
|
statsTable := GetSchema(SendStats{})
|
||||||
|
|
||||||
|
// 使用 ON DUPLICATE KEY UPDATE 或 UPSERT 逻辑
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
INSERT INTO %s (task_id, task_type, day, status, num)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE num = num + ?
|
||||||
|
`, statsTable)
|
||||||
|
|
||||||
|
return db.Exec(query, taskID, taskType, day, status, num, num).Error
|
||||||
|
}
|
||||||
+41
-20
@@ -317,27 +317,27 @@ func GetBasicStatisticData() (BasicStatisticData, error) {
|
|||||||
return statistic, nil
|
return statistic, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrendStatisticData 获取趋势统计数据
|
// GetTrendStatisticData 获取趋势统计数据(使用 send_stats 表)
|
||||||
func GetTrendStatisticData() (TrendStatisticData, error) {
|
func GetTrendStatisticData() (TrendStatisticData, error) {
|
||||||
var statistic TrendStatisticData
|
var statistic TrendStatisticData
|
||||||
var latestData []LatestSendData
|
var latestData []LatestSendData
|
||||||
logt := GetSchema(SendTasksLogs{})
|
statsTable := GetSchema(SendStats{})
|
||||||
|
|
||||||
// 最近30天数据
|
// 最近30天数据
|
||||||
days := 30
|
days := 30
|
||||||
now := util.GetNowTime()
|
now := util.GetNowTime()
|
||||||
past := now.AddDate(0, 0, -days)
|
past := now.AddDate(0, 0, -days)
|
||||||
pastDate := past.Format("2006-01-02")
|
pastDate := past.Format("2006-01-02")
|
||||||
next := now.AddDate(0, 0, 1)
|
|
||||||
nextDate := next.Format("2006-01-02")
|
|
||||||
queryData := db.
|
queryData := db.
|
||||||
Table(logt).
|
Table(statsTable).
|
||||||
Select(`
|
Select(`
|
||||||
CAST(DATE(created_on) AS CHAR) AS day,
|
day,
|
||||||
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS day_succ_num,
|
SUM(CASE WHEN status = 'success' THEN num ELSE 0 END) AS day_succ_num,
|
||||||
SUM(CASE WHEN status != 1 or status is null THEN 1 ELSE 0 END) AS day_failed_num,
|
SUM(CASE WHEN status = 'failed' THEN num ELSE 0 END) AS day_failed_num,
|
||||||
COUNT(*) AS num`).
|
SUM(num) AS num
|
||||||
Where(fmt.Sprintf(" created_on >= '%s' and created_on <= '%s' ", pastDate, nextDate)).
|
`).
|
||||||
|
Where("day >= ?", pastDate).
|
||||||
Group("day").
|
Group("day").
|
||||||
Order("day")
|
Order("day")
|
||||||
|
|
||||||
@@ -346,21 +346,42 @@ func GetTrendStatisticData() (TrendStatisticData, error) {
|
|||||||
return statistic, nil
|
return statistic, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelStatisticData 获取渠道统计数据(包含任务实例和模板实例)
|
// GetChannelStatisticData 获取渠道统计数据(使用 send_stats 表的任务类型统计)
|
||||||
func GetChannelStatisticData() (ChannelStatisticData, error) {
|
func GetChannelStatisticData() (ChannelStatisticData, error) {
|
||||||
var statistic ChannelStatisticData
|
var statistic ChannelStatisticData
|
||||||
var wayCateData []WayCateData
|
var wayCateData []WayCateData
|
||||||
inst := GetSchema(SendTasksIns{})
|
statsTable := GetSchema(SendStats{})
|
||||||
wayst := GetSchema(SendWays{})
|
|
||||||
|
// 任务类型映射
|
||||||
|
taskTypeMap := map[string]string{
|
||||||
|
"task": "发信任务",
|
||||||
|
"template": "模板任务",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计任务类型分布
|
||||||
|
var taskTypeStats []struct {
|
||||||
|
TaskType string
|
||||||
|
Num int64
|
||||||
|
}
|
||||||
|
|
||||||
// 统计所有实例的渠道分布(包含任务实例和模板实例)
|
|
||||||
// 不区分 task_id 和 template_id,统计所有关联到渠道的实例
|
|
||||||
db.
|
db.
|
||||||
Table(inst).
|
Table(statsTable).
|
||||||
Select(fmt.Sprintf("%s.name as way_name, count(%s.id) as count_num", wayst, inst)).
|
Select("task_type, SUM(num) AS num").
|
||||||
Joins(fmt.Sprintf("JOIN %s ON %s.way_id = %s.id", wayst, inst, wayst)).
|
Group("task_type").
|
||||||
Group(fmt.Sprintf("%s.id", wayst)).
|
Order("num DESC").
|
||||||
Scan(&wayCateData)
|
Scan(&taskTypeStats)
|
||||||
|
|
||||||
|
// 转换为 WayCateData 格式(复用前端已有的数据结构)
|
||||||
|
for _, stat := range taskTypeStats {
|
||||||
|
wayName := taskTypeMap[stat.TaskType]
|
||||||
|
if wayName == "" {
|
||||||
|
wayName = stat.TaskType
|
||||||
|
}
|
||||||
|
wayCateData = append(wayCateData, WayCateData{
|
||||||
|
WayName: wayName,
|
||||||
|
CountNum: int(stat.Num),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
statistic.WayCateData = wayCateData
|
statistic.WayCateData = wayCateData
|
||||||
return statistic, nil
|
return statistic, nil
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ func GetStatisticData(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
appG.CResponse(http.StatusOK, "获取渠道统计成功", data)
|
appG.CResponse(http.StatusOK, "获取渠道统计成功", data)
|
||||||
|
case "send_stats":
|
||||||
|
// 新增:基于 send_stats 表的统计数据
|
||||||
|
data, err := msgService.GetSendStatsData()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusInternalServerError, fmt.Sprintf("获取发送统计失败!原因:%s", err), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appG.CResponse(http.StatusOK, "获取发送统计成功", data)
|
||||||
default:
|
default:
|
||||||
// 默认返回完整统计数据(保持向后兼容)
|
// 默认返回完整统计数据(保持向后兼容)
|
||||||
data, err := msgService.GetStatisticData()
|
data, err := msgService.GetStatisticData()
|
||||||
@@ -52,3 +60,28 @@ func GetStatisticData(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSendStatsByTask 获取指定任务的发送统计数据
|
||||||
|
func GetSendStatsByTask(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
appG = app.Gin{C: c}
|
||||||
|
)
|
||||||
|
|
||||||
|
taskID := c.Query("task_id")
|
||||||
|
if taskID == "" {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "任务ID不能为空", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msgService := statistic_service.StatisticService{
|
||||||
|
TaskID: taskID,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := msgService.GetSendStatsByTask()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusInternalServerError, fmt.Sprintf("获取任务统计失败!原因:%s", err), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
appG.CResponse(http.StatusOK, "获取任务统计成功", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ func InitRouter(f embed.FS) *gin.Engine {
|
|||||||
|
|
||||||
// statistic
|
// statistic
|
||||||
apiV1.GET("/statistic", v1.GetStatisticData)
|
apiV1.GET("/statistic", v1.GetStatisticData)
|
||||||
|
apiV1.GET("/statistic/task", v1.GetSendStatsByTask)
|
||||||
|
|
||||||
// cronMessage
|
// cronMessage
|
||||||
apiV1.POST("/cronmessages/addone", v1.AddCronMsgTask)
|
apiV1.POST("/cronmessages/addone", v1.AddCronMsgTask)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"message-nest/models"
|
"message-nest/models"
|
||||||
"message-nest/pkg/constant"
|
"message-nest/pkg/constant"
|
||||||
|
"message-nest/pkg/util"
|
||||||
"message-nest/service/send_message_service/unified"
|
"message-nest/service/send_message_service/unified"
|
||||||
"message-nest/service/send_task_service"
|
"message-nest/service/send_task_service"
|
||||||
"message-nest/service/send_way_service"
|
"message-nest/service/send_way_service"
|
||||||
@@ -294,6 +295,8 @@ func (sm *SendMessageService) Send(task models.TaskIns) (string, error) {
|
|||||||
sm.AppendSendContent()
|
sm.AppendSendContent()
|
||||||
// 日志写到数据库
|
// 日志写到数据库
|
||||||
sm.RecordSendLog()
|
sm.RecordSendLog()
|
||||||
|
// 更新统计数据(任务级别:一次任务算一次)
|
||||||
|
sm.UpdateSendStats()
|
||||||
|
|
||||||
totalOutputLog := strings.Join(sm.LogOutput, "\n")
|
totalOutputLog := strings.Join(sm.LogOutput, "\n")
|
||||||
if sm.Status == SendSuccess {
|
if sm.Status == SendSuccess {
|
||||||
@@ -339,6 +342,49 @@ func (sm *SendMessageService) RecordSendLog() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateSendStats 更新发送统计数据(任务级别)
|
||||||
|
func (sm *SendMessageService) UpdateSendStats() {
|
||||||
|
// 获取当前日期
|
||||||
|
currentDay := sm.getCurrentDay()
|
||||||
|
|
||||||
|
// 解析任务ID(如果是数字ID)
|
||||||
|
var taskID *uint
|
||||||
|
if sm.TaskID != "" {
|
||||||
|
// 尝试将字符串ID转换为uint(如果是数字ID)
|
||||||
|
var id uint64
|
||||||
|
_, err := fmt.Sscanf(sm.TaskID, "%d", &id)
|
||||||
|
if err == nil {
|
||||||
|
taskIDValue := uint(id)
|
||||||
|
taskID = &taskIDValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定任务类型
|
||||||
|
taskType := "task"
|
||||||
|
if sm.SendMode == SendModeTemplate {
|
||||||
|
taskType = "template"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据任务的最终状态更新统计(一次任务只记录一次)
|
||||||
|
var status string
|
||||||
|
if sm.Status == SendSuccess {
|
||||||
|
status = "success"
|
||||||
|
} else {
|
||||||
|
status = "failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新统计:每次任务执行记录为1次
|
||||||
|
err := models.IncrementSendStats(taskID, taskType, currentDay, status, 1)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("更新发送统计失败:%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCurrentDay 获取当前日期(YYYY-MM-DD格式)
|
||||||
|
func (sm *SendMessageService) getCurrentDay() string {
|
||||||
|
return util.GetNowTimeStr()[:10]
|
||||||
|
}
|
||||||
|
|
||||||
// TransError 转化错误
|
// TransError 转化错误
|
||||||
func (sm *SendMessageService) TransError(err string) string {
|
func (sm *SendMessageService) TransError(err string) string {
|
||||||
if err == "" {
|
if err == "" {
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package statistic_service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"message-nest/models"
|
"message-nest/models"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatisticService struct {
|
type StatisticService struct {
|
||||||
|
TaskID string
|
||||||
|
Days int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *StatisticService) GetStatisticData() (models.StatisticData, error) {
|
func (sw *StatisticService) GetStatisticData() (models.StatisticData, error) {
|
||||||
@@ -25,3 +28,27 @@ func (sw *StatisticService) GetTrendStatisticData() (models.TrendStatisticData,
|
|||||||
func (sw *StatisticService) GetChannelStatisticData() (models.ChannelStatisticData, error) {
|
func (sw *StatisticService) GetChannelStatisticData() (models.ChannelStatisticData, error) {
|
||||||
return models.GetChannelStatisticData()
|
return models.GetChannelStatisticData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSendStatsData 获取发送统计数据(基于 send_stats 表)
|
||||||
|
func (sw *StatisticService) GetSendStatsData() (models.SendStatsData, error) {
|
||||||
|
days := sw.Days
|
||||||
|
if days <= 0 {
|
||||||
|
days = 30 // 默认30天
|
||||||
|
}
|
||||||
|
return models.GetSendStatsData(days)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSendStatsByTask 获取指定任务的发送统计数据
|
||||||
|
func (sw *StatisticService) GetSendStatsByTask() (models.SendStatsData, error) {
|
||||||
|
days := sw.Days
|
||||||
|
if days <= 0 {
|
||||||
|
days = 30 // 默认30天
|
||||||
|
}
|
||||||
|
|
||||||
|
taskID, err := strconv.ParseUint(sw.TaskID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return models.SendStatsData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return models.GetSendStatsByTask(uint(taskID), days)
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ let state = reactive({
|
|||||||
today_failed_num: 0,
|
today_failed_num: 0,
|
||||||
},
|
},
|
||||||
trendData: {
|
trendData: {
|
||||||
latest_send_data: [] as SendData[],
|
latest_send_data: [] as SendData[] | null,
|
||||||
},
|
},
|
||||||
channelData: {
|
channelData: {
|
||||||
way_cate_data: [] as CateData[],
|
way_cate_data: [] as CateData[] | null,
|
||||||
},
|
},
|
||||||
loading: {
|
loading: {
|
||||||
basic: false,
|
basic: false,
|
||||||
@@ -111,24 +111,25 @@ const loadAllStatisticData = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderLineChart = () => {
|
const renderLineChart = () => {
|
||||||
|
const latestSendData = state.trendData.latest_send_data || [];
|
||||||
const options = {
|
const options = {
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: '发送总数',
|
name: '发送总数',
|
||||||
data: state.trendData.latest_send_data.length > 0
|
data: latestSendData.length > 0
|
||||||
? state.trendData.latest_send_data.map(item => item.num || 0)
|
? latestSendData.map(item => item.num || 0)
|
||||||
: []
|
: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '发送成功数',
|
name: '发送成功数',
|
||||||
data: state.trendData.latest_send_data.length > 0
|
data: latestSendData.length > 0
|
||||||
? state.trendData.latest_send_data.map(item => item.day_succ_num || 0)
|
? latestSendData.map(item => item.day_succ_num || 0)
|
||||||
: []
|
: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '发送失败数',
|
name: '发送失败数',
|
||||||
data: state.trendData.latest_send_data.length > 0
|
data: latestSendData.length > 0
|
||||||
? state.trendData.latest_send_data.map(item => item.day_failed_num || 0)
|
? latestSendData.map(item => item.day_failed_num || 0)
|
||||||
: []
|
: []
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -175,8 +176,8 @@ const renderLineChart = () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
categories: state.trendData.latest_send_data.length > 0
|
categories: latestSendData.length > 0
|
||||||
? state.trendData.latest_send_data.map(item => item.day)
|
? latestSendData.map(item => item.day)
|
||||||
: [],
|
: [],
|
||||||
axisBorder: {
|
axisBorder: {
|
||||||
show: false
|
show: false
|
||||||
@@ -332,9 +333,10 @@ const renderLineChart = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderPieChart = () => {
|
const renderPieChart = () => {
|
||||||
|
const wayCateData = state.channelData.way_cate_data || [];
|
||||||
const options = {
|
const options = {
|
||||||
series: state.channelData.way_cate_data.length > 0
|
series: wayCateData.length > 0
|
||||||
? state.channelData.way_cate_data.map(item => item.count_num)
|
? wayCateData.map(item => item.count_num)
|
||||||
: [],
|
: [],
|
||||||
chart: {
|
chart: {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
@@ -355,8 +357,8 @@ const renderPieChart = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
labels: state.channelData.way_cate_data.length > 0
|
labels: wayCateData.length > 0
|
||||||
? state.channelData.way_cate_data.map(item => item.way_name)
|
? wayCateData.map(item => item.way_name)
|
||||||
: [],
|
: [],
|
||||||
colors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
|
colors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
Reference in New Issue
Block a user