|
|
@@ -1,8 +1,7 @@ |
|
|
|
package com.hz.pm.api.meeting.task; |
|
|
|
|
|
|
|
import cn.hutool.core.util.ArrayUtil; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.Wrapper; |
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
|
|
import com.hz.pm.api.common.util.SpringContextHolder; |
|
|
|
import com.hz.pm.api.meeting.builder.ExpertInviteBuilder; |
|
|
@@ -37,7 +36,11 @@ import org.springframework.util.Assert; |
|
|
|
|
|
|
|
import javax.annotation.PostConstruct; |
|
|
|
import javax.annotation.Resource; |
|
|
|
import java.time.*; |
|
|
|
import java.time.Duration; |
|
|
|
import java.time.Instant; |
|
|
|
import java.time.LocalDateTime; |
|
|
|
import java.time.LocalTime; |
|
|
|
import java.time.temporal.ChronoUnit; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
@@ -72,19 +75,43 @@ public class ExpertRandomInviteTask { |
|
|
|
private final IExpertInviteRuleService inviteRuleService; |
|
|
|
private final IMeetingService meetingService; |
|
|
|
private final ExpertInviteManage expertInviteManage; |
|
|
|
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; |
|
|
|
private final IExpertInviteAvoidRuleService avoidRuleService; |
|
|
|
private final MeetingNotifyHelper meetingNotifyHelper; |
|
|
|
private final MeetingSettingsManage meetingSettingsManage; |
|
|
|
|
|
|
|
/** |
|
|
|
* 用来存入线程执行句柄, 停止定时任务时使用 |
|
|
|
*/ |
|
|
|
private static final ConcurrentMap<Long, ScheduledFuture<?>> INVITE_TASK_MAP = new ConcurrentHashMap<>(); |
|
|
|
|
|
|
|
private CacheHashKey getCacheKey(Long meetingId) { |
|
|
|
//================================================================================================================== |
|
|
|
|
|
|
|
@PostConstruct |
|
|
|
public void initTask() { |
|
|
|
if (Boolean.FALSE.equals(properties.getEnable())) { |
|
|
|
log.warn("随机邀请已关闭"); |
|
|
|
return; |
|
|
|
} |
|
|
|
initInviteTaskAfterStarted(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 构建会议缓存key |
|
|
|
* |
|
|
|
* @param meetingId 会议ID |
|
|
|
* @return 缓存key |
|
|
|
*/ |
|
|
|
@SuppressWarnings("all") |
|
|
|
private static CacheHashKey cacheKey(Long meetingId) { |
|
|
|
String field = meetingId == null ? null : meetingId.toString(); |
|
|
|
return new CacheHashKey(MEETING_ID_INVITE_RANDOM, field, EXPIRE_TIME); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 校验是否在专家抽取任务执行时间之内 |
|
|
|
* |
|
|
|
* @return \ |
|
|
|
*/ |
|
|
|
private boolean inInviteTimeRange() { |
|
|
|
MeetingSettingsSaveReq settings = meetingSettingsManage.getSettings(MeetingSettingsTypeEnum.INVITE_CALL_IGNORE_TIME); |
|
|
|
LocalTime currTime = LocalTime.now(); |
|
|
@@ -97,20 +124,11 @@ public class ExpertRandomInviteTask { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@PostConstruct |
|
|
|
public void initTask() { |
|
|
|
if (Boolean.FALSE.equals(properties.getEnable())) { |
|
|
|
log.warn("随机邀请已关闭……"); |
|
|
|
return; |
|
|
|
} |
|
|
|
initInviteTaskAfterStarted(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 项目重启之后重新初始化邀请任务 |
|
|
|
*/ |
|
|
|
private void initInviteTaskAfterStarted() { |
|
|
|
Map<Long, InviteCacheDTO> caches = cachePlusOps.hGetAll(getCacheKey(null)); |
|
|
|
Map<Long, InviteCacheDTO> caches = cachePlusOps.hGetAll(cacheKey(null)); |
|
|
|
if (MapUtils.isEmpty(caches)) { |
|
|
|
log.info("暂无需要初始化的抽取会议信息"); |
|
|
|
return; |
|
|
@@ -121,7 +139,7 @@ public class ExpertRandomInviteTask { |
|
|
|
LocalDateTime tsTime = cache.getTaskStartTime(); |
|
|
|
boolean added = addInviteTask(cache.getMeetingId(), true, inviteDelay, reInvite, tsTime); |
|
|
|
if (!added) { |
|
|
|
cachePlusOps.hDel(getCacheKey(cache.getMeetingId())); |
|
|
|
cachePlusOps.hDel(cacheKey(cache.getMeetingId())); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -138,7 +156,7 @@ public class ExpertRandomInviteTask { |
|
|
|
if (ruleMap.isEmpty()) { |
|
|
|
return Boolean.FALSE; |
|
|
|
} |
|
|
|
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) |
|
|
|
Wrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) |
|
|
|
.select(MeetingExpert::getRuleId, MeetingExpert::getStatus) |
|
|
|
.in(MeetingExpert::getRuleId, ruleMap.keySet()) |
|
|
|
.eq(MeetingExpert::getStatus, ExpertAttendStatusEnum.AGREED.getCode()); |
|
|
@@ -165,41 +183,44 @@ public class ExpertRandomInviteTask { |
|
|
|
**/ |
|
|
|
public void notifyInviteTask(Long meetingId, boolean... reInvite) { |
|
|
|
boolean tmpReInvite = ArrayUtil.isEmpty(reInvite) || reInvite[0]; |
|
|
|
if (!INVITE_TASK_MAP.containsKey(meetingId)) { |
|
|
|
if (addInviteTask(meetingId, false, properties.getInviteDelay(), tmpReInvite, LocalDateTime.now())) { |
|
|
|
log.info("重置会议的随机抽取状态:{}", meetingId); |
|
|
|
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); |
|
|
|
update.set(Meeting::getInviteStatus, false); |
|
|
|
update.eq(Meeting::getId, meetingId); |
|
|
|
meetingService.update(update); |
|
|
|
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, tmpReInvite, LocalDateTime.now()); |
|
|
|
cachePlusOps.hSet(getCacheKey(meetingId), cacheVal); |
|
|
|
} |
|
|
|
if (INVITE_TASK_MAP.containsKey(meetingId)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
LocalDateTime now = LocalDateTime.now(); |
|
|
|
if (addInviteTask(meetingId, false, properties.getInviteDelay(), tmpReInvite, now)) { |
|
|
|
log.info("重置会议的随机抽取状态:{}", meetingId); |
|
|
|
Wrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class) |
|
|
|
.set(Meeting::getInviteStatus, false) |
|
|
|
.eq(Meeting::getId, meetingId); |
|
|
|
meetingService.update(update); |
|
|
|
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, tmpReInvite, now); |
|
|
|
cachePlusOps.hSet(cacheKey(meetingId), cacheVal); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 添加专家抽取校验任务 |
|
|
|
* |
|
|
|
* @param meetingId 会议ID |
|
|
|
* @param checked 是否前置校验 |
|
|
|
* @param delayTime 延迟执行时间 |
|
|
|
* @param reInvite 是否可以邀请被拒绝的专家 |
|
|
|
* @param tsTime 任务启动时间 |
|
|
|
* @param meetingId 会议ID |
|
|
|
* @param checked 是否前置校验 |
|
|
|
* @param delayTime 延迟执行时间 |
|
|
|
* @param reInvite 是否可以邀请被拒绝的专家 |
|
|
|
* @param taskStataTime 任务启动时间 |
|
|
|
* @return 是否添加任务成功 |
|
|
|
* @author WendyYang |
|
|
|
**/ |
|
|
|
private boolean addInviteTask(Long meetingId, boolean checked, int delayTime, boolean reInvite, LocalDateTime tsTime) { |
|
|
|
private boolean addInviteTask(Long meetingId, boolean checked, int delayTime, |
|
|
|
boolean reInvite, LocalDateTime taskStataTime) { |
|
|
|
if (checked && !inviteCountCheck(meetingId)) { |
|
|
|
// 如果抽取数量满足直接返回 |
|
|
|
return Boolean.FALSE; |
|
|
|
} |
|
|
|
Instant startTime = LocalDateTime.now().plusMinutes(delayTime).atZone(ZoneId.systemDefault()).toInstant(); |
|
|
|
Instant startTime = Instant.now().plus(delayTime, ChronoUnit.MINUTES); |
|
|
|
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> { |
|
|
|
ExpertRandomInviteTask bean = SpringContextHolder.getBean(ExpertRandomInviteTask.class); |
|
|
|
try { |
|
|
|
// 抽取专家 |
|
|
|
bean.invite(meetingId, reInvite, tsTime); |
|
|
|
bean.invite(meetingId, reInvite, taskStataTime); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("执行专家邀请任务异常:{}", meetingId, e); |
|
|
|
} |
|
|
@@ -212,15 +233,15 @@ public class ExpertRandomInviteTask { |
|
|
|
/** |
|
|
|
* 创建会议时添加抽取任务 |
|
|
|
* |
|
|
|
* @param meetingId 会议ID |
|
|
|
* @param tsTime 开始时间 |
|
|
|
* @param meetingId 会议ID |
|
|
|
* @param taskStartTime 开始时间 |
|
|
|
* @author WendyYang |
|
|
|
**/ |
|
|
|
public void addInviteTaskByMeetingCreate(Long meetingId, LocalDateTime tsTime) { |
|
|
|
public void addInviteTaskByMeetingCreate(Long meetingId, LocalDateTime taskStartTime) { |
|
|
|
Assert.isTrue(properties.getEnable(), "随机邀请已关闭"); |
|
|
|
addInviteTask(meetingId, false, properties.getInviteDelay(), false, tsTime); |
|
|
|
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, false, tsTime); |
|
|
|
cachePlusOps.hSet(getCacheKey(meetingId), cacheVal); |
|
|
|
addInviteTask(meetingId, false, properties.getInviteDelay(), false, taskStartTime); |
|
|
|
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, false, taskStartTime); |
|
|
|
cachePlusOps.hSet(cacheKey(meetingId), cacheVal); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -247,7 +268,7 @@ public class ExpertRandomInviteTask { |
|
|
|
// 随机邀请规则 |
|
|
|
Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); |
|
|
|
// 回避规则 |
|
|
|
AvoidRuleDTO avoidRule = inviteAvoidRuleService.getAvoidInfo(meetingId); |
|
|
|
AvoidRuleDTO avoidRule = avoidRuleService.getAvoidInfo(meetingId); |
|
|
|
// 还需要抽取的规则数量 |
|
|
|
AtomicInteger notIgnoreCnt = new AtomicInteger(ruleMap.size()); |
|
|
|
AtomicInteger notSupportCnt = new AtomicInteger(0); |
|
|
@@ -304,7 +325,7 @@ public class ExpertRandomInviteTask { |
|
|
|
} |
|
|
|
|
|
|
|
private void killTaskAndDelCacheMeetingId(Long meetingId) { |
|
|
|
cachePlusOps.hDel(getCacheKey(meetingId)); |
|
|
|
cachePlusOps.hDel(cacheKey(meetingId)); |
|
|
|
ScheduledFuture<?> future = INVITE_TASK_MAP.get(meetingId); |
|
|
|
if (future != null) { |
|
|
|
INVITE_TASK_MAP.remove(meetingId); |
|
|
|