|
|
@@ -14,6 +14,7 @@ import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import javax.annotation.Resource;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
@@ -40,6 +41,7 @@ public class TaskService implements TaskServiceInterface {
|
|
|
private PointsLogMapper pointsLogMapper;
|
|
|
|
|
|
@Resource
|
|
|
+ @Lazy
|
|
|
private UserService userService;
|
|
|
|
|
|
@Resource
|
|
|
@@ -54,15 +56,9 @@ public class TaskService implements TaskServiceInterface {
|
|
|
@Resource
|
|
|
private EnergyService energyService;
|
|
|
|
|
|
- @Resource
|
|
|
- private OnboardingService onboardingService;
|
|
|
-
|
|
|
@Resource
|
|
|
private FamilyRelationshipScoreMapper familyRelationshipScoreMapper;
|
|
|
|
|
|
- @Resource
|
|
|
- private GrowthTaskService growthTaskService;
|
|
|
-
|
|
|
@Resource
|
|
|
private CartService cartService;
|
|
|
|
|
|
@@ -78,6 +74,9 @@ public class TaskService implements TaskServiceInterface {
|
|
|
@Resource
|
|
|
private SurveyTemplateMapper surveyTemplateMapper;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private TaskTemplateMapper taskTemplateMapper;
|
|
|
+
|
|
|
private static final int EARLY_BONUS = 1; // 提前完成奖励
|
|
|
private static final int PENALTY_MAX_DAILY = 5; // 每日最多扣分
|
|
|
private static final int LATE_GRACE_MINUTES = 10; // 10分钟内不算迟到
|
|
|
@@ -287,8 +286,15 @@ task.setReviewByCategory(dto.getReviewByCategory() != null ? dto.getReviewByCate
|
|
|
task.setStartCount(0);
|
|
|
task.setMinDurationSeconds(dto.getMinDurationSeconds() != null ? dto.getMinDurationSeconds() : 0);
|
|
|
|
|
|
- task.setSourceType(dto.getSourceType());
|
|
|
+task.setSourceType(dto.getSourceType() != null ? dto.getSourceType() : "self");
|
|
|
task.setSourceId(dto.getSourceId());
|
|
|
+ task.setIsDailyProgress(dto.getIsDailyProgress() != null ? dto.getIsDailyProgress() : 0);
|
|
|
+ task.setTargetValue(dto.getTargetValue());
|
|
|
+
|
|
|
+ // 进度型任务无 deadline(原 growth_task DAILY:每日重置,无截止时间)
|
|
|
+ if (task.getIsDailyProgress() != null && task.getIsDailyProgress() == 1) {
|
|
|
+ task.setDeadline(null);
|
|
|
+ }
|
|
|
|
|
|
return task;
|
|
|
}
|
|
|
@@ -322,9 +328,16 @@ public List<Task> getTodayTasks(Long memberId, String dimensionCode) {
|
|
|
|
|
|
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<Task>()
|
|
|
.eq(Task::getFamilyMemberId, memberId)
|
|
|
- .ge(Task::getDeadline, startOfDay)
|
|
|
- .lt(Task::getDeadline, endOfDay)
|
|
|
.in(Task::getStatus, Arrays.asList("pending", "completed", "locked", "pending_review"))
|
|
|
+ .and(w -> w
|
|
|
+ // 普通任务:按 deadline 判断今日
|
|
|
+ .and(w2 -> w2.isNotNull(Task::getDeadline)
|
|
|
+ .ge(Task::getDeadline, startOfDay)
|
|
|
+ .lt(Task::getDeadline, endOfDay))
|
|
|
+ // 进度型任务:按 createdAt 判断今日(deadline 为 NULL)
|
|
|
+ .or(w3 -> w3.eq(Task::getIsDailyProgress, 1)
|
|
|
+ .ge(Task::getCreatedAt, startOfDay)
|
|
|
+ .lt(Task::getCreatedAt, endOfDay)))
|
|
|
.orderByAsc(Task::getDeadline);
|
|
|
|
|
|
if (dimensionCode != null && !dimensionCode.isEmpty()) {
|
|
|
@@ -336,6 +349,7 @@ public List<Task> getTodayTasks(Long memberId, String dimensionCode) {
|
|
|
|
|
|
SortUtil.applySort(wrapper);
|
|
|
List<Task> all = taskMapper.selectList(wrapper);
|
|
|
+ fillProgress(all, memberId);
|
|
|
return filterLockedChildren(all);
|
|
|
}
|
|
|
|
|
|
@@ -768,7 +782,7 @@ public List<Task> getTodayTasks(Long memberId, String dimensionCode) {
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
result.put("pointsEarned", pointsEarned);
|
|
|
|
|
|
- try { FamilyMember child = familyMemberMapper.selectById(task.getFamilyMemberId()); if (child != null) { onboardingService.completeTask(child.getUserId(), "FIRST_TASK"); } } catch (Exception e) { /* onboarding trigger failure should not block task completion */ }
|
|
|
+ try { FamilyMember child = familyMemberMapper.selectById(task.getFamilyMemberId()); if (child != null) { this.completeOnboardingTask(child.getUserId(), "FIRST_TASK"); } } catch (Exception e) { /* onboarding trigger failure should not block task completion */ }
|
|
|
result.put("newBalance", user.getTotalPoints());
|
|
|
result.put("needReview", task.getNeedReview() == 1);
|
|
|
|
|
|
@@ -895,7 +909,7 @@ public List<Task> getTodayTasks(Long memberId, String dimensionCode) {
|
|
|
|
|
|
try {
|
|
|
if (child.getUserId() != null) {
|
|
|
- growthTaskService.updateProgress(child.getUserId(), "DAILY_TASK", 1);
|
|
|
+ this.updateProgress(child.getUserId(), "DAILY_TASK", 1);
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
log.warn("成长任务进度更新失败: memberId={}, error={}", memberId, e.getMessage());
|
|
|
@@ -1520,4 +1534,336 @@ return 0; // 达到每日扣分上限
|
|
|
log.warn("调研任务自动生成模板失败(不影响任务创建): taskId={}, error={}", task.getId(), e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // ==================== 统一任务系统:成长任务迁移(原 GrowthTaskService) ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 回填进度型任务的当前进度(progress/todayDone,不入库)
|
|
|
+ */
|
|
|
+ private void fillProgress(List<Task> tasks, Long memberId) {
|
|
|
+ if (tasks == null || tasks.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (Task t : tasks) {
|
|
|
+ if (t.getIsDailyProgress() != null && t.getIsDailyProgress() == 1) {
|
|
|
+ TaskExecution exec = taskExecutionMapper.selectOne(new LambdaQueryWrapper<TaskExecution>()
|
|
|
+ .eq(TaskExecution::getTaskId, t.getId())
|
|
|
+ .eq(TaskExecution::getMemberId, memberId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ int progress = 0;
|
|
|
+ if (exec != null && exec.getExtra() != null) {
|
|
|
+ try {
|
|
|
+ progress = JSON.parseObject(exec.getExtra()).getIntValue("progress");
|
|
|
+ } catch (Exception ignore) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ t.setProgress(progress);
|
|
|
+ t.setTodayDone("completed".equals(t.getStatus()) ? 1 : 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:更新每日进度型任务的进度(原 growth_task updateProgress)
|
|
|
+ * 按 (userId→familyMemberId, taskKey) 找当日任务实例,累计进度,达标自动完成+发奖
|
|
|
+ * taskKey 匹配约定:title 精确匹配 OR title 以 "[taskKey]" 前缀匹配(迁移时 task_key 拼入 title)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public void updateProgress(Long userId, String taskKey, int increment) {
|
|
|
+ if (userId == null) {
|
|
|
+ // 未绑定登录账号的家庭成员(如仅建档的孩子)无成长任务进度
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (member == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ cal.set(Calendar.MINUTE, 0);
|
|
|
+ cal.set(Calendar.SECOND, 0);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ Date startOfDay = cal.getTime();
|
|
|
+ cal.add(Calendar.DAY_OF_MONTH, 1);
|
|
|
+ Date endOfDay = cal.getTime();
|
|
|
+
|
|
|
+ Task task = taskMapper.selectOne(new LambdaQueryWrapper<Task>()
|
|
|
+ .eq(Task::getFamilyMemberId, member.getId())
|
|
|
+ .eq(Task::getIsDailyProgress, 1)
|
|
|
+ .ge(Task::getCreatedAt, startOfDay)
|
|
|
+ .lt(Task::getCreatedAt, endOfDay)
|
|
|
+ .and(w -> w.eq(Task::getTitle, taskKey)
|
|
|
+ .or().likeRight(Task::getTitle, "[" + taskKey + "]"))
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (task == null) {
|
|
|
+ log.warn("统一任务进度更新:未找到今日进度型任务 taskKey={}, userId={}", taskKey, userId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if ("completed".equals(task.getStatus())) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读当前进度(task_executions.extra.progress),累加
|
|
|
+ TaskExecution exec = taskExecutionMapper.selectOne(new LambdaQueryWrapper<TaskExecution>()
|
|
|
+ .eq(TaskExecution::getTaskId, task.getId())
|
|
|
+ .eq(TaskExecution::getMemberId, member.getId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ int progress = 0;
|
|
|
+ if (exec != null && exec.getExtra() != null) {
|
|
|
+ try {
|
|
|
+ progress = JSON.parseObject(exec.getExtra()).getIntValue("progress");
|
|
|
+ } catch (Exception ignore) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ progress += increment;
|
|
|
+ int target = task.getTargetValue() != null ? task.getTargetValue() : 1;
|
|
|
+
|
|
|
+ if (exec == null) {
|
|
|
+ exec = new TaskExecution();
|
|
|
+ exec.setTaskId(task.getId());
|
|
|
+ exec.setMemberId(member.getId());
|
|
|
+ exec.setStatus("started");
|
|
|
+ exec.setStartedAt(new Date());
|
|
|
+ exec.setCreatedAt(new Date());
|
|
|
+ }
|
|
|
+ exec.setStatus("finished");
|
|
|
+ exec.setFinishedAt(new Date());
|
|
|
+ exec.setExtra("{\"progress\":" + progress + ",\"target\":" + target + "}");
|
|
|
+ if (exec.getId() == null) {
|
|
|
+ taskExecutionMapper.insert(exec);
|
|
|
+ } else {
|
|
|
+ taskExecutionMapper.updateById(exec);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 达标自动完成 + 发奖(复用现有奖励链路)
|
|
|
+ if (progress >= target) {
|
|
|
+ awardTaskCompletionRewards(task, member.getId(), new Date());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:AI 对话生成任务(原 growth_task createDynamicTask)
|
|
|
+ * 直接写入 tasks 表,source_type=ai
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public Long createDynamicTask(Long userId, String title, String description,
|
|
|
+ String dimension, Integer rewardPoints, String sourceConversationId) {
|
|
|
+ User user = userService.getUserInfo(userId);
|
|
|
+ Task task = new Task();
|
|
|
+ task.setFamilyId(user.getFamilyId());
|
|
|
+ task.setCreatorId(userId);
|
|
|
+ task.setExecutorType("child");
|
|
|
+ // 执行者:AI 任务发给当前用户对应家庭成员(若有)
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (member != null) {
|
|
|
+ task.setExecutorId(member.getId());
|
|
|
+ task.setFamilyMemberId(member.getId());
|
|
|
+ task.setChildId(member.getId());
|
|
|
+ }
|
|
|
+ task.setTitle(title);
|
|
|
+ task.setDescription(description);
|
|
|
+ task.setPoints(rewardPoints != null ? rewardPoints : 10);
|
|
|
+ task.setCategory("成长");
|
|
|
+ task.setStatus("pending");
|
|
|
+ task.setNeedReview(0);
|
|
|
+ task.setIsTemplate(0);
|
|
|
+ task.setSourceType("ai");
|
|
|
+ task.setSourceId(0L);
|
|
|
+ task.setDimensionCode(dimension != null ? dimension : "body");
|
|
|
+ task.setMemberOnly(0);
|
|
|
+ task.setDeadline(new Date(System.currentTimeMillis() + 7L * 24 * 3600 * 1000)); // 7天有效期
|
|
|
+ task.setCreatedAt(new Date());
|
|
|
+ task.setUpdatedAt(new Date());
|
|
|
+ taskMapper.insert(task);
|
|
|
+ log.info("创建AI动态任务: userId={}, taskId={}, title={}", userId, task.getId(), title);
|
|
|
+ return task.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:查询用户每日进度型任务列表(原 growth-task/list)
|
|
|
+ * type: DAILY(NEWBIE 在 Task 5 处理)
|
|
|
+ */
|
|
|
+ public List<Map<String, Object>> getGrowthTaskList(Long userId, String type, String dimension) {
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ List<Map<String, Object>> result = new ArrayList<>();
|
|
|
+ if (member == null || !"DAILY".equals(type)) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ cal.set(Calendar.MINUTE, 0);
|
|
|
+ cal.set(Calendar.SECOND, 0);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ Date startOfDay = cal.getTime();
|
|
|
+ cal.add(Calendar.DAY_OF_MONTH, 1);
|
|
|
+ Date endOfDay = cal.getTime();
|
|
|
+
|
|
|
+ List<Task> tasks = taskMapper.selectList(new LambdaQueryWrapper<Task>()
|
|
|
+ .eq(Task::getFamilyMemberId, member.getId())
|
|
|
+ .eq(Task::getIsDailyProgress, 1)
|
|
|
+ .ge(Task::getCreatedAt, startOfDay)
|
|
|
+ .lt(Task::getCreatedAt, endOfDay)
|
|
|
+ .orderByAsc(Task::getId));
|
|
|
+ for (Task task : tasks) {
|
|
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
+ item.put("taskLogId", task.getId());
|
|
|
+ item.put("id", task.getId());
|
|
|
+ item.put("type", "DAILY");
|
|
|
+ item.put("title", task.getTitle());
|
|
|
+ item.put("description", task.getDescription());
|
|
|
+ item.put("rewardPoints", task.getPoints());
|
|
|
+ item.put("rewardEnergy", 0);
|
|
|
+ item.put("targetValue", task.getTargetValue() != null ? task.getTargetValue() : 1);
|
|
|
+ item.put("dimension", task.getDimensionCode());
|
|
|
+
|
|
|
+ TaskExecution exec = taskExecutionMapper.selectOne(new LambdaQueryWrapper<TaskExecution>()
|
|
|
+ .eq(TaskExecution::getTaskId, task.getId())
|
|
|
+ .eq(TaskExecution::getMemberId, member.getId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ int progress = 0;
|
|
|
+ if (exec != null && exec.getExtra() != null) {
|
|
|
+ try {
|
|
|
+ progress = JSON.parseObject(exec.getExtra()).getIntValue("progress");
|
|
|
+ } catch (Exception ignore) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ item.put("progress", progress);
|
|
|
+ item.put("completed", "completed".equals(task.getStatus()) ? 1 : 0);
|
|
|
+ item.put("claimed", 0); // 统一任务系统:自动发放,无 claimed
|
|
|
+ result.add(item);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 统一任务系统:新人引导迁移(原 OnboardingService) ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:新用户注册初始化新人引导任务
|
|
|
+ * 按 admin_task_templates 中 onboarding_sequence 有值的模板生成 tasks(source_type=onboarding)
|
|
|
+ * 顺序链:sequence 递增,前序未完成则后序 locked(复用 prerequisite_task_id + locked 状态)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public void initOnboardingTasks(Long userId) {
|
|
|
+ User user = userService.getUserInfo(userId);
|
|
|
+ if (user == null || user.getFamilyId() == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 幂等:该用户已有 onboarding 任务则跳过
|
|
|
+ Long existing = taskMapper.selectCount(new LambdaQueryWrapper<Task>()
|
|
|
+ .eq(Task::getCreatorId, userId)
|
|
|
+ .eq(Task::getSourceType, "onboarding"));
|
|
|
+ if (existing != null && existing > 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<TaskTemplate> templates = taskTemplateMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<TaskTemplate>()
|
|
|
+ .eq(TaskTemplate::getIsActive, 1)
|
|
|
+ .isNotNull(TaskTemplate::getOnboardingSequence)
|
|
|
+ .orderByAsc(TaskTemplate::getOnboardingSequence));
|
|
|
+ if (templates.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ Date now = new Date();
|
|
|
+ Long prevTaskId = null;
|
|
|
+ for (TaskTemplate tpl : templates) {
|
|
|
+ Task task = new Task();
|
|
|
+ task.setFamilyId(user.getFamilyId());
|
|
|
+ task.setCreatorId(userId);
|
|
|
+ task.setExecutorType("child");
|
|
|
+ if (member != null) {
|
|
|
+ task.setExecutorId(member.getId());
|
|
|
+ task.setFamilyMemberId(member.getId());
|
|
|
+ task.setChildId(member.getId());
|
|
|
+ }
|
|
|
+ task.setTitle(tpl.getTitle());
|
|
|
+ task.setDescription(tpl.getDescription());
|
|
|
+ task.setPoints(tpl.getPoints() != null ? tpl.getPoints() : 2);
|
|
|
+ task.setCategory(tpl.getCategory());
|
|
|
+ task.setStatus(prevTaskId == null ? "pending" : "locked"); // 首任务可直接做,后续需解锁
|
|
|
+ task.setNeedReview(tpl.getNeedReview() != null ? tpl.getNeedReview() : 0);
|
|
|
+ task.setIsTemplate(0);
|
|
|
+ task.setSourceType("onboarding");
|
|
|
+ task.setTemplateId(tpl.getId());
|
|
|
+ task.setPrerequisiteTaskId(prevTaskId); // 顺序链
|
|
|
+ task.setMemberOnly(0);
|
|
|
+ task.setDeadline(new Date(now.getTime() + 30L * 24 * 3600 * 1000)); // 30天有效期
|
|
|
+ task.setCreatedAt(now);
|
|
|
+ task.setUpdatedAt(now);
|
|
|
+ taskMapper.insert(task);
|
|
|
+ prevTaskId = task.getId();
|
|
|
+ }
|
|
|
+ log.info("新用户{}初始化{}条新人引导任务", userId, templates.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:完成指定新人引导任务(原 OnboardingService.completeTask)
|
|
|
+ * 按 source_type=onboarding + title 精确匹配(title 约定 = 原 taskType,如 FIRST_TASK)
|
|
|
+ */
|
|
|
+ public void completeOnboardingTask(Long userId, String templateTitle) {
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (member == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Task task = taskMapper.selectOne(new LambdaQueryWrapper<Task>()
|
|
|
+ .eq(Task::getFamilyMemberId, member.getId())
|
|
|
+ .eq(Task::getSourceType, "onboarding")
|
|
|
+ .eq(Task::getTitle, templateTitle)
|
|
|
+ .eq(Task::getStatus, "pending")
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (task != null) {
|
|
|
+ awardTaskCompletionRewards(task, member.getId(), new Date());
|
|
|
+ unlockPrerequisiteTasks(task.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一任务系统:查询用户的新人引导任务列表(原 OnboardingService.getProgress)
|
|
|
+ * 返回前端兼容结构:taskType=title、status(completed→CLAIMED,其余→PENDING)、rewardPoints、rewardEnergy
|
|
|
+ */
|
|
|
+ public List<Map<String, Object>> getOnboardingTasks(Long userId) {
|
|
|
+ FamilyMember member = familyMemberMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<FamilyMember>()
|
|
|
+ .eq(FamilyMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ List<Map<String, Object>> result = new ArrayList<>();
|
|
|
+ if (member == null) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ List<Task> tasks = taskMapper.selectList(new LambdaQueryWrapper<Task>()
|
|
|
+ .eq(Task::getFamilyMemberId, member.getId())
|
|
|
+ .eq(Task::getSourceType, "onboarding")
|
|
|
+ .orderByAsc(Task::getId));
|
|
|
+ for (Task task : tasks) {
|
|
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
+ item.put("taskType", task.getTitle());
|
|
|
+ item.put("rewardPoints", task.getPoints() != null ? task.getPoints() : 0);
|
|
|
+ item.put("rewardEnergy", task.getPoints() != null ? task.getPoints() : 0); // 能量≈积分(与 awardTaskCompletionRewards 一致)
|
|
|
+ // 状态映射:completed→CLAIMED(奖励已自动发放),其余→PENDING
|
|
|
+ item.put("status", "completed".equals(task.getStatus()) ? "CLAIMED" : "PENDING");
|
|
|
+ result.add(item);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|