| | using ToolHub.Models; |
| | using Microsoft.AspNetCore.Http; |
| | using System.Security.Claims; |
| |
|
| | namespace ToolHub.Services; |
| |
|
| | |
| | |
| | |
| | public abstract class BaseToolService |
| | { |
| | protected readonly IFreeSql _freeSql; |
| | protected readonly IHttpContextAccessor _httpContextAccessor; |
| |
|
| | protected BaseToolService(IFreeSql freeSql, IHttpContextAccessor httpContextAccessor) |
| | { |
| | _freeSql = freeSql; |
| | _httpContextAccessor = httpContextAccessor; |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task RecordToolAccessAsync(int toolId, string accessType = "view", int duration = 0) |
| | { |
| | try |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | if (httpContext == null) return; |
| |
|
| | var userId = GetCurrentUserId(); |
| | var sessionId = GetSessionId(); |
| | var ipAddress = GetClientIpAddress(); |
| | var userAgent = GetUserAgent(); |
| | var referer = GetReferer(); |
| |
|
| | var access = new UserToolAccess |
| | { |
| | UserId = userId, |
| | ToolId = toolId, |
| | SessionId = sessionId, |
| | IpAddress = ipAddress, |
| | UserAgent = userAgent, |
| | Referer = referer, |
| | AccessType = accessType, |
| | Duration = duration |
| | }; |
| |
|
| | await _freeSql.Insert(access).ExecuteAffrowsAsync(); |
| |
|
| | |
| | await _freeSql.Update<Tool>() |
| | .Where(t => t.Id == toolId) |
| | .Set(t => t.ViewCount + 1) |
| | .ExecuteAffrowsAsync(); |
| |
|
| | |
| | await UpdateDailyStatisticsAsync(toolId, accessType); |
| | } |
| | catch (Exception ex) |
| | { |
| | |
| | Console.WriteLine($"记录工具访问失败: {ex.Message}"); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task UpdateDailyStatisticsAsync(int toolId, string accessType) |
| | { |
| | var today = DateTime.Today; |
| | var stats = await _freeSql.Select<ToolStatistics>() |
| | .Where(s => s.ToolId == toolId && s.Date == today) |
| | .FirstAsync(); |
| |
|
| | if (stats == null) |
| | { |
| | |
| | stats = new ToolStatistics |
| | { |
| | ToolId = toolId, |
| | Date = today |
| | }; |
| | await _freeSql.Insert(stats).ExecuteAffrowsAsync(); |
| | } |
| |
|
| | |
| | var updateQuery = _freeSql.Update<ToolStatistics>() |
| | .Where(s => s.Id == stats.Id); |
| |
|
| | switch (accessType.ToLower()) |
| | { |
| | case "view": |
| | updateQuery.Set(s => s.DailyViews + 1); |
| | break; |
| | case "favorite": |
| | updateQuery.Set(s => s.DailyFavorites + 1); |
| | break; |
| | case "share": |
| | updateQuery.Set(s => s.DailyShares + 1); |
| | break; |
| | case "download": |
| | updateQuery.Set(s => s.DailyDownloads + 1); |
| | break; |
| | } |
| |
|
| | updateQuery.Set(s => s.UpdatedAt, DateTime.Now); |
| | await updateQuery.ExecuteAffrowsAsync(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task<ToolStatistics?> GetToolStatisticsAsync(int toolId, DateTime date) |
| | { |
| | return await _freeSql.Select<ToolStatistics>() |
| | .Where(s => s.ToolId == toolId && s.Date == date) |
| | .FirstAsync(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task<List<UserToolAccess>> GetToolAccessRecordsAsync(int toolId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100) |
| | { |
| | var query = _freeSql.Select<UserToolAccess>() |
| | .Include(ua => ua.User) |
| | .Where(ua => ua.ToolId == toolId); |
| |
|
| | if (startDate.HasValue) |
| | query = query.Where(ua => ua.CreatedAt >= startDate.Value); |
| |
|
| | if (endDate.HasValue) |
| | query = query.Where(ua => ua.CreatedAt <= endDate.Value.AddDays(1)); |
| |
|
| | return await query |
| | .OrderByDescending(ua => ua.CreatedAt) |
| | .Take(limit) |
| | .ToListAsync(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task<List<UserToolAccess>> GetUserToolAccessRecordsAsync(int userId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100) |
| | { |
| | var query = _freeSql.Select<UserToolAccess>() |
| | .Include(ua => ua.Tool) |
| | .Where(ua => ua.UserId == userId); |
| |
|
| | if (startDate.HasValue) |
| | query = query.Where(ua => ua.CreatedAt >= startDate.Value); |
| |
|
| | if (endDate.HasValue) |
| | query = query.Where(ua => ua.CreatedAt <= endDate.Value); |
| |
|
| | return await query |
| | .OrderByDescending(ua => ua.CreatedAt) |
| | .Take(limit) |
| | .ToListAsync(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task<List<Tool>> GetPopularToolsAsync(int count = 10, DateTime? startDate = null) |
| | { |
| | var query = _freeSql.Select<Tool>() |
| | .Include(t => t.Category) |
| | .Where(t => t.IsActive); |
| |
|
| | if (startDate.HasValue) |
| | { |
| | |
| | var toolAccessData = _freeSql.Select<UserToolAccess>() |
| | .Where(ua => ua.CreatedAt >= startDate.Value) |
| | .GroupBy(ua => ua.ToolId) |
| | .Select(g => new { ToolId = g.Key, Count = g.Count() }) |
| | .OrderByDescending(x => x.Count) |
| | .Take(count) |
| | .ToList(); |
| |
|
| | var toolIds = toolAccessData.Select(x => x.ToolId).ToList(); |
| |
|
| | if (toolIds.Any()) |
| | { |
| | query = query.Where(t => toolIds.Contains(t.Id)); |
| | } |
| | } |
| | else |
| | { |
| | |
| | query = query.OrderByDescending(t => t.ViewCount); |
| | } |
| |
|
| | return await query.Take(count).ToListAsync(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected int? GetCurrentUserId() |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | if (httpContext?.User?.Identity?.IsAuthenticated == true) |
| | { |
| | var userIdClaim = httpContext.User.FindFirst(ClaimTypes.NameIdentifier); |
| | if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId)) |
| | { |
| | return userId; |
| | } |
| | } |
| | return null; |
| | } |
| |
|
| | |
| | |
| | |
| | protected string? GetSessionId() |
| | { |
| | string sessionId = string.Empty; |
| | try |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | return httpContext?.Session?.Id; |
| | } |
| | catch (Exception ex) |
| | { |
| | Console.WriteLine($"获取会话ID失败: {ex.Message}"); |
| | return sessionId; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | protected string? GetClientIpAddress() |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | if (httpContext == null) return null; |
| |
|
| | |
| | var ip = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault() ?? |
| | httpContext.Request.Headers["X-Real-IP"].FirstOrDefault() ?? |
| | httpContext.Connection.RemoteIpAddress?.ToString(); |
| |
|
| | return ip; |
| | } |
| |
|
| | |
| | |
| | |
| | protected string? GetUserAgent() |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | return httpContext?.Request.Headers["User-Agent"].FirstOrDefault(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected string? GetReferer() |
| | { |
| | var httpContext = _httpContextAccessor.HttpContext; |
| | return httpContext?.Request.Headers["Referer"].FirstOrDefault(); |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task UpdateAverageDurationAsync(int toolId) |
| | { |
| | var today = DateTime.Today; |
| | var avgDuration = await _freeSql.Select<UserToolAccess>() |
| | .Where(ua => ua.ToolId == toolId && ua.CreatedAt >= today && ua.Duration > 0) |
| | .AvgAsync(ua => ua.Duration); |
| |
|
| | if (avgDuration > 0) |
| | { |
| | await _freeSql.Update<ToolStatistics>() |
| | .Where(s => s.ToolId == toolId && s.Date == today) |
| | .Set(s => s.AverageDuration, (decimal)avgDuration) |
| | .ExecuteAffrowsAsync(); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | protected async Task<List<object>> GetToolUsageTrendAsync(int toolId, int days = 30) |
| | { |
| | var endDate = DateTime.Today; |
| | var startDate = endDate.AddDays(-days + 1); |
| |
|
| | var stats = await _freeSql.Select<ToolStatistics>() |
| | .Where(s => s.ToolId == toolId && s.Date >= startDate && s.Date <= endDate) |
| | .OrderBy(s => s.Date) |
| | .ToListAsync(); |
| |
|
| | var result = new List<object>(); |
| | for (var date = startDate; date <= endDate; date = date.AddDays(1)) |
| | { |
| | var dayStats = stats.FirstOrDefault(s => s.Date == date); |
| | result.Add(new |
| | { |
| | Date = date.ToString("yyyy-MM-dd"), |
| | Views = dayStats?.DailyViews ?? 0, |
| | UniqueViews = dayStats?.DailyUniqueViews ?? 0, |
| | Favorites = dayStats?.DailyFavorites ?? 0, |
| | Shares = dayStats?.DailyShares ?? 0, |
| | Downloads = dayStats?.DailyDownloads ?? 0, |
| | AverageDuration = dayStats?.AverageDuration ?? 0 |
| | }); |
| | } |
| |
|
| | return result; |
| | } |
| | } |
| |
|