|
|
@@ -0,0 +1,126 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.etotem.cfc.entity.Child;
|
|
|
+import com.etotem.cfc.entity.OnboardingTask;
|
|
|
+import com.etotem.cfc.mapper.ChildMapper;
|
|
|
+import com.etotem.cfc.mapper.OnboardingTaskMapper;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class OnboardingService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private OnboardingTaskMapper onboardingTaskMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private PointsService pointsService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private EnergyService energyService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ChildMapper childMapper;
|
|
|
+
|
|
|
+ private static final Map<String, int[]> REWARDS = new LinkedHashMap<>();
|
|
|
+ static {
|
|
|
+ REWARDS.put("REGISTER", new int[]{100, 10});
|
|
|
+ REWARDS.put("COMPLETE_PROFILE", new int[]{50, 5});
|
|
|
+ REWARDS.put("ADD_CHILD", new int[]{100, 10});
|
|
|
+ REWARDS.put("FIRST_CHECKIN", new int[]{30, 5});
|
|
|
+ REWARDS.put("FIRST_TASK", new int[]{50, 5});
|
|
|
+ REWARDS.put("BIND_REFERRAL", new int[]{50, 10});
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Initialize 6 PENDING onboarding tasks for a new user
|
|
|
+ */
|
|
|
+ public void initForUser(Long userId) {
|
|
|
+ for (Map.Entry<String, int[]> entry : REWARDS.entrySet()) {
|
|
|
+ OnboardingTask task = new OnboardingTask();
|
|
|
+ task.setUserId(userId);
|
|
|
+ task.setTaskType(entry.getKey());
|
|
|
+ task.setRewardPoints(entry.getValue()[0]);
|
|
|
+ task.setRewardEnergy(entry.getValue()[1]);
|
|
|
+ task.setStatus("PENDING");
|
|
|
+ task.setCreatedAt(new Date());
|
|
|
+ onboardingTaskMapper.insert(task);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Mark a task as COMPLETED if it is still PENDING
|
|
|
+ */
|
|
|
+ public void completeTask(Long userId, String taskType) {
|
|
|
+ OnboardingTask task = onboardingTaskMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<OnboardingTask>()
|
|
|
+ .eq(OnboardingTask::getUserId, userId)
|
|
|
+ .eq(OnboardingTask::getTaskType, taskType)
|
|
|
+ .eq(OnboardingTask::getStatus, "PENDING")
|
|
|
+ .last("LIMIT 1")
|
|
|
+ );
|
|
|
+ if (task != null) {
|
|
|
+ task.setStatus("COMPLETED");
|
|
|
+ task.setCompletedAt(new Date());
|
|
|
+ onboardingTaskMapper.updateById(task);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Claim reward for a COMPLETED task: set CLAIMED, award points + energy
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public String claimReward(Long userId, String taskType) {
|
|
|
+ OnboardingTask task = onboardingTaskMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<OnboardingTask>()
|
|
|
+ .eq(OnboardingTask::getUserId, userId)
|
|
|
+ .eq(OnboardingTask::getTaskType, taskType)
|
|
|
+ .eq(OnboardingTask::getStatus, "COMPLETED")
|
|
|
+ .last("LIMIT 1")
|
|
|
+ );
|
|
|
+ if (task == null) {
|
|
|
+ return "任务未完成或已领取";
|
|
|
+ }
|
|
|
+
|
|
|
+ task.setStatus("CLAIMED");
|
|
|
+ onboardingTaskMapper.updateById(task);
|
|
|
+
|
|
|
+ // Find child by userId to award points and energy
|
|
|
+ Child child = childMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<Child>()
|
|
|
+ .eq(Child::getUserId, userId)
|
|
|
+ .last("LIMIT 1")
|
|
|
+ );
|
|
|
+ if (child != null) {
|
|
|
+ try {
|
|
|
+ pointsService.awardSystemPoints(child.getId(), task.getRewardPoints(),
|
|
|
+ "新手引导奖励: " + taskType);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // Points award failure should not block claim
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ energyService.awardEnergy(child.getId(), "onboarding", 0L,
|
|
|
+ task.getRewardEnergy(), "新手引导奖励: " + taskType, 30);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // Energy award failure should not block claim
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "奖励已发放";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get all onboarding tasks for a user
|
|
|
+ */
|
|
|
+ public List<OnboardingTask> getProgress(Long userId) {
|
|
|
+ return onboardingTaskMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<OnboardingTask>()
|
|
|
+ .eq(OnboardingTask::getUserId, userId)
|
|
|
+ .orderByAsc(OnboardingTask::getTaskType)
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|