diff --git a/QYZH.InteractiveMagazine.Models/Dto/UserAnswerTaskService/BatchClaimPointsOutput.cs b/QYZH.InteractiveMagazine.Models/Dto/UserAnswerTaskService/BatchClaimPointsOutput.cs
index b9a2f48..8432e3e 100644
--- a/QYZH.InteractiveMagazine.Models/Dto/UserAnswerTaskService/BatchClaimPointsOutput.cs
+++ b/QYZH.InteractiveMagazine.Models/Dto/UserAnswerTaskService/BatchClaimPointsOutput.cs
@@ -8,7 +8,7 @@ public class BatchClaimPointsInput
///
/// 任务分组Id列表(JournalPageTaskGroupId)
///
- public List GroupIds { get; set; } = [];
+ public HashSet GroupIds { get; set; } = [];
}
///
@@ -73,6 +73,11 @@ public class BatchClaimFailItem
///
public long GroupId { get; set; }
+ ///
+ /// 任务编号(从 JournalPageTask.No 字段按 - 分割取索引2,前面加"任务")
+ ///
+ public string TaskNo { get; set; }
+
///
/// 失败原因
///
diff --git a/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskUserAnswer.cs b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskUserAnswer.cs
index 3c5fc6f..2a18c41 100644
--- a/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskUserAnswer.cs
+++ b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskUserAnswer.cs
@@ -63,7 +63,7 @@ namespace QYZH.InteractiveMagazine.Models.Entity
/// Default:0
/// Nullable:False
///
- public float GrowthPoints { get; set; }
+ public int GrowthPoints { get; set; }
///
/// Desc:题目得分
diff --git a/QYZH.InteractiveMagazine.Service/UserAnswerTaskService.cs b/QYZH.InteractiveMagazine.Service/UserAnswerTaskService.cs
index c946979..3d8a047 100644
--- a/QYZH.InteractiveMagazine.Service/UserAnswerTaskService.cs
+++ b/QYZH.InteractiveMagazine.Service/UserAnswerTaskService.cs
@@ -1218,7 +1218,7 @@ public class UserAnswerTaskService(
var mainTask = relatedTasks.FirstOrDefault(t => t.Id == groupId);
if (mainTask == null)
{
- throw new BusinessException("子题目无法单独领取积分,请从主任务入口领取", ResultCode.BAD_REQUEST);
+ throw new BusinessException("跨页题目需要完成所有任务才能领取积分", ResultCode.BAD_REQUEST);
}
// 查询用户答题记录
@@ -1275,8 +1275,8 @@ public class UserAnswerTaskService(
}
// 积分、成长值、得分(均取主任务数据)
- int totalPoints = mainTask.Points;
- int totalGrowthPoints = mainTask.GrowthPoint;
+ int totalPoints = mainTaskAnswer.Points;
+ int totalGrowthPoints = mainTaskAnswer.GrowthPoints;
float score = mainTaskAnswer.Score;
if (totalPoints <= 0)
@@ -1315,6 +1315,7 @@ public class UserAnswerTaskService(
await answerRepository.Context.Updateable()
.SetColumns(u => u.Points == newPointsBalance)
.SetColumns(u => u.GrowthPoints == newGrowthPointsBalance)
+ .SetColumns(u => u.UpdatedBy == userId.ToString())
.SetColumns(u => u.UpdatedAt == DateTime.Now)
.Where(u => u.Id == userId)
.ExecuteCommandAsync();
@@ -1401,82 +1402,111 @@ public class UserAnswerTaskService(
{
throw new BusinessException("任务分组Id列表不能为空", ResultCode.BAD_REQUEST);
}
-
- var groupIds = input.GroupIds.Distinct().ToList();
+
#endregion
- #region 2. 批量查询已领取的积分记录
- // 批量查询已领取的积分记录(用于重复领取校验)
+ #region 2. 批量查询所有数据(一次性查询,避免N+1)
+ // ============================================
+ // 2. 批量查询所有数据
+ // - 所有 GroupId 对应的任务(JournalPageTask)
+ // - 所有 GroupId 对应的用户答题记录(JournalPageTaskUserAnswer)
+ // - 已领取的积分记录(用于重复领取校验)
+ // ============================================
+
+ // 2.1 批量查询所有相关任务(按 GroupId 分组)
+ var allTasks = await taskRepository.Context.Queryable()
+ .Where(t => input.GroupIds.Contains(t.GroupId))
+ .ToListAsync();
+ var tasksByGroupId = allTasks.GroupBy(t => t.GroupId).ToDictionary(g => g.Key, g => g.ToList());
+
+ // 2.2 批量查询所有用户答题记录(按 JournalPageTaskGroupId 分组)
+ var allUserAnswers = await answerRepository.Context.Queryable()
+ .Where(a => input.GroupIds.Contains(a.JournalPageTaskGroupId) && a.UserId == userId)
+ .ToListAsync();
+ var answersByGroupId = allUserAnswers.GroupBy(a => a.JournalPageTaskGroupId).ToDictionary(g => g.Key, g => g.ToList());
+
+ // 2.3 批量查询已领取的积分记录(用于重复领取校验)
var claimedRecords = await answerRepository.Context.Queryable()
- .Where(r => groupIds.Contains((long)r.RelatedId!) && r.UserId == userId)
- .Where(r => r.ChangeType == PointsChangeTypeEnum.TaskReward.ToString())
+ .Where(r => input.GroupIds.Contains((long)r.RelatedId!) && r.UserId == userId)
+ .Where(r => r.ChangeType == nameof(PointsChangeTypeEnum.TaskReward))
.ToListAsync();
var claimedGroupIds = claimedRecords.Select(r => r.RelatedId!.Value).ToHashSet();
#endregion
- #region 3. 逐个校验每个 GroupId,筛选可领取的任务
- // 存储可领取的任务信息
- var claimableTasks = new List<(long GroupId, int Points, int GrowthPoints, float Score, string TaskName, string TaskNo)>();
+ #region 3. 内存中筛选可领取的任务
+ // ============================================
+ // 3. 在内存中逐个校验每个 GroupId,筛选可领取的任务
+ // 所有数据已在步骤2中一次性查询完成,这里只做内存筛选
+ // ============================================
+ var claimableTasks = new List<(long GroupId, int Points, int GrowthPoints, float Score, string TaskNo)>();
- foreach (var groupId in groupIds)
+ foreach (var groupId in input.GroupIds)
{
try
{
- #region 3.1 根据 GroupId 查询所有相关任务
- var relatedTasks = await taskRepository.Context.Queryable()
- .Where(t => t.GroupId == groupId)
- .ToListAsync();
-
- if (relatedTasks == null || relatedTasks.Count == 0)
+ // 3.1 从内存中获取相关任务
+ if (!tasksByGroupId.TryGetValue(groupId, out var relatedTasks) || relatedTasks.Count == 0)
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = string.Empty,
Message = "任务不存在"
});
continue;
}
- #endregion
- #region 3.2 判断是否跨页题目并找主任务
+ // 3.2 判断是否跨页题目并找主任务
bool isCrossPage = relatedTasks.Count > 1;
- // 主任务:Id == GroupId
var mainTask = relatedTasks.FirstOrDefault(t => t.Id == groupId);
+
+ // ============================================
+ // 【任务编号计算】
+ // 从 JournalPageTask.No 字段按 - 分割,取索引为 2 的部分,前面加"任务"
+ // 如果找不到主任务,尝试从子任务中计算
+ // ============================================
+ string taskNo = string.Empty;
+ var taskForNo = mainTask ?? relatedTasks.FirstOrDefault();
+ if (taskForNo != null && !string.IsNullOrEmpty(taskForNo.No))
+ {
+ var parts = taskForNo.No.Split('-');
+ if (parts.Length >= 3)
+ {
+ taskNo = $"任务{parts[2]}";
+ }
+ }
+
if (mainTask == null)
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "子题目无法单独领取积分,请从主任务入口领取"
});
continue;
}
- #endregion
- #region 3.3 查询用户答题记录
- var userAnswers = await answerRepository.Context.Queryable()
- .Where(a => a.JournalPageTaskGroupId == groupId && a.UserId == userId)
- .ToListAsync();
-
- if (userAnswers == null || userAnswers.Count == 0)
+ // 3.3 从内存中获取用户答题记录
+ if (!answersByGroupId.TryGetValue(groupId, out var userAnswers) || userAnswers.Count == 0)
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "请先完成答题再领取积分"
});
continue;
}
- #endregion
- #region 3.4 完成校验
- // 校验主任务完成状态:Status=1
+ // 3.4 完成校验
var mainTaskAnswer = userAnswers.FirstOrDefault(a => a.JournalPageTaskId == groupId);
if (mainTaskAnswer == null || mainTaskAnswer.Status != (int)UserAnswerStatusEnum.Complete)
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "请先完成答题再领取积分"
});
continue;
@@ -1485,43 +1515,38 @@ public class UserAnswerTaskService(
// 跨页题目:校验所有任务
if (isCrossPage)
{
- bool allCompleted = true;
- foreach (var task in relatedTasks)
+ bool allCompleted = relatedTasks.All(task =>
{
var answer = userAnswers.FirstOrDefault(a => a.JournalPageTaskId == task.Id);
- if (answer == null || answer.Status != (int)UserAnswerStatusEnum.Complete)
- {
- allCompleted = false;
- break;
- }
- }
+ return answer != null && answer.Status == (int)UserAnswerStatusEnum.Complete;
+ });
if (!allCompleted)
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "跨页题目需要完成所有任务才能领取积分"
});
continue;
}
}
- #endregion
- #region 3.5 重复领取校验
+ // 3.5 重复领取校验
if (claimedGroupIds.Contains(groupId))
{
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "积分已领取,请勿重复领取"
});
continue;
}
- #endregion
- #region 3.6 计算积分、成长值、得分
- int points = mainTask.Points;
- int growthPoints = mainTask.GrowthPoint;
+ // 3.6 计算积分、成长值、得分
+ int points = mainTaskAnswer.Points;
+ int growthPoints = mainTaskAnswer.GrowthPoints;
float score = mainTaskAnswer.Score;
if (points <= 0)
@@ -1529,34 +1554,35 @@ public class UserAnswerTaskService(
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = "该任务无积分可领取"
});
continue;
}
- var taskName = mainTask.Task ?? string.Empty;
-
- // 任务编号计算
- string taskNo = string.Empty;
- if (!string.IsNullOrEmpty(mainTask.No))
- {
- var parts = mainTask.No.Split('-');
- if (parts.Length >= 3)
- {
- taskNo = $"任务{parts[2]}";
- }
- }
- #endregion
-
// 添加到可领取列表
- claimableTasks.Add((groupId, points, growthPoints, score, taskName, taskNo));
+ claimableTasks.Add((groupId, points, growthPoints, score, taskNo));
}
catch (Exception ex)
{
- // 捕获异常并添加到失败列表,不中断其他任务的处理
+ // 异常情况下,尝试从已查询的数据中计算 taskNo
+ string taskNo = string.Empty;
+ if (tasksByGroupId.TryGetValue(groupId, out var tasks) && tasks.Count > 0)
+ {
+ var task = tasks.FirstOrDefault(t => t.Id == groupId) ?? tasks.FirstOrDefault();
+ if (task != null && !string.IsNullOrEmpty(task.No))
+ {
+ var parts = task.No.Split('-');
+ if (parts.Length >= 3)
+ {
+ taskNo = $"任务{parts[2]}";
+ }
+ }
+ }
result.FailItems.Add(new BatchClaimFailItem
{
GroupId = groupId,
+ TaskNo = taskNo,
Message = ex.Message
});
}
@@ -1612,6 +1638,7 @@ public class UserAnswerTaskService(
await answerRepository.Context.Updateable()
.SetColumns(u => u.Points == newPointsBalance)
.SetColumns(u => u.GrowthPoints == newGrowthPointsBalance)
+ .SetColumns(u => u.UpdatedBy == userId.ToString())
.SetColumns(u => u.UpdatedAt == DateTime.Now)
.Where(u => u.Id == userId)
.ExecuteCommandAsync();
diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/WeChat/UserAnswerTaskController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/WeChat/UserAnswerTaskController.cs
index 6290909..e80782f 100644
--- a/QYZH.InteractiveMagazine.WebApi/Controllers/WeChat/UserAnswerTaskController.cs
+++ b/QYZH.InteractiveMagazine.WebApi/Controllers/WeChat/UserAnswerTaskController.cs
@@ -203,7 +203,7 @@ public class UserAnswerTaskController : WeChatBaseController
{
try
{
- var userId = ConstUserId;//GetCurrentUserId();
+ var userId = GetCurrentUserId();
if (userId == 0)
{
return BaseResponse.Fail(ResultCode.DENY, "未获取到用户信息");
@@ -239,7 +239,7 @@ public class UserAnswerTaskController : WeChatBaseController
{
try
{
- var userId = GetCurrentUserId();
+ var userId = ConstUserId;//GetCurrentUserId();
if (userId == 0)
{
return BaseResponse.Fail(ResultCode.DENY, "未获取到用户信息");