Files

125 lines
3.3 KiB
Go
Raw Permalink 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 (
"context"
"time"
"github.com/user-management-system/internal/domain"
"github.com/user-management-system/internal/repository"
)
// StatsService 统计服务
type StatsService struct {
userRepo *repository.UserRepository
loginLogRepo *repository.LoginLogRepository
}
// NewStatsService 创建统计服务
func NewStatsService(
userRepo *repository.UserRepository,
loginLogRepo *repository.LoginLogRepository,
) *StatsService {
return &StatsService{
userRepo: userRepo,
loginLogRepo: loginLogRepo,
}
}
// UserStats 用户统计数据
type UserStats struct {
TotalUsers int64 `json:"total_users"`
ActiveUsers int64 `json:"active_users"`
InactiveUsers int64 `json:"inactive_users"`
LockedUsers int64 `json:"locked_users"`
DisabledUsers int64 `json:"disabled_users"`
NewUsersToday int64 `json:"new_users_today"`
NewUsersWeek int64 `json:"new_users_week"`
NewUsersMonth int64 `json:"new_users_month"`
}
// LoginStats 登录统计数据
type LoginStats struct {
LoginsTodaySuccess int64 `json:"logins_today_success"`
LoginsTodayFailed int64 `json:"logins_today_failed"`
LoginsWeek int64 `json:"logins_week"`
}
// DashboardStats 仪表盘综合统计
type DashboardStats struct {
Users UserStats `json:"users"`
Logins LoginStats `json:"logins"`
}
// GetUserStats 获取用户统计
func (s *StatsService) GetUserStats(ctx context.Context) (*UserStats, error) {
stats := &UserStats{}
// 统计总用户数
_, total, err := s.userRepo.List(ctx, 0, 1)
if err != nil {
return nil, err
}
stats.TotalUsers = total
// 按状态统计
statusCounts := map[domain.UserStatus]*int64{
domain.UserStatusActive: &stats.ActiveUsers,
domain.UserStatusInactive: &stats.InactiveUsers,
domain.UserStatusLocked: &stats.LockedUsers,
domain.UserStatusDisabled: &stats.DisabledUsers,
}
for status, countPtr := range statusCounts {
_, cnt, err := s.userRepo.ListByStatus(ctx, status, 0, 1)
if err == nil {
*countPtr = cnt
}
}
// 今日新增
stats.NewUsersToday = s.countNewUsers(ctx, daysAgo(0))
// 本周新增
stats.NewUsersWeek = s.countNewUsers(ctx, daysAgo(7))
// 本月新增
stats.NewUsersMonth = s.countNewUsers(ctx, daysAgo(30))
return stats, nil
}
// countNewUsers 统计指定时间之后的新增用户数
func (s *StatsService) countNewUsers(ctx context.Context, since time.Time) int64 {
_, count, err := s.userRepo.ListCreatedAfter(ctx, since, 0, 0)
if err != nil {
return 0
}
return count
}
// GetDashboardStats 获取仪表盘综合统计
func (s *StatsService) GetDashboardStats(ctx context.Context) (*DashboardStats, error) {
userStats, err := s.GetUserStats(ctx)
if err != nil {
return nil, err
}
loginStats := &LoginStats{}
// 今日登录成功/失败
today := daysAgo(0)
if s.loginLogRepo != nil {
loginStats.LoginsTodaySuccess = s.loginLogRepo.CountByResultSince(ctx, true, today)
loginStats.LoginsTodayFailed = s.loginLogRepo.CountByResultSince(ctx, false, today)
loginStats.LoginsWeek = s.loginLogRepo.CountByResultSince(ctx, true, daysAgo(7))
}
return &DashboardStats{
Users: *userStats,
Logins: *loginStats,
}, nil
}
// daysAgo 返回N天前的时间当天0点
func daysAgo(n int) time.Time {
now := time.Now()
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
return start.AddDate(0, 0, -n)
}