@@ -0,0 +1,20 @@ | |||||
package com.ningdatech.pmapi.common.model.entity; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* CountGroupByDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:44 2022/8/28 | |||||
*/ | |||||
@Data | |||||
public class CountGroupByDTO<T> { | |||||
private Integer total; | |||||
private T groupKey; | |||||
} |
@@ -5,13 +5,13 @@ import com.ningdatech.basic.util.StrPool; | |||||
import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
import org.springframework.util.NumberUtils; | import org.springframework.util.NumberUtils; | ||||
import java.util.Arrays; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
import java.util.UUID; | |||||
import java.util.*; | |||||
import java.util.function.Consumer; | import java.util.function.Consumer; | ||||
import java.util.function.Function; | |||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import static java.util.stream.Collectors.toList; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* BizUtils | * BizUtils | ||||
@@ -26,6 +26,12 @@ public class BizUtils { | |||||
} | } | ||||
public static <T extends Collection<?>> void notEmpty(T objs, Consumer<T> consumer) { | |||||
if (objs != null && !objs.isEmpty()) { | |||||
consumer.accept(objs); | |||||
} | |||||
} | |||||
public static <T extends Number> List<T> splitToNum(String str, Class<T> aClass) { | public static <T extends Number> List<T> splitToNum(String str, Class<T> aClass) { | ||||
if (StrUtil.isEmpty(str)) { | if (StrUtil.isEmpty(str)) { | ||||
return Collections.emptyList(); | return Collections.emptyList(); | ||||
@@ -46,7 +52,7 @@ public class BizUtils { | |||||
} | } | ||||
} | } | ||||
public static void notBlank(String str,Consumer<String> consumer) { | |||||
public static void notBlank(String str, Consumer<String> consumer) { | |||||
if (StrUtil.isNotBlank(str)) { | if (StrUtil.isNotBlank(str)) { | ||||
consumer.accept(str); | consumer.accept(str); | ||||
} | } | ||||
@@ -69,4 +75,34 @@ public class BizUtils { | |||||
return UUID.randomUUID().toString().replace("-", ""); | return UUID.randomUUID().toString().replace("-", ""); | ||||
} | } | ||||
/** | |||||
* 对象分组取第一条 | |||||
* | |||||
* @param objs 对象集合 | |||||
* @param group 分组函数 | |||||
* @param comparator 比较器 | |||||
* @return java.util.Collection<T> | |||||
* @author WendyYang | |||||
**/ | |||||
public static <T> Collection<T> groupFirst(Collection<T> objs, Function<T, Object> group, Comparator<T> comparator) { | |||||
return groupFirstMap(objs, group, comparator).values(); | |||||
} | |||||
/** | |||||
* 对象分组取第一条 | |||||
* | |||||
* @param objs 对象集合 | |||||
* @param group 分组函数 | |||||
* @param comparator 比较器 | |||||
* @return java.util.Collection<T> | |||||
* @author WendyYang | |||||
**/ | |||||
public static <V, K> Map<K, V> groupFirstMap(Collection<V> objs, Function<V, K> group, Comparator<V> comparator) { | |||||
return objs.stream().collect(Collectors.groupingBy(group, | |||||
Collectors.collectingAndThen(toList(), w -> { | |||||
w.sort(comparator); | |||||
return w.get(0); | |||||
}))); | |||||
} | |||||
} | } |
@@ -0,0 +1,29 @@ | |||||
package com.ningdatech.pmapi.common.util; | |||||
import cn.hutool.core.text.StrPool; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* StrUtils | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 21:23 2023/2/23 | |||||
*/ | |||||
public class StrUtils extends StrUtil { | |||||
private StrUtils() { | |||||
} | |||||
public static List<String> split(String str) { | |||||
if (isBlank(str)) { | |||||
return Collections.emptyList(); | |||||
} | |||||
return split(str, StrPool.COMMA); | |||||
} | |||||
} |
@@ -0,0 +1,20 @@ | |||||
package com.ningdatech.pmapi.expert.helper; | |||||
import lombok.RequiredArgsConstructor; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @author liuxinxin | |||||
* @date 2022/8/18 上午10:02 | |||||
* 校验是否一个账号对一个专家有操作的权限 | |||||
*/ | |||||
@Component | |||||
@RequiredArgsConstructor | |||||
public class PermissionCheckHelper { | |||||
public boolean isSuperAdmin() { | |||||
// TODO | |||||
return false; | |||||
} | |||||
} |
@@ -3,6 +3,8 @@ package com.ningdatech.pmapi.expert.service; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion; | import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion; | ||||
import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||
import java.util.List; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* 服务类 | * 服务类 | ||||
@@ -13,4 +15,14 @@ import com.baomidou.mybatisplus.extension.service.IService; | |||||
*/ | */ | ||||
public interface IExpertIntentionWorkRegionService extends IService<ExpertIntentionWorkRegion> { | public interface IExpertIntentionWorkRegionService extends IService<ExpertIntentionWorkRegion> { | ||||
/** | |||||
* 根据履职意向地或许满足履职意向地的用户ID集合 | |||||
* | |||||
* @param regionCode regionCode | |||||
* @param regionLevel regionLevel | |||||
* @return java.util.List<java.lang.Long> | |||||
* @author WendyYang | |||||
**/ | |||||
List<Long> userIdsMatchIntentionRegion(String regionCode, Integer regionLevel); | |||||
} | } |
@@ -1,11 +1,13 @@ | |||||
package com.ningdatech.pmapi.expert.service; | package com.ningdatech.pmapi.expert.service; | ||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import java.util.List; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* 服务类 | |||||
* 服务类 | |||||
* </p> | * </p> | ||||
* | * | ||||
* @author Liuxinxin | * @author Liuxinxin | ||||
@@ -21,4 +23,13 @@ public interface IExpertUserFullInfoService extends IService<ExpertUserFullInfo> | |||||
* @return / | * @return / | ||||
**/ | **/ | ||||
ExpertUserFullInfo getByUserId(Long userId); | ExpertUserFullInfo getByUserId(Long userId); | ||||
/** | |||||
* 查询用户信息 | |||||
* | |||||
* @param userId 用户ID | |||||
* @return / | |||||
**/ | |||||
List<ExpertUserFullInfo> listByUserId(List<Long> userId); | |||||
} | } |
@@ -1,14 +1,19 @@ | |||||
package com.ningdatech.pmapi.expert.service.impl; | package com.ningdatech.pmapi.expert.service.impl; | ||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion; | import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion; | ||||
import com.ningdatech.pmapi.expert.mapper.ExpertIntentionWorkRegionMapper; | import com.ningdatech.pmapi.expert.mapper.ExpertIntentionWorkRegionMapper; | ||||
import com.ningdatech.pmapi.expert.service.IExpertIntentionWorkRegionService; | import com.ningdatech.pmapi.expert.service.IExpertIntentionWorkRegionService; | ||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
import java.util.List; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* 服务实现类 | |||||
* 服务实现类 | |||||
* </p> | * </p> | ||||
* | * | ||||
* @author Liuxinxin | * @author Liuxinxin | ||||
@@ -17,4 +22,14 @@ import org.springframework.stereotype.Service; | |||||
@Service | @Service | ||||
public class ExpertIntentionWorkRegionServiceImpl extends ServiceImpl<ExpertIntentionWorkRegionMapper, ExpertIntentionWorkRegion> implements IExpertIntentionWorkRegionService { | public class ExpertIntentionWorkRegionServiceImpl extends ServiceImpl<ExpertIntentionWorkRegionMapper, ExpertIntentionWorkRegion> implements IExpertIntentionWorkRegionService { | ||||
@Override | |||||
public List<Long> userIdsMatchIntentionRegion(String regionCode, Integer regionLevel) { | |||||
LambdaQueryWrapper<ExpertIntentionWorkRegion> intentionQuery = Wrappers.lambdaQuery(ExpertIntentionWorkRegion.class) | |||||
.eq(ExpertIntentionWorkRegion::getRegionCode, regionCode) | |||||
.eq(ExpertIntentionWorkRegion::getRegionLevel, regionLevel) | |||||
.select(ExpertIntentionWorkRegion::getUserId); | |||||
List<ExpertIntentionWorkRegion> userIdMatchIntentionRegion = list(intentionQuery); | |||||
return CollUtils.fieldList(userIdMatchIntentionRegion, ExpertIntentionWorkRegion::getUserId); | |||||
} | |||||
} | } |
@@ -28,4 +28,9 @@ public class ExpertUserFullInfoServiceImpl extends ServiceImpl<NdExpertUserFullI | |||||
return getOne(Wrappers.<ExpertUserFullInfo>lambdaQuery().eq(ExpertUserFullInfo::getUserId, userId)); | return getOne(Wrappers.<ExpertUserFullInfo>lambdaQuery().eq(ExpertUserFullInfo::getUserId, userId)); | ||||
} | } | ||||
@Override | |||||
public List<ExpertUserFullInfo> listByUserId(List<Long> userIds) { | |||||
return list(Wrappers.<ExpertUserFullInfo>lambdaQuery().in(ExpertUserFullInfo::getUserId, userIds)); | |||||
} | |||||
} | } |
@@ -0,0 +1,40 @@ | |||||
package com.ningdatech.pmapi.meeting.builder; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import com.ningdatech.pmapi.user.entity.UserInfo; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteBuilder | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 21:30 2022/11/21 | |||||
*/ | |||||
public class ExpertInviteBuilder { | |||||
private ExpertInviteBuilder() { | |||||
} | |||||
public static MeetingExpert getExpertByRandom(Long meetingId, ExpertUserFullInfo user, Long ruleId) { | |||||
return getExpertBasic(meetingId, user, ruleId, ExpertInviteType.RANDOM); | |||||
} | |||||
private static MeetingExpert getExpertBasic(Long meetingId, ExpertUserFullInfo user, Long ruleId, ExpertInviteType type) { | |||||
MeetingExpert expert = new MeetingExpert(); | |||||
expert.setMeetingId(meetingId); | |||||
expert.setMobile(user.getPhoneNo()); | |||||
expert.setExpertId(user.getId()); | |||||
expert.setExpertName(user.getExpertName()); | |||||
expert.setRuleId(ruleId); | |||||
expert.setInviteType(type.getCode()); | |||||
return expert; | |||||
} | |||||
public static MeetingExpert getExpertByAppoint(Long meetingId, ExpertUserFullInfo user, Long ruleId) { | |||||
return getExpertBasic(meetingId, user, ruleId, ExpertInviteType.APPOINT); | |||||
} | |||||
} |
@@ -0,0 +1,129 @@ | |||||
//package com.ningdatech.pmapi.meeting.builder; | |||||
// | |||||
// | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
//import com.ningdatech.pmapi.sms.utils.DateUtil; | |||||
// | |||||
//import java.time.format.DateTimeFormatter; | |||||
//import java.util.ArrayList; | |||||
//import java.util.List; | |||||
// | |||||
///** | |||||
// * <p> | |||||
// * YxtSmsContextBuilder | |||||
// * </p> | |||||
// * | |||||
// * @author WendyYang | |||||
// * @since 14:19 2022/11/17 | |||||
// */ | |||||
//public class YxtSmsContextBuilder { | |||||
// | |||||
// private YxtSmsContextBuilder() { | |||||
// } | |||||
// | |||||
// public static List<SendSmsContext> smsToExpertByCancelMeeting(Meeting meeting, List<MeetingExpert> experts, String meetingType) { | |||||
// String holdCompany = meeting.getHoldCompanyBracket(); | |||||
// String meetingTime = meeting.getStartTime().format(DateUtil.DTF_YMD_HM); | |||||
// List<SendSmsContext> contexts = new ArrayList<>(); | |||||
// for (MeetingExpert me : experts) { | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.MEETING_CANCEL, | |||||
// me.getExpertName(), meeting.getCancelRemark(), meetingTime, meetingType, meeting.getContact())); | |||||
// context.setReceiveNumber(me.getMobile()); | |||||
// contexts.add(context); | |||||
// } | |||||
// return contexts; | |||||
// } | |||||
// | |||||
// public static List<SendSmsContext> smsToExpertBySendNotice(Meeting meeting, List<MeetingExpert> experts, String meetingType) { | |||||
// String holdCompany = meeting.getHoldCompanyBracket(); | |||||
// String meetingTime = meeting.getStartTime().format(DateUtil.DTF_YMD_HM); | |||||
// List<SendSmsContext> contexts = new ArrayList<>(); | |||||
// for (MeetingExpert me : experts) { | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.SEND_MEETING_NOTICE, | |||||
// me.getExpertName(), me.getUpdateOn().format(DateUtil.DTF_YMD_HM), | |||||
// meetingType, meetingTime, meeting.getRegionDetail(), meeting.getContact())); | |||||
// context.setReceiveNumber(me.getMobile()); | |||||
// contexts.add(context); | |||||
// } | |||||
// return contexts; | |||||
// } | |||||
// | |||||
// public static SendSmsContext smsToExpertByReplace(Meeting meeting, MeetingExpert expert, String meetingType) { | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// String holdCompany = meeting.getHoldCompanyBracket(); | |||||
// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.EXPERT_REPLACED, | |||||
// expert.getExpertName(), | |||||
// meeting.getStartTime().format(DateUtil.DTF_YMD_HM), | |||||
// meetingType, | |||||
// meeting.getContact() | |||||
// )); | |||||
// context.setReceiveNumber(expert.getMobile()); | |||||
// return context; | |||||
// } | |||||
// | |||||
// public static List<SendSmsContext> smsToExpertByMeetingChange(Meeting old, Meeting curr, List<MeetingExpert> experts, String meetingType) { | |||||
// List<SendSmsContext> contexts = new ArrayList<>(); | |||||
// String holdCompany = curr.getHoldCompanyBracket(); | |||||
// String sTimeOld = old.getStartTime().format(DateUtil.DTF_YMD_HM); | |||||
// String sTimeNew = curr.getStartTime().format(DateUtil.DTF_YMD_HM); | |||||
// for (MeetingExpert me : experts) { | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// String content = String.format(YxtSmsTemplateConst.MEETING_INGO_CHANGE, me.getExpertName(), | |||||
// sTimeOld, meetingType, sTimeNew, curr.getRegionDetail(), curr.getContact()); | |||||
// context.setContent(holdCompany + content); | |||||
// context.setReceiveNumber(me.getMobile()); | |||||
// contexts.add(context); | |||||
// } | |||||
// return contexts; | |||||
// } | |||||
// | |||||
// public static SendSmsContext smsToInvitorByExpertLeave(UserBasicInfo invitor, String meetingName, String expertName) { | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setReceiveNumber(invitor.getPhoneNo()); | |||||
// context.setContent(String.format(YxtSmsTemplateConst.TEMP_LEAVE_APPLY, invitor.getNickName(), | |||||
// meetingName, expertName, WebProperties.webUrl)); | |||||
// return context; | |||||
// } | |||||
// | |||||
// public static SendSmsContext smsToExpertByLeavePassed(ExpertLeave leave, String leaveUser, String mobile) { | |||||
// String smsContent = String.format(YxtSmsTemplateConst.LEAVE_APPLY_PASSED, leaveUser, | |||||
// leave.getStartTime().format(DateTimeFormatter.ofPattern(DatePattern.YMD_HMS)), | |||||
// leave.getEndTime().format(DateTimeFormatter.ofPattern(DatePattern.YMD_HMS))); | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(smsContent); | |||||
// context.setReceiveNumber(mobile); | |||||
// return context; | |||||
// } | |||||
// | |||||
// public static SendSmsContext smsToExpertBtLeaveReject(String leaveUser, String mobile, String opinion) { | |||||
// String smsContent = String.format(YxtSmsTemplateConst.LEAVE_APPLY_REFUSED, leaveUser, opinion); | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(smsContent); | |||||
// context.setReceiveNumber(mobile); | |||||
// return context; | |||||
// } | |||||
// | |||||
// public static SendSmsContext smsByRandomInviteStop(String inviterName, String meetingName, String mobile) { | |||||
// String smsContent = String.format(YxtSmsTemplateConst.RANDOM_INVITE_STOP, | |||||
// inviterName, meetingName, WebProperties.webUrl | |||||
// ); | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(smsContent); | |||||
// context.setReceiveNumber(mobile); | |||||
// return context; | |||||
// } | |||||
// | |||||
// | |||||
// public static SendSmsContext meetingInviteCompleteNotice(Meeting meeting) { | |||||
// String smsContent = String.format(YxtSmsTemplateConst.RANDOM_EXTRACTION_COMPLETED, | |||||
// meeting.getConnecter(), meeting.getName(), WebProperties.webUrl | |||||
// ); | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(smsContent); | |||||
// context.setReceiveNumber(meeting.getContact()); | |||||
// return context; | |||||
// } | |||||
//} |
@@ -0,0 +1,77 @@ | |||||
package com.ningdatech.pmapi.meeting.controller; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import com.ningdatech.basic.model.PageVo; | |||||
import com.ningdatech.log.annotation.WebLog; | |||||
import com.ningdatech.pmapi.meeting.entity.req.MeetingCalenderReq; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.*; | |||||
import com.ningdatech.pmapi.meeting.manage.DashboardManage; | |||||
import io.swagger.annotations.Api; | |||||
import io.swagger.annotations.ApiOperation; | |||||
import lombok.AllArgsConstructor; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
import org.springframework.web.bind.annotation.RequestMapping; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
import javax.validation.Valid; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* DashboardController | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 22:19 2022/8/24 | |||||
*/ | |||||
@Api(tags = "工作台相关接口") | |||||
@RestController | |||||
@AllArgsConstructor | |||||
@RequestMapping("/api/v1/dashboard") | |||||
public class DashboardController { | |||||
private final DashboardManage dashboardManage; | |||||
@ApiOperation("会议日历") | |||||
@GetMapping("/meetingCalender") | |||||
@WebLog(value = "会议日历") | |||||
public List<MeetingCalenderItemVO> meetingCalender(@Valid MeetingCalenderReq po) { | |||||
return dashboardManage.meetingCalender(po); | |||||
} | |||||
@ApiOperation("待办:专家评价列表") | |||||
@GetMapping("/todo/expertEvaluation") | |||||
@WebLog(value = "待办:专家评价列表") | |||||
public PageVo<ExpertEvaluationToDoListItemVO> expertEvaluationToDo(PagePo po) { | |||||
return dashboardManage.expertEvaluationToDo(po); | |||||
} | |||||
@ApiOperation("待办:专家待替换列表") | |||||
@GetMapping("/todo/expertReplace") | |||||
@WebLog(value = "待办:专家待替换列表") | |||||
public PageVo<ExpertReplaceTodoListItemVO> expertReplaceToDo(PagePo po) { | |||||
return dashboardManage.expertReplaceTodoList(po); | |||||
} | |||||
@ApiOperation("待办:专家待确认列表") | |||||
@GetMapping("/todo/expertConfirm") | |||||
@WebLog(value = "待办:专家待确认列表") | |||||
public PageVo<MeetingConfirmToDoListItemVO> expertConfirmToDo(PagePo po) { | |||||
return dashboardManage.expertConfirmToDo(po); | |||||
} | |||||
@ApiOperation("会议数量统计") | |||||
@GetMapping("/meetingCountSummary") | |||||
@WebLog(value = "会议数量统计") | |||||
public MeetingCountSummaryVO meetingCountSummary() { | |||||
return dashboardManage.meetingCountSummary(); | |||||
} | |||||
@ApiOperation("专家工作台:会议数量统计") | |||||
@GetMapping("/meetingCountByExpert") | |||||
@WebLog(value = "专家工作台:会议数量统计") | |||||
public MeetingCountByExpertVO meetingCountByExpert() { | |||||
return dashboardManage.meetingCountByExpert(); | |||||
} | |||||
} |
@@ -0,0 +1,173 @@ | |||||
package com.ningdatech.pmapi.meeting.controller; | |||||
import com.ningdatech.basic.model.IdVo; | |||||
import com.ningdatech.basic.model.PageVo; | |||||
import com.ningdatech.log.annotation.WebLog; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingBasicDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.req.*; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.*; | |||||
import com.ningdatech.pmapi.meeting.manage.MeetingManage; | |||||
import io.swagger.annotations.Api; | |||||
import io.swagger.annotations.ApiOperation; | |||||
import lombok.AllArgsConstructor; | |||||
import org.springframework.validation.annotation.Validated; | |||||
import org.springframework.web.bind.annotation.*; | |||||
import javax.validation.Valid; | |||||
/** | |||||
* <p> | |||||
* 会议 前端控制器 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Validated | |||||
@RestController | |||||
@AllArgsConstructor | |||||
@Api(tags = "会议管理") | |||||
@RequestMapping("/api/v1/meeting") | |||||
public class MeetingController { | |||||
private final MeetingManage meetingManage; | |||||
@PostMapping("/save") | |||||
@ApiOperation("新建会议") | |||||
@WebLog(value = "新建会议") | |||||
public IdVo<Long> meetingCreate(@Valid @RequestBody MeetingBasicDTO po) { | |||||
return meetingManage.save(po); | |||||
} | |||||
@PostMapping("/expertInviteByCreate") | |||||
@ApiOperation("新建会议-专家抽取") | |||||
@WebLog(value = "新建会议-专家抽取") | |||||
public void expertInviteByCreate(@Valid @RequestBody ExpertInviteCreateReq po) { | |||||
meetingManage.expertInviteByCreate(po); | |||||
} | |||||
@ApiOperation("专家抽取数量校验") | |||||
@PostMapping("/expertCountOnChange") | |||||
public ExpertCountOnChangeVO expertCountOnChange(@RequestBody ExpertInviteCreateReq po) { | |||||
return meetingManage.expertCountOnChange(po); | |||||
} | |||||
@ApiOperation("专家抽取员事务列表") | |||||
@GetMapping("/meetingListByManager") | |||||
@WebLog(value = "专家抽取员事务列表") | |||||
public PageVo<MeetingByManagerVO> meetingListByManager(MeetingListReq po) { | |||||
return meetingManage.meetingListByManager(po); | |||||
} | |||||
@ApiOperation("履职记录 | 专家会议列表") | |||||
@GetMapping("/meetingListByExpert") | |||||
@WebLog(value = "履职记录 | 专家会议列表") | |||||
public PageVo<MeetingByManagerVO> meetingListByExpert(MeetingListReq po) { | |||||
return meetingManage.meetingListByExpert(po); | |||||
} | |||||
@ApiOperation("会议详情-基本信息") | |||||
@GetMapping("detail/{meetingId}/basicInfo") | |||||
@WebLog(value = "会议详情-基本信息") | |||||
public MeetingDetailBasicVO meetingBasic(@PathVariable Long meetingId) { | |||||
return meetingManage.getMeetingBasicInfo(meetingId); | |||||
} | |||||
@ApiOperation("会议结果上传") | |||||
@PostMapping("/uploadMeetingResult") | |||||
@WebLog(value = "会议结果上传") | |||||
public void uploadMeetingResult(@Valid @RequestBody MeetingResultReq po) { | |||||
meetingManage.uploadMeetingResult(po); | |||||
} | |||||
@ApiOperation("会议结果详情") | |||||
@GetMapping("/detail/{meetingId}/meetingResult") | |||||
@WebLog(value = "会议结果详情况") | |||||
public MeetingResultVO meetingResultDetail(@PathVariable Long meetingId) { | |||||
return meetingManage.meetingResultDetail(meetingId); | |||||
} | |||||
@ApiOperation("邀请情况详情") | |||||
@GetMapping("/detail/{meetingId}/inviteDetail") | |||||
@WebLog(value = "邀请情况详请") | |||||
public ExpertInviteDetailVO inviteDetail(@PathVariable Long meetingId) { | |||||
return meetingManage.inviteDetail(meetingId); | |||||
} | |||||
@ApiOperation("会议基础信息修改") | |||||
@PostMapping("/basicInfo/modify") | |||||
@WebLog(value = "会议基础信息修改") | |||||
public void meetingBasicInfoModify(@Valid @RequestBody MeetingBasicInfoModifyReq po) { | |||||
meetingManage.meetingBasicInfoModify(po); | |||||
} | |||||
@ApiOperation("会议详情-抽取规则") | |||||
@GetMapping("/detail/inviteRule/{meetingId}") | |||||
@WebLog(value = "会议详情-抽取规则") | |||||
public InviteRuleDetailVO inviteRuleDetail(@PathVariable Long meetingId) { | |||||
return meetingManage.inviteRuleDetail(meetingId); | |||||
} | |||||
@ApiOperation("专家移除") | |||||
@PostMapping("/expertRemove") | |||||
@WebLog(value = "专家移除") | |||||
public void expertRemove(@RequestBody ExpertRemoveReq po) { | |||||
meetingManage.expertRemove(po); | |||||
} | |||||
@ApiOperation("专家替换") | |||||
@PostMapping("/expertReplace") | |||||
@WebLog(value = "专家替换") | |||||
public void expertReplace(@RequestBody ExpertRemoveReq po) { | |||||
meetingManage.expertReplace(po); | |||||
} | |||||
@ApiOperation("确认名单(下发会议通知)") | |||||
@GetMapping("/sendMeetingNotice/{meetingId}") | |||||
@WebLog(value = "确认名单(下发会议通知") | |||||
public void sendMeetingNotice(@PathVariable Long meetingId) { | |||||
meetingManage.sendMeetingNotice(meetingId); | |||||
} | |||||
@ApiOperation("停止抽取") | |||||
@GetMapping("/stopInvite/{meetingId}") | |||||
@WebLog(value = "停止抽取") | |||||
public void stopInvite(@PathVariable Long meetingId) { | |||||
meetingManage.stopRandomInvite(meetingId); | |||||
} | |||||
@ApiOperation("取消会议") | |||||
@PostMapping("/cancelMeeting") | |||||
@WebLog(value = "取消会议") | |||||
public void cancelMeeting(@Valid @RequestBody MeetingCancelReq po) { | |||||
meetingManage.cancelMeeting(po); | |||||
} | |||||
@ApiOperation("邀请函信息") | |||||
@GetMapping("/expertInvitationDetail") | |||||
@WebLog(value = "邀请函信息") | |||||
public ExpertInvitationDetailVO expertInvitationDetail(@RequestParam("meetingId") Long meetingId, | |||||
@RequestParam(required = false) Long expertId) { | |||||
return meetingManage.expertInvitationDetail(meetingId, expertId); | |||||
} | |||||
@ApiOperation("批量补充专家") | |||||
@PostMapping("batchAppointExperts") | |||||
@WebLog(value = "批量补充专家") | |||||
public void batchAppointExperts(@Valid @RequestBody BatchAppointExpertsReq po) { | |||||
meetingManage.batchAppointExperts(po); | |||||
} | |||||
@ApiOperation("确认参加") | |||||
@PostMapping("/confirmAttendByManager") | |||||
@WebLog(value = "确认参加") | |||||
public void confirmAttendByManager(@RequestBody ExpertRemoveReq po) { | |||||
meetingManage.confirmAttendByManager(po); | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.config; | |||||
import lombok.Data; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* <p> | |||||
* SystemProperties | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 14:39 2022/9/15 | |||||
*/ | |||||
@Data | |||||
@Component | |||||
public class WebProperties { | |||||
public static String webUrl; | |||||
public static String provincialUrl; | |||||
@Value("${web.url:}") | |||||
private void setWebUrl(String url) { | |||||
webUrl = url; | |||||
} | |||||
/** | |||||
* 省局项目管理调用跳转地址 | |||||
*/ | |||||
@Value("${web.provincial:}") | |||||
private void setProvincial(String provincial) { | |||||
provincialUrl = provincial; | |||||
} | |||||
} |
@@ -0,0 +1,56 @@ | |||||
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 io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteAvoidRule | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Data | |||||
@TableName("meeting_expert_invite_avoid_rule") | |||||
@ApiModel(value = "ExpertInviteAvoidRule对象") | |||||
public class ExpertInviteAvoidRule implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
@ApiModelProperty("事务ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("回避专家ID") | |||||
private String expertIds; | |||||
@ApiModelProperty("回避单位名称") | |||||
private String companyIds; | |||||
@ApiModelProperty("回避本单位同事") | |||||
private Boolean avoidMates; | |||||
@ApiModelProperty("创建人ID") | |||||
private Long createBy; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("修改时间") | |||||
private LocalDateTime updateOn; | |||||
@ApiModelProperty("修改人ID") | |||||
private Long updateBy; | |||||
} |
@@ -0,0 +1,54 @@ | |||||
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 io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.time.LocalDateTime; | |||||
import java.time.LocalTime; | |||||
/** | |||||
* <p> | |||||
* 专家抽取免打扰时间设置 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-11-21 | |||||
*/ | |||||
@Data | |||||
@TableName("expert_invite_ignore_time") | |||||
@ApiModel(value = "ExpertInviteIgnoreTime对象", description = "专家抽取免打扰时间设置") | |||||
public class ExpertInviteIgnoreTime implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
@ApiModelProperty("是否启用") | |||||
private Boolean enable; | |||||
@ApiModelProperty("开始时间") | |||||
private LocalTime startTime; | |||||
@ApiModelProperty("截止时间") | |||||
private LocalTime endTime; | |||||
@ApiModelProperty("创建人ID") | |||||
private Long createBy; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("修改人ID") | |||||
private Long updateBy; | |||||
@ApiModelProperty("修改时间") | |||||
private LocalDateTime updateOn; | |||||
} |
@@ -0,0 +1,55 @@ | |||||
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 io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteRule | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Data | |||||
@TableName("meeting_expert_invite_rule") | |||||
@ApiModel(value = "ExpertInviteRule对象") | |||||
public class ExpertInviteRule implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
private Long meetingId; | |||||
@ApiModelProperty("抽取规则") | |||||
private String inviteRule; | |||||
@ApiModelProperty("创建人ID") | |||||
private Long createBy; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("修改时间") | |||||
private LocalDateTime updateOn; | |||||
@ApiModelProperty("修改人ID") | |||||
private Long updateBy; | |||||
@ApiModelProperty("抽取类型:1 自定义规则、2 指定邀请") | |||||
private Integer inviteType; | |||||
@ApiModelProperty("抽取数量") | |||||
private Integer inviteCount; | |||||
} |
@@ -0,0 +1,116 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.domain; | |||||
import com.baomidou.mybatisplus.annotation.*; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* 会议-实体 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Data | |||||
@TableName("meeting") | |||||
@ApiModel(value = "Meeting对象", description = "会议") | |||||
public class Meeting implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
@ApiModelProperty("事务名称") | |||||
private String name; | |||||
@ApiModelProperty("事务类型") | |||||
private String type; | |||||
@ApiModelProperty("开始时间") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("结束时间") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("地区编码") | |||||
private String regionCode; | |||||
@ApiModelProperty("地区层级") | |||||
private Integer regionLevel; | |||||
@ApiModelProperty("地区详情") | |||||
private String regionDetail; | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@ApiModelProperty("事务说明") | |||||
private String description; | |||||
@ApiModelProperty("附件") | |||||
private String attachment; | |||||
@ApiModelProperty("备注") | |||||
private String remark; | |||||
@ApiModelProperty("创建人ID") | |||||
@TableField(fill = FieldFill.INSERT) | |||||
private Long createBy; | |||||
@ApiModelProperty("创建时间") | |||||
@TableField(fill = FieldFill.INSERT) | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("修改人ID") | |||||
@TableField(fill = FieldFill.INSERT_UPDATE) | |||||
private Long updateBy; | |||||
@ApiModelProperty("修改时间") | |||||
@TableField(fill = FieldFill.INSERT_UPDATE) | |||||
private LocalDateTime updateOn; | |||||
@ApiModelProperty("创建人") | |||||
private String author; | |||||
@ApiModelProperty("创建人地区编码") | |||||
private String authorRegionCode; | |||||
@ApiModelProperty("创建人地区层级") | |||||
private Integer authorRegionLevel; | |||||
private Integer status; | |||||
private String resultDescription; | |||||
private String resultAttachment; | |||||
@ApiModelProperty("是否下发会议通知") | |||||
private Boolean sendMeetingNotice; | |||||
@ApiModelProperty("是否停止随机邀请") | |||||
private Boolean stopRandomInvite; | |||||
@ApiModelProperty("是否进行了专家抽取") | |||||
private Boolean invited; | |||||
@ApiModelProperty("取消说明") | |||||
private String cancelRemark; | |||||
@ApiModelProperty("举办单位") | |||||
private String holdCompany; | |||||
public String getHoldCompanyBracket() { | |||||
return "(" + this.getHoldCompany() + ")"; | |||||
} | |||||
} |
@@ -0,0 +1,73 @@ | |||||
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 io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
import java.io.Serializable; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* 事务专家表 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-27 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@TableName("meeting_expert") | |||||
@ApiModel(value = "MeetingExpert对象", description = "事务专家表") | |||||
public class MeetingExpert implements Serializable { | |||||
@Tolerate | |||||
public MeetingExpert() { | |||||
} | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
@ApiModelProperty("事务ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("专家ID") | |||||
private Long expertId; | |||||
@ApiModelProperty("邀请规则ID") | |||||
private Long ruleId; | |||||
private String mobile; | |||||
@ApiModelProperty("当前状态") | |||||
private Integer status; | |||||
@ApiModelProperty("前一个状态") | |||||
private Integer preStatus; | |||||
private Long preId; | |||||
@ApiModelProperty("邀请类型") | |||||
private Integer inviteType; | |||||
private Long createBy; | |||||
private LocalDateTime createOn; | |||||
private Long updateBy; | |||||
private LocalDateTime updateOn; | |||||
private String submitKey; | |||||
private String expertName; | |||||
} |
@@ -0,0 +1,66 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.domain; | |||||
import com.baomidou.mybatisplus.annotation.IdType; | |||||
import com.baomidou.mybatisplus.annotation.TableField; | |||||
import com.baomidou.mybatisplus.annotation.TableId; | |||||
import com.baomidou.mybatisplus.annotation.TableName; | |||||
import com.ningdatech.pmapi.sys.model.entity.BaseEntity; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
/** | |||||
* <p> | |||||
* 专家评价表 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-25 | |||||
*/ | |||||
@Data | |||||
@TableName("meeting_expert_evaluation") | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel(value = "MeetingExpertEvaluation对象", description = "专家评价表") | |||||
public class MeetingExpertEvaluation extends BaseEntity { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("主键") | |||||
@TableId(type = IdType.AUTO) | |||||
private Long id; | |||||
@ApiModelProperty("专家事务关联ID") | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("事务ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("专家ID") | |||||
private Long expertId; | |||||
@TableField(value = "is_attended") | |||||
@ApiModelProperty("是否参加") | |||||
private Boolean attended; | |||||
@TableField(value = "is_in_time") | |||||
@ApiModelProperty("是否准时参加") | |||||
private Boolean inTime; | |||||
@TableField(value = "is_violated") | |||||
@ApiModelProperty("是否违规") | |||||
private Boolean violated; | |||||
@ApiModelProperty("参与程度") | |||||
private Integer initiative; | |||||
@ApiModelProperty("建设性建议") | |||||
private String advice; | |||||
@ApiModelProperty("评审结果情况") | |||||
private String evaluateResult; | |||||
@ApiModelProperty("违规情况") | |||||
private String violation; | |||||
} |
@@ -0,0 +1,39 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotNull; | |||||
/** | |||||
* <p> | |||||
* AbstractExpertExtractRule | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:10 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("抽取规则") | |||||
public abstract class AbstractInviteRule { | |||||
@ApiModelProperty("id") | |||||
private Long id; | |||||
@ApiModelProperty("专家抽取数量") | |||||
@NotNull(message = "专家抽取数量不能为空", groups = {RuleSave.class}) | |||||
private Integer count; | |||||
@ApiModelProperty("抽取类型:1 随机抽取、2 指定抽取") | |||||
@NotNull(message = "抽取类型不能为空", groups = {RuleSave.class, CountCheck.class}) | |||||
private Integer inviteType; | |||||
public interface RuleSave { | |||||
} | |||||
public interface CountCheck { | |||||
} | |||||
} |
@@ -0,0 +1,34 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import lombok.ToString; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* AppointExtractRuleDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:19 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@ToString(callSuper = true) | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel("指定抽取规则") | |||||
public class AppointInviteRuleDTO extends AbstractInviteRule { | |||||
@NotEmpty(message = "邀请说明不能为空", groups = {RuleSave.class}) | |||||
@ApiModelProperty("邀请说明") | |||||
private String inviteDesc; | |||||
@NotEmpty(message = "专家ID不能为空", groups = {RuleSave.class, CountCheck.class}) | |||||
@ApiModelProperty("专家ID") | |||||
private List<Long> expertIds; | |||||
} |
@@ -0,0 +1,60 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* AvoidInfoDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:22 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("回避信息") | |||||
public class AvoidInfoDTO { | |||||
@ApiModelProperty("回避单位") | |||||
@NotEmpty(message = "回避单位不能为空", groups = {AbstractInviteRule.RuleSave.class}) | |||||
private List<String> companyIds; | |||||
@ApiModelProperty("是否回避同单位其他专家") | |||||
@NotNull(message = "是否回避同单位其他专家不能为空") | |||||
private Boolean avoidMates; | |||||
@ApiModelProperty("回避专家ID") | |||||
private List<Long> expertIds; | |||||
/** | |||||
* 返回一个默认值,仅在前端未传值时使用 | |||||
* | |||||
* @return / | |||||
*/ | |||||
public static AvoidInfoDTO defVal() { | |||||
AvoidInfoDTO val = new AvoidInfoDTO(); | |||||
val.setAvoidMates(false); | |||||
val.setCompanyIds(Collections.emptyList()); | |||||
val.setExpertIds(Collections.emptyList()); | |||||
return val; | |||||
} | |||||
public void initDefVal() { | |||||
if (this.avoidMates == null) { | |||||
this.setAvoidMates(false); | |||||
} | |||||
if (this.companyIds == null) { | |||||
this.setCompanyIds(Collections.emptyList()); | |||||
} | |||||
if (this.expertIds == null) { | |||||
this.setExpertIds(Collections.emptyList()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
/** | |||||
* <p> | |||||
* CountConfirmByMeetingIdDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 14:21 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@AllArgsConstructor | |||||
public class CountConfirmByMeetingIdDTO { | |||||
@Tolerate | |||||
public CountConfirmByMeetingIdDTO() { | |||||
} | |||||
private Long meetingId; | |||||
private Integer total; | |||||
private Integer confirmed; | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertChooseDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 00:44 2022/7/27 | |||||
*/ | |||||
@Data | |||||
@AllArgsConstructor | |||||
public class ExpertChooseDTO { | |||||
private List<ExpertUserFullInfo> experts; | |||||
private Integer total; | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertDictChooseDTO | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:49 2022/8/9 | |||||
*/ | |||||
@Data | |||||
public class ExpertDictChooseDTO { | |||||
@ApiModelProperty("专家字典类型") | |||||
private String expertDict; | |||||
@ApiModelProperty("字典编码") | |||||
private List<String> dictCodes; | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertTagChooseDTO | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 19:45 2022/7/26 | |||||
*/ | |||||
@Data | |||||
public class ExpertTagChooseDTO { | |||||
@ApiModelProperty("专家标签") | |||||
private String expertTag; | |||||
@ApiModelProperty("标签编码") | |||||
private List<String> tagCodes; | |||||
} |
@@ -0,0 +1,22 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* MeetingAndAttendStatusDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 22:48 2022/8/22 | |||||
*/ | |||||
@Data | |||||
public class MeetingAndAttendStatusDTO { | |||||
private Long meetingId; | |||||
private Integer status; | |||||
private Boolean attended; | |||||
} |
@@ -0,0 +1,80 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.time.LocalDateTime; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingBasicDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 09:35 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("会议基本信息") | |||||
public class MeetingBasicDTO { | |||||
@NotEmpty(message = "抽取单位不能为空") | |||||
@ApiModelProperty("抽取单位") | |||||
private String inviterCompany; | |||||
@NotEmpty(message = "事务名称不能为空") | |||||
@ApiModelProperty("事务名称") | |||||
private String name; | |||||
@NotEmpty(message = "事务类型不能为空") | |||||
@ApiModelProperty("事务类型") | |||||
private String type; | |||||
@NotNull(message = "开始时间不能为空") | |||||
@ApiModelProperty("开始时间") | |||||
private LocalDateTime startTime; | |||||
@NotNull(message = "结束时间不能为空") | |||||
@ApiModelProperty("结束时间") | |||||
private LocalDateTime endTime; | |||||
@NotEmpty(message = "地区编码不能为空") | |||||
@ApiModelProperty("地区编码") | |||||
private String regionCode; | |||||
@NotNull(message = "地区编码层级不能为空") | |||||
@ApiModelProperty("地区编码层级") | |||||
private Integer regionLevel; | |||||
@NotEmpty(message = "地址详情不能为空") | |||||
@ApiModelProperty("地址详情") | |||||
private String regionDetail; | |||||
@NotEmpty(message = "联系人不能为空") | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@NotEmpty(message = "联系方式不能为空") | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@NotEmpty(message = "事务说明不能为空") | |||||
@ApiModelProperty("事务说明") | |||||
private String description; | |||||
@ApiModelProperty("附件ID") | |||||
private List<String> attachmentIds; | |||||
@ApiModelProperty("备注") | |||||
private String remark; | |||||
@ApiModelProperty("创建人") | |||||
private String author; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
} |
@@ -0,0 +1,46 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* RandomExtractRuleDto | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:18 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel("随机抽取规则") | |||||
public class RandomInviteRuleDTO extends AbstractInviteRule { | |||||
@ApiModelProperty("专家字典信息") | |||||
private List<ExpertDictChooseDTO> expertDicts; | |||||
@ApiModelProperty("履职意向地编码") | |||||
private String intentionRegionCode; | |||||
@ApiModelProperty("履职意向地层级") | |||||
private Integer intentionRegionLevel; | |||||
@ApiModelProperty("专家层级编码") | |||||
private String expertRegionCode; | |||||
@ApiModelProperty("专家层级级别") | |||||
private Integer expertRegionLevel; | |||||
@ApiModelProperty("专家标签") | |||||
private List<ExpertTagChooseDTO> expertTags; | |||||
@ApiModelProperty("专家最长响应时间") | |||||
@NotNull(message = "专家最长响应时间不能为空", groups = {RuleSave.class}) | |||||
private Integer waitForCallbackMinutes; | |||||
} |
@@ -0,0 +1,45 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.enumeration; | |||||
import lombok.Getter; | |||||
import java.util.Arrays; | |||||
/** | |||||
* <p> | |||||
* ExpertAttendStatus | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 09:23 2022/8/9 | |||||
*/ | |||||
@Getter | |||||
public enum ExpertAttendStatus { | |||||
NOTICING("通知中", 0), | |||||
NOT_ANSWERED("未应答", 1), | |||||
REPLACED("已替换", 2), | |||||
AGREED("同意参加", 3), | |||||
REFUSED("拒绝参加", 4), | |||||
CANCELED("已移除", 5), | |||||
ON_LEAVE("已请假", 6); | |||||
private final Integer code; | |||||
private final String desc; | |||||
ExpertAttendStatus(String desc, Integer code) { | |||||
this.code = code; | |||||
this.desc = desc; | |||||
} | |||||
public boolean eq(Integer code) { | |||||
return this.getCode().equals(code); | |||||
} | |||||
public static ExpertAttendStatus getByCode(Integer code) { | |||||
return Arrays.stream(values()) | |||||
.filter(w -> w.eq(code)) | |||||
.findFirst() | |||||
.orElseThrow(() -> new IllegalArgumentException("无效的邀请状态")); | |||||
} | |||||
} |
@@ -0,0 +1,39 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.enumeration; | |||||
import lombok.Getter; | |||||
import java.util.Arrays; | |||||
/** | |||||
* <p> | |||||
* ExpertExtractRuleType | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:11 2022/7/26 | |||||
*/ | |||||
@Getter | |||||
public enum ExpertInviteType { | |||||
/** | |||||
* 专家抽取类型 | |||||
*/ | |||||
RANDOM(1, "随机邀请"), | |||||
APPOINT(2, "指定邀请"); | |||||
private final Integer code; | |||||
private final String name; | |||||
ExpertInviteType(Integer code, String name) { | |||||
this.code = code; | |||||
this.name = name; | |||||
} | |||||
public static ExpertInviteType getByCode(Integer code) { | |||||
return Arrays.stream(values()) | |||||
.filter(w -> w.getCode().equals(code)) | |||||
.findFirst() | |||||
.orElseThrow(() -> new IllegalArgumentException("无效的邀请类型")); | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.enumeration; | |||||
import lombok.Getter; | |||||
import java.util.Arrays; | |||||
/** | |||||
* <p> | |||||
* MeetingDateTermType-会议日期类型 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 09:54 2022/8/15 | |||||
*/ | |||||
@Getter | |||||
public enum MeetingDateTermType { | |||||
ONE_DAY(1, "一天"), | |||||
MORE_THAN_ONE(2, "两天及以上"); | |||||
private final Integer code; | |||||
private final String name; | |||||
MeetingDateTermType(Integer code, String name) { | |||||
this.code = code; | |||||
this.name = name; | |||||
} | |||||
public static MeetingDateTermType getByCode(Integer code) { | |||||
return Arrays.stream(values()) | |||||
.filter(w -> w.getCode().equals(code)) | |||||
.findFirst() | |||||
.orElseThrow(() -> new IllegalArgumentException("无效的会议日期类型编码")); | |||||
} | |||||
} |
@@ -0,0 +1,73 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.enumeration; | |||||
import lombok.Getter; | |||||
import java.util.Arrays; | |||||
/** | |||||
* <p> | |||||
* MeetingStatus | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 11:14 2022/8/8 | |||||
*/ | |||||
public class MeetingStatus { | |||||
/** | |||||
* 管理员事务列表:事务状态 | |||||
*/ | |||||
@Getter | |||||
public enum Manager { | |||||
UNCOMPLETED("未完成", 1), | |||||
COMPLETED("已完成", 2), | |||||
CANCELED("已取消", 3); | |||||
private final String desc; | |||||
private final Integer code; | |||||
Manager(String desc, Integer code) { | |||||
this.desc = desc; | |||||
this.code = code; | |||||
} | |||||
public boolean eq(Integer code) { | |||||
return this.getCode().equals(code); | |||||
} | |||||
public static Manager getByCode(Integer code) { | |||||
return Arrays.stream(values()) | |||||
.filter(w -> w.getCode().equals(code)) | |||||
.findFirst() | |||||
.orElseThrow(() -> new IllegalArgumentException("状态编码")); | |||||
} | |||||
} | |||||
@Getter | |||||
public enum Expert { | |||||
TO_ATTEND("待参加", 1), | |||||
ATTENDED("已参加", 2), | |||||
ON_LEAVE("已请假", 3), | |||||
UN_ATTEND("缺席", 4); | |||||
private final String desc; | |||||
private final Integer code; | |||||
Expert(String desc, Integer code) { | |||||
this.desc = desc; | |||||
this.code = code; | |||||
} | |||||
public static Expert getByCode(Integer code) { | |||||
return Arrays.stream(values()) | |||||
.filter(w -> w.getCode().equals(code)) | |||||
.findFirst() | |||||
.orElseThrow(() -> new IllegalArgumentException("状态编码")); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.enumeration; | |||||
/** | |||||
* <p> | |||||
* MeetingStatusByDashboard | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 14:02 2022/8/30 | |||||
*/ | |||||
public enum MeetingStatusByDashboard { | |||||
/** | |||||
* 已完成 | |||||
*/ | |||||
COMPLETED, | |||||
/** | |||||
* 已取消 | |||||
*/ | |||||
CANCELED, | |||||
/** | |||||
* 待召开 | |||||
*/ | |||||
TO_BE_HELD, | |||||
/** | |||||
* 已召开 | |||||
*/ | |||||
HELD | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* BatchAppointExpertsPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:49 2022/8/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("补充专家参数实体") | |||||
public class BatchAppointExpertsReq { | |||||
@NotEmpty(message = "专家ID不能为空") | |||||
@ApiModelProperty("专家ID") | |||||
private List<Long> expertIds; | |||||
@NotNull(message = "会议ID不能为空") | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
} |
@@ -0,0 +1,49 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotNull; | |||||
/** | |||||
* <p> | |||||
* ExpertEvaluationPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:30 2022/7/25 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家评价实体") | |||||
public class ExpertEvaluationReq { | |||||
@ApiModelProperty("专家事务关联ID") | |||||
@NotNull(message = "专家事务关联ID不能为空") | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("是否参加") | |||||
@NotNull(message = "是否参加不能为空") | |||||
private Boolean attended; | |||||
@ApiModelProperty("是否准时参加") | |||||
private Boolean inTime; | |||||
@ApiModelProperty("是否违规") | |||||
@NotNull(message = "是否违规不能为空") | |||||
private Boolean violated; | |||||
@ApiModelProperty("违规情况") | |||||
private String violation; | |||||
@ApiModelProperty("参与程度:1 很积极...5 很消极") | |||||
@NotNull(message = "参与程度不能为空") | |||||
private Integer initiative; | |||||
@ApiModelProperty("建设性的建议") | |||||
private String advice; | |||||
@ApiModelProperty("评审结果") | |||||
private String evaluateResult; | |||||
} |
@@ -0,0 +1,43 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AbstractInviteRule; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.Valid; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingCreatePo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:32 2022/7/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家抽取新家实体") | |||||
public class ExpertInviteCreateReq { | |||||
@NotNull(message = "会议ID不能为空", groups = {AbstractInviteRule.RuleSave.class, AbstractInviteRule.CountCheck.class}) | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@Valid | |||||
@ApiModelProperty("回避信息") | |||||
private AvoidInfoDTO avoidInfo; | |||||
@Valid | |||||
@ApiModelProperty("随机抽取规则") | |||||
private List<RandomInviteRuleDTO> randomRules; | |||||
@Valid | |||||
@ApiModelProperty("指定抽取规则") | |||||
private AppointInviteRuleDTO appointRule; | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.time.LocalTime; | |||||
/** | |||||
* <p> | |||||
* 专家抽取免打扰时间设置 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-11-21 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家抽取免打扰时间设置") | |||||
public class ExpertInviteIgnoreTimeModifyReq { | |||||
@ApiModelProperty("主键") | |||||
private Long id; | |||||
@ApiModelProperty("是否启用:true 是、false 否") | |||||
private Boolean enable; | |||||
@ApiModelProperty("开始时间(格式:HH:mm)") | |||||
@JSONField(format = "HH:mm") | |||||
private LocalTime startTime; | |||||
@ApiModelProperty("截止时间(格式:HH:mm)") | |||||
@JSONField(format = "HH:mm") | |||||
private LocalTime endTime; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* ExpertRemovePo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 08:59 2022/8/10 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家(移除/替换)实体") | |||||
public class ExpertRemoveReq { | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("专家ID") | |||||
private Long expertId; | |||||
@ApiModelProperty("专家会议ID") | |||||
private Long expertMeetingId; | |||||
} |
@@ -0,0 +1,82 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.time.LocalDateTime; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingBasicInfoModifyPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 11:15 2022/8/17 | |||||
*/ | |||||
@Data | |||||
public class MeetingBasicInfoModifyReq { | |||||
@NotEmpty(message = "抽取单位不能为空") | |||||
@ApiModelProperty("抽取单位") | |||||
private String inviterCompany; | |||||
@ApiModelProperty("会议ID") | |||||
@NotNull(message = "会议ID不能为空") | |||||
private Long id; | |||||
@NotEmpty(message = "会议名称不能为空") | |||||
@ApiModelProperty("会议名称") | |||||
private String name; | |||||
@NotEmpty(message = "会议类型不能为空") | |||||
@ApiModelProperty("会议类型") | |||||
private String type; | |||||
@NotNull(message = "开始时间不能为空") | |||||
@ApiModelProperty("开始时间") | |||||
private LocalDateTime startTime; | |||||
@NotNull(message = "结束时间不能为空") | |||||
@ApiModelProperty("结束时间") | |||||
private LocalDateTime endTime; | |||||
@NotEmpty(message = "地区编码不能为空") | |||||
@ApiModelProperty("地区编码") | |||||
private String regionCode; | |||||
@NotNull(message = "地区编码层级不能为空") | |||||
@ApiModelProperty("地区编码层级") | |||||
private Integer regionLevel; | |||||
@NotEmpty(message = "地址详情不能为空") | |||||
@ApiModelProperty("地址详情") | |||||
private String regionDetail; | |||||
@NotEmpty(message = "联系人不能为空") | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@NotEmpty(message = "联系方式不能为空") | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@NotEmpty(message = "会议说明不能为空") | |||||
@ApiModelProperty("会议说明") | |||||
private String description; | |||||
@ApiModelProperty("附件ID") | |||||
private List<String> attachmentIds; | |||||
@ApiModelProperty("备注") | |||||
private String remark; | |||||
@ApiModelProperty("创建人") | |||||
private String author; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import lombok.Data; | |||||
import org.springframework.format.annotation.DateTimeFormat; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.time.LocalDate; | |||||
/** | |||||
* <p> | |||||
* MeetingCalenderPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 22:38 2022/8/24 | |||||
*/ | |||||
@Data | |||||
public class MeetingCalenderReq { | |||||
@NotNull(message = "开始日期不能为空") | |||||
@DateTimeFormat(pattern = "yyyy-MM-dd") | |||||
private LocalDate startDate; | |||||
@NotNull(message = "结束日期不能为空") | |||||
@DateTimeFormat(pattern = "yyyy-MM-dd") | |||||
private LocalDate endDate; | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotBlank; | |||||
import javax.validation.constraints.NotNull; | |||||
/** | |||||
* <p> | |||||
* MeetingCancelPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:43 2022/8/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("会议取消实体") | |||||
public class MeetingCancelReq { | |||||
@NotNull(message = "会议ID不能为空") | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@NotBlank(message = "取消说明不能为空") | |||||
@ApiModelProperty("取消说明") | |||||
private String cancelRemark; | |||||
} |
@@ -0,0 +1,21 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
/** | |||||
* <p> | |||||
* MeetingListByExpertPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 17:02 2022/8/23 | |||||
*/ | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
public class MeetingListByExpertReq extends PagePo { | |||||
private Long expertId; | |||||
} |
@@ -0,0 +1,49 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import org.springframework.format.annotation.DateTimeFormat; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* MeetingListByManagerPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 11:07 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家抽取员事务列表请求参数") | |||||
@EqualsAndHashCode(callSuper = true) | |||||
public class MeetingListReq extends PagePo { | |||||
@ApiModelProperty("事务名称") | |||||
private String name; | |||||
@ApiModelProperty("事务开始时间") | |||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("事务结束时间") | |||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("地点") | |||||
private String address; | |||||
@ApiModelProperty("事务状态:1 未完成、2 已完成、3 已取消\n" + | |||||
"专家参与状态:1 待参加、2 已参加、3 已请假") | |||||
private Integer status; | |||||
@ApiModelProperty("事务类型") | |||||
private String type; | |||||
@ApiModelProperty("专家ID") | |||||
private Long expertId; | |||||
} |
@@ -0,0 +1,34 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.req; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import javax.validation.constraints.NotBlank; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingResultPo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 21:20 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@ApiModel("会议结果上传实体") | |||||
public class MeetingResultReq { | |||||
@NotNull(message = "事务ID不能为空") | |||||
@ApiModelProperty("事务ID") | |||||
private Long meetingId; | |||||
@NotBlank(message = "会议结果说明不能为空") | |||||
@ApiModelProperty("会议结果说明") | |||||
private String resultDescription; | |||||
@ApiModelProperty("附件ID") | |||||
private List<Long> attachments; | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* ExpertAttendSummaryVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 11:18 2022/8/28 | |||||
*/ | |||||
@Data | |||||
public class ExpertAttendSummaryVO { | |||||
private transient Long expertId; | |||||
@ApiModelProperty("专家姓名") | |||||
private String expertName; | |||||
@ApiModelProperty("专家出席次数") | |||||
private Integer attendCount; | |||||
} |
@@ -0,0 +1,48 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.ningdatech.pmapi.sys.model.dto.RegionDTO; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertBasicInfoVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:58 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
public class ExpertBasicInfoVO { | |||||
@Tolerate | |||||
public ExpertBasicInfoVO() { | |||||
} | |||||
@ApiModelProperty("专家ID") | |||||
private Long expertId; | |||||
@ApiModelProperty("专家姓名") | |||||
private String name; | |||||
@ApiModelProperty("专家层级") | |||||
private List<RegionDTO> regions; | |||||
@ApiModelProperty("职称级别") | |||||
private String jobLevel; | |||||
@ApiModelProperty("单位属性") | |||||
private String companyType; | |||||
@ApiModelProperty("工作单位") | |||||
private String company; | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
} |
@@ -0,0 +1,38 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertCountOnChangeVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:02 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@ApiModel("专家抽取数量校验实体") | |||||
public class ExpertCountOnChangeVO { | |||||
@ApiModelProperty("每个随机规则对应的可抽取数量") | |||||
private List<Integer> countList; | |||||
@ApiModelProperty("参数是否通过校验:true 是、false 否") | |||||
private Boolean status; | |||||
@ApiModelProperty("错误提醒") | |||||
private String message; | |||||
public void addCountList(Integer count) { | |||||
this.countList.add(count); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* ExpertEvaluationListVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 16:03 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家评价列表") | |||||
public class ExpertEvaluationListVO { | |||||
@ApiModelProperty("专家评价ID") | |||||
private Long evaluationId; | |||||
@ApiModelProperty("专家信息") | |||||
private ExpertBasicInfoVO expert; | |||||
} |
@@ -0,0 +1,38 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* ExpertEvaluationToDoListItemVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 13:58 2022/8/29 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家评价待办列表") | |||||
@EqualsAndHashCode(callSuper = true) | |||||
public class ExpertEvaluationToDoListItemVO extends ExpertBasicInfoVO { | |||||
@ApiModelProperty("专家会议ID") | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("会议名称") | |||||
private String meetingName; | |||||
@ApiModelProperty("会议开始时间") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("会议结束时间") | |||||
private LocalDateTime endTime; | |||||
} |
@@ -0,0 +1,60 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import com.ningdatech.pmapi.sys.model.dto.RegionDTO; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
import java.time.LocalDateTime; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertInvitationDetailVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 13:51 2022/8/27 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
public class ExpertInvitationDetailVO { | |||||
@Tolerate | |||||
public ExpertInvitationDetailVO() { | |||||
} | |||||
@ApiModelProperty("专家确认时间") | |||||
private LocalDateTime inviteTime; | |||||
@ApiModelProperty("会议举办单位") | |||||
private String holdCompany; | |||||
@ApiModelProperty("会议开始时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("会议结束时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("会议名称") | |||||
private String meetingName; | |||||
@ApiModelProperty("举办地址详情") | |||||
private String regionDetail; | |||||
private List<RegionDTO> regions; | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@ApiModelProperty("专家名称") | |||||
private String expertName; | |||||
} |
@@ -0,0 +1,95 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteDetailVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 08:58 2022/8/9 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家邀请情况实体") | |||||
public class ExpertInviteDetailVO { | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel("最终参与名单实体") | |||||
public static class ExpertAttendListItemVO extends ExpertBasicInfoVO { | |||||
private Long meetingId; | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("邀请方式") | |||||
private String inviteType; | |||||
} | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel("随机邀请名单实体") | |||||
public static class RandomInviteListItemVO extends ExpertBasicInfoVO { | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("专家会议ID") | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("电话通知状态") | |||||
private String noticeStatus; | |||||
@ApiModelProperty("邀请结果") | |||||
private String confirmResult; | |||||
@ApiModelProperty("邀请状态") | |||||
private Integer status; | |||||
} | |||||
@ApiModelProperty("参与数量总计") | |||||
private Integer attendTotal = 0; | |||||
@ApiModelProperty("随机邀请参与数量") | |||||
private Integer randomAttend = 0; | |||||
@ApiModelProperty("指定邀请参与数量") | |||||
private Integer appointAttend = 0; | |||||
@ApiModelProperty("是否已停止邀请") | |||||
private Boolean hasStopInvite; | |||||
@ApiModelProperty("是否已下发通知") | |||||
private Boolean hasSendNotice; | |||||
@ApiModelProperty("最终参与名单") | |||||
private List<ExpertAttendListItemVO> attendList = new ArrayList<>(); | |||||
@ApiModelProperty("随机邀请名单") | |||||
private List<RandomInviteListItemVO> randomInviteList = new ArrayList<>(); | |||||
@ApiModelProperty("指定邀请名单") | |||||
private List<RandomInviteListItemVO> appointInviteList = new ArrayList<>(); | |||||
public void addAttendList(ExpertAttendListItemVO attend) { | |||||
this.attendList.add(attend); | |||||
} | |||||
public void addRandomInviteList(RandomInviteListItemVO randomInvite) { | |||||
this.randomInviteList.add(randomInvite); | |||||
} | |||||
public void addAppointInviteList(RandomInviteListItemVO appointInvite) { | |||||
this.appointInviteList.add(appointInvite); | |||||
} | |||||
} |
@@ -0,0 +1,43 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.time.LocalDateTime; | |||||
import java.time.LocalTime; | |||||
/** | |||||
* <p> | |||||
* 专家抽取免打扰时间设置 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-11-21 | |||||
*/ | |||||
@Data | |||||
@ApiModel("专家抽取免打扰时间设置") | |||||
public class ExpertInviteIgnoreTimeListVO { | |||||
@ApiModelProperty("主键") | |||||
private Long id; | |||||
@ApiModelProperty("是否启用:true 是、false 否") | |||||
private Boolean enable; | |||||
@ApiModelProperty("开始时间") | |||||
@JSONField(format = "HH:mm") | |||||
private LocalTime startTime; | |||||
@ApiModelProperty("截止时间") | |||||
@JSONField(format = "HH:mm") | |||||
private LocalTime endTime; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("修改时间") | |||||
private LocalDateTime updateOn; | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
/** | |||||
* <p> | |||||
* MeetingExpertListItemFoEvaluationVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:06 2022/8/24 | |||||
*/ | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
@ApiModel("专家评价专家列表视图实体") | |||||
public class ExpertListItemFoEvaluationVO extends ExpertBasicInfoVO { | |||||
@ApiModelProperty("是否已评价:true 已评价、false 未评价") | |||||
private boolean evaluated; | |||||
@ApiModelProperty("评价ID") | |||||
private Long evaluationId; | |||||
@ApiModelProperty("专家会议ID") | |||||
private Long expertMeetingId; | |||||
} |
@@ -0,0 +1,41 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* ExpertReplaceTodoListItemVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 16:46 2022/8/29 | |||||
*/ | |||||
@Data | |||||
@EqualsAndHashCode(callSuper = true) | |||||
public class ExpertReplaceTodoListItemVO extends ExpertBasicInfoVO { | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
private Long expertMeetingId; | |||||
@ApiModelProperty("会议名称") | |||||
private String meetingName; | |||||
@ApiModelProperty("邀请结果") | |||||
private Integer status; | |||||
@ApiModelProperty("邀请方式") | |||||
private String inviteType; | |||||
@ApiModelProperty("开始时间") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("结束时间") | |||||
private LocalDateTime endTime; | |||||
} |
@@ -0,0 +1,72 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* InviteRuleDetailVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 14:58 2022/8/17 | |||||
*/ | |||||
@Data | |||||
public class InviteRuleDetailVO { | |||||
@ApiModelProperty("是否创建邀请规则") | |||||
private Boolean invited; | |||||
@ApiModelProperty("随机邀请规则") | |||||
private List<RandomInviteRuleVO> randomRules; | |||||
@ApiModelProperty("是否有指定抽取规则") | |||||
private Boolean hasAppointRule; | |||||
@ApiModelProperty("指定抽取规则") | |||||
private AppointRuleVo appointRule; | |||||
@ApiModelProperty("是否有回避规则") | |||||
private Boolean hasAvoidInfo; | |||||
@ApiModelProperty("回避信息") | |||||
private AvoidInfoVo avoidInfo; | |||||
@Data | |||||
public static class AvoidInfoVo { | |||||
private List<String> companyIds; | |||||
private Boolean avoidMates; | |||||
private List<ExpertBasicInfoVO> experts; | |||||
} | |||||
@Data | |||||
public static class AppointRuleVo { | |||||
private String inviteDesc; | |||||
private List<ExpertBasicInfoVO> experts; | |||||
} | |||||
public Boolean setAndGetHasAppointRule(Boolean hasAppointRule) { | |||||
this.hasAppointRule = hasAppointRule; | |||||
return this.hasAppointRule; | |||||
} | |||||
public Boolean setAndGetHasAvoidInfo(Boolean hasAvoidInfo) { | |||||
this.hasAvoidInfo = hasAvoidInfo; | |||||
return this.hasAvoidInfo; | |||||
} | |||||
public Boolean setAndGetInvited(Boolean invited) { | |||||
this.invited = invited; | |||||
return this.invited; | |||||
} | |||||
} |
@@ -0,0 +1,76 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* <p> | |||||
* MeetingByManagerVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 11:43 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@ApiModel("会议实体(管理员列表)") | |||||
public class MeetingByManagerVO { | |||||
@Tolerate | |||||
public MeetingByManagerVO() { | |||||
} | |||||
@ApiModelProperty("事务ID") | |||||
private Long id; | |||||
@ApiModelProperty("事务状态") | |||||
private Integer status; | |||||
@ApiModelProperty("会议参加状态:1 待参加、2 已参加、3 已请假") | |||||
private Integer attendStatus; | |||||
@ApiModelProperty("事务名称") | |||||
private String name; | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@ApiModelProperty("会议地址详情") | |||||
private String meetingAddress; | |||||
@ApiModelProperty("事务类型编码") | |||||
private String dateType; | |||||
@ApiModelProperty("事务类型名称") | |||||
private String dateTypeName; | |||||
@ApiModelProperty("事务开始时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("事务结束时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("邀请人数") | |||||
private Integer inviteCount; | |||||
@ApiModelProperty("确认人数") | |||||
private Integer confirmCount; | |||||
@ApiModelProperty("是否进行了专家抽取:true 是、false 否") | |||||
private Boolean invited; | |||||
@ApiModelProperty("抽取单位") | |||||
private String inviterCompany; | |||||
} |
@@ -0,0 +1,38 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.time.LocalDate; | |||||
import java.util.Collection; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingCalenderItemVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 22:57 2022/8/24 | |||||
*/ | |||||
@Data | |||||
@ApiModel("会议日历视图实体") | |||||
public class MeetingCalenderItemVO { | |||||
@ApiModelProperty("当前日期") | |||||
private LocalDate today; | |||||
@ApiModelProperty("是否请假") | |||||
private Boolean hasLeave; | |||||
@ApiModelProperty("请假ID") | |||||
private Collection<Long> leaveIds; | |||||
@ApiModelProperty("是否有会议") | |||||
private Boolean hasMeeting; | |||||
@ApiModelProperty("会议信息") | |||||
private List<MeetingByManagerVO> meetings; | |||||
} |
@@ -0,0 +1,51 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.ningdatech.pmapi.sys.model.dto.RegionDTO; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.time.LocalDateTime; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingConfirmToDoListItem | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:20 2022/8/29 | |||||
*/ | |||||
@Data | |||||
public class MeetingConfirmToDoListItemVO { | |||||
@ApiModelProperty("会议ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("会议名称") | |||||
private String meetingName; | |||||
@ApiModelProperty("会议开始时间") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("会议结束时间") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("会议类型") | |||||
private String type; | |||||
@ApiModelProperty("举办地址详情") | |||||
private String regionDetail; | |||||
@ApiModelProperty("举办地址") | |||||
private List<RegionDTO> regions; | |||||
@ApiModelProperty("状态") | |||||
private Integer status; | |||||
@ApiModelProperty("邀请总人数") | |||||
private Integer totalExpert; | |||||
@ApiModelProperty("确认总人数") | |||||
private Integer confirmedExpert; | |||||
} |
@@ -0,0 +1,46 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* MeetingCountByExpertVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:23 2022/10/19 | |||||
*/ | |||||
@Data | |||||
@AllArgsConstructor | |||||
@ApiModel("专家工作台:会议数量统计视图") | |||||
public class MeetingCountByExpertVO { | |||||
@ApiModelProperty("待参加数量") | |||||
private Integer toBeAttended; | |||||
@ApiModelProperty("已参加数量") | |||||
private Integer attended; | |||||
@ApiModelProperty("请假数量") | |||||
private Integer leaved; | |||||
public static MeetingCountByExpertVO init() { | |||||
return new MeetingCountByExpertVO(0, 0, 0); | |||||
} | |||||
public void incrToBeAttended() { | |||||
this.toBeAttended += 1; | |||||
} | |||||
public void incrAttended() { | |||||
this.attended += 1; | |||||
} | |||||
public void incrLeaved() { | |||||
this.leaved += 1; | |||||
} | |||||
} |
@@ -0,0 +1,33 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* MeetingCountSummaryVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 09:43 2022/8/30 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@ApiModel("会议数量统计视图实体") | |||||
public class MeetingCountSummaryVO { | |||||
@ApiModelProperty("已完成") | |||||
private Integer completed; | |||||
@ApiModelProperty("已取消") | |||||
private Integer canceled; | |||||
@ApiModelProperty("待召开") | |||||
private Integer toBeHeld; | |||||
@ApiModelProperty("已召开") | |||||
private Integer held; | |||||
} |
@@ -0,0 +1,97 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import com.ningdatech.file.entity.vo.result.AttachFileVo; | |||||
import com.ningdatech.pmapi.sys.model.dto.RegionDTO; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.experimental.Tolerate; | |||||
import java.time.LocalDateTime; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingDetailBasicVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 15:16 2022/8/8 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@ApiModel("会议详情基本信息") | |||||
public class MeetingDetailBasicVO { | |||||
@Tolerate | |||||
public MeetingDetailBasicVO() { | |||||
} | |||||
private Long id; | |||||
@ApiModelProperty("会议名称") | |||||
private String name; | |||||
@ApiModelProperty("会议类型名称") | |||||
private String typeName; | |||||
@ApiModelProperty("会议类型代码") | |||||
private String type; | |||||
@ApiModelProperty("开始时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime startTime; | |||||
@ApiModelProperty("结束时间") | |||||
@JSONField(format = "yyyy-MM-dd HH:mm") | |||||
private LocalDateTime endTime; | |||||
@ApiModelProperty("联系人") | |||||
private String connecter; | |||||
@ApiModelProperty("创建人") | |||||
private String author; | |||||
private List<RegionDTO> regions; | |||||
@ApiModelProperty("地点") | |||||
private String address; | |||||
@ApiModelProperty("联系方式") | |||||
private String contact; | |||||
@ApiModelProperty("创建时间") | |||||
private LocalDateTime createOn; | |||||
@ApiModelProperty("会议说明") | |||||
private String description; | |||||
@ApiModelProperty("相关材料") | |||||
private List<AttachFileVo> attachments; | |||||
@ApiModelProperty("备注") | |||||
private String remark; | |||||
@ApiModelProperty("会议状态") | |||||
private Integer status; | |||||
@ApiModelProperty("专家出席状态") | |||||
private Integer attendStatus; | |||||
@ApiModelProperty("取消说明") | |||||
private String cancelRemark; | |||||
@ApiModelProperty("创建人") | |||||
private String createBy; | |||||
private Boolean invited; | |||||
@ApiModelProperty("抽取单位") | |||||
private String inviterCompany; | |||||
@ApiModelProperty("是否已确认下发会议通知名单") | |||||
private Boolean sendMeetingNotice; | |||||
} |
@@ -0,0 +1,29 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.ningdatech.file.entity.vo.result.AttachFileVo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* MeetingResultVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 21:28 2022/8/8 | |||||
*/ | |||||
@Data | |||||
public class MeetingResultVO { | |||||
@ApiModelProperty("事务ID") | |||||
private Long meetingId; | |||||
@ApiModelProperty("会议结果说明") | |||||
private String resultDescription; | |||||
@ApiModelProperty("附件信息") | |||||
private List<AttachFileVo> attachments; | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.ningdatech.pmapi.meeting.entity.vo; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import com.ningdatech.pmapi.sys.model.dto.RegionDTO; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.EqualsAndHashCode; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* RandomInviteRuleVo | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 09:55 2022/8/26 | |||||
*/ | |||||
@Data | |||||
@ApiModel("随机抽取规则视图实体") | |||||
@EqualsAndHashCode(callSuper = true) | |||||
public class RandomInviteRuleVO extends RandomInviteRuleDTO { | |||||
@ApiModelProperty("履职意向地(回显使用)") | |||||
private List<RegionDTO> intentionRegions; | |||||
@ApiModelProperty("专家层级意向地(回显使用)") | |||||
private List<RegionDTO> expertRegions; | |||||
} |
@@ -0,0 +1,80 @@ | |||||
package com.ningdatech.pmapi.meeting.helper; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.stereotype.Component; | |||||
import java.time.LocalDateTime; | |||||
import java.util.*; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteHelper | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 16:35 2022/11/21 | |||||
*/ | |||||
@Slf4j | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class ExpertInviteHelper { | |||||
private final IMeetingService meetingService; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
/** | |||||
* 获取时间段内被抽中的专家(通知中、确认参加) | |||||
* | |||||
* @param start 开始时间 | |||||
* @param end 结束时间 | |||||
* @return java.util.List<java.lang.Long> | |||||
* @author WendyYang | |||||
**/ | |||||
public List<Long> listInvitedExpertByTime(LocalDateTime start, LocalDateTime end) { | |||||
LambdaQueryWrapper<Meeting> meetingQuery = Wrappers.lambdaQuery(Meeting.class) | |||||
.select(Meeting::getId) | |||||
.eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode()) | |||||
.and(wrapper -> wrapper.between(Meeting::getStartTime, start, end) | |||||
.or(wrapper1 -> wrapper1.between(Meeting::getEndTime, start, end))); | |||||
List<Meeting> meetings = meetingService.list(meetingQuery); | |||||
if (meetings.isEmpty()) { | |||||
return Collections.emptyList(); | |||||
} | |||||
List<Long> meetingIds = CollUtils.fieldList(meetings, Meeting::getId); | |||||
LambdaQueryWrapper<MeetingExpert> meetingExpertQuery = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.select(MeetingExpert::getExpertId) | |||||
.in(MeetingExpert::getStatus, ExpertAttendStatus.AGREED.getCode(), ExpertAttendStatus.NOTICING.getCode()) | |||||
.in(MeetingExpert::getMeetingId, meetingIds); | |||||
List<MeetingExpert> meetingExperts = meetingExpertService.list(meetingExpertQuery); | |||||
return CollUtils.fieldList(meetingExperts, MeetingExpert::getExpertId); | |||||
} | |||||
public Set<Long> listExpertLeaveOrInvited(LocalDateTime start, LocalDateTime end) { | |||||
Set<Long> notInUserIds = new HashSet<>(); | |||||
notInUserIds.addAll(listInvitedExpertByTime(start, end)); | |||||
return notInUserIds; | |||||
} | |||||
public Set<Long> getAvoidExpert(List<Long> appoints, AvoidInfoDTO avoid, LocalDateTime start, LocalDateTime end) { | |||||
Set<Long> expertIds = new HashSet<>(); | |||||
Optional.ofNullable(appoints).ifPresent(expertIds::addAll); | |||||
Optional.ofNullable(avoid) | |||||
.flatMap(w -> Optional.ofNullable(w.getExpertIds())) | |||||
.ifPresent(expertIds::addAll); | |||||
// 过滤掉请假专家 | |||||
expertIds.addAll(listInvitedExpertByTime(start, end)); | |||||
return expertIds; | |||||
} | |||||
} |
@@ -0,0 +1,222 @@ | |||||
package com.ningdatech.pmapi.meeting.helper; | |||||
import cn.hutool.core.lang.Assert; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.ningdatech.basic.exception.BizException; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
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.entity.ExpertUserFullInfo; | |||||
import com.ningdatech.pmapi.expert.model.dto.ExpertDictionaryDTO; | |||||
import com.ningdatech.pmapi.expert.model.dto.ExpertUserFullInfoDTO; | |||||
import com.ningdatech.pmapi.expert.service.ExpertInfoService; | |||||
import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVO; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.MeetingByManagerVO; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meta.constant.DictExpertInfoTypeEnum; | |||||
import com.ningdatech.pmapi.meta.helper.DictionaryCache; | |||||
import com.ningdatech.pmapi.meta.model.dto.DictionaryDTO; | |||||
import lombok.AllArgsConstructor; | |||||
import org.apache.commons.collections4.CollectionUtils; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.*; | |||||
/** | |||||
* <p> | |||||
* MeetingManageHelper | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 17:23 2022/8/23 | |||||
*/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class MeetingManageHelper { | |||||
private final DictionaryCache dictionaryCache; | |||||
private final ExpertInfoService expertInfoService; | |||||
private final IExpertUserFullInfoService expertUserFullInfoService; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final IExpertInviteRuleService inviteRuleService; | |||||
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | |||||
/** | |||||
* 获取专家出席会议的状态 | |||||
* | |||||
* @param info 会议状态及评价信息 | |||||
* @return java.lang.Integer | |||||
* @author WendyYang | |||||
**/ | |||||
public Integer getExpertAttendStatus(MeetingAndAttendStatusDTO info) { | |||||
if (info.getAttended() == null && info.getStatus().equals(ExpertAttendStatus.AGREED.getCode())) { | |||||
return MeetingStatus.Expert.TO_ATTEND.getCode(); | |||||
} else if (info.getStatus().equals(ExpertAttendStatus.ON_LEAVE.getCode())) { | |||||
return MeetingStatus.Expert.ON_LEAVE.getCode(); | |||||
} else if (info.getAttended() != null && info.getAttended()) { | |||||
return MeetingStatus.Expert.ATTENDED.getCode(); | |||||
} else { | |||||
return MeetingStatus.Expert.UN_ATTEND.getCode(); | |||||
} | |||||
} | |||||
public MeetingByManagerVO buildByMeeting(Meeting meeting) { | |||||
return MeetingByManagerVO.builder() | |||||
.id(meeting.getId()) | |||||
.dateTypeName(dictionaryCache.getByCode(meeting.getType()).getName()) | |||||
.meetingAddress(meeting.getRegionDetail()) | |||||
.name(meeting.getName()) | |||||
.startTime(meeting.getStartTime()) | |||||
.endTime(meeting.getEndTime()) | |||||
.connecter(meeting.getConnecter()) | |||||
.contact(meeting.getContact()) | |||||
.status(meeting.getStatus()) | |||||
.invited(meeting.getInvited()) | |||||
.inviterCompany(meeting.getHoldCompany()) | |||||
.build(); | |||||
} | |||||
public void buildMeetingQuery(LambdaQueryWrapper<Meeting> query, MeetingListReq po) { | |||||
if (StrUtil.isNotBlank(po.getName())) { | |||||
query.like(Meeting::getName, po.getName()); | |||||
} | |||||
if (StrUtil.isNotBlank(po.getAddress())) { | |||||
query.like(Meeting::getRegionDetail, po.getAddress()); | |||||
} | |||||
if (StrUtil.isNotBlank(po.getType())) { | |||||
query.eq(Meeting::getType, po.getType()); | |||||
} | |||||
if (po.getStartTime() != null) { | |||||
query.ge(Meeting::getStartTime, po.getStartTime()); | |||||
} | |||||
if (po.getEndTime() != null) { | |||||
query.le(Meeting::getEndTime, po.getEndTime()); | |||||
} | |||||
} | |||||
/** | |||||
* 构建用户基本信息 | |||||
* | |||||
* @param userIds 用户ID | |||||
* @return java.util.Map<java.lang.Long, com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVo> | |||||
* @author WendyYang | |||||
**/ | |||||
public Map<Long, ExpertBasicInfoVO> getExpertBasicInfo(List<Long> userIds) { | |||||
/*List<ExpertFullInfoAllDTO> expertInfos = expertInfoService.listExpertUserFullInfoAll(userIds); | |||||
return CollUtils.listToMap(expertInfos, ExpertFullInfoAllDTO::getUserId, w -> { | |||||
ExpertBasicInfoVO basicInfoVo = new ExpertBasicInfoVO(); | |||||
ExpertUserFullInfoDTO userInfo = w.getExpertUserInfoDTO(); | |||||
basicInfoVo.setName(userInfo.getName()); | |||||
basicInfoVo.setExpertId(w.getUserId()); | |||||
basicInfoVo.setContact(userInfo.getPhoneNo()); | |||||
basicInfoVo.setCompany(userInfo.getCompany()); | |||||
Optional<ExpertDictionaryDTO> first = w.getExpertDictionaryList().stream() | |||||
.filter(dict -> dict.getExpertInfoField().equals(DictExpertInfoTypeEnum.TITLE_LEVEL.getKey())) | |||||
.findFirst(); | |||||
if (first.isPresent()) { | |||||
DictionaryDTO dictInfo = dictionaryCache.getByCode(first.get().getDictionaryCode()); | |||||
basicInfoVo.setJobLevel(dictInfo.getName()); | |||||
} else { | |||||
basicInfoVo.setJobLevel(""); | |||||
} | |||||
basicInfoVo.setCompanyType(""); | |||||
return basicInfoVo; | |||||
});*/ | |||||
// TODO | |||||
return null; | |||||
} | |||||
public AvoidInfoDTO getAvoidInfoDto(Long meetingId) { | |||||
ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId); | |||||
AvoidInfoDTO avoidInfoDto = new AvoidInfoDTO(); | |||||
avoidInfoDto.setAvoidMates(avoidRule.getAvoidMates()); | |||||
avoidInfoDto.setExpertIds(BizUtils.splitToLong(avoidRule.getExpertIds())); | |||||
avoidInfoDto.setCompanyIds(StrUtils.split(avoidRule.getCompanyIds())); | |||||
return avoidInfoDto; | |||||
} | |||||
public void saveAvoidInfo(Long meetingId, List<Long> expertIds) { | |||||
ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId); | |||||
avoidRule.setExpertIds(CollUtils.joinByComma(expertIds)); | |||||
inviteAvoidRuleService.saveOrUpdate(avoidRule); | |||||
} | |||||
/** | |||||
* 校验是否能够进行指定邀请 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @param expertIds 专家ID | |||||
* @author WendyYang | |||||
**/ | |||||
public List<ExpertUserFullInfo> appointExpertCheck(Long meetingId, List<Long> expertIds) { | |||||
List<ExpertUserFullInfo> experts = expertUserFullInfoService.listByUserId(expertIds); | |||||
AvoidInfoDTO avoidRule = getAvoidInfoDto(meetingId); | |||||
Map<String, Integer> countMap = new HashMap<>(16); | |||||
experts.forEach(expert -> { | |||||
if (avoidRule.getCompanyIds().contains(expert.getCompany())) { | |||||
throw BizException.wrap("回避单位的专家不可出现在指定邀请名单中"); | |||||
} | |||||
if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds()) && avoidRule.getExpertIds().contains(expert.getUserId())) { | |||||
throw BizException.wrap("已回避的专家不可被指定邀请"); | |||||
} | |||||
if (avoidRule.getAvoidMates()) { | |||||
Integer oldValue = countMap.put(expert.getCompany(), 1); | |||||
Assert.isNull(oldValue, "不可选择同单位的多个专家"); | |||||
} | |||||
// 校验专家状态 | |||||
ExpertAccountStatusEnum accountStatus = ExpertAccountStatusEnum.of(expert.getExpertAccountStatus()); | |||||
if (!accountStatus.equals(ExpertAccountStatusEnum.AVAILABLE)) { | |||||
throw BizException.wrap("专家%s不可被抽取", expert.getExpertName()); | |||||
} | |||||
}); | |||||
Map<Long, ExpertUserFullInfo> expertMap = CollUtils.listToMap(experts, ExpertUserFullInfo::getUserId); | |||||
List<MeetingExpert> meetingExperts = meetingExpertService.listByMeetingId(meetingId); | |||||
if (!meetingExperts.isEmpty()) { | |||||
Comparator<MeetingExpert> comparator = Comparator.comparing(MeetingExpert::getUpdateOn).reversed(); | |||||
Collection<MeetingExpert> values = BizUtils.groupFirst(meetingExperts, MeetingExpert::getExpertId, comparator); | |||||
values.forEach(w -> { | |||||
ExpertUserFullInfo expertInfo = expertMap.get(w.getExpertId()); | |||||
if (expertInfo != null) { | |||||
String expertName = expertInfo.getExpertName(); | |||||
switch (ExpertAttendStatus.getByCode(w.getStatus())) { | |||||
case REFUSED: | |||||
throw BizException.wrap("专家%s已拒绝参加", expertName); | |||||
case CANCELED: | |||||
throw BizException.wrap("专家%s已被移除", expertName); | |||||
case REPLACED: | |||||
switch (ExpertAttendStatus.getByCode(w.getPreStatus())) { | |||||
case REFUSED: | |||||
throw BizException.wrap("专家%s已拒绝参加", expertName); | |||||
case CANCELED: | |||||
throw BizException.wrap("专家%s已被移除", expertName); | |||||
default: | |||||
break; | |||||
} | |||||
break; | |||||
case AGREED: | |||||
throw BizException.wrap("专家%s已同意参加", expertName); | |||||
case NOTICING: | |||||
throw BizException.wrap("专家%s正在通知中", expertName); | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
return experts; | |||||
} | |||||
} |
@@ -0,0 +1,50 @@ | |||||
package com.ningdatech.pmapi.meeting.helper; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import lombok.AllArgsConstructor; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* YxtCallOrSmsHelper | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 23:59 2022/8/31 | |||||
*/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class YxtCallOrSmsHelper { | |||||
// private final YinXinTongClient yinXinTongClient; | |||||
public void callByMeetingExperts(Meeting meeting, List<MeetingExpert> experts) { | |||||
/*String callContent = String.format(YxtCallTemplateConst.OFFLINE_TEMPLATE, | |||||
meeting.getHoldCompany(), meeting.getName(), | |||||
meeting.getStartTime().format(DateUtil.DTF_YMD_HM), meeting.getRegionDetail()); | |||||
List<SubmitTaskCallContext> callContexts = CollUtils.convert(experts, w -> { | |||||
SubmitTaskCallContext context = new SubmitTaskCallContext(); | |||||
context.setContent(callContent); | |||||
context.setReceiveNumber(w.getMobile()); | |||||
return context; | |||||
}); | |||||
SubmitTaskCallResponse callResponse = yinXinTongClient.submitTaskCall(SubmitTaskCallCmd.of(callContexts)); | |||||
experts.forEach(w -> w.setSubmitKey(callResponse.getSubmitKey()));*/ | |||||
} | |||||
/*public void sendSms(List<SendSmsContext> smsList) { | |||||
yinXinTongClient.submitSmsTask(new SendSmsCmd() {{ | |||||
setContextList(smsList); | |||||
setSmsSignEnum(YxtSmsSignEnum.ZJS_ELECTRONIC_EXPERT_LIB); | |||||
}}); | |||||
} | |||||
public void sendSms(SendSmsContext sms) { | |||||
sendSms(Collections.singletonList(sms)); | |||||
}*/ | |||||
} |
@@ -0,0 +1,241 @@ | |||||
package com.ningdatech.pmapi.meeting.manage; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.ningdatech.basic.exception.BizException; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import com.ningdatech.basic.model.PageVo; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
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.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusByDashboard; | |||||
import com.ningdatech.pmapi.meeting.entity.req.MeetingCalenderReq; | |||||
import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.*; | |||||
import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertEvaluationService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import com.ningdatech.pmapi.meta.helper.DictionaryCache; | |||||
import com.ningdatech.pmapi.user.util.LoginUserUtil; | |||||
import lombok.AllArgsConstructor; | |||||
import org.apache.commons.lang3.tuple.Pair; | |||||
import org.springframework.stereotype.Component; | |||||
import java.time.LocalDate; | |||||
import java.time.LocalDateTime; | |||||
import java.time.LocalTime; | |||||
import java.util.*; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* <p> | |||||
* DashboardManage | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 23:04 2022/8/24 | |||||
*/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class DashboardManage { | |||||
private final MeetingManage meetingManage; | |||||
private final IMeetingService meetingService; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final MeetingManageHelper meetingManageHelper; | |||||
private final IMeetingExpertEvaluationService meetingExpertEvaluationService; | |||||
private final DictionaryCache dictionaryCache; | |||||
public static final int MEETING_CALENDER_MONTHS = 2; | |||||
public List<MeetingCalenderItemVO> meetingCalender(MeetingCalenderReq po) { | |||||
if (po.getStartDate().plusMonths(MEETING_CALENDER_MONTHS).isBefore(po.getEndDate())) { | |||||
throw new BizException("最多可查询两个月数据"); | |||||
} | |||||
MeetingListReq meetingListPo = new MeetingListReq(); | |||||
meetingListPo.setPageSize(500); | |||||
meetingListPo.setStartTime(po.getStartDate().atStartOfDay()); | |||||
meetingListPo.setEndTime(po.getEndDate().atTime(LocalTime.MAX)); | |||||
PageVo<MeetingByManagerVO> meetingPage = meetingManage.meetingListByExpert(meetingListPo); | |||||
Map<LocalDate, List<MeetingByManagerVO>> meetingByDate = meetingPage.getRecords().stream().map(w -> { | |||||
List<Pair<LocalDate, MeetingByManagerVO>> pairs = new ArrayList<>(); | |||||
LocalDateTime tempTime = w.getStartTime(); | |||||
while (tempTime.isBefore(w.getEndTime())) { | |||||
pairs.add(Pair.of(tempTime.toLocalDate(), w)); | |||||
tempTime = tempTime.plusDays(1); | |||||
} | |||||
return pairs; | |||||
}).flatMap(Collection::stream) | |||||
.collect(Collectors.groupingBy(Pair::getLeft, | |||||
Collectors.collectingAndThen(Collectors.mapping(Pair::getRight, Collectors.toList()), | |||||
w -> { | |||||
w.sort(Comparator.comparing(MeetingByManagerVO::getStartTime)); | |||||
return w; | |||||
}))); | |||||
LocalDate tempDate = po.getStartDate(); | |||||
List<MeetingCalenderItemVO> result = new ArrayList<>(); | |||||
while (!tempDate.isAfter(po.getEndDate())) { | |||||
MeetingCalenderItemVO item = new MeetingCalenderItemVO(); | |||||
List<MeetingByManagerVO> meetings = meetingByDate.get(tempDate); | |||||
item.setHasMeeting(meetings != null); | |||||
if (item.getHasMeeting()) { | |||||
item.setMeetings(meetings); | |||||
} | |||||
item.setToday(tempDate); | |||||
result.add(item); | |||||
tempDate = tempDate.plusDays(1); | |||||
} | |||||
return result; | |||||
} | |||||
public PageVo<ExpertEvaluationToDoListItemVO> expertEvaluationToDo(PagePo po) { | |||||
PageVo<ExpertEvaluationToDoListItemVO> result = PageVo.of(new ArrayList<>(), 0L); | |||||
// 查询所有未完成的项目 | |||||
LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class) | |||||
.select(Meeting::getId) | |||||
.ne(Meeting::getStatus, MeetingStatus.Manager.CANCELED.getCode()) | |||||
.eq(Meeting::getCreateBy, LoginUserUtil.getUserId()); | |||||
List<Meeting> meetings = meetingService.list(query); | |||||
if (meetings.isEmpty()) { | |||||
return PageVo.empty(); | |||||
} | |||||
List<Long> meetingIds = CollUtils.fieldList(meetings, Meeting::getId); | |||||
Page<MeetingExpert> page = meetingExpertEvaluationService.pageExpertEvaluationTodo(meetingIds, po); | |||||
if (page.getTotal() > 0) { | |||||
List<Long> expertIds = new ArrayList<>(), meetingIdsByPage = new ArrayList<>(); | |||||
page.getRecords().forEach(w -> { | |||||
meetingIdsByPage.add(w.getMeetingId()); | |||||
expertIds.add(w.getExpertId()); | |||||
}); | |||||
Map<Long, Meeting> meetingMap = CollUtils.listToMap(meetingService.listByIds(meetingIdsByPage), Meeting::getId); | |||||
Map<Long, ExpertBasicInfoVO> basicInfoVoMap = meetingManageHelper.getExpertBasicInfo(expertIds); | |||||
page.getRecords().forEach(w -> { | |||||
ExpertBasicInfoVO expertInfo = basicInfoVoMap.get(w.getExpertId()); | |||||
Meeting meeting = meetingMap.get(w.getMeetingId()); | |||||
ExpertEvaluationToDoListItemVO item = BeanUtil.copyProperties(expertInfo, ExpertEvaluationToDoListItemVO.class); | |||||
item.setMeetingName(meeting.getName()); | |||||
item.setMeetingId(w.getMeetingId()); | |||||
item.setExpertMeetingId(w.getId()); | |||||
item.setStartTime(meeting.getStartTime()); | |||||
item.setEndTime(meeting.getEndTime()); | |||||
result.getRecords().add(item); | |||||
}); | |||||
result.setTotal(page.getTotal()); | |||||
} | |||||
return result; | |||||
} | |||||
public PageVo<MeetingConfirmToDoListItemVO> expertConfirmToDo(PagePo po) { | |||||
// 查询所有未完成的项目 | |||||
LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class) | |||||
.eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode()) | |||||
.eq(Meeting::getCreateBy, LoginUserUtil.getUserId()) | |||||
.orderByDesc(Meeting::getStartTime); | |||||
List<Meeting> meetings = meetingService.list(query); | |||||
if (meetings.isEmpty()) { | |||||
return PageVo.empty(); | |||||
} | |||||
List<Long> meetingIds = CollUtils.fieldList(meetings, Meeting::getId); | |||||
Map<Long, CountConfirmByMeetingIdDTO> confirmedMap = meetingExpertService.countConfirmedByMeetingIds(meetingIds); | |||||
confirmedMap.entrySet().removeIf(w -> { | |||||
CountConfirmByMeetingIdDTO confirm = w.getValue(); | |||||
return confirm.getConfirmed().equals(confirm.getTotal()); | |||||
}); | |||||
if (confirmedMap.size() == 0) { | |||||
return PageVo.empty(); | |||||
} | |||||
meetings.removeIf(w -> !confirmedMap.containsKey(w.getId())); | |||||
List<MeetingConfirmToDoListItemVO> dataList = meetings.stream() | |||||
.skip((long) (po.getPageNumber() - 1) * po.getPageSize()) | |||||
.limit(po.getPageSize()).map(w -> { | |||||
MeetingConfirmToDoListItemVO item = new MeetingConfirmToDoListItemVO(); | |||||
CountConfirmByMeetingIdDTO confirm = confirmedMap.get(w.getId()); | |||||
if (confirm == null) { | |||||
item.setTotalExpert(0); | |||||
item.setConfirmedExpert(0); | |||||
} else { | |||||
item.setTotalExpert(confirm.getTotal()); | |||||
item.setConfirmedExpert(confirm.getConfirmed()); | |||||
} | |||||
item.setMeetingId(w.getId()); | |||||
item.setEndTime(w.getEndTime()); | |||||
item.setStartTime(w.getStartTime()); | |||||
item.setStatus(w.getStatus()); | |||||
item.setRegionDetail(w.getRegionDetail()); | |||||
item.setType(dictionaryCache.getByCode(w.getType()).getName()); | |||||
item.setMeetingName(w.getName()); | |||||
return item; | |||||
}).collect(Collectors.toList()); | |||||
return PageVo.of(dataList, meetings.size()); | |||||
} | |||||
public PageVo<ExpertReplaceTodoListItemVO> expertReplaceTodoList(PagePo po) { | |||||
// 查询所有未完成的项目 | |||||
LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class) | |||||
.eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode()) | |||||
.eq(Meeting::getCreateBy, LoginUserUtil.getUserId()) | |||||
.orderByDesc(Meeting::getStartTime); | |||||
List<Meeting> meetings = meetingService.list(query); | |||||
if (meetings.isEmpty()) { | |||||
return PageVo.empty(); | |||||
} | |||||
List<Long> meetingIds = CollUtils.fieldList(meetings, Meeting::getId); | |||||
Page<MeetingExpert> page = meetingExpertService.pageExpertByStatusAndMeetingIds(new Page<>(po.getPageNumber(), po.getPageSize()), | |||||
meetingIds, ExpertAttendStatus.ON_LEAVE); | |||||
if (page.getTotal() == 0) { | |||||
return PageVo.empty(); | |||||
} | |||||
Map<Long, Meeting> meetingMap = CollUtils.listToMap(meetings, Meeting::getId); | |||||
List<Long> expertIds = CollUtils.fieldList(page.getRecords(), MeetingExpert::getExpertId); | |||||
Map<Long, ExpertBasicInfoVO> basicInfoVoMap = meetingManageHelper.getExpertBasicInfo(expertIds); | |||||
List<ExpertReplaceTodoListItemVO> dataList = page.getRecords().stream().map(w -> { | |||||
ExpertBasicInfoVO basicInfoVo = basicInfoVoMap.get(w.getExpertId()); | |||||
ExpertReplaceTodoListItemVO item = BeanUtil.copyProperties(basicInfoVo, ExpertReplaceTodoListItemVO.class); | |||||
item.setMeetingId(w.getMeetingId()); | |||||
item.setExpertMeetingId(w.getId()); | |||||
Meeting meeting = meetingMap.get(w.getMeetingId()); | |||||
item.setMeetingName(meeting.getName()); | |||||
item.setInviteType(ExpertInviteType.getByCode(w.getInviteType()).getName()); | |||||
item.setStatus(w.getStatus()); | |||||
item.setStartTime(meeting.getStartTime()); | |||||
item.setEndTime(meeting.getEndTime()); | |||||
return item; | |||||
}).collect(Collectors.toList()); | |||||
return PageVo.of(dataList, page.getTotal()); | |||||
} | |||||
public MeetingCountSummaryVO meetingCountSummary() { | |||||
Map<MeetingStatusByDashboard, Integer> meetingCountSummary = meetingService.meetingCountSummary(LoginUserUtil.getUserId()); | |||||
return MeetingCountSummaryVO.builder() | |||||
.canceled(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.CANCELED, 0)) | |||||
.completed(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.COMPLETED, 0)) | |||||
.toBeHeld(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.TO_BE_HELD, 0)) | |||||
.held(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.HELD, 0)) | |||||
.build(); | |||||
} | |||||
public MeetingCountByExpertVO meetingCountByExpert() { | |||||
List<MeetingAndAttendStatusDTO> attendStatusList = meetingExpertService.listByExpertIdAndStatus(LoginUserUtil.getUserId(), null, null); | |||||
MeetingCountByExpertVO result = MeetingCountByExpertVO.init(); | |||||
attendStatusList.forEach(w -> { | |||||
if (w.getStatus().equals(ExpertAttendStatus.ON_LEAVE.getCode())) { | |||||
result.incrLeaved(); | |||||
} else if (w.getAttended() != null && w.getAttended()) { | |||||
result.incrAttended(); | |||||
} else { | |||||
result.incrToBeAttended(); | |||||
} | |||||
}); | |||||
return result; | |||||
} | |||||
} |
@@ -0,0 +1,672 @@ | |||||
package com.ningdatech.pmapi.meeting.manage; | |||||
import cn.hutool.core.collection.CollUtil; | |||||
import com.alibaba.fastjson.JSONObject; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.pmapi.common.util.BizUtils; | |||||
import com.ningdatech.pmapi.expert.constant.ExpertAccountStatusEnum; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertAvoidCompany; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import com.ningdatech.pmapi.expert.service.IExpertAvoidCompanyService; | |||||
import com.ningdatech.pmapi.expert.service.IExpertIntentionWorkRegionService; | |||||
import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
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.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.*; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | |||||
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import com.ningdatech.pmapi.meta.helper.TagCache; | |||||
import com.ningdatech.pmapi.meta.model.entity.ExpertDictionary; | |||||
import com.ningdatech.pmapi.meta.model.entity.ExpertTag; | |||||
import com.ningdatech.pmapi.meta.service.IExpertDictionaryService; | |||||
import com.ningdatech.pmapi.meta.service.IExpertTagService; | |||||
import lombok.AllArgsConstructor; | |||||
import org.apache.commons.collections4.CollectionUtils; | |||||
import org.apache.commons.collections4.MapUtils; | |||||
import org.apache.commons.collections4.Predicate; | |||||
import org.apache.commons.lang3.ObjectUtils; | |||||
import org.apache.commons.lang3.RandomUtils; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.util.Assert; | |||||
import java.time.LocalDateTime; | |||||
import java.util.*; | |||||
import java.util.stream.Collectors; | |||||
import java.util.stream.Stream; | |||||
/** | |||||
* <p> | |||||
* 专家邀请管理 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 18:05 2022/8/8 | |||||
*/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class ExpertInviteManage { | |||||
private final IExpertDictionaryService expertDictionaryService; | |||||
private final TagCache tagCache; | |||||
private final IExpertTagService expertTagService; | |||||
private final IExpertIntentionWorkRegionService workRegionService; | |||||
private final IExpertInviteRuleService inviteRuleService; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final ExpertInviteHelper expertInviteHelper; | |||||
private final IExpertUserFullInfoService expertUserFullInfoService; | |||||
private final IMeetingService meetingService; | |||||
private final IExpertAvoidCompanyService iExpertAvoidCompanyService; | |||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
private static final Predicate<Collection<?>> COLL_EMPTY = (coll) -> coll != null && coll.isEmpty(); | |||||
private LambdaQueryWrapper<ExpertUserFullInfo> buildBaseExpertQuery() { | |||||
return Wrappers.lambdaQuery(ExpertUserFullInfo.class) | |||||
.select(ExpertUserFullInfo::getUserId, | |||||
ExpertUserFullInfo::getId, | |||||
ExpertUserFullInfo::getCompany, | |||||
ExpertUserFullInfo::getPhoneNo) | |||||
.eq(ExpertUserFullInfo::getExpertAccountStatus, ExpertAccountStatusEnum.AVAILABLE.getKey()); | |||||
} | |||||
/** | |||||
* 增加专家层级限制 | |||||
* | |||||
* @param query 查询 | |||||
* @param rule 随机邀请规则 | |||||
*/ | |||||
private static void addRegionLimit(LambdaQueryWrapper<ExpertUserFullInfo> query, RandomInviteRuleDTO rule) { | |||||
if (ObjectUtils.allNotNull(rule.getExpertRegionCode(), rule.getExpertRegionLevel())) { | |||||
query.eq(ExpertUserFullInfo::getRegionCode, rule.getExpertRegionCode()); | |||||
query.eq(ExpertUserFullInfo::getRegionLevel, rule.getExpertRegionLevel()); | |||||
} | |||||
} | |||||
/** | |||||
* 获取满足履职意向地的专家ID | |||||
* null -> 表示无需过滤 | |||||
* | |||||
* @param rule 抽取规则 | |||||
* @return java.util.List<java.lang.Long> | |||||
* @author WendyYang | |||||
**/ | |||||
private List<Long> expertIdsByRegion(RandomInviteRuleDTO rule) { | |||||
if (rule.getIntentionRegionCode() == null || rule.getIntentionRegionLevel() == null) { | |||||
return null; | |||||
} | |||||
return workRegionService.userIdsMatchIntentionRegion(rule.getIntentionRegionCode(), rule.getIntentionRegionLevel()); | |||||
} | |||||
/** | |||||
* 如果抽取回避单位和专家回避单位一致,同样需要回避该专家 | |||||
* | |||||
* @param companyNames / | |||||
* @return / | |||||
*/ | |||||
private List<Long> avoidCompanyExpertIds(List<String> companyNames) { | |||||
if (CollUtil.isEmpty(companyNames)) { | |||||
return new ArrayList<>(); | |||||
} | |||||
List<String> dealCompanyNames = new ArrayList<>(); | |||||
for (String companyName : companyNames) { | |||||
if (companyName.contains(",")) { | |||||
String[] splitCompanyNames = companyName.split(","); | |||||
for (String splitCompanyName : splitCompanyNames) { | |||||
dealCompanyNames.add(splitCompanyName); | |||||
} | |||||
} else { | |||||
dealCompanyNames.add(companyName); | |||||
} | |||||
} | |||||
List<ExpertAvoidCompany> expertAvoidCompanyList = iExpertAvoidCompanyService.list(Wrappers.lambdaQuery(ExpertAvoidCompany.class) | |||||
.in(ExpertAvoidCompany::getCompanyName, dealCompanyNames)); | |||||
return expertAvoidCompanyList.stream().map(ExpertAvoidCompany::getUserId).distinct().collect(Collectors.toList()); | |||||
} | |||||
private List<Long> mergeExpertIdsByCondition(RandomInviteRuleDTO rule, AvoidInfoDTO avoidInfo) { | |||||
// 处理履职意向地 | |||||
List<Long> expertIdsByIntentionRegion = expertIdsByRegion(rule); | |||||
if (COLL_EMPTY.evaluate(expertIdsByIntentionRegion)) { | |||||
return null; | |||||
} | |||||
// 处理专家标签 | |||||
List<Long> expertIdsByTag = expertIdsByTag(rule); | |||||
if (COLL_EMPTY.evaluate(expertIdsByTag)) { | |||||
return null; | |||||
} | |||||
// 处理专家字典 | |||||
List<Long> expertIdsByDict = expertIdsByDict(rule); | |||||
if (COLL_EMPTY.evaluate(expertIdsByDict)) { | |||||
return null; | |||||
} | |||||
// 处理专家回避单位 与 抽取回避单位是否相同 | |||||
List<Long> avoidCompanyExpertIds = avoidCompanyExpertIds(avoidInfo.getCompanyIds()); | |||||
// 聚合用户ID | |||||
List<Long> expertIdsIn = new ArrayList<>(); | |||||
if (ObjectUtils.anyNotNull(expertIdsByDict, expertIdsByTag, expertIdsByIntentionRegion)) { | |||||
Optional.ofNullable(expertIdsByDict).ifPresent(expertIdsIn::addAll); | |||||
Optional.ofNullable(expertIdsByTag).ifPresent(item -> { | |||||
if (expertIdsIn.isEmpty()) { | |||||
expertIdsIn.addAll(expertIdsByTag); | |||||
} else { | |||||
expertIdsIn.removeIf(w -> !expertIdsByTag.contains(w)); | |||||
} | |||||
}); | |||||
Optional.ofNullable(expertIdsByIntentionRegion).ifPresent(item -> { | |||||
if (expertIdsIn.isEmpty()) { | |||||
expertIdsIn.addAll(expertIdsByIntentionRegion); | |||||
} else { | |||||
expertIdsIn.removeIf(w -> !expertIdsByIntentionRegion.contains(w)); | |||||
} | |||||
}); | |||||
if (expertIdsIn.isEmpty()) { | |||||
return null; | |||||
} | |||||
} | |||||
if (CollUtil.isNotEmpty(avoidCompanyExpertIds)) { | |||||
for (Long avoidCompanyExpertId : avoidCompanyExpertIds) { | |||||
expertIdsIn.remove(avoidCompanyExpertId); | |||||
} | |||||
} | |||||
return expertIdsIn; | |||||
} | |||||
/** | |||||
* 根据专家标签获取满足的专家ID | |||||
* | |||||
* @param rule 抽取规则 | |||||
* @return java.util.List<java.lang.Long> | |||||
* @author WendyYang | |||||
**/ | |||||
private List<Long> expertIdsByTag(RandomInviteRuleDTO rule) { | |||||
if (CollectionUtils.isEmpty(rule.getExpertTags())) { | |||||
return null; | |||||
} | |||||
LambdaQueryWrapper<ExpertTag> query = Wrappers.lambdaQuery(ExpertTag.class) | |||||
.select(ExpertTag::getUserId, ExpertTag::getExpertInfoField); | |||||
rule.getExpertTags().forEach(tag -> { | |||||
List<String> codes = tag.getTagCodes().stream() | |||||
.map(tagCache::listChildrenCodes) | |||||
.flatMap(Collection::stream) | |||||
.collect(Collectors.toList()); | |||||
query.or(wrapper -> wrapper.eq(ExpertTag::getExpertInfoField, tag.getExpertTag()) | |||||
.in(ExpertTag::getTagCode, codes)); | |||||
}); | |||||
List<ExpertTag> expertTagList = expertTagService.list(query); | |||||
return expertTagList.stream() | |||||
.collect(Collectors.groupingBy(ExpertTag::getUserId, Collectors.collectingAndThen(Collectors.toList(), | |||||
tags -> CollUtils.fieldList(tags, ExpertTag::getExpertInfoField).size()))) | |||||
.entrySet().stream().filter(w -> w.getValue() == rule.getExpertTags().size()) | |||||
.map(Map.Entry::getKey).collect(Collectors.toList()); | |||||
} | |||||
/** | |||||
* 根据专家字典获取满足的专家ID | |||||
* null -> 表示无需过虑 | |||||
* 空集合 -> 未查到 | |||||
* | |||||
* @param rule 抽取规则 | |||||
* @return java.util.List<java.lang.Long> | |||||
* @author WendyYang | |||||
**/ | |||||
private List<Long> expertIdsByDict(RandomInviteRuleDTO rule) { | |||||
if (CollectionUtils.isEmpty(rule.getExpertDicts())) { | |||||
return null; | |||||
} | |||||
LambdaQueryWrapper<ExpertDictionary> query = Wrappers.lambdaQuery(ExpertDictionary.class) | |||||
.select(ExpertDictionary::getUserId, ExpertDictionary::getExpertInfoField); | |||||
for (ExpertDictChooseDTO dict : rule.getExpertDicts()) { | |||||
query.or(wrapper -> wrapper.eq(ExpertDictionary::getExpertInfoField, dict.getExpertDict()) | |||||
.in(ExpertDictionary::getDictionaryCode, dict.getDictCodes())); | |||||
} | |||||
List<ExpertDictionary> expertDictionaryList = expertDictionaryService.list(query); | |||||
return expertDictionaryList.stream() | |||||
.collect(Collectors.groupingBy(ExpertDictionary::getUserId, | |||||
Collectors.collectingAndThen(Collectors.toList(), | |||||
dicts -> CollUtils.fieldList(dicts, ExpertDictionary::getExpertInfoField).size()))) | |||||
.entrySet().stream().filter(w -> w.getValue() == rule.getExpertDicts().size()) | |||||
.map(Map.Entry::getKey).collect(Collectors.toList()); | |||||
} | |||||
/** | |||||
* 专家抽取(随机) | |||||
* | |||||
* @param avoidInfo 回避信息 | |||||
* @param randomRule 抽取规则 | |||||
* @param appointExpertIds 指定抽取专家ID | |||||
* @return 满足抽取条件的专家 | |||||
* @author WendyYang | |||||
**/ | |||||
public ExpertChooseDTO expertInviteByRandomRule(AvoidInfoDTO avoidInfo, | |||||
RandomInviteRuleDTO randomRule, | |||||
List<Long> appointExpertIds, | |||||
LocalDateTime start, | |||||
LocalDateTime end) { | |||||
ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | |||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo); | |||||
if (expertIdsIn == null) { | |||||
return result; | |||||
} | |||||
boolean avoid = avoidInfo != null; | |||||
boolean avoidExpert = avoid && CollUtil.isNotEmpty(avoidInfo.getExpertIds()); | |||||
boolean avoidCompany = avoid && CollUtil.isNotEmpty(avoidInfo.getCompanyIds()); | |||||
Set<String> tmpAvoidCompany = new HashSet<>(); | |||||
if (avoidCompany) { | |||||
List<String> companyIds = avoidInfo.getCompanyIds(); | |||||
for (String companyId : companyIds) { | |||||
if (companyId.contains(",")) { | |||||
String[] splitCompanyIds = companyId.split(","); | |||||
for (String splitCompanyId : splitCompanyIds) { | |||||
tmpAvoidCompany.add(splitCompanyId); | |||||
} | |||||
} else { | |||||
tmpAvoidCompany.add(companyId); | |||||
} | |||||
} | |||||
} | |||||
// 回避信息 | |||||
if (CollUtil.isNotEmpty(appointExpertIds) && avoid && avoidInfo.getAvoidMates()) { | |||||
// 如果设置了回避本单位同事且手动指定了专家,则对应的单位需要排除 | |||||
List<ExpertUserFullInfo> appointUsers = expertUserFullInfoService.listByUserId(appointExpertIds); | |||||
tmpAvoidCompany.addAll(CollUtils.fieldList(appointUsers, ExpertUserFullInfo::getCompany)); | |||||
} | |||||
LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery(); | |||||
query.notIn(!tmpAvoidCompany.isEmpty(), ExpertUserFullInfo::getCompany, tmpAvoidCompany); | |||||
if (avoidCompany) { | |||||
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.getCompanyIds())); | |||||
} | |||||
// 处理专家层级 | |||||
addRegionLimit(query, randomRule); | |||||
if (!expertIdsIn.isEmpty()) { | |||||
if (avoidExpert) { | |||||
expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w)); | |||||
if (expertIdsIn.isEmpty()) { | |||||
// 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | |||||
// 如果为空则说明没有符合条件的 | |||||
return result; | |||||
} | |||||
} | |||||
if (CollUtil.isNotEmpty(appointExpertIds)) { | |||||
expertIdsIn.removeIf(appointExpertIds::contains); | |||||
if (expertIdsIn.isEmpty()) { | |||||
return result; | |||||
} | |||||
} | |||||
// 过滤掉已参加会议的专家 | |||||
List<Long> expertIdsLockByMeeting = expertInviteHelper.listInvitedExpertByTime(start, end); | |||||
expertIdsIn.removeIf(expertIdsLockByMeeting::contains); | |||||
if (expertIdsIn.isEmpty()) { | |||||
return result; | |||||
} | |||||
query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | |||||
} else if (avoidExpert || CollUtil.isNotEmpty(appointExpertIds)) { | |||||
Set<Long> tempExperts = expertInviteHelper.getAvoidExpert(appointExpertIds, avoidInfo, start, end); | |||||
query.notIn(ExpertUserFullInfo::getUserId, tempExperts); | |||||
} else { | |||||
Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | |||||
if (!notInUserIds.isEmpty()) { | |||||
query.notIn(ExpertUserFullInfo::getUserId, notInUserIds); | |||||
} | |||||
} | |||||
List<ExpertUserFullInfo> userFullInfos = expertUserFullInfoService.list(query); | |||||
if (userFullInfos.isEmpty()) { | |||||
return result; | |||||
} | |||||
if (avoid && avoidInfo.getAvoidMates()) { | |||||
// 回避同单位其他专家 | |||||
Map<String, List<ExpertUserFullInfo>> userFullInfoMap = CollUtils.group(userFullInfos, ExpertUserFullInfo::getCompany); | |||||
result.setTotal(userFullInfoMap.size()); | |||||
if (randomRule.getCount() == null || userFullInfoMap.size() >= randomRule.getCount()) { | |||||
List<ExpertUserFullInfo> userFullInfoList = inviteGroupByCompany(userFullInfoMap, randomRule.getCount()); | |||||
result.setExperts(userFullInfoList); | |||||
} | |||||
} else { | |||||
result.setTotal(userFullInfos.size()); | |||||
// count为空表示数量校验 | |||||
if (randomRule.getCount() == null || result.getTotal() >= randomRule.getCount()) { | |||||
List<ExpertUserFullInfo> userFullInfoList = inviteWithoutCompany(userFullInfos, randomRule.getCount()); | |||||
result.setExperts(userFullInfoList); | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* 专家替换、补充 | |||||
* | |||||
* @param avoidInfo 回避信息 | |||||
* @param randomRule 随机抽取 | |||||
* @param meetingExperts 已抽取人员 | |||||
* @param count 抽取数量 | |||||
* @return com.ningdatech.emapi.meeting.entity.dto.ExpertChooseDto | |||||
* @author WendyYang | |||||
**/ | |||||
public ExpertChooseDTO expertReplaceByRandomRule(AvoidInfoDTO avoidInfo, | |||||
RandomInviteRuleDTO randomRule, | |||||
Collection<MeetingExpert> meetingExperts, | |||||
Integer count, | |||||
LocalDateTime start, | |||||
LocalDateTime end, | |||||
Long replacedExpertId) { | |||||
ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0); | |||||
// 合并标签、字典 | |||||
List<Long> expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo); | |||||
if (expertIdsIn == null) { | |||||
return result; | |||||
} | |||||
LambdaQueryWrapper<ExpertUserFullInfo> query = buildBaseExpertQuery(); | |||||
query.notIn(ExpertUserFullInfo::getCompany, avoidInfo.getCompanyIds()); | |||||
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.getCompanyIds())); | |||||
// 处理专家层级 | |||||
if (ObjectUtils.allNotNull(randomRule.getExpertRegionCode(), randomRule.getExpertRegionLevel())) { | |||||
query.eq(ExpertUserFullInfo::getRegionCode, randomRule.getExpertRegionCode()); | |||||
query.eq(ExpertUserFullInfo::getRegionLevel, randomRule.getExpertRegionLevel()); | |||||
} | |||||
if (expertIdsIn.size() > 0) { | |||||
if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w)); | |||||
if (expertIdsIn.isEmpty()) { | |||||
// 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID | |||||
// 如果为空则说明没有符合条件的 | |||||
return result; | |||||
} | |||||
} | |||||
List<Long> lockExpertIds = expertInviteHelper.listInvitedExpertByTime(start, end); | |||||
expertIdsIn.removeIf(lockExpertIds::contains); | |||||
if (expertIdsIn.isEmpty()) { | |||||
return result; | |||||
} | |||||
query.in(ExpertUserFullInfo::getUserId, expertIdsIn); | |||||
} else if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
Set<Long> notInExpertIds = expertInviteHelper.getAvoidExpert(avoidInfo.getExpertIds(), null, start, end); | |||||
query.notIn(ExpertUserFullInfo::getUserId, notInExpertIds); | |||||
} else { | |||||
Set<Long> notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end); | |||||
if (notInUserIds.size() > 0) { | |||||
query.notIn(ExpertUserFullInfo::getUserId, notInUserIds); | |||||
} | |||||
} | |||||
List<ExpertUserFullInfo> userFullInfos = expertUserFullInfoService.list(query); | |||||
if (userFullInfos.size() == 0) { | |||||
return result; | |||||
} | |||||
Comparator<MeetingExpert> sort = Comparator.comparing(MeetingExpert::getUpdateOn).reversed(); | |||||
Map<Long, MeetingExpert> tempExpertIdsMap = BizUtils.groupFirstMap(meetingExperts, MeetingExpert::getExpertId, sort); | |||||
Map<ExpertAttendStatus, List<MeetingExpert>> expertIdGroupByStatus = tempExpertIdsMap.values().stream() | |||||
.collect(Collectors.groupingBy(w -> ExpertAttendStatus.getByCode(w.getStatus()))); | |||||
// 回避同单位其他专家 | |||||
List<MeetingExpert> removeExpertByCompany = new ArrayList<>(); | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.AGREED), removeExpertByCompany::addAll); | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.NOTICING), removeExpertByCompany::addAll); | |||||
List<Long> removeExpertIds = new ArrayList<>(); | |||||
// 拒绝参加的不可以被再次抽中 | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.REFUSED), w -> { | |||||
List<Long> tempRefused = CollUtils.fieldList(w, MeetingExpert::getExpertId); | |||||
removeExpertIds.addAll(tempRefused); | |||||
}); | |||||
// 被取消的也不可以被再次抽中 | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.CANCELED), w -> { | |||||
List<Long> tempCanceled = CollUtils.fieldList(w, MeetingExpert::getExpertId); | |||||
removeExpertIds.addAll(tempCanceled); | |||||
}); | |||||
// 被替换之前是上述两种状态的不可被再次抽中 | |||||
BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.REPLACED), w -> { | |||||
for (MeetingExpert me : w) { | |||||
BizUtils.notNull(me.getPreStatus(), preStatus -> { | |||||
if (ExpertAttendStatus.REFUSED.eq(preStatus) || ExpertAttendStatus.CANCELED.eq(preStatus)) { | |||||
removeExpertIds.add(me.getExpertId()); | |||||
} | |||||
}); | |||||
} | |||||
}); | |||||
// 不为空时表示单个专家替换否则为专家补抽 | |||||
if (replacedExpertId != null) { | |||||
removeExpertIds.add(replacedExpertId); | |||||
} | |||||
List<Long> tempExpertIds = CollUtils.fieldList(removeExpertByCompany, MeetingExpert::getExpertId); | |||||
if (avoidInfo.getAvoidMates()) { | |||||
if (!tempExpertIds.isEmpty()) { | |||||
Set<String> confirmedCompany = userFullInfos.stream() | |||||
.filter(w -> tempExpertIds.contains(w.getUserId())) | |||||
.map(ExpertUserFullInfo::getCompany).collect(Collectors.toSet()); | |||||
userFullInfos.removeIf(w -> confirmedCompany.contains(w.getCompany())); | |||||
} | |||||
userFullInfos.removeIf(w -> removeExpertIds.contains(w.getUserId())); | |||||
Map<String, List<ExpertUserFullInfo>> groupByCompany = CollUtils.group(userFullInfos, ExpertUserFullInfo::getCompany); | |||||
result.setTotal(groupByCompany.size()); | |||||
result.setExperts(inviteGroupByCompany(groupByCompany, count)); | |||||
} else { | |||||
// 移除确认参加、通知中的、拒绝参加、已取消 | |||||
userFullInfos.removeIf(w -> tempExpertIds.contains(w.getUserId()) || removeExpertIds.contains(w.getUserId())); | |||||
result.setTotal(userFullInfos.size()); | |||||
result.setExperts(inviteWithoutCompany(userFullInfos, count)); | |||||
} | |||||
return result; | |||||
} | |||||
private List<List<MeetingExpert>> selectMeetingExpertByCount() { | |||||
LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class) | |||||
.select(Meeting::getId) | |||||
.orderByDesc(Meeting::getCreateOn) | |||||
.last("limit " + 5); | |||||
List<Long> meetingIds = CollUtils.fieldList(meetingService.list(query), Meeting::getId); | |||||
if (meetingIds.isEmpty()) { | |||||
return Collections.emptyList(); | |||||
} | |||||
Map<Long, List<MeetingExpert>> groupByMeetingId = meetingExpertService.listByMeetingIds(meetingIds) | |||||
.stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId)); | |||||
return groupByMeetingId.entrySet().stream() | |||||
.sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) | |||||
.map(Map.Entry::getValue) | |||||
.collect(Collectors.toList()); | |||||
} | |||||
/** | |||||
* 每个单位只抽取一人 | |||||
* | |||||
* @param expertGroupByCompany 需要抽取的人 | |||||
* @param count 抽取数量 | |||||
* @return java.util.List<com.ningdatech.emapi.expert.entity.domain.ExpertUserFullInfo> | |||||
* @author WendyYang | |||||
**/ | |||||
private List<ExpertUserFullInfo> inviteGroupByCompany(Map<String, List<ExpertUserFullInfo>> expertGroupByCompany, Integer count) { | |||||
if (MapUtils.isEmpty(expertGroupByCompany)) { | |||||
return Collections.emptyList(); | |||||
} | |||||
List<List<MeetingExpert>> meetingExperts = selectMeetingExpertByCount(); | |||||
if (meetingExperts.isEmpty()) { | |||||
return expertGroupByCompany.values().stream() | |||||
.map(expertUsers -> expertUsers.get(RandomUtils.nextInt(0, expertUsers.size()))) | |||||
.limit(count).collect(Collectors.toList()); | |||||
} else { | |||||
List<ExpertUserFullInfo> result = new ArrayList<>(); | |||||
List<String> keySet = new ArrayList<>(expertGroupByCompany.keySet()); | |||||
for (int i = 0; i < count; i++) { | |||||
String key = keySet.get(RandomUtils.nextInt(0, keySet.size())); | |||||
List<ExpertUserFullInfo> expertUserFullInfos = expertGroupByCompany.get(key); | |||||
for (List<MeetingExpert> expertList : meetingExperts) { | |||||
List<ExpertUserFullInfo> tempList = expertUserFullInfos.stream() | |||||
.filter(w -> expertList.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId()))) | |||||
.collect(Collectors.toList()); | |||||
if (!tempList.isEmpty()) { | |||||
result.add(tempList.get(RandomUtils.nextInt(0, tempList.size()))); | |||||
break; | |||||
} else if (meetingExperts.indexOf(expertList) == (meetingExperts.size() - 1)) { | |||||
result.add(expertUserFullInfos.get(RandomUtils.nextInt(0, expertUserFullInfos.size()))); | |||||
} | |||||
} | |||||
if (result.size() < count) { | |||||
keySet.remove(key); | |||||
if (keySet.isEmpty()) { | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
} | |||||
private List<ExpertUserFullInfo> inviteWithoutCompany(List<ExpertUserFullInfo> userFullInfos, Integer count) { | |||||
List<ExpertUserFullInfo> result = new ArrayList<>(); | |||||
List<List<MeetingExpert>> meetingExpertList = selectMeetingExpertByCount(); | |||||
if (meetingExpertList.isEmpty()) { | |||||
for (int i = 0; i < count; i++) { | |||||
int randomIndex = RandomUtils.nextInt(0, userFullInfos.size()); | |||||
result.add(userFullInfos.remove(randomIndex)); | |||||
if (userFullInfos.size() == 0) { | |||||
break; | |||||
} | |||||
} | |||||
} else { | |||||
for (List<MeetingExpert> meetingExperts : meetingExpertList) { | |||||
List<ExpertUserFullInfo> unSelectedUsers = userFullInfos.stream() | |||||
.filter(w -> meetingExperts.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId()))) | |||||
.collect(Collectors.toList()); | |||||
if (!unSelectedUsers.isEmpty()) { | |||||
result.addAll(unSelectedUsers); | |||||
if (result.size() >= count) { | |||||
return result.subList(0, count); | |||||
} | |||||
userFullInfos.removeAll(unSelectedUsers); | |||||
} | |||||
} | |||||
if (userFullInfos.size() == 0) { | |||||
return result; | |||||
} | |||||
int restCount = Math.min(count - result.size(), userFullInfos.size()); | |||||
int groupCount = userFullInfos.size() / restCount; | |||||
if (userFullInfos.size() > restCount) { | |||||
Stream.iterate(0, t -> t + 1).limit(restCount) | |||||
.forEach(t -> { | |||||
int start = t * groupCount; | |||||
int end = start + groupCount; | |||||
if (end >= groupCount * restCount) { | |||||
end = userFullInfos.size(); | |||||
} | |||||
result.add(userFullInfos.get(RandomUtils.nextInt(start, end))); | |||||
}); | |||||
} else { | |||||
result.addAll(userFullInfos); | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* 构建邀请规则 | |||||
* | |||||
* @param inviteRule 邀请规则 | |||||
* @param meetingId 会议ID | |||||
* @return {@link ExpertInviteRule} | |||||
* @author WendyYang | |||||
**/ | |||||
private static ExpertInviteRule getExpertInviteRule(AbstractInviteRule inviteRule, Long meetingId) { | |||||
ExpertInviteRule rule = new ExpertInviteRule(); | |||||
rule.setInviteRule(JSONObject.toJSONString(inviteRule)); | |||||
rule.setInviteCount(inviteRule.getCount()); | |||||
rule.setInviteType(inviteRule.getInviteType()); | |||||
rule.setMeetingId(meetingId); | |||||
return rule; | |||||
} | |||||
public Map<Long, ExpertUserFullInfo> checkAppointExpertConflictWithAvoidRule(AppointInviteRuleDTO appointRule, AvoidInfoDTO avoidRule) { | |||||
if (appointRule == null) { | |||||
return Collections.emptyMap(); | |||||
} | |||||
List<ExpertUserFullInfo> expertInfos = expertUserFullInfoService.listByUserId(appointRule.getExpertIds()); | |||||
Map<Long, ExpertUserFullInfo> infoMap = CollUtils.listToMap(expertInfos, ExpertUserFullInfo::getUserId); | |||||
if (avoidRule == null) { | |||||
return infoMap; | |||||
} | |||||
Map<String, Integer> countMap = new HashMap<>(16); | |||||
infoMap.forEach((key, userFullInfo) -> { | |||||
if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds())) { | |||||
boolean contains = avoidRule.getExpertIds().contains(key); | |||||
Assert.isTrue(!contains, "已回避的专家不可被指定邀请"); | |||||
} | |||||
if (CollectionUtils.isNotEmpty(avoidRule.getCompanyIds())) { | |||||
boolean contains = avoidRule.getCompanyIds().contains(userFullInfo.getCompany()); | |||||
Assert.isTrue(!contains, "回避单位的专家不可出现在指定邀请名单中"); | |||||
} | |||||
if (avoidRule.getAvoidMates()) { | |||||
Integer oldValue = countMap.put(userFullInfo.getCompany(), 1); | |||||
Assert.isNull(oldValue, "不可选择同单位的多个专家"); | |||||
} | |||||
}); | |||||
return infoMap; | |||||
} | |||||
/** | |||||
* 专家抽取(会议创建时抽取) | |||||
* | |||||
* @param randomRules 随机抽取规则 | |||||
* @param appointRule 指定抽取规则 | |||||
* @param avoid 回避信息 | |||||
* @author WendyYang | |||||
**/ | |||||
public void expertInviteByMeetingCreate(Meeting meeting, | |||||
List<RandomInviteRuleDTO> randomRules, | |||||
AppointInviteRuleDTO appointRule, | |||||
AvoidInfoDTO avoid) { | |||||
Map<Long, ExpertUserFullInfo> appointUser = checkAppointExpertConflictWithAvoidRule(appointRule, avoid); | |||||
List<MeetingExpert> expertInserts = new ArrayList<>(); | |||||
boolean appointed = appointRule != null; | |||||
// 处理随机抽取规则 | |||||
if (CollectionUtils.isNotEmpty(randomRules)) { | |||||
List<ExpertInviteRule> randoms = new ArrayList<>(); | |||||
List<ExpertChooseDTO> expertsByRandom = new ArrayList<>(); | |||||
List<Long> tempExpertIdSelected = new ArrayList<>(); | |||||
if (appointed) { | |||||
tempExpertIdSelected.addAll(appointRule.getExpertIds()); | |||||
} | |||||
LocalDateTime startTime = meeting.getStartTime(), endTime = meeting.getEndTime(); | |||||
randomRules.forEach(rule -> { | |||||
ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoid, rule, tempExpertIdSelected, startTime, endTime); | |||||
expertsByRandom.add(tempExperts); | |||||
tempExpertIdSelected.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId)); | |||||
randoms.add(getExpertInviteRule(rule, meeting.getId())); | |||||
}); | |||||
inviteRuleService.saveBatch(randoms); | |||||
for (int i = 0; i < expertsByRandom.size(); i++) { | |||||
Long ruleId = randoms.get(i).getId(); | |||||
expertsByRandom.get(i).getExperts().forEach(w -> { | |||||
MeetingExpert expert = ExpertInviteBuilder.getExpertByRandom(meeting.getId(), w, ruleId); | |||||
expert.setStatus(ExpertAttendStatus.NOTICING.getCode()); | |||||
expertInserts.add(expert); | |||||
}); | |||||
} | |||||
yxtCallOrSmsHelper.callByMeetingExperts(meeting, expertInserts); | |||||
} | |||||
if (appointed) { | |||||
// 处理指定抽取规则 | |||||
ExpertInviteRule appoint = getExpertInviteRule(appointRule, meeting.getId()); | |||||
inviteRuleService.save(appoint); | |||||
Long ruleId = appoint.getId(); | |||||
appointRule.getExpertIds().forEach(w -> { | |||||
ExpertUserFullInfo info = appointUser.get(w); | |||||
MeetingExpert expert = ExpertInviteBuilder.getExpertByAppoint(meeting.getId(), info, ruleId); | |||||
expert.setStatus(ExpertAttendStatus.NOTICING.getCode()); | |||||
expertInserts.add(expert); | |||||
}); | |||||
} | |||||
meetingExpertService.saveBatch(expertInserts); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package com.ningdatech.pmapi.meeting.manage; | |||||
import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertEvaluationService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import lombok.AllArgsConstructor; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* <p> | |||||
* MeetingExpertManage | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 10:04 2022/8/24 | |||||
*/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class MeetingExpertManage { | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final IMeetingExpertEvaluationService meetingExpertEvaluationService; | |||||
private final MeetingManageHelper meetingManageHelper; | |||||
} |
@@ -0,0 +1,708 @@ | |||||
package com.ningdatech.pmapi.meeting.manage; | |||||
import cn.hutool.core.bean.BeanUtil; | |||||
import cn.hutool.core.collection.CollUtil; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import cn.hutool.crypto.SecureUtil; | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.ningdatech.basic.exception.BizException; | |||||
import com.ningdatech.basic.model.IdVo; | |||||
import com.ningdatech.basic.model.PageVo; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.basic.util.ValidUtil; | |||||
import com.ningdatech.cache.lock.DistributedLock; | |||||
import com.ningdatech.file.entity.vo.result.AttachFileVo; | |||||
import com.ningdatech.file.service.FileService; | |||||
import com.ningdatech.pmapi.common.util.BizUtils; | |||||
import com.ningdatech.pmapi.common.util.StrUtils; | |||||
import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
import com.ningdatech.pmapi.expert.helper.PermissionCheckHelper; | |||||
import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.*; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus.Manager; | |||||
import com.ningdatech.pmapi.meeting.entity.req.*; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.*; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.ExpertInviteDetailVO.ExpertAttendListItemVO; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.ExpertInviteDetailVO.RandomInviteListItemVO; | |||||
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | |||||
import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper; | |||||
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import com.ningdatech.pmapi.meeting.task.ExpertInviteTask; | |||||
import com.ningdatech.pmapi.meta.helper.DictionaryCache; | |||||
import com.ningdatech.pmapi.meta.helper.TagCache; | |||||
import com.ningdatech.pmapi.user.entity.UserInfo; | |||||
import com.ningdatech.pmapi.user.service.IUserInfoService; | |||||
import com.ningdatech.pmapi.user.util.LoginUserUtil; | |||||
import lombok.RequiredArgsConstructor; | |||||
import org.apache.commons.collections4.CollectionUtils; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.transaction.annotation.Transactional; | |||||
import org.springframework.util.Assert; | |||||
import java.time.LocalDateTime; | |||||
import java.util.*; | |||||
import java.util.function.Function; | |||||
/** | |||||
* <p> | |||||
* MeetingManage | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 13:35 2022/7/26 | |||||
*/ | |||||
@Component | |||||
@RequiredArgsConstructor | |||||
public class MeetingManage { | |||||
private final IMeetingService meetingService; | |||||
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | |||||
private final IExpertInviteRuleService inviteRuleService; | |||||
private final IExpertUserFullInfoService expertUserFullInfoService; | |||||
private final FileService fileService; | |||||
private final TagCache tagCache; | |||||
private final DictionaryCache dictionaryCache; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final ExpertInviteManage expertInviteManage; | |||||
private final ExpertInviteTask expertInviteTask; | |||||
private final MeetingManageHelper meetingManageHelper; | |||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
private final DistributedLock distributedLock; | |||||
private final PermissionCheckHelper permissionCheckHelper; | |||||
private final IUserInfoService userInfoService; | |||||
private final ExpertInviteHelper expertInviteHelper; | |||||
private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; | |||||
private static final String MEETING_CREATE_KEY = "MEETING_CREATE:"; | |||||
/** | |||||
* 锁定时间10 * 60秒 | |||||
*/ | |||||
public static final int RETRY_TIMES = 3; | |||||
public IdVo<Long> save(MeetingBasicDTO po) { | |||||
String md5ByParam = SecureUtil.md5(po.toString()); | |||||
String key = MEETING_CREATE_KEY + md5ByParam; | |||||
if (!distributedLock.lock(key, RETRY_TIMES)) { | |||||
throw BizException.wrap("会议正在创建中"); | |||||
} | |||||
try { | |||||
Meeting meeting = BeanUtil.copyProperties(po, Meeting.class); | |||||
meeting.setStatus(Manager.UNCOMPLETED.getCode()); | |||||
if (CollectionUtils.isNotEmpty(po.getAttachmentIds())) { | |||||
meeting.setAttachment(CollUtils.joinByComma(po.getAttachmentIds())); | |||||
} | |||||
Long userId = LoginUserUtil.getUserId(); | |||||
UserInfo userInfo = userInfoService.getById(userId); | |||||
meeting.setHoldCompany(po.getInviterCompany()); | |||||
meeting.setAuthor(userInfo.getUsername()); | |||||
meeting.setInvited(Boolean.FALSE); | |||||
meeting.setStopRandomInvite(true); | |||||
meeting.setSendMeetingNotice(false); | |||||
meetingService.save(meeting); | |||||
return IdVo.of(meeting.getId()); | |||||
} finally { | |||||
distributedLock.releaseLock(key); | |||||
} | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void expertInviteByCreate(ExpertInviteCreateReq req) { | |||||
// 未传递指定邀请专家直接忽略 | |||||
if (req.getAppointRule() != null && CollectionUtils.isEmpty(req.getAppointRule().getExpertIds())) { | |||||
Assert.isTrue(CollectionUtils.isNotEmpty(req.getRandomRules()), "未指定抽取规则"); | |||||
req.setAppointRule(null); | |||||
} | |||||
String key = INVITED_RULE_CREATE + req.getMeetingId(); | |||||
if (!distributedLock.lock(key, RETRY_TIMES)) { | |||||
throw BizException.wrap("不可重复进行专家抽取"); | |||||
} | |||||
try { | |||||
Meeting meeting = meetingService.getById(req.getMeetingId()); | |||||
Assert.isTrue(!meeting.getInvited(), "不可重复进行专家抽取"); | |||||
ExpertCountOnChangeVO countOnChange = expertCountOnChange(req); | |||||
for (int i = 0; i < req.getRandomRules().size(); i++) { | |||||
Integer checkCount = countOnChange.getCountList().get(i); | |||||
Integer inviteCount = req.getRandomRules().get(i).getCount(); | |||||
Assert.isTrue(checkCount >= inviteCount, "可供抽取的专家数量不足"); | |||||
} | |||||
AvoidInfoDTO avoidInfo = req.getAvoidInfo(); | |||||
expertInviteManage.expertInviteByMeetingCreate(meeting, req.getRandomRules(), req.getAppointRule(), avoidInfo); | |||||
LambdaUpdateWrapper<Meeting> updater = Wrappers.lambdaUpdate(Meeting.class) | |||||
.set(Meeting::getInvited, Boolean.TRUE) | |||||
.eq(Meeting::getId, req.getMeetingId()); | |||||
if (CollectionUtils.isNotEmpty(req.getRandomRules())) { | |||||
expertInviteTask.addInviteExpertTaskByMeetingCreate(meeting.getId(), 5); | |||||
updater.set(Meeting::getStopRandomInvite, false); | |||||
} | |||||
meetingService.update(updater); | |||||
// 回避规则 | |||||
if (avoidInfo != null) { | |||||
ExpertInviteAvoidRule avoidRule = new ExpertInviteAvoidRule(); | |||||
avoidRule.setMeetingId(meeting.getId()); | |||||
avoidRule.setAvoidMates(avoidInfo.getAvoidMates()); | |||||
avoidRule.setCompanyIds(CollUtils.joinByComma(avoidInfo.getCompanyIds())); | |||||
if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
avoidRule.setExpertIds(CollUtils.joinByComma(avoidInfo.getExpertIds())); | |||||
} | |||||
inviteAvoidRuleService.save(avoidRule); | |||||
} | |||||
} finally { | |||||
distributedLock.releaseLock(key); | |||||
} | |||||
} | |||||
/** | |||||
* 抽取数量校验 | |||||
* | |||||
* @param po 抽取参数 | |||||
* @return {@link ExpertCountOnChangeVO} | |||||
* @author WendyYang | |||||
**/ | |||||
public ExpertCountOnChangeVO expertCountOnChange(ExpertInviteCreateReq po) { | |||||
// 未传递指定邀请专家直接忽略 | |||||
if (po.getAppointRule() != null && CollUtil.isEmpty(po.getAppointRule().getExpertIds())) { | |||||
Assert.isTrue(CollUtil.isNotEmpty(po.getRandomRules()), "未指定抽取规则"); | |||||
po.setAppointRule(null); | |||||
} | |||||
boolean appointed = po.getAppointRule() != null; | |||||
expertInviteManage.checkAppointExpertConflictWithAvoidRule(po.getAppointRule(), po.getAvoidInfo()); | |||||
Meeting meeting = meetingService.getById(po.getMeetingId()); | |||||
ExpertCountOnChangeVO resultCount = new ExpertCountOnChangeVO(); | |||||
resultCount.setStatus(true); | |||||
resultCount.setCountList(new ArrayList<>()); | |||||
// 参数校验 | |||||
String errMsg = ValidUtil.validFast(po, AbstractInviteRule.CountCheck.class); | |||||
if (errMsg != null) { | |||||
resultCount.setStatus(false); | |||||
resultCount.setMessage(errMsg); | |||||
return resultCount; | |||||
} | |||||
List<Long> expertIdsChoose = new ArrayList<>(); | |||||
if (appointed) { | |||||
expertIdsChoose.addAll(po.getAppointRule().getExpertIds()); | |||||
} | |||||
for (RandomInviteRuleDTO randomRule : po.getRandomRules()) { | |||||
ExpertChooseDTO chooseExpert = expertInviteManage.expertInviteByRandomRule(po.getAvoidInfo(), | |||||
randomRule, expertIdsChoose, meeting.getStartTime(), meeting.getEndTime()); | |||||
resultCount.addCountList(chooseExpert.getTotal()); | |||||
} | |||||
return resultCount; | |||||
} | |||||
/** | |||||
* 专家会议列表 | |||||
* | |||||
* @param req 查询参数 | |||||
* @return 会议列表 | |||||
* @author WendyYang | |||||
**/ | |||||
public PageVo<MeetingByManagerVO> meetingListByExpert(MeetingListReq req) { | |||||
Long expertId = req.getExpertId() != null ? req.getExpertId() : LoginUserUtil.getUserId(); | |||||
List<MeetingAndAttendStatusDTO> expertDtoList = meetingExpertService.listByExpertIdAndStatus(expertId, req.getStatus(), null); | |||||
if (expertDtoList.isEmpty()) { | |||||
return PageVo.empty(); | |||||
} | |||||
Map<Long, MeetingAndAttendStatusDTO> mapByMeetingId = new HashMap<>(16); | |||||
expertDtoList.forEach(w -> mapByMeetingId.put(w.getMeetingId(), w)); | |||||
LambdaQueryWrapper<Meeting> query = new LambdaQueryWrapper<Meeting>() | |||||
.orderByDesc(Meeting::getCreateOn) | |||||
.in(Meeting::getId, mapByMeetingId.keySet()) | |||||
.ne(Meeting::getStatus, Manager.CANCELED.getCode()); | |||||
if (req.getExpertId() == null) { | |||||
meetingManageHelper.buildMeetingQuery(query, req); | |||||
} | |||||
Page<Meeting> page = meetingService.page(req.page(), query); | |||||
if (page.getTotal() == 0) { | |||||
return PageVo.empty(); | |||||
} | |||||
PageVo<MeetingByManagerVO> result = new PageVo<>(new ArrayList<>(), page.getTotal()); | |||||
page.getRecords().forEach(meeting -> { | |||||
MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting); | |||||
MeetingAndAttendStatusDTO info = mapByMeetingId.get(meeting.getId()); | |||||
item.setAttendStatus(meetingManageHelper.getExpertAttendStatus(info)); | |||||
result.getRecords().add(item); | |||||
}); | |||||
return result; | |||||
} | |||||
/** | |||||
* 管理员会议列表 | |||||
* | |||||
* @param po 查询参数 | |||||
* @return 会议列表 | |||||
* @author WendyYang | |||||
*/ | |||||
public PageVo<MeetingByManagerVO> meetingListByManager(MeetingListReq po) { | |||||
LambdaQueryWrapper<Meeting> query = new LambdaQueryWrapper<Meeting>() | |||||
.orderByDesc(Meeting::getCreateOn); | |||||
// 补充逻辑 如果拥有超级管理员权限可以看到所有事务 | |||||
if (!permissionCheckHelper.isSuperAdmin()) { | |||||
query.eq(Meeting::getCreateBy, LoginUserUtil.getUserId()); | |||||
} | |||||
query.eq(po.getStatus() != null, Meeting::getStatus, po.getStatus()); | |||||
meetingManageHelper.buildMeetingQuery(query, po); | |||||
Page<Meeting> page = meetingService.page(po.page(), query); | |||||
if (page.getTotal() == 0) { | |||||
return PageVo.empty(); | |||||
} | |||||
PageVo<MeetingByManagerVO> result = new PageVo<>(new ArrayList<>(), page.getTotal()); | |||||
Map<Long, CountConfirmByMeetingIdDTO> countConfirmMap = new HashMap<>(16); | |||||
List<Long> meetingIds = CollUtils.fieldList(page.getRecords(), Meeting::getId); | |||||
countConfirmMap.putAll(meetingExpertService.countConfirmedByMeetingIds(meetingIds)); | |||||
page.getRecords().forEach(meeting -> { | |||||
MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting); | |||||
CountConfirmByMeetingIdDTO confirm = countConfirmMap.get(meeting.getId()); | |||||
if (confirm == null) { | |||||
item.setInviteCount(0); | |||||
item.setConfirmCount(0); | |||||
} else { | |||||
item.setInviteCount(confirm.getTotal()); | |||||
item.setConfirmCount(confirm.getConfirmed()); | |||||
} | |||||
result.getRecords().add(item); | |||||
}); | |||||
return result; | |||||
} | |||||
public MeetingDetailBasicVO getMeetingBasicInfo(Long meetingId) { | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
if (Objects.isNull(meeting)) { | |||||
throw new BizException("该会议信息不存在"); | |||||
} | |||||
String attachment = meeting.getAttachment(); | |||||
List<AttachFileVo> attachments = new ArrayList<>(); | |||||
if (StrUtils.isNotBlank(attachment)) { | |||||
attachments.addAll(fileService.getByIds(BizUtils.splitToLong(attachment))); | |||||
} | |||||
Integer attendStatus = null; | |||||
if (LoginUserUtil.isExpert()) { | |||||
List<Long> meIds = Collections.singletonList(meetingId); | |||||
List<MeetingAndAttendStatusDTO> status = meetingExpertService.listByExpertIdAndStatus(LoginUserUtil.getUserId(), null, meIds); | |||||
if (status.isEmpty()) { | |||||
throw BizException.wrap("您未被邀请参加次会议"); | |||||
} | |||||
attendStatus = meetingManageHelper.getExpertAttendStatus(status.get(0)); | |||||
} | |||||
return MeetingDetailBasicVO.builder() | |||||
.id(meeting.getId()) | |||||
.name(meeting.getName()) | |||||
.type(meeting.getType()) | |||||
.typeName(dictionaryCache.getByCode(meeting.getType()).getName()) | |||||
.author(meeting.getAuthor()) | |||||
.startTime(meeting.getStartTime()) | |||||
.endTime(meeting.getEndTime()) | |||||
.createOn(meeting.getCreateOn()) | |||||
.contact(meeting.getContact()) | |||||
.connecter(meeting.getConnecter()) | |||||
.description(meeting.getDescription()) | |||||
.remark(meeting.getRemark()) | |||||
.address(meeting.getRegionDetail()) | |||||
.attachments(attachments) | |||||
.status(meeting.getStatus()) | |||||
.attendStatus(attendStatus) | |||||
.cancelRemark(meeting.getCancelRemark()) | |||||
.createBy(meeting.getAuthor()) | |||||
.inviterCompany(meeting.getHoldCompany()) | |||||
.invited(meeting.getInvited()) | |||||
.sendMeetingNotice(meeting.getSendMeetingNotice()) | |||||
.build(); | |||||
} | |||||
public void uploadMeetingResult(MeetingResultReq po) { | |||||
LambdaUpdateWrapper<Meeting> updater = Wrappers.lambdaUpdate(Meeting.class) | |||||
.eq(Meeting::getId, po.getMeetingId()) | |||||
.set(Meeting::getResultDescription, po.getResultDescription()) | |||||
.set(Meeting::getStatus, Manager.COMPLETED.getCode()); | |||||
if (CollectionUtils.isNotEmpty(po.getAttachments())) { | |||||
updater.set(Meeting::getResultAttachment, CollUtils.joinByComma(po.getAttachments())); | |||||
} | |||||
meetingService.update(updater); | |||||
} | |||||
public MeetingResultVO meetingResultDetail(Long meetingId) { | |||||
LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class) | |||||
.select(Meeting::getResultAttachment, Meeting::getResultDescription) | |||||
.eq(Meeting::getId, meetingId); | |||||
Meeting meeting = meetingService.getOne(query); | |||||
MeetingResultVO result = new MeetingResultVO(); | |||||
result.setMeetingId(meetingId); | |||||
result.setResultDescription(meeting.getResultDescription()); | |||||
result.setAttachments(new ArrayList<>()); | |||||
if (StrUtils.isNotBlank(meeting.getResultAttachment())) { | |||||
List<Long> fileIds = BizUtils.splitToLong(meeting.getResultAttachment()); | |||||
result.getAttachments().addAll(fileService.getByIds(fileIds)); | |||||
} | |||||
return result; | |||||
} | |||||
public ExpertInviteDetailVO inviteDetail(Long meetingId) { | |||||
ExpertInviteDetailVO result = new ExpertInviteDetailVO(); | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
if (Objects.isNull(meeting)) { | |||||
throw new BizException("该会议信息不存在"); | |||||
} | |||||
result.setHasStopInvite(meeting.getStopRandomInvite()); | |||||
result.setHasSendNotice(meeting.getSendMeetingNotice()); | |||||
List<MeetingExpert> experts = meetingExpertService.listByMeetingId(meetingId); | |||||
if (experts.isEmpty()) { | |||||
return result; | |||||
} | |||||
List<MeetingExpert> randomList = new ArrayList<>(); | |||||
List<MeetingExpert> appointList = new ArrayList<>(); | |||||
List<MeetingExpert> attendList = new ArrayList<>(); | |||||
List<Long> expertIds = new ArrayList<>(); | |||||
experts.forEach(w -> { | |||||
boolean randomInvite = w.getInviteType().equals(ExpertInviteType.RANDOM.getCode()); | |||||
if (randomInvite) { | |||||
randomList.add(w); | |||||
} else { | |||||
appointList.add(w); | |||||
} | |||||
if (w.getStatus().equals(ExpertAttendStatus.AGREED.getCode())) { | |||||
attendList.add(w); | |||||
if (randomInvite) { | |||||
result.setRandomAttend(result.getRandomAttend() + 1); | |||||
} else { | |||||
result.setAppointAttend(result.getAppointAttend() + 1); | |||||
} | |||||
} | |||||
expertIds.add(w.getExpertId()); | |||||
}); | |||||
result.setAttendTotal(attendList.size()); | |||||
Map<Long, ExpertBasicInfoVO> expertBasicInfoVoMap = meetingManageHelper.getExpertBasicInfo(expertIds); | |||||
Function<MeetingExpert, RandomInviteListItemVO> mapping = sme -> { | |||||
ExpertBasicInfoVO basicInfoVo = expertBasicInfoVoMap.get(sme.getExpertId()); | |||||
RandomInviteListItemVO item = BeanUtil.copyProperties(basicInfoVo, RandomInviteListItemVO.class); | |||||
item.setStatus(sme.getStatus()); | |||||
item.setMeetingId(sme.getMeetingId()); | |||||
item.setExpertMeetingId(sme.getId()); | |||||
ExpertAttendStatus status = ExpertAttendStatus.getByCode(sme.getStatus()); | |||||
if (status.equals(ExpertAttendStatus.NOTICING)) { | |||||
item.setNoticeStatus(status.getDesc()); | |||||
item.setConfirmResult(StrUtil.EMPTY); | |||||
} else { | |||||
item.setNoticeStatus("已通知"); | |||||
item.setConfirmResult(status.getDesc()); | |||||
} | |||||
return item; | |||||
}; | |||||
// 随机邀请列表 | |||||
randomList.forEach(w -> result.addRandomInviteList(mapping.apply(w))); | |||||
// 指定抽取列表 | |||||
appointList.forEach(w -> result.addAppointInviteList(mapping.apply(w))); | |||||
// 确定参加列表 | |||||
attendList.forEach(w -> { | |||||
ExpertBasicInfoVO expertBasicInfoVo = expertBasicInfoVoMap.get(w.getExpertId()); | |||||
ExpertAttendListItemVO item = BeanUtil.copyProperties(expertBasicInfoVo, ExpertAttendListItemVO.class); | |||||
item.setInviteType(ExpertInviteType.getByCode(w.getInviteType()).getName()); | |||||
result.addAttendList(item); | |||||
}); | |||||
return result; | |||||
} | |||||
private boolean meetingInfoChange(Meeting old, Meeting current) { | |||||
if (!old.getStartTime().equals(current.getStartTime())) { | |||||
return Boolean.TRUE; | |||||
} | |||||
if (!old.getRegionCode().equals(current.getRegionCode())) { | |||||
return Boolean.TRUE; | |||||
} | |||||
if (!old.getRegionDetail().equals(current.getRegionDetail())) { | |||||
return Boolean.TRUE; | |||||
} | |||||
return Boolean.FALSE; | |||||
} | |||||
/** | |||||
* 会议基本信息修改 | |||||
* | |||||
* @param po 修改参数 | |||||
**/ | |||||
public void meetingBasicInfoModify(MeetingBasicInfoModifyReq po) { | |||||
Meeting meeting = new Meeting(); | |||||
BeanUtil.copyProperties(po, meeting); | |||||
if (CollectionUtils.isEmpty(po.getAttachmentIds())) { | |||||
meeting.setAttachment(StrUtil.EMPTY); | |||||
} else { | |||||
meeting.setAttachment(CollUtils.joinByComma(po.getAttachmentIds())); | |||||
} | |||||
if (StrUtil.isBlank(po.getRemark())) { | |||||
meeting.setRemark(StrUtil.EMPTY); | |||||
} | |||||
LocalDateTime now = LocalDateTime.now(); | |||||
meeting.setHoldCompany(po.getInviterCompany()); | |||||
Meeting old = meetingService.getById(po.getId()); | |||||
if (Manager.UNCOMPLETED.eq(old.getStatus()) && meetingInfoChange(old, meeting)) { | |||||
List<MeetingExpert> meList = meetingExpertService.listExpertByAgreeAttend(Collections.singletonList(po.getId())); | |||||
if (!meList.isEmpty() && old.getStartTime().isAfter(now)) { | |||||
// TODO | |||||
/*String meetingType = dictionaryCache.getByCode(old.getType()).getName(); | |||||
List<SendSmsContext> contexts = YxtSmsContextBuilder.smsToExpertByMeetingChange(old, meeting, meList, meetingType); | |||||
yxtCallOrSmsHelper.sendSms(contexts);*/ | |||||
} | |||||
} | |||||
meetingService.updateById(meeting); | |||||
} | |||||
/** | |||||
* 抽取规则详情 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @return {@link InviteRuleDetailVO} | |||||
* @author WendyYang | |||||
**/ | |||||
public InviteRuleDetailVO inviteRuleDetail(Long meetingId) { | |||||
InviteRuleDetailVO result = new InviteRuleDetailVO(); | |||||
List<ExpertInviteRule> inviteRules = inviteRuleService.listByMeetingId(meetingId); | |||||
if (!result.setAndGetInvited(inviteRules.size() > 0)) { | |||||
return result; | |||||
} | |||||
result.setRandomRules(new ArrayList<>()); | |||||
Map<ExpertInviteType, List<ExpertInviteRule>> groupByType = CollUtils.group(inviteRules, w -> ExpertInviteType.getByCode(w.getInviteType())); | |||||
List<ExpertInviteRule> randoms = groupByType.get(ExpertInviteType.RANDOM); | |||||
if (CollectionUtils.isNotEmpty(randoms)) { | |||||
randoms.forEach(random -> { | |||||
RandomInviteRuleVO randomRule = JSON.parseObject(random.getInviteRule(), RandomInviteRuleVO.class); | |||||
if (randomRule.getExpertTags() != null) { | |||||
randomRule.getExpertTags().forEach(w -> { | |||||
List<String> tagNames = CollUtils.convert(w.getTagCodes(), tagCode -> tagCache.getByTagCode(tagCode).getTagName()); | |||||
w.setTagCodes(tagNames); | |||||
}); | |||||
} | |||||
if (randomRule.getExpertDicts() != null) { | |||||
randomRule.getExpertDicts().forEach(w -> { | |||||
List<String> dictNames = CollUtils.convert(w.getDictCodes(), dictCode -> dictionaryCache.getByCode(dictCode).getName()); | |||||
w.setDictCodes(dictNames); | |||||
}); | |||||
} | |||||
if (StrUtil.isNotEmpty(randomRule.getIntentionRegionCode())) { | |||||
/*List<RegionDTO> intentionRegions = regionCache.listParents(randomRule.getIntentionRegionCode(), randomRule.getIntentionRegionLevel()); | |||||
randomRule.setIntentionRegions(intentionRegions);*/ | |||||
} | |||||
if (StrUtil.isNotEmpty(randomRule.getExpertRegionCode())) { | |||||
/*List<RegionDTO> expertRegions = regionCache.listParents(randomRule.getExpertRegionCode(), randomRule.getExpertRegionLevel()); | |||||
randomRule.setExpertRegions(expertRegions);*/ | |||||
} | |||||
result.getRandomRules().add(randomRule); | |||||
}); | |||||
} | |||||
List<ExpertInviteRule> appoints = groupByType.get(ExpertInviteType.APPOINT); | |||||
if (result.setAndGetHasAppointRule(CollUtil.isNotEmpty(appoints))) { | |||||
ExpertInviteRule appoint = appoints.get(0); | |||||
AppointInviteRuleDTO appointRule = JSON.parseObject(appoint.getInviteRule(), AppointInviteRuleDTO.class); | |||||
InviteRuleDetailVO.AppointRuleVo vo = new InviteRuleDetailVO.AppointRuleVo(); | |||||
vo.setInviteDesc(appointRule.getInviteDesc()); | |||||
vo.setExperts(new ArrayList<>(meetingManageHelper.getExpertBasicInfo(appointRule.getExpertIds()).values())); | |||||
result.setAppointRule(vo); | |||||
} | |||||
AvoidInfoDTO avoidInfo = inviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
if (result.setAndGetHasAvoidInfo(avoidInfo != null)) { | |||||
InviteRuleDetailVO.AvoidInfoVo vo = new InviteRuleDetailVO.AvoidInfoVo(); | |||||
vo.setAvoidMates(avoidInfo.getAvoidMates()); | |||||
vo.setCompanyIds(avoidInfo.getCompanyIds()); | |||||
if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) { | |||||
vo.setExperts(new ArrayList<>(meetingManageHelper.getExpertBasicInfo(avoidInfo.getExpertIds()).values())); | |||||
} | |||||
result.setAvoidInfo(vo); | |||||
} | |||||
return result; | |||||
} | |||||
public void expertRemove(ExpertRemoveReq po) { | |||||
LambdaUpdateWrapper<MeetingExpert> update = Wrappers.lambdaUpdate(MeetingExpert.class) | |||||
.eq(MeetingExpert::getId, po.getExpertMeetingId()) | |||||
.set(MeetingExpert::getStatus, ExpertAttendStatus.CANCELED.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(ExpertInviteType.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, ExpertAttendStatus.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(ExpertAttendStatus.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 po) { | |||||
List<ExpertUserFullInfo> userInfos = meetingManageHelper.appointExpertCheck(po.getMeetingId(), po.getExpertIds()); | |||||
List<MeetingExpert> expertList = CollUtils.convert(userInfos, w -> { | |||||
MeetingExpert me = ExpertInviteBuilder.getExpertByAppoint(po.getMeetingId(), w, 0L); | |||||
me.setStatus(ExpertAttendStatus.NOTICING.getCode()); | |||||
return me; | |||||
}); | |||||
meetingExpertService.saveBatch(expertList); | |||||
} | |||||
public void sendMeetingNotice(Long meetingId) { | |||||
String key = "SEND_MEETING_NOTICE:" + meetingId; | |||||
if (!distributedLock.lock(key, RETRY_TIMES)) { | |||||
throw BizException.wrap("正在下发会议通知"); | |||||
} | |||||
try { | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
Assert.isTrue(Manager.UNCOMPLETED.eq(meeting.getStatus()), "非未完成会议无法发送会议通知"); | |||||
Assert.isTrue(!meeting.getSendMeetingNotice(), "该会议已下发过会议通知"); | |||||
Assert.isTrue(meeting.getStopRandomInvite(), "随机邀请未结束"); | |||||
int noticeCount = meetingExpertService.countExpertByStatusAndMeetingId(ExpertAttendStatus.NOTICING, meetingId, null); | |||||
Assert.isTrue(noticeCount == 0, "存在未确认完成的专家,暂无法下发会议通知"); | |||||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class) | |||||
.set(Meeting::getSendMeetingNotice, Boolean.TRUE) | |||||
.eq(Meeting::getId, meetingId); | |||||
meetingService.update(update); | |||||
// 发送会议通知 | |||||
List<MeetingExpert> experts = meetingExpertService.listExpertByAgreeAttend(Collections.singletonList(meetingId)); | |||||
if (!experts.isEmpty()) { | |||||
// TODO | |||||
// String meetingType = dictionaryCache.getByCode(meeting.getType()).getName(); | |||||
// List<SendSmsContext> contexts = YxtSmsContextBuilder.smsToExpertBySendNotice(meeting, experts, meetingType); | |||||
// yxtCallOrSmsHelper.sendSms(contexts); | |||||
} | |||||
} finally { | |||||
distributedLock.releaseLock(key); | |||||
} | |||||
} | |||||
public void stopRandomInvite(Long meetingId) { | |||||
expertInviteTask.cancelByMeetingId(meetingId); | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void cancelMeeting(MeetingCancelReq po) { | |||||
String key = "CANCEL_MEETING:" + po.getMeetingId(); | |||||
if (!distributedLock.lock(key, RETRY_TIMES)) { | |||||
throw BizException.wrap("正在取消会议,请刷新后重试"); | |||||
} | |||||
try { | |||||
Meeting meeting = meetingService.getById(po.getMeetingId()); | |||||
Assert.isTrue(!Manager.CANCELED.eq(meeting.getStatus()), "会议已取消"); | |||||
Assert.isTrue(meeting.getStartTime().isAfter(LocalDateTime.now()), "会议已开始,暂时无法取消"); | |||||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class) | |||||
.set(Meeting::getStatus, Manager.CANCELED.getCode()) | |||||
.set(Meeting::getUpdateBy, LoginUserUtil.getUserId()) | |||||
.set(Meeting::getCancelRemark, po.getCancelRemark()) | |||||
.set(Meeting::getUpdateOn, LocalDateTime.now()) | |||||
.eq(Meeting::getId, po.getMeetingId()); | |||||
meetingService.update(update); | |||||
expertInviteTask.cancelByMeetingId(po.getMeetingId()); | |||||
// 发送通知给专家 | |||||
List<MeetingExpert> experts = meetingExpertService.listExpertByAgreeAttend(Collections.singletonList(po.getMeetingId())); | |||||
if (!experts.isEmpty()) { | |||||
// TODO | |||||
// meeting.setCancelRemark(po.getCancelRemark()); | |||||
// String meetingType = dictionaryCache.getByCode(meeting.getType()).getName(); | |||||
// List<SendSmsContext> contexts = YxtSmsContextBuilder.smsToExpertByCancelMeeting(meeting, experts, meetingType); | |||||
// yxtCallOrSmsHelper.sendSms(contexts); | |||||
} | |||||
} finally { | |||||
distributedLock.releaseLock(key); | |||||
} | |||||
} | |||||
public ExpertInvitationDetailVO expertInvitationDetail(Long meetingId, Long expertId) { | |||||
Long userId = expertId == null ? LoginUserUtil.getUserId() : expertId; | |||||
MeetingExpert me = meetingExpertService.getByMeetingIdAndExpertId(meetingId, userId); | |||||
Assert.notNull(me, "未被邀请参加"); | |||||
Assert.isTrue(ExpertAttendStatus.AGREED.eq(me.getStatus()), "未确认参加"); | |||||
ExpertUserFullInfo expertInfo = expertUserFullInfoService.getByUserId(userId); | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
return ExpertInvitationDetailVO.builder() | |||||
.expertName(expertInfo.getExpertName()) | |||||
.holdCompany(meeting.getHoldCompany()) | |||||
.regionDetail(meeting.getRegionDetail()) | |||||
.meetingName(meeting.getName()) | |||||
.startTime(meeting.getStartTime()) | |||||
.endTime(meeting.getEndTime()) | |||||
.inviteTime(me.getCreateOn()) | |||||
.connecter(meeting.getConnecter()) | |||||
.contact(meeting.getContact()) | |||||
.build(); | |||||
} | |||||
public void confirmAttendByManager(ExpertRemoveReq po) { | |||||
MeetingExpert meetingExpert = meetingExpertService.getById(po.getExpertMeetingId()); | |||||
if (meetingExpert.getStatus().equals(ExpertAttendStatus.NOTICING.getCode())) { | |||||
LambdaUpdateWrapper<MeetingExpert> update = Wrappers.lambdaUpdate(MeetingExpert.class) | |||||
.set(MeetingExpert::getStatus, ExpertAttendStatus.AGREED.getCode()) | |||||
.set(MeetingExpert::getUpdateOn, LocalDateTime.now()) | |||||
.set(MeetingExpert::getUpdateBy, LoginUserUtil.getUserId()) | |||||
.eq(MeetingExpert::getId, po.getExpertMeetingId()); | |||||
meetingExpertService.update(update); | |||||
} else { | |||||
ExpertAttendStatus status = ExpertAttendStatus.getByCode(meetingExpert.getStatus()); | |||||
throw BizException.wrap("该专家" + status.getDesc()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
package com.ningdatech.pmapi.meeting.mapper; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | |||||
/** | |||||
* <p> | |||||
* Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface ExpertInviteAvoidRuleMapper extends BaseMapper<ExpertInviteAvoidRule> { | |||||
} |
@@ -0,0 +1,5 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
<mapper namespace="com.ningdatech.pmapi.meeting.mapper.ExpertInviteAvoidRuleMapper"> | |||||
</mapper> |
@@ -0,0 +1,16 @@ | |||||
package com.ningdatech.pmapi.meeting.mapper; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
/** | |||||
* <p> | |||||
* Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface ExpertInviteRuleMapper extends BaseMapper<ExpertInviteRule> { | |||||
} |
@@ -0,0 +1,5 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
<mapper namespace="com.ningdatech.pmapi.meeting.mapper.ExpertInviteRuleMapper"> | |||||
</mapper> |
@@ -0,0 +1,26 @@ | |||||
package com.ningdatech.pmapi.meeting.mapper; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.ningdatech.pmapi.common.model.entity.CountGroupByDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpertEvaluation; | |||||
import org.apache.ibatis.annotations.Param; | |||||
import java.util.Collection; | |||||
/** | |||||
* <p> | |||||
* 专家评价表 Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-25 | |||||
*/ | |||||
public interface MeetingExpertEvaluationMapper extends BaseMapper<MeetingExpertEvaluation> { | |||||
Page<CountGroupByDTO<Long>> countExpertAttend(@Param("expertIds") Collection<Long> expertIds, @Param("isAttended") Boolean isAttended, Page<CountGroupByDTO<Long>> page); | |||||
Page<MeetingExpert> pageExpertEvaluationToDo(@Param("meetingIds") Collection<Long> meetingIds, Page<MeetingExpert> po); | |||||
} |
@@ -0,0 +1,25 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
<mapper namespace="com.ningdatech.pmapi.meeting.mapper.MeetingExpertEvaluationMapper"> | |||||
<select id="countExpertAttend" resultType="com.ningdatech.pmapi.common.model.entity.CountGroupByDTO"> | |||||
select count(1) total, expert_id groupKey from meeting_expert_evaluation | |||||
where expert_id | |||||
<foreach collection="expertIds" separator="," close=")" open=" in (" item="expertId">#{expertId}</foreach> | |||||
<if test="isAttended != null"> | |||||
and is_attended = #{isAttended} | |||||
</if> | |||||
group by expert_id order by total desc | |||||
</select> | |||||
<select id="pageExpertEvaluationToDo" | |||||
resultType="com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert"> | |||||
select * from (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id ORDER BY update_on DESC ) | |||||
rowNumber, ID, expert_id, status, meeting_id FROM meeting_expert | |||||
where meeting_id <foreach collection="meetingIds" item="item" open=" in (" close=")" separator=","> | |||||
#{item}</foreach>) em | |||||
WHERE rowNumber = 1 and status = 3 and not exists (select 1 from meeting_expert_evaluation where | |||||
expert_meeting_id = em.id) | |||||
</select> | |||||
</mapper> |
@@ -0,0 +1,81 @@ | |||||
package com.ningdatech.pmapi.meeting.mapper; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import org.apache.ibatis.annotations.Param; | |||||
import java.util.Collection; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* 事务专家表 Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-27 | |||||
*/ | |||||
public interface MeetingExpertMapper extends BaseMapper<MeetingExpert> { | |||||
/** | |||||
* 根据专家状态查询需要参加的会议信息 | |||||
* | |||||
* @param expertId 专家ID | |||||
* @param status 状态 | |||||
* @param meetingIds 会议ID | |||||
* @return 专家参会状态列表 | |||||
* @author WendyYang | |||||
**/ | |||||
List<MeetingAndAttendStatusDTO> selectByExpertIdAndStatus(@Param("expertId") Long expertId, | |||||
@Param("status") Integer status, | |||||
@Param("meetingIds") List<Long> meetingIds); | |||||
/** | |||||
* 分页查询专家列表 | |||||
* | |||||
* @param page 分页数据 | |||||
* @param status 状态{@link ExpertAttendStatus} | |||||
* @param meetingId 会议ID | |||||
* @param inviteType 邀请类型 | |||||
* @return Page<MeetingExpert> | |||||
* @author WendyYang | |||||
**/ | |||||
Page<MeetingExpert> selectExpertByStatusAndMeetingId(Page<MeetingExpert> page, @Param("status") Integer status, | |||||
@Param("meetingId") Long meetingId, | |||||
@Param("inviteType") Integer inviteType); | |||||
/** | |||||
* 分页查询专家列表 | |||||
* | |||||
* @param page 分页数据 | |||||
* @param status 状态{@link ExpertAttendStatus} | |||||
* @param meetingIds 会议ID | |||||
* @return Page<MeetingExpert> | |||||
* @author WendyYang | |||||
**/ | |||||
Page<MeetingExpert> selectExpertByStatusAndMeetingIds(Page<MeetingExpert> page, @Param("status") Integer status, | |||||
@Param("meetingIds") Collection<Long> meetingIds); | |||||
/** | |||||
* 根据会议ID与参与状态统计专家数量 | |||||
* | |||||
* @param status 会议状态 | |||||
* @param meetingId 会议ID | |||||
* @param inviteType 邀请类型 | |||||
* @return 数量 | |||||
*/ | |||||
int countExpertByStatusAndMeetingId(@Param("status") Integer status, @Param("meetingId") Long meetingId, @Param("inviteType") Integer inviteType); | |||||
/** | |||||
* 查询会议的所有被抽取人最后一条记录 | |||||
* | |||||
* @param meetingIds 会议ID | |||||
* @return 抽取记录 | |||||
* @author WendyYang | |||||
**/ | |||||
List<MeetingExpert> listExpertLastByMeetingIds(@Param("meetingIds") Collection<Long> meetingIds); | |||||
} |
@@ -0,0 +1,82 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
<mapper namespace="com.ningdatech.pmapi.meeting.mapper.MeetingExpertMapper"> | |||||
<select id="selectByExpertIdAndStatus" | |||||
resultType="com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO"> | |||||
SELECT em.meeting_id meetingId, em.status, mee.is_attended attended | |||||
FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY meeting_id ORDER BY update_on DESC ) rowNumber, ID, expert_id, | |||||
status, meeting_id | |||||
FROM meeting_expert | |||||
where expert_id = #{expertId} | |||||
<if test="meetingIds != null and meetingIds.size > 0"> | |||||
and meeting_id | |||||
<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> | |||||
<if test="status == null"> | |||||
and em.status in (3,6) | |||||
</if> | |||||
</select> | |||||
<select id="selectExpertByStatusAndMeetingId" | |||||
resultType="com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert"> | |||||
SELECT * FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id ORDER BY update_on DESC ) rowNumber, | |||||
ID, expert_id, status, meeting_id, invite_type, mobile, expert_name, update_on FROM meeting_expert | |||||
where meeting_id = #{meetingId} | |||||
<if test="inviteType != null"> | |||||
and invite_type = #{inviteType} | |||||
</if> | |||||
) em | |||||
WHERE rowNumber = 1 | |||||
<if test="status != null"> | |||||
and status = #{status} | |||||
</if> | |||||
</select> | |||||
<select id="selectExpertByStatusAndMeetingIds" | |||||
resultType="com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert"> | |||||
SELECT * FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id, meeting_id ORDER BY update_on DESC ) rowNumber, | |||||
ID, expert_id, status, meeting_id, invite_type, mobile, expert_name, update_on FROM meeting_expert | |||||
where meeting_id <foreach collection="meetingIds" separator="," close=")" open=" in (" item="item"> | |||||
#{item}</foreach>) em | |||||
WHERE rowNumber = 1 | |||||
<if test="status != null"> | |||||
and status = #{status} | |||||
</if> | |||||
</select> | |||||
<select id="countExpertByStatusAndMeetingId" | |||||
resultType="int"> | |||||
SELECT count(1) FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id, meeting_id ORDER BY update_on DESC ) | |||||
rowNumber, status FROM meeting_expert | |||||
where meeting_id = #{meetingId} | |||||
<if test="inviteType != null"> | |||||
and invite_type = #{inviteType} | |||||
</if> | |||||
) em | |||||
WHERE rowNumber = 1 | |||||
<if test="status != null"> | |||||
and status = #{status} | |||||
</if> | |||||
</select> | |||||
<select id="listExpertLastByMeetingIds" resultType="com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert"> | |||||
SELECT * FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY expert_id, meeting_id ORDER BY update_on DESC ) rowNumber, | |||||
ID, expert_id, status, meeting_id, invite_type, mobile, expert_name, update_on, pre_id, rule_id FROM meeting_expert | |||||
where meeting_id <foreach collection="meetingIds" separator="," close=")" open=" in (" item="item"> | |||||
#{item}</foreach>) em WHERE rowNumber = 1 | |||||
</select> | |||||
</mapper> |
@@ -0,0 +1,21 @@ | |||||
package com.ningdatech.pmapi.meeting.mapper; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.ningdatech.pmapi.common.model.entity.CountGroupByDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* 会议 Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface MeetingMapper extends BaseMapper<Meeting> { | |||||
List<CountGroupByDTO<String>> meetingCountSummary(Long createBy); | |||||
} |
@@ -0,0 +1,18 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
<mapper namespace="com.ningdatech.pmapi.meeting.mapper.MeetingMapper"> | |||||
<select id="meetingCountSummary" resultType="com.ningdatech.pmapi.common.model.entity.CountGroupByDTO"> | |||||
select status groupKey, count(1) total | |||||
from (SELECT (CASE | |||||
WHEN (status = 1 AND now() < start_time) THEN 'TO_BE_HELD' | |||||
WHEN (status = 1 AND now() >= start_time) THEN 'HELD' | |||||
WHEN status = 2 THEN 'COMPLETED' | |||||
ELSE 'CANCELED' | |||||
END) status | |||||
FROM meeting | |||||
where create_by = #{createBy}) temp | |||||
GROUP BY status | |||||
</select> | |||||
</mapper> |
@@ -0,0 +1,28 @@ | |||||
package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
/** | |||||
* <p> | |||||
* IExpertInviteAvoidRuleService服务类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface IExpertInviteAvoidRuleService extends IService<ExpertInviteAvoidRule> { | |||||
ExpertInviteAvoidRule getByMeetingId(Long meetingId); | |||||
/** | |||||
* 获取回避信息 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @return com.ningdatech.emapi.meeting.entity.dto.AvoidInfoDto | |||||
* @author WendyYang | |||||
**/ | |||||
AvoidInfoDTO getAvoidInfoDto(Long meetingId); | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* <p> | |||||
* 服务类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface IExpertInviteRuleService extends IService<ExpertInviteRule> { | |||||
List<ExpertInviteRule> listByMeetingId(Long meetingId); | |||||
Map<Long, RandomInviteRuleDTO> randomRuleByMeetingId(Long meetingId); | |||||
} |
@@ -0,0 +1,26 @@ | |||||
package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import com.ningdatech.pmapi.common.model.entity.CountGroupByDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpertEvaluation; | |||||
import java.util.Collection; | |||||
/** | |||||
* <p> | |||||
* 专家评价表 服务类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-25 | |||||
*/ | |||||
public interface IMeetingExpertEvaluationService extends IService<MeetingExpertEvaluation> { | |||||
Page<CountGroupByDTO<Long>> listExpertAttendSummary(Collection<Long> expertIds, Boolean isAttended, Page<CountGroupByDTO<Long>> page); | |||||
Page<MeetingExpert> pageExpertEvaluationTodo(Collection<Long> meetingIds, PagePo po); | |||||
} |
@@ -0,0 +1,123 @@ | |||||
package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | |||||
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.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import java.util.Collection; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* <p> | |||||
* 事务专家表 服务类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-27 | |||||
*/ | |||||
public interface IMeetingExpertService extends IService<MeetingExpert> { | |||||
/** | |||||
* 查询专家的参与状态 | |||||
* | |||||
* @param expertId 专家ID | |||||
* @param status 状态{@link MeetingStatus.Expert} | |||||
* @param meetingIds 会议ID | |||||
* @return 会议参加状态统计 | |||||
* @author WendyYang | |||||
**/ | |||||
List<MeetingAndAttendStatusDTO> listByExpertIdAndStatus(Long expertId, Integer status, List<Long> meetingIds); | |||||
/** | |||||
* 查询每个事物的确认进度 | |||||
* | |||||
* @param meetingIds 事务ID | |||||
* @return 确认进度 | |||||
* @author WendyYang | |||||
**/ | |||||
Map<Long, CountConfirmByMeetingIdDTO> countConfirmedByMeetingIds(List<Long> meetingIds); | |||||
/** | |||||
* 根据事务ID查询所有邀请记录 | |||||
* | |||||
* @param meetingId 事务ID | |||||
* @return 邀请专家记录 | |||||
*/ | |||||
List<MeetingExpert> listByMeetingId(Long meetingId); | |||||
/** | |||||
* 根据事务ID查询所有邀请记录 | |||||
* | |||||
* @param meetingIds 事务ID | |||||
* @return List<SubjectMatterExpert> | |||||
*/ | |||||
List<MeetingExpert> listByMeetingIds(List<Long> meetingIds); | |||||
/** | |||||
* 获取专家参与事务的最新记录 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @param expertId 专家ID | |||||
* @return 专家参会记录 | |||||
* @author WendyYang | |||||
**/ | |||||
MeetingExpert getByMeetingIdAndExpertId(Long meetingId, Long expertId); | |||||
/** | |||||
* 根据状态与会议ID分页查询专家列表 | |||||
* | |||||
* @param page 分页 | |||||
* @param meetingId 会议ID | |||||
* @param status 状态 | |||||
* @param inviteType 邀请类型 | |||||
* @return Page<MeetingExpert> | |||||
* @author WendyYang | |||||
**/ | |||||
Page<MeetingExpert> pageExpertByStatusAndMeetingId(Page<MeetingExpert> page, Long meetingId, ExpertAttendStatus status, Integer inviteType); | |||||
/** | |||||
* 批量查询某个状态的专家邀请记录 | |||||
* | |||||
* @param page 分页参数 | |||||
* @param meetingIds 会议ID | |||||
* @param status 状态 | |||||
* @return 专家邀请记录 | |||||
* @author WendyYang | |||||
**/ | |||||
Page<MeetingExpert> pageExpertByStatusAndMeetingIds(Page<MeetingExpert> page, List<Long> meetingIds, ExpertAttendStatus status); | |||||
/** | |||||
* 根据邀请类型统计会议下某个状态的专家数量 | |||||
* | |||||
* @param status 状态 | |||||
* @param meetingId 会议ID | |||||
* @param inviteType 邀请类型 | |||||
* @return int | |||||
* @author WendyYang | |||||
**/ | |||||
int countExpertByStatusAndMeetingId(ExpertAttendStatus status, Long meetingId, ExpertInviteType inviteType); | |||||
/** | |||||
* 查询所有同意参加的专家记录 | |||||
* | |||||
* @param meetingIds 会议ID | |||||
* @return List<MeetingExpert> | |||||
* @author WendyYang | |||||
**/ | |||||
List<MeetingExpert> listExpertByAgreeAttend(Collection<Long> meetingIds); | |||||
/** | |||||
* 查询会议的所有被抽取人最后一条记录 | |||||
* | |||||
* @param meetingIds 会议ID | |||||
* @return 抽取记录 | |||||
* @author WendyYang | |||||
**/ | |||||
List<MeetingExpert> listExpertLastByMeetingIds(Collection<Long> meetingIds); | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package com.ningdatech.pmapi.meeting.service; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusByDashboard; | |||||
import java.util.Map; | |||||
/** | |||||
* <p> | |||||
* 会议 服务类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
public interface IMeetingService extends IService<Meeting> { | |||||
/** | |||||
* 停止抽取 | |||||
* | |||||
* @param meetingId 会议ID | |||||
**/ | |||||
void stopRandomInvite(Long meetingId); | |||||
Map<MeetingStatusByDashboard, Integer> meetingCountSummary(Long createBy); | |||||
} |
@@ -0,0 +1,45 @@ | |||||
package com.ningdatech.pmapi.meeting.service.impl; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.pmapi.common.util.BizUtils; | |||||
import com.ningdatech.pmapi.common.util.StrUtils; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.mapper.ExpertInviteAvoidRuleMapper; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | |||||
import org.springframework.stereotype.Service; | |||||
/** | |||||
* <p> | |||||
* 服务实现类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Service | |||||
public class ExpertInviteAvoidRuleServiceImpl extends ServiceImpl<ExpertInviteAvoidRuleMapper, ExpertInviteAvoidRule> implements IExpertInviteAvoidRuleService { | |||||
@Override | |||||
public ExpertInviteAvoidRule getByMeetingId(Long meetingId) { | |||||
LambdaQueryWrapper<ExpertInviteAvoidRule> query = Wrappers.lambdaQuery(ExpertInviteAvoidRule.class) | |||||
.eq(ExpertInviteAvoidRule::getMeetingId, meetingId); | |||||
return getOne(query); | |||||
} | |||||
@Override | |||||
public AvoidInfoDTO getAvoidInfoDto(Long meetingId) { | |||||
ExpertInviteAvoidRule avoidRule = getByMeetingId(meetingId); | |||||
if (avoidRule == null) { | |||||
return null; | |||||
} | |||||
AvoidInfoDTO avoidInfo = new AvoidInfoDTO(); | |||||
avoidInfo.setAvoidMates(avoidRule.getAvoidMates()); | |||||
avoidInfo.setExpertIds(BizUtils.splitToLong(avoidRule.getExpertIds())); | |||||
avoidInfo.setCompanyIds(StrUtils.split(avoidRule.getCompanyIds())); | |||||
return avoidInfo; | |||||
} | |||||
} |
@@ -0,0 +1,47 @@ | |||||
package com.ningdatech.pmapi.meeting.service.impl; | |||||
import com.alibaba.fastjson.JSONObject; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import com.ningdatech.pmapi.meeting.mapper.ExpertInviteRuleMapper; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* <p> | |||||
* 服务实现类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Service | |||||
public class ExpertInviteRuleServiceImpl extends ServiceImpl<ExpertInviteRuleMapper, ExpertInviteRule> implements IExpertInviteRuleService { | |||||
public static LambdaQueryWrapper<ExpertInviteRule> wrapperByMeetingId(Long meetingId) { | |||||
return Wrappers.lambdaQuery(ExpertInviteRule.class).eq(ExpertInviteRule::getMeetingId, meetingId); | |||||
} | |||||
@Override | |||||
public List<ExpertInviteRule> listByMeetingId(Long meetingId) { | |||||
return list(wrapperByMeetingId(meetingId)); | |||||
} | |||||
@Override | |||||
public Map<Long, RandomInviteRuleDTO> randomRuleByMeetingId(Long meetingId) { | |||||
LambdaQueryWrapper<ExpertInviteRule> query = wrapperByMeetingId(meetingId) | |||||
.eq(ExpertInviteRule::getInviteType, ExpertInviteType.RANDOM.getCode()); | |||||
List<ExpertInviteRule> inviteRules = baseMapper.selectList(query); | |||||
return inviteRules.stream().collect(Collectors.toMap(ExpertInviteRule::getId, | |||||
w -> JSONObject.parseObject(w.getInviteRule(), RandomInviteRuleDTO.class))); | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package com.ningdatech.pmapi.meeting.service.impl; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.basic.model.PagePo; | |||||
import com.ningdatech.pmapi.common.model.entity.CountGroupByDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpertEvaluation; | |||||
import com.ningdatech.pmapi.meeting.mapper.MeetingExpertEvaluationMapper; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertEvaluationService; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.Collection; | |||||
/** | |||||
* <p> | |||||
* 专家评价表 服务实现类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-25 | |||||
*/ | |||||
@Service | |||||
public class MeetingExpertEvaluationServiceImpl extends ServiceImpl<MeetingExpertEvaluationMapper, MeetingExpertEvaluation> implements IMeetingExpertEvaluationService { | |||||
@Override | |||||
public Page<CountGroupByDTO<Long>> listExpertAttendSummary(Collection<Long> expertIds, Boolean isAttended, Page<CountGroupByDTO<Long>> page) { | |||||
return baseMapper.countExpertAttend(expertIds, isAttended, page); | |||||
} | |||||
@Override | |||||
public Page<MeetingExpert> pageExpertEvaluationTodo(Collection<Long> meetingIds, PagePo po) { | |||||
return baseMapper.pageExpertEvaluationToDo(meetingIds, new Page<>(po.getPageNumber(), po.getPageSize())); | |||||
} | |||||
} |
@@ -0,0 +1,135 @@ | |||||
package com.ningdatech.pmapi.meeting.service.impl; | |||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
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.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
import com.ningdatech.pmapi.meeting.mapper.ExpertInviteRuleMapper; | |||||
import com.ningdatech.pmapi.meeting.mapper.MeetingExpertMapper; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import lombok.RequiredArgsConstructor; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.Collection; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* <p> | |||||
* 事务专家表 服务实现类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-27 | |||||
*/ | |||||
@Service | |||||
@RequiredArgsConstructor | |||||
public class MeetingExpertServiceImpl extends ServiceImpl<MeetingExpertMapper, MeetingExpert> implements IMeetingExpertService { | |||||
private final ExpertInviteRuleMapper inviteRuleMapper; | |||||
@Override | |||||
public List<MeetingAndAttendStatusDTO> listByExpertIdAndStatus(Long expertId, Integer status, List<Long> meetingIds) { | |||||
return baseMapper.selectByExpertIdAndStatus(expertId, status, meetingIds); | |||||
} | |||||
@Override | |||||
public Map<Long, CountConfirmByMeetingIdDTO> countConfirmedByMeetingIds(List<Long> meetingIds) { | |||||
List<ExpertInviteRule> inviteRules = inviteRuleMapper.selectList(Wrappers.lambdaQuery(ExpertInviteRule.class) | |||||
.eq(ExpertInviteRule::getInviteType, ExpertInviteType.RANDOM.getCode()) | |||||
.in(ExpertInviteRule::getMeetingId, meetingIds)); | |||||
Map<Long, Integer> countByRandom = CollUtils.groupSumInt(inviteRules, ExpertInviteRule::getMeetingId, ExpertInviteRule::getInviteCount); | |||||
Page<MeetingExpert> page = pageExpertByStatusAndMeetingIds(new Page<>(0, 500), meetingIds, null); | |||||
return page.getRecords().stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId, | |||||
Collectors.collectingAndThen(Collectors.toList(), | |||||
w -> { | |||||
Long meetingId = w.get(0).getMeetingId(); | |||||
CountConfirmByMeetingIdDTO confirm = CountConfirmByMeetingIdDTO.builder() | |||||
.confirmed(0) | |||||
.total(countByRandom.getOrDefault(meetingId, 0)) | |||||
.meetingId(meetingId) | |||||
.build(); | |||||
w.forEach(item -> { | |||||
ExpertAttendStatus attendStatus = ExpertAttendStatus.getByCode(item.getStatus()); | |||||
if (item.getInviteType().equals(ExpertInviteType.APPOINT.getCode())) { | |||||
// 被替换和已取消的不计数 | |||||
if (attendStatus.equals(ExpertAttendStatus.CANCELED) | |||||
|| attendStatus.equals(ExpertAttendStatus.REPLACED)) { | |||||
return; | |||||
} | |||||
confirm.setTotal(confirm.getTotal() + 1); | |||||
} | |||||
// 除通知中的均为已确认 | |||||
if (attendStatus.equals(ExpertAttendStatus.AGREED)) { | |||||
confirm.setConfirmed(confirm.getConfirmed() + 1); | |||||
} | |||||
}); | |||||
return confirm; | |||||
}))); | |||||
} | |||||
@Override | |||||
public List<MeetingExpert> listByMeetingId(Long meetingId) { | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.eq(MeetingExpert::getMeetingId, meetingId) | |||||
.orderByDesc(MeetingExpert::getUpdateOn); | |||||
return list(query); | |||||
} | |||||
@Override | |||||
public List<MeetingExpert> listByMeetingIds(List<Long> meetingIds) { | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.in(MeetingExpert::getMeetingId, meetingIds) | |||||
.orderByDesc(MeetingExpert::getUpdateOn); | |||||
return list(query); | |||||
} | |||||
@Override | |||||
public MeetingExpert getByMeetingIdAndExpertId(Long meetingId, Long expertId) { | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.eq(MeetingExpert::getExpertId, expertId) | |||||
.eq(MeetingExpert::getMeetingId, meetingId) | |||||
.orderByDesc(MeetingExpert::getUpdateOn) | |||||
.last("limit 1"); | |||||
return getOne(query); | |||||
} | |||||
@Override | |||||
public Page<MeetingExpert> pageExpertByStatusAndMeetingId(Page<MeetingExpert> page, Long meetingId, ExpertAttendStatus status, Integer inviteType) { | |||||
return baseMapper.selectExpertByStatusAndMeetingId(page, status.getCode(), meetingId, inviteType); | |||||
} | |||||
@Override | |||||
public Page<MeetingExpert> pageExpertByStatusAndMeetingIds(Page<MeetingExpert> page, List<Long> meetingIds, ExpertAttendStatus status) { | |||||
return baseMapper.selectExpertByStatusAndMeetingIds(page, status == null ? null : status.getCode(), meetingIds); | |||||
} | |||||
@Override | |||||
public int countExpertByStatusAndMeetingId(ExpertAttendStatus status, Long meetingId, ExpertInviteType inviteType) { | |||||
Integer tempStatus = status == null ? null : status.getCode(); | |||||
Integer tempInviteType = inviteType == null ? null : inviteType.getCode(); | |||||
return baseMapper.countExpertByStatusAndMeetingId(tempStatus, meetingId, tempInviteType); | |||||
} | |||||
@Override | |||||
public List<MeetingExpert> listExpertByAgreeAttend(Collection<Long> meetingIds) { | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.eq(MeetingExpert::getStatus, ExpertAttendStatus.AGREED.getCode()) | |||||
.in(MeetingExpert::getMeetingId, meetingIds); | |||||
return baseMapper.selectList(query); | |||||
} | |||||
@Override | |||||
public List<MeetingExpert> listExpertLastByMeetingIds(Collection<Long> meetingIds) { | |||||
return baseMapper.listExpertLastByMeetingIds(meetingIds); | |||||
} | |||||
} |
@@ -0,0 +1,42 @@ | |||||
package com.ningdatech.pmapi.meeting.service.impl; | |||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.pmapi.common.model.entity.CountGroupByDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusByDashboard; | |||||
import com.ningdatech.pmapi.meeting.mapper.MeetingMapper; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* <p> | |||||
* 会议 服务实现类 | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2022-07-26 | |||||
*/ | |||||
@Service | |||||
public class MeetingServiceImpl extends ServiceImpl<MeetingMapper, Meeting> implements IMeetingService { | |||||
@Override | |||||
public void stopRandomInvite(Long meetingId) { | |||||
Meeting meeting = new Meeting(); | |||||
meeting.setId(meetingId); | |||||
meeting.setStopRandomInvite(Boolean.TRUE); | |||||
baseMapper.updateById(meeting); | |||||
} | |||||
@Override | |||||
public Map<MeetingStatusByDashboard, Integer> meetingCountSummary(Long createBy) { | |||||
List<CountGroupByDTO<String>> meetingCountSummary = baseMapper.meetingCountSummary(createBy); | |||||
return CollUtils.listToMap(meetingCountSummary, | |||||
w -> MeetingStatusByDashboard.valueOf(w.getGroupKey()), | |||||
CountGroupByDTO::getTotal); | |||||
} | |||||
} |
@@ -0,0 +1,241 @@ | |||||
//package com.ningdatech.pmapi.meeting.task; | |||||
// | |||||
//import com.alibaba.fastjson.JSON; | |||||
//import com.alibaba.fastjson.JSONObject; | |||||
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
//import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
//import com.ningdatech.basic.util.StrPool; | |||||
//import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; | |||||
//import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
//import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
//import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
//import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | |||||
//import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
//import com.ningdatech.pmapi.meta.helper.DictionaryCache; | |||||
//import com.ningdatech.pmapi.sms.utils.DateUtil; | |||||
//import lombok.AllArgsConstructor; | |||||
//import lombok.extern.slf4j.Slf4j; | |||||
//import org.apache.commons.lang3.StringUtils; | |||||
//import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||||
//import org.springframework.stereotype.Component; | |||||
// | |||||
//import javax.annotation.PostConstruct; | |||||
//import java.time.Duration; | |||||
//import java.time.Instant; | |||||
//import java.time.LocalDateTime; | |||||
//import java.time.temporal.ChronoUnit; | |||||
//import java.util.*; | |||||
//import java.util.stream.Collectors; | |||||
// | |||||
//import static com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus.AGREED; | |||||
//import static com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus.NOTICING; | |||||
// | |||||
// | |||||
///** | |||||
// * <p> | |||||
// * ExpertCallResultRewriteTask | |||||
// * <br> | |||||
// * 专家电话结果回填 | |||||
// * </p> | |||||
// * | |||||
// * @author WendyYang | |||||
// * @since 14:15 2022/8/18 | |||||
// */ | |||||
//@Slf4j | |||||
//@Component | |||||
//@AllArgsConstructor | |||||
//public class ExpertCallResultRewriteTask { | |||||
// | |||||
// private final RandomInviteProperties randomInviteProperties; | |||||
// | |||||
// private final ThreadPoolTaskScheduler scheduler; | |||||
// private final IMeetingExpertService meetingExpertService; | |||||
// private final IExpertInviteRuleService inviteRuleService; | |||||
// private final IMeetingService meetingService; | |||||
// private final ISysMsgRecordDetailService msgRecordDetailService; | |||||
// private final DictionaryCache dictionaryCache; | |||||
// private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
// private final IExpertUserFullInfoService iExpertUserFullInfoService; | |||||
// | |||||
// @PostConstruct | |||||
// public void initTask() { | |||||
// if (!randomInviteProperties.getEnable()) { | |||||
// log.warn("随机邀请已关闭……"); | |||||
// return; | |||||
// } | |||||
// Instant startTime = Instant.now().plus(randomInviteProperties.getResultRewriteFixedRate(), ChronoUnit.MINUTES); | |||||
// // 处理电话结果回填 | |||||
// scheduler.scheduleAtFixedRate(this::rewritePhoneCallResult, startTime, Duration.ofMinutes(randomInviteProperties.getResultRewriteFixedRate())); | |||||
// } | |||||
// | |||||
// | |||||
// public void rewritePhoneCallResult() { | |||||
// log.info("开始执行电话结果回填任务:{}", Thread.currentThread().getName()); | |||||
// // 查询所有邀请的专家信息 状态为通话中的 | |||||
// LambdaQueryWrapper<MeetingExpert> meQuery = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
// .eq(MeetingExpert::getStatus, NOTICING.getCode()) | |||||
// .eq(MeetingExpert::getInviteType, ExpertInviteType.RANDOM.getCode()); | |||||
// List<MeetingExpert> experts = meetingExpertService.list(meQuery); | |||||
// if (experts.isEmpty()) { | |||||
// log.info("暂无电话结果回填任务执行"); | |||||
// return; | |||||
// } | |||||
// // 所有随机邀请的规则ID | |||||
// Map<Long, String> submitKeys = new HashMap<>(experts.size()); | |||||
// Set<Long> randomRuleIds = experts.stream().peek(w -> submitKeys.put(w.getId(), w.getSubmitKey())) | |||||
// .map(MeetingExpert::getRuleId).collect(Collectors.toSet()); | |||||
// // 查询随机邀请回调等待时间 | |||||
// Map<Long, Integer> callbackMinutes = new HashMap<>(randomRuleIds.size()); | |||||
// if (!randomRuleIds.isEmpty()) { | |||||
// List<ExpertInviteRule> inviteRules = inviteRuleService.listByIds(randomRuleIds); | |||||
// inviteRules.forEach(w -> { | |||||
// RandomInviteRuleDTO rule = JSON.parseObject(w.getInviteRule(), RandomInviteRuleDTO.class); | |||||
// callbackMinutes.put(w.getId(), rule.getWaitForCallbackMinutes()); | |||||
// }); | |||||
// } | |||||
// LambdaQueryWrapper<SysMsgRecordDetail> msgRecordDetailQuery = Wrappers.lambdaQuery(SysMsgRecordDetail.class) | |||||
// .in(SysMsgRecordDetail::getSubmitKey, submitKeys.values()); | |||||
// List<SysMsgRecordDetail> recordDetailList = msgRecordDetailService.list(msgRecordDetailQuery); | |||||
// if (recordDetailList.isEmpty()) { | |||||
// return; | |||||
// } | |||||
// Map<String, SysMsgRecordDetail> recordDetailMap = recordDetailList.stream() | |||||
// .collect(Collectors.toMap(w -> w.getSubmitKey() + StrPool.UNDERSCORE + w.getReceiveNumber(), w -> w)); | |||||
// List<MeetingExpert> updates = new ArrayList<>(), agrees = new ArrayList<>(); | |||||
// for (MeetingExpert expert : experts) { | |||||
// String key = expert.getSubmitKey() + StrPool.UNDERSCORE + expert.getMobile(); | |||||
// SysMsgRecordDetail msgRecordDetail = recordDetailMap.get(key); | |||||
// if (msgRecordDetail == null) { | |||||
// // 极端情况下获取不到submitKey异常情况 | |||||
// continue; | |||||
// } | |||||
// Integer minutes = callbackMinutes.get(expert.getRuleId()); | |||||
// Optional<Integer> status = getStatusByMsgRecordDetail(msgRecordDetail, minutes, expert.getCreateOn()); | |||||
// if (status.isPresent()) { | |||||
// MeetingExpert update = new MeetingExpert(); | |||||
// update.setUpdateBy(0L); | |||||
// update.setUpdateOn(LocalDateTime.now()); | |||||
// update.setId(expert.getId()); | |||||
// update.setPreStatus(expert.getStatus()); | |||||
// update.setStatus(status.get()); | |||||
// if (AGREED.eq(update.getStatus())) { | |||||
// sendAgreeNotice(expert); | |||||
// agrees.add(expert); | |||||
// } | |||||
// updates.add(update); | |||||
// } | |||||
// } | |||||
// meetingExpertService.updateBatchById(updates); | |||||
// if (agrees.size() > 0) { | |||||
// obtainCallBackAfterMeetingCanceled(agrees); | |||||
// } | |||||
// } | |||||
// | |||||
// private void sendAgreeNotice(MeetingExpert expert) { | |||||
// try { | |||||
// Meeting meeting = meetingService.getById(expert.getMeetingId()); | |||||
// if (Objects.isNull(meeting)) { | |||||
// return; | |||||
// } | |||||
// ExpertUserFullInfo expertUserFullInfo = iExpertUserFullInfoService.getByUserId(expert.getExpertId()); | |||||
// String expertName = null; | |||||
// if (Objects.nonNull(expertUserFullInfo)) { | |||||
// expertName = expertUserFullInfo.getExpertName(); | |||||
// } | |||||
// String smsContent = String.format(YxtSmsTemplateConst.EXPERT_AGREE_NOTICE, meeting.getHoldCompany(), expertName, meeting.getName() | |||||
// , meeting.getStartTime().format(DateUtil.DTF_YMD_HM), meeting.getRegionDetail(), meeting.getConnecter(), meeting.getContact(), WebProperties.webUrl); | |||||
// SendSmsContext context = new SendSmsContext(); | |||||
// context.setContent(smsContent); | |||||
// context.setReceiveNumber(expert.getMobile()); | |||||
// | |||||
// yxtCallOrSmsHelper.sendSms(context); | |||||
// } catch (Exception e) { | |||||
// log.info("发送专家会议接受通知短信失败:{}", JSONObject.toJSONString(expert)); | |||||
// } | |||||
// } | |||||
// | |||||
// private static Optional<Integer> getStatusByMsgRecordDetail(SysMsgRecordDetail msgRecordDetail, int minutes, LocalDateTime createOn) { | |||||
// LocalDateTime time = LocalDateTime.now().minusMinutes(minutes); | |||||
// String callBackJson = msgRecordDetail.getCallBackJson(); | |||||
// if (StrUtils.isBlank(callBackJson) && time.isBefore(createOn)) { | |||||
// return Optional.empty(); | |||||
// } | |||||
// ExpertAttendStatus status; | |||||
// if (StrUtils.isNotBlank(callBackJson)) { | |||||
// try { | |||||
// JSONObject callbackObject = JSON.parseObject(callBackJson); | |||||
// Date dialBeginTime = callbackObject.getDate("dialBeginTime"); | |||||
// if (dialBeginTime == null) { | |||||
// return Optional.empty(); | |||||
// } | |||||
// Integer resultCode = callbackObject.getInteger("resultCode"); | |||||
// if (resultCode != null && resultCode == 0) { | |||||
// String pressKeyStr = callbackObject.getString("pressKey"); | |||||
// if (Objects.nonNull(pressKeyStr)) { | |||||
// pressKeyStr = pressKeyStr.replaceAll("\\*", "").trim(); | |||||
// } | |||||
// Integer pressKey = null; | |||||
// if (StringUtils.isNotBlank(pressKeyStr)) { | |||||
// pressKey = Integer.parseInt(pressKeyStr); | |||||
// } | |||||
// if (pressKey == null) { | |||||
// if (time.isBefore(createOn)) { | |||||
// return Optional.empty(); | |||||
// } | |||||
// status = REFUSED; | |||||
// } else { | |||||
// if (pressKey == 1) { | |||||
// status = AGREED; | |||||
// } else { | |||||
// status = REFUSED; | |||||
// } | |||||
// } | |||||
// } else { | |||||
// status = NOT_ANSWERED; | |||||
// } | |||||
// } catch (Exception e) { | |||||
// log.error("获取电话回调结果异常", e); | |||||
// status = NOT_ANSWERED; | |||||
// } | |||||
// } else { | |||||
// // 超时未回复设置为拒绝参加 | |||||
// status = REFUSED; | |||||
// } | |||||
// return Optional.of(status.getCode()); | |||||
// } | |||||
// | |||||
// /** | |||||
// * 会议取消之后拿到回调结果的话需要发送取消短信 | |||||
// **/ | |||||
// private void obtainCallBackAfterMeetingCanceled(List<MeetingExpert> experts) { | |||||
// /*List<Long> meetingIds = CollUtils.fieldList(experts, MeetingExpert::getMeetingId); | |||||
// LambdaQueryWrapper<Meeting> mQuery = Wrappers.lambdaQuery(Meeting.class) | |||||
// .eq(Meeting::getStatus, Manager.CANCELED.getCode()) | |||||
// .in(Meeting::getId, meetingIds); | |||||
// Map<Long, Meeting> meetingMap = CollUtils.listToMap(meetingService.list(mQuery), Meeting::getId); | |||||
// if (meetingMap.size() > 0) { | |||||
// Map<Meeting, List<MeetingExpert>> expertList = new HashMap<>(16); | |||||
// experts.forEach(w -> { | |||||
// Meeting meeting = meetingMap.get(w.getMeetingId()); | |||||
// if (meeting == null) { | |||||
// return; | |||||
// } | |||||
// List<MeetingExpert> list = expertList.computeIfAbsent(meeting, k -> new ArrayList<>()); | |||||
// list.add(w); | |||||
// }); | |||||
// if (!expertList.isEmpty()) { | |||||
// expertList.forEach((m, mes) -> { | |||||
// String meetingType = dictionaryCache.getByCode(m.getType()).getName(); | |||||
// List<SendSmsContext> contexts = YxtSmsContextBuilder.smsToExpertByCancelMeeting(m, mes, meetingType); | |||||
// yxtCallOrSmsHelper.sendSms(contexts); | |||||
// }); | |||||
// } | |||||
// }*/ | |||||
// } | |||||
// | |||||
//} |
@@ -0,0 +1,29 @@ | |||||
package com.ningdatech.pmapi.meeting.task; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.context.annotation.Configuration; | |||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteExecutorConfig | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 16:21 2022/8/16 | |||||
*/ | |||||
@Configuration | |||||
public class ExpertInviteExecutorConfig { | |||||
@Bean(name = "expertInviteScheduler") | |||||
public ThreadPoolTaskScheduler threadPoolTaskScheduler() { | |||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); | |||||
scheduler.setPoolSize(3); | |||||
scheduler.setThreadGroupName("expert-invite"); | |||||
scheduler.setThreadNamePrefix("invite-executor-"); | |||||
scheduler.setAwaitTerminationSeconds(60); | |||||
scheduler.setWaitForTasksToCompleteOnShutdown(true); | |||||
return scheduler; | |||||
} | |||||
} |
@@ -0,0 +1,326 @@ | |||||
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.update.LambdaUpdateWrapper; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.cache.model.cache.CacheKey; | |||||
import com.ningdatech.cache.repository.CachePlusOps; | |||||
import com.ningdatech.pmapi.common.util.SpringContextHolder; | |||||
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.MeetingExpert; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType; | |||||
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; | |||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
import com.ningdatech.pmapi.user.util.LoginUserUtil; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.aop.framework.AopContext; | |||||
import org.springframework.beans.factory.annotation.Qualifier; | |||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.transaction.annotation.Transactional; | |||||
import org.springframework.util.Assert; | |||||
import javax.annotation.PostConstruct; | |||||
import javax.annotation.Resource; | |||||
import java.time.Duration; | |||||
import java.time.Instant; | |||||
import java.time.LocalDateTime; | |||||
import java.time.ZoneId; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import java.util.concurrent.ConcurrentMap; | |||||
import java.util.concurrent.ScheduledFuture; | |||||
import java.util.concurrent.atomic.AtomicInteger; | |||||
import java.util.function.Function; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* <p> | |||||
* ExpertInviteTask | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 21:25 2022/8/15 | |||||
*/ | |||||
@Slf4j | |||||
@Component | |||||
@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 CacheKey CACHE_KEY = new CacheKey(MEETING_ID_INVITE_RANDOM); | |||||
private final CachePlusOps cachePlusOps; | |||||
@Qualifier("expertInviteScheduler") | |||||
@Resource(name = "expertInviteScheduler") | |||||
private ThreadPoolTaskScheduler scheduler; | |||||
private final IMeetingExpertService meetingExpertService; | |||||
private final IExpertInviteRuleService inviteRuleService; | |||||
private final IMeetingService meetingService; | |||||
private final ExpertInviteManage expertInviteManage; | |||||
private final IExpertInviteAvoidRuleService expertInviteAvoidRuleService; | |||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
public ExpertInviteTask currProxy() { | |||||
return (ExpertInviteTask) AopContext.currentProxy(); | |||||
} | |||||
/** | |||||
* 用来存入线程执行情况, 方便于停止定时任务时使用 | |||||
*/ | |||||
protected static final ConcurrentMap<Long, ScheduledFuture<?>> INVITE_MAP = new ConcurrentHashMap<>(); | |||||
@PostConstruct | |||||
public void initTask() { | |||||
if (!properties.getEnable()) { | |||||
log.warn("随机邀请已关闭……"); | |||||
return; | |||||
} | |||||
initInviteTaskByStart(); | |||||
} | |||||
/** | |||||
* 项目重启之后重新初始化邀请任务 | |||||
*/ | |||||
private void initInviteTaskByStart() { | |||||
Set<Object> meetingIds = cachePlusOps.sMembers(CACHE_KEY); | |||||
if (meetingIds == null || meetingIds.isEmpty()) { | |||||
return; | |||||
} | |||||
for (Object meetingId : meetingIds) { | |||||
addInviteExpertTask(Convert.toLong(meetingId), true, properties.getInviteDelay()); | |||||
} | |||||
} | |||||
/** | |||||
* 专家抽取校验 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @return boolean | |||||
* @author WendyYang | |||||
**/ | |||||
private boolean inviteCheck(Long meetingId) { | |||||
List<ExpertInviteRule> expertInviteRules = inviteRuleService.listByMeetingId(meetingId); | |||||
Function<ExpertInviteRule, ExpertInviteType> groupKey = w -> ExpertInviteType.getByCode(w.getInviteType()); | |||||
Map<ExpertInviteType, List<ExpertInviteRule>> groupByType = CollUtils.group(expertInviteRules, groupKey); | |||||
List<ExpertInviteRule> randomRules = groupByType.get(ExpertInviteType.RANDOM); | |||||
if (CollUtil.isEmpty(randomRules)) { | |||||
return false; | |||||
} | |||||
Map<Long, ExpertInviteRule> ruleMap = CollUtils.listToMap(randomRules, ExpertInviteRule::getId); | |||||
LambdaQueryWrapper<MeetingExpert> query = Wrappers.lambdaQuery(MeetingExpert.class) | |||||
.in(MeetingExpert::getRuleId, ruleMap.keySet()) | |||||
.in(MeetingExpert::getStatus, ExpertAttendStatus.AGREED.getCode()); | |||||
List<MeetingExpert> meetingExperts = meetingExpertService.list(query); | |||||
int totalCount = CollUtils.sum(randomRules, ExpertInviteRule::getInviteCount); | |||||
boolean needed = totalCount > meetingExperts.size(); | |||||
if (!needed) { | |||||
cancelByMeetingId(meetingId); | |||||
} | |||||
return needed; | |||||
} | |||||
/** | |||||
* 唤醒某个会议的抽取任务 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @author WendyYang | |||||
**/ | |||||
public void addInviteExpertTask(Long meetingId) { | |||||
boolean contains = INVITE_MAP.containsKey(meetingId); | |||||
if (!contains) { | |||||
addInviteExpertTask(meetingId, false, properties.getInviteDelay()); | |||||
log.info("重置会议的随机抽取状态:{}", meetingId); | |||||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | |||||
update.set(Meeting::getStopRandomInvite, false); | |||||
update.set(Meeting::getUpdateBy, LoginUserUtil.getUserId()); | |||||
update.set(Meeting::getUpdateOn, LocalDateTime.now()); | |||||
update.eq(Meeting::getId, meetingId); | |||||
meetingService.update(update); | |||||
} | |||||
} | |||||
/** | |||||
* 添加专家抽取校验任务 | |||||
* | |||||
* @param meetingId 会议ID | |||||
* @param checked 是否前置校验 | |||||
* @param delayedMinutes 延迟执行时间 | |||||
* @author WendyYang | |||||
**/ | |||||
public void addInviteExpertTask(Long meetingId, boolean checked, int delayedMinutes) { | |||||
if (checked && !inviteCheck(meetingId)) { | |||||
return; | |||||
} | |||||
Instant startTime = LocalDateTime.now().plusMinutes(delayedMinutes).atZone(ZoneId.systemDefault()).toInstant(); | |||||
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> { | |||||
ExpertInviteTask bean = SpringContextHolder.getBean(ExpertInviteTask.class); | |||||
try { | |||||
bean.invite(meetingId); | |||||
} catch (Exception e) { | |||||
log.error("执行专家邀请任务异常:{}", meetingId, e); | |||||
} | |||||
}, startTime, Duration.ofMinutes(properties.getInviteFixedRate())); | |||||
INVITE_MAP.putIfAbsent(meetingId, future); | |||||
log.info("添加专家抽取后台任务:{}", meetingId); | |||||
} | |||||
public void addInviteExpertTaskByMeetingCreate(Long meetingId, int delayedMinutes) { | |||||
Assert.isTrue(properties.getEnable(), "随机邀请已关闭"); | |||||
addInviteExpertTask(meetingId, false, delayedMinutes); | |||||
cachePlusOps.sAdd(CACHE_KEY, meetingId); | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void invite(Long meetingId) { | |||||
log.info("开始进行专家后台抽取:{}", meetingId); | |||||
Meeting meeting = meetingService.getById(meetingId); | |||||
if (meeting.getStartTime().isBefore(LocalDateTime.now())) { | |||||
// 会议开始结束随机抽取 | |||||
cancelByMeetingId(meetingId); | |||||
log.info("会议已开始停止抽取:{}", meeting); | |||||
return; | |||||
} | |||||
// 随机邀请规则 | |||||
Map<Long, RandomInviteRuleDTO> ruleMap = inviteRuleService.randomRuleByMeetingId(meetingId); | |||||
// 回避规则 | |||||
AvoidInfoDTO avoidInfoDto = expertInviteAvoidRuleService.getAvoidInfoDto(meetingId); | |||||
// 还需要抽取的规则数量 | |||||
AtomicInteger notIgnoreCnt = new AtomicInteger(ruleMap.size()); | |||||
AtomicInteger notSupportCnt = new AtomicInteger(0); | |||||
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); | |||||
// 已确认参加、通话中数量 | |||||
ExpertCntBO cnt = countMap.getOrDefault(ruleId, ExpertCntBO.zeroInit()); | |||||
int tempCurrent = cnt.getAgreeCnt() + cnt.getNoticeCnt(); | |||||
if (tempCurrent == value.getCount()) { | |||||
if (cnt.getAgreeCnt().equals(value.getCount())) { | |||||
notIgnoreCnt.decrementAndGet(); | |||||
} | |||||
return; | |||||
} | |||||
int currInviteCnt = value.getCount() - tempCurrent; | |||||
ExpertChooseDTO expertChoose = expertInviteManage.expertReplaceByRandomRule(avoidInfoDto, value, | |||||
expertMap.values(), currInviteCnt, meeting.getStartTime(), meeting.getEndTime(), null); | |||||
if (expertChoose.getTotal() > 0) { | |||||
List<MeetingExpert> expertMeetings = CollUtils.convert(expertChoose.getExperts(), w -> { | |||||
MeetingExpert expert = ExpertInviteBuilder.getExpertByRandom(meetingId, w, ruleId); | |||||
expert.setPreStatus(ExpertAttendStatus.NOTICING.getCode()); | |||||
expert.setStatus(ExpertAttendStatus.NOTICING.getCode()); | |||||
return expert; | |||||
}); | |||||
yxtCallOrSmsHelper.callByMeetingExperts(meeting, expertMeetings); | |||||
log.info("会议:{} 后台抽取专家:{}名", meetingId, expertMeetings.size()); | |||||
meetingExpertService.saveBatch(expertMeetings); | |||||
} else { | |||||
// 抽取人数不够 | |||||
notSupportCnt.incrementAndGet(); | |||||
} | |||||
}); | |||||
if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) { | |||||
if (notSupportCnt.get() > 0) { | |||||
// TODO | |||||
/*UserInfo inviterBasic = userInfoService.getById(meeting.getCreateBy()); | |||||
UserInfo inviter = userInfoService.getById(inviterBasic.getId()); | |||||
SendSmsContext context = YxtSmsContextBuilder.smsByRandomInviteStop(inviter.getNickname(), meeting.getName(), inviterBasic.getPhoneNo()); | |||||
yxtCallOrSmsHelper.sendSms(context);*/ | |||||
} | |||||
log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt); | |||||
currProxy().cancelByMeetingId(meetingId); | |||||
} | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void cancelByMeetingId(Long meetingId) { | |||||
log.info("终止专家抽取:{}", meetingId); | |||||
meetingService.stopRandomInvite(meetingId); | |||||
cachePlusOps.sRem(CACHE_KEY, meetingId); | |||||
ScheduledFuture<?> future = INVITE_MAP.get(meetingId); | |||||
if (future != null) { | |||||
INVITE_MAP.remove(meetingId); | |||||
if (!future.isCancelled()) { | |||||
future.cancel(true); | |||||
} | |||||
} | |||||
} | |||||
//================================================================================================================== | |||||
private Map<Long, ExpertCntBO> countByAgree(Map<Long, MeetingExpert> expertMap, Map<Long, MeetingExpert> replacedMap) { | |||||
return expertMap.entrySet().stream() | |||||
.collect(Collectors.groupingBy(w -> w.getValue().getRuleId(), | |||||
Collectors.collectingAndThen(Collectors.mapping(Map.Entry::getValue, Collectors.toList()), w -> { | |||||
ExpertCntBO cnt = ExpertCntBO.zeroInit(); | |||||
for (MeetingExpert expert : w) { | |||||
if (ExpertAttendStatus.AGREED.eq(expert.getStatus())) { | |||||
cnt.incrAgreeCnt(); | |||||
} else if (ExpertAttendStatus.NOTICING.eq(expert.getStatus())) { | |||||
cnt.incrNoticeCnt(); | |||||
} else if (ExpertAttendStatus.REPLACED.eq(expert.getStatus())) { | |||||
MeetingExpert replacedExpert = replacedMap.get(expert.getId()); | |||||
if (replacedExpert != null && ExpertAttendStatus.AGREED.eq(replacedExpert.getStatus())) { | |||||
cnt.incrAgreeCnt(); | |||||
} | |||||
} | |||||
} | |||||
return cnt; | |||||
}))); | |||||
} | |||||
@Data | |||||
public static class ExpertCntBO { | |||||
private Integer agreeCnt; | |||||
private Integer noticeCnt; | |||||
public ExpertCntBO(Integer agreeCnt, Integer noticeCnt) { | |||||
this.agreeCnt = agreeCnt; | |||||
this.noticeCnt = noticeCnt; | |||||
} | |||||
public void incrAgreeCnt() { | |||||
agreeCnt++; | |||||
} | |||||
public void incrNoticeCnt() { | |||||
noticeCnt++; | |||||
} | |||||
public static ExpertCntBO zeroInit() { | |||||
return new ExpertCntBO(0, 0); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,93 @@ | |||||
//package com.ningdatech.pmapi.meeting.task; | |||||
// | |||||
//import com.alibaba.fastjson.JSONObject; | |||||
//import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||||
//import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
//import com.ningdatech.pmapi.meeting.builder.YxtSmsContextBuilder; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
//import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus; | |||||
//import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus; | |||||
//import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | |||||
//import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
//import lombok.AllArgsConstructor; | |||||
//import lombok.extern.slf4j.Slf4j; | |||||
//import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||||
//import org.springframework.stereotype.Component; | |||||
// | |||||
//import javax.annotation.PostConstruct; | |||||
//import java.time.Duration; | |||||
//import java.time.Instant; | |||||
//import java.time.temporal.ChronoUnit; | |||||
//import java.util.HashSet; | |||||
//import java.util.List; | |||||
//import java.util.Objects; | |||||
//import java.util.Set; | |||||
// | |||||
///** | |||||
// * @author liuxinxin | |||||
// * @date 2023/2/2 上午9:57 | |||||
// */ | |||||
// | |||||
//@Slf4j | |||||
//@Component | |||||
//@AllArgsConstructor | |||||
//public class MeetingInviteCompleteNoticeTask { | |||||
// | |||||
// private final RandomInviteProperties randomInviteProperties; | |||||
// private final IMeetingService meetingService; | |||||
// private final IMeetingExpertService meetingExpertService; | |||||
// private final ThreadPoolTaskScheduler scheduler; | |||||
// private final RedisUtils redisUtils; | |||||
// private final static String MEETING_INVITE_COMPLETE_NOTICED_MEETING_ID_CACHE_KEY = "MEETING_INVITE_COMPLETE_NOTICED_MEETING_ID_CACHE_KEY"; | |||||
// private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
// private final IExpertInviteRuleService iExpertInviteRuleService; | |||||
// | |||||
// @PostConstruct | |||||
// public void initTask() { | |||||
// Instant startTime = Instant.now().plus(randomInviteProperties.getMeetingInviteCompleteNoticeRate(), ChronoUnit.MINUTES); | |||||
// // 处理电话结果回填 | |||||
// scheduler.scheduleAtFixedRate(this::meetingInviteCompleteNotice, startTime, Duration.ofMinutes(randomInviteProperties.getResultRewriteFixedRate())); | |||||
// } | |||||
// | |||||
// public void meetingInviteCompleteNotice() { | |||||
// log.info("开始执行抽取完成通知:{}", Thread.currentThread().getName()); | |||||
// List<Meeting> meetingIdList = meetingService.list(Wrappers.lambdaQuery(Meeting.class) | |||||
// .eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode()) | |||||
// .eq(Meeting::getSendMeetingNotice, false) | |||||
// .eq(Meeting::getStopRandomInvite, true)); | |||||
// | |||||
// Set<Long> completeNoticedMeetingIdList = getCompleteNoticedMeetingIdList(); | |||||
// for (Meeting meeting : meetingIdList) { | |||||
// Long meetingId = meeting.getId(); | |||||
// if (completeNoticedMeetingIdList.add(meetingId)) { | |||||
// List<ExpertInviteRule> expertInviteRules = iExpertInviteRuleService.listByMeetingId(meetingId); | |||||
// if (expertInviteRules.size() == 0) { | |||||
// return; | |||||
// } | |||||
// int noticeCount = meetingExpertService.countExpertByStatusAndMeetingId(ExpertAttendStatus.NOTICING, meetingId, null); | |||||
// if (noticeCount == 0) { | |||||
// redisUtils.set(MEETING_INVITE_COMPLETE_NOTICED_MEETING_ID_CACHE_KEY, JSONObject.toJSONString(completeNoticedMeetingIdList), 24 * 60 * 60); | |||||
// if (StringUtils.isNotBlank(meeting.getContact()) && StringUtils.isNotBlank(meeting.getConnecter())) { | |||||
// SendSmsCmd.SendSmsContext context = YxtSmsContextBuilder.meetingInviteCompleteNotice(meeting); | |||||
// yxtCallOrSmsHelper.sendSms(context); | |||||
// } | |||||
// } | |||||
// } | |||||
// } | |||||
// } | |||||
// | |||||
// private Set<Long> getCompleteNoticedMeetingIdList() { | |||||
// Object result = redisUtils.get(MEETING_INVITE_COMPLETE_NOTICED_MEETING_ID_CACHE_KEY); | |||||
// HashSet<Long> completeNoticedMeetingIdSet = new HashSet<>(); | |||||
// if (Objects.nonNull(result)) { | |||||
// String resultStr = result.toString(); | |||||
// List<Long> completeNoticedMeetingIdList = JSONObject.parseArray(resultStr, Long.class); | |||||
// completeNoticedMeetingIdSet = new HashSet<>(completeNoticedMeetingIdList); | |||||
// } | |||||
// return completeNoticedMeetingIdSet; | |||||
// } | |||||
// | |||||
//} |
@@ -0,0 +1,160 @@ | |||||
//package com.ningdatech.pmapi.meeting.task; | |||||
// | |||||
//import cn.hutool.crypto.SecureUtil; | |||||
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||
//import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
//import com.ningdatech.basic.util.CollUtils; | |||||
//import com.ningdatech.basic.util.StrPool; | |||||
//import com.ningdatech.cache.model.cache.CacheHashKey; | |||||
//import com.ningdatech.cache.repository.CachePlusOps; | |||||
//import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
//import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
//import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus; | |||||
//import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingExpertService; | |||||
//import com.ningdatech.pmapi.meeting.service.IMeetingService; | |||||
//import com.ningdatech.pmapi.meta.helper.DictionaryCache; | |||||
//import lombok.AllArgsConstructor; | |||||
//import lombok.Data; | |||||
//import lombok.extern.slf4j.Slf4j; | |||||
//import org.springframework.scheduling.annotation.Scheduled; | |||||
//import org.springframework.stereotype.Component; | |||||
// | |||||
//import java.time.LocalDateTime; | |||||
//import java.time.temporal.ChronoUnit; | |||||
//import java.util.ArrayList; | |||||
//import java.util.HashMap; | |||||
//import java.util.List; | |||||
//import java.util.Map; | |||||
//import java.util.stream.Collectors; | |||||
// | |||||
///** | |||||
// * <p> | |||||
// * NoticeExpertAt24HoursBeforeMeetingTask | |||||
// * </p> | |||||
// * | |||||
// * @author WendyYang | |||||
// * @since 09:16 2022/11/16 | |||||
// */ | |||||
//@Slf4j | |||||
//@Component | |||||
//@AllArgsConstructor | |||||
//public class NoticeExpertAt24HoursBeforeMeetingTask { | |||||
// | |||||
// @Data | |||||
// private static class NoticeValue { | |||||
// | |||||
// private LocalDateTime startTime; | |||||
// | |||||
// private String addressMd5; | |||||
// | |||||
// } | |||||
// | |||||
// private final IMeetingService meetingService; | |||||
// private final IMeetingExpertService meetingExpertService; | |||||
// private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
// private final DictionaryCache dictionaryCache; | |||||
// private final CachePlusOps cachePlusOps; | |||||
// private final IExpertUserFullInfoService expertUserFullInfoService; | |||||
// | |||||
// private static final String EXPERT_NOTICE_AT_24H_BEFORE_MEETING = "EXPERT_NOTICE_AT_24H_BEFORE_MEETING"; | |||||
// | |||||
// private void addNoticeKey(Long meetingId, Map<String, Object> noticeValue, LocalDateTime startTime) { | |||||
// long mills = ChronoUnit.SECONDS.between(LocalDateTime.now(), startTime); | |||||
// CacheHashKey key = new CacheHashKey(); | |||||
// key.setKey(EXPERT_NOTICE_AT_24H_BEFORE_MEETING + StrPool.COLON + meetingId); | |||||
// key.setField(mills); | |||||
// cachePlusOps.hSet(key, noticeValue); | |||||
// } | |||||
// | |||||
// private Map<Long, NoticeValue> getNoticeKey(Long meetingId) { | |||||
// Map<Object, Object> cache = cachePlusOps.hGet(EXPERT_NOTICE_AT_24H_BEFORE_MEETING + StrPool.COLON + meetingId); | |||||
// return cache.entrySet().stream().collect(Collectors.toMap(w -> Long.valueOf(w.getKey().toString()), w -> (NoticeValue) w.getValue())); | |||||
// } | |||||
// | |||||
// /** | |||||
// * 查询需要发送通知的会议: | |||||
// * <ul>1. 未完成</ul> | |||||
// * <ul>2. 创建邀请</ul> | |||||
// * <ul>3. 当前时间距离会议开始时间不足24小时</ul> | |||||
// * | |||||
// * @return 会议信息 | |||||
// * @author WendyYang | |||||
// **/ | |||||
// private Map<Long, Meeting> loadMeetingAt24HoursBeforeMeeting() { | |||||
// LambdaQueryWrapper<Meeting> query = Wrappers.lambdaQuery(Meeting.class); | |||||
// LocalDateTime now = LocalDateTime.now(), hoursAgoBy24 = now.plusHours(24); | |||||
// // 10分钟之内不再发送通知 | |||||
// query.between(Meeting::getStartTime, now.plusMinutes(10), hoursAgoBy24); | |||||
// query.eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode()); | |||||
// query.eq(Meeting::getInvited, Boolean.TRUE); | |||||
// List<Meeting> meetings = meetingService.list(query); | |||||
// return CollUtils.listToMap(meetings, Meeting::getId); | |||||
// } | |||||
// | |||||
// private String addressDetailMd5(Meeting meeting) { | |||||
// String content = meeting.getRegionCode() + StrPool.HASH + meeting.getRegionLevel() + StrPool.HASH + meeting.getRegionDetail(); | |||||
// return SecureUtil.md5(content); | |||||
// } | |||||
// | |||||
// private boolean skipExpert(NoticeValue noticeValue, String addressMd5, LocalDateTime startTime) { | |||||
// boolean skip = noticeValue.getAddressMd5().equals(addressMd5); | |||||
// if (skip) { | |||||
// skip = noticeValue.getStartTime().equals(startTime); | |||||
// } | |||||
// return skip; | |||||
// } | |||||
// | |||||
// @Scheduled(cron = "${expert-attend-notice.cron:0 0/5 7-21 * * ?}") | |||||
// public void execute() { | |||||
// log.info("开始执行会议开始前24小时再次短信提醒任务"); | |||||
// Map<Long, Meeting> meetingsMap = loadMeetingAt24HoursBeforeMeeting(); | |||||
// if (meetingsMap.isEmpty()) { | |||||
// return; | |||||
// } | |||||
// List<MeetingExpert> expertList = meetingExpertService.listExpertByAgreeAttend(meetingsMap.keySet()); | |||||
// if (expertList.isEmpty()) { | |||||
// return; | |||||
// } | |||||
// List<SendSmsCmd.SendSmsContext> contexts = new ArrayList<>(); | |||||
// Map<Long, List<MeetingExpert>> expertGroup = CollUtils.group(expertList, MeetingExpert::getMeetingId); | |||||
// expertGroup.forEach((meetingId, experts) -> { | |||||
// Map<String, Object> noticeCache = new HashMap<>(16); | |||||
// Meeting meeting = meetingsMap.get(meetingId); | |||||
// String md5 = addressDetailMd5(meeting); | |||||
// Map<Long, NoticeValue> noticeKey = getNoticeKey(meetingId); | |||||
// String holdCompany = meeting.getHoldCompanyBracket(); | |||||
// String startTime = meeting.getStartTime().format(DateUtil.DTF_YMD_HM); | |||||
// String meetingType = dictionaryCache.getByCode(meeting.getType()).getName(); | |||||
// for (MeetingExpert expert : experts) { | |||||
// NoticeValue noticeValue = noticeKey.get(expert.getId()); | |||||
// if (noticeValue != null) { | |||||
// if (skipExpert(noticeValue, md5, meeting.getStartTime())) { | |||||
// continue; | |||||
// } | |||||
// } | |||||
// NoticeValue value = new NoticeValue(); | |||||
// value.setAddressMd5(md5); | |||||
// value.setStartTime(meeting.getStartTime()); | |||||
// noticeCache.put(expert.getId().toString(), value); | |||||
// SendSmsCmd.SendSmsContext context = new SendSmsCmd.SendSmsContext(); | |||||
// | |||||
// ExpertUserFullInfo expertUserFullInfo = expertUserFullInfoService.getByUserId(expert.getExpertId()); | |||||
// String content = String.format(YxtSmsTemplateConst.SEND_MEETING_NOTICE, expertUserFullInfo.getName(), | |||||
// expert.getUpdateOn().format(DateUtil.DTF_YMD_HM), meetingType, startTime, | |||||
// meeting.getRegionDetail(), meeting.getContact()); | |||||
// context.setContent(holdCompany + content); | |||||
// context.setReceiveNumber(expert.getMobile()); | |||||
// contexts.add(context); | |||||
// } | |||||
// if (!noticeCache.isEmpty()) { | |||||
// addNoticeKey(meetingId, noticeCache, meeting.getStartTime()); | |||||
// } | |||||
// }); | |||||
// if (!contexts.isEmpty()) { | |||||
// yxtCallOrSmsHelper.sendSms(contexts); | |||||
// } | |||||
// } | |||||
// | |||||
//} |
@@ -0,0 +1,40 @@ | |||||
package com.ningdatech.pmapi.meeting.task; | |||||
import lombok.Data; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* <p> | |||||
* TelInviteTaskProperties | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 17:25 2022/9/9 | |||||
*/ | |||||
@Data | |||||
@Component | |||||
@ConfigurationProperties(prefix = "random-invite") | |||||
public class RandomInviteProperties { | |||||
/** | |||||
* 是否开启随机抽取 | |||||
*/ | |||||
private Boolean enable = true; | |||||
/** | |||||
* 电话结果回填执行频率(分钟) | |||||
*/ | |||||
private Integer resultRewriteFixedRate = 2; | |||||
/** | |||||
* 随机邀请延迟执行(分钟) | |||||
*/ | |||||
private Integer inviteDelay = 2; | |||||
/** | |||||
* 随机邀请执行频率(分钟) | |||||
*/ | |||||
private Integer inviteFixedRate = 3; | |||||
/** | |||||
* 会议抽取完成通知 管理员下发会议通知 | |||||
*/ | |||||
private Integer meetingInviteCompleteNoticeRate = 1; | |||||
} |
@@ -2,6 +2,7 @@ package com.ningdatech.pmapi.user.util; | |||||
import com.ningdatech.basic.auth.AbstractLoginUserUtil; | import com.ningdatech.basic.auth.AbstractLoginUserUtil; | ||||
import com.ningdatech.pmapi.sys.model.entity.Role; | import com.ningdatech.pmapi.sys.model.entity.Role; | ||||
import com.ningdatech.pmapi.user.entity.enumeration.RoleEnum; | |||||
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails; | import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails; | ||||
import java.util.List; | import java.util.List; | ||||
@@ -25,4 +26,9 @@ public class LoginUserUtil extends AbstractLoginUserUtil { | |||||
return userRoleList.stream().map(Role::getId).collect(Collectors.toList()); | return userRoleList.stream().map(Role::getId).collect(Collectors.toList()); | ||||
} | } | ||||
public static boolean isExpert() { | |||||
UserInfoDetails detail = loginUserDetail(); | |||||
return detail.getUserRoleList().stream().anyMatch(w -> RoleEnum.EXPERT.eq(w.getCode())); | |||||
} | |||||
} | } |