125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
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)
|
||
}
|