소스 검색

Merge remote-tracking branch 'origin/master'

tags/24080901
CMM 1 년 전
부모
커밋
f8979f4786
13개의 변경된 파일72개의 추가작업 그리고 62개의 파일을 삭제
  1. +7
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java
  2. +7
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java
  3. +3
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/InviteCacheDTO.java
  4. +0
    -3
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java
  5. +1
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java
  6. +3
    -7
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/DashboardManage.java
  7. +3
    -8
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java
  8. +22
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
  9. +1
    -8
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml
  10. +7
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingService.java
  11. +1
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingExpertServiceImpl.java
  12. +1
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingServiceImpl.java
  13. +16
    -17
      pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java

+ 7
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java 파일 보기

@@ -46,6 +46,13 @@ public class MeetingController {
meetingManage.continueInvite(req.getMeetingId());
}

@PostMapping("/convertToAppoint")
@ApiOperation(value = "转为指定抽取")
@WebLog(value = "转为指定抽取")
public void convertToAppoint(@Valid @RequestBody MeetingIdReq req) {
meetingManage.convertToAppoint(req.getMeetingId());
}

@PostMapping("/expertInviteByCreate")
@ApiOperation(value = "新建会议-专家抽取", hidden = true)
@WebLog(value = "新建会议-专家抽取")


+ 7
- 6
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java 파일 보기

@@ -1,8 +1,6 @@
package com.ningdatech.pmapi.meeting.entity.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
@@ -58,15 +56,18 @@ public class MeetingExpert implements Serializable {
@ApiModelProperty("邀请类型")
private Integer inviteType;

private String submitKey;

@TableField(fill = FieldFill.INSERT)
private Long createBy;

@TableField(fill = FieldFill.INSERT)
private LocalDateTime createOn;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateBy;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateOn;

private String submitKey;


}

pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingInviteCacheDTO.java → pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/InviteCacheDTO.java 파일 보기

@@ -11,14 +11,14 @@ import lombok.Data;
* @since 19:21 2023/3/7
*/
@Data
public final class MeetingInviteCacheDTO {
public final class InviteCacheDTO {

private Long meetingId;

private Boolean invitedRefused;

public static MeetingInviteCacheDTO of(Long meetingId, Boolean invitedRefused) {
MeetingInviteCacheDTO bo = new MeetingInviteCacheDTO();
public static InviteCacheDTO of(Long meetingId, Boolean invitedRefused) {
InviteCacheDTO bo = new InviteCacheDTO();
bo.setMeetingId(meetingId);
bo.setInvitedRefused(invitedRefused);
return bo;

+ 0
- 3
pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java 파일 보기

@@ -19,11 +19,8 @@ public enum ExpertAttendStatusEnum {

NOTICING("通知中", 0),
UNANSWERED("未应答", 1),
REPLACED("已替换", 2),
AGREED("同意参加", 3),
REFUSED("拒绝参加", 4),
REMOVED("已移除", 5),
ON_LEAVE("已请假", 6),
RELEASED("已释放", 7);

private final String value;


+ 1
- 2
pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java 파일 보기

@@ -196,6 +196,7 @@ public class MeetingManageHelper {
*
* @param meetingId 会议ID
* @param expertIds 专家ID
* @return 符合邀请规则的专家
* @author WendyYang
**/
public List<ExpertUserFullInfo> appointExpertCheck(Long meetingId, List<Long> expertIds) {
@@ -226,8 +227,6 @@ public class MeetingManageHelper {
switch (ExpertAttendStatusEnum.getByCode(w.getStatus())) {
case REFUSED:
throw BizException.wrap("专家%s已拒绝参加", expertName);
case REMOVED:
throw BizException.wrap("专家%s已被移除", expertName);
case AGREED:
throw BizException.wrap("专家%s已同意参加", expertName);
case NOTICING:


+ 3
- 7
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/DashboardManage.java 파일 보기

@@ -12,10 +12,9 @@ import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
import com.ningdatech.pmapi.meeting.entity.dto.CountConfirmByMeetingIdDTO;
import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum;
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusEnum;
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusByDashboard;
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusEnum;
import com.ningdatech.pmapi.meeting.entity.req.MeetingCalenderReq;
import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq;
import com.ningdatech.pmapi.meeting.entity.vo.*;
@@ -186,8 +185,7 @@ public class DashboardManage {
return PageVo.empty();
}
List<Long> meetingIds = CollUtils.fieldList(meetings, Meeting::getId);
Page<MeetingExpert> page = meetingExpertService.pageExpertByStatusAndMeetingIds(new Page<>(po.getPageNumber(), po.getPageSize()),
meetingIds, ExpertAttendStatusEnum.ON_LEAVE);
Page<MeetingExpert> page = meetingExpertService.pageExpertByStatusAndMeetingIds(po.page(), meetingIds, null);
if (page.getTotal() == 0) {
return PageVo.empty();
}
@@ -224,9 +222,7 @@ public class DashboardManage {
List<MeetingAndAttendStatusDTO> attendStatusList = meetingExpertService.listByExpertIdAndStatus(LoginUserUtil.getUserId(), null, null);
MeetingCountByExpertVO result = MeetingCountByExpertVO.init();
attendStatusList.forEach(w -> {
if (w.getStatus().equals(ExpertAttendStatusEnum.ON_LEAVE.getCode())) {
result.incrLeaved();
} else if (w.getAttended() != null && w.getAttended()) {
if (w.getAttended() != null && w.getAttended()) {
result.incrAttended();
} else {
result.incrToBeAttended();


+ 3
- 8
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java 파일 보기

@@ -407,11 +407,6 @@ public class ExpertInviteManage {
removeExpertIds.addAll(tempRefused);
});
}
// 被取消的也不可以被再次抽中
BizUtils.notEmpty(expertGroupByStatus.get(ExpertAttendStatusEnum.REMOVED), w -> {
List<Long> tempCanceled = CollUtils.fieldList(w, MeetingExpert::getExpertId);
removeExpertIds.addAll(tempCanceled);
});
List<Long> tempExpertIds = CollUtils.fieldList(removeExpertByCompany, MeetingExpert::getExpertId);
// 移除确认参加、通知中的、拒绝参加、已取消
userFullInfos.removeIf(w -> tempExpertIds.contains(w.getUserId()) || removeExpertIds.contains(w.getUserId()));
@@ -545,13 +540,13 @@ public class ExpertInviteManage {
if (CollectionUtils.isNotEmpty(randomRules)) {
List<ExpertInviteRule> randoms = new ArrayList<>();
List<ExpertChooseDTO> expertsByRandom = new ArrayList<>();
List<Long> choosedExpertIds = new ArrayList<>();
List<Long> chooseExpertIds = new ArrayList<>();
LocalDateTime startTime = meeting.getStartTime();
LocalDateTime endTime = meeting.getEndTime();
randomRules.forEach(rule -> {
ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoidRuled, rule, choosedExpertIds, startTime, endTime);
ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoidRuled, rule, chooseExpertIds, startTime, endTime);
expertsByRandom.add(tempExperts);
choosedExpertIds.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId));
chooseExpertIds.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId));
randoms.add(getExpertInviteRule(rule, meeting.getId()));
});
inviteRuleService.saveBatch(randoms);


+ 22
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java 파일 보기

@@ -140,6 +140,7 @@ public class MeetingManage {
}
}

@Transactional(rollbackFor = Exception.class)
public void continueInvite(Long meetingId) {
String key = "CONTINUE_INVITE:" + meetingId;
if (!distributedLock.lock(key, RETRY_TIMES)) {
@@ -157,7 +158,28 @@ public class MeetingManage {
if (!invitedContinue) {
throw BizException.wrap("抽取人员数量已满足抽取规则");
}
expertInviteTask.notifyInviteTask(meetingId);
} finally {
distributedLock.releaseLock(key);
}
}

@Transactional(rollbackFor = Exception.class)
public void convertToAppoint(Long meetingId) {
String key = "CONVERT_TO_APPOINT:" + meetingId;
if (!distributedLock.lock(key, RETRY_TIMES)) {
throw BizException.wrap("已进行转换,请勿重复点击");
}
try {
Meeting meeting = meetingService.getById(meetingId);
if (!MeetingStatusEnum.NORMAL.eq(meeting.getStatus())) {
throw BizException.wrap("转换失败,请刷新后重试");
}
expertInviteTask.cancelByMeetingId(meetingId);
LambdaUpdateWrapper<Meeting> meetingUpdate = Wrappers.lambdaUpdate(Meeting.class)
.set(Meeting::getInviteType, ExpertInviteTypeEnum.APPOINT.getCode())
.eq(Meeting::getId, meetingId);
meetingService.update(meetingUpdate);
} finally {
distributedLock.releaseLock(key);
}


+ 1
- 8
pmapi/src/main/java/com/ningdatech/pmapi/meeting/mapper/MeetingExpertMapper.xml 파일 보기

@@ -4,7 +4,7 @@

<select id="selectByExpertIdAndStatus"
resultType="com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO">
SELECT em.meeting_id meetingId, em.status, mee.is_attended attended
SELECT em.meeting_id meetingId, em.status
FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY meeting_id ORDER BY update_on DESC ) rowNumber, ID, expert_id,
status, meeting_id
FROM meeting_expert
@@ -14,14 +14,7 @@
<foreach collection="meetingIds" open="in (" close=")" item="item">#{item}</foreach>
</if>
) em
left join meeting_expert_evaluation mee on mee.expert_meeting_id = em.id
WHERE rowNumber = 1
<if test="status == 1">
AND em.status = 3 and mee.is_attended is null
</if>
<if test="status == 2">
AND em.status = 3 and mee.is_attended = true
</if>
<if test="status == 3">
AND em.status = 6
</if>


+ 7
- 0
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/IMeetingService.java 파일 보기

@@ -23,6 +23,13 @@ public interface IMeetingService extends IService<Meeting> {
**/
void stopRandomInvite(Long meetingId);

/**
* 工作台会议状态统计
*
* @param createBy 创建人
* @return 各状态会议统计
* @author WendyYang
**/
Map<MeetingStatusByDashboard, Integer> meetingCountSummary(Long createBy);

}

+ 1
- 6
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingExpertServiceImpl.java 파일 보기

@@ -59,12 +59,7 @@ public class MeetingExpertServiceImpl extends ServiceImpl<MeetingExpertMapper, M
.build();
w.forEach(item -> {
ExpertAttendStatusEnum attendStatus = ExpertAttendStatusEnum.getByCode(item.getStatus());
if (item.getInviteType().equals(ExpertInviteTypeEnum.APPOINT.getCode())) {
// 被替换和已取消的不计数
if (attendStatus.equals(ExpertAttendStatusEnum.REMOVED)
|| attendStatus.equals(ExpertAttendStatusEnum.REPLACED)) {
return;
}
if (ExpertInviteTypeEnum.APPOINT.eq(item.getInviteType())) {
confirm.setTotal(confirm.getTotal() + 1);
}
// 除通知中的均为已确认


+ 1
- 2
pmapi/src/main/java/com/ningdatech/pmapi/meeting/service/impl/MeetingServiceImpl.java 파일 보기

@@ -34,8 +34,7 @@ public class MeetingServiceImpl extends ServiceImpl<MeetingMapper, Meeting> impl
@Override
public Map<MeetingStatusByDashboard, Integer> meetingCountSummary(Long createBy) {
List<CountGroupByDTO<String>> meetingCountSummary = baseMapper.meetingCountSummary(createBy);
return CollUtils.listToMap(meetingCountSummary,
w -> MeetingStatusByDashboard.valueOf(w.getGroupKey()),
return CollUtils.listToMap(meetingCountSummary, w -> MeetingStatusByDashboard.valueOf(w.getGroupKey()),
CountGroupByDTO::getTotal);
}



+ 16
- 17
pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java 파일 보기

@@ -12,10 +12,9 @@ import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
import com.ningdatech.pmapi.meeting.entity.dto.AvoidRuleDTO;
import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO;
import com.ningdatech.pmapi.meeting.entity.dto.MeetingInviteCacheDTO;
import com.ningdatech.pmapi.meeting.entity.dto.InviteCacheDTO;
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO;
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper;
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage;
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService;
@@ -62,15 +61,10 @@ import java.util.stream.Collectors;
@AllArgsConstructor
public class ExpertInviteTask {

private final ExpertInviteHelper expertInviteHelper;
private final RandomInviteProperties properties;
private static final String MEETING_ID_INVITE_RANDOM = "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 static final Duration EXPIRE_TIME = Duration.ofDays(60);

private final CachePlusOps cachePlusOps;
@Qualifier("expertInviteScheduler")
@@ -92,6 +86,10 @@ public class ExpertInviteTask {
return (ExpertInviteTask) AopContext.currentProxy();
}

private CacheHashKey getCacheKey(Long meetingId) {
return new CacheHashKey(MEETING_ID_INVITE_RANDOM, meetingId, EXPIRE_TIME);
}

@PostConstruct
public void initTask() {
if (!properties.getEnable()) {
@@ -105,12 +103,12 @@ public class ExpertInviteTask {
* 项目重启之后重新初始化邀请任务
*/
private void initInviteTaskAfterAppStarted() {
Map<Long, MeetingInviteCacheDTO> meetingIdMap = cachePlusOps.hGetAll(CACHE_KEY);
if (MapUtils.isEmpty(meetingIdMap)) {
Map<Long, InviteCacheDTO> caches = cachePlusOps.hGetAll(getCacheKey(null));
if (MapUtils.isEmpty(caches)) {
log.info("暂无需要初始化的抽取会议信息");
return;
}
for (MeetingInviteCacheDTO cache : meetingIdMap.values()) {
for (InviteCacheDTO cache : caches.values()) {
addInviteExpertTask(cache.getMeetingId(), true, properties.getInviteDelay(), cache.getInvitedRefused());
}
}
@@ -151,16 +149,16 @@ public class ExpertInviteTask {
* @param meetingId 会议ID
* @author WendyYang
**/
public void addInviteExpertTask(Long meetingId) {
public void notifyInviteTask(Long meetingId) {
if (!INVITE_MAP.containsKey(meetingId)) {
addInviteExpertTask(meetingId, false, properties.getInviteDelay(), false);
addInviteExpertTask(meetingId, false, properties.getInviteDelay(), true);
log.info("重置会议的随机抽取状态:{}", meetingId);
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class);
update.set(Meeting::getInviteStatus, false);
update.set(Meeting::getUpdateBy, LoginUserUtil.getUserId());
update.set(Meeting::getUpdateOn, LocalDateTime.now());
update.eq(Meeting::getId, meetingId);
meetingService.update(update);
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, true);
cachePlusOps.hSet(getCacheKey(meetingId), cacheVal);
}
}

@@ -201,7 +199,8 @@ public class ExpertInviteTask {
public void addInviteExpertTaskByMeetingCreate(Long meetingId, int delayedMinutes) {
Assert.isTrue(properties.getEnable(), "随机邀请已关闭");
addInviteExpertTask(meetingId, false, delayedMinutes, false);
cachePlusOps.sAdd(CACHE_KEY, meetingId);
InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, false);
cachePlusOps.hSet(getCacheKey(meetingId), cacheVal);
}

@Transactional(rollbackFor = Exception.class)
@@ -268,7 +267,7 @@ public class ExpertInviteTask {
public void cancelByMeetingId(Long meetingId) {
log.info("终止专家抽取:{}", meetingId);
meetingService.stopRandomInvite(meetingId);
cachePlusOps.sRem(CACHE_KEY, meetingId);
cachePlusOps.hDel(getCacheKey(meetingId));
ScheduledFuture<?> future = INVITE_MAP.get(meetingId);
if (future != null) {
INVITE_MAP.remove(meetingId);


불러오는 중...
취소
저장