HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/TaskService.cs
2026-02-04 21:19:40 +08:00

283 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Task;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace HoneyBox.Core.Services;
/// <summary>
/// 任务服务实现
/// </summary>
public class TaskService : ITaskService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<TaskService> _logger;
public TaskService(HoneyBoxDbContext dbContext, ILogger<TaskService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
/// <inheritdoc />
public async Task<TaskListResponse> GetTaskListAsync(int userId, int type)
{
// 获取任务列表
var tasks = await _dbContext.Tasks
.Where(t => t.Type == type && t.DeletedAt == null)
.OrderByDescending(t => t.Sort)
.ThenByDescending(t => t.Id)
.ToListAsync();
var taskDtos = new List<TaskDto>();
foreach (var task in tasks)
{
// 计算任务周期时间范围
var (startTime, endTime) = GetTaskPeriod(task.Type);
// 计算任务进度
int completedCount = await CalculateTaskProgress(userId, task.Cate, startTime);
// 判断是否已完成
int targetNumber = task.Number ?? 0;
int isComplete;
int percentage;
int ywcCount;
if (completedCount >= targetNumber)
{
isComplete = 1;
percentage = 100;
ywcCount = targetNumber;
}
else
{
isComplete = 0;
percentage = targetNumber > 0 ? (int)Math.Round((double)completedCount / targetNumber * 100) : 0;
ywcCount = completedCount;
}
// 检查是否已领取
var hasClaimed = await _dbContext.UserTasks
.AnyAsync(ut => ut.UserId == userId
&& ut.TaskId == task.Id
&& ut.CreatedAt >= startTime
&& ut.CreatedAt <= endTime
&& ut.DeletedAt == null);
if (hasClaimed)
{
isComplete = 2; // 已领取
}
taskDtos.Add(new TaskDto
{
Id = task.Id,
Type = task.Type,
Cate = task.Cate,
Title = task.Title,
Number = targetNumber,
ZNumber = task.ZNumber ?? 0,
IsComplete = isComplete,
Percentage = percentage,
YwcCount = ywcCount
});
}
return new TaskListResponse
{
TaskList = taskDtos
};
}
/// <inheritdoc />
public async Task<ClaimTaskRewardResponse> ClaimTaskRewardAsync(int userId, int taskListId)
{
// 获取任务信息
var task = await _dbContext.Tasks
.FirstOrDefaultAsync(t => t.Id == taskListId && t.DeletedAt == null);
if (task == null)
{
throw new InvalidOperationException("任务不存在");
}
// 计算任务周期时间范围
var (startTime, endTime) = GetTaskPeriod(task.Type);
// 检查任务是否已完成
int completedCount = await CalculateTaskProgress(userId, task.Cate, startTime);
int targetNumber = task.Number ?? 0;
if (completedCount < targetNumber)
{
throw new InvalidOperationException("任务未完成");
}
// 检查是否已领取
var hasClaimed = await _dbContext.UserTasks
.AnyAsync(ut => ut.UserId == userId
&& ut.TaskId == taskListId
&& ut.CreatedAt >= startTime
&& ut.CreatedAt <= endTime
&& ut.DeletedAt == null);
if (hasClaimed)
{
throw new InvalidOperationException("你已经领取过了");
}
// 开始事务
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
var now = DateTime.Now;
// 创建用户任务记录
var userTask = new UserTask
{
UserId = userId,
TaskId = taskListId,
Type = task.Type,
Cate = task.Cate,
IsImportant = task.IsImportant,
Number = task.Number,
ZNumber = task.ZNumber,
CreatedAt = now,
UpdatedAt = now
};
await _dbContext.UserTasks.AddAsync(userTask);
// 发放欧气值奖励
int reward = task.ZNumber ?? 0;
int currentOuQi = 0;
if (reward > 0)
{
var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
if (user != null)
{
user.OuQi = (user.OuQi ?? 0) + reward;
currentOuQi = user.OuQi ?? 0;
// 重新计算欧气等级
user.OuQiLevel = CalculateOuQiLevel(currentOuQi);
user.UpdatedAt = now;
// 记录欧气值变动
var profitOuQi = new ProfitOuQi
{
UserId = userId,
ChangeMoney = reward,
Money = currentOuQi,
Type = 1, // 完成任务
Content = "完成任务",
CreatedAt = now
};
await _dbContext.ProfitOuQis.AddAsync(profitOuQi);
}
}
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("用户 {UserId} 领取任务 {TaskId} 奖励 {Reward} 欧气值", userId, taskListId, reward);
return new ClaimTaskRewardResponse
{
Reward = reward,
CurrentOuQi = currentOuQi
};
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "用户 {UserId} 领取任务 {TaskId} 奖励失败", userId, taskListId);
throw new InvalidOperationException("网络故障, 请稍后再试");
}
}
/// <summary>
/// 获取任务周期时间范围
/// </summary>
/// <param name="taskType">任务类型: 1=每日, 2=每周</param>
/// <returns>开始时间和结束时间</returns>
private (DateTime startTime, DateTime endTime) GetTaskPeriod(int taskType)
{
var now = DateTime.Now;
if (taskType == 1)
{
// 每日任务: 当天 00:00:00 到 23:59:59
var startTime = now.Date;
var endTime = now.Date.AddDays(1).AddSeconds(-1);
return (startTime, endTime);
}
else
{
// 每周任务: 本周一 00:00:00 到 本周日 23:59:59
var dayOfWeek = (int)now.DayOfWeek;
// 周日是0需要转换为7
if (dayOfWeek == 0) dayOfWeek = 7;
var startTime = now.Date.AddDays(-(dayOfWeek - 1)); // 本周一
var endTime = startTime.AddDays(7).AddSeconds(-1); // 本周日 23:59:59
return (startTime, endTime);
}
}
/// <summary>
/// 计算任务进度
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="taskCate">任务分类: 1=邀请, 2=抽赏</param>
/// <param name="startTime">开始时间</param>
/// <returns>完成数量</returns>
private async Task<int> CalculateTaskProgress(int userId, int taskCate, DateTime startTime)
{
if (taskCate == 1)
{
// 邀请好友注册: 统计推荐人为当前用户且注册时间在周期内的用户数
return await _dbContext.Users
.CountAsync(u => u.Pid == userId && u.CreatedAt >= startTime);
}
else if (taskCate == 2)
{
// 抽赏任务: 统计已支付订单数 (pay_type < 10 且 status = 1)
// 将DateTime转换为Unix时间戳进行比较
var startTimestamp = (int)((DateTimeOffset)startTime).ToUnixTimeSeconds();
return await _dbContext.Orders
.CountAsync(o => o.UserId == userId
&& o.PayType < 10
&& o.Status == 1
&& o.Addtime >= startTimestamp);
}
return 0;
}
/// <summary>
/// 根据欧气值计算欧气等级
/// </summary>
/// <param name="ouQi">当前欧气值</param>
/// <returns>欧气等级</returns>
private static int CalculateOuQiLevel(int ouQi)
{
// 等级阈值: 0=普通, 1=青铜(100), 2=白银(500), 3=黄金(1000),
// 4=铂金(3000), 5=钻石(6000), 6=星耀(10000), 7=王者(20000)
if (ouQi >= 20000) return 7;
if (ouQi >= 10000) return 6;
if (ouQi >= 6000) return 5;
if (ouQi >= 3000) return 4;
if (ouQi >= 1000) return 3;
if (ouQi >= 500) return 2;
if (ouQi >= 100) return 1;
return 0;
}
}