|
@@ -6,9 +6,12 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.google.common.collect.Lists;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
|
|
|
import com.yonge.cooleshow.auth.api.entity.SysUser;
|
|
|
import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
|
|
|
+import com.yonge.cooleshow.biz.dal.dao.StudentDao;
|
|
|
+import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanDto;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanPayDto;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
|
|
@@ -22,8 +25,13 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.ActivityPlanReward;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.ActivityRegistration;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
|
|
|
+import com.yonge.cooleshow.biz.dal.entity.Student;
|
|
|
+import com.yonge.cooleshow.biz.dal.entity.Subject;
|
|
|
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.EQueryOp;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.MK;
|
|
|
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityPlanEvaluationService;
|
|
@@ -32,21 +40,33 @@ import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityPlanStandardService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityRegistrationService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.ActivityRewardService;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.SysMessageService;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.ActivityMusicVo;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
|
|
|
+import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.MusicActivityVo;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.activity.ActivityTeacherWrapper;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
|
|
|
+import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
|
|
|
import com.yonge.cooleshow.common.entity.HttpResponseResult;
|
|
|
-import com.yonge.cooleshow.common.enums.*;
|
|
|
+import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
|
|
|
+import com.yonge.cooleshow.common.enums.ActivityShareEnum;
|
|
|
+import com.yonge.cooleshow.common.enums.ActivityTypeEnum;
|
|
|
+import com.yonge.cooleshow.common.enums.CacheNameEnum;
|
|
|
+import com.yonge.cooleshow.common.enums.EStatus;
|
|
|
+import com.yonge.cooleshow.common.enums.RegistrationMethodEnum;
|
|
|
+import com.yonge.cooleshow.common.enums.YesOrNoEnum;
|
|
|
import com.yonge.toolset.base.exception.BizException;
|
|
|
import com.yonge.toolset.base.util.StringUtil;
|
|
|
+import com.yonge.toolset.base.util.ThreadPool;
|
|
|
import com.yonge.toolset.payment.util.DistributedLock;
|
|
|
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.joda.time.DateTime;
|
|
|
+import org.redisson.api.RLock;
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
@@ -104,6 +124,10 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
|
|
|
@Autowired
|
|
|
private RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ private StudentDao studentMapper;
|
|
|
+ @Autowired
|
|
|
+ private SubjectService subjectService;
|
|
|
|
|
|
//保存/更新拓展字段
|
|
|
private static final Map<ActivityTypeEnum, Consumer<ActivityPlanDto>> saveOrUpdateExpand = new HashMap<>();
|
|
@@ -169,9 +193,50 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
|
|
|
List<ActivityPlanVo> wrappers = baseMapper.selectPage(page, query);
|
|
|
|
|
|
+ if (CollectionUtils.isEmpty(wrappers)) {
|
|
|
+ return page.setRecords(wrappers);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> activityIds = wrappers.stream()
|
|
|
+ .map(ActivityPlan::getId).distinct().collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 参与人数
|
|
|
+ Map<Long, Integer> participantNumMap = Maps.newConcurrentMap();
|
|
|
+ // 获奖人数
|
|
|
+ Map<Long, Integer> winnerNumMap = Maps.newConcurrentMap();
|
|
|
+ Lists.partition(activityIds, 30).parallelStream().forEach(item ->
|
|
|
+
|
|
|
+ Lists.newArrayList(EQueryOp.values()).parallelStream().forEach(dataType -> {
|
|
|
+
|
|
|
+ switch (dataType) {
|
|
|
+ case FUNCTION_1:
|
|
|
+ // 参与人数
|
|
|
+ Map<Long, Integer> participantMap = getBaseMapper().selectActivityParticipateStatInfo(activityIds).stream()
|
|
|
+ .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));
|
|
|
+
|
|
|
+ participantNumMap.putAll(participantMap);
|
|
|
+ break;
|
|
|
+ case FUNCTION_2:
|
|
|
+ // 获奖人数
|
|
|
+ Map<Long, Integer> winnerMap = getBaseMapper().selectActivityWinnerStatInfo(activityIds).stream()
|
|
|
+ .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));
|
|
|
+
|
|
|
+ winnerNumMap.putAll(winnerMap);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
// 分享活动-参与人数获奖人数相等
|
|
|
for (ActivityPlanVo item : wrappers) {
|
|
|
|
|
|
+ // 参与人数、获奖人数
|
|
|
+ item.registrationNum(participantNumMap.getOrDefault(item.getId(), 0))
|
|
|
+ .rewardNum(winnerNumMap.getOrDefault(item.getId(), 0));
|
|
|
+
|
|
|
// 重置分享活动获奖与参与人数
|
|
|
if (ActivityTypeEnum.SHARE == item.getActivityType()) {
|
|
|
item.setRegistrationNum(item.getRewardNum());
|
|
@@ -434,6 +499,11 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
@Override
|
|
|
public MusicActivityVo getActivityInfo(Long activityPlanId, SysUser user) {
|
|
|
ActivityPlan activityPlan = this.getById(activityPlanId);
|
|
|
+
|
|
|
+ if (Objects.isNull(activityPlan)) {
|
|
|
+ throw new BizException("无效的活动ID");
|
|
|
+ }
|
|
|
+
|
|
|
if (activityPlan.getActivityState() != 1) {
|
|
|
activityPlan.setActivityState(0);
|
|
|
}
|
|
@@ -447,9 +517,115 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
}
|
|
|
|
|
|
|
|
|
- // 活动曲目
|
|
|
- List<ActivityMusicVo> activityMusicVoList = activityEvaluationService.getActivityMusic(activityPlanId, userId);
|
|
|
- activityVo.setActivityMusicVoList(activityMusicVoList);
|
|
|
+ // 评测活动曲目信息
|
|
|
+ if (ActivityTypeEnum.EVALUATION == activityPlan.getActivityType()) {
|
|
|
+
|
|
|
+ // 活动曲目
|
|
|
+ List<ActivityMusicVo> activityMusicVoList = activityEvaluationService.getActivityMusic(activityPlanId, userId);
|
|
|
+ activityVo.setActivityMusicVoList(activityMusicVoList);
|
|
|
+
|
|
|
+ // 评测难度
|
|
|
+ String evaluationDifficulty = baseMapper.selectActivityPlanEvaluation(activityPlanId);
|
|
|
+ activityVo.setEvaluationDifficulty(evaluationDifficulty);
|
|
|
+
|
|
|
+ // 计算评测活动声部最高分
|
|
|
+ if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {
|
|
|
+
|
|
|
+ Map<String, List<ActivityMusicVo>> collect = activityMusicVoList.stream()
|
|
|
+ .collect(Collectors.groupingBy(x -> x.getSubjectId().split(",")[0]));
|
|
|
+
|
|
|
+ // 曲目难度
|
|
|
+ Map<Integer, String> difficultyMap = Maps.newHashMap();
|
|
|
+ difficultyMap.put(0, "BEGINNER");
|
|
|
+ difficultyMap.put(1, "ADVANCED");
|
|
|
+ difficultyMap.put(2, "PERFORMER");
|
|
|
+ // FIXME:临时增加声部曲目难度字段
|
|
|
+ for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {
|
|
|
+
|
|
|
+ int index = 0;
|
|
|
+ for (ActivityMusicVo item : entry.getValue()) {
|
|
|
+
|
|
|
+ if (StringUtils.isEmpty(item.getEvaluationDifficulty())) {
|
|
|
+
|
|
|
+ item.setEvaluationDifficulty(difficultyMap.getOrDefault(index, "PERFORMER"));
|
|
|
+ }
|
|
|
+
|
|
|
+ index += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算声部评测最高分
|
|
|
+ Map<String, ActivityRankingVo> highestScoreMap = Maps.newConcurrentMap();
|
|
|
+ collect.entrySet().parallelStream().forEach(item -> {
|
|
|
+
|
|
|
+ // 单声部计算用户总分排名用户信息
|
|
|
+ List<ActivityRankingVo> records = getBaseMapper().selectActivityHighestScoreRankingInfo(activityPlanId, Long.parseLong(item.getKey()),
|
|
|
+ 1D, 1);
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(records)) {
|
|
|
+
|
|
|
+ highestScoreMap.put(item.getKey(), records.get(0));
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 用户学生身份声部信息
|
|
|
+ List<Long> userIds = highestScoreMap.values().stream()
|
|
|
+ .map(ActivityRankingVo::getUserId).distinct().collect(Collectors.toList());
|
|
|
+
|
|
|
+ Map<Long, Long> userSubjectMap = Maps.newHashMap();
|
|
|
+ Map<Long, String> subjectNameMap = Maps.newHashMap();
|
|
|
+ if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
+
|
|
|
+ userSubjectMap = studentMapper.selectList(Wrappers.<Student>lambdaQuery().in(Student::getUserId, userIds)).stream()
|
|
|
+ .filter(x -> Objects.nonNull(x.getSubjectId()))
|
|
|
+ .collect(Collectors.toMap(Student::getUserId, x -> Long.parseLong(Optional.ofNullable(x.getSubjectId()).orElse("0").split(",")[0]), (o, n) -> n));
|
|
|
+
|
|
|
+
|
|
|
+ subjectNameMap = subjectService.findBySubjectByIdList(Lists.newArrayList(userSubjectMap.values())).stream()
|
|
|
+ .collect(Collectors.toMap(Subject::getId, Subject::getName, (o, n) -> n));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ List<MusicActivityVo.SubjectInfo> subjectInfos = Lists.newArrayList();
|
|
|
+ ActivityMusicVo musicVo;
|
|
|
+ ActivityRankingVo ranking;
|
|
|
+ for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(entry.getValue())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ musicVo = entry.getValue().get(0);
|
|
|
+
|
|
|
+ MusicActivityVo.SubjectInfo subjectInfo = MusicActivityVo.SubjectInfo.builder()
|
|
|
+ .subjectId(musicVo.getSubjectId().split(",")[0])
|
|
|
+ .subjectName(musicVo.getMusicSubject())
|
|
|
+ .join(entry.getValue().stream().anyMatch(x -> x.getJoin() == YesOrNoEnum.YES) ? 1 : 0)
|
|
|
+ .userId(0L)
|
|
|
+ .username("")
|
|
|
+ .userAvatar("")
|
|
|
+ .userSubject("")
|
|
|
+ .score(0D)
|
|
|
+ .musicNums(entry.getValue().size())
|
|
|
+ .build();
|
|
|
+ subjectInfos.add(subjectInfo);
|
|
|
+
|
|
|
+ // 最高分记录
|
|
|
+ if (highestScoreMap.containsKey(entry.getKey())) {
|
|
|
+
|
|
|
+ ranking = highestScoreMap.get(entry.getKey());
|
|
|
+
|
|
|
+ subjectInfo.userId(ranking.getUserId())
|
|
|
+ .username(ranking.getUsername())
|
|
|
+ .userAvatar(ranking.getUserAvatar())
|
|
|
+ .userSubject(subjectNameMap.getOrDefault(userSubjectMap.get(ranking.getUserId()), ""))
|
|
|
+ .score(ranking.getScore());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ activityVo.setSubjectInfos(subjectInfos);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 报名状态
|
|
|
activityVo.setJoin(activityRegistrationService.getRegistration(userId, activityPlanId));
|
|
@@ -458,10 +634,6 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
List<ActivityReward> activityRewardList = activityRewardService.getActivityReward(activityPlanId);
|
|
|
activityVo.setActivityRewardList(activityRewardList);
|
|
|
|
|
|
- // 评测难度
|
|
|
- String evaluationDifficulty = baseMapper.selectActivityPlanEvaluation(activityPlanId);
|
|
|
-
|
|
|
- activityVo.setEvaluationDifficulty(evaluationDifficulty);
|
|
|
return activityVo;
|
|
|
}
|
|
|
|
|
@@ -576,43 +748,94 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public void activityState() {
|
|
|
- List<ActivityPlan> list = baseMapper.activityState();
|
|
|
- for (ActivityPlan plan : list) {
|
|
|
- DistributedLock.of(redissonClient)
|
|
|
- .runIfLockToFunction(CacheNameEnum.LOCK_ACTIVITY_STOCK.getRedisKey(plan.getId())
|
|
|
- , (id) -> {
|
|
|
- ActivityPlan activityPlan = getById(id);
|
|
|
- if (activityPlan.getActivityState() == 0) {
|
|
|
- activityPlan.setActivityState(1);
|
|
|
- baseMapper.updateById(activityPlan);
|
|
|
-
|
|
|
- //开始活动
|
|
|
- Consumer<Long> afterFunction = startActivity.get(activityPlan.getActivityType());
|
|
|
- if (!Objects.isNull(afterFunction)) {
|
|
|
- afterFunction.accept(activityPlan.getId());
|
|
|
- }
|
|
|
- } else {
|
|
|
- activityPlan.setActivityState(0);
|
|
|
- activityPlan.setRewardFlag(1);
|
|
|
- baseMapper.updateById(activityPlan);
|
|
|
-
|
|
|
- //完成活动
|
|
|
- Consumer<Long> afterFunction = successActivity.get(activityPlan.getActivityType());
|
|
|
- if (!Objects.isNull(afterFunction)) {
|
|
|
- afterFunction.accept(activityPlan.getId());
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
- }, plan.getId(), 10l);
|
|
|
- }
|
|
|
+
|
|
|
+ // 方法调整为异常执行,预防HTTP接口调用返回超时响应
|
|
|
+ ThreadPool.getExecutor().submit(() -> {
|
|
|
+
|
|
|
+ RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_EVALUATION_CRON.getCode());
|
|
|
+ try {
|
|
|
+ if (lock.isLocked()) {
|
|
|
+ log.warn("activityState {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 增加达标活动计算同步标识,前一个请求未执行完时忽略后续执行请求
|
|
|
+ lock.lock();
|
|
|
+
|
|
|
+ List<ActivityPlan> list = baseMapper.activityState();
|
|
|
+ for (ActivityPlan plan : list) {
|
|
|
+ DistributedLock.of(redissonClient)
|
|
|
+ .runIfLockToFunction(CacheNameEnum.LOCK_ACTIVITY_STOCK.getRedisKey(plan.getId())
|
|
|
+ , (id) -> {
|
|
|
+ ActivityPlan activityPlan = getById(id);
|
|
|
+ if (activityPlan.getActivityState() == 0) {
|
|
|
+ activityPlan.setActivityState(1);
|
|
|
+ baseMapper.updateById(activityPlan);
|
|
|
+
|
|
|
+ //开始活动
|
|
|
+ Consumer<Long> afterFunction = startActivity.get(activityPlan.getActivityType());
|
|
|
+ if (!Objects.isNull(afterFunction)) {
|
|
|
+ afterFunction.accept(activityPlan.getId());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ activityPlan.setActivityState(0);
|
|
|
+ activityPlan.setRewardFlag(1);
|
|
|
+ baseMapper.updateById(activityPlan);
|
|
|
+
|
|
|
+ //完成活动
|
|
|
+ Consumer<Long> afterFunction = successActivity.get(activityPlan.getActivityType());
|
|
|
+ if (!Objects.isNull(afterFunction)) {
|
|
|
+ afterFunction.accept(activityPlan.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }, plan.getId(), 10l);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("activityState time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
|
|
|
+ } finally {
|
|
|
+ // 释放锁
|
|
|
+ if (lock.isLocked() && lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock(); // 删除同步标识
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
+ @Override
|
|
|
public void activityIng() {
|
|
|
- for (ActivityTypeEnum activityTypeEnum : activityIng.keySet()) {
|
|
|
- activityIng.get(activityTypeEnum).accept(null);
|
|
|
- }
|
|
|
+
|
|
|
+ // 当前处理任务调整为异步执行
|
|
|
+ ThreadPool.getExecutor().submit(() -> {
|
|
|
+
|
|
|
+ RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_STANDARD_GIFT_CRON.getCode());
|
|
|
+ try {
|
|
|
+ if (lock.isLocked()) {
|
|
|
+ log.warn("activityIng {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 增加达标活动计算同步标识,前一个请求未执行完时忽略后续执行请求
|
|
|
+ lock.lock();
|
|
|
+
|
|
|
+ for (ActivityTypeEnum activityTypeEnum : activityIng.keySet()) {
|
|
|
+ activityIng.get(activityTypeEnum).accept(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("activityIng time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
|
|
|
+ } finally {
|
|
|
+ // 释放锁
|
|
|
+ if (lock.isLocked() && lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock(); // 删除同步标识
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -635,10 +858,10 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
|
|
|
List<Long> collect = saveOrUpdateRewardDto.getUpdateRewardDtoList().stream()
|
|
|
.map(ActivityPlanReward::getRewardId).distinct().collect(Collectors.toList());
|
|
|
|
|
|
- long validRewardNums = activityRewardService.listByIds(collect).stream()
|
|
|
- .filter(x -> x.getRewardClient().equals(activityPlan.getActivityClient().getCode()))
|
|
|
- .count();
|
|
|
- if (saveOrUpdateRewardDto.getUpdateRewardDtoList().size() != validRewardNums) {
|
|
|
+ String clientType = activityPlan.getActivityClient().getCode();
|
|
|
+ boolean invalidRewardNums = activityRewardService.listByIds(collect).stream()
|
|
|
+ .anyMatch(x -> !Lists.newArrayList(x.getRewardClient().split(",")).contains(clientType));
|
|
|
+ if (invalidRewardNums) {
|
|
|
throw new BizException("添加奖品与活动客户端不匹配");
|
|
|
}
|
|
|
|