package statistics import ( "fmt" "net/http" "strconv" "time" "task-track-backend/model" "task-track-backend/pkg/database" "github.com/gin-gonic/gin" ) // UserStatisticsResponse 用户统计响应 type UserStatisticsResponse struct { // 基本统计 TotalUsers int64 `json:"total_users"` ActiveUsers int64 `json:"active_users"` // 最近30天有活动的用户 // 用户任务统计 UserTaskStats []UserTaskStat `json:"user_task_stats"` // 用户效率统计 UserEfficiencyStats []UserEfficiencyStat `json:"user_efficiency_stats"` // 用户活跃度统计 UserActivityStats []UserActivityStat `json:"user_activity_stats"` // 用户完成率排行 UserCompletionRank []UserCompletionRank `json:"user_completion_rank"` // 用户任务分配统计 UserAssignmentStats []UserAssignmentStat `json:"user_assignment_stats"` // 总体用户效率指标 OverallEfficiency struct { AverageCompletionRate float64 `json:"average_completion_rate"` AverageTasksPerUser float64 `json:"average_tasks_per_user"` AverageCompletionTime float64 `json:"average_completion_time"` } `json:"overall_efficiency"` } // UserTaskStat 用户任务统计 type UserTaskStat struct { UserID uint `json:"user_id"` Username string `json:"username"` RealName string `json:"real_name"` CreatedTasks int64 `json:"created_tasks"` AssignedTasks int64 `json:"assigned_tasks"` CompletedTasks int64 `json:"completed_tasks"` PendingTasks int64 `json:"pending_tasks"` InProgressTasks int64 `json:"in_progress_tasks"` } // UserEfficiencyStat 用户效率统计 type UserEfficiencyStat struct { UserID uint `json:"user_id"` Username string `json:"username"` RealName string `json:"real_name"` CompletionRate float64 `json:"completion_rate"` AverageCompletionTime float64 `json:"average_completion_time"` TasksCompletedThisWeek int64 `json:"tasks_completed_this_week"` TasksCompletedThisMonth int64 `json:"tasks_completed_this_month"` } // UserActivityStat 用户活跃度统计 type UserActivityStat struct { UserID uint `json:"user_id"` Username string `json:"username"` RealName string `json:"real_name"` LastActivity time.Time `json:"last_activity"` CommentsCount int64 `json:"comments_count"` TasksCreatedThisWeek int64 `json:"tasks_created_this_week"` TasksCreatedThisMonth int64 `json:"tasks_created_this_month"` } // UserCompletionRank 用户完成率排行 type UserCompletionRank struct { UserID uint `json:"user_id"` Username string `json:"username"` RealName string `json:"real_name"` CompletionRate float64 `json:"completion_rate"` CompletedTasks int64 `json:"completed_tasks"` TotalTasks int64 `json:"total_tasks"` Rank int `json:"rank"` } // UserAssignmentStat 用户任务分配统计 type UserAssignmentStat struct { UserID uint `json:"user_id"` Username string `json:"username"` RealName string `json:"real_name"` UrgentTasks int64 `json:"urgent_tasks"` HighPriorityTasks int64 `json:"high_priority_tasks"` MediumPriorityTasks int64 `json:"medium_priority_tasks"` LowPriorityTasks int64 `json:"low_priority_tasks"` OverdueTasks int64 `json:"overdue_tasks"` } func (h *StatisticsHandler) GetUserStatistics(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) } } // 获取用户ID参数(可选,如果提供则只查询该用户) userIDStr := c.Query("user_id") var userID uint if userIDStr != "" { if id, err := strconv.ParseUint(userIDStr, 10, 32); err == nil { userID = uint(id) } } db := database.GetDB() var response UserStatisticsResponse // 基础用户查询构建器 baseUserQuery := db.Model(&model.User{}) if organizationID > 0 { baseUserQuery = baseUserQuery.Joins("JOIN user_organizations ON users.id = user_organizations.user_id"). Where("user_organizations.organization_id = ?", organizationID) } if userID > 0 { baseUserQuery = baseUserQuery.Where("users.id = ?", userID) } // 1. 基本统计 if err := baseUserQuery.Count(&response.TotalUsers).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户总数失败"}) return } // 活跃用户数(最近30天有任务活动) thirtyDaysAgo := time.Now().AddDate(0, 0, -30) activeUserQuery := baseUserQuery.Joins("JOIN tasks ON users.id = tasks.creator_id OR users.id = tasks.assignee_id"). Where("tasks.created_at >= ? OR tasks.updated_at >= ?", thirtyDaysAgo, thirtyDaysAgo). Distinct("users.id") if err := activeUserQuery.Count(&response.ActiveUsers).Error; err != nil { response.ActiveUsers = 0 } // 2. 用户任务统计 var userTaskStats []UserTaskStat // 构建用户任务统计查询 userTaskQuery := ` SELECT u.id as user_id, u.username, u.real_name, COALESCE(created_tasks.count, 0) as created_tasks, COALESCE(assigned_tasks.count, 0) as assigned_tasks, COALESCE(completed_tasks.count, 0) as completed_tasks, COALESCE(pending_tasks.count, 0) as pending_tasks, COALESCE(in_progress_tasks.count, 0) as in_progress_tasks FROM users u LEFT JOIN ( SELECT creator_id, COUNT(*) as count FROM tasks WHERE 1=1 %s GROUP BY creator_id ) created_tasks ON u.id = created_tasks.creator_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL %s GROUP BY assignee_id ) assigned_tasks ON u.id = assigned_tasks.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'completed' %s GROUP BY assignee_id ) completed_tasks ON u.id = completed_tasks.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'pending' %s GROUP BY assignee_id ) pending_tasks ON u.id = pending_tasks.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'in_progress' %s GROUP BY assignee_id ) in_progress_tasks ON u.id = in_progress_tasks.assignee_id WHERE 1=1 %s ORDER BY (COALESCE(created_tasks.count, 0) + COALESCE(assigned_tasks.count, 0)) DESC LIMIT 20 ` // 构建WHERE条件 orgCondition := "" userCondition := "" if organizationID > 0 { orgCondition = "AND organization_id = " + strconv.FormatUint(uint64(organizationID), 10) } if userID > 0 { userCondition = "AND u.id = " + strconv.FormatUint(uint64(userID), 10) } finalQuery := fmt.Sprintf(userTaskQuery, orgCondition, orgCondition, orgCondition, orgCondition, orgCondition, userCondition) if err := db.Raw(finalQuery).Scan(&userTaskStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户任务统计失败"}) return } response.UserTaskStats = userTaskStats // 3. 用户效率统计 var userEfficiencyStats []UserEfficiencyStat now := time.Now() weekStart := now.AddDate(0, 0, -int(now.Weekday())+1) monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) efficiencyQuery := ` SELECT u.id as user_id, u.username, u.real_name, CASE WHEN total_assigned.count > 0 THEN (completed_assigned.count * 100.0 / total_assigned.count) ELSE 0 END as completion_rate, COALESCE(avg_completion.avg_hours, 0) as average_completion_time, COALESCE(week_completed.count, 0) as tasks_completed_this_week, COALESCE(month_completed.count, 0) as tasks_completed_this_month FROM users u LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL %s GROUP BY assignee_id ) total_assigned ON u.id = total_assigned.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'completed' %s GROUP BY assignee_id ) completed_assigned ON u.id = completed_assigned.assignee_id LEFT JOIN ( SELECT assignee_id, AVG(TIMESTAMPDIFF(HOUR, created_at, updated_at)) as avg_hours FROM tasks WHERE assignee_id IS NOT NULL AND status = 'completed' %s GROUP BY assignee_id ) avg_completion ON u.id = avg_completion.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'completed' AND updated_at >= '%s' %s GROUP BY assignee_id ) week_completed ON u.id = week_completed.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND status = 'completed' AND updated_at >= '%s' %s GROUP BY assignee_id ) month_completed ON u.id = month_completed.assignee_id WHERE 1=1 %s HAVING total_assigned.count > 0 ORDER BY completion_rate DESC LIMIT 20 ` finalEfficiencyQuery := fmt.Sprintf(efficiencyQuery, orgCondition, orgCondition, orgCondition, weekStart.Format("2006-01-02"), orgCondition, monthStart.Format("2006-01-02"), orgCondition, userCondition) if err := db.Raw(finalEfficiencyQuery).Scan(&userEfficiencyStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户效率统计失败"}) return } response.UserEfficiencyStats = userEfficiencyStats // 4. 用户活跃度统计 var userActivityStats []UserActivityStat activityQuery := ` SELECT u.id as user_id, u.username, u.real_name, COALESCE(MAX(GREATEST(t.created_at, t.updated_at)), u.created_at) as last_activity, COALESCE(comments.count, 0) as comments_count, COALESCE(week_created.count, 0) as tasks_created_this_week, COALESCE(month_created.count, 0) as tasks_created_this_month FROM users u LEFT JOIN tasks t ON u.id = t.creator_id OR u.id = t.assignee_id LEFT JOIN ( SELECT user_id, COUNT(*) as count FROM task_comments GROUP BY user_id ) comments ON u.id = comments.user_id LEFT JOIN ( SELECT creator_id, COUNT(*) as count FROM tasks WHERE created_at >= '%s' %s GROUP BY creator_id ) week_created ON u.id = week_created.creator_id LEFT JOIN ( SELECT creator_id, COUNT(*) as count FROM tasks WHERE created_at >= '%s' %s GROUP BY creator_id ) month_created ON u.id = month_created.creator_id WHERE 1=1 %s GROUP BY u.id, u.username, u.real_name, u.created_at, comments.count, week_created.count, month_created.count ORDER BY last_activity DESC LIMIT 20 ` finalActivityQuery := fmt.Sprintf(activityQuery, weekStart.Format("2006-01-02"), orgCondition, monthStart.Format("2006-01-02"), orgCondition, userCondition) if err := db.Raw(finalActivityQuery).Scan(&userActivityStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户活跃度统计失败"}) return } response.UserActivityStats = userActivityStats // 5. 用户完成率排行 var userCompletionRank []UserCompletionRank for i, stat := range userEfficiencyStats { rank := UserCompletionRank{ UserID: stat.UserID, Username: stat.Username, RealName: stat.RealName, CompletionRate: stat.CompletionRate, Rank: i + 1, } // 获取用户的总任务数和完成任务数 for _, taskStat := range userTaskStats { if taskStat.UserID == stat.UserID { rank.TotalTasks = taskStat.AssignedTasks rank.CompletedTasks = taskStat.CompletedTasks break } } userCompletionRank = append(userCompletionRank, rank) } response.UserCompletionRank = userCompletionRank // 6. 用户任务分配统计 var userAssignmentStats []UserAssignmentStat assignmentQuery := ` SELECT u.id as user_id, u.username, u.real_name, COALESCE(urgent.count, 0) as urgent_tasks, COALESCE(high_priority.count, 0) as high_priority_tasks, COALESCE(medium_priority.count, 0) as medium_priority_tasks, COALESCE(low_priority.count, 0) as low_priority_tasks, COALESCE(overdue.count, 0) as overdue_tasks FROM users u LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND priority = 'urgent' %s GROUP BY assignee_id ) urgent ON u.id = urgent.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND priority = 'high' %s GROUP BY assignee_id ) high_priority ON u.id = high_priority.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND priority = 'medium' %s GROUP BY assignee_id ) medium_priority ON u.id = medium_priority.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND priority = 'low' %s GROUP BY assignee_id ) low_priority ON u.id = low_priority.assignee_id LEFT JOIN ( SELECT assignee_id, COUNT(*) as count FROM tasks WHERE assignee_id IS NOT NULL AND end_time < NOW() AND status != 'completed' %s GROUP BY assignee_id ) overdue ON u.id = overdue.assignee_id WHERE 1=1 %s ORDER BY (COALESCE(urgent.count, 0) + COALESCE(high_priority.count, 0)) DESC LIMIT 20 ` finalAssignmentQuery := fmt.Sprintf(assignmentQuery, orgCondition, orgCondition, orgCondition, orgCondition, orgCondition, userCondition) if err := db.Raw(finalAssignmentQuery).Scan(&userAssignmentStats).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户任务分配统计失败"}) return } response.UserAssignmentStats = userAssignmentStats // 7. 总体效率指标 if len(userEfficiencyStats) > 0 { var totalCompletionRate float64 var totalTasks int64 var totalCompletionTime float64 var validTimeCount int64 for _, stat := range userEfficiencyStats { totalCompletionRate += stat.CompletionRate if stat.AverageCompletionTime > 0 { totalCompletionTime += stat.AverageCompletionTime validTimeCount++ } } for _, stat := range userTaskStats { totalTasks += stat.AssignedTasks } response.OverallEfficiency.AverageCompletionRate = totalCompletionRate / float64(len(userEfficiencyStats)) if response.TotalUsers > 0 { response.OverallEfficiency.AverageTasksPerUser = float64(totalTasks) / float64(response.TotalUsers) } if validTimeCount > 0 { response.OverallEfficiency.AverageCompletionTime = totalCompletionTime / float64(validTimeCount) } } c.JSON(http.StatusOK, response) }