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()
.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()
.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()
.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 GetToolStatisticsAsync(int toolId, DateTime date)
{
return await _freeSql.Select()
.Where(s => s.ToolId == toolId && s.Date == date)
.FirstAsync();
}
///
/// 获取工具访问记录
///
protected async Task> GetToolAccessRecordsAsync(int toolId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100)
{
var query = _freeSql.Select()
.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> GetUserToolAccessRecordsAsync(int userId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100)
{
var query = _freeSql.Select()
.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> GetPopularToolsAsync(int count = 10, DateTime? startDate = null)
{
var query = _freeSql.Select()
.Include(t => t.Category)
.Where(t => t.IsActive);
if (startDate.HasValue)
{
// 基于指定日期后的访问量排序
var toolAccessData = _freeSql.Select()
.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();
}
///
/// 获取当前用户ID
///
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;
}
///
/// 获取会话ID
///
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;
}
}
///
/// 获取客户端IP地址
///
protected string? GetClientIpAddress()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
// 尝试从各种头部获取真实IP
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()
.Where(ua => ua.ToolId == toolId && ua.CreatedAt >= today && ua.Duration > 0)
.AvgAsync(ua => ua.Duration);
if (avgDuration > 0)
{
await _freeSql.Update()
.Where(s => s.ToolId == toolId && s.Date == today)
.Set(s => s.AverageDuration, (decimal)avgDuration)
.ExecuteAffrowsAsync();
}
}
///
/// 获取工具使用趋势数据
///
protected async Task> GetToolUsageTrendAsync(int toolId, int days = 30)
{
var endDate = DateTime.Today;
var startDate = endDate.AddDays(-days + 1);
var stats = await _freeSql.Select()
.Where(s => s.ToolId == toolId && s.Date >= startDate && s.Date <= endDate)
.OrderBy(s => s.Date)
.ToListAsync();
var result = new List