283 lines
9.2 KiB
C#
283 lines
9.2 KiB
C#
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;
|
||
}
|
||
}
|