|
|
@@ -0,0 +1,208 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
+import com.etotem.cfc.entity.CircleChallenge;
|
|
|
+import com.etotem.cfc.entity.HealthCircle;
|
|
|
+import com.etotem.cfc.entity.HealthCircleMember;
|
|
|
+import com.etotem.cfc.mapper.CircleChallengeMapper;
|
|
|
+import com.etotem.cfc.mapper.HealthCircleMapper;
|
|
|
+import com.etotem.cfc.mapper.HealthCircleMemberMapper;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class HealthCircleService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private HealthCircleMapper healthCircleMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private HealthCircleMemberMapper healthCircleMemberMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private CircleChallengeMapper circleChallengeMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private FamilyHealthScoreService familyHealthScoreService;
|
|
|
+
|
|
|
+ public List<HealthCircle> getUserCircles(Long familyId) {
|
|
|
+ if (familyId == null) return new ArrayList<>();
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getFamilyId, familyId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ List<HealthCircleMember> memberships = healthCircleMemberMapper.selectList(mw);
|
|
|
+ if (memberships.isEmpty()) return new ArrayList<>();
|
|
|
+
|
|
|
+ List<Long> circleIds = new ArrayList<>();
|
|
|
+ for (HealthCircleMember m : memberships) {
|
|
|
+ circleIds.add(m.getCircleId());
|
|
|
+ }
|
|
|
+ LambdaQueryWrapper<HealthCircle> cw = new LambdaQueryWrapper<HealthCircle>()
|
|
|
+ .in(HealthCircle::getId, circleIds)
|
|
|
+ .eq(HealthCircle::getStatus, "active");
|
|
|
+ return healthCircleMapper.selectList(cw);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public Result<HealthCircle> createCircle(String name, String description, Long creatorFamilyId) {
|
|
|
+ if (name == null || name.trim().isEmpty()) {
|
|
|
+ return Result.error("圈名称不能为空");
|
|
|
+ }
|
|
|
+ int count = countActiveCircles(creatorFamilyId);
|
|
|
+ if (count >= 3) {
|
|
|
+ return Result.error("每个家庭最多加入3个健康圈");
|
|
|
+ }
|
|
|
+
|
|
|
+ HealthCircle circle = new HealthCircle();
|
|
|
+ circle.setName(name.trim());
|
|
|
+ circle.setDescription(description);
|
|
|
+ circle.setCreatorFamilyId(creatorFamilyId);
|
|
|
+ circle.setInviteCode(generateInviteCode());
|
|
|
+ circle.setMemberLimit(20);
|
|
|
+ circle.setStatus("active");
|
|
|
+ circle.setCreatedAt(new Date());
|
|
|
+ healthCircleMapper.insert(circle);
|
|
|
+
|
|
|
+ HealthCircleMember owner = new HealthCircleMember();
|
|
|
+ owner.setCircleId(circle.getId());
|
|
|
+ owner.setFamilyId(creatorFamilyId);
|
|
|
+ owner.setRole("owner");
|
|
|
+ owner.setJoinedAt(new Date());
|
|
|
+ owner.setStatus("active");
|
|
|
+ owner.setCreatedAt(new Date());
|
|
|
+ healthCircleMemberMapper.insert(owner);
|
|
|
+
|
|
|
+ log.info("已创建健康圈: id={}, name={}, familyId={}", circle.getId(), name, creatorFamilyId);
|
|
|
+ return Result.success(circle);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public Result<Void> joinCircle(String inviteCode, Long familyId) {
|
|
|
+ if (inviteCode == null || familyId == null) {
|
|
|
+ return Result.error("参数错误");
|
|
|
+ }
|
|
|
+ LambdaQueryWrapper<HealthCircle> cw = new LambdaQueryWrapper<HealthCircle>()
|
|
|
+ .eq(HealthCircle::getInviteCode, inviteCode)
|
|
|
+ .eq(HealthCircle::getStatus, "active");
|
|
|
+ HealthCircle circle = healthCircleMapper.selectOne(cw);
|
|
|
+ if (circle == null) {
|
|
|
+ return Result.error("邀请码无效或圈已解散");
|
|
|
+ }
|
|
|
+
|
|
|
+ int count = countActiveCircles(familyId);
|
|
|
+ if (count >= 3) {
|
|
|
+ return Result.error("每个家庭最多加入3个健康圈");
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getCircleId, circle.getId())
|
|
|
+ .eq(HealthCircleMember::getFamilyId, familyId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ if (healthCircleMemberMapper.selectCount(mw) > 0) {
|
|
|
+ return Result.error("已在圈中");
|
|
|
+ }
|
|
|
+
|
|
|
+ int memberCount = countCircleMembers(circle.getId());
|
|
|
+ if (memberCount >= circle.getMemberLimit()) {
|
|
|
+ return Result.error("圈已满员");
|
|
|
+ }
|
|
|
+
|
|
|
+ HealthCircleMember member = new HealthCircleMember();
|
|
|
+ member.setCircleId(circle.getId());
|
|
|
+ member.setFamilyId(familyId);
|
|
|
+ member.setRole("member");
|
|
|
+ member.setJoinedAt(new Date());
|
|
|
+ member.setStatus("active");
|
|
|
+ member.setCreatedAt(new Date());
|
|
|
+ healthCircleMemberMapper.insert(member);
|
|
|
+
|
|
|
+ log.info("家庭加入健康圈: familyId={}, circleId={}", familyId, circle.getId());
|
|
|
+ return Result.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public Result<Void> leaveCircle(Long circleId, Long familyId) {
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getCircleId, circleId)
|
|
|
+ .eq(HealthCircleMember::getFamilyId, familyId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ HealthCircleMember membership = healthCircleMemberMapper.selectOne(mw);
|
|
|
+ if (membership == null) {
|
|
|
+ return Result.error("不在该圈中");
|
|
|
+ }
|
|
|
+ membership.setStatus("left");
|
|
|
+ membership.setLeftAt(new Date());
|
|
|
+ healthCircleMemberMapper.updateById(membership);
|
|
|
+ log.info("家庭退出健康圈: familyId={}, circleId={}", familyId, circleId);
|
|
|
+ return Result.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Object> getCircleRanking(Long circleId) {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+ if (circleId == null) return result;
|
|
|
+
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getCircleId, circleId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ List<HealthCircleMember> members = healthCircleMemberMapper.selectList(mw);
|
|
|
+
|
|
|
+ List<Map<String, Object>> familyScores = new ArrayList<>();
|
|
|
+ for (HealthCircleMember m : members) {
|
|
|
+ Map<String, Object> entry = familyHealthScoreService.getFamilyRanking(m.getFamilyId(), null, "parent");
|
|
|
+ int totalScore = 0;
|
|
|
+ if (entry != null && entry.get("totalScore") != null) {
|
|
|
+ totalScore = ((Number) entry.get("totalScore")).intValue();
|
|
|
+ }
|
|
|
+ Map<String, Object> familyEntry = new HashMap<>();
|
|
|
+ familyEntry.put("familyId", m.getFamilyId());
|
|
|
+ familyEntry.put("totalScore", totalScore);
|
|
|
+ familyEntry.put("memberCount", entry.get("members") != null ? ((List) entry.get("members")).size() : 0);
|
|
|
+ familyScores.add(familyEntry);
|
|
|
+ }
|
|
|
+
|
|
|
+ familyScores.sort((a, b) -> ((Number) b.get("totalScore")).intValue() - ((Number) a.get("totalScore")).intValue());
|
|
|
+
|
|
|
+ HealthCircle circle = healthCircleMapper.selectById(circleId);
|
|
|
+ result.put("circleName", circle != null ? circle.getName() : "");
|
|
|
+ result.put("rankings", familyScores);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<CircleChallenge> getCircleChallenges(Long circleId) {
|
|
|
+ if (circleId == null) return new ArrayList<>();
|
|
|
+ LambdaQueryWrapper<CircleChallenge> cw = new LambdaQueryWrapper<CircleChallenge>()
|
|
|
+ .eq(CircleChallenge::getCircleId, circleId)
|
|
|
+ .orderByDesc(CircleChallenge::getCreatedAt);
|
|
|
+ return circleChallengeMapper.selectList(cw);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int countActiveCircles(Long familyId) {
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getFamilyId, familyId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ return (int) healthCircleMemberMapper.selectCount(mw);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int countCircleMembers(Long circleId) {
|
|
|
+ LambdaQueryWrapper<HealthCircleMember> mw = new LambdaQueryWrapper<HealthCircleMember>()
|
|
|
+ .eq(HealthCircleMember::getCircleId, circleId)
|
|
|
+ .eq(HealthCircleMember::getStatus, "active");
|
|
|
+ return (int) healthCircleMemberMapper.selectCount(mw);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateInviteCode() {
|
|
|
+ String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
|
+ StringBuilder code = new StringBuilder();
|
|
|
+ Random rnd = new Random();
|
|
|
+ for (int i = 0; i < 6; i++) {
|
|
|
+ code.append(chars.charAt(rnd.nextInt(chars.length())));
|
|
|
+ }
|
|
|
+ return code.toString();
|
|
|
+ }
|
|
|
+}
|