diff --git a/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/AbstractStatsAchievementService.java b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/AbstractStatsAchievementService.java
new file mode 100644
index 0000000000..9ecd4ad915
--- /dev/null
+++ b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/AbstractStatsAchievementService.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2018 人人开源 https://www.renren.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.epmet.modules.group.service;
+
+import com.epmet.commons.tools.constant.NumConstant;
+import com.epmet.commons.tools.exception.EpmetErrorCode;
+import com.epmet.commons.tools.exception.RenException;
+import com.epmet.commons.tools.utils.ConvertUtils;
+import com.epmet.modules.enums.AchievementTypeEnum;
+import com.epmet.modules.group.dao.ResiGroupDao;
+import com.epmet.modules.group.entity.ResiGroupAchievementConfigEntity;
+import com.epmet.modules.member.dao.ResiGroupMemberDao;
+import com.epmet.modules.support.GroupAchievementUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * desc:实时计算小组成就完成情况
+ *
+ * @author generator generator@elink-cn.com
+ * @since v1.0.0 2021-04-19
+ */
+public abstract class AbstractStatsAchievementService {
+
+ @Autowired
+ public ResiGroupAchievementConfigService achievementConfigService;
+ @Autowired
+ public ResiGroupAchievementStatsService achievementStatsService;
+ @Autowired
+ public ResiGroupDao resiGroupDao;
+ @Autowired
+ private ResiGroupMemberDao resiGroupMemberDao;
+
+ /**
+ * desc: 根据成绩类型 分页获取成就配置 按targetValue 升序
+ *
+ * @param offset
+ * @param pageSize
+ * @return java.util.List
+ * @author LiuJanJun
+ * @date 2021/4/22 1:36 下午
+ */
+ /**
+ * desc: 根据成绩类型 分页获取成就配置 按targetValue 升序
+ *
+ * @param pageNum
+ * @param pageSize
+ * @return java.util.List
+ * @author LiuJanJun
+ * @date 2021/4/22 1:36 下午
+ */
+ protected List getAchievemnetConfigPage(int pageNum, int pageSize, String achievementType) {
+ return achievementConfigService.selectMoreThanOneByValue(achievementType,(pageNum- NumConstant.ONE)*pageSize,pageSize);
+ }
+
+ /**
+ * desc:初始化配置
+ * @param achievementType
+ * @return
+ */
+ protected List initAchievementConfig(String achievementType){
+ AchievementTypeEnum anEnum = AchievementTypeEnum.getEnum(achievementType);
+ if (anEnum == null){
+ throw new RenException(EpmetErrorCode.INTERNAL_VALIDATE_ERROR.getCode());
+ }
+ if (AchievementTypeEnum.MEMBER.getCode().equals(anEnum.getCode())){
+ throw new RenException("小组人数都到10000啦?");
+ }
+ ResiGroupAchievementConfigEntity lastOne = achievementConfigService.getLastOne(achievementType);
+ List newConfigList = new ArrayList<>();
+ Integer nextTargetValue = null;
+ for (int i = 0; i < 5; i++) {
+ nextTargetValue = GroupAchievementUtils.getNextTargetValue(achievementType,lastOne.getTargetValue());
+ ResiGroupAchievementConfigEntity next = ConvertUtils.sourceToTarget(lastOne, ResiGroupAchievementConfigEntity.class);
+ next.setTargetValue(nextTargetValue);
+ newConfigList.add(next);
+ }
+ achievementConfigService.insertBatch(newConfigList);
+
+ return newConfigList;
+ }
+
+}
diff --git a/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/StatsAchievementService.java b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/StatsAchievementService.java
new file mode 100644
index 0000000000..7b532f83e0
--- /dev/null
+++ b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/StatsAchievementService.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2018 人人开源 https://www.renren.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.epmet.modules.group.service;
+
+/**
+ * desc:实时计算小组成就完成情况
+ *
+ * @author generator generator@elink-cn.com
+ * @since v1.0.0 2021-04-19
+ */
+public interface StatsAchievementService{
+
+ /**
+ * desc: 计算小组成就 统一入口
+ *
+ * @param achievementType 成就类型 小组人数、话题数、转议题数、小组内问题解决数
+ * @return java.lang.Boolean
+ * @author LiuJanJun
+ * @date 2021/4/20
+ */
+ Boolean calculateAcm(String achievementType);
+
+ /**
+ * desc: 根据小组Id计算小组成就 入口
+ *
+ * @param customerId
+ * @param groupId
+ * @param achievementType 成就类型 小组人数、话题数、转议题数、小组内问题解决数
+ * @return java.lang.Boolean
+ * @author LiuJanJun
+ * @date 2021/4/20
+ */
+ Boolean calculateAcm(String customerId, String groupId, String achievementType);
+
+
+}
diff --git a/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/impl/StatsAchievementServiceImpl.java b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/impl/StatsAchievementServiceImpl.java
new file mode 100644
index 0000000000..6e265b15bb
--- /dev/null
+++ b/epmet-module/resi-group/resi-group-server/src/main/java/com/epmet/modules/group/service/impl/StatsAchievementServiceImpl.java
@@ -0,0 +1,209 @@
+package com.epmet.modules.group.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.epmet.commons.tools.constant.NumConstant;
+import com.epmet.commons.tools.exception.EpmetErrorCode;
+import com.epmet.commons.tools.exception.RenException;
+import com.epmet.modules.enums.AchievementTypeEnum;
+import com.epmet.modules.group.entity.ResiGroupAchievementConfigEntity;
+import com.epmet.modules.group.entity.ResiGroupAchievementStatsEntity;
+import com.epmet.modules.group.service.AbstractStatsAchievementService;
+import com.epmet.modules.group.service.StatsAchievementService;
+import com.epmet.modules.member.dao.ResiGroupMemberDao;
+import com.epmet.modules.topic.dao.ResiTopicDao;
+import com.epmet.modules.topic.entity.ResiTopicEntity;
+import com.epmet.resi.group.constant.TopicConstant;
+import com.epmet.resi.group.dto.group.ResiGroupAchievementStatsDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * desc:
+ *
+ * @author: LiuJanJun
+ * @date: 2021/4/20 5:48 下午
+ * @version: 1.0
+ */
+@Slf4j
+@Service
+public class StatsAchievementServiceImpl extends AbstractStatsAchievementService implements StatsAchievementService {
+ @Autowired
+ private ResiGroupMemberDao resiGroupMemberDao;
+ @Autowired
+ private ResiTopicDao resiTopicDao;
+
+
+ /**
+ * desc: 计算小组成就 统一入口
+ *
+ * @param achievementType 成就类型
+ * @return java.lang.Boolean
+ * @author LiuJanJun
+ * @date 2021/4/20
+ */
+ @Override
+ public Boolean calculateAcm(String achievementType) {
+ if (StringUtils.isBlank(achievementType)) {
+ //计算所有类型的 小组人数、话题数、转议题数、小组内问题解决数
+ }
+ return null;
+ }
+
+ /**
+ * desc: 根据小组Id计算小组成就 入口
+ *
+ * @param customerId
+ * @param groupId
+ * @param achievementType 成就类型 小组人数、话题数、转议题数、小组内问题解决数
+ * @return java.lang.Boolean
+ * @author LiuJanJun
+ * @date 2021/4/20
+ */
+ @Override
+ public Boolean calculateAcm(String customerId, String groupId, String achievementType) {
+ AchievementTypeEnum anEnum = AchievementTypeEnum.getEnum(achievementType);
+ if (StringUtils.isBlank(customerId) || StringUtils.isBlank(groupId) || anEnum == null) {
+ return false;
+ }
+ switch (anEnum) {
+ case TOPIC:
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.lambda().eq(ResiTopicEntity::getCustomerId,customerId)
+ .eq(ResiTopicEntity::getGroupId,groupId)
+ .eq(ResiTopicEntity::getStatus, TopicConstant.AUTO_PASSED)
+ .eq(ResiTopicEntity::getDelFlag,NumConstant.ZERO);
+ int currentValue = resiTopicDao.selectCount(queryWrapper);
+ break;
+ case MEMBER:
+ int currentValue = resiGroupMemberDao.countMembers(customerId, groupId);
+ calculateMember(customerId, groupId, currentValue, achievementType);
+ break;
+ case TOISSUE:
+
+ break;
+ case RESOVLE_TOPIC:
+
+ break;
+ default:
+ log.info("calculateAcm error");
+ }
+ return true;
+ }
+
+ /**
+ * desc: 计算小组的人数等级
+ *
+ * @param customerId
+ * @param groupId
+ */
+ private void calculateMember(String customerId, String groupId,int currentValue, String achievementType) {
+
+ ResiGroupAchievementStatsEntity one = super.achievementStatsService.selectLastUnAchieved(customerId, groupId, achievementType);
+
+ List haveArrive = new ArrayList<>();
+ //如果没有实现的额成就则说明是初始化
+ if (one == null) {
+ initAchievementStat(customerId, groupId, achievementType, currentValue, haveArrive);
+ super.achievementStatsService.saveOrUpdate(haveArrive,false);
+ return;
+ }
+
+ boolean isBatch = false;
+ Integer targetValue = one.getTargetValue();
+ //改为已实现
+ if (currentValue >= targetValue) {
+ isBatch = true;
+// ResiGroupAchievementStatsEntity newStat = ConvertUtils.sourceToTarget(one, ResiGroupAchievementStatsEntity.class);
+// newStat.setCurrentValue(targetValue);
+// newStat.setIsArrive(1);
+// haveArrive.add(newStat);
+
+ boolean isContinue;
+ int pageNum = NumConstant.ONE;
+ int pageSize = NumConstant.TEN;
+ do {
+ List list = getConfigByType(achievementType,pageNum++,pageSize);
+ isContinue = buildArrivList(customerId, groupId, achievementType, currentValue, one.getTargetValue(), haveArrive, list);
+ }while (isContinue);
+ }
+
+ if (isBatch) {
+ super.achievementStatsService.saveOrUpdate(haveArrive,true);
+ } else {
+ //未实现 只更新当前值
+ ResiGroupAchievementStatsDTO newStat = new ResiGroupAchievementStatsDTO();
+ newStat.setId(one.getId());
+ newStat.setCurrentValue(currentValue);
+ super.achievementStatsService.update(newStat);
+ }
+ }
+
+ private void initAchievementStat(String customerId, String groupId, String achievementType, int currentValue, List haveArrive) {
+
+ boolean isContinue;
+ int pageNum = NumConstant.ONE;
+ int pageSize = NumConstant.TEN;
+ do { //没有任何数据说明是初始化
+ List list = getConfigByType(achievementType,pageNum++,pageSize);
+ //查询和初始化都失败啦
+ if (CollectionUtils.isEmpty(list)) {
+ log.error("calculateMember get config fail");
+ throw new RenException(EpmetErrorCode.INTERNAL_VALIDATE_ERROR.getCode());
+ }
+ isContinue = buildArrivList(customerId, groupId, achievementType, currentValue, null, haveArrive, list);
+ }while (isContinue);
+ if (CollectionUtils.isEmpty(haveArrive)) {
+ throw new RenException("小组达成成就失败");
+ }
+ }
+
+ private boolean buildArrivList(String customerId, String groupId, String achievementType, int currentValue, Integer targetValue, List haveArrive, List list) {
+ boolean isContinue = true;
+ for (ResiGroupAchievementConfigEntity configEntity : list) {
+ if (targetValue != null) {
+ //筛选出已经完成的成就
+ if (configEntity.getTargetValue()= configEntity.getTargetValue()) {
+ statsEntity.setIsArrive(1);
+ } else {
+ //如果没有达到则 放入这一条后 退出
+ statsEntity.setIsArrive(0);
+ isContinue = false;
+ break;
+ }
+ }
+ return isContinue;
+ }
+
+ private List getConfigByType(String achievementType,int pageNum,int pageSize) {
+ List list = super.getAchievemnetConfigPage(pageNum, pageSize, achievementType);
+ if (CollectionUtils.isEmpty(list)) {
+ log.warn("获取小组成就配置错误,{} 开始进行初始化规则", AchievementTypeEnum.MEMBER.getCode());
+ list = super.initAchievementConfig(AchievementTypeEnum.MEMBER.getCode());
+ }
+ return list;
+ }
+
+
+}
diff --git a/epmet-module/resi-group/resi-group-server/src/test/com/epmet/modules/group/service/impl/StatsAchievementServiceImplTest.java b/epmet-module/resi-group/resi-group-server/src/test/com/epmet/modules/group/service/impl/StatsAchievementServiceImplTest.java
new file mode 100644
index 0000000000..5c2f1bf56c
--- /dev/null
+++ b/epmet-module/resi-group/resi-group-server/src/test/com/epmet/modules/group/service/impl/StatsAchievementServiceImplTest.java
@@ -0,0 +1,25 @@
+package com.epmet.modules.group.service.impl;
+
+import com.epmet.modules.group.service.StatsAchievementService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class StatsAchievementServiceImplTest {
+ @Autowired
+ private StatsAchievementService statsAchievementService;
+
+ @Test
+ public void calculateAcm() {
+
+ String customerId = "test_cid";
+ String groupId = "test_groupId";
+ String achievementType = "member";
+ Boolean aBoolean = statsAchievementService.calculateAcm(customerId, groupId, achievementType);
+ System.out.println(aBoolean);
+ }
+}