using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Models.Rank;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace HoneyBox.Core.Services;
///
/// 排行榜服务实现
///
public class RankService : IRankService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger _logger;
///
/// 有效的排行榜类型
///
private static readonly HashSet ValidRankTypes = new(StringComparer.OrdinalIgnoreCase)
{
"diamond", "integral", "dadajuan", "invite", "loss"
};
public RankService(HoneyBoxDbContext dbContext, ILogger logger)
{
_dbContext = dbContext;
_logger = logger;
}
///
public async Task GetWeekRankAsync(int userId)
{
// 获取当前用户信息
var user = await _dbContext.Users
.Where(u => u.Id == userId)
.Select(u => new { u.Nickname, u.HeadImg })
.FirstOrDefaultAsync();
if (user == null)
{
throw new InvalidOperationException("用户不存在");
}
// 计算本周时间范围(周一到周日)
var (weekStart, weekEnd) = GetWeekRange(DateTime.Now);
var weekStartTimestamp = ToUnixTimestamp(weekStart);
var weekEndTimestamp = ToUnixTimestamp(weekEnd);
// 查询当前用户本周消费总额
var myOrderTotal = await _dbContext.Orders
.Where(o => o.UserId == userId
&& o.Addtime >= weekStartTimestamp
&& o.Addtime <= weekEndTimestamp
&& o.Status == 1
&& o.OrderType < 5)
.SumAsync(o => (decimal?)o.OrderTotal) ?? 0;
// 查询排行榜前30名
var rankData = await _dbContext.Orders
.Where(o => o.Addtime >= weekStartTimestamp
&& o.Addtime <= weekEndTimestamp
&& o.Status == 1
&& o.OrderType < 5)
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
OrderTotal = g.Sum(o => o.OrderTotal)
})
.OrderByDescending(x => x.OrderTotal)
.ThenBy(x => x.UserId)
.Take(30)
.ToListAsync();
// 获取用户信息
var userIds = rankData.Select(r => r.UserId).ToList();
var users = await _dbContext.Users
.Where(u => userIds.Contains(u.Id))
.Select(u => new { u.Id, u.Nickname, u.HeadImg })
.ToDictionaryAsync(u => u.Id);
// 获取周榜奖品信息 (goods_id = -1 表示周榜奖品)
var prizes = await _dbContext.GoodsItems
.Where(g => g.GoodsId == -1 && g.Rank >= 1 && g.Rank <= 30)
.Select(g => new { g.Rank, g.Title, g.ImgUrl })
.ToDictionaryAsync(g => g.Rank);
// 构建排行榜数据
var data = new List();
object myRank = "暂未上榜";
object myPrizeTitle = 0;
object myPrizeImgurl = 0;
for (int i = 0; i < rankData.Count; i++)
{
var item = rankData[i];
var rank = i + 1;
var userInfo = users.GetValueOrDefault(item.UserId);
var prizeInfo = prizes.GetValueOrDefault(rank);
var rankItem = new RankItemDto
{
Rank = rank,
UserId = item.UserId,
Nickname = userInfo?.Nickname ?? "",
Headimg = userInfo?.HeadImg ?? "",
OrderTotal = item.OrderTotal,
PrizeTitle = prizeInfo?.Title ?? "",
PrizeImgurl = prizeInfo?.ImgUrl ?? ""
};
data.Add(rankItem);
// 判断当前用户是否在排名中
if (item.UserId == userId)
{
myRank = rank;
myPrizeTitle = prizeInfo?.Title ?? "";
myPrizeImgurl = prizeInfo?.ImgUrl ?? "";
}
}
return new RankResponse
{
Date = $"{weekStart:MM月dd日}-{weekEnd:MM月dd日}",
EndDate = weekEndTimestamp,
MyRank = new MyRankDto
{
MyRank = myRank,
MyPrizeTitle = myPrizeTitle,
MyPrizeImgurl = myPrizeImgurl,
MyOrderTotal = myOrderTotal,
MyNickname = user.Nickname,
MyHeadimg = user.HeadImg
},
Data = data
};
}
///
public async Task GetMonthRankAsync(int userId)
{
// 获取当前用户信息
var user = await _dbContext.Users
.Where(u => u.Id == userId)
.Select(u => new { u.Nickname, u.HeadImg })
.FirstOrDefaultAsync();
if (user == null)
{
throw new InvalidOperationException("用户不存在");
}
// 计算本月时间范围
var (monthStart, monthEnd) = GetMonthRange(DateTime.Now);
var monthStartTimestamp = ToUnixTimestamp(monthStart);
var monthEndTimestamp = ToUnixTimestamp(monthEnd);
// 查询当前用户本月消费总额
var myOrderTotal = await _dbContext.Orders
.Where(o => o.UserId == userId
&& o.Addtime >= monthStartTimestamp
&& o.Addtime <= monthEndTimestamp
&& o.Status == 1
&& o.OrderType < 5)
.SumAsync(o => (decimal?)o.OrderTotal) ?? 0;
// 查询排行榜前30名
var rankData = await _dbContext.Orders
.Where(o => o.Addtime >= monthStartTimestamp
&& o.Addtime <= monthEndTimestamp
&& o.Status == 1
&& o.OrderType < 5)
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
OrderTotal = g.Sum(o => o.OrderTotal)
})
.OrderByDescending(x => x.OrderTotal)
.ThenBy(x => x.UserId)
.Take(30)
.ToListAsync();
// 获取用户信息
var userIds = rankData.Select(r => r.UserId).ToList();
var users = await _dbContext.Users
.Where(u => userIds.Contains(u.Id))
.Select(u => new { u.Id, u.Nickname, u.HeadImg })
.ToDictionaryAsync(u => u.Id);
// 获取月榜奖品信息 (goods_id = -2 表示月榜奖品)
var prizes = await _dbContext.GoodsItems
.Where(g => g.GoodsId == -2 && g.Rank >= 1 && g.Rank <= 30)
.Select(g => new { g.Rank, g.Title, g.ImgUrl })
.ToDictionaryAsync(g => g.Rank);
// 构建排行榜数据
var data = new List();
object myRank = "暂未上榜";
object myPrizeTitle = 0;
object myPrizeImgurl = 0;
for (int i = 0; i < rankData.Count; i++)
{
var item = rankData[i];
var rank = i + 1;
var userInfo = users.GetValueOrDefault(item.UserId);
var prizeInfo = prizes.GetValueOrDefault(rank);
var rankItem = new RankItemDto
{
Rank = rank,
UserId = item.UserId,
Nickname = userInfo?.Nickname ?? "",
Headimg = userInfo?.HeadImg ?? "",
OrderTotal = item.OrderTotal,
PrizeTitle = prizeInfo?.Title ?? "",
PrizeImgurl = prizeInfo?.ImgUrl ?? ""
};
data.Add(rankItem);
// 判断当前用户是否在排名中
if (item.UserId == userId)
{
myRank = rank;
myPrizeTitle = prizeInfo?.Title ?? "";
myPrizeImgurl = prizeInfo?.ImgUrl ?? "";
}
}
return new RankResponse
{
Date = $"{monthStart:MM月dd日}-{monthEnd:MM月dd日}",
EndDate = monthEndTimestamp,
MyRank = new MyRankDto
{
MyRank = myRank,
MyPrizeTitle = myPrizeTitle,
MyPrizeImgurl = myPrizeImgurl,
MyOrderTotal = myOrderTotal,
MyNickname = user.Nickname,
MyHeadimg = user.HeadImg
},
Data = data
};
}
///
/// 获取本周时间范围(周一00:00:00到周日23:59:59)
///
private static (DateTime start, DateTime end) GetWeekRange(DateTime date)
{
// 获取当前是周几 (0=周日, 1=周一, ..., 6=周六)
var dayOfWeek = (int)date.DayOfWeek;
// 计算到周一的天数差
var daysToMonday = dayOfWeek == 0 ? 6 : dayOfWeek - 1;
// 本周一00:00:00
var weekStart = date.Date.AddDays(-daysToMonday);
// 本周日23:59:59
var weekEnd = weekStart.AddDays(6).AddHours(23).AddMinutes(59).AddSeconds(59);
return (weekStart, weekEnd);
}
///
/// 获取本月时间范围(1号00:00:00到月末23:59:59)
///
private static (DateTime start, DateTime end) GetMonthRange(DateTime date)
{
// 本月1号00:00:00
var monthStart = new DateTime(date.Year, date.Month, 1, 0, 0, 0);
// 本月最后一天23:59:59
var daysInMonth = DateTime.DaysInMonth(date.Year, date.Month);
var monthEnd = new DateTime(date.Year, date.Month, daysInMonth, 23, 59, 59);
return (monthStart, monthEnd);
}
///
/// 将DateTime转换为Unix时间戳
///
private static int ToUnixTimestamp(DateTime dateTime)
{
return (int)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
}
///
public async Task> GetRankListAsync(string type, int page = 1, int limit = 10)
{
if (!ValidRankTypes.Contains(type))
{
throw new InvalidOperationException("无效的排行榜类型");
}
return type.ToLower() switch
{
"diamond" => await GetDiamondRankAsync(page, limit),
"integral" => await GetIntegralRankAsync(page, limit),
"dadajuan" => await GetDadajuanRankAsync(page, limit),
"invite" => await GetInviteRankAsync(page, limit),
"loss" => await GetLossRankAsync(page, limit),
_ => new List()
};
}
///
public async Task GetConsumeRecordAsync(int page = 1, int limit = 10)
{
// 获取本月时间范围
var (monthStart, monthEnd) = GetMonthRange(DateTime.Now);
var monthStartTimestamp = ToUnixTimestamp(monthStart);
var monthEndTimestamp = ToUnixTimestamp(monthEnd);
// 查询本月消费排行榜
var rankData = await _dbContext.Orders
.Where(o => o.Status == 1
&& o.Price > 0
&& o.Addtime >= monthStartTimestamp
&& o.Addtime <= monthEndTimestamp)
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
Price = g.Sum(o => o.Price)
})
.OrderByDescending(x => x.Price)
.Skip((page - 1) * limit)
.Take(limit)
.ToListAsync();
// 获取用户信息
var userIds = rankData.Select(r => r.UserId).ToList();
var users = await _dbContext.Users
.Where(u => userIds.Contains(u.Id))
.Select(u => new { u.Id, u.Nickname, u.HeadImg, u.Mobile })
.ToDictionaryAsync(u => u.Id);
// 构建响应数据
var list = rankData.Select(item =>
{
var userInfo = users.GetValueOrDefault(item.UserId);
return new ConsumeRecordItemDto
{
UserId = item.UserId,
Nickname = userInfo?.Nickname ?? "",
Headimg = userInfo?.HeadImg ?? "",
Mobile = userInfo?.Mobile ?? "",
Price = item.Price
};
}).ToList();
return new ConsumeRecordResponse { List = list };
}
#region Private Rank Methods
///
/// 获取钻石排行榜
///
private async Task> GetDiamondRankAsync(int page, int limit)
{
// 获取测试用户ID列表
var testUserIds = await _dbContext.Users
.Where(u => u.IsTest > 0 && u.Status == 1)
.Select(u => u.Id)
.ToListAsync();
// 查询钻石消费排行
var rankData = await _dbContext.Orders
.Where(o => o.Status == 1
&& o.UseMoney > 0
&& !testUserIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
Value = g.Sum(o => o.UseMoney)
})
.OrderByDescending(x => x.Value)
.Skip((page - 1) * limit)
.Take(limit)
.ToListAsync();
return await BuildRankListAsync(rankData, page, limit, "钻石");
}
///
/// 获取UU币排行榜
///
private async Task> GetIntegralRankAsync(int page, int limit)
{
// 获取测试用户ID列表
var testUserIds = await _dbContext.Users
.Where(u => u.IsTest > 0 && u.Status == 1)
.Select(u => u.Id)
.ToListAsync();
// 查询积分消费排行
var rankData = await _dbContext.Orders
.Where(o => o.Status == 1
&& o.UseIntegral > 0
&& !testUserIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
Value = g.Sum(o => o.UseIntegral)
})
.OrderByDescending(x => x.Value)
.Skip((page - 1) * limit)
.Take(limit)
.ToListAsync();
return await BuildRankListAsync(rankData, page, limit, "UU币");
}
///
/// 获取达达卷排行榜
///
private async Task> GetDadajuanRankAsync(int page, int limit)
{
// 达达卷排行榜默认显示更多数据
var actualLimit = limit == 10 ? 200 : limit;
// 获取测试用户ID列表
var testUserIds = await _dbContext.Users
.Where(u => u.IsTest > 0 && u.Status == 1)
.Select(u => u.Id)
.ToListAsync();
// 查询达达卷回收排行
var rankData = await _dbContext.OrderItemsRecoveries
.Where(o => o.Money > 0
&& !testUserIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
Value = g.Sum(o => o.Money) * 100 // 转换为达达卷单位
})
.OrderByDescending(x => x.Value)
.Skip((page - 1) * actualLimit)
.Take(actualLimit)
.ToListAsync();
return await BuildRankListAsync(rankData, page, actualLimit, "达达卷");
}
///
/// 获取邀请排行榜
///
private async Task> GetInviteRankAsync(int page, int limit)
{
// 邀请排行榜默认显示更多数据
var actualLimit = limit == 10 ? 50 : limit;
// 查询邀请排行
var rankData = await _dbContext.Users
.Where(u => u.Pid > 0 && u.IsTest == 0 && u.Status == 1)
.GroupBy(u => u.Pid)
.Select(g => new
{
UserId = g.Key,
Value = (decimal)g.Count()
})
.Where(x => x.Value > 0)
.OrderByDescending(x => x.Value)
.Skip((page - 1) * actualLimit)
.Take(actualLimit)
.ToListAsync();
return await BuildRankListAsync(rankData, page, actualLimit, "人");
}
///
/// 获取亏损排行榜
///
private async Task> GetLossRankAsync(int page, int limit)
{
// 获取测试用户ID列表
var testUserIds = await _dbContext.Users
.Where(u => u.IsTest > 0)
.Select(u => u.Id)
.ToListAsync();
// 查询订单消费数据
var orderData = await _dbContext.Orders
.Where(o => o.Status == 1 && !testUserIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
ConsumeMoney = g.Sum(o => o.Price)
})
.ToListAsync();
// 获取所有相关用户ID
var userIds = orderData.Select(o => o.UserId).ToList();
// 查询出货金额
var outputData = await _dbContext.OrderItems
.Where(o => userIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
OutputMoney = g.Sum(o => o.GoodslistMoney)
})
.ToDictionaryAsync(x => x.UserId, x => x.OutputMoney);
// 查询达达卷金额
var dadaData = await _dbContext.OrderItemsRecoveries
.Where(o => userIds.Contains(o.UserId))
.GroupBy(o => o.UserId)
.Select(g => new
{
UserId = g.Key,
DadaMoney = g.Sum(o => o.Money)
})
.ToDictionaryAsync(x => x.UserId, x => x.DadaMoney);
// 计算亏损并排序
var lossData = orderData
.Select(o =>
{
var outputMoney = outputData.GetValueOrDefault(o.UserId, 0);
var dadaMoney = dadaData.GetValueOrDefault(o.UserId, 0);
var lossMoney = outputMoney - (o.ConsumeMoney + dadaMoney);
return new { o.UserId, LossMoney = lossMoney };
})
.Where(x => x.LossMoney < 0) // 只显示亏损用户
.OrderBy(x => x.LossMoney) // 亏损越多排名越前
.Skip((page - 1) * limit)
.Take(limit)
.ToList();
// 获取用户信息
var lossUserIds = lossData.Select(x => x.UserId).ToList();
var users = await _dbContext.Users
.Where(u => lossUserIds.Contains(u.Id))
.Select(u => new { u.Id, u.Nickname, u.HeadImg })
.ToDictionaryAsync(u => u.Id);
// 构建排行榜数据
var result = new List();
var offset = (page - 1) * limit;
for (int i = 0; i < lossData.Count; i++)
{
var item = lossData[i];
var userInfo = users.GetValueOrDefault(item.UserId);
if (userInfo != null)
{
result.Add(new GenericRankItemDto
{
Rank = offset + i + 1,
UserId = item.UserId,
Nickname = userInfo.Nickname ?? "",
Headimg = userInfo.HeadImg ?? "",
Value = Math.Abs(item.LossMoney), // 显示亏损金额的绝对值
Unit = "元"
});
}
}
return result;
}
///
/// 构建排行榜列表
///
private async Task> BuildRankListAsync(
List rankData,
int page,
int limit,
string unit) where T : class
{
// 使用反射获取UserId和Value属性
var userIdProp = typeof(T).GetProperty("UserId");
var valueProp = typeof(T).GetProperty("Value");
if (userIdProp == null || valueProp == null)
{
return new List();
}
var userIds = rankData.Select(r => (int)userIdProp.GetValue(r)!).ToList();
var users = await _dbContext.Users
.Where(u => userIds.Contains(u.Id))
.Select(u => new { u.Id, u.Nickname, u.HeadImg })
.ToDictionaryAsync(u => u.Id);
var result = new List();
var offset = (page - 1) * limit;
for (int i = 0; i < rankData.Count; i++)
{
var item = rankData[i];
var userId = (int)userIdProp.GetValue(item)!;
var value = Convert.ToDecimal(valueProp.GetValue(item));
var userInfo = users.GetValueOrDefault(userId);
if (userInfo != null)
{
result.Add(new GenericRankItemDto
{
Rank = offset + i + 1,
UserId = userId,
Nickname = userInfo.Nickname ?? "",
Headimg = userInfo.HeadImg ?? "",
Value = value,
Unit = unit
});
}
}
return result;
}
#endregion
}