diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java index a70a51f..dee41ff 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java @@ -8,11 +8,9 @@ import com.ningdatech.pmapi.meeting.entity.dto.ReviewProjectDTO; import com.ningdatech.pmapi.meeting.entity.req.*; import com.ningdatech.pmapi.meeting.entity.vo.*; import com.ningdatech.pmapi.meeting.manage.MeetingManage; -import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; -import lombok.Getter; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -165,7 +163,7 @@ public class MeetingController { @ApiOperation("重发短信") @PostMapping("/confirmedRoster") @WebLog(value = "重发短信") - public void resendSms(MeetingCancelReq req) { + public void resendSms(@RequestBody MeetingCancelReq req) { meetingManage.confirmedRoster(req.getMeetingId()); } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java index 95389e9..1440751 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java @@ -36,12 +36,12 @@ public class MeetingBasicDTO { @NotNull(message = "开始时间不能为空") @ApiModelProperty("开始时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime startTime; @NotNull(message = "结束时间不能为空") @ApiModelProperty("结束时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime endTime; @NotNull(message = "评审耗时不能为空") @@ -50,7 +50,7 @@ public class MeetingBasicDTO { @NotNull(message = "评委出席时间不能为空") @ApiModelProperty("评委出席时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime judgesAttendanceTime; @NotEmpty(message = "评审地点不能为空") diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java index 2d206dd..2488ff5 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java @@ -26,11 +26,11 @@ public class MeetingListReq extends PagePo { private String name; @ApiModelProperty("会议开始时间") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime startTime; @ApiModelProperty("会议结束时间") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime endTime; @ApiModelProperty("事务状态") diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java index af17437..fb4b5a1 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java @@ -23,6 +23,7 @@ import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO; import com.ningdatech.pmapi.meeting.entity.dto.MeetingBasicDTO; import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum; import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq; import com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVO; import com.ningdatech.pmapi.meeting.entity.vo.MeetingByManagerVO; @@ -194,20 +195,28 @@ public class MeetingManageHelper { /** * 校验是否能够进行指定邀请 * - * @param meetingId 会议ID - * @param expertIds 专家ID + * @param meetingId 会议ID + * @param expertIds 专家ID + * @param inviteType 邀请类型 * @return 符合邀请规则的专家 * @author WendyYang **/ - public List appointExpertCheck(Long meetingId, List expertIds) { + public List appointExpertCheck(Long meetingId, Integer inviteType, List expertIds) { List experts = expertUserFullInfoService.listByUserId(expertIds); - AvoidRuleDTO avoidRule = getAvoidInfoDto(meetingId); + AvoidRuleDTO avoidRule; + if (ExpertInviteTypeEnum.RANDOM.eq(inviteType)) { + avoidRule = getAvoidInfoDto(meetingId); + } else { + avoidRule = null; + } experts.forEach(expert -> { - if (avoidRule.getAvoidUnitIdList().contains(expert.getCompany())) { - throw BizException.wrap("请移除已回避单位的专家"); - } - if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds()) && avoidRule.getExpertIds().contains(expert.getUserId())) { - throw BizException.wrap("请移除已回避的专家"); + if (avoidRule != null) { + if (avoidRule.getAvoidUnitIdList().contains(expert.getCompany())) { + throw BizException.wrap("请移除已回避单位的专家"); + } + if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds()) && avoidRule.getExpertIds().contains(expert.getUserId())) { + throw BizException.wrap("请移除已回避的专家"); + } } // 校验专家状态 ExpertAccountStatusEnum accountStatus = ExpertAccountStatusEnum.of(expert.getExpertAccountStatus()); diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java index bd713f0..3a1f4b0 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java @@ -1,13 +1,24 @@ package com.ningdatech.pmapi.meeting.helper; +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.sms.constant.VoiceSmsTemplateConst; +import com.ningdatech.pmapi.sms.utils.DateUtil; +import com.ningdatech.yxt.client.YxtClient; +import com.ningdatech.yxt.constants.YxtSmsSignEnum; +import com.ningdatech.yxt.model.cmd.SendSmsCmd; +import com.ningdatech.yxt.model.cmd.SendSmsCmd.SendSmsContext; +import com.ningdatech.yxt.model.cmd.SubmitTaskCallResponse; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; +import static com.ningdatech.yxt.model.cmd.SubmitTaskCallCmd.SubmitTaskCallContext; +import static com.ningdatech.yxt.model.cmd.SubmitTaskCallCmd.of; + /** *

* YxtCallOrSmsHelper @@ -20,24 +31,24 @@ import java.util.List; @AllArgsConstructor public class YxtCallOrSmsHelper { - // private final YinXinTongClient yinXinTongClient; + private final YxtClient yxtClient; public void callByMeetingExperts(Meeting meeting, List experts) { - /*String callContent = String.format(YxtCallTemplateConst.OFFLINE_TEMPLATE, - meeting.getHoldCompany(), meeting.getName(), - meeting.getStartTime().format(DateUtil.DTF_YMD_HM), meeting.getRegionDetail()); + String callContent = String.format(VoiceSmsTemplateConst.OFFLINE_TEMPLATE, + meeting.getHoldOrg(), meeting.getName(), + meeting.getStartTime().format(DateUtil.DTF_YMD_HM), meeting.getMeetingAddress()); List 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()));*/ + SubmitTaskCallResponse callResponse = yxtClient.submitTaskCall(of(callContexts)); + experts.forEach(w -> w.setSubmitKey(callResponse.getSubmitKey())); } - /*public void sendSms(List smsList) { - yinXinTongClient.submitSmsTask(new SendSmsCmd() {{ + public void sendSms(List smsList) { + yxtClient.submitSmsTask(new SendSmsCmd() {{ setContextList(smsList); setSmsSignEnum(YxtSmsSignEnum.ZJS_ELECTRONIC_EXPERT_LIB); }}); @@ -45,6 +56,6 @@ public class YxtCallOrSmsHelper { public void sendSms(SendSmsContext sms) { sendSms(Collections.singletonList(sms)); - }*/ + } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java index 10996f9..02c29f6 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java @@ -559,7 +559,7 @@ public class MeetingManage { throw BizException.wrap("补充专家失败"); } AppointInviteRuleDTO rule = inviteRuleService.appointRuleByMeetingId(meetingId); - List userInfos = meetingManageHelper.appointExpertCheck(meetingId, req.getExpertIdList()); + List userInfos = meetingManageHelper.appointExpertCheck(meetingId, meeting.getInviteType(), req.getExpertIdList()); List expertList = CollUtils.convert(userInfos, w -> { MeetingExpert me = ExpertInviteBuilder.getExpertByAppoint(meetingId, w, rule.getId()); me.setStatus(ExpertAttendStatusEnum.NOTICING.getCode()); diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java index 8f971b9..d0d8ee3 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertCallResultRewriteTask.java @@ -1,241 +1,252 @@ -//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; -// -// -///** -// *

-// * ExpertCallResultRewriteTask -// *
-// * 专家电话结果回填 -// *

-// * -// * @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 meQuery = Wrappers.lambdaQuery(MeetingExpert.class) -// .eq(MeetingExpert::getStatus, NOTICING.getCode()) -// .eq(MeetingExpert::getInviteType, ExpertInviteType.RANDOM.getCode()); -// List experts = meetingExpertService.list(meQuery); -// if (experts.isEmpty()) { -// log.info("暂无电话结果回填任务执行"); -// return; -// } -// // 所有随机邀请的规则ID -// Map submitKeys = new HashMap<>(experts.size()); -// Set randomRuleIds = experts.stream().peek(w -> submitKeys.put(w.getId(), w.getSubmitKey())) -// .map(MeetingExpert::getRuleId).collect(Collectors.toSet()); -// // 查询随机邀请回调等待时间 -// Map callbackMinutes = new HashMap<>(randomRuleIds.size()); -// if (!randomRuleIds.isEmpty()) { -// List inviteRules = inviteRuleService.listByIds(randomRuleIds); -// inviteRules.forEach(w -> { -// RandomInviteRuleDTO rule = JSON.parseObject(w.getInviteRule(), RandomInviteRuleDTO.class); -// callbackMinutes.put(w.getId(), rule.getWaitForCallbackMinutes()); -// }); -// } -// LambdaQueryWrapper msgRecordDetailQuery = Wrappers.lambdaQuery(SysMsgRecordDetail.class) -// .in(SysMsgRecordDetail::getSubmitKey, submitKeys.values()); -// List recordDetailList = msgRecordDetailService.list(msgRecordDetailQuery); -// if (recordDetailList.isEmpty()) { -// return; -// } -// Map recordDetailMap = recordDetailList.stream() -// .collect(Collectors.toMap(w -> w.getSubmitKey() + StrPool.UNDERSCORE + w.getReceiveNumber(), w -> w)); -// List 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 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 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 experts) { -// /*List meetingIds = CollUtils.fieldList(experts, MeetingExpert::getMeetingId); -// LambdaQueryWrapper mQuery = Wrappers.lambdaQuery(Meeting.class) -// .eq(Meeting::getStatus, Manager.CANCELED.getCode()) -// .in(Meeting::getId, meetingIds); -// Map meetingMap = CollUtils.listToMap(meetingService.list(mQuery), Meeting::getId); -// if (meetingMap.size() > 0) { -// Map> expertList = new HashMap<>(16); -// experts.forEach(w -> { -// Meeting meeting = meetingMap.get(w.getMeetingId()); -// if (meeting == null) { -// return; -// } -// List 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 contexts = YxtSmsContextBuilder.smsToExpertByCancelMeeting(m, mes, meetingType); -// yxtCallOrSmsHelper.sendSms(contexts); -// }); -// } -// }*/ -// } -// -//} +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.common.util.StrUtils; +import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo; +import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService; +import com.ningdatech.pmapi.meeting.entity.config.WebProperties; +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.ExpertAttendStatusEnum; +import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteTypeEnum; +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.constant.VoiceSmsTemplateConst; +import com.ningdatech.pmapi.sms.utils.DateUtil; +import com.ningdatech.yxt.entity.SysMsgRecordDetail; +import com.ningdatech.yxt.model.cmd.SendSmsCmd.SendSmsContext; +import com.ningdatech.yxt.service.ISysMsgRecordDetailService; +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.ExpertAttendStatusEnum.*; + +/** + *

+ * ExpertCallResultRewriteTask + *
+ * 专家电话结果回填 + *

+ * + * @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 userFullInfoService; + + @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 meQuery = Wrappers.lambdaQuery(MeetingExpert.class) + .eq(MeetingExpert::getStatus, NOTICING.getCode()) + .eq(MeetingExpert::getInviteType, ExpertInviteTypeEnum.RANDOM.getCode()); + List experts = meetingExpertService.list(meQuery); + if (experts.isEmpty()) { + log.info("暂无电话结果回填任务执行"); + return; + } + // 所有随机邀请的规则ID + Map submitKeys = new HashMap<>(experts.size()); + Set randomRuleIds = experts.stream().peek(w -> submitKeys.put(w.getId(), w.getSubmitKey())) + .map(MeetingExpert::getRuleId).collect(Collectors.toSet()); + // 查询随机邀请回调等待时间 + Map callbackMinutes = new HashMap<>(randomRuleIds.size()); + if (!randomRuleIds.isEmpty()) { + List inviteRules = inviteRuleService.listByIds(randomRuleIds); + inviteRules.forEach(w -> { + RandomInviteRuleDTO rule = JSON.parseObject(w.getInviteRule(), RandomInviteRuleDTO.class); + callbackMinutes.put(w.getId(), rule.getWaitForCallbackMinutes()); + }); + } + LambdaQueryWrapper msgRecordDetailQuery = Wrappers.lambdaQuery(SysMsgRecordDetail.class) + .in(SysMsgRecordDetail::getSubmitKey, submitKeys.values()); + List recordDetailList = msgRecordDetailService.list(msgRecordDetailQuery); + if (recordDetailList.isEmpty()) { + return; + } + Map recordDetailMap = recordDetailList.stream() + .collect(Collectors.toMap(w -> w.getSubmitKey() + StrPool.UNDERSCORE + w.getReceiveNumber(), w -> w)); + List 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 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.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 = userFullInfoService.getByUserId(expert.getExpertId()); + String expertName = null; + if (Objects.nonNull(expertUserFullInfo)) { + expertName = expertUserFullInfo.getExpertName(); + } + String smsContent = String.format(VoiceSmsTemplateConst.EXPERT_AGREE_ATTEND_TEMPLATE, + meeting.getHoldOrg(), + expertName, + meeting.getName(), + meeting.getStartTime().format(DateUtil.DTF_YMD_HM), + meeting.getMeetingAddress(), + 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 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(); + } + ExpertAttendStatusEnum 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 = UNANSWERED; + } + } catch (Exception e) { + log.error("获取电话回调结果异常", e); + status = UNANSWERED; + } + } else { + // 超时未回复设置为拒绝参加 + status = REFUSED; + } + return Optional.of(status.getCode()); + } + + /** + * 会议取消之后拿到回调结果的话需要发送取消短信 + **/ + private void obtainCallBackAfterMeetingCanceled(List experts) { + /*List meetingIds = CollUtils.fieldList(experts, MeetingExpert::getMeetingId); + LambdaQueryWrapper mQuery = Wrappers.lambdaQuery(Meeting.class) + .eq(Meeting::getStatus, Manager.CANCELED.getCode()) + .in(Meeting::getId, meetingIds); + Map meetingMap = CollUtils.listToMap(meetingService.list(mQuery), Meeting::getId); + if (meetingMap.size() > 0) { + Map> expertList = new HashMap<>(16); + experts.forEach(w -> { + Meeting meeting = meetingMap.get(w.getMeetingId()); + if (meeting == null) { + return; + } + List 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 contexts = YxtSmsContextBuilder.smsToExpertByCancelMeeting(m, mes, meetingType); + yxtCallOrSmsHelper.sendSms(contexts); + }); + } + }*/ + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/organization/service/impl/DingOrganizationServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/organization/service/impl/DingOrganizationServiceImpl.java index 53bf625..90655b4 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/organization/service/impl/DingOrganizationServiceImpl.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/organization/service/impl/DingOrganizationServiceImpl.java @@ -11,7 +11,10 @@ import com.ningdatech.pmapi.organization.model.entity.DingOrganization; import com.ningdatech.pmapi.organization.service.IDingOrganizationService; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -58,7 +61,7 @@ public class DingOrganizationServiceImpl extends ServiceImpl listNameByCodes(Collection codes) { LambdaQueryWrapper query = Wrappers.lambdaQuery(DingOrganization.class) .select(DingOrganization::getOrganizationName) - .eq(DingOrganization::getOrganizationCode, codes); + .in(DingOrganization::getOrganizationCode, codes); return CollUtils.fieldList(list(query), DingOrganization::getOrganizationName); } @@ -76,7 +79,7 @@ public class DingOrganizationServiceImpl extends ServiceImpl dingOrganizationList = listByCodes(orgCodeList); return dingOrganizationList.stream() - .filter(r -> StringUtils.isNotBlank(r.getOrganizationCode()) && Objects.nonNull(r)) - .collect(Collectors.toMap(DingOrganization::getOrganizationCode, r->r)); + .filter(r -> StringUtils.isNotBlank(r.getOrganizationCode())) + .collect(Collectors.toMap(DingOrganization::getOrganizationCode, r -> r)); } } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/VoiceSmsTemplateConst.java b/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/VoiceSmsTemplateConst.java new file mode 100644 index 0000000..0fea8eb --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/VoiceSmsTemplateConst.java @@ -0,0 +1,28 @@ +package com.ningdatech.pmapi.sms.constant; + +/** + *

+ * VoiceSmsTemplateConst + *

+ * + * @author WendyYang + * @since 15:10 2023/3/30 + */ +public interface VoiceSmsTemplateConst { + + /** + * 短信登陆验证码 + */ + String SMS_LOGIN_TEMPLATE = "验证码:%s(有效期为%s分钟),请勿泄露给他人,如非本人操作,请忽略此信息。"; + + /** + * 专家电话通知语音模版 + */ + String OFFLINE_TEMPLATE = "尊敬的专家您好,%s现邀请您作为专家参加%s会议,会议时间:%s,会议地点:%s。 确认参加请按 1,拒绝参加请按 2。请您选择"; + + /** + * 专家同意参加短信通知模板 + */ + String EXPERT_AGREE_ATTEND_TEMPLATE = ""; + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/YxtSmsTemplateConst.java b/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/YxtSmsTemplateConst.java deleted file mode 100644 index 02ad6a5..0000000 --- a/pmapi/src/main/java/com/ningdatech/pmapi/sms/constant/YxtSmsTemplateConst.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ningdatech.pmapi.sms.constant; - -/** - * @author liuxinxin - * @date 2022/8/8 下午5:05 - */ -public interface YxtSmsTemplateConst { - - /** - * 短信登陆验证码 - */ - String SMS_LOGIN_TEMPLATE = "验证码:%s(有效期为%s分钟),请勿泄露给他人,如非本人操作,请忽略此信息。"; -} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/sms/manage/SmsManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/sms/manage/SmsManage.java index 1f3f3fc..e65ce28 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/sms/manage/SmsManage.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/sms/manage/SmsManage.java @@ -6,7 +6,7 @@ import com.ningdatech.basic.exception.BizException; import com.ningdatech.cache.model.cache.CacheKey; import com.ningdatech.cache.repository.CachePlusOps; import com.ningdatech.pmapi.sms.constant.VerificationCodeType; -import com.ningdatech.pmapi.sms.constant.YxtSmsTemplateConst; +import com.ningdatech.pmapi.sms.constant.VoiceSmsTemplateConst; import com.ningdatech.pmapi.sms.model.dto.VerifyCodeCacheDTO; import com.ningdatech.pmapi.sms.model.po.ReqVerificationCodePO; import com.ningdatech.pmapi.sms.utils.DateUtil; @@ -69,7 +69,7 @@ public class SmsManage { case LOGIN: SendSmsCmd.SendSmsContext sendSmsContext = new SendSmsCmd.SendSmsContext(); sendSmsContext.setReceiveNumber(request.getMobile()); - sendSmsContext.setContent(String.format(YxtSmsTemplateConst.SMS_LOGIN_TEMPLATE, code, verificationCodeTypeEnum.getExpireTime())); + sendSmsContext.setContent(String.format(VoiceSmsTemplateConst.SMS_LOGIN_TEMPLATE, code, verificationCodeTypeEnum.getExpireTime())); sendSmsCmd.setContextList(Collections.singletonList(sendSmsContext)); sendSmsCmd.setSmsSignEnum(YxtSmsSignEnum.ZJS_ELECTRONIC_EXPERT_LIB); break;