@@ -39,6 +39,13 @@ public class MeetingController { | |||||
return meetingManage.meetingCreateAndInviteExpert(req); | return meetingManage.meetingCreateAndInviteExpert(req); | ||||
} | } | ||||
@PostMapping("/continueInvite") | |||||
@ApiOperation(value = "续抽专家") | |||||
@WebLog(value = "续抽专家") | |||||
public void continueInvite(@Valid @RequestBody MeetingIdReq req) { | |||||
meetingManage.continueInvite(req.getMeetingId()); | |||||
} | |||||
@PostMapping("/expertInviteByCreate") | @PostMapping("/expertInviteByCreate") | ||||
@ApiOperation(value = "新建会议-专家抽取", hidden = true) | @ApiOperation(value = "新建会议-专家抽取", hidden = true) | ||||
@WebLog(value = "新建会议-专家抽取") | @WebLog(value = "新建会议-专家抽取") | ||||
@@ -94,13 +101,6 @@ public class MeetingController { | |||||
return meetingManage.inviteRuleDetail(meetingId); | return meetingManage.inviteRuleDetail(meetingId); | ||||
} | } | ||||
@ApiOperation("专家替换") | |||||
@PostMapping("/expertReplace") | |||||
@WebLog(value = "专家替换") | |||||
public void expertReplace(@RequestBody ExpertRemoveReq po) { | |||||
meetingManage.expertReplace(po); | |||||
} | |||||
@ApiOperation("停止抽取") | @ApiOperation("停止抽取") | ||||
@GetMapping("/stopInvite/{meetingId}") | @GetMapping("/stopInvite/{meetingId}") | ||||
@WebLog(value = "停止抽取") | @WebLog(value = "停止抽取") | ||||
@@ -55,11 +55,6 @@ public class MeetingExpert implements Serializable { | |||||
@ApiModelProperty("是否是专家组长") | @ApiModelProperty("是否是专家组长") | ||||
private Boolean isHeadman; | private Boolean isHeadman; | ||||
@ApiModelProperty("前一个状态") | |||||
private Integer preStatus; | |||||
private Long preId; | |||||
@ApiModelProperty("邀请类型") | @ApiModelProperty("邀请类型") | ||||
private Integer inviteType; | private Integer inviteType; | ||||
@@ -5,7 +5,6 @@ import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | import lombok.Data; | ||||
import javax.validation.constraints.NotEmpty; | import javax.validation.constraints.NotEmpty; | ||||
import javax.validation.constraints.NotNull; | |||||
import java.util.List; | import java.util.List; | ||||
/** | /** | ||||
@@ -18,7 +17,7 @@ import java.util.List; | |||||
*/ | */ | ||||
@Data | @Data | ||||
@ApiModel("回避信息") | @ApiModel("回避信息") | ||||
public class AvoidInfoDTO { | |||||
public class AvoidRuleDTO { | |||||
@ApiModelProperty("回避单位") | @ApiModelProperty("回避单位") | ||||
@NotEmpty(message = "回避单位不能为空", groups = {AbstractInviteRule.RuleSave.class}) | @NotEmpty(message = "回避单位不能为空", groups = {AbstractInviteRule.RuleSave.class}) |
@@ -0,0 +1,27 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* MeetingInviteDTO | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 19:21 2023/3/7 | |||||
*/ | |||||
@Data | |||||
public final class MeetingInviteCacheDTO { | |||||
private Long meetingId; | |||||
private Boolean invitedRefused; | |||||
public static MeetingInviteCacheDTO of(Long meetingId, Boolean invitedRefused) { | |||||
MeetingInviteCacheDTO bo = new MeetingInviteCacheDTO(); | |||||
bo.setMeetingId(meetingId); | |||||
bo.setInvitedRefused(invitedRefused); | |||||
return bo; | |||||
} | |||||
} |
@@ -1,7 +1,7 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | package com.ningdatech.pmapi.meeting.entity.req; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | ||||
import io.swagger.annotations.ApiModel; | import io.swagger.annotations.ApiModel; | ||||
import io.swagger.annotations.ApiModelProperty; | import io.swagger.annotations.ApiModelProperty; | ||||
@@ -33,7 +33,7 @@ public class ExpertInviteReq { | |||||
@Valid | @Valid | ||||
@NotNull(message = "回避信息不能为空") | @NotNull(message = "回避信息不能为空") | ||||
@ApiModelProperty("回避信息") | @ApiModelProperty("回避信息") | ||||
private AvoidInfoDTO avoidRule; | |||||
private AvoidRuleDTO avoidRule; | |||||
@Valid | @Valid | ||||
@ApiModelProperty("随机抽取规则") | @ApiModelProperty("随机抽取规则") | ||||
@@ -0,0 +1,20 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* MeetingIdReq | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 17:10 2023/3/7 | |||||
*/ | |||||
@Data | |||||
public class MeetingIdReq { | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
} |
@@ -11,7 +11,7 @@ import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AbstractInviteRule; | import com.ningdatech.pmapi.meeting.entity.dto.AbstractInviteRule; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | ||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | ||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | import com.ningdatech.pmapi.meeting.service.IMeetingService; | ||||
@@ -69,7 +69,7 @@ public class ExpertInviteHelper { | |||||
return new HashSet<>(listInvitedExpertByTime(start, end)); | return new HashSet<>(listInvitedExpertByTime(start, end)); | ||||
} | } | ||||
public Set<Long> getAvoidExpert(List<Long> appoints, AvoidInfoDTO avoid, LocalDateTime start, LocalDateTime end) { | |||||
public Set<Long> getAvoidExpert(List<Long> appoints, AvoidRuleDTO avoid, LocalDateTime start, LocalDateTime end) { | |||||
Set<Long> expertIds = new HashSet<>(); | Set<Long> expertIds = new HashSet<>(); | ||||
Optional.ofNullable(appoints).ifPresent(expertIds::addAll); | Optional.ofNullable(appoints).ifPresent(expertIds::addAll); | ||||
Optional.ofNullable(avoid) | Optional.ofNullable(avoid) | ||||
@@ -1,5 +1,6 @@ | |||||
package com.ningdatech.pmapi.meeting.helper; | package com.ningdatech.pmapi.meeting.helper; | ||||
import cn.hutool.core.collection.CollUtil; | |||||
import cn.hutool.core.lang.Assert; | import cn.hutool.core.lang.Assert; | ||||
import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
@@ -14,9 +15,10 @@ import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO; | import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingBasicDTO; | import com.ningdatech.pmapi.meeting.entity.dto.MeetingBasicDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | ||||
import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq; | import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq; | ||||
import com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVO; | import com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVO; | ||||
@@ -30,7 +32,10 @@ import lombok.AllArgsConstructor; | |||||
import org.apache.commons.collections4.CollectionUtils; | import org.apache.commons.collections4.CollectionUtils; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import java.util.*; | |||||
import java.util.Collection; | |||||
import java.util.Comparator; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
@@ -60,6 +65,36 @@ public class MeetingManageHelper { | |||||
} | } | ||||
/** | /** | ||||
* 校验会议是否还可继续抽取 | |||||
*/ | |||||
public boolean checkCouldBeInvitedContinue(Long meetingId) { | |||||
Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); | |||||
List<MeetingExpert> experts = meetingExpertService.listExpertLastByMeetingId(meetingId); | |||||
if (experts.isEmpty()) { | |||||
return Boolean.TRUE; | |||||
} | |||||
Map<Long, List<MeetingExpert>> expertMap = CollUtils.group(experts, MeetingExpert::getRuleId); | |||||
for (Map.Entry<Long, RandomInviteRuleDTO> entry : ruleMap.entrySet()) { | |||||
List<MeetingExpert> tmpExperts = expertMap.get(entry.getKey()); | |||||
if (CollUtil.isEmpty(tmpExperts)) { | |||||
return Boolean.TRUE; | |||||
} | |||||
int count = 0; | |||||
for (MeetingExpert w : tmpExperts) { | |||||
boolean status = ExpertAttendStatusEnum.AGREED.eq(w.getStatus()) || | |||||
ExpertAttendStatusEnum.NOTICING.eq(w.getStatus()); | |||||
if (status) { | |||||
count++; | |||||
} | |||||
} | |||||
if (count < entry.getValue().getCount()) { | |||||
return Boolean.TRUE; | |||||
} | |||||
} | |||||
return Boolean.FALSE; | |||||
} | |||||
/** | |||||
* 获取专家出席会议的状态 | * 获取专家出席会议的状态 | ||||
* | * | ||||
* @param info 会议状态及评价信息 | * @param info 会议状态及评价信息 | ||||
@@ -104,7 +139,7 @@ public class MeetingManageHelper { | |||||
query.and(q1 -> q1.exists("select 1 from nd_project np inner join meeting_inner_project mip on mip.project_id = np.id" + | query.and(q1 -> q1.exists("select 1 from nd_project np inner join meeting_inner_project mip on mip.project_id = np.id" + | ||||
" where mip.meeting_id = meeting.id and np.project_name like {0}", projectName) | " where mip.meeting_id = meeting.id and np.project_name like {0}", projectName) | ||||
.or(q2 -> q2.exists("select 1 from meeting_outer_project mop where mop.meeting_id = meeting.id" + | .or(q2 -> q2.exists("select 1 from meeting_outer_project mop where mop.meeting_id = meeting.id" + | ||||
"and mop.project_name like {0}", projectName))); | |||||
" and mop.project_name like {0}", projectName))); | |||||
} | } | ||||
} | } | ||||
@@ -140,9 +175,9 @@ public class MeetingManageHelper { | |||||
return null; | return null; | ||||
} | } | ||||
public AvoidInfoDTO getAvoidInfoDto(Long meetingId) { | |||||
public AvoidRuleDTO getAvoidInfoDto(Long meetingId) { | |||||
ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId); | ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId); | ||||
AvoidInfoDTO result = new AvoidInfoDTO(); | |||||
AvoidRuleDTO result = new AvoidRuleDTO(); | |||||
result.setAvoidOrgIdList(StrUtil.split(avoidRule.getAvoidOrgIds(), ",")); | result.setAvoidOrgIdList(StrUtil.split(avoidRule.getAvoidOrgIds(), ",")); | ||||
result.setExpertIds(BizUtils.splitToLong(avoidRule.getAvoidExpertIds())); | result.setExpertIds(BizUtils.splitToLong(avoidRule.getAvoidExpertIds())); | ||||
result.setAvoidUnitIdList(StrUtil.split(avoidRule.getAvoidUnitIds(), ",")); | result.setAvoidUnitIdList(StrUtil.split(avoidRule.getAvoidUnitIds(), ",")); | ||||
@@ -165,7 +200,7 @@ public class MeetingManageHelper { | |||||
**/ | **/ | ||||
public List<ExpertUserFullInfo> appointExpertCheck(Long meetingId, List<Long> expertIds) { | public List<ExpertUserFullInfo> appointExpertCheck(Long meetingId, List<Long> expertIds) { | ||||
List<ExpertUserFullInfo> experts = expertUserFullInfoService.listByUserId(expertIds); | List<ExpertUserFullInfo> experts = expertUserFullInfoService.listByUserId(expertIds); | ||||
AvoidInfoDTO avoidRule = getAvoidInfoDto(meetingId); | |||||
AvoidRuleDTO avoidRule = getAvoidInfoDto(meetingId); | |||||
experts.forEach(expert -> { | experts.forEach(expert -> { | ||||
if (avoidRule.getAvoidUnitIdList().contains(expert.getCompany())) { | if (avoidRule.getAvoidUnitIdList().contains(expert.getCompany())) { | ||||
throw BizException.wrap("请移除已回避单位的专家"); | throw BizException.wrap("请移除已回避单位的专家"); | ||||
@@ -193,16 +228,6 @@ public class MeetingManageHelper { | |||||
throw BizException.wrap("专家%s已拒绝参加", expertName); | throw BizException.wrap("专家%s已拒绝参加", expertName); | ||||
case REMOVED: | case REMOVED: | ||||
throw BizException.wrap("专家%s已被移除", expertName); | throw BizException.wrap("专家%s已被移除", expertName); | ||||
case REPLACED: | |||||
switch (ExpertAttendStatusEnum.getByCode(w.getPreStatus())) { | |||||
case REFUSED: | |||||
throw BizException.wrap("专家%s已拒绝参加", expertName); | |||||
case REMOVED: | |||||
throw BizException.wrap("专家%s已被移除", expertName); | |||||
default: | |||||
break; | |||||
} | |||||
break; | |||||
case AGREED: | case AGREED: | ||||
throw BizException.wrap("专家%s已同意参加", expertName); | throw BizException.wrap("专家%s已同意参加", expertName); | ||||
case NOTICING: | case NOTICING: | ||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
import com.ningdatech.basic.util.CollUtils; | import com.ningdatech.basic.util.CollUtils; | ||||
import com.ningdatech.pmapi.common.util.BizUtils; | import com.ningdatech.pmapi.common.util.BizUtils; | ||||
import com.ningdatech.pmapi.common.util.StrUtils; | |||||
import com.ningdatech.pmapi.expert.constant.ExpertAccountStatusEnum; | import com.ningdatech.pmapi.expert.constant.ExpertAccountStatusEnum; | ||||
import com.ningdatech.pmapi.expert.entity.ExpertAvoidCompany; | import com.ningdatech.pmapi.expert.entity.ExpertAvoidCompany; | ||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | ||||
@@ -15,7 +16,7 @@ import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.ExpertDictChooseDTO; | import com.ningdatech.pmapi.meeting.entity.dto.ExpertDictChooseDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | ||||
@@ -135,7 +136,7 @@ public class ExpertInviteManage { | |||||
return expertAvoidCompanyList.stream().map(ExpertAvoidCompany::getUserId).distinct().collect(Collectors.toList()); | return expertAvoidCompanyList.stream().map(ExpertAvoidCompany::getUserId).distinct().collect(Collectors.toList()); | ||||
} | } | ||||
private List<Long> mergeExpertIdsByCondition(RandomInviteRuleDTO rule, AvoidInfoDTO avoidInfo) { | |||||
private List<Long> mergeExpertIdsByCondition(RandomInviteRuleDTO rule, AvoidRuleDTO avoidInfo) { | |||||
// 处理履职意向地 | // 处理履职意向地 | ||||
List<Long> expertIdsByIntentionRegion = expertIdsByRegion(rule); | List<Long> expertIdsByIntentionRegion = expertIdsByRegion(rule); | ||||
if (COLL_EMPTY.evaluate(expertIdsByIntentionRegion)) { | if (COLL_EMPTY.evaluate(expertIdsByIntentionRegion)) { | ||||
@@ -246,34 +247,31 @@ public class ExpertInviteManage { | |||||
/** | /** | ||||
* 专家抽取(随机) | * 专家抽取(随机) | ||||
* | * | ||||
* @param avoidInfo 回避信息 | |||||
* @param avoidRule 回避信息 | |||||
* @param randomRule 抽取规则 | * @param randomRule 抽取规则 | ||||
* @param appointExpertIds 指定抽取专家ID | * @param appointExpertIds 指定抽取专家ID | ||||
* @return 满足抽取条件的专家 | * @return 满足抽取条件的专家 | ||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
public ExpertChooseDTO expertInviteByRandomRule(AvoidInfoDTO avoidInfo, | |||||
public ExpertChooseDTO expertInviteByRandomRule(AvoidRuleDTO avoidRule, | |||||
RandomInviteRuleDTO randomRule, | RandomInviteRuleDTO randomRule, | ||||
List<Long> appointExpertIds, | List<Long> appointExpertIds, | ||||
LocalDateTime start, | LocalDateTime start, | ||||
LocalDateTime end) { | LocalDateTime end) { | ||||
ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | ||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo); | |||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidRule); | |||||
if (expertIdsIn == null) { | if (expertIdsIn == null) { | ||||
return result; | return result; | ||||
} | } | ||||
boolean avoid = avoidInfo != null; | |||||
boolean avoidExpert = avoid && CollUtil.isNotEmpty(avoidInfo.getExpertIds()); | |||||
boolean avoidCompany = avoid && CollUtil.isNotEmpty(avoidInfo.getAvoidUnitIdList()); | |||||
boolean avoidExpert = CollUtil.isNotEmpty(avoidRule.getExpertIds()); | |||||
boolean avoidCompany = CollUtil.isNotEmpty(avoidRule.getAvoidUnitIdList()); | |||||
Set<String> tmpAvoidCompany = new HashSet<>(); | Set<String> tmpAvoidCompany = new HashSet<>(); | ||||
if (avoidCompany) { | if (avoidCompany) { | ||||
List<String> companyIds = avoidInfo.getAvoidUnitIdList(); | |||||
List<String> companyIds = avoidRule.getAvoidUnitIdList(); | |||||
for (String companyId : companyIds) { | for (String companyId : companyIds) { | ||||
if (companyId.contains(",")) { | if (companyId.contains(",")) { | ||||
String[] splitCompanyIds = companyId.split(","); | String[] splitCompanyIds = companyId.split(","); | ||||
for (String splitCompanyId : splitCompanyIds) { | |||||
tmpAvoidCompany.add(splitCompanyId); | |||||
} | |||||
Collections.addAll(tmpAvoidCompany, splitCompanyIds); | |||||
} else { | } else { | ||||
tmpAvoidCompany.add(companyId); | tmpAvoidCompany.add(companyId); | ||||
} | } | ||||
@@ -284,14 +282,13 @@ public class ExpertInviteManage { | |||||
query.notIn(!tmpAvoidCompany.isEmpty(), ExpertUserFullInfo::getCompany, tmpAvoidCompany); | query.notIn(!tmpAvoidCompany.isEmpty(), ExpertUserFullInfo::getCompany, tmpAvoidCompany); | ||||
if (avoidCompany) { | if (avoidCompany) { | ||||
query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" + | query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" + | ||||
" and company_name in ({0})", CollUtils.joinByComma(avoidInfo.getAvoidUnitIdList())); | |||||
" and company_name in ({0})", CollUtils.joinByComma(avoidRule.getAvoidUnitIdList())); | |||||
} | } | ||||
// 处理专家层级 | // 处理专家层级 | ||||
addRegionLimit(query, randomRule); | addRegionLimit(query, randomRule); | ||||
if (!expertIdsIn.isEmpty()) { | if (!expertIdsIn.isEmpty()) { | ||||
if (avoidExpert) { | if (avoidExpert) { | ||||
expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w)); | |||||
expertIdsIn.removeIf(w -> avoidRule.getExpertIds().contains(w)); | |||||
if (expertIdsIn.isEmpty()) { | if (expertIdsIn.isEmpty()) { | ||||
// 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | // 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | ||||
// 如果为空则说明没有符合条件的 | // 如果为空则说明没有符合条件的 | ||||
@@ -312,7 +309,7 @@ public class ExpertInviteManage { | |||||
} | } | ||||
query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | ||||
} else if (avoidExpert || CollUtil.isNotEmpty(appointExpertIds)) { | } else if (avoidExpert || CollUtil.isNotEmpty(appointExpertIds)) { | ||||
Set<Long> tempExperts = expertInviteHelper.getAvoidExpert(appointExpertIds, avoidInfo, start, end); | |||||
Set<Long> tempExperts = expertInviteHelper.getAvoidExpert(appointExpertIds, avoidRule, start, end); | |||||
query.notIn(ExpertUserFullInfo::getUserId, tempExperts); | query.notIn(ExpertUserFullInfo::getUserId, tempExperts); | ||||
} else { | } else { | ||||
Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | ||||
@@ -320,15 +317,15 @@ public class ExpertInviteManage { | |||||
query.notIn(ExpertUserFullInfo::getUserId, notInUserIds); | query.notIn(ExpertUserFullInfo::getUserId, notInUserIds); | ||||
} | } | ||||
} | } | ||||
List<ExpertUserFullInfo> userFullInfos = expertUserFullInfoService.list(query); | |||||
if (userFullInfos.isEmpty()) { | |||||
List<ExpertUserFullInfo> userInfoList = expertUserFullInfoService.list(query); | |||||
if (userInfoList.isEmpty()) { | |||||
return result; | return result; | ||||
} | } | ||||
result.setTotal(userFullInfos.size()); | |||||
Map<String, List<ExpertUserFullInfo>> userGroupByUnit = CollUtils.group(userInfoList, ExpertUserFullInfo::getCompany); | |||||
result.setTotal(userInfoList.size()); | |||||
// count为空表示数量校验 | // count为空表示数量校验 | ||||
if (randomRule.getCount() == null || result.getTotal() >= randomRule.getCount()) { | if (randomRule.getCount() == null || result.getTotal() >= randomRule.getCount()) { | ||||
List<ExpertUserFullInfo> userFullInfoList = inviteWithoutCompany(userFullInfos, randomRule.getCount()); | |||||
result.setExperts(userFullInfoList); | |||||
result.setExperts(inviteGroupByCompany(userGroupByUnit, randomRule.getCount())); | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
@@ -336,39 +333,41 @@ public class ExpertInviteManage { | |||||
/** | /** | ||||
* 专家替换、补充 | * 专家替换、补充 | ||||
* | * | ||||
* @param avoidInfo 回避信息 | |||||
* @param avoidRule 回避信息 | |||||
* @param randomRule 随机抽取 | * @param randomRule 随机抽取 | ||||
* @param meetingExperts 已抽取人员 | |||||
* @param invitedExperts 已抽取人员 | |||||
* @param count 抽取数量 | * @param count 抽取数量 | ||||
* @return com.ningdatech.emapi.meeting.entity.dto.ExpertChooseDto | |||||
* @param start 会议开始时间 | |||||
* @param end 会议结束时间 | |||||
* @return {@link ExpertChooseDTO} | |||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
public ExpertChooseDTO expertReplaceByRandomRule(AvoidInfoDTO avoidInfo, | |||||
public ExpertChooseDTO expertReplaceByRandomRule(AvoidRuleDTO avoidRule, | |||||
RandomInviteRuleDTO randomRule, | RandomInviteRuleDTO randomRule, | ||||
Collection<MeetingExpert> meetingExperts, | |||||
Collection<MeetingExpert> invitedExperts, | |||||
Integer count, | Integer count, | ||||
LocalDateTime start, | LocalDateTime start, | ||||
LocalDateTime end, | LocalDateTime end, | ||||
Long replacedExpertId) { | |||||
boolean invitedRefused) { | |||||
ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | ||||
// 合并标签、字典 | // 合并标签、字典 | ||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo); | |||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidRule); | |||||
if (expertIdsIn == null) { | if (expertIdsIn == null) { | ||||
return result; | return result; | ||||
} | } | ||||
LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery(); | LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery(); | ||||
query.notIn(ExpertUserFullInfo::getCompany, avoidInfo.getAvoidUnitIdList()); | |||||
query.notIn(ExpertUserFullInfo::getCompany, avoidRule.getAvoidUnitIdList()); | |||||
query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" + | query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" + | ||||
" and company_name in ({0})", CollUtils.joinByComma(avoidInfo.getAvoidOrgIdList())); | |||||
" and company_name in ({0})", CollUtils.joinByComma(avoidRule.getAvoidOrgIdList())); | |||||
// 处理专家层级 | // 处理专家层级 | ||||
if (ObjectUtils.allNotNull(randomRule.getExpertRegionCode(), randomRule.getExpertRegionLevel())) { | |||||
if (StrUtils.isNotBlank(randomRule.getExpertRegionCode())) { | |||||
query.eq(ExpertUserFullInfo::getRegionCode, randomRule.getExpertRegionCode()); | query.eq(ExpertUserFullInfo::getRegionCode, randomRule.getExpertRegionCode()); | ||||
query.eq(ExpertUserFullInfo::getRegionLevel, randomRule.getExpertRegionLevel()); | query.eq(ExpertUserFullInfo::getRegionLevel, randomRule.getExpertRegionLevel()); | ||||
} | } | ||||
if (expertIdsIn.size() > 0) { | if (expertIdsIn.size() > 0) { | ||||
if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w)); | |||||
if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds())) { | |||||
expertIdsIn.removeIf(w -> avoidRule.getExpertIds().contains(w)); | |||||
if (expertIdsIn.isEmpty()) { | if (expertIdsIn.isEmpty()) { | ||||
// 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | // 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | ||||
// 如果为空则说明没有符合条件的 | // 如果为空则说明没有符合条件的 | ||||
@@ -381,8 +380,8 @@ public class ExpertInviteManage { | |||||
return result; | return result; | ||||
} | } | ||||
query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | ||||
} else if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
Set<Long> notInExpertIds = expertInviteHelper.getAvoidExpert(avoidInfo.getExpertIds(), null, start, end); | |||||
} else if (CollUtil.isNotEmpty(avoidRule.getExpertIds())) { | |||||
Set<Long> notInExpertIds = expertInviteHelper.getAvoidExpert(avoidRule.getExpertIds(), null, start, end); | |||||
query.notIn(ExpertUserFullInfo::getUserId, notInExpertIds); | query.notIn(ExpertUserFullInfo::getUserId, notInExpertIds); | ||||
} else { | } else { | ||||
Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | ||||
@@ -394,44 +393,31 @@ public class ExpertInviteManage { | |||||
if (userFullInfos.size() == 0) { | if (userFullInfos.size() == 0) { | ||||
return result; | return result; | ||||
} | } | ||||
Comparator<MeetingExpert> sort = Comparator.comparing(MeetingExpert::getUpdateOn).reversed(); | |||||
Map<Long, MeetingExpert> tempExpertIdsMap = BizUtils.groupFirstMap(meetingExperts, MeetingExpert::getExpertId, sort); | |||||
Map<ExpertAttendStatusEnum, List<MeetingExpert>> expertIdGroupByStatus = tempExpertIdsMap.values().stream() | |||||
Map<ExpertAttendStatusEnum, List<MeetingExpert>> expertGroupByStatus = invitedExperts.stream() | |||||
.collect(Collectors.groupingBy(w -> ExpertAttendStatusEnum.getByCode(w.getStatus()))); | .collect(Collectors.groupingBy(w -> ExpertAttendStatusEnum.getByCode(w.getStatus()))); | ||||
// 回避同单位其他专家 | // 回避同单位其他专家 | ||||
List<MeetingExpert> removeExpertByCompany = new ArrayList<>(); | List<MeetingExpert> removeExpertByCompany = new ArrayList<>(); | ||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatusEnum.AGREED), removeExpertByCompany::addAll); | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatusEnum.NOTICING), removeExpertByCompany::addAll); | |||||
BizUtils.notEmpty(expertGroupByStatus.get(ExpertAttendStatusEnum.AGREED), removeExpertByCompany::addAll); | |||||
BizUtils.notEmpty(expertGroupByStatus.get(ExpertAttendStatusEnum.NOTICING), removeExpertByCompany::addAll); | |||||
List<Long> removeExpertIds = new ArrayList<>(); | List<Long> removeExpertIds = new ArrayList<>(); | ||||
// 拒绝参加的不可以被再次抽中 | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatusEnum.REFUSED), w -> { | |||||
List<Long> tempRefused = CollUtils.fieldList(w, MeetingExpert::getExpertId); | |||||
removeExpertIds.addAll(tempRefused); | |||||
}); | |||||
if (invitedRefused) { | |||||
// 拒绝参加的不可以被再次抽中 | |||||
BizUtils.notEmpty(expertGroupByStatus.get(ExpertAttendStatusEnum.REFUSED), w -> { | |||||
List<Long> tempRefused = CollUtils.fieldList(w, MeetingExpert::getExpertId); | |||||
removeExpertIds.addAll(tempRefused); | |||||
}); | |||||
} | |||||
// 被取消的也不可以被再次抽中 | // 被取消的也不可以被再次抽中 | ||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatusEnum.REMOVED), w -> { | |||||
BizUtils.notEmpty(expertGroupByStatus.get(ExpertAttendStatusEnum.REMOVED), w -> { | |||||
List<Long> tempCanceled = CollUtils.fieldList(w, MeetingExpert::getExpertId); | List<Long> tempCanceled = CollUtils.fieldList(w, MeetingExpert::getExpertId); | ||||
removeExpertIds.addAll(tempCanceled); | removeExpertIds.addAll(tempCanceled); | ||||
}); | }); | ||||
// 被替换之前是上述两种状态的不可被再次抽中 | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatusEnum.REPLACED), w -> { | |||||
for (MeetingExpert me : w) { | |||||
BizUtils.notNull(me.getPreStatus(), preStatus -> { | |||||
if (ExpertAttendStatusEnum.REFUSED.eq(preStatus) || ExpertAttendStatusEnum.REMOVED.eq(preStatus)) { | |||||
removeExpertIds.add(me.getExpertId()); | |||||
} | |||||
}); | |||||
} | |||||
}); | |||||
// 不为空时表示单个专家替换否则为专家补抽 | |||||
if (replacedExpertId != null) { | |||||
removeExpertIds.add(replacedExpertId); | |||||
} | |||||
List<Long> tempExpertIds = CollUtils.fieldList(removeExpertByCompany, MeetingExpert::getExpertId); | List<Long> tempExpertIds = CollUtils.fieldList(removeExpertByCompany, MeetingExpert::getExpertId); | ||||
// 移除确认参加、通知中的、拒绝参加、已取消 | // 移除确认参加、通知中的、拒绝参加、已取消 | ||||
userFullInfos.removeIf(w -> tempExpertIds.contains(w.getUserId()) || removeExpertIds.contains(w.getUserId())); | userFullInfos.removeIf(w -> tempExpertIds.contains(w.getUserId()) || removeExpertIds.contains(w.getUserId())); | ||||
result.setTotal(userFullInfos.size()); | |||||
result.setExperts(inviteWithoutCompany(userFullInfos, count)); | |||||
Map<String, List<ExpertUserFullInfo>> userGroupByUnit = CollUtils.group(userFullInfos, ExpertUserFullInfo::getCompany); | |||||
result.setTotal(userGroupByUnit.size()); | |||||
result.setExperts(inviteGroupByCompany(userGroupByUnit, count)); | |||||
return result; | return result; | ||||
} | } | ||||
@@ -455,26 +441,26 @@ public class ExpertInviteManage { | |||||
/** | /** | ||||
* 每个单位只抽取一人 | * 每个单位只抽取一人 | ||||
* | * | ||||
* @param expertGroupByCompany 需要抽取的人 | |||||
* @param count 抽取数量 | |||||
* @param expertGroupByUnit 需要抽取的人 | |||||
* @param count 抽取数量 | |||||
* @return java.util.List<com.ningdatech.emapi.expert.entity.domain.ExpertUserFullInfo> | * @return java.util.List<com.ningdatech.emapi.expert.entity.domain.ExpertUserFullInfo> | ||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
private List<ExpertUserFullInfo> inviteGroupByCompany(Map<String, List<ExpertUserFullInfo>> expertGroupByCompany, Integer count) { | |||||
if (MapUtils.isEmpty(expertGroupByCompany)) { | |||||
private List<ExpertUserFullInfo> inviteGroupByCompany(Map<String, List<ExpertUserFullInfo>> expertGroupByUnit, Integer count) { | |||||
if (MapUtils.isEmpty(expertGroupByUnit)) { | |||||
return Collections.emptyList(); | return Collections.emptyList(); | ||||
} | } | ||||
List<List<MeetingExpert>> meetingExperts = selectMeetingExpertByCount(); | List<List<MeetingExpert>> meetingExperts = selectMeetingExpertByCount(); | ||||
if (meetingExperts.isEmpty()) { | if (meetingExperts.isEmpty()) { | ||||
return expertGroupByCompany.values().stream() | |||||
return expertGroupByUnit.values().stream() | |||||
.map(expertUsers -> expertUsers.get(RandomUtils.nextInt(0, expertUsers.size()))) | .map(expertUsers -> expertUsers.get(RandomUtils.nextInt(0, expertUsers.size()))) | ||||
.limit(count).collect(Collectors.toList()); | .limit(count).collect(Collectors.toList()); | ||||
} else { | } else { | ||||
List<ExpertUserFullInfo> result = new ArrayList<>(); | List<ExpertUserFullInfo> result = new ArrayList<>(); | ||||
List<String> keySet = new ArrayList<>(expertGroupByCompany.keySet()); | |||||
List<String> keySet = new ArrayList<>(expertGroupByUnit.keySet()); | |||||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||||
String key = keySet.get(RandomUtils.nextInt(0, keySet.size())); | String key = keySet.get(RandomUtils.nextInt(0, keySet.size())); | ||||
List<ExpertUserFullInfo> expertUserFullInfos = expertGroupByCompany.get(key); | |||||
List<ExpertUserFullInfo> expertUserFullInfos = expertGroupByUnit.get(key); | |||||
for (List<MeetingExpert> expertList : meetingExperts) { | for (List<MeetingExpert> expertList : meetingExperts) { | ||||
List<ExpertUserFullInfo> tempList = expertUserFullInfos.stream() | List<ExpertUserFullInfo> tempList = expertUserFullInfos.stream() | ||||
.filter(w -> expertList.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId()))) | .filter(w -> expertList.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId()))) | ||||
@@ -547,12 +533,13 @@ public class ExpertInviteManage { | |||||
* 专家抽取(会议创建时抽取) | * 专家抽取(会议创建时抽取) | ||||
* | * | ||||
* @param randomRules 随机抽取规则 | * @param randomRules 随机抽取规则 | ||||
* @param avoid 回避信息 | |||||
* @param avoidRuled 回避信息 | |||||
* @param meeting 会议信息 | |||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
public void expertRandomInviteByMeetingCreate(Meeting meeting, | |||||
List<RandomInviteRuleDTO> randomRules, | |||||
AvoidInfoDTO avoid) { | |||||
public void expertInviteByMeetingCreate(Meeting meeting, | |||||
List<RandomInviteRuleDTO> randomRules, | |||||
AvoidRuleDTO avoidRuled) { | |||||
List<MeetingExpert> expertInserts = new ArrayList<>(); | List<MeetingExpert> expertInserts = new ArrayList<>(); | ||||
// 处理随机抽取规则 | // 处理随机抽取规则 | ||||
if (CollectionUtils.isNotEmpty(randomRules)) { | if (CollectionUtils.isNotEmpty(randomRules)) { | ||||
@@ -562,7 +549,7 @@ public class ExpertInviteManage { | |||||
LocalDateTime startTime = meeting.getStartTime(); | LocalDateTime startTime = meeting.getStartTime(); | ||||
LocalDateTime endTime = meeting.getEndTime(); | LocalDateTime endTime = meeting.getEndTime(); | ||||
randomRules.forEach(rule -> { | randomRules.forEach(rule -> { | ||||
ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoid, rule, choosedExpertIds, startTime, endTime); | |||||
ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoidRuled, rule, choosedExpertIds, startTime, endTime); | |||||
expertsByRandom.add(tempExperts); | expertsByRandom.add(tempExperts); | ||||
choosedExpertIds.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId)); | choosedExpertIds.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId)); | ||||
randoms.add(getExpertInviteRule(rule, meeting.getId())); | randoms.add(getExpertInviteRule(rule, meeting.getId())); | ||||
@@ -140,6 +140,29 @@ public class MeetingManage { | |||||
} | } | ||||
} | } | ||||
public void continueInvite(Long meetingId) { | |||||
String key = "CONTINUE_INVITE:" + meetingId; | |||||
if (!distributedLock.lock(key, RETRY_TIMES)) { | |||||
throw BizException.wrap("已进行续抽,请勿重复点击"); | |||||
} | |||||
try { | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
if (!meeting.getInviteStatus()) { | |||||
throw BizException.wrap("该会议正在抽取专家,暂无法续抽"); | |||||
} | |||||
if (!MeetingStatusEnum.NORMAL.eq(meeting.getStatus())) { | |||||
throw BizException.wrap("续抽失败,请刷新后重试"); | |||||
} | |||||
boolean invitedContinue = meetingManageHelper.checkCouldBeInvitedContinue(meetingId); | |||||
if (!invitedContinue) { | |||||
throw BizException.wrap("抽取人员数量已满足抽取规则"); | |||||
} | |||||
} finally { | |||||
distributedLock.releaseLock(key); | |||||
} | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | @Transactional(rollbackFor = Exception.class) | ||||
public void expertInviteByCreate(ExpertInviteReq req) { | public void expertInviteByCreate(ExpertInviteReq req) { | ||||
String key = INVITED_RULE_CREATE + req.getMeetingId(); | String key = INVITED_RULE_CREATE + req.getMeetingId(); | ||||
@@ -151,7 +174,7 @@ public class MeetingManage { | |||||
if (ExpertInviteTypeEnum.RANDOM.eq(req.getInviteType())) { | if (ExpertInviteTypeEnum.RANDOM.eq(req.getInviteType())) { | ||||
List<RandomInviteRuleDTO> randomRules = req.getRandomRules(); | List<RandomInviteRuleDTO> randomRules = req.getRandomRules(); | ||||
Assert.notEmpty(randomRules, "随机抽取规则不能为空"); | Assert.notEmpty(randomRules, "随机抽取规则不能为空"); | ||||
AvoidInfoDTO avoidInfo = req.getAvoidRule(); | |||||
AvoidRuleDTO avoidInfo = req.getAvoidRule(); | |||||
Assert.notNull(avoidInfo, "回避信息不能为空"); | Assert.notNull(avoidInfo, "回避信息不能为空"); | ||||
// 随机抽取的话则需进行抽取数量校验 | // 随机抽取的话则需进行抽取数量校验 | ||||
ExpertCountOnChangeVO countOnChange = expertCountOnChange(req); | ExpertCountOnChangeVO countOnChange = expertCountOnChange(req); | ||||
@@ -163,23 +186,21 @@ public class MeetingManage { | |||||
Integer inviteCount = randomRules.get(i).getCount(); | Integer inviteCount = randomRules.get(i).getCount(); | ||||
Assert.isTrue(checkCount >= inviteCount, "可供抽取的专家数量不足"); | Assert.isTrue(checkCount >= inviteCount, "可供抽取的专家数量不足"); | ||||
} | } | ||||
expertInviteManage.expertRandomInviteByMeetingCreate(meeting, randomRules, avoidInfo); | |||||
expertInviteManage.expertInviteByMeetingCreate(meeting, randomRules, avoidInfo); | |||||
expertInviteTask.addInviteExpertTaskByMeetingCreate(meeting.getId(), 5); | expertInviteTask.addInviteExpertTaskByMeetingCreate(meeting.getId(), 5); | ||||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | ||||
update.set(Meeting::getInviteStatus, false); | update.set(Meeting::getInviteStatus, false); | ||||
update.eq(Meeting::getId, meeting.getId()); | update.eq(Meeting::getId, meeting.getId()); | ||||
meetingService.update(update); | meetingService.update(update); | ||||
// 回避规则 | // 回避规则 | ||||
if (avoidInfo != null) { | |||||
ExpertInviteAvoidRule avoidRule = new ExpertInviteAvoidRule(); | |||||
avoidRule.setMeetingId(meeting.getId()); | |||||
// 未传值时设置为0 表示不限制周参与次数 | |||||
avoidRule.setWeekInviteCount(ObjectUtil.defaultIfNull(avoidRule.getWeekInviteCount(), 0)); | |||||
avoidRule.setAvoidOrgIds(CollUtils.joinByComma(avoidInfo.getAvoidOrgIdList())); | |||||
avoidRule.setAvoidUnitIds(CollUtils.joinByComma(avoidInfo.getAvoidUnitIdList())); | |||||
avoidRule.setAvoidExpertIds(CollUtils.joinByComma(avoidInfo.getExpertIds())); | |||||
inviteAvoidRuleService.save(avoidRule); | |||||
} | |||||
ExpertInviteAvoidRule avoidRule = new ExpertInviteAvoidRule(); | |||||
avoidRule.setMeetingId(meeting.getId()); | |||||
// 未传值时设置为0 表示不限制周参与次数 | |||||
avoidRule.setWeekInviteCount(ObjectUtil.defaultIfNull(avoidRule.getWeekInviteCount(), 0)); | |||||
avoidRule.setAvoidOrgIds(CollUtils.joinByComma(avoidInfo.getAvoidOrgIdList())); | |||||
avoidRule.setAvoidUnitIds(CollUtils.joinByComma(avoidInfo.getAvoidUnitIdList())); | |||||
avoidRule.setAvoidExpertIds(CollUtils.joinByComma(avoidInfo.getExpertIds())); | |||||
inviteAvoidRuleService.save(avoidRule); | |||||
} else { | } else { | ||||
// 指定邀请 | // 指定邀请 | ||||
AppointInviteRuleDTO appointRule = req.getAppointRule(); | AppointInviteRuleDTO appointRule = req.getAppointRule(); | ||||
@@ -449,7 +470,7 @@ public class MeetingManage { | |||||
} | } | ||||
result.getRandomRules().add(randomRule); | result.getRandomRules().add(randomRule); | ||||
}); | }); | ||||
AvoidInfoDTO avoidInfo = inviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
AvoidRuleDTO avoidInfo = inviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
AvoidInfoVO vo = new AvoidInfoVO(); | AvoidInfoVO vo = new AvoidInfoVO(); | ||||
vo.setAvoidOrgIds(avoidInfo.getAvoidOrgIdList()); | vo.setAvoidOrgIds(avoidInfo.getAvoidOrgIdList()); | ||||
vo.setAvoidUnitIds(avoidInfo.getAvoidUnitIdList()); | vo.setAvoidUnitIds(avoidInfo.getAvoidUnitIdList()); | ||||
@@ -469,75 +490,6 @@ public class MeetingManage { | |||||
return result; | return result; | ||||
} | } | ||||
public void expertRemove(ExpertRemoveReq po) { | |||||
LambdaUpdateWrapper<MeetingExpert> update = Wrappers.lambdaUpdate(MeetingExpert.class) | |||||
.eq(MeetingExpert::getId, po.getExpertMeetingId()) | |||||
.set(MeetingExpert::getStatus, ExpertAttendStatusEnum.REMOVED.getCode()); | |||||
meetingExpertService.update(update); | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void expertReplace(ExpertRemoveReq po) { | |||||
MeetingExpert meetingExpert = meetingExpertService.getById(po.getExpertMeetingId()); | |||||
ExpertUserFullInfo expertFullInfo; | |||||
Long ruleId = 0L; | |||||
Meeting meeting = meetingService.getById(po.getMeetingId()); | |||||
if (po.getExpertId() != null) { | |||||
// 指定邀请替换 | |||||
List<ExpertUserFullInfo> userInfos = meetingManageHelper.appointExpertCheck(po.getMeetingId(), Collections.singletonList(po.getExpertId())); | |||||
expertFullInfo = userInfos.get(0); | |||||
} else { | |||||
List<ExpertInviteRule> inviteRules = inviteRuleService.listByMeetingId(po.getMeetingId()); | |||||
// 邀请规则 | |||||
RandomInviteRuleDTO randomInviteRuleDto = null; | |||||
for (ExpertInviteRule rule : inviteRules) { | |||||
if (rule.getInviteType().equals(ExpertInviteTypeEnum.RANDOM.getCode()) && | |||||
rule.getId().equals(meetingExpert.getRuleId())) { | |||||
randomInviteRuleDto = JSON.parseObject(rule.getInviteRule(), RandomInviteRuleDTO.class); | |||||
ruleId = rule.getId(); | |||||
break; | |||||
} | |||||
} | |||||
// 回避规则 | |||||
AvoidInfoDTO avoidInfoDto = meetingManageHelper.getAvoidInfoDto(po.getMeetingId()); | |||||
// 添加回避该替换的专家 | |||||
List<Long> expertIds = avoidInfoDto.getExpertIds(); | |||||
if (CollUtil.isEmpty(expertIds)) { | |||||
expertIds = new ArrayList<>(); | |||||
} | |||||
expertIds.add(meetingExpert.getExpertId()); | |||||
avoidInfoDto.setExpertIds(expertIds); | |||||
meetingManageHelper.saveAvoidInfo(po.getMeetingId(), avoidInfoDto.getExpertIds()); | |||||
List<MeetingExpert> meetingExperts = meetingExpertService.listByMeetingId(po.getMeetingId()); | |||||
ExpertChooseDTO expertChooseDto = expertInviteManage.expertReplaceByRandomRule(avoidInfoDto, randomInviteRuleDto, | |||||
meetingExperts, 1, meeting.getStartTime(), meeting.getEndTime(), meetingExpert.getExpertId()); | |||||
Assert.isTrue(expertChooseDto.getTotal() > 0, "暂无专家可供替换"); | |||||
expertFullInfo = expertChooseDto.getExperts().get(0); | |||||
expertInviteTask.addInviteExpertTask(po.getMeetingId()); | |||||
} | |||||
LambdaUpdateWrapper<MeetingExpert> update = Wrappers.lambdaUpdate(MeetingExpert.class) | |||||
.eq(MeetingExpert::getId, po.getExpertMeetingId()) | |||||
.set(MeetingExpert::getUpdateOn, LocalDateTime.now()) | |||||
.set(MeetingExpert::getPreStatus, meetingExpert.getStatus()) | |||||
.set(MeetingExpert::getStatus, ExpertAttendStatusEnum.REPLACED.getCode()); | |||||
meetingExpertService.update(update); | |||||
MeetingExpert me; | |||||
if (po.getExpertId() == null) { | |||||
me = ExpertInviteBuilder.getExpertByRandom(po.getMeetingId(), expertFullInfo, ruleId); | |||||
} else { | |||||
me = ExpertInviteBuilder.getExpertByAppoint(po.getMeetingId(), expertFullInfo, ruleId); | |||||
} | |||||
me.setStatus(ExpertAttendStatusEnum.NOTICING.getCode()); | |||||
me.setPreId(po.getExpertMeetingId()); | |||||
yxtCallOrSmsHelper.callByMeetingExperts(meeting, Collections.singletonList(me)); | |||||
meetingExpertService.save(me); | |||||
// 发送专家替换短信 TODO | |||||
// String meetingType = dictionaryCache.getByCode(meeting.getType()).getName(); | |||||
// SendSmsContext context = YxtSmsContextBuilder.smsToExpertByReplace(meeting, meetingExpert, meetingType); | |||||
// yxtCallOrSmsHelper.sendSms(context); | |||||
} | |||||
public void batchAppointExperts(BatchAppointExpertsReq req) { | public void batchAppointExperts(BatchAppointExpertsReq req) { | ||||
Long meetingId = req.getMeetingId(); | Long meetingId = req.getMeetingId(); | ||||
String key = "BATCH_APPOINT_EXPERT:" + meetingId; | String key = "BATCH_APPOINT_EXPERT:" + meetingId; | ||||
@@ -2,7 +2,7 @@ package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
@@ -23,6 +23,6 @@ public interface IExpertInviteAvoidRuleService extends IService<ExpertInviteAvoi | |||||
* @return com.ningdatech.emapi.meeting.entity.dto.AvoidInfoDto | * @return com.ningdatech.emapi.meeting.entity.dto.AvoidInfoDto | ||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
AvoidInfoDTO getAvoidInfoDto(Long meetingId); | |||||
AvoidRuleDTO getAvoidInfoDto(Long meetingId); | |||||
} | } |
@@ -27,7 +27,7 @@ public interface IMeetingExpertService extends IService<MeetingExpert> { | |||||
* 查询专家的参与状态 | * 查询专家的参与状态 | ||||
* | * | ||||
* @param expertId 专家ID | * @param expertId 专家ID | ||||
* @param status 状态{@link MeetingStatus.Expert} | |||||
* @param status 状态 | |||||
* @param meetingIds 会议ID | * @param meetingIds 会议ID | ||||
* @return 会议参加状态统计 | * @return 会议参加状态统计 | ||||
* @author WendyYang | * @author WendyYang | ||||
@@ -35,7 +35,7 @@ public interface IMeetingExpertService extends IService<MeetingExpert> { | |||||
List<MeetingAndAttendStatusDTO> listByExpertIdAndStatus(Long expertId, Integer status, List<Long> meetingIds); | List<MeetingAndAttendStatusDTO> listByExpertIdAndStatus(Long expertId, Integer status, List<Long> meetingIds); | ||||
/** | /** | ||||
* 查询每个事物的确认进度 | |||||
* 查询每个会议的确认进度 | |||||
* | * | ||||
* @param meetingIds 事务ID | * @param meetingIds 事务ID | ||||
* @return 确认进度 | * @return 确认进度 | ||||
@@ -132,4 +132,15 @@ public interface IMeetingExpertService extends IService<MeetingExpert> { | |||||
**/ | **/ | ||||
List<MeetingExpert> listExpertLastByMeetingIds(Collection<Long> meetingIds); | List<MeetingExpert> listExpertLastByMeetingIds(Collection<Long> meetingIds); | ||||
/** | |||||
* 查询会议的所有被抽取人最后一条记录 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @return 抽取记录 | |||||
* @author WendyYang | |||||
**/ | |||||
default List<MeetingExpert> listExpertLastByMeetingId(Long meetingId) { | |||||
return listExpertLastByMeetingIds(Collections.singletonList(meetingId)); | |||||
} | |||||
} | } |
@@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.pmapi.common.util.BizUtils; | import com.ningdatech.pmapi.common.util.BizUtils; | ||||
import com.ningdatech.pmapi.common.util.StrUtils; | import com.ningdatech.pmapi.common.util.StrUtils; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.mapper.ExpertInviteAvoidRuleMapper; | import com.ningdatech.pmapi.meeting.mapper.ExpertInviteAvoidRuleMapper; | ||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | ||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
@@ -30,12 +30,12 @@ public class ExpertInviteAvoidRuleServiceImpl extends ServiceImpl<ExpertInviteAv | |||||
} | } | ||||
@Override | @Override | ||||
public AvoidInfoDTO getAvoidInfoDto(Long meetingId) { | |||||
public AvoidRuleDTO getAvoidInfoDto(Long meetingId) { | |||||
ExpertInviteAvoidRule avoidRule = getByMeetingId(meetingId); | ExpertInviteAvoidRule avoidRule = getByMeetingId(meetingId); | ||||
if (avoidRule == null) { | if (avoidRule == null) { | ||||
return null; | return null; | ||||
} | } | ||||
AvoidInfoDTO avoidInfo = new AvoidInfoDTO(); | |||||
AvoidRuleDTO avoidInfo = new AvoidRuleDTO(); | |||||
avoidInfo.setAvoidOrgIdList(StrUtils.split(avoidRule.getAvoidOrgIds())); | avoidInfo.setAvoidOrgIdList(StrUtils.split(avoidRule.getAvoidOrgIds())); | ||||
avoidInfo.setAvoidUnitIdList(StrUtils.split(avoidRule.getAvoidUnitIds())); | avoidInfo.setAvoidUnitIdList(StrUtils.split(avoidRule.getAvoidUnitIds())); | ||||
avoidInfo.setExpertIds(BizUtils.splitToLong(avoidRule.getAvoidExpertIds())); | avoidInfo.setExpertIds(BizUtils.splitToLong(avoidRule.getAvoidExpertIds())); | ||||
@@ -1,23 +1,20 @@ | |||||
package com.ningdatech.pmapi.meeting.task; | package com.ningdatech.pmapi.meeting.task; | ||||
import cn.hutool.core.collection.CollUtil; | |||||
import cn.hutool.core.convert.Convert; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
import com.ningdatech.basic.util.CollUtils; | import com.ningdatech.basic.util.CollUtils; | ||||
import com.ningdatech.cache.model.cache.CacheKey; | |||||
import com.ningdatech.cache.model.cache.CacheHashKey; | |||||
import com.ningdatech.cache.repository.CachePlusOps; | import com.ningdatech.cache.repository.CachePlusOps; | ||||
import com.ningdatech.pmapi.common.util.SpringContextHolder; | import com.ningdatech.pmapi.common.util.SpringContextHolder; | ||||
import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder; | import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | ||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingInviteCacheDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | ||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum; | |||||
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | ||||
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | ||||
import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage; | import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage; | ||||
@@ -29,6 +26,7 @@ import com.ningdatech.pmapi.user.util.LoginUserUtil; | |||||
import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
import org.apache.commons.collections4.MapUtils; | |||||
import org.springframework.aop.framework.AopContext; | import org.springframework.aop.framework.AopContext; | ||||
import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | ||||
@@ -42,15 +40,12 @@ import java.time.Duration; | |||||
import java.time.Instant; | import java.time.Instant; | ||||
import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||
import java.time.ZoneId; | import java.time.ZoneId; | ||||
import java.util.Collections; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import java.util.concurrent.ConcurrentMap; | import java.util.concurrent.ConcurrentMap; | ||||
import java.util.concurrent.ScheduledFuture; | import java.util.concurrent.ScheduledFuture; | ||||
import java.util.concurrent.atomic.AtomicInteger; | import java.util.concurrent.atomic.AtomicInteger; | ||||
import java.util.function.Function; | |||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
@@ -69,9 +64,13 @@ public class ExpertInviteTask { | |||||
private final ExpertInviteHelper expertInviteHelper; | private final ExpertInviteHelper expertInviteHelper; | ||||
private final RandomInviteProperties properties; | private final RandomInviteProperties properties; | ||||
private static final String MEETING_ID_INVITE_RANDOM = "MEETING_ID_INVITE_RANDOM"; | private static final String MEETING_ID_INVITE_RANDOM = "MEETING_ID_INVITE_RANDOM"; | ||||
private static final CacheKey CACHE_KEY = new CacheKey(MEETING_ID_INVITE_RANDOM); | |||||
private static final CacheHashKey CACHE_KEY = new CacheHashKey(); | |||||
static { | |||||
CACHE_KEY.setKey(MEETING_ID_INVITE_RANDOM); | |||||
CACHE_KEY.setExpire(Duration.ofDays(100)); | |||||
} | |||||
private final CachePlusOps cachePlusOps; | private final CachePlusOps cachePlusOps; | ||||
@Qualifier("expertInviteScheduler") | @Qualifier("expertInviteScheduler") | ||||
@@ -81,38 +80,38 @@ public class ExpertInviteTask { | |||||
private final IExpertInviteRuleService inviteRuleService; | private final IExpertInviteRuleService inviteRuleService; | ||||
private final IMeetingService meetingService; | private final IMeetingService meetingService; | ||||
private final ExpertInviteManage expertInviteManage; | private final ExpertInviteManage expertInviteManage; | ||||
private final IExpertInviteAvoidRuleService expertInviteAvoidRuleService; | |||||
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | |||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | ||||
public ExpertInviteTask currProxy() { | |||||
return (ExpertInviteTask) AopContext.currentProxy(); | |||||
} | |||||
/** | /** | ||||
* 用来存入线程执行情况, 方便于停止定时任务时使用 | * 用来存入线程执行情况, 方便于停止定时任务时使用 | ||||
*/ | */ | ||||
protected static final ConcurrentMap<Long, ScheduledFuture<?>> INVITE_MAP = new ConcurrentHashMap<>(); | protected static final ConcurrentMap<Long, ScheduledFuture<?>> INVITE_MAP = new ConcurrentHashMap<>(); | ||||
public ExpertInviteTask currProxy() { | |||||
return (ExpertInviteTask) AopContext.currentProxy(); | |||||
} | |||||
@PostConstruct | @PostConstruct | ||||
public void initTask() { | public void initTask() { | ||||
if (!properties.getEnable()) { | if (!properties.getEnable()) { | ||||
log.warn("随机邀请已关闭……"); | log.warn("随机邀请已关闭……"); | ||||
return; | return; | ||||
} | } | ||||
// initInviteTaskByStart(); | |||||
initInviteTaskAfterAppStarted(); | |||||
} | } | ||||
/** | /** | ||||
* 项目重启之后重新初始化邀请任务 | * 项目重启之后重新初始化邀请任务 | ||||
*/ | */ | ||||
private void initInviteTaskByStart() { | |||||
Set<Object> meetingIds = cachePlusOps.sMembers(CACHE_KEY); | |||||
if (meetingIds == null || meetingIds.isEmpty()) { | |||||
private void initInviteTaskAfterAppStarted() { | |||||
Map<Long, MeetingInviteCacheDTO> meetingIdMap = cachePlusOps.hGetAll(CACHE_KEY); | |||||
if (MapUtils.isEmpty(meetingIdMap)) { | |||||
log.info("暂无需要初始化的抽取会议信息"); | |||||
return; | return; | ||||
} | } | ||||
for (Object meetingId : meetingIds) { | |||||
addInviteExpertTask(Convert.toLong(meetingId), true, properties.getInviteDelay()); | |||||
for (MeetingInviteCacheDTO cache : meetingIdMap.values()) { | |||||
addInviteExpertTask(cache.getMeetingId(), true, properties.getInviteDelay(), cache.getInvitedRefused()); | |||||
} | } | ||||
} | } | ||||
@@ -123,25 +122,27 @@ public class ExpertInviteTask { | |||||
* @return boolean | * @return boolean | ||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
private boolean inviteCheck(Long meetingId) { | |||||
List<ExpertInviteRule> expertInviteRules = inviteRuleService.listByMeetingId(meetingId); | |||||
Function<ExpertInviteRule, ExpertInviteTypeEnum> groupKey = w -> ExpertInviteTypeEnum.getByCode(w.getInviteType()); | |||||
Map<ExpertInviteTypeEnum, List<ExpertInviteRule>> groupByType = CollUtils.group(expertInviteRules, groupKey); | |||||
List<ExpertInviteRule> randomRules = groupByType.get(ExpertInviteTypeEnum.RANDOM); | |||||
if (CollUtil.isEmpty(randomRules)) { | |||||
return false; | |||||
private boolean inviteCountCheck(Long meetingId) { | |||||
Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); | |||||
if (ruleMap.isEmpty()) { | |||||
return Boolean.FALSE; | |||||
} | } | ||||
Map<Long, ExpertInviteRule> ruleMap = CollUtils.listToMap(randomRules, ExpertInviteRule::getId); | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | ||||
.select(MeetingExpert::getRuleId, MeetingExpert::getStatus) | |||||
.in(MeetingExpert::getRuleId, ruleMap.keySet()) | .in(MeetingExpert::getRuleId, ruleMap.keySet()) | ||||
.in(MeetingExpert::getStatus, ExpertAttendStatusEnum.AGREED.getCode()); | .in(MeetingExpert::getStatus, ExpertAttendStatusEnum.AGREED.getCode()); | ||||
List<MeetingExpert> meetingExperts = meetingExpertService.list(query); | |||||
int totalCount = CollUtils.sum(randomRules, ExpertInviteRule::getInviteCount); | |||||
boolean needed = totalCount > meetingExperts.size(); | |||||
if (!needed) { | |||||
cancelByMeetingId(meetingId); | |||||
List<MeetingExpert> experts = meetingExpertService.list(query); | |||||
if (experts.isEmpty()) { | |||||
return Boolean.FALSE; | |||||
} | |||||
Map<Long, Long> cntMap = CollUtils.groupCount(experts, MeetingExpert::getRuleId); | |||||
for (Map.Entry<Long, RandomInviteRuleDTO> entry : ruleMap.entrySet()) { | |||||
Long agreeCnt = cntMap.getOrDefault(entry.getKey(), 0L); | |||||
if (agreeCnt < entry.getValue().getCount()) { | |||||
return Boolean.FALSE; | |||||
} | |||||
} | } | ||||
return needed; | |||||
return Boolean.TRUE; | |||||
} | } | ||||
/** | /** | ||||
@@ -151,9 +152,8 @@ public class ExpertInviteTask { | |||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
public void addInviteExpertTask(Long meetingId) { | public void addInviteExpertTask(Long meetingId) { | ||||
boolean contains = INVITE_MAP.containsKey(meetingId); | |||||
if (!contains) { | |||||
addInviteExpertTask(meetingId, false, properties.getInviteDelay()); | |||||
if (!INVITE_MAP.containsKey(meetingId)) { | |||||
addInviteExpertTask(meetingId, false, properties.getInviteDelay(), false); | |||||
log.info("重置会议的随机抽取状态:{}", meetingId); | log.info("重置会议的随机抽取状态:{}", meetingId); | ||||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | ||||
update.set(Meeting::getInviteStatus, false); | update.set(Meeting::getInviteStatus, false); | ||||
@@ -170,17 +170,19 @@ public class ExpertInviteTask { | |||||
* @param meetingId 会议ID | * @param meetingId 会议ID | ||||
* @param checked 是否前置校验 | * @param checked 是否前置校验 | ||||
* @param delayedMinutes 延迟执行时间 | * @param delayedMinutes 延迟执行时间 | ||||
* @param invitedRefused 是否可以邀请被拒绝的专家 | |||||
* @author WendyYang | * @author WendyYang | ||||
**/ | **/ | ||||
public void addInviteExpertTask(Long meetingId, boolean checked, int delayedMinutes) { | |||||
if (checked && !inviteCheck(meetingId)) { | |||||
public void addInviteExpertTask(Long meetingId, boolean checked, int delayedMinutes, boolean invitedRefused) { | |||||
if (checked && !inviteCountCheck(meetingId)) { | |||||
// 如果抽取数量满足直接返回 | |||||
return; | return; | ||||
} | } | ||||
Instant startTime = LocalDateTime.now().plusMinutes(delayedMinutes).atZone(ZoneId.systemDefault()).toInstant(); | Instant startTime = LocalDateTime.now().plusMinutes(delayedMinutes).atZone(ZoneId.systemDefault()).toInstant(); | ||||
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> { | ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> { | ||||
ExpertInviteTask bean = SpringContextHolder.getBean(ExpertInviteTask.class); | ExpertInviteTask bean = SpringContextHolder.getBean(ExpertInviteTask.class); | ||||
try { | try { | ||||
bean.invite(meetingId); | |||||
bean.invite(meetingId, invitedRefused); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
log.error("执行专家邀请任务异常:{}", meetingId, e); | log.error("执行专家邀请任务异常:{}", meetingId, e); | ||||
} | } | ||||
@@ -189,53 +191,55 @@ public class ExpertInviteTask { | |||||
log.info("添加专家抽取后台任务:{}", meetingId); | log.info("添加专家抽取后台任务:{}", meetingId); | ||||
} | } | ||||
/** | |||||
* 创建会议时添加抽取任务 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @param delayedMinutes 延迟时间 | |||||
* @author WendyYang | |||||
**/ | |||||
public void addInviteExpertTaskByMeetingCreate(Long meetingId, int delayedMinutes) { | public void addInviteExpertTaskByMeetingCreate(Long meetingId, int delayedMinutes) { | ||||
Assert.isTrue(properties.getEnable(), "随机邀请已关闭"); | Assert.isTrue(properties.getEnable(), "随机邀请已关闭"); | ||||
addInviteExpertTask(meetingId, false, delayedMinutes); | |||||
addInviteExpertTask(meetingId, false, delayedMinutes, false); | |||||
cachePlusOps.sAdd(CACHE_KEY, meetingId); | cachePlusOps.sAdd(CACHE_KEY, meetingId); | ||||
} | } | ||||
@Transactional(rollbackFor = Exception.class) | @Transactional(rollbackFor = Exception.class) | ||||
public void invite(Long meetingId) { | |||||
public void invite(Long meetingId, Boolean invitedRefused) { | |||||
log.info("开始进行专家后台抽取:{}", meetingId); | log.info("开始进行专家后台抽取:{}", meetingId); | ||||
Meeting meeting = meetingService.getById(meetingId); | Meeting meeting = meetingService.getById(meetingId); | ||||
if (meeting.getStartTime().isBefore(LocalDateTime.now())) { | if (meeting.getStartTime().isBefore(LocalDateTime.now())) { | ||||
// 会议开始结束随机抽取 | |||||
cancelByMeetingId(meetingId); | |||||
log.info("会议已开始停止抽取:{}", meeting); | log.info("会议已开始停止抽取:{}", meeting); | ||||
cancelByMeetingId(meetingId); | |||||
return; | return; | ||||
} | } | ||||
// 随机邀请规则 | // 随机邀请规则 | ||||
Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); | Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); | ||||
// 回避规则 | // 回避规则 | ||||
AvoidInfoDTO avoidInfoDto = expertInviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
AvoidRuleDTO avoidRule = inviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
// 还需要抽取的规则数量 | // 还需要抽取的规则数量 | ||||
AtomicInteger notIgnoreCnt = new AtomicInteger(ruleMap.size()); | AtomicInteger notIgnoreCnt = new AtomicInteger(ruleMap.size()); | ||||
AtomicInteger notSupportCnt = new AtomicInteger(0); | AtomicInteger notSupportCnt = new AtomicInteger(0); | ||||
ruleMap.forEach((ruleId, value) -> { | ruleMap.forEach((ruleId, value) -> { | ||||
List<Long> singletonList = Collections.singletonList(meetingId); | |||||
List<MeetingExpert> tempExperts = meetingExpertService.listExpertLastByMeetingIds(singletonList); | |||||
Map<Long, MeetingExpert> expertMap = CollUtils.listToMap(tempExperts, MeetingExpert::getExpertId); | |||||
Map<Long, MeetingExpert> replacedMap = expertMap.values().stream().filter(w -> w.getPreId() > 0) | |||||
.collect(Collectors.toMap(MeetingExpert::getPreId, w -> w)); | |||||
Map<Long, ExpertCntBO> countMap = countByAgree(expertMap, replacedMap); | |||||
// 已确认参加、通话中数量 | |||||
List<MeetingExpert> tmpExperts = meetingExpertService.listExpertLastByMeetingId(meetingId); | |||||
Map<Long, MeetingExpert> expertMap = CollUtils.listToMap(tmpExperts, MeetingExpert::getExpertId); | |||||
// 统计通知中与同意参加专家数量 | |||||
Map<Long, ExpertCntBO> countMap = countByAgree(expertMap); | |||||
ExpertCntBO cnt = countMap.getOrDefault(ruleId, ExpertCntBO.zeroInit()); | ExpertCntBO cnt = countMap.getOrDefault(ruleId, ExpertCntBO.zeroInit()); | ||||
int tempCurrent = cnt.getAgreeCnt() + cnt.getNoticeCnt(); | |||||
if (tempCurrent == value.getCount()) { | |||||
int wouldAttendCnt = cnt.getAgreeCnt() + cnt.getNoticeCnt(); | |||||
if (wouldAttendCnt == value.getCount()) { | |||||
if (cnt.getAgreeCnt().equals(value.getCount())) { | if (cnt.getAgreeCnt().equals(value.getCount())) { | ||||
notIgnoreCnt.decrementAndGet(); | notIgnoreCnt.decrementAndGet(); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
int currInviteCnt = value.getCount() - tempCurrent; | |||||
ExpertChooseDTO expertChoose = expertInviteManage.expertReplaceByRandomRule(avoidInfoDto, value, | |||||
expertMap.values(), currInviteCnt, meeting.getStartTime(), meeting.getEndTime(), null); | |||||
int needInviteCnt = value.getCount() - wouldAttendCnt; | |||||
ExpertChooseDTO expertChoose = expertInviteManage.expertReplaceByRandomRule(avoidRule, value, | |||||
tmpExperts, needInviteCnt, meeting.getStartTime(), meeting.getEndTime(), invitedRefused); | |||||
if (expertChoose.getTotal() > 0) { | if (expertChoose.getTotal() > 0) { | ||||
List<MeetingExpert> expertMeetings = CollUtils.convert(expertChoose.getExperts(), w -> { | List<MeetingExpert> expertMeetings = CollUtils.convert(expertChoose.getExperts(), w -> { | ||||
MeetingExpert expert = ExpertInviteBuilder.getExpertByRandom(meetingId, w, ruleId); | MeetingExpert expert = ExpertInviteBuilder.getExpertByRandom(meetingId, w, ruleId); | ||||
expert.setPreStatus(ExpertAttendStatusEnum.NOTICING.getCode()); | |||||
expert.setStatus(ExpertAttendStatusEnum.NOTICING.getCode()); | expert.setStatus(ExpertAttendStatusEnum.NOTICING.getCode()); | ||||
return expert; | return expert; | ||||
}); | }); | ||||
@@ -276,7 +280,7 @@ public class ExpertInviteTask { | |||||
//================================================================================================================== | //================================================================================================================== | ||||
private Map<Long, ExpertCntBO> countByAgree(Map<Long, MeetingExpert> expertMap, Map<Long, MeetingExpert> replacedMap) { | |||||
private Map<Long, ExpertCntBO> countByAgree(Map<Long, MeetingExpert> expertMap) { | |||||
return expertMap.entrySet().stream() | return expertMap.entrySet().stream() | ||||
.collect(Collectors.groupingBy(w -> w.getValue().getRuleId(), | .collect(Collectors.groupingBy(w -> w.getValue().getRuleId(), | ||||
Collectors.collectingAndThen(Collectors.mapping(Map.Entry::getValue, Collectors.toList()), w -> { | Collectors.collectingAndThen(Collectors.mapping(Map.Entry::getValue, Collectors.toList()), w -> { | ||||
@@ -286,11 +290,6 @@ public class ExpertInviteTask { | |||||
cnt.incrAgreeCnt(); | cnt.incrAgreeCnt(); | ||||
} else if (ExpertAttendStatusEnum.NOTICING.eq(expert.getStatus())) { | } else if (ExpertAttendStatusEnum.NOTICING.eq(expert.getStatus())) { | ||||
cnt.incrNoticeCnt(); | cnt.incrNoticeCnt(); | ||||
} else if (ExpertAttendStatusEnum.REPLACED.eq(expert.getStatus())) { | |||||
MeetingExpert replacedExpert = replacedMap.get(expert.getId()); | |||||
if (replacedExpert != null && ExpertAttendStatusEnum.AGREED.eq(replacedExpert.getStatus())) { | |||||
cnt.incrAgreeCnt(); | |||||
} | |||||
} | } | ||||
} | } | ||||
return cnt; | return cnt; | ||||
@@ -15,7 +15,7 @@ spring: | |||||
timeout: 5000 | timeout: 5000 | ||||
host: 47.98.125.47 | host: 47.98.125.47 | ||||
port: 26379 | port: 26379 | ||||
database: 0 | |||||
database: 4 | |||||
password: Ndkj1234 | password: Ndkj1234 | ||||
jedis: | jedis: | ||||
pool: | pool: | ||||