新增情人节活动

This commit is contained in:
liaozetao
2024-02-05 20:42:16 +08:00
parent 80fe39de53
commit 1e701b777d
83 changed files with 4125 additions and 23 deletions

View File

@@ -2286,6 +2286,14 @@ public enum RedisKey {
//特殊礼物
special_gift_rank,
act_user_task_lock,
act_user_complete_task_lock,
mq_status,
act_user_task_score,
;
public String getKey() {

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.accompany</groupId>
<artifactId>accompany-business-festival-activity</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>fastival-activity-mq</artifactId>
<dependencies>
<dependency>
<groupId>com.accompany</groupId>
<artifactId>accompany-core-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.accompany</groupId>
<artifactId>accompany-mq-service</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.accompany</groupId>
<artifactId>festival-activity-service</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,90 @@
package com.accompany.mq.consumer;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.constant.RewardFlagConstant;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.enums.ActTaskStatusEnum;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.business.activity.service.ActTaskRewardService;
import com.accompany.business.activity.service.ActUserTaskService;
import com.accompany.business.activity.strategy.ActRewardFactory;
import com.accompany.common.redis.RedisKey;
import com.accompany.mq.constant.MqConstant;
import com.accompany.mq.listener.AbstractMessageListener;
import com.accompany.mq.model.ActTaskRewardMqMessage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/31 11:19
* @description:
*/
@Slf4j
@Component
@ConditionalOnProperty(name = "spring.application.name", havingValue = "web")
@RocketMQMessageListener(topic = MqConstant.ACT_TASK_REWARD_TOPIC, consumerGroup = MqConstant.ACT_TASK_REWARD_CONSUME_GROUP)
public class ActTaskRewardConsumer extends AbstractMessageListener<ActTaskRewardMqMessage> {
@Autowired
private ActUserTaskService actUserTaskService;
@Autowired
private ActTaskRewardService actTaskRewardService;
@Resource(name = "bizExecutor")
private TaskExecutor bizExecutor;
@Override
protected void onMessage(ActTaskRewardMqMessage object) throws Exception {
Long userTaskId = object.getUserTaskId();
if (!jedisService.setnx(RedisKey.act_user_complete_task_lock.getKey(String.valueOf(userTaskId)), String.valueOf(userTaskId), 10 * 60)) {
log.info("userTaskId : {},重复执行", userTaskId);
return;
}
ActUserTask actUserTask = actUserTaskService.getById(userTaskId);
Integer taskStatus = actUserTask.getTaskStatus();
if (taskStatus != ActTaskStatusEnum.COMPLETE.ordinal()) {
log.info("userTaskId : {} is not complete.", userTaskId);
return;
}
String activityCode = actUserTask.getActivityCode();
String taskCode = actUserTask.getTaskCode();
Long uid = actUserTask.getUid();
List<ActTaskReward> actTaskRewards = actTaskRewardService.list(Wrappers.<ActTaskReward>lambdaQuery()
.eq(ActTaskReward::getActivityCode, activityCode)
.eq(ActTaskReward::getTaskCode, taskCode));
if (CollectionUtil.isEmpty(actTaskRewards)) {
return;
}
for (ActTaskReward actTaskReward : actTaskRewards) {
String rewardType = actTaskReward.getRewardType();
Integer rewardFlag = actTaskReward.getRewardFlag();
if ((rewardFlag & RewardFlagConstant.REWARD_FLAG_FOR_AUTO) == 0) {
continue;
}
//自动发放
ActRewardContext context = new ActRewardContext();
context.setUid(uid);
context.setReward(actTaskReward);
context.setTask(actUserTask);
bizExecutor.execute(() -> ActRewardFactory.getReward(rewardType).grant(context));
}
actUserTask.setTaskStatus(ActTaskStatusEnum.GRANT.ordinal());
actUserTaskService.updateById(actUserTask);
}
@Override
protected RedisKey mqLock() {
return RedisKey.mq_status;
}
}

View File

@@ -0,0 +1,163 @@
package com.accompany.mq.consumer;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.dto.ActTaskContext;
import com.accompany.business.activity.enums.ActTaskStatusEnum;
import com.accompany.business.activity.handle.IActTaskHandler;
import com.accompany.business.activity.model.ActActivity;
import com.accompany.business.activity.model.ActTask;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.business.activity.service.ActActivityService;
import com.accompany.business.activity.service.ActTaskRewardService;
import com.accompany.business.activity.service.ActTaskService;
import com.accompany.business.activity.service.ActUserTaskService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.core.base.SpringContextHolder;
import com.accompany.mq.constant.MqConstant;
import com.accompany.mq.listener.AbstractMessageListener;
import com.accompany.mq.model.ActTaskRewardMqMessage;
import com.accompany.mq.model.ActUserTaskMqMessage;
import com.accompany.mq.producer.MQMessageProducer;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author: liaozetao
* @date: 2024/2/4 19:10
* @description:
*/
@Slf4j
@Component
@ConditionalOnProperty(name = "spring.application.name", havingValue = "web")
@RocketMQMessageListener(topic = MqConstant.ACT_USER_TASK_TOPIC, consumerGroup = MqConstant.ACT_USER_TASK_CONSUME_GROUP)
public class ActUserTaskConsumer extends AbstractMessageListener<ActUserTaskMqMessage> {
@Autowired
private ActActivityService actActivityService;
@Autowired
private ActUserTaskService actUserTaskService;
@Autowired
private ActTaskService actTaskService;
@Autowired
private ActTaskRewardService actTaskRewardService;
@Autowired
private MQMessageProducer mqMessageProducer;
@Override
protected void onMessage(ActUserTaskMqMessage object) throws Exception {
Long uid = object.getSendUid();
Date messTime = new Date(object.getMessTime());
List<ActActivity> actActivities = actActivityService.list(Wrappers.<ActActivity>lambdaQuery()
.eq(ActActivity::getActivityStatus, Constant.Yes1No0.YES)
.le(ActActivity::getStartTime, messTime)
.ge(ActActivity::getEndTime, messTime));
if (CollectionUtil.isEmpty(actActivities)) {
return;
}
ActActivity actActivity = actActivities.get(0);
String activityCode = actActivity.getActivityCode();
List<ActTask> actTasks = actTaskService.list(Wrappers.<ActTask>lambdaQuery()
.eq(ActTask::getActivityCode, activityCode));
if (CollectionUtil.isEmpty(actTasks)) {
return;
}
List<ActTask> parentTasks = actTasks.stream().filter(v -> StrUtil.isEmpty(v.getParentCode())).collect(Collectors.toList());
if (CollectionUtil.isEmpty(parentTasks)) {
return;
}
String redisKey = RedisKey.act_user_task_lock.getKey(activityCode, uid.toString());
//若锁超时,直接执行
String lockVal = jedisLockService.lock(redisKey, 10 * 1000);
try {
for (ActTask parentTask : parentTasks) {
iterate(actActivity, object, parentTask, actTasks);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
jedisLockService.unlock(redisKey, lockVal);
}
//奖品处理
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, actActivity.getActivityCode())
.eq(ActUserTask::getUid, uid)
.eq(ActUserTask::getTaskStatus, ActTaskStatusEnum.COMPLETE.ordinal())
.between(ActUserTask::getCreateTime, actActivity.getStartTime(), actActivity.getEndTime()));
if (CollectionUtil.isNotEmpty(actUserTasks)) {
for (ActUserTask actUserTask : actUserTasks) {
String taskCode = actUserTask.getTaskCode();
int count = actTaskRewardService.count(Wrappers.<ActTaskReward>lambdaQuery()
.eq(ActTaskReward::getActivityCode, activityCode)
.eq(ActTaskReward::getTaskCode, taskCode));
if (count > 0) {
Long userTaskId = actUserTask.getId();
log.info("userTaskId : {}", userTaskId);
ActTaskRewardMqMessage message = new ActTaskRewardMqMessage();
message.setUserTaskId(userTaskId);
mqMessageProducer.send(MqConstant.ACT_USER_TASK_TOPIC, message);
}
}
}
}
public void iterate(ActActivity actActivity, ActUserTaskMqMessage object, ActTask parent, List<ActTask> actTasks) {
String taskCode = parent.getTaskCode();
//子任务
List<ActTask> children = actTasks.stream().filter(v -> StrUtil.isNotEmpty(v.getParentCode()) && v.getParentCode().equals(taskCode)).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(children)) {
for (ActTask child : children) {
iterate(actActivity, object, child, actTasks);
}
}
String executor = parent.getExecutor();
if (StrUtil.isEmpty(executor)) {
return;
}
try {
log.info("taskCode : {}, executor : {}", taskCode, executor);
Object bean = SpringContextHolder.getBean(executor);
if (bean instanceof IActTaskHandler) {
ActTaskContext context = getActTaskContext(actActivity, object, parent);
((IActTaskHandler) bean).handle(context);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
@NotNull
private static ActTaskContext getActTaskContext(ActActivity actActivity, ActUserTaskMqMessage object, ActTask parent) {
Date startTime = actActivity.getStartTime();
Date endTime = actActivity.getEndTime();
ActTaskContext context = new ActTaskContext();
context.setRoomUid(object.getRoomUid());
context.setSendUid(object.getSendUid());
context.setReceiveUid(object.getReceiveUid());
context.setGiftId(object.getGiftId());
context.setGiftValue(object.getGiftValue());
context.setTaskTime(object.getMessTime());
context.setActivityStartTime(startTime);
context.setActivityEndTime(endTime);
context.setTaskStartTime(startTime);
context.setTaskEndTime(endTime);
context.setActTask(parent);
return context;
}
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActActivity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/1/26 17:13
* @description:
*/
public interface ActActivityDao extends BaseMapper<ActActivity> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActComponent;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/1/26 17:13
* @description:
*/
public interface ActComponentDao extends BaseMapper<ActComponent> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActTaskCondition;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/1/26 17:15
* @description:
*/
public interface ActTaskConditionDao extends BaseMapper<ActTaskCondition> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActTask;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/1/26 17:14
* @description:
*/
public interface ActTaskDao extends BaseMapper<ActTask> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActTaskReward;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/1/26 17:15
* @description:
*/
public interface ActTaskRewardDao extends BaseMapper<ActTaskReward> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActUserRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author: liaozetao
* @date: 2024/2/1 11:39
* @description:
*/
public interface ActUserRecordDao extends BaseMapper<ActUserRecord> {
}

View File

@@ -0,0 +1,22 @@
package com.accompany.business.mapper;
import com.accompany.business.activity.model.ActUserTask;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* @author: liaozetao
* @date: 2024/1/26 17:17
* @description:
*/
public interface ActUserTaskDao extends BaseMapper<ActUserTask> {
/**
* 更新兑换数量
*
* @param activityCode
* @param taskCode
* @param exchangeValue
*/
void updateExchangeValue(@Param("activityCode") String activityCode, @Param("taskCode") String taskCode, @Param("exchangeValue") Integer exchangeValue);
}

View File

@@ -0,0 +1,215 @@
package com.accompany.business.valentine;
import com.accompany.business.common.dto.CpRankActConfigDto;
import com.accompany.business.common.dto.CpRankActCpProp;
import com.accompany.business.valentine.constant.ValentinesConstant;
import com.accompany.common.constant.AppEnum;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.base.SpringContextHolder;
import com.accompany.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@Slf4j
public class ValentinesCpDao implements InitializingBean {
private final String MODULE_NAME = "cp_rank";
@Autowired
private RedissonClient redissonClient;
private RMap<String, CpRankActCpProp> cpPropMap;
private RMap<Long, Map<String, CpRankActCpProp>> userCpPropMap;
@Override
public void afterPropertiesSet() throws Exception {
String cpPropKey = String.join("_", AppEnum.getCurApp().getValue(), ValentinesConstant.actName, MODULE_NAME, "cp_prop");
cpPropMap = redissonClient.getMap(cpPropKey);
String userCpProp = String.join("_", AppEnum.getCurApp().getValue(), ValentinesConstant.actName, MODULE_NAME, "user_cp_prop");
userCpPropMap = redissonClient.getMap(userCpProp);
}
public Long getTheMaxScoreByUid(Long uid) {
Map<String, CpRankActCpProp> propMap = userCpPropMap.get(uid);
if (CollectionUtils.isEmpty(propMap)){
return 0L;
}
return propMap.values().stream().max(Comparator.comparing(CpRankActCpProp::getScore)).map(CpRankActCpProp::getScore).orElse(0L);
}
public List<CpRankActCpProp> listCpByUid(Long uid, Long size) {
Map<String, CpRankActCpProp> propMap = userCpPropMap.get(uid);
if (CollectionUtils.isEmpty(propMap)){
return null;
}
if (null == size){
size = Long.MAX_VALUE;
}
return propMap.values().stream()
.sorted(Comparator.comparing(CpRankActCpProp::getScore).reversed()).limit(size).collect(Collectors.toList());
}
public String buildCpUid(Long fromUid, Long toUid){
List<Long> uidList = new ArrayList<>(2);
uidList.add(fromUid);
uidList.add(toUid);
return uidList.stream().sorted()
.map(Object::toString)
.collect(Collectors.joining("_"));
}
public List<Long> takeApartCpUid(String cpUid) {
return Arrays.stream(cpUid.split("_")).map(Long::parseLong).collect(Collectors.toList());
}
public CpRankActCpProp getCpPropByCpUid(String cpUid) {
return cpPropMap.get(cpUid);
}
public Map<String, CpRankActCpProp> mapCpPropByCpUidSet(Set<String> cpUidSet) {
Map<String, CpRankActCpProp> map = cpPropMap.getAll(cpUidSet);
if (CollectionUtils.isEmpty(map)){
return Collections.emptyMap();
}
return map;
}
private <R> R withLock(Long uid, String redisKey, Function<Map<String, CpRankActCpProp>, R> function){
String lockKey = String.join("_", AppEnum.getCurApp().getValue(), ValentinesConstant.actName, MODULE_NAME, redisKey, uid.toString());
RLock lock = redissonClient.getLock(lockKey);
boolean isLocked = false;
try {
isLocked = lock.tryLock(3, TimeUnit.SECONDS);
if (!isLocked){
log.error("[2024情人节活动] {} 获取 {} 锁超时", uid, lockKey);
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
Map<String, CpRankActCpProp> propMap = userCpPropMap.getOrDefault(uid, new HashMap<>());
return function.apply(propMap);
} catch (InterruptedException e) {
log.error("[2024情人节活动] {} 获取 {} 锁异常", uid, lockKey, e);
throw new ServiceException(BusiStatus.SERVER_BUSY);
} finally {
if (isLocked){
lock.unlock();
}
}
}
public void saveCpProp(CpRankActCpProp cpProp, CpRankActConfigDto configDto) {
if (!cpPropMap.fastPutIfAbsent(cpProp.getCpUid(), cpProp)){
return;
}
saveUserCpProp(cpProp.getFromUid(), cpProp.getToUid(), cpProp, configDto);
saveUserCpProp(cpProp.getToUid(), cpProp.getFromUid(), cpProp, configDto);
}
public List<Integer> saveUserCpProp(Long fromUid, Long toUid, CpRankActCpProp userProp, CpRankActConfigDto config){
return withLock(fromUid, "user_cp_prop_lock", propMap->{
if (CollectionUtils.isEmpty(propMap)){
propMap.put(toUid.toString(), userProp);
userCpPropMap.fastPut(fromUid, propMap);
return null;
}
CpRankActCpProp cpUserProp = propMap.get(toUid.toString());
if (null == cpUserProp){
propMap.put(toUid.toString(), userProp);
userCpPropMap.fastPut(fromUid, propMap);
return null;
}
if (cpUserProp.getScore() >= userProp.getScore()){
return null;
}
Long maxScore = getTheMaxScoreByUid(fromUid);
//更新分数
cpUserProp.setScore(userProp.getScore());
userCpPropMap.fastPut(fromUid, propMap);
if (cpUserProp.getScore().compareTo(maxScore) > 0){
List<Integer> taskIds = config.getCpScoreTasks().stream()
.filter(task->maxScore.compareTo(task.getScore()) < 0
&& cpUserProp.getScore().compareTo(task.getScore()) >= 0)
.map(CpRankActConfigDto.CpScoreTask::getId).collect(Collectors.toList());
return taskIds;
}
return null;
});
}
public Map<Long, List<Integer>> updateCpScore(String cpUid, Double totalScore, CpRankActConfigDto config) {
CpRankActCpProp cpProp = getCpPropByCpUid(cpUid);
if (null == cpProp){
return null;
}
long score = BigDecimal.valueOf(totalScore).setScale(0, RoundingMode.DOWN).longValue();
if (cpProp.getScore() >= score){
return null;
}
boolean needUpdate = false;
boolean locked = false;
String lockKey = String.join("_", AppEnum.getCurApp().getValue(), ValentinesConstant.actName, MODULE_NAME, "cp_prop_lock", cpUid);
RLock lock = redissonClient.getLock(lockKey);
try {
locked = lock.tryLock(3, TimeUnit.SECONDS);
if (!locked){
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
cpProp = getCpPropByCpUid(cpUid);
if (cpProp.getScore() < score){
cpProp.setScore(score);
cpPropMap.fastPut(cpUid, cpProp);
needUpdate = true;
}
} catch (InterruptedException e) {
//todo log
throw new RuntimeException(e);
} finally {
if (locked){
lock.unlock();
}
}
if (!needUpdate){
return null;
}
Map<Long, List<Integer>> taskMap = new HashMap<>();
List<Integer> taskIds = SpringContextHolder.getBean(ValentinesCpDao.class).saveUserCpProp(cpProp.getFromUid(), cpProp.getToUid(), cpProp, config);
if (!CollectionUtils.isEmpty(taskIds)){
taskMap.put(cpProp.getFromUid(), taskIds);
}
List<Integer> taskIdsList = SpringContextHolder.getBean(ValentinesCpDao.class).saveUserCpProp(cpProp.getToUid(), cpProp.getFromUid(), cpProp, config);
if (!CollectionUtils.isEmpty(taskIdsList)){
taskMap.put(cpProp.getToUid(), taskIdsList);
}
return taskMap;
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActActivityDao">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActComponentDao">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActTaskConditionDao">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActTaskDao">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActTaskRewardDao">
</mapper>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActUserRecordDao">
</mapper>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mapper.ActUserTaskDao">
<update id="updateExchangeValue">
update act_user_task set exchange_value = exchange_value + #{exchangeValue} where activity_code =
#{activityCode} and task_code = #{taskCode}
</update>
</mapper>

View File

@@ -0,0 +1,24 @@
package com.accompany.scheduler.valentines;
import com.accompany.business.valentine.service.ValentinesCpRankService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@Slf4j
public class ValentinesCpRankTask {
@Autowired
private ValentinesCpRankService service;
@Scheduled(cron = "1 0 0 * * ?")
public void settlement(){
LocalDateTime now = LocalDateTime.now();
service.settlement(now);
}
}

View File

@@ -0,0 +1,14 @@
package com.accompany.business.activity.constant;
/**
* @author: liaozetao
* @date: 2024/1/31 11:38
* @description:
*/
public interface RewardFlagConstant {
//是否自动
int REWARD_FLAG_FOR_AUTO = 0b1;
//是否定时失效
int REWARD_FLAG_FOR_FIX_TIME = 0b10;
}

View File

@@ -0,0 +1,11 @@
package com.accompany.business.activity.constant;
/**
* @author: liaozetao
* @date: 2024/1/31 17:17
* @description:
*/
public interface ValentinesDayConstant {
String actName = "valentines_day_2024";
}

View File

@@ -0,0 +1,14 @@
package com.accompany.business.activity.constants;
/**
* @author: liaozetao
* @date: 2024/1/31 11:38
* @description:
*/
public interface ActRewardFlagConstant {
//是否自动
int REWARD_FLAG_FOR_AUTO = 0b1;
//是否定时失效
int REWARD_FLAG_FOR_FIX_TIME = 0b10;
}

View File

@@ -0,0 +1,49 @@
package com.accompany.business.activity.dto;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.model.ActUserTask;
import lombok.Data;
/**
* @author: liaozetao
* @date: 2024/1/31 14:42
* @description:
*/
@Data
public class ActRewardContext {
/**
* 用户UID
*/
private Long uid;
/**
* 任务
*/
private ActUserTask task;
/**
* 奖品
*/
private ActTaskReward reward;
/**
* 活动名字
*/
private String activityName;
/**
* 名称
*/
private String rewardName;
/**
* 图片
*/
private String rewardIcon;
/**
* 有效时间
*/
private String effectTime;
}

View File

@@ -0,0 +1,71 @@
package com.accompany.business.activity.dto;
import com.accompany.business.activity.model.ActTask;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/2/5 10:39
* @description:
*/
@Data
public class ActTaskContext {
/**
* 房间UID
*/
private Long roomUid;
/**
* 送礼用户UID
*/
private Long sendUid;
/**
* 收礼用户UID
*/
private Long receiveUid;
/**
* 礼物ID
*/
private Integer giftId;
/**
* 礼物值
*/
private Long giftValue;
/**
* 任务时间
*/
private Long taskTime;
/**
* 活动开始时间
*/
private Date activityStartTime;
/**
* 活动结束时间
*/
private Date activityEndTime;
/**
* 任务开始时间
*/
private Date taskStartTime;
/**
* 任务结束时间
*/
private Date taskEndTime;
/**
* 任务
*/
private ActTask actTask;
}

View File

@@ -0,0 +1,15 @@
package com.accompany.business.activity.enums;
/**
* @author: liaozetao
* @date: 2024/1/26 16:53
* @description:
*/
public enum ActConditionKindEnum {
//等于
EQ,
//大于等于
GE;
}

View File

@@ -0,0 +1,14 @@
package com.accompany.business.activity.enums;
/**
* @author: liaozetao
* @date: 2024/1/29 12:05
* @description:
*/
public enum ActConditionTypeEnum {
SCORE,
GIFT,
;
}

View File

@@ -0,0 +1,21 @@
package com.accompany.business.activity.enums;
/**
* @author: liaozetao
* @date: 2024/1/29 14:25
* @description:
*/
public enum ActTaskStatusEnum {
//进行中
PROCESS,
//完成
COMPLETE,
//失败
FAILURE,
//发放
GRANT;
}

View File

@@ -0,0 +1,15 @@
package com.accompany.business.activity.enums;
/**
* @author: liaozetao
* @date: 2024/1/29 14:20
* @description:
*/
public enum ActTimeTypeEnum {
//单次
ONCE,
//循环
LOOP,
}

View File

@@ -0,0 +1,73 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 16:34
* @description:
*/
@Data
@ApiModel
@TableName("act_activity")
public class ActActivity {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 活动名称
*/
@ApiModelProperty("活动名称")
private String activityName;
/**
* 开始时间
*/
@ApiModelProperty("开始时间")
private Date startTime;
/**
* 结束时间
*/
@ApiModelProperty("结束时间")
private Date endTime;
/**
* 活动状态
*/
@ApiModelProperty("活动状态")
private Integer activityStatus;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,61 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 16:38
* @description:
*/
@Data
@ApiModel
@TableName("act_component")
public class ActComponent {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 组件名称
*/
@ApiModelProperty("组件名称")
private String componentName;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,121 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 16:45
* @description:
*/
@Data
@ApiModel
@TableName("act_task")
public class ActTask {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 父级编码
*/
@ApiModelProperty("父级编码")
private String parentCode;
/**
* 任务图片
*/
@ApiModelProperty("任务图片")
private String taskIcon;
/**
* 任务名称
*/
@ApiModelProperty("任务名称")
private String taskName;
/**
* 任务类型
*/
@ApiModelProperty("任务类型 0 获得 1 达到")
private Integer taskType;
/**
* 时间类型 0 单次 1 循环
*/
@ApiModelProperty("时间类型 0 单次 1 循环")
private Integer timeType;
/**
* 开始时间格式
*/
@ApiModelProperty("开始时间格式")
private String startTimeFormat;
/**
* 任务时长
*/
@ApiModelProperty("任务时长")
private Integer timeDuration;
/**
* 任务值
*/
@ApiModelProperty("任务值")
private Integer taskValue;
/**
* 排序
*/
@ApiModelProperty("排序")
private Integer seqNo;
/**
* 执行者
*/
@ApiModelProperty("执行者")
private String executor;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,79 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 16:50
* @description:
*/
@Data
@ApiModel
@TableName("act_task_condition")
public class ActTaskCondition {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 条件编码
*/
@ApiModelProperty("条件编码")
private String conditionCode;
/**
* 条件种类 EQ 等于 LT 小于 LE 小于等于 GT 大于 GE 大于等于 IN 包含
*/
@ApiModelProperty("条件种类 EQ 等于 LT 小于 LE 小于等于 GT 大于 GE 大于等于 IN 包含")
private String conditionKind;
/**
* 达成值
*/
@ApiModelProperty("达成值")
private Long conditionValue;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,103 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 17:00
* @description:
*/
@Data
@ApiModel
@TableName("act_task_reward")
public class ActTaskReward {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 奖品类型
*/
@ApiModelProperty("奖品类型")
private String rewardType;
/**
* 奖品ID
*/
@ApiModelProperty("奖品ID")
private Long rewardId;
/**
* 奖品数量
*/
@ApiModelProperty("奖品数量")
private Integer rewardNum;
/**
* 奖品标识
*/
@ApiModelProperty("奖品标识")
private Integer rewardFlag;
/**
* 通知
*/
@ApiModelProperty("通知")
private String noticeMessage;
/**
* 时间单位
*/
@ApiModelProperty("时间单位")
private Integer timeUnit;
/**
* 失效时间格式
*/
@ApiModelProperty("失效时间格式")
private String expireTimeFormat;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,99 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/2/1 11:34
* @description:
*/
@Data
@TableName("act_user_record")
public class ActUserRecord {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户UID
*/
@ApiModelProperty("用户UID")
private Long uid;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 活跃值
*/
@ApiModelProperty("活跃值")
private Long activityValue;
/**
* 奖品ID
*/
@ApiModelProperty("奖品ID")
private Long rewardId;
/**
* 奖品类型
*/
@ApiModelProperty("奖品类型")
private String rewardType;
/**
* 奖品名称
*/
@ApiModelProperty("奖品名称")
private String rewardName;
/**
* 奖品icon
*/
@ApiModelProperty("奖品icon")
private String rewardIcon;
/**
* 奖品数量
*/
@ApiModelProperty("奖品数量")
private Integer rewardNum;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
private Date updateTime;
}

View File

@@ -0,0 +1,109 @@
package com.accompany.business.activity.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/26 16:56
* @description:
*/
@Data
@ApiModel
@TableName("act_user_task")
public class ActUserTask {
/**
* 主键
*/
@ApiModelProperty("主键")
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户UID
*/
@ApiModelProperty("用户UID")
private Long uid;
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 组件编码
*/
@ApiModelProperty("组件编码")
private String componentCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 条件编码
*/
@ApiModelProperty("条件编码")
private String conditionCode;
/**
* 任务状态
*/
@ApiModelProperty("任务状态")
private Integer taskStatus;
/**
* 活跃值
*/
@ApiModelProperty("活跃值")
private Long activityValue;
/**
* 完成数量
*/
@ApiModelProperty("完成数量")
private Long completeValue;
/**
* 兑换数量
*/
@ApiModelProperty("兑换数量")
private Long exchangeValue;
/**
* 开始时间
*/
@ApiModelProperty("开始时间")
private Date startTime;
/**
* 结束时间
*/
@ApiModelProperty("结束时间")
private Date endTime;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,69 @@
package com.accompany.business.activity.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author: liaozetao
* @date: 2024/1/26 18:09
* @description:
*/
@Data
public class ActivityReward {
/**
* 奖品ID
*/
@ApiModelProperty("奖品ID")
private Long rewardId;
/**
* 奖品名称
*/
@ApiModelProperty("奖品名称")
private String rewardName;
/**
* 奖品图标
*/
@ApiModelProperty("奖品图标")
private String rewardIcon;
/**
* 奖品类型
*/
@ApiModelProperty("奖品类型")
private String rewardType;
/**
* 展示值
*/
@ApiModelProperty("展示值")
private String showValue;
/**
* 过期天数
*/
@ApiModelProperty("过期天数")
private Integer expireDay;
/**
* 过期小时数
*/
@ApiModelProperty("过期小时数")
private Integer expireHour;
/**
* 过期分钟数
*/
@ApiModelProperty("过期分钟数")
private Integer expireMinute;
/**
* 是否已发放
*/
@ApiModelProperty("是否已发放")
private Boolean granted = false;
}

View File

@@ -0,0 +1,87 @@
package com.accompany.business.activity.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/26 18:08
* @description:
*/
@Data
public class ActivityTask {
/**
* 活动编码
*/
@ApiModelProperty("活动编码")
private String activityCode;
/**
* 任务编码
*/
@ApiModelProperty("任务编码")
private String taskCode;
/**
* 任务名称
*/
@ApiModelProperty("任务名称")
private String taskName;
/**
* 展示图片
*/
@ApiModelProperty("展示图片")
private String taskIcon;
/**
* 展示价值
*/
@ApiModelProperty("展示价值")
private String showValue;
/**
* 关联值
*/
@ApiModelProperty("关联值")
private String referenceValue;
/**
* 完成值
*/
@ApiModelProperty("完成值")
private Long completeValue;
/**
* 活动值
*/
@ApiModelProperty("活动值")
private Long activityValue;
/**
* 任务值
*/
@ApiModelProperty("任务值")
private String taskValue;
/**
* 是否完成
*/
@ApiModelProperty("是否完成")
private Boolean completed = false;
/**
* 活动奖品
*/
@ApiModelProperty("活动奖品")
private ActivityReward reward;
/**
* 子项
*/
@ApiModelProperty("子项")
private List<ActivityTask> children;
}

View File

@@ -0,0 +1,19 @@
package com.accompany.business.valentine.constant;
public class ValentinesConstant {
public static String actName = "act_valentine_2024";
public static class SysConfId {
public static final String ACT_RANK_CONFIG = actName + "_cp_rank_config";
}
public static class BtnStatus {
public static final Integer NONE = 0;
public static final Integer CAN = 1;
public static final Integer HAD = 2;
}
public static String cp_tip = "恭喜~你在「热恋情人节」活动中的热恋值突破了 %d获得 %s 奖励有效期24h快去查看吧";
}

View File

@@ -0,0 +1,13 @@
package com.accompany.business.valentine.dto;
import com.accompany.business.common.dto.CpRankActCpProp;
import lombok.Data;
import java.util.Map;
@Data
public class ValentinesCpUserProp extends CpRankActCpProp {
private Map<Integer, Integer> cpTaskStatus;
}

View File

@@ -0,0 +1,20 @@
package com.accompany.business.valentine.vo;
import com.accompany.business.common.vo.ActivityCpRankVo;
import com.accompany.business.common.vo.ActivityStageTaskItemVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@ApiModel
@Data
public class ValentinesCpRankVo extends ActivityCpRankVo {
private Long uid;
@ApiModelProperty("当前最高分")
private Long score;
@ApiModelProperty("cp任务列表")
private List<ActivityStageTaskItemVo> cpTaskList;
}

View File

@@ -0,0 +1,30 @@
package com.accompany.business.activity.decorate;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.vo.ActivityTask;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/29 14:15
* @description:
*/
public class ActivityTaskDecorateChain {
private final ActivityTaskDecorator decorator;
public ActivityTaskDecorateChain(ActivityTaskDecorator decorator) {
this.decorator = decorator;
}
public void decorate(List<ActivityTask> activityTasks) {
if (CollectionUtil.isEmpty(activityTasks)) {
return;
}
//循环处理
for (ActivityTask activityTask : activityTasks) {
decorator.decorate(activityTask);
}
}
}

View File

@@ -0,0 +1,32 @@
package com.accompany.business.activity.decorate;
import com.accompany.business.activity.service.ActTaskConditionService;
import com.accompany.business.activity.service.impl.ActTaskConditionServiceImpl;
import com.accompany.business.activity.vo.ActivityTask;
import com.accompany.core.base.SpringContextHolder;
/**
* @author: liaozetao
* @date: 2024/1/29 11:53
* @description:
*/
public abstract class ActivityTaskDecorator {
private final ActivityTaskDecorator prevDecorator;
protected final ActTaskConditionService actTaskConditionService;
public ActivityTaskDecorator(ActivityTaskDecorator prevDecorator) {
this.prevDecorator = prevDecorator;
this.actTaskConditionService = SpringContextHolder.getBeanOfClass(ActTaskConditionServiceImpl.class);
}
public void decorate(ActivityTask activityTask) {
if (prevDecorator != null) {
prevDecorator.decorate(activityTask);
}
decorateTask(activityTask);
}
public abstract void decorateTask(ActivityTask activityTask);
}

View File

@@ -0,0 +1,59 @@
package com.accompany.business.activity.decorate;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.enums.ActConditionKindEnum;
import com.accompany.business.activity.model.ActTaskCondition;
import com.accompany.business.activity.vo.ActivityTask;
import com.accompany.business.model.Gift;
import com.accompany.business.model.GiftExample;
import com.accompany.business.mybatismapper.GiftMapper;
import com.accompany.core.base.SpringContextHolder;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/29 12:02
* @description:
*/
public class ActivityTaskForGiftDecorator extends ActivityTaskDecorator {
private final GiftMapper giftMapper;
public ActivityTaskForGiftDecorator() {
this(null);
}
public ActivityTaskForGiftDecorator(ActivityTaskDecorator prevDecorator) {
super(prevDecorator);
giftMapper = SpringContextHolder.getBeanOfClass(GiftMapper.class);
}
@Override
public void decorateTask(ActivityTask activityTask) {
String activityCode = activityTask.getActivityCode();
String taskCode = activityTask.getTaskCode();
List<ActTaskCondition> actTaskConditions = actTaskConditionService.list(Wrappers.<ActTaskCondition>lambdaQuery()
.eq(ActTaskCondition::getActivityCode, activityCode)
.eq(ActTaskCondition::getTaskCode, taskCode));
if (CollectionUtil.isEmpty(actTaskConditions)) {
return;
}
ActTaskCondition actTaskCondition = actTaskConditions.get(0);
Long conditionValue = actTaskCondition.getConditionValue();
String conditionKind = actTaskCondition.getConditionKind();
if (!ActConditionKindEnum.EQ.name().equals(conditionKind)) {
return;
}
GiftExample example = new GiftExample();
example.createCriteria().andGiftIdEqualTo(conditionValue.intValue());
List<Gift> gifts = giftMapper.selectByExample(example);
if (CollectionUtil.isEmpty(gifts)) {
return;
}
Gift gift = gifts.get(0);
activityTask.setTaskIcon(gift.getPicUrl());
activityTask.setShowValue(String.valueOf(gift.getGoldPrice()));
}
}

View File

@@ -0,0 +1,91 @@
package com.accompany.business.activity.handle;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.dto.ActTaskContext;
import com.accompany.business.activity.enums.ActConditionKindEnum;
import com.accompany.business.activity.enums.ActTimeTypeEnum;
import com.accompany.business.activity.model.ActTask;
import com.accompany.business.activity.model.ActTaskCondition;
import com.accompany.business.activity.service.ActTaskConditionService;
import com.accompany.business.activity.service.ActUserTaskService;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.service.common.JedisService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/2/5 10:37
* @description:
*/
@Slf4j
public class IActTaskHandler {
@Autowired
protected ActTaskConditionService actTaskConditionService;
@Autowired
protected ActUserTaskService actUserTaskService;
@Autowired
protected JedisService jedisService;
public void handle(ActTaskContext context) {
ActTask actTask = context.getActTask();
if (actTask == null) {
return;
}
String activityCode = actTask.getActivityCode();
String componentCode = actTask.getComponentCode();
String taskCode = actTask.getTaskCode();
Long taskTime = context.getTaskTime();
Date startTime = context.getActivityStartTime();
Date endTime = context.getActivityEndTime();
log.info("taskCode : {}, taskTime : {}, startTime : {}, endTime : {}", taskCode, taskTime, startTime, endTime);
Date now = new Date(taskTime);
Integer timeType = actTask.getTimeType();
if (ActTimeTypeEnum.LOOP.ordinal() == timeType) {
String startTimeFormat = actTask.getStartTimeFormat();
Integer timeDuration = actTask.getTimeDuration();
startTime = DateTimeUtil.convertStrToDate(DateTimeUtil.convertDate(now, startTimeFormat));
if (startTime != null) {
endTime = new Date(startTime.getTime() + timeDuration * 1000);
}
}
context.setTaskStartTime(startTime);
context.setTaskEndTime(endTime);
List<ActTaskCondition> actTaskConditions = actTaskConditionService.list(Wrappers.<ActTaskCondition>lambdaQuery()
.eq(ActTaskCondition::getActivityCode, activityCode)
.eq(ActTaskCondition::getComponentCode, componentCode)
.eq(ActTaskCondition::getTaskCode, taskCode));
if (CollectionUtil.isEmpty(actTaskConditions)) {
return;
}
for (ActTaskCondition actTaskCondition : actTaskConditions) {
String conditionKind = actTaskCondition.getConditionKind();
if (ActConditionKindEnum.EQ.name().equals(conditionKind)) {
eq(actTaskCondition, context);
} else if (ActConditionKindEnum.GE.name().equals(conditionKind)) {
ge(actTaskCondition, context);
}
}
doHandle(context);
}
protected boolean eq(ActTaskCondition actTaskCondition, ActTaskContext context) {
return true;
}
protected boolean ge(ActTaskCondition actTaskCondition, ActTaskContext context) {
return true;
}
public void doHandle(ActTaskContext context) {
}
}

View File

@@ -0,0 +1,89 @@
package com.accompany.business.activity.listener;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.model.ActActivity;
import com.accompany.business.activity.service.ActActivityService;
import com.accompany.business.event.GiftMessageEvent;
import com.accompany.business.message.GiftMessage;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.service.common.JedisService;
import com.accompany.mq.constant.MqConstant;
import com.accompany.mq.model.ActUserTaskMqMessage;
import com.accompany.mq.producer.MQMessageProducer;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/29 18:59
* @description:
*/
@Slf4j
@Component
public class ActTaskListener implements ApplicationListener<GiftMessageEvent> {
@Autowired
private ActActivityService actActivityService;
@Autowired
private JedisService jedisService;
@Autowired
private MQMessageProducer mqMessageProducer;
@Async
@Override
public void onApplicationEvent(@NotNull GiftMessageEvent event) {
try {
log.info("ActTaskListener GiftMessageEvent : {}", event);
Object source = event.getSource();
if (source == null) {
return;
}
GiftMessage giftMessage = (GiftMessage) source;
Integer giftId = giftMessage.getGiftId();
Long goldNum = giftMessage.getGoldNum();
Long sendUid = giftMessage.getSendUid();
Date now = new Date();
Long messTime = giftMessage.getMessTime();
if (messTime != null) {
now = new Date(messTime);
}
log.info("messTime : {}", messTime);
List<ActActivity> actActivities = actActivityService.list(Wrappers.<ActActivity>lambdaQuery()
.eq(ActActivity::getActivityStatus, Constant.Yes1No0.YES)
.le(ActActivity::getStartTime, now)
.ge(ActActivity::getEndTime, now));
if (CollectionUtil.isEmpty(actActivities)) {
return;
}
for (ActActivity actActivity : actActivities) {
String activityCode = actActivity.getActivityCode();
log.info("activityCode : {}", activityCode);
Date startTime = actActivity.getStartTime();
Date endTime = actActivity.getEndTime();
jedisService.hincrBy(RedisKey.act_user_task_score.getKey(activityCode, DateTimeUtil.convertDate(startTime, DateTimeUtil.ACTIVITY_DATE_HOUR_PATTERN), DateTimeUtil.convertDate(endTime, DateTimeUtil.ACTIVITY_DATE_HOUR_PATTERN)), sendUid.toString(), goldNum);
ActUserTaskMqMessage message = new ActUserTaskMqMessage();
message.setRoomUid(giftMessage.getRoomUid());
message.setSendUid(giftMessage.getSendUid());
message.setReceiveUid(giftMessage.getRecvUid());
message.setGiftId(giftId);
message.setGiftValue(giftMessage.getGoldNum());
message.setMessTime(now.getTime());
mqMessageProducer.send(MqConstant.ACT_USER_TASK_TOPIC, message);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActActivity;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/1/26 17:22
* @description:
*/
public interface ActActivityService extends IService<ActActivity> {
}

View File

@@ -0,0 +1,13 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActComponent;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/1/26 17:23
* @description:
*/
public interface ActComponentService extends IService<ActComponent> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActTaskCondition;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/1/26 17:23
* @description:
*/
public interface ActTaskConditionService extends IService<ActTaskCondition> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActTaskReward;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/1/26 17:23
* @description:
*/
public interface ActTaskRewardService extends IService<ActTaskReward> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActTask;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/1/26 17:23
* @description:
*/
public interface ActTaskService extends IService<ActTask> {
}

View File

@@ -0,0 +1,12 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActUserRecord;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: liaozetao
* @date: 2024/2/1 11:40
* @description:
*/
public interface ActUserRecordService extends IService<ActUserRecord> {
}

View File

@@ -0,0 +1,32 @@
package com.accompany.business.activity.service;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.business.activity.vo.ActivityTask;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/26 17:23
* @description:
*/
public interface ActUserTaskService extends IService<ActUserTask> {
/**
* 获取活动任务
* @param componentCode
* @return
*/
List<ActivityTask> getActivityTasks(String componentCode);
/**
* 兑换
* @param activityCode
* @param diamondNum
* @param taskCode
* @param num
*/
void exchange(String activityCode, String taskCode, Integer diamondNum, Integer num);
}

View File

@@ -0,0 +1,18 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActActivity;
import com.accompany.business.activity.service.ActActivityService;
import com.accompany.business.mapper.ActActivityDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/1/26 17:26
* @description:
*/
@Slf4j
@Service
public class ActActivityServiceImpl extends ServiceImpl<ActActivityDao, ActActivity> implements ActActivityService {
}

View File

@@ -0,0 +1,19 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActComponent;
import com.accompany.business.activity.service.ActComponentService;
import com.accompany.business.mapper.ActComponentDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/1/26 17:27
* @description:
*/
@Slf4j
@Service
public class ActComponentServiceImpl extends ServiceImpl<ActComponentDao, ActComponent> implements ActComponentService {
}

View File

@@ -0,0 +1,18 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActTaskCondition;
import com.accompany.business.activity.service.ActTaskConditionService;
import com.accompany.business.mapper.ActTaskConditionDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/1/26 17:27
* @description:
*/
@Slf4j
@Service
public class ActTaskConditionServiceImpl extends ServiceImpl<ActTaskConditionDao, ActTaskCondition> implements ActTaskConditionService {
}

View File

@@ -0,0 +1,18 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.service.ActTaskRewardService;
import com.accompany.business.mapper.ActTaskRewardDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/1/26 17:27
* @description:
*/
@Slf4j
@Service
public class ActTaskRewardServiceImpl extends ServiceImpl<ActTaskRewardDao, ActTaskReward> implements ActTaskRewardService {
}

View File

@@ -0,0 +1,18 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActTask;
import com.accompany.business.activity.service.ActTaskService;
import com.accompany.business.mapper.ActTaskDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/1/26 17:27
* @description:
*/
@Slf4j
@Service
public class ActTaskServiceImpl extends ServiceImpl<ActTaskDao, ActTask> implements ActTaskService {
}

View File

@@ -0,0 +1,18 @@
package com.accompany.business.activity.service.impl;
import com.accompany.business.activity.model.ActUserRecord;
import com.accompany.business.activity.service.ActUserRecordService;
import com.accompany.business.mapper.ActUserRecordDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/2/1 11:40
* @description:
*/
@Slf4j
@Service
public class ActUserRecordServiceImpl extends ServiceImpl<ActUserRecordDao, ActUserRecord> implements ActUserRecordService {
}

View File

@@ -0,0 +1,307 @@
package com.accompany.business.activity.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.decorate.ActivityTaskDecorateChain;
import com.accompany.business.activity.decorate.ActivityTaskForGiftDecorator;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.enums.ActConditionKindEnum;
import com.accompany.business.activity.enums.ActTaskStatusEnum;
import com.accompany.business.activity.enums.ActTimeTypeEnum;
import com.accompany.business.activity.model.*;
import com.accompany.business.activity.service.*;
import com.accompany.business.activity.strategy.ActRewardFactory;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.activity.vo.ActivityTask;
import com.accompany.business.mapper.ActUserTaskDao;
import com.accompany.business.model.UserPurse;
import com.accompany.business.service.purse.UserPurseService;
import com.accompany.business.service.record.BillRecordService;
import com.accompany.common.constant.Constant;
import com.accompany.common.exception.ApiException;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.base.UidContextHolder;
import com.accompany.core.enumeration.BillObjTypeEnum;
import com.accompany.core.exception.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
* @author: liaozetao
* @date: 2024/1/26 17:27
* @description:
*/
@Slf4j
@Service
public class ActUserTaskServiceImpl extends ServiceImpl<ActUserTaskDao, ActUserTask> implements ActUserTaskService {
@Autowired
private ActActivityService actActivityService;
@Autowired
private ActTaskService actTaskService;
@Autowired
private ActTaskConditionService actTaskConditionService;
@Autowired
private ActUserTaskService actUserTaskService;
@Autowired
private ActUserRecordService actUserRecordService;
@Autowired
private ActTaskRewardService actTaskRewardService;
@Autowired
private UserPurseService userPurseService;
@Autowired
private BillRecordService billRecordService;
@Override
public List<ActivityTask> getActivityTasks(String componentCode) {
List<ActivityTask> activityTasks = new ArrayList<>();
List<ActTask> actTasks = actTaskService.list(Wrappers.<ActTask>lambdaQuery()
.eq(ActTask::getComponentCode, componentCode)
.isNull(ActTask::getParentCode)
.orderByAsc(ActTask::getSeqNo));
if (CollectionUtil.isNotEmpty(actTasks)) {
for (ActTask actTask : actTasks) {
ActivityTask activityTask = buildActivityTask(actTask);
if (activityTask != null) {
activityTasks.add(activityTask);
}
}
}
return activityTasks;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void exchange(String activityCode, String taskCode, Integer diamondNum, Integer num) {
Date now = new Date();
int count = actActivityService.count(Wrappers.<ActActivity>lambdaQuery()
.eq(ActActivity::getActivityCode, activityCode)
.eq(ActActivity::getActivityStatus, Constant.Yes1No0.YES)
.le(ActActivity::getStartTime, now)
.ge(ActActivity::getEndTime, now));
if (count == 0) {
throw new ApiException("活动已结束");
}
Long uid = UidContextHolder.get();
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getUid, uid));
if (CollectionUtil.isEmpty(actUserTasks)) {
throw new ApiException("未完成任务");
}
List<ActTask> actTasks = actTaskService.list(Wrappers.<ActTask>lambdaQuery()
.eq(ActTask::getActivityCode, activityCode)
.eq(ActTask::getTaskCode, taskCode));
if (CollectionUtil.isEmpty(actTasks)) {
throw new ApiException("任务不存在");
}
List<ActTaskCondition> actTaskConditions = actTaskConditionService.list(Wrappers.<ActTaskCondition>lambdaQuery()
.eq(ActTaskCondition::getActivityCode, activityCode)
.eq(ActTaskCondition::getTaskCode, taskCode)
.eq(ActTaskCondition::getConditionKind, ActConditionKindEnum.GE.name()));
if (CollectionUtil.isEmpty(actTaskConditions)) {
throw new ApiException("任务条件不存在");
}
ActTaskCondition actTaskCondition = actTaskConditions.get(0);
Long conditionValue = actTaskCondition.getConditionValue();
long activityValue = actUserTasks.stream().mapToLong(ActUserTask::getActivityValue).sum();
if (conditionValue == 0) {
throw new ApiException("任务值不能为0");
}
long validNum = activityValue / conditionValue;
if (num > validNum) {
throw new ApiException("超过可用数量");
}
List<ActTaskReward> actTaskRewards = actTaskRewardService.list(Wrappers.<ActTaskReward>lambdaQuery()
.eq(ActTaskReward::getActivityCode, activityCode)
.eq(ActTaskReward::getTaskCode, taskCode));
if (CollectionUtil.isEmpty(actTaskRewards)) {
throw new ApiException("缺少奖励配置");
}
//余额校验
UserPurse userPurse = userPurseService.queryUserPurse(uid);
Double currentDiamonds = userPurse.getDiamonds();
if (diamondNum > currentDiamonds) {
throw new ApiException(BusiStatus.PURSE_MONEY_NOT_ENOUGH);
}
//扣减钱包
if (!userPurseService.subDiamond(uid, diamondNum.doubleValue(), BillObjTypeEnum.ACTIVITY_PACKET.getDesc())) {
userPurse = userPurseService.queryUserPurse(uid);
currentDiamonds = userPurse.getDiamonds();
log.error("[购买活动礼物] {} 当前钱包钻石数 {} ,扣钻石数 {} 不成功", uid, currentDiamonds, diamondNum);
throw new ServiceException(BusiStatus.SERVER_BUSY);
}
for (ActTaskReward actTaskReward : actTaskRewards) {
ActRewardContext context = new ActRewardContext();
context.setUid(uid);
context.setReward(actTaskReward);
ActUserTask actUserTask = new ActUserTask();
actUserTask.setActivityValue(num * conditionValue);
context.setTask(actUserTask);
Long recordId = ActRewardFactory.getReward(actTaskReward.getRewardType()).grant(context);
String recordIdStr = StrUtil.EMPTY;
if (recordId != null) {
recordIdStr = recordId.toString();
}
//添加账单记录
if (recordId != null) {
billRecordService.insertGeneralBillRecord(uid, uid, recordIdStr, BillObjTypeEnum.ACTIVITY_PACKET, diamondNum.doubleValue());
}
}
//更新兑换值
baseMapper.updateExchangeValue(activityCode, taskCode, (int) (num * conditionValue));
}
private ActivityTask buildActivityTask(ActTask actTask) {
Long uid = UidContextHolder.get();
if (actTask == null) {
return null;
}
Date now = new Date();
String activityCode = actTask.getActivityCode();
List<ActActivity> actActivities = actActivityService.list(Wrappers.<ActActivity>lambdaQuery()
.eq(ActActivity::getActivityStatus, Constant.Yes1No0.YES)
.le(ActActivity::getStartTime, now)
.ge(ActActivity::getEndTime, now));
if (CollectionUtil.isEmpty(actActivities)) {
return null;
}
ActActivity actActivity = actActivities.get(0);
String taskCode = actTask.getTaskCode();
String taskName = actTask.getTaskName();
Integer timeType = actTask.getTimeType();
Integer taskValue = actTask.getTaskValue();
Date startTime = actActivity.getStartTime();
Date endTime = actActivity.getEndTime();
if (ActTimeTypeEnum.LOOP.ordinal() == timeType) {
String startTimeFormat = actTask.getStartTimeFormat();
Integer timeDuration = actTask.getTimeDuration();
startTime = DateTimeUtil.convertStrToDate(DateTimeUtil.convertDate(now, startTimeFormat));
if (startTime != null) {
endTime = new Date(startTime.getTime() + timeDuration * 1000);
}
}
//节点
ActivityTask node = new ActivityTask();
node.setActivityCode(activityCode);
node.setTaskCode(taskCode);
node.setTaskName(taskName);
node.setTaskIcon(actTask.getTaskIcon());
if (taskValue != null) {
node.setTaskValue(String.valueOf(taskValue));
}
//装饰
ActivityTaskForGiftDecorator decorator = new ActivityTaskForGiftDecorator();
ActivityTaskDecorateChain chain = new ActivityTaskDecorateChain(decorator);
chain.decorate(Collections.singletonList(node));
//奖品
List<ActTaskReward> rewards = actTaskRewardService.list(Wrappers.<ActTaskReward>lambdaQuery()
.eq(ActTaskReward::getActivityCode, activityCode)
.eq(ActTaskReward::getTaskCode, taskCode));
if (CollectionUtil.isNotEmpty(rewards)) {
ActTaskReward actTaskReward = rewards.get(0);
String rewardType = actTaskReward.getRewardType();
ActRewardContext context = new ActRewardContext();
context.setUid(uid);
context.setReward(actTaskReward);
ActivityReward reward = ActRewardFactory.getReward(rewardType).getReward(context);
List<ActUserTask> actUserTasks = list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getUid, uid));
if (CollectionUtil.isNotEmpty(actUserTasks)) {
ActUserTask actUserTask = actUserTasks.get(0);
reward.setGranted(actUserTask.getTaskStatus() == ActTaskStatusEnum.GRANT.ordinal());
}
node.setReward(reward);
}
//完成任务条件
List<ActTaskCondition> actTaskConditions = actTaskConditionService.list(Wrappers.<ActTaskCondition>lambdaQuery()
.eq(ActTaskCondition::getActivityCode, activityCode)
.eq(ActTaskCondition::getTaskCode, taskCode));
//查询当前用户任务状态
boolean isCompleted = false;
List<String> referenceValue = new ArrayList<>();
long conditionValue = 0;
long completeValue = 0;
long exchangeValue = 0;
if (CollectionUtil.isNotEmpty(actTaskConditions)) {
Boolean[] completeArray = new Boolean[actTaskConditions.size()];
for (int i = 0, len = actTaskConditions.size(); i < len; i++) {
completeArray[i] = Boolean.FALSE;
ActTaskCondition actTaskCondition = actTaskConditions.get(i);
String conditionKind = actTaskCondition.getConditionKind();
String conditionCode = actTaskCondition.getConditionCode();
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getConditionCode, conditionCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, startTime, endTime));
if (ActConditionKindEnum.EQ.name().equals(conditionKind)) {
if (CollectionUtil.isNotEmpty(actUserTasks)) {
completeArray[i] = actUserTasks.stream().allMatch(v -> v.getActivityValue().equals(actTaskCondition.getConditionValue()));
if (completeArray[i]) {
referenceValue.add(String.valueOf(conditionValue));
}
}
} else if (ActConditionKindEnum.GE.name().equals(conditionKind)) {
conditionValue += actTaskCondition.getConditionValue();
if (CollectionUtil.isNotEmpty(actUserTasks)) {
long activityValue = actUserTasks.stream().mapToLong(ActUserTask::getActivityValue).sum();
completeArray[i] = activityValue >= conditionValue;
completeValue += activityValue;
}
}
if (CollectionUtil.isNotEmpty(actUserTasks)) {
exchangeValue += actUserTasks.stream().mapToLong(ActUserTask::getExchangeValue).sum();
}
}
isCompleted = Arrays.stream(completeArray).allMatch(v -> v);
}
node.setCompleted(isCompleted);
if (CollectionUtil.isNotEmpty(referenceValue)) {
node.setReferenceValue(CollectionUtil.join(referenceValue, StrUtil.COMMA));
}
if (conditionValue != 0) {
node.setTaskValue(String.valueOf(conditionValue));
}
node.setCompleteValue(completeValue);
if (completeValue < exchangeValue) {
node.setActivityValue(0L);
} else {
node.setActivityValue(completeValue - exchangeValue);
}
//子任务
List<ActTask> actTasks = actTaskService.list(Wrappers.<ActTask>lambdaQuery()
.eq(ActTask::getParentCode, taskCode)
.orderByAsc(ActTask::getSeqNo));
if (CollectionUtil.isNotEmpty(actTasks)) {
List<ActivityTask> children = new ArrayList<>();
for (ActTask task : actTasks) {
ActivityTask activityTask = buildActivityTask(task);
if (activityTask != null) {
children.add(activityTask);
}
}
node.setChildren(children);
}
return node;
}
}

View File

@@ -0,0 +1,37 @@
package com.accompany.business.activity.strategy;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.common.exception.ApiException;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.base.SpringContextHolder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: liaozetao
* @date: 2024/1/29 11:19
* @description:
*/
public final class ActRewardFactory {
private static final Map<String, IActRewardStrategy> ACT_REWARD_MAP = new ConcurrentHashMap<>();
private static void init() {
if (ACT_REWARD_MAP.isEmpty()) {
Map<String, IActRewardStrategy> map = SpringContextHolder.getApplicationContext().getBeansOfType(IActRewardStrategy.class);
if (CollectionUtil.isEmpty(map)) {
throw new ApiException(BusiStatus.SERVERERROR);
}
for (Map.Entry<String, IActRewardStrategy> entry : map.entrySet()) {
ACT_REWARD_MAP.put(entry.getValue().getRewardType(), entry.getValue());
}
}
}
public static IActRewardStrategy getReward(String rewardType) {
init();
return ACT_REWARD_MAP.get(rewardType);
}
}

View File

@@ -0,0 +1,70 @@
package com.accompany.business.activity.strategy;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.common.constant.RewardTypeEnum;
import com.accompany.business.model.dress.ChatBubble;
import com.accompany.business.mybatismapper.dress.ChatBubbleMapper;
import com.accompany.business.service.dress.UserChatBubbleService;
import com.accompany.business.service.vip.ChatBubbleService;
import com.accompany.common.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author: liaozetao
* @date: 2024/1/31 16:57
* @description:
*/
@Slf4j
@Component
public class ActRewardForChatBubbleStrategy extends IActRewardStrategy {
@Autowired
private ChatBubbleMapper chatBubbleMapper;
@Autowired
private ChatBubbleService chatBubbleService;
@Autowired
private UserChatBubbleService userChatBubbleService;
@Override
String getRewardType() {
return RewardTypeEnum.CHATBUBBLE.name();
}
@Override
Byte getSecretarySkipType() {
return Constant.SecretarySkipType.CHAT_BUBBLE;
}
@Override
void doGetReward(ActivityReward reward) {
Long rewardId = reward.getRewardId();
ChatBubble chatBubble = chatBubbleService.getChatBubbleById(rewardId);
reward.setRewardName(chatBubble.getName());
}
@Override
void doGrant(ActRewardContext context) {
ActTaskReward reward = context.getReward();
Long rewardId = reward.getRewardId();
if (rewardId == null) {
return;
}
ChatBubble chatBubble = chatBubbleService.getChatBubbleById(rewardId);
if (null == chatBubble) {
return;
}
String activityName = context.getActivityName();
context.setRewardName(chatBubble.getName());
context.setRewardIcon(chatBubble.getAndroidUrl());
Integer rewardNum = reward.getRewardNum();
Long uid = context.getUid();
userChatBubbleService.sendChatBubbleToUser(uid, rewardId, Constant.UserInfoCardComeFrom.ADMIN_SEND, rewardNum, activityName, false);
}
}

View File

@@ -0,0 +1,120 @@
package com.accompany.business.activity.strategy;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.common.constant.RewardTypeEnum;
import com.accompany.business.model.Gift;
import com.accompany.business.model.GiftExample;
import com.accompany.business.mybatismapper.GiftMapper;
import com.accompany.business.param.UserBackpackParam;
import com.accompany.business.service.gift.GiftService;
import com.accompany.business.service.user.UserBackpackService;
import com.accompany.common.constant.Constant;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.exception.ServiceException;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/29 11:01
* @description:
*/
@Slf4j
@Component
public class ActRewardForGiftStrategy extends IActRewardStrategy {
@Autowired
private GiftMapper giftMapper;
@Autowired
private GiftService giftService;
@Autowired
private UserBackpackService userBackpackService;
private final static int MAX_RETRY_TIME = 3;
@Override
String getRewardType() {
return RewardTypeEnum.GIFT.name();
}
@Override
Byte getSecretarySkipType() {
return Constant.SecretarySkipType.ROOM;
}
@Override
void doGetReward(ActivityReward reward) {
Long rewardId = reward.getRewardId();
GiftExample example = new GiftExample();
example.createCriteria().andGiftIdEqualTo(rewardId.intValue());
List<Gift> gifts = giftMapper.selectByExample(example);
if (CollectionUtil.isEmpty(gifts)) {
return;
}
Gift gift = gifts.get(0);
reward.setRewardName(gift.getGiftName());
reward.setRewardIcon(gift.getGifUrl());
reward.setShowValue(gift.getGoldPrice().toString());
}
@Override
void doGrant(ActRewardContext context) {
ActTaskReward reward = context.getReward();
Long rewardId = reward.getRewardId();
if (rewardId == null) {
return;
}
Integer giftId = rewardId.intValue();
Gift gift = giftService.getGiftByIdFromDb(giftId);
if (gift == null) {
return;
}
context.setRewardName(gift.getGiftName());
context.setRewardIcon(gift.getPicUrl());
UserBackpackParam userBackpack = new UserBackpackParam();
userBackpack.setUid(context.getUid());
userBackpack.setGiftId(gift.getGiftId());
userBackpack.setGiftType(gift.getGiftType());
userBackpack.setGiftSeq(gift.getSeqNo());
userBackpack.setCount(reward.getRewardNum());
log.info("userBackpack : {}", JSONObject.toJSONString(userBackpack));
int tryTimes = 0;
boolean needRetry = false;
do {
try {
userBackpackService.saveOrUpdateUserBackpack(userBackpack);
needRetry = false;
} catch (Exception e) {
tryTimes++;
if (e instanceof ServiceException) {
ServiceException se = (ServiceException) e;
if (BusiStatus.SERVERBUSY.equals(se.getBusiStatus())) {
if (tryTimes < MAX_RETRY_TIME) {
needRetry = true;
log.error("saveOrUpdateUserBackpack fail, retry....");
try {
Thread.sleep(10000L);
} catch (InterruptedException ignored) {
}
} else {
needRetry = false;
}
}
}
if (!needRetry) {
throw e;
}
}
} while (needRetry && tryTimes < MAX_RETRY_TIME);
}
}

View File

@@ -0,0 +1,68 @@
package com.accompany.business.activity.strategy;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.common.constant.RewardTypeEnum;
import com.accompany.business.model.Headwear;
import com.accompany.business.mybatismapper.UserHeadwearMapper;
import com.accompany.business.service.headwear.HeadwearService;
import com.accompany.common.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author: liaozetao
* @date: 2024/1/31 15:21
* @description:
*/
@Slf4j
@Component
public class ActRewardForHeadWearStrategy extends IActRewardStrategy {
@Autowired
private UserHeadwearMapper userHeadwearMapper;
@Autowired
private HeadwearService headwearService;
@Override
String getRewardType() {
return RewardTypeEnum.HEADWEAR.name();
}
@Override
Byte getSecretarySkipType() {
return Constant.SecretarySkipType.HEADWEAR;
}
@Override
void doGetReward(ActivityReward reward) {
Long rewardId = reward.getRewardId();
Headwear headWear = headwearService.getHeadwear(rewardId.intValue());
reward.setRewardName(headWear.getName());
reward.setShowValue(headWear.getPrice().toString());
reward.setExpireDay(headWear.getDays());
}
@Override
void doGrant(ActRewardContext context) {
ActTaskReward reward = context.getReward();
Long rewardId = reward.getRewardId();
if (rewardId == null) {
return;
}
int headWearId = rewardId.intValue();
Headwear headWear = headwearService.getHeadwear(headWearId);
if (headWear == null) {
return;
}
context.setRewardName(headWear.getName());
context.setRewardIcon(headWear.getPic());
Integer rewardNum = reward.getRewardNum();
Long uid = context.getUid();
headwearService.officialSendHeadWearSingle(headWearId, uid, rewardNum, false);
}
}

View File

@@ -0,0 +1,114 @@
package com.accompany.business.activity.strategy;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.constant.RewardFlagConstant;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.common.constant.RewardTypeEnum;
import com.accompany.business.model.Nameplate;
import com.accompany.business.mybatismapper.NameplateMapper;
import com.accompany.business.mybatismapper.UserNameplateMapper;
import com.accompany.business.service.nameplate.UserNameplateService;
import com.accompany.common.constant.Constant;
import com.accompany.common.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/29 11:03
* @description:
*/
@Slf4j
@Component
public class ActRewardForNameplateStrategy extends IActRewardStrategy {
@Autowired
private NameplateMapper nameplateMapper;
@Autowired
private UserNameplateMapper userNameplateMapper;
@Autowired
private UserNameplateService userNameplateService;
@Override
String getRewardType() {
return RewardTypeEnum.NAMEPLATE.name();
}
@Override
Byte getSecretarySkipType() {
return Constant.SecretarySkipType.NAMEPLATE;
}
@Override
void doGetReward(ActivityReward reward) {
Long rewardId = reward.getRewardId();
Nameplate nameplate = nameplateMapper.selectById(rewardId);
if (nameplate == null) {
return;
}
reward.setRewardName(nameplate.getName());
Long dressShopPrice = nameplate.getDressShopPrice();
if (dressShopPrice != null) {
reward.setShowValue(dressShopPrice.toString());
}
reward.setExpireDay(nameplate.getDays());
}
@Override
void doGrant(ActRewardContext context) {
Long uid = context.getUid();
String activityName = context.getActivityName();
ActTaskReward reward = context.getReward();
Long rewardId = reward.getRewardId();
if (rewardId == null) {
return;
}
Nameplate nameplate = nameplateMapper.selectById(rewardId);
if (nameplate == null) {
return;
}
context.setRewardName(nameplate.getName());
context.setRewardIcon(nameplate.getIconPic());
Integer rewardNum = reward.getRewardNum();
Integer timeUnit = reward.getTimeUnit();
LocalDateTime now = LocalDateTime.now();
if (Calendar.DATE == timeUnit) {
now = now.plusDays(rewardNum);
}
Date expireTime = DateTimeUtil.converLocalDateTimeToDate(now);
Integer rewardFlag = reward.getRewardFlag();
String expireTimeFormat = reward.getExpireTimeFormat();
log.info("rewardId : {}, rewardFlag : {}, expireTimeFormat : {}, rewardNum : {}", rewardId, rewardFlag, expireTimeFormat, rewardNum);
//固定时间失效
if ((rewardFlag & RewardFlagConstant.REWARD_FLAG_FOR_FIX_TIME) != 0 && StrUtil.isNotEmpty(expireTimeFormat)) {
expireTime = DateTimeUtil.converLocalDateTimeToDate(now);
String[] expireTimeArray = expireTimeFormat.split(StrUtil.SPACE);
String expireDate = DateTimeUtil.convertDate(expireTime, DateTimeUtil.DEFAULT_DATE_PATTERN);
String expireTimeStr = expireDate + StrUtil.SPACE + expireTimeArray[1];
expireTime = DateTimeUtil.convertStrToDate(expireTimeStr, DateTimeUtil.DEFAULT_DATETIME_PATTERN);
Date currentTime = new Date();
if (expireTime != null && expireTime.getTime() <= currentTime.getTime()) {
now = LocalDateTime.now();
if (Calendar.DATE == timeUnit) {
now = now.plusDays(rewardNum);
}
expireTime = DateTimeUtil.converLocalDateTimeToDate(now);
expireDate = DateTimeUtil.convertDate(expireTime, DateTimeUtil.DEFAULT_DATE_PATTERN);
expireTimeStr = expireDate + StrUtil.SPACE + expireTimeArray[1];
expireTime = DateTimeUtil.convertStrToDate(expireTimeStr, DateTimeUtil.DEFAULT_DATETIME_PATTERN);
}
}
log.info("uid : {}, rewardId : {}, activityName : {}, expireTime : {}", uid, rewardId, activityName, expireTime);
userNameplateService.sendUserNameplate(uid, rewardId, activityName, expireTime);
}
}

View File

@@ -0,0 +1,164 @@
package com.accompany.business.activity.strategy;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.dto.ActRewardContext;
import com.accompany.business.activity.model.ActActivity;
import com.accompany.business.activity.model.ActTaskReward;
import com.accompany.business.activity.model.ActUserRecord;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.business.activity.service.ActActivityService;
import com.accompany.business.activity.service.ActUserRecordService;
import com.accompany.business.activity.vo.ActivityReward;
import com.accompany.business.param.neteasepush.NeteaseSendMsgParam;
import com.accompany.business.service.SendSysMsgService;
import com.accompany.common.config.SystemConfig;
import com.accompany.common.constant.Attach;
import com.accompany.common.constant.Constant;
import com.accompany.core.service.common.JedisService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/1/29 11:00
* @description:
*/
@Slf4j
public abstract class IActRewardStrategy {
@Autowired
protected ActActivityService actActivityService;
@Autowired
private ActUserRecordService actUserRecordService;
@Autowired
protected SendSysMsgService sendSysMsgService;
@Autowired
protected JedisService jedisService;
/**
* 奖品类型
*
* @return
*/
abstract String getRewardType();
/**
* 小秘书
*
* @return
*/
abstract Byte getSecretarySkipType();
/**
* 获取奖品信息
*
* @param context
* @return
*/
public ActivityReward getReward(ActRewardContext context) {
Long rewardId = context.getReward().getRewardId();
ActivityReward reward = new ActivityReward();
reward.setRewardId(rewardId);
reward.setRewardType(getRewardType());
doGetReward(reward);
return reward;
}
/**
* 处理
*
* @param reward
* @return
*/
abstract void doGetReward(ActivityReward reward);
public Long grant(ActRewardContext context) {
log.info("==== 开始发放奖励 ====, context : {}", JSONObject.toJSONString(context));
Long recordId = null;
Long uid = context.getUid();
ActTaskReward reward = context.getReward();
if (reward == null) {
return null;
}
Long rewardId = reward.getRewardId();
Integer rewardNum = reward.getRewardNum();
String noticeMessage = reward.getNoticeMessage();
String activityCode = reward.getActivityCode();
List<ActActivity> actActivities = actActivityService.list(Wrappers.<ActActivity>lambdaQuery().eq(ActActivity::getActivityCode, activityCode));
if (CollectionUtil.isEmpty(actActivities)) {
return null;
}
ActActivity actActivity = actActivities.get(0);
String activityName = actActivity.getActivityName();
context.setActivityName(activityName);
try {
doGrant(context);
String rewardName = context.getRewardName();
String rewardIcon = context.getRewardIcon();
//奖品记录
ActUserRecord record = new ActUserRecord();
record.setUid(uid);
record.setActivityCode(activityCode);
record.setComponentCode(reward.getComponentCode());
record.setTaskCode(reward.getTaskCode());
ActUserTask task = context.getTask();
if (task != null) {
record.setActivityValue(task.getActivityValue());
}
record.setRewardId(rewardId);
record.setRewardType(getRewardType());
record.setRewardName(rewardName);
record.setRewardIcon(rewardIcon);
record.setRewardNum(rewardNum);
actUserRecordService.save(record);
recordId = record.getId();
//发送消息
if (StrUtil.isEmpty(noticeMessage)) {
return recordId;
}
String message = noticeMessage.replaceAll("activityName", activityName).replaceAll("rewardName", rewardName).replaceAll("rewardIcon", rewardIcon);
sendSysMsgService.sendMsg(getNeteaseSendMsgParam(activityName, message, uid));
} catch (Exception e) {
log.error("{} {} {} {} {} 发奖异常", uid, getRewardType(), rewardId, rewardNum, activityName, e);
}
log.info("==== 发放奖励结束 ====, context : {}", JSONObject.toJSONString(context));
return recordId;
}
@NotNull
private NeteaseSendMsgParam getNeteaseSendMsgParam(String activityName, String message, Long uid) {
Attach attach = new Attach();
attach.setFirst(Constant.DefineProtocol.CUSTOM_MESS_HEAD_SECRETARY);
attach.setSecond(Constant.DefineProtocol.CUSTOM_MESS_SUB_SECRETARY_INTRACTION);
JSONObject jsonObject = new JSONObject();
jsonObject.put("title", "[" + activityName + "]");
jsonObject.put("msg", message);
jsonObject.put("routerType", getSecretarySkipType());
jsonObject.put("routerValue", 1);
attach.setData(jsonObject);
NeteaseSendMsgParam neteaseSendMsgParam = new NeteaseSendMsgParam();
neteaseSendMsgParam.setType(Constant.DefineProtocol.CUSTOM_MESS_DEFINE);
neteaseSendMsgParam.setFrom(SystemConfig.secretaryUid);
neteaseSendMsgParam.setOpe(0);
neteaseSendMsgParam.setTo(String.valueOf(uid));
neteaseSendMsgParam.setAttach(attach);
return neteaseSendMsgParam;
}
/**
* 处理发放逻辑
*
* @param context
*/
abstract void doGrant(ActRewardContext context);
}

View File

@@ -5,9 +5,7 @@ import com.accompany.business.base.rankobj.CpRankObjectProvider;
import com.accompany.business.common.constant.CpRankTypeEnum;
import com.accompany.business.common.dto.CpRankActConfigDto;
import com.accompany.business.common.dto.RewardDto;
import com.accompany.business.common.vo.ActivityCpRankItemVo;
import com.accompany.business.common.vo.ActivityCpRankVo;
import com.accompany.business.common.vo.RewardVo;
import com.accompany.business.common.vo.*;
import com.accompany.business.core.utils.RewardUtil;
import com.accompany.common.constant.AppEnum;
import com.accompany.common.status.BusiStatus;
@@ -106,7 +104,7 @@ public abstract class BaseCpRankActService<Provider extends CpRankObjectProvider
cpRankItemVo.setCpUid(cpUid);
Integer cpRanking = cpRankingList.get(index);
cpRankItemVo.setRanking(null != cpRanking && cpRanking < 30? cpRanking + 1: 0);
cpRankItemVo.setRanking(null != cpRanking && cpRanking < (rankSize - 1)? cpRanking + 1: 0);
Double cpScore = cpScoreList.get(index);
cpRankItemVo.setScore(null != cpScore? BigDecimal.valueOf(cpScore).setScale(0, RoundingMode.DOWN).longValue(): 0L);
@@ -134,7 +132,7 @@ public abstract class BaseCpRankActService<Provider extends CpRankObjectProvider
}
private ActivityCpRankVo buildActivityRankVo(List<ActivityCpRankItemVo> rankItemVoList, List<ActivityCpRankItemVo> meRankVoList,
CpRankActConfigDto config, CpRankTypeEnum rankType) {
CpRankActConfigDto config, CpRankTypeEnum rankType) {
String startTime = config.getStartTime().format(dateTimeFormatter);
String endTime = config.getEndTime().format(dateTimeFormatter);
@@ -258,8 +256,9 @@ public abstract class BaseCpRankActService<Provider extends CpRankObjectProvider
int rewardLevel = settlementSizes.stream().mapToInt(Integer::intValue).filter(level->ranking<=level).min().getAsInt();
int rewardIndex = settlementSizes.indexOf(rewardLevel);
List<RewardDto> rewards = rewardConfigList.get(rewardIndex);
for (RewardDto r: rewards) {
for (Long uid: uidList){
for (Long uid: uidList){
List<RewardDto> userRewards = listRewardConfig(uid, rewards);
for (RewardDto r: userRewards) {
String uidRewardKey = String.join("_", cpUid, uid.toString(), r.getType().getType().toString(), r.getRefId().toString());
if (needFlag && flagSet.contains(uidRewardKey)){
continue;
@@ -282,6 +281,10 @@ public abstract class BaseCpRankActService<Provider extends CpRankObjectProvider
rank.expire(expireDateTime);
}
public List<RewardDto> listRewardConfig(Long uid, List<RewardDto> rewards){
return rewards;
}
protected void logRankReward(CpRankTypeEnum rankType, String date, String rankKey, Integer rankIndex, Long uid, RewardVo reward) {
}

View File

@@ -24,9 +24,14 @@ import com.accompany.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
@Service
@Slf4j
@@ -54,6 +59,20 @@ public class RewardUtil {
@Resource(name = "bizExecutor")
private ThreadPoolExecutor bizExecutor;
public List<RewardVo> sendRewardByUid(Long uid,
List<RewardDto> rewardList,
BiFunction<Long, List<RewardDto>, List<RewardDto>> selector,
String remark) {
List<RewardDto> userRewards = selector.apply(uid, rewardList);
if (CollectionUtils.isEmpty(userRewards)) {
return Collections.emptyList();
}
return userRewards.parallelStream()
.map(rewardDto -> sendRewardByType(uid, rewardDto, remark, Boolean.FALSE))
.collect(Collectors.toList());
}
public RewardVo sendRewardByType(Long uid, RewardDto reward, String remark) {
return sendRewardByType(uid, reward, remark, Boolean.FALSE);
}
@@ -71,17 +90,17 @@ public class RewardUtil {
vo.setNum(num);
vo.setUnit(typeEnum.getUnit());
switch (typeEnum){
switch (typeEnum) {
case HEADWEAR:
Headwear headwear = headwearService.getHeadwear(refId);
if (null == headwear){
if (null == headwear) {
throw new ServiceException(BusiStatus.NOT_FOUNT_REWARD_ITEM);
}
bizExecutor.execute(()->{
bizExecutor.execute(() -> {
try {
headwearService.officialSendHeadWearSingle(headwear.getHeadwearId(), uid, num, needSendMessage);
} catch (Exception e){
} catch (Exception e) {
log.error("[RewardUtil] {} {} {} {} {} 发奖异常", uid, typeEnum, refId, num, remark, e);
}
});
@@ -91,14 +110,14 @@ public class RewardUtil {
break;
case NAMEPLATE:
Nameplate nameplate = nameplateMapper.selectById(refId.longValue());
if (null == nameplate){
if (null == nameplate) {
throw new ServiceException(BusiStatus.NOT_FOUNT_REWARD_ITEM);
}
bizExecutor.execute(()->{
bizExecutor.execute(() -> {
try {
userNameplateService.officialSendNameplateSingle(nameplate.getId(), uid, num, remark, SystemConfig.secretaryUid, null, null);
} catch (Exception e){
} catch (Exception e) {
log.error("[RewardUtil] {} {} {} {} {} 发奖异常", uid, typeEnum, refId, num, remark, e);
}
});
@@ -108,14 +127,14 @@ public class RewardUtil {
break;
case CHATBUBBLE:
ChatBubble chatBubble = chatBubbleService.getChatBubbleById(refId.longValue());
if (null == chatBubble){
if (null == chatBubble) {
throw new ServiceException(BusiStatus.NOT_FOUNT_REWARD_ITEM);
}
bizExecutor.execute(()->{
bizExecutor.execute(() -> {
try {
userChatBubbleService.sendChatBubbleToUser(uid, chatBubble.getId(), Constant.UserInfoCardComeFrom.ADMIN_SEND, num, remark, needSendMessage);
} catch (Exception e){
} catch (Exception e) {
log.error("[RewardUtil] {} {} {} {} {} 发奖异常", uid, typeEnum, refId, num, remark, e);
}
});
@@ -125,14 +144,14 @@ public class RewardUtil {
break;
case INFOCARD:
InfoCard infoCard = infoCardService.getInfoCardById(refId.longValue());
if (null == infoCard){
if (null == infoCard) {
throw new ServiceException(BusiStatus.NOT_FOUNT_REWARD_ITEM);
}
bizExecutor.execute(()->{
bizExecutor.execute(() -> {
try {
userInfoCardService.sendInfoCardToUser(uid, infoCard.getId(), Constant.UserInfoCardComeFrom.ADMIN_SEND, num, remark, needSendMessage);
} catch (Exception e){
} catch (Exception e) {
log.error("[RewardUtil] {} {} {} {} {} 发奖异常", uid, typeEnum, refId, num, remark, e);
}
});
@@ -142,14 +161,14 @@ public class RewardUtil {
break;
case CAR:
CarGoods car = carGoodsService.getCarGoods(refId);
if (null == car){
if (null == car) {
throw new ServiceException(BusiStatus.NOT_FOUNT_REWARD_ITEM);
}
bizExecutor.execute(()->{
bizExecutor.execute(() -> {
try {
carPayService.experCarByOfficial(uid, car.getId(), num, remark, needSendMessage);
} catch (Exception e){
} catch (Exception e) {
log.error("[RewardUtil] {} {} {} {} {} 发奖异常", uid, typeEnum, refId, num, remark, e);
}
});

View File

@@ -0,0 +1,178 @@
package com.accompany.business.valentine.handler;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.dto.ActTaskContext;
import com.accompany.business.activity.enums.ActTaskStatusEnum;
import com.accompany.business.activity.handle.IActTaskHandler;
import com.accompany.business.activity.model.ActTask;
import com.accompany.business.activity.model.ActTaskCondition;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.business.activity.service.ActTaskService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/2/5 10:48
* @description:
*/
@Slf4j
@Component
public class ValentinesDayBoxHandler extends IActTaskHandler {
@Autowired
private ActTaskService actTaskService;
@Override
protected boolean eq(ActTaskCondition actTaskCondition, ActTaskContext context) {
Long conditionValue = actTaskCondition.getConditionValue();
Long uid = context.getSendUid();
Integer giftId = context.getGiftId();
Date startTime = context.getTaskStartTime();
Date endTime = context.getTaskEndTime();
ActTask actTask = context.getActTask();
log.info("conditionValue : {}, uid : {}, giftId : {}, startTime : {}, endTime : {}", conditionValue, uid, giftId, startTime, endTime);
if (giftId == null) {
return false;
}
if (conditionValue == null || !conditionValue.equals(giftId.longValue())) {
return false;
}
String conditionCode = actTaskCondition.getConditionCode();
String activityCode = actTask.getActivityCode();
String componentCode = actTask.getComponentCode();
String taskCode = actTask.getTaskCode();
ActUserTask actUserTask = new ActUserTask();
actUserTask.setUid(uid);
actUserTask.setActivityCode(activityCode);
actUserTask.setComponentCode(componentCode);
actUserTask.setTaskCode(taskCode);
actUserTask.setConditionCode(conditionCode);
actUserTask.setActivityValue(0L);
actUserTask.setStartTime(startTime);
actUserTask.setEndTime(endTime);
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getComponentCode, componentCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getConditionCode, conditionCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, startTime, endTime)
.orderByAsc(ActUserTask::getCreateTime));
if (CollectionUtil.isNotEmpty(actUserTasks)) {
ActUserTask task = actUserTasks.get(0);
Integer taskStatus = task.getTaskStatus();
if (ActTaskStatusEnum.COMPLETE.ordinal() == taskStatus) {
log.info("taskCode : {} is already complete.", taskCode);
return true;
}
actUserTask.setId(task.getId());
}
actUserTask.setActivityValue(giftId.longValue());
actUserTask.setTaskStatus(ActTaskStatusEnum.COMPLETE.ordinal());
actUserTaskService.saveOrUpdate(actUserTask);
log.info("conditionValue : {}, uid : {}, giftId : {}, startTime : {}, endTime : {} is complete.", conditionValue, uid, giftId, startTime, endTime);
return true;
}
@Override
public void doHandle(ActTaskContext context) {
Long uid = context.getSendUid();
Date startTime = context.getTaskStartTime();
Date endTime = context.getTaskEndTime();
ActTask actTask = context.getActTask();
String activityCode = actTask.getActivityCode();
String componentCode = actTask.getComponentCode();
String parentCode = actTask.getTaskCode();
log.info("doHandle uid : {}, parentCode : {}", uid, parentCode);
List<ActTask> actTasks = actTaskService.list(Wrappers.<ActTask>lambdaQuery()
.eq(ActTask::getActivityCode, activityCode)
.eq(ActTask::getComponentCode, componentCode)
.eq(ActTask::getParentCode, parentCode)
.orderByAsc(ActTask::getSeqNo));
if (CollectionUtil.isEmpty(actTasks)) {
return;
}
List<ActTaskCondition> actTaskConditions = actTaskConditionService.list(Wrappers.<ActTaskCondition>lambdaQuery()
.eq(ActTaskCondition::getActivityCode, activityCode)
.eq(ActTaskCondition::getComponentCode, componentCode)
.eq(ActTaskCondition::getTaskCode, parentCode));
if (CollectionUtil.isEmpty(actTaskConditions)) {
return;
}
ActTaskCondition actTaskCondition = actTaskConditions.get(0);
String conditionCode = actTaskCondition.getConditionCode();
Long conditionValue = actTaskCondition.getConditionValue();
ActUserTask actUserTask = new ActUserTask();
actUserTask.setUid(uid);
actUserTask.setActivityCode(activityCode);
actUserTask.setComponentCode(componentCode);
actUserTask.setTaskCode(parentCode);
actUserTask.setConditionCode(conditionCode);
actUserTask.setActivityValue(0L);
actUserTask.setTaskStatus(ActTaskStatusEnum.PROCESS.ordinal());
actUserTask.setStartTime(startTime);
actUserTask.setEndTime(endTime);
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getComponentCode, componentCode)
.eq(ActUserTask::getTaskCode, parentCode)
.eq(ActUserTask::getConditionCode, conditionCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, startTime, endTime));
if (CollectionUtil.isNotEmpty(actUserTasks)) {
ActUserTask task = actUserTasks.get(0);
Integer taskStatus = task.getTaskStatus();
if (ActTaskStatusEnum.COMPLETE.ordinal() == taskStatus || ActTaskStatusEnum.GRANT.ordinal() == taskStatus) {
log.info("parentCode : {} is complete", parentCode);
return;
}
actUserTask.setId(task.getId());
}
int length = actTasks.size();
log.info("task execute length : {}", length);
Boolean[] completeArray = new Boolean[length];
for (int i = 0; i < length; i++) {
completeArray[i] = false;
ActTask children = actTasks.get(i);
String taskCode = children.getTaskCode();
actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getComponentCode, componentCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, startTime, endTime)
.orderByAsc(ActUserTask::getCreateTime));
if (CollectionUtil.isEmpty(actUserTasks)) {
continue;
}
ActUserTask task = actUserTasks.get(0);
Integer taskStatus = task.getTaskStatus();
completeArray[i] = ActTaskStatusEnum.COMPLETE.ordinal() == taskStatus;
}
long count = Arrays.stream(completeArray).filter(v -> v).count();
log.info("task taskCount : {}", count);
actUserTask.setActivityValue(count);
if (conditionValue != null && conditionValue.equals(count)) {
actUserTask.setTaskStatus(ActTaskStatusEnum.COMPLETE.ordinal());
}
int taskCount = actUserTaskService.count(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getComponentCode, componentCode)
.eq(ActUserTask::getTaskCode, parentCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, startTime, endTime));
if (taskCount == 0) {
actUserTaskService.save(actUserTask);
} else {
actUserTaskService.updateById(actUserTask);
}
log.info("doHandle uid : {}, parentCode : {} is end.", uid, parentCode);
}
}

View File

@@ -0,0 +1,67 @@
package com.accompany.business.valentine.handler;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.dto.ActTaskContext;
import com.accompany.business.activity.handle.IActTaskHandler;
import com.accompany.business.activity.model.ActTask;
import com.accompany.business.activity.model.ActTaskCondition;
import com.accompany.business.activity.model.ActUserTask;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.DateTimeUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/2/5 11:45
* @description:
*/
@Slf4j
@Component
public class ValentinesDayHighGiftHandler extends IActTaskHandler {
@Override
protected boolean ge(ActTaskCondition actTaskCondition, ActTaskContext context) {
Long uid = context.getSendUid();
ActTask actTask = context.getActTask();
String activityCode = actTask.getActivityCode();
String componentCode = actTask.getComponentCode();
String taskCode = actTask.getTaskCode();
Date activityStartTime = context.getActivityStartTime();
Date activityEndTime = context.getActivityEndTime();
Date taskStartTime = context.getTaskStartTime();
Date taskEndTime = context.getTaskEndTime();
long activityValue = 0L;
String scoreStr = jedisService.hget(RedisKey.act_user_task_score.getKey(activityCode, DateTimeUtil.convertDate(activityStartTime, DateTimeUtil.ACTIVITY_DATE_HOUR_PATTERN), DateTimeUtil.convertDate(activityEndTime, DateTimeUtil.ACTIVITY_DATE_HOUR_PATTERN)), uid.toString());
if (StrUtil.isNotEmpty(scoreStr)) {
activityValue = Long.parseLong(scoreStr);
}
String conditionCode = actTaskCondition.getConditionCode();
ActUserTask actUserTask = new ActUserTask();
actUserTask.setUid(uid);
actUserTask.setActivityCode(activityCode);
actUserTask.setComponentCode(componentCode);
actUserTask.setTaskCode(taskCode);
actUserTask.setConditionCode(conditionCode);
actUserTask.setActivityValue(activityValue);
actUserTask.setStartTime(taskStartTime);
actUserTask.setEndTime(taskEndTime);
List<ActUserTask> actUserTasks = actUserTaskService.list(Wrappers.<ActUserTask>lambdaQuery()
.eq(ActUserTask::getActivityCode, activityCode)
.eq(ActUserTask::getComponentCode, componentCode)
.eq(ActUserTask::getTaskCode, taskCode)
.eq(ActUserTask::getConditionCode, conditionCode)
.eq(ActUserTask::getUid, uid)
.between(ActUserTask::getCreateTime, taskStartTime, taskEndTime));
if (CollectionUtil.isNotEmpty(actUserTasks)) {
actUserTask.setId(actUserTasks.get(0).getId());
}
log.info("activityCode : {}, taskCode : {}, activityValue : {}", activityCode, taskCode, activityValue);
actUserTaskService.saveOrUpdate(actUserTask);
return true;
}
}

View File

@@ -0,0 +1,83 @@
package com.accompany.business.valentine.listener;
import com.accompany.business.common.dto.CpRankActConfigDto;
import com.accompany.business.event.GiftMessageEvent;
import com.accompany.business.message.GiftMessage;
import com.accompany.business.model.Hall;
import com.accompany.business.model.clan.Clan;
import com.accompany.business.service.clan.ClanService;
import com.accompany.business.service.hall.HallService;
import com.accompany.business.valentine.service.ValentinesCpRankService;
import com.accompany.common.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @author: liaozetao
* @date: 2024/1/31 17:09
* @description:
*/
@Slf4j
@Component
public class ValentinesCpRankGiftListener implements ApplicationListener<GiftMessageEvent> {
@Autowired
protected ValentinesCpRankService service;
@Autowired
private HallService hallService;
@Autowired
private ClanService clanService;
@Override
public void onApplicationEvent(GiftMessageEvent event) {
GiftMessage giftMessage = (GiftMessage) event.getSource();
Date sendGiftTime = DateTimeUtil.convertMsToDate(giftMessage.getMessTime());
LocalDateTime sendGiftLocalDateTime = DateTimeUtil.converDateToLocalDateTime(sendGiftTime);
CpRankActConfigDto config = service.getRankActConfig();
if (!config.inActTimeRange(sendGiftLocalDateTime)){
return;
}
Long senderUid = giftMessage.getSendUid();
Long receiverUid = giftMessage.getRecvUid();
Integer giftId = giftMessage.getGiftId();
Integer giftNum = giftMessage.getGiftNum();
Long totalGoldNum = giftMessage.getGoldNum();
Hall senderHall = hallService.getValidHallByUid(senderUid);
if (null != senderHall){
return;
}
Clan senderClan = clanService.getByClanElderUid(senderUid);
if (null != senderClan){
return;
}
Hall receiverHall = hallService.getValidHallByUid(receiverUid);
if (null != receiverHall){
return;
}
Clan receiverClan = clanService.getByClanElderUid(receiverUid);
if (null != receiverClan){
return;
}
String cpUid = service.addAndGetCpUid(config, senderUid, receiverUid, giftId, giftNum, totalGoldNum, sendGiftTime);
if (StringUtils.isBlank(cpUid)){
return;
}
//收礼榜
service.updateRank(cpUid, config, giftId, giftNum, totalGoldNum, sendGiftTime);
}
}

View File

@@ -0,0 +1,207 @@
package com.accompany.business.valentine.service;
import com.accompany.business.base.service.BaseCpRankActService;
import com.accompany.business.common.constant.CpRankTypeEnum;
import com.accompany.business.common.constant.RewardTypeEnum;
import com.accompany.business.common.dto.CpRankActConfigDto;
import com.accompany.business.common.dto.CpRankActCpProp;
import com.accompany.business.common.dto.RewardDto;
import com.accompany.business.common.vo.ActivityCpRankVo;
import com.accompany.business.common.vo.ActivityStageTaskItemVo;
import com.accompany.business.common.vo.RewardVo;
import com.accompany.business.core.utils.RewardUtil;
import com.accompany.business.service.dress.UserChatBubbleService;
import com.accompany.business.service.headwear.HeadwearService;
import com.accompany.business.service.user.UsersService;
import com.accompany.business.valentine.ValentinesCpDao;
import com.accompany.business.valentine.constant.ValentinesConstant;
import com.accompany.business.valentine.vo.ValentinesCpRankVo;
import com.accompany.common.constant.Constant;
import com.accompany.common.status.BusiStatus;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Users;
import com.accompany.core.service.SysConfService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
@Service
@Slf4j
public class ValentinesCpRankService extends BaseCpRankActService<ValentinesCpUsersRankObjectProvider> {
@Autowired
private SysConfService sysConfService;
@Autowired
private ValentinesCpDao cpDao;
@Autowired
private RewardUtil rewardUtil;
@Autowired
private UsersService usersService;
@Autowired
private HeadwearService headwearService;
@Autowired
private UserChatBubbleService userChatBubbleService;
private final String MODULE_NAME = "cp";
@Override
public String getActName() {
return ValentinesConstant.actName + "_" + MODULE_NAME;
}
@Override
public String addAndGetCpUid(CpRankActConfigDto config, Long fromUid, Long toUid, Integer giftId, Integer giftNum, Long totalGoldNum, Date sendGiftTime) {
if (null == fromUid || null == toUid || fromUid.equals(toUid)){
throw new ServiceException(BusiStatus.PARAMERROR);
}
String cpUid = cpDao.buildCpUid(fromUid, toUid);
CpRankActCpProp cpProp = cpDao.getCpPropByCpUid(cpUid);
if (null != cpProp){
return cpUid;
}
//任何礼物都行
// if (CollectionUtils.isEmpty(config.getCpGiftIds())
// || !config.getCpGiftIds().contains(giftId)) {
// return null;
// }
cpProp = new CpRankActCpProp();
cpProp.setCpUid(cpUid);
cpProp.setFromUid(fromUid);
cpProp.setToUid(toUid);
cpProp.setScore(0L);
cpProp.setCreateTime(sendGiftTime);
cpDao.saveCpProp(cpProp, config);
log.info("[2024情人节活动]-cp榜 fromUid {} toUid {} 组成cp {}", fromUid, toUid, cpUid);
return cpUid;
}
@Override
public List<Long> takeApartCpUid(String cpUid) {
return cpDao.takeApartCpUid(cpUid);
}
@Override
protected void afterUpdateTotalRank(String cpUid, Double totalScore, CpRankActConfigDto config) {
Map<Long, List<Integer>> taskMap = cpDao.updateCpScore(cpUid, totalScore, config);
if (CollectionUtils.isEmpty(taskMap)){
return;
}
for (Map.Entry<Long, List<Integer>> entry: taskMap.entrySet()){
Long uid = entry.getKey();
List<Integer> taskIds = entry.getValue();
config.getCpScoreTasks().stream().filter(task->taskIds.contains(task.getId()))
.forEach(task->{
List<RewardVo> rewardList = rewardUtil.sendRewardByUid(uid, task.getRewardList(), rewardSeletor, "[2024情人节活动]");
log.info("[2024情人节活动] {} 达到 {} 分,完成 {} 任务,奖励 {}", uid, totalScore, task.getId(), JSON.toJSONString(rewardList));
RewardVo reward = rewardList.get(0);
if (null == reward){
return;
}
String tip = String.format(ValentinesConstant.cp_tip, task.getScore(), reward.getName());
if (RewardTypeEnum.HEADWEAR.getType().equals(reward.getType())){
headwearService.sendHeadwearSecretaryMessage(uid, tip);
} else if (RewardTypeEnum.CHATBUBBLE.getType().equals(reward.getType())) {
userChatBubbleService.sendChatBubbleSecretaryMessage(uid, tip);
}
});
}
}
private BiFunction<Long, List<RewardDto>, List<RewardDto>> rewardSeletor = (uid, rewardList)->{
Users u = usersService.getUsersByUid(uid);
if (null == u || Constant.SexType.female.equals(u.getGender())){
return Collections.singletonList(rewardList.get(0));
}
return Collections.singletonList(rewardList.get(1));
};
public ValentinesCpRankVo getRank(Long uid) {
List<CpRankActCpProp> cpUserPropList = cpDao.listCpByUid(uid, 10L);
List<String> cpUidList = !CollectionUtils.isEmpty(cpUserPropList)?
cpUserPropList.stream()
.sorted(Comparator.comparing(CpRankActCpProp::getScore).reversed())
.map(CpRankActCpProp::getCpUid)
.collect(Collectors.toList()):
Collections.emptyList();
ActivityCpRankVo rankVo = super.getRank(cpUidList, CpRankTypeEnum.TOTAL, null, 15);
Long score = cpDao.getTheMaxScoreByUid(uid);
List<ActivityStageTaskItemVo> taskItemVos = getConfig().getCpScoreTasks().stream().map(task->{
ActivityStageTaskItemVo vo = new ActivityStageTaskItemVo();
vo.setTaskId(task.getId());
vo.setScore(task.getScore());
vo.setStatus(score.compareTo(task.getScore()) >= 0?
ValentinesConstant.BtnStatus.HAD:
ValentinesConstant.BtnStatus.NONE);
return vo;
}).collect(Collectors.toList());
ValentinesCpRankVo vo = new ValentinesCpRankVo();
BeanUtils.copyProperties(rankVo, vo);
vo.setScore(score);
vo.setUid(uid);
vo.setCpTaskList(taskItemVos);
return vo;
}
@Override
protected void logUpdateRank(String cpUid, Integer giftId, Integer giftNum, Long totalGoldNum, Double score) {
log.info("[2024情人节活动]-cp榜 {} 收礼 {} {} 个总价值 {} 钻石,增加值 {}", cpUid, giftId, giftNum, totalGoldNum, score);
}
@Override
protected void logRankReward(CpRankTypeEnum rankType, String date, String rankKey, Integer rankIndex, Long uid, RewardVo reward) {
log.info("[2024情人节活动]-cp榜 {} 发奖励, 第 {} 名 {} 奖励 {}", rankKey, rankIndex, uid, JSON.toJSONString(reward));
}
@Override
public List<RewardDto> listRewardConfig(Long uid, List<RewardDto> rewards) {
Users u = usersService.getUsersByUid(uid);
if (u == null || Constant.SexType.female.equals(u.getGender())){
return getOddOrEvenIndexList(rewards, false);
} else if (Constant.SexType.male.equals(u.getGender())) {
return getOddOrEvenIndexList(rewards, true);
}
return super.listRewardConfig(uid, rewards);
}
public List<RewardDto> getOddOrEvenIndexList(List<RewardDto> list, boolean isOdd) {
List<RewardDto> result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (isOdd && i % 2 != 0) {
result.add(list.get(i));
} else if (!isOdd && i % 2 == 0) {
result.add(list.get(i));
}
}
return result;
}
@Override
public CpRankActConfigDto getRankActConfig() {
return getConfig();
}
public CpRankActConfigDto getConfig(){
String configStr = sysConfService.getSysConfValueById(ValentinesConstant.SysConfId.ACT_RANK_CONFIG);
if (!StringUtils.hasText(configStr)){
throw new ServiceException(BusiStatus.ALREADY_NOTEXISTS_CONFIG);
}
return JSON.parseObject(configStr, CpRankActConfigDto.class);
}
}

View File

@@ -0,0 +1,116 @@
package com.accompany.business.valentine.service;
import com.accompany.business.base.rankobj.CpRankObject;
import com.accompany.business.base.rankobj.CpRankObjectProvider;
import com.accompany.business.common.dto.CpRankActCpProp;
import com.accompany.business.service.user.UsersService;
import com.accompany.business.valentine.ValentinesCpDao;
import com.accompany.core.model.Users;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class ValentinesCpUsersRankObjectProvider implements CpRankObjectProvider {
@Autowired
private ValentinesCpDao cpDao;
@Autowired
private UsersService usersService;
@Override
public Map<String, CpRankObject> mapRankObjectByUids(List<String> cpUidList) {
Map<String, CpRankObject> map = new HashMap<>();
Map<String, CpRankActCpProp> cpPropMap = cpDao.mapCpPropByCpUidSet(new HashSet<>(cpUidList));
List<Long> uidList = cpUidList.stream()
.map(cpUid->cpUid.split("_"))
.flatMap(Arrays::stream)
.map(Long::parseLong)
.distinct().collect(Collectors.toList());
Map<Long, Users> userMap = usersService.getUsersMapByUids(uidList);
for (String cpUid: cpUidList) {
CpRankObject obj = new CpRankObject();
obj.setType(CpRankObject.CpRankObjectType.CP_USER);
obj.setCpUid(cpUid);
String[] uidArray = cpUid.split("_");
Long leftUid = Long.parseLong(uidArray[0]);
Long rightUid = Long.parseLong(uidArray[1]);
CpRankActCpProp cpProp = cpPropMap.get(cpUid);
if (null != cpProp){
leftUid = cpProp.getFromUid();
rightUid = cpProp.getToUid();
}
obj.setLeftUid(leftUid);
Users leftUser = userMap.get(leftUid);
if (null != leftUser){
obj.setLeftErbanNo(leftUser.getErbanNo());
obj.setLeftNick(leftUser.getNick());
obj.setLeftAvatar(leftUser.getAvatar());
}
obj.setRightUid(rightUid);
Users rightUser = userMap.get(rightUid);
if (null != rightUser){
obj.setRightErbanNo(rightUser.getErbanNo());
obj.setRightNick(rightUser.getNick());
obj.setRightAvatar(rightUser.getAvatar());
}
map.put(cpUid, obj);
}
return map;
}
@Override
public CpRankObject getRankObjectByUid(String cpUid) {
if (StringUtils.isBlank(cpUid)){
return null;
}
List<Long> uidList = Arrays.stream(cpUid.split("_"))
.map(Long::parseLong)
.distinct().collect(Collectors.toList());
Map<Long, Users> userMap = usersService.getUsersMapByUids(uidList);
CpRankObject obj = new CpRankObject();
obj.setType(CpRankObject.CpRankObjectType.CP_USER);
obj.setCpUid(cpUid);
String[] uidArray = cpUid.split("_");
Long leftUid = Long.parseLong(uidArray[0]);
obj.setLeftUid(leftUid);
Users leftUser = userMap.get(leftUid);
if (null != leftUser){
obj.setLeftErbanNo(leftUser.getErbanNo());
obj.setLeftNick(leftUser.getNick());
obj.setLeftAvatar(leftUser.getAvatar());
}
Long rightUid = Long.parseLong(uidArray[1]);
obj.setRightUid(rightUid);
Users rightUser = userMap.get(rightUid);
if (null != rightUser){
obj.setRightErbanNo(rightUser.getErbanNo());
obj.setRightNick(rightUser.getNick());
obj.setRightAvatar(rightUser.getAvatar());
}
return obj;
}
}

View File

@@ -17,6 +17,11 @@
<artifactId>festival-activity-service</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.accompany</groupId>
<artifactId>fastival-activity-mq</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,48 @@
package com.accompany.business.activity;
import cn.hutool.core.collection.CollectionUtil;
import com.accompany.business.activity.model.ActActivity;
import com.accompany.business.activity.service.ActActivityService;
import com.accompany.common.constant.Constant;
import com.accompany.common.result.BusiResult;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/2/4 14:26
* @description:
*/
@Api(tags = "活动")
@RestController
@RequestMapping("/activity")
public class ActActivityController {
@Autowired
private ActActivityService actActivityService;
/**
* 获取信息
* @param activityCode
* @return
*/
@ApiOperation("获取信息")
@GetMapping("info")
public BusiResult<ActActivity> info(@RequestParam("activityCode") String activityCode) {
List<ActActivity> actActivities = actActivityService.list(Wrappers.<ActActivity>lambdaQuery()
.eq(ActActivity::getActivityCode, activityCode)
.eq(ActActivity::getActivityStatus, Constant.Yes1No0.YES));
if (CollectionUtil.isNotEmpty(actActivities)) {
return BusiResult.success(actActivities.get(0));
}
return BusiResult.success();
}
}

View File

@@ -0,0 +1,55 @@
package com.accompany.business.activity;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.activity.model.ActUserRecord;
import com.accompany.business.activity.service.ActUserRecordService;
import com.accompany.common.result.BusiResult;
import com.accompany.core.base.UidContextHolder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: liaozetao
* @date: 2024/2/2 19:35
* @description:
*/
@Api(tags = "活动任务记录")
@RestController
@RequestMapping("/activity/task/user/record")
public class ActUserRecordController {
@Autowired
private ActUserRecordService actUserRecordService;
/**
* 活动记录
*
* @param activityCode
* @param taskCode
* @param pageNum
* @param pageSize
* @return
*/
@ApiOperation("活动记录")
@GetMapping("page")
public BusiResult<IPage<ActUserRecord>> page(@RequestParam(value = "activityCode") String activityCode,
@RequestParam(value = "componentCode", required = false) String componentCode,
@RequestParam(value = "taskCode", required = false) String taskCode,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "30") Integer pageSize) {
return BusiResult.success(actUserRecordService.page(new Page<>(pageNum, pageSize), Wrappers.<ActUserRecord>lambdaQuery()
.eq(ActUserRecord::getActivityCode, activityCode)
.eq(StrUtil.isNotEmpty(componentCode), ActUserRecord::getComponentCode, componentCode)
.eq(StrUtil.isNotEmpty(taskCode), ActUserRecord::getTaskCode, taskCode)
.eq(ActUserRecord::getUid, UidContextHolder.get())
.orderByDesc(ActUserRecord::getCreateTime)));
}
}

View File

@@ -0,0 +1,51 @@
package com.accompany.business.activity;
import com.accompany.business.activity.service.ActUserTaskService;
import com.accompany.business.activity.vo.ActivityTask;
import com.accompany.common.result.BusiResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author: liaozetao
* @date: 2024/2/1 11:16
* @description:
*/
@Api(tags = "活动任务")
@RestController
@RequestMapping("/activity/task")
public class ActivityTaskController {
@Autowired
private ActUserTaskService actUserTaskService;
/**
* 用户任务
* @param componentCode
* @return
*/
@ApiOperation("用户任务")
@GetMapping("/user")
public BusiResult<List<ActivityTask>> getActUserTask(@RequestParam("componentCode") String componentCode) {
return BusiResult.success(actUserTaskService.getActivityTasks(componentCode));
}
/**
* 兑换
* @param taskCode
* @param diamondNum
* @param num
* @return
*/
@ApiOperation("兑换")
@PostMapping("/exchange")
public BusiResult<Void> exchange(@RequestParam("activityCode") String activityCode, @RequestParam("taskCode") String taskCode, @RequestParam("diamondNum") Integer diamondNum, @RequestParam("num") Integer num) {
actUserTaskService.exchange(activityCode, taskCode, diamondNum, num);
return BusiResult.success();
}
}

View File

@@ -0,0 +1,62 @@
package com.accompany.business.valentines;
import com.accompany.business.valentine.service.ValentinesCpRankService;
import com.accompany.business.valentine.vo.ValentinesCpRankVo;
import com.accompany.common.annotation.Authorization;
import com.accompany.common.constant.ApplicationConstant;
import com.accompany.common.result.BusiResult;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.exception.ServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
@Api(tags = "2024情人节活动",value = "2024情人节活动")
@RequestMapping("/act/2024Valentines/cpRank")
@RestController
public class ValentinesCpRankController {
@Autowired
private ValentinesCpRankService service;
@ApiOperation("cp排行榜")
@GetMapping("/getRank")
@Authorization
public BusiResult<ValentinesCpRankVo> getRank(HttpServletRequest request){
String uidStr = request.getHeader(ApplicationConstant.PublicParameters.PUB_UID);
Long uid = Long.parseLong(uidStr);
ValentinesCpRankVo rankVo = service.getRank(uid);
return new BusiResult<>(rankVo);
}
@ApiOperation("结算")
@ApiImplicitParams({
@ApiImplicitParam(name = "date", value = "结算日期", required = true)
})
@PostMapping("/settlement")
public BusiResult<Void> settlement(String date, Boolean needFlag){
if (!StringUtils.hasText(date)){
throw new ServiceException(BusiStatus.PARAMERROR);
}
Date time = DateTimeUtil.convertStrToDate(date, DateTimeUtil.DEFAULT_DATE_PATTERN);
LocalDateTime dateTime = DateTimeUtil.converDateToLocalDateTime(time);
if (null == needFlag){
needFlag = true;
}
service.settlement(dateTime, needFlag);
return new BusiResult<>(BusiStatus.SUCCESS);
}
}

View File

@@ -18,6 +18,7 @@
<module>festival-activity-service</module>
<module>festival-activity-web</module>
<module>festival-activity-scheduler</module>
<module>fastival-activity-mq</module>
</modules>
<properties>

View File

@@ -42,4 +42,12 @@ public interface MqConstant {
String CHARGE_CONSUME_GROUP = "charge_consume_group";
String ACT_USER_TASK_TOPIC = "act_user_task_topic";
String ACT_USER_TASK_CONSUME_GROUP = "act_user_task_consume_group";
String ACT_TASK_REWARD_TOPIC = "act_task_reward_topic";
String ACT_TASK_REWARD_CONSUME_GROUP = "act_task_reward_consume_group";
}

View File

@@ -0,0 +1,17 @@
package com.accompany.mq.model;
import lombok.Data;
/**
* @author: liaozetao
* @date: 2024/2/5 11:57
* @description:
*/
@Data
public class ActTaskRewardMqMessage extends BaseMqMessage {
/**
* 用户任务ID
*/
private Long userTaskId;
}

View File

@@ -0,0 +1,42 @@
package com.accompany.mq.model;
import lombok.Data;
/**
* @author: liaozetao
* @date: 2024/1/31 11:43
* @description:
*/
@Data
public class ActUserTaskMqMessage extends BaseMqMessage {
/**
* 房间UID
*/
private Long roomUid;
/**
* 送礼用户UID
*/
private Long sendUid;
/**
* 收礼用户UID
*/
private Long receiveUid;
/**
* 礼物ID
*/
private Integer giftId;
/**
* 礼物值
*/
private Long giftValue;
/**
* 消息时间
*/
private Long messTime;
}

View File

@@ -3,6 +3,7 @@ package com.accompany.mq.listener;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.accompany.common.redis.RedisKey;
import com.accompany.core.service.common.JedisLockService;
import com.accompany.core.service.common.JedisService;
import com.accompany.mq.model.BaseMqMessage;
import com.google.gson.internal.$Gson$Types;
@@ -26,6 +27,9 @@ public abstract class AbstractMessageListener<T extends BaseMqMessage> implement
@Autowired
protected JedisService jedisService;
@Autowired
protected JedisLockService jedisLockService;
@Override
public void onMessage(String message) {
try {