package statistics import ( "net/http" "strconv" "time" "task-track-backend/model" "task-track-backend/pkg/database" "github.com/gin-gonic/gin" ) // TaskStatisticsResponse 任务统计响应 type TaskStatisticsResponse struct { // 基本统计 TotalTasks int64 `json:"total_tasks"` PendingTasks int64 `json:"pending_tasks"` InProgressTasks int64 `json:"in_progress_tasks"` CompletedTasks int64 `json:"completed_tasks"` CancelledTasks int64 `json:"cancelled_tasks"` // 按状态统计 TasksByStatus []TaskStatusStat `json:"tasks_by_status"` // 按优先级统计 TasksByPriority []TaskPriorityStat `json:"tasks_by_priority"` // 按类型统计 TasksByType []TaskTypeStat `json:"tasks_by_type"` // 按创建者统计 TasksByCreator []TaskCreatorStat `json:"tasks_by_creator"` // 按分配者统计 TasksByAssignee []TaskAssigneeStat `json:"tasks_by_assignee"` // 时间趋势统计(最近30天) DailyTrend []DailyTaskStat `json:"daily_trend"` // 完成率统计 CompletionRate float64 `json:"completion_rate"` // 平均完成时间(小时) AverageCompletionTime float64 `json:"average_completion_time"` // 逾期任务统计 OverdueTasks int64 `json:"overdue_tasks"` // 即将到期任务统计(7天内) UpcomingTasks int64 `json:"upcoming_tasks"` } // TaskStatusStat 任务状态统计 type TaskStatusStat struct { Status string `json:"status"` Count int64 `json:"count"` Percentage float64 `json:"percentage"` } // TaskPriorityStat 任务优先级统计 type TaskPriorityStat struct { Priority string `json:"priority"` Count int64 `json:"count"` Percentage float64 `json:"percentage"` } // TaskTypeStat 任务类型统计 type TaskTypeStat struct { Type string `json:"type"` Count int64 `json:"count"` Percentage float64 `json:"percentage"` } // TaskCreatorStat 任务创建者统计 type TaskCreatorStat struct { CreatorID uint `json:"creator_id"` CreatorName string `json:"creator_name"` Count int64 `json:"count"` } // TaskAssigneeStat 任务分配者统计 type TaskAssigneeStat struct { AssigneeID uint `json:"assignee_id"` AssigneeName string `json:"assignee_name"` Count int64 `json:"count"` } // DailyTaskStat 每日任务统计 type DailyTaskStat struct { Date string `json:"date"` Created int64 `json:"created"` Completed int64 `json:"completed"` } func (h *StatisticsHandler) GetTaskStatistics(c *gin.Context) { // 获取组织ID参数(可选) organizationIDStr := c.Query("organization_id") var organizationID uint if organizationIDStr != "" { if id, err := strconv.ParseUint(organizationIDStr, 10, 32); err == nil { organizationID = uint(id) } } // 获取时间范围参数 daysStr := c.DefaultQuery("days", "30") days, err := strconv.Atoi(daysStr) if err != nil { days = 30 } db := database.GetDB() var response TaskStatisticsResponse // 基础查询构建器 baseTaskQuery := db.Model(&model.Task{}) if organizationID > 0 { baseTaskQuery = baseTaskQuery.Where("organization_id = ?", organizationID) } // 1. 基本统计 if err := baseTaskQuery.Count(&response.TotalTasks).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取任务总数失败"}) return } // 各状态任务数 if err := baseTaskQuery.Where("status = ?", "pending").Count(&response.PendingTasks).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取待处理任务数失败"}) return } if err := baseTaskQuery.Where("status = ?", "in_progress").Count(&response.InProgressTasks).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取进行中任务数失败"}) return } if err := baseTaskQuery.Where("status = ?", "completed").Count(&response.CompletedTasks).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取已完成任务数失败"}) return } if err := baseTaskQuery.Where("status = ?", "cancelled").Count(&response.CancelledTasks).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取已取消任务数失败"}) return } // 2. 按状态统计 var statusStats []struct { Status string `json:"status"` Count int64 `json:"count"` } statusQuery := baseTaskQuery.Select("status, count(*) as count").Group("status") if err := statusQuery.Find(&statusStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取任务状态统计失败"}) return } response.TasksByStatus = make([]TaskStatusStat, len(statusStats)) for i, stat := range statusStats { percentage := float64(0) if response.TotalTasks > 0 { percentage = float64(stat.Count) / float64(response.TotalTasks) * 100 } response.TasksByStatus[i] = TaskStatusStat{ Status: stat.Status, Count: stat.Count, Percentage: percentage, } } // 3. 按优先级统计 var priorityStats []struct { Priority string `json:"priority"` Count int64 `json:"count"` } priorityQuery := baseTaskQuery.Select("priority, count(*) as count").Group("priority") if err := priorityQuery.Find(&priorityStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取任务优先级统计失败"}) return } response.TasksByPriority = make([]TaskPriorityStat, len(priorityStats)) for i, stat := range priorityStats { percentage := float64(0) if response.TotalTasks > 0 { percentage = float64(stat.Count) / float64(response.TotalTasks) * 100 } response.TasksByPriority[i] = TaskPriorityStat{ Priority: stat.Priority, Count: stat.Count, Percentage: percentage, } } // 4. 按类型统计 var typeStats []struct { Type string `json:"type"` Count int64 `json:"count"` } typeQuery := baseTaskQuery.Select("type, count(*) as count").Group("type") if err := typeQuery.Find(&typeStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取任务类型统计失败"}) return } response.TasksByType = make([]TaskTypeStat, len(typeStats)) for i, stat := range typeStats { percentage := float64(0) if response.TotalTasks > 0 { percentage = float64(stat.Count) / float64(response.TotalTasks) * 100 } response.TasksByType[i] = TaskTypeStat{ Type: stat.Type, Count: stat.Count, Percentage: percentage, } } // 5. 按创建者统计 var creatorStats []struct { CreatorID uint `json:"creator_id"` CreatorName string `json:"creator_name"` Count int64 `json:"count"` } creatorQuery := baseTaskQuery.Select("creator_id, users.real_name as creator_name, count(*) as count"). Joins("LEFT JOIN users ON tasks.creator_id = users.id"). Group("creator_id, users.real_name"). Order("count desc"). Limit(10) if err := creatorQuery.Find(&creatorStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取创建者统计失败"}) return } response.TasksByCreator = make([]TaskCreatorStat, len(creatorStats)) for i, stat := range creatorStats { response.TasksByCreator[i] = TaskCreatorStat{ CreatorID: stat.CreatorID, CreatorName: stat.CreatorName, Count: stat.Count, } } // 6. 按分配者统计 var assigneeStats []struct { AssigneeID uint `json:"assignee_id"` AssigneeName string `json:"assignee_name"` Count int64 `json:"count"` } assigneeQuery := baseTaskQuery.Select("assignee_id, users.real_name as assignee_name, count(*) as count"). Joins("LEFT JOIN users ON tasks.assignee_id = users.id"). Where("assignee_id IS NOT NULL"). Group("assignee_id, users.real_name"). Order("count desc"). Limit(10) if err := assigneeQuery.Find(&assigneeStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取分配者统计失败"}) return } response.TasksByAssignee = make([]TaskAssigneeStat, len(assigneeStats)) for i, stat := range assigneeStats { response.TasksByAssignee[i] = TaskAssigneeStat{ AssigneeID: stat.AssigneeID, AssigneeName: stat.AssigneeName, Count: stat.Count, } } // 7. 时间趋势统计 now := time.Now() startDate := now.AddDate(0, 0, -days) response.DailyTrend = make([]DailyTaskStat, 0) for i := 0; i < days; i++ { date := startDate.AddDate(0, 0, i) dateStr := date.Format("2006-01-02") // 当天创建的任务数 var createdCount int64 createdQuery := baseTaskQuery.Where("DATE(created_at) = ?", dateStr) if err := createdQuery.Count(&createdCount).Error; err != nil { createdCount = 0 } // 当天完成的任务数 var completedCount int64 completedQuery := baseTaskQuery.Where("status = ? AND DATE(updated_at) = ?", "completed", dateStr) if err := completedQuery.Count(&completedCount).Error; err != nil { completedCount = 0 } response.DailyTrend = append(response.DailyTrend, DailyTaskStat{ Date: dateStr, Created: createdCount, Completed: completedCount, }) } // 8. 完成率 if response.TotalTasks > 0 { response.CompletionRate = float64(response.CompletedTasks) / float64(response.TotalTasks) * 100 } // 9. 平均完成时间 var avgCompletionTime struct { AverageHours float64 `json:"average_hours"` } avgQuery := baseTaskQuery.Select("AVG(TIMESTAMPDIFF(HOUR, created_at, updated_at)) as average_hours"). Where("status = ?", "completed") if err := avgQuery.Scan(&avgCompletionTime).Error; err == nil { response.AverageCompletionTime = avgCompletionTime.AverageHours } // 10. 逾期任务统计 now = time.Now() overdueQuery := baseTaskQuery.Where("end_time < ? AND status != ?", now, "completed") if err := overdueQuery.Count(&response.OverdueTasks).Error; err != nil { response.OverdueTasks = 0 } // 11. 即将到期任务统计 sevenDaysLater := now.AddDate(0, 0, 7) upcomingQuery := baseTaskQuery.Where("end_time BETWEEN ? AND ? AND status != ?", now, sevenDaysLater, "completed") if err := upcomingQuery.Count(&response.UpcomingTasks).Error; err != nil { response.UpcomingTasks = 0 } c.JSON(http.StatusOK, response) }