MilliSim/backend/MilliSim.Api/Services/DashboardService.cs

164 lines
5.8 KiB
C#

using Microsoft.EntityFrameworkCore;
using MilliSim.Common.Dtos;
using MilliSim.Common.Entities;
using MilliSim.Common.Models;
using MilliSim.Data;
using MilliSim.Services.Infrastructure;
namespace MilliSim.Services;
public class DashboardService : IDashboardService
{
private readonly MilliSimDbContext _db;
private readonly ICurrentUserService _currentUser;
private readonly IFileStorageService _fileStorage;
public DashboardService(MilliSimDbContext db, ICurrentUserService currentUser, IFileStorageService fileStorage)
{
_db = db;
_currentUser = currentUser;
_fileStorage = fileStorage;
}
public async Task<ApiResponse<DashboardData>> GetDashboardDataAsync()
{
var userId = _currentUser.UserId;
// ===== Stats =====
var projectCount = await _db.Projects.CountAsync();
var customerCount = await _db.Users.CountAsync(u => u.Role == UserRole.Customer);
var todayStart = DateTime.Now.Date;
var todayEnd = todayStart.AddDays(1);
var todayVisits = await _db.OperationLogs
.CountAsync(l => l.CreatedAt >= todayStart && l.CreatedAt < todayEnd);
var activeAuthorizations = await _db.Authorizations
.CountAsync(a => a.Status == AuthorizationStatus.Active);
var unreadMessages = await _db.Notifications
.Where(n => n.UserId == null || n.UserId == userId)
.Where(n => !_db.NotificationReads.Any(r => r.NotificationId == n.Id && r.UserId == userId))
.CountAsync();
// ===== Trends: 近 7 天 =====
var startDate = DateTime.Now.Date.AddDays(-6);
var endDate = DateTime.Now.Date.AddDays(1);
var visits = await _db.OperationLogs
.Where(l => l.CreatedAt >= startDate && l.CreatedAt < endDate)
.GroupBy(l => l.CreatedAt.Date)
.Select(g => new { Date = g.Key, Count = g.Count() })
.ToListAsync();
var experiences = await _db.ExperienceLogs
.Where(l => l.CreatedAt >= startDate && l.CreatedAt < endDate)
.GroupBy(l => l.CreatedAt.Date)
.Select(g => new { Date = g.Key, Count = g.Count() })
.ToListAsync();
var trends = new List<TrendData>();
for (var i = 0; i < 7; i++)
{
var date = startDate.AddDays(i);
trends.Add(new TrendData
{
Date = date.ToString("MM-dd"),
Visits = visits.FirstOrDefault(v => v.Date == date)?.Count ?? 0,
Experiences = experiences.FirstOrDefault(e => e.Date == date)?.Count ?? 0
});
}
// 如果没有真实数据则返回模拟数据
if (trends.Sum(t => t.Visits + t.Experiences) == 0)
{
var random = new Random();
foreach (var t in trends)
{
t.Visits = random.Next(50, 200);
t.Experiences = random.Next(10, 80);
}
}
// ===== CategoryDistribution: 按分类统计项目数 =====
var categoryDistribution = await _db.Projects
.Join(_db.ProjectCategories,
p => p.CategoryId,
c => c.Id,
(p, c) => new { c.Name })
.GroupBy(x => x.Name)
.Select(g => new CategoryDistribution
{
Name = g.Key,
Count = g.Count()
})
.ToListAsync();
// ===== RecentActivities: 当前用户最近 10 条操作日志 =====
var recentLogEntities = await _db.OperationLogs
.Where(l => l.UserId == userId)
.OrderByDescending(l => l.CreatedAt)
.Take(10)
.ToListAsync();
var recentUserIds = recentLogEntities.Select(l => l.UserId).Distinct().ToList();
var recentNicknames = await _db.Users
.Where(u => recentUserIds.Contains(u.Id))
.ToDictionaryAsync(u => u.Id, u => u.Nickname);
var recentActivities = recentLogEntities.Select(l => new OperationLogDto
{
Id = l.Id,
UserId = l.UserId,
Username = l.Username,
Nickname = recentNicknames.GetValueOrDefault(l.UserId) ?? string.Empty,
Module = l.Module,
Operation = l.Operation,
Detail = l.Detail,
Ip = l.Ip,
CreatedAt = l.CreatedAt
}).ToList();
// ===== HotProjects: 按 ExperienceCount 倒序取 6 个(封面需 COS 签名) =====
var hotProjectEntities = await _db.Projects
.Include(p => p.Category)
.OrderByDescending(p => p.ExperienceCount)
.Take(6)
.ToListAsync();
var hotProjects = hotProjectEntities.Select(p => new ProjectDto
{
Id = p.Id,
Name = p.Name,
CategoryId = p.CategoryId,
CategoryName = p.Category != null ? p.Category.Name : string.Empty,
CoverImage = _fileStorage.GetSignedUrl(p.CoverImage),
Description = p.Description,
Status = p.Status,
IsFeatured = p.IsFeatured,
ViewCount = p.ViewCount,
ExperienceCount = p.ExperienceCount,
FavoriteCount = p.FavoriteCount,
CreatedAt = p.CreatedAt
}).ToList();
var data = new DashboardData
{
Stats = new DashboardStats
{
ProjectCount = projectCount,
CustomerCount = customerCount,
TodayVisits = todayVisits,
ActiveAuthorizations = activeAuthorizations,
UnreadMessages = unreadMessages
},
Trends = trends,
CategoryDistribution = categoryDistribution,
RecentActivities = recentActivities,
HotProjects = hotProjects
};
return ApiResponse<DashboardData>.Success(data);
}
}