|
|
@@ -0,0 +1,175 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
+import com.etotem.cfc.entity.FamilyChallenge;
|
|
|
+import com.etotem.cfc.entity.FamilyChallengeProgress;
|
|
|
+import com.etotem.cfc.mapper.FamilyChallengeMapper;
|
|
|
+import com.etotem.cfc.mapper.FamilyChallengeProgressMapper;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class FamilyChallengeService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private FamilyChallengeMapper familyChallengeMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private FamilyChallengeProgressMapper familyChallengeProgressMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private HealthScoreService healthScoreService;
|
|
|
+
|
|
|
+ public List<FamilyChallenge> getActiveChallenges(Long familyId) {
|
|
|
+ if (familyId == null) return new ArrayList<>();
|
|
|
+
|
|
|
+ LambdaQueryWrapper<FamilyChallenge> wrapper = new LambdaQueryWrapper<FamilyChallenge>()
|
|
|
+ .eq(FamilyChallenge::getFamilyId, familyId)
|
|
|
+ .eq(FamilyChallenge::getStatus, "active");
|
|
|
+ List<FamilyChallenge> active = familyChallengeMapper.selectList(wrapper);
|
|
|
+
|
|
|
+ if (active.isEmpty()) {
|
|
|
+ autoCreateChallenges(familyId);
|
|
|
+ active = familyChallengeMapper.selectList(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ return active;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void autoCreateChallenges(Long familyId) {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ int year = cal.get(Calendar.YEAR);
|
|
|
+ int month = cal.get(Calendar.MONTH);
|
|
|
+
|
|
|
+ cal.set(year, month, 1, 0, 0, 0);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ Date startDate = cal.getTime();
|
|
|
+
|
|
|
+ cal.add(Calendar.MONTH, 1);
|
|
|
+ Date endDate = cal.getTime();
|
|
|
+
|
|
|
+ String[][] templates = {
|
|
|
+ {"full_checkin", "全员打卡挑战", "全家连续打卡3天,一起养成好习惯!", "3", "50", ""},
|
|
|
+ {"sports", "运动PK挑战", "全周家庭总运动时长超过300分钟!", "7", "100", ""},
|
|
|
+ {"health_week", "健康周挑战", "全员每日完成微行动,连续7天健康生活!", "7", "50", "健康之家"}
|
|
|
+ };
|
|
|
+
|
|
|
+ for (String[] t : templates) {
|
|
|
+ LambdaQueryWrapper<FamilyChallenge> exists = new LambdaQueryWrapper<FamilyChallenge>()
|
|
|
+ .eq(FamilyChallenge::getFamilyId, familyId)
|
|
|
+ .eq(FamilyChallenge::getChallengeType, t[0])
|
|
|
+ .eq(FamilyChallenge::getStartDate, startDate);
|
|
|
+ if (familyChallengeMapper.selectCount(exists) > 0) continue;
|
|
|
+
|
|
|
+ FamilyChallenge challenge = new FamilyChallenge();
|
|
|
+ challenge.setFamilyId(familyId);
|
|
|
+ challenge.setChallengeType(t[0]);
|
|
|
+ challenge.setTitle(t[1]);
|
|
|
+ challenge.setDescription(t[2]);
|
|
|
+ challenge.setDurationDays(Integer.parseInt(t[3]));
|
|
|
+ challenge.setRewardPoints(Integer.parseInt(t[4]));
|
|
|
+ challenge.setRewardBadge(t[5].isEmpty() ? null : t[5]);
|
|
|
+ challenge.setStartDate(startDate);
|
|
|
+ challenge.setEndDate(endDate);
|
|
|
+ challenge.setStatus("active");
|
|
|
+ challenge.setCreatedAt(new Date());
|
|
|
+ familyChallengeMapper.insert(challenge);
|
|
|
+ log.info("已自动创建挑战: familyId={}, type={}, start={}", familyId, t[0], startDate);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public Result<Void> updateProgress(Long challengeId, Long childId, int delta) {
|
|
|
+ if (challengeId == null || childId == null) {
|
|
|
+ return Result.error("参数错误");
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<FamilyChallengeProgress> wrapper = new LambdaQueryWrapper<FamilyChallengeProgress>()
|
|
|
+ .eq(FamilyChallengeProgress::getChallengeId, challengeId)
|
|
|
+ .eq(FamilyChallengeProgress::getChildId, childId);
|
|
|
+ FamilyChallengeProgress progress = familyChallengeProgressMapper.selectOne(wrapper);
|
|
|
+
|
|
|
+ if (progress == null) {
|
|
|
+ progress = new FamilyChallengeProgress();
|
|
|
+ progress.setChallengeId(challengeId);
|
|
|
+ progress.setChildId(childId);
|
|
|
+ progress.setProgressValue(delta);
|
|
|
+ progress.setCompleted(false);
|
|
|
+ progress.setCreatedAt(new Date());
|
|
|
+ progress.setUpdatedAt(new Date());
|
|
|
+ familyChallengeProgressMapper.insert(progress);
|
|
|
+ } else {
|
|
|
+ progress.setProgressValue(progress.getProgressValue() + delta);
|
|
|
+ progress.setUpdatedAt(new Date());
|
|
|
+ familyChallengeProgressMapper.updateById(progress);
|
|
|
+ }
|
|
|
+
|
|
|
+ FamilyChallenge challenge = familyChallengeMapper.selectById(challengeId);
|
|
|
+ if (challenge != null && "active".equals(challenge.getStatus())) {
|
|
|
+ checkAndSettle(challenge);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void settleChallenge(Long challengeId) {
|
|
|
+ FamilyChallenge challenge = familyChallengeMapper.selectById(challengeId);
|
|
|
+ if (challenge == null) return;
|
|
|
+ checkAndSettle(challenge);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void checkAndSettle(FamilyChallenge challenge) {
|
|
|
+ boolean isCompleted = false;
|
|
|
+ LambdaQueryWrapper<FamilyChallengeProgress> pw = new LambdaQueryWrapper<FamilyChallengeProgress>()
|
|
|
+ .eq(FamilyChallengeProgress::getChallengeId, challenge.getId());
|
|
|
+ List<FamilyChallengeProgress> progresses = familyChallengeProgressMapper.selectList(pw);
|
|
|
+ int totalProgress = 0;
|
|
|
+ for (FamilyChallengeProgress p : progresses) {
|
|
|
+ totalProgress += (p.getProgressValue() != null ? p.getProgressValue() : 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ("full_checkin".equals(challenge.getChallengeType())) {
|
|
|
+ isCompleted = progresses.size() > 0;
|
|
|
+ for (FamilyChallengeProgress p : progresses) {
|
|
|
+ if (p.getProgressValue() == null || p.getProgressValue() < 3) {
|
|
|
+ isCompleted = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if ("sports".equals(challenge.getChallengeType())) {
|
|
|
+ isCompleted = totalProgress >= 300;
|
|
|
+ } else if ("health_week".equals(challenge.getChallengeType())) {
|
|
|
+ isCompleted = progresses.size() > 0;
|
|
|
+ for (FamilyChallengeProgress p : progresses) {
|
|
|
+ if (p.getProgressValue() == null || p.getProgressValue() < 7) {
|
|
|
+ isCompleted = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isCompleted || challenge.getEndDate() == null || new Date().after(challenge.getEndDate())) {
|
|
|
+ challenge.setStatus("completed");
|
|
|
+ familyChallengeMapper.updateById(challenge);
|
|
|
+ log.info("挑战已结算: id={}, type={}, completed={}", challenge.getId(), challenge.getChallengeType(), isCompleted);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<FamilyChallenge> getChallengeHistory(Long familyId) {
|
|
|
+ if (familyId == null) return new ArrayList<>();
|
|
|
+ LambdaQueryWrapper<FamilyChallenge> wrapper = new LambdaQueryWrapper<FamilyChallenge>()
|
|
|
+ .eq(FamilyChallenge::getFamilyId, familyId)
|
|
|
+ .eq(FamilyChallenge::getStatus, "completed")
|
|
|
+ .orderByDesc(FamilyChallenge::getEndDate);
|
|
|
+ return familyChallengeMapper.selectList(wrapper);
|
|
|
+ }
|
|
|
+}
|