@@ -0,0 +1,24 @@ | |||||
package com.ningdatech.pmapi.meeting.constant; | |||||
/** | |||||
* <p> | |||||
* MeetingMsgConst | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2023/4/20 | |||||
**/ | |||||
public interface MeetingMsgTemplateConst { | |||||
/** | |||||
* 已结束:自动抽取结束,结束时给会议发起人发送浙政钉工作通知、短信:“注意,xxx会议自动抽取已结束,请及时确认是否召开会议”。 | |||||
*/ | |||||
String INVITE_END = "注意,%s会议自动抽取已结束,请及时确认是否召开会议"; | |||||
/** | |||||
* 尊敬的【姓名】专家您好,您于【确认时间】接受了信息化项目评审会议邀请,会议时间:【会议时间】,会议地点:【会议地点】。请准时参加评审会议。如有疑问请联系【联系人】(【联系方式】)。 | |||||
*/ | |||||
String CONFIRMED_ROSTER = "尊敬的%s专家您好,您于%s接受了信息化项目评审会议邀请,会议时间:%s,会议地点:%s。请准时参加评审会议。如有疑问请联系%s(%s)。"; | |||||
} |
@@ -0,0 +1,147 @@ | |||||
package com.ningdatech.pmapi.meeting.helper; | |||||
import cn.hutool.core.date.DatePattern; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||||
import com.ningdatech.basic.util.CollUtils; | |||||
import com.ningdatech.basic.util.NdDateUtils; | |||||
import com.ningdatech.pmapi.meeting.constant.MeetingMsgTemplateConst; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.Meeting; | |||||
import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert; | |||||
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo; | |||||
import com.ningdatech.pmapi.organization.model.entity.DingOrganization; | |||||
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService; | |||||
import com.ningdatech.pmapi.organization.service.IDingOrganizationService; | |||||
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum; | |||||
import com.ningdatech.pmapi.staging.service.INdWorkNoticeStagingService; | |||||
import com.ningdatech.pmapi.sys.model.entity.Notify; | |||||
import com.ningdatech.pmapi.sys.service.INotifyService; | |||||
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo; | |||||
import com.ningdatech.pmapi.user.entity.UserInfo; | |||||
import com.ningdatech.pmapi.user.service.IUserInfoService; | |||||
import com.ningdatech.yxt.model.cmd.SendSmsCmd.SendSmsContext; | |||||
import lombok.AllArgsConstructor; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.transaction.annotation.Transactional; | |||||
import java.time.LocalDateTime; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* <p> | |||||
* MeetingMsgHelper | |||||
* </p> | |||||
* | |||||
* @author WendyYang | |||||
* @since 2023/4/20 | |||||
**/ | |||||
@Component | |||||
@AllArgsConstructor | |||||
public class MeetingMsgHelper { | |||||
private final IUserInfoService userInfoService; | |||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||||
private final INdWorkNoticeStagingService workNoticeStagingService; | |||||
private final IDingEmployeeInfoService dingEmployeeInfoService; | |||||
private final IDingOrganizationService dingOrganizationService; | |||||
private final INotifyService notifyService; | |||||
private Notify getNotify(Long userId, String msg, Map<String, Object> extraPara) { | |||||
Notify notify = new Notify(); | |||||
notify.setUserId(userId); | |||||
notify.setContent(msg); | |||||
notify.setReaded(Boolean.FALSE); | |||||
notify.setCreateTime(LocalDateTime.now()); | |||||
String extraJson = JSON.toJSONString(extraPara); | |||||
notify.setExtraInfo(extraJson); | |||||
return notify; | |||||
} | |||||
private WorkNoticeInfo getSendWorkNoticeInfo(Long accountId) { | |||||
WorkNoticeInfo workNoticeInfo = new WorkNoticeInfo(); | |||||
workNoticeInfo.setAccountId(accountId); | |||||
// 根据浙政钉用户ID获取部门code | |||||
DingEmployeeInfo employeeInfo = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class) | |||||
.eq(DingEmployeeInfo::getAccountId, accountId) | |||||
.eq(DingEmployeeInfo::getMainJob, String.valueOf(Boolean.TRUE)) | |||||
.last("limit 1")); | |||||
String organizationCode = employeeInfo.getOrganizationCode(); | |||||
workNoticeInfo.setOrganizationCode(organizationCode); | |||||
// 根据部门code获取部门名称 | |||||
DingOrganization dingOrganization = dingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class) | |||||
.eq(DingOrganization::getOrganizationCode, organizationCode)); | |||||
String organizationName = dingOrganization.getOrganizationName(); | |||||
workNoticeInfo.setOrganizationName(organizationName); | |||||
// 构建唯一的消息ID | |||||
String bizMsgId = "ZD_WORK_NOTICE_" + StrUtil.UNDERLINE + organizationCode + StrUtil.UNDERLINE | |||||
+ organizationName + accountId + StrUtil.UNDERLINE + System.currentTimeMillis(); | |||||
workNoticeInfo.setBizMsgId(bizMsgId); | |||||
String receiverUserId = String.valueOf(accountId); | |||||
workNoticeInfo.setReceiverUserId(receiverUserId); | |||||
return workNoticeInfo; | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void sendInviteStopMsg(Long userId, Long meetingId, String meetingName) { | |||||
UserInfo info = userInfoService.getById(userId); | |||||
String msgContent = String.format(MeetingMsgTemplateConst.INVITE_END, meetingName); | |||||
// 音信通消息 | |||||
SendSmsContext yxtContent = new SendSmsContext(); | |||||
yxtContent.setContent(msgContent); | |||||
yxtContent.setReceiveNumber(info.getMobile()); | |||||
yxtCallOrSmsHelper.sendSms(yxtContent); | |||||
// 发送工作通知 | |||||
if (info.getAccountId() != null) { | |||||
WorkNoticeInfo swn = getSendWorkNoticeInfo(info.getAccountId()); | |||||
swn.setMsg(msgContent); | |||||
workNoticeStagingService.addByWorkNotice(swn, MsgTypeEnum.REVIEW_MEETING); | |||||
Map<String, Object> map = new HashMap<>(); | |||||
map.put("meetingId", meetingId); | |||||
Notify notify = getNotify(userId, msgContent, map); | |||||
notifyService.save(notify); | |||||
} | |||||
} | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public void sendConfirmedRosterMsg(List<MeetingExpert> experts, Meeting meeting) { | |||||
List<Long> userIds = CollUtils.fieldList(experts, MeetingExpert::getExpertId); | |||||
List<UserInfo> userInfos = userInfoService.listByIds(userIds); | |||||
Map<Long, UserInfo> userMap = CollUtils.listToMap(userInfos, UserInfo::getId); | |||||
String sTime = meeting.getStartTime().format(DatePattern.NORM_DATETIME_MINUTE_FORMATTER); | |||||
String eTime = meeting.getEndTime().format(DatePattern.NORM_DATETIME_MINUTE_FORMATTER); | |||||
String meetingTime = sTime + " - " + eTime; | |||||
List<SendSmsContext> yxtContents = new ArrayList<>(); | |||||
List<Notify> notifies = new ArrayList<>(); | |||||
List<WorkNoticeInfo> workingNotices = new ArrayList<>(); | |||||
experts.forEach(w -> { | |||||
String msgContent = String.format(MeetingMsgTemplateConst.CONFIRMED_ROSTER, | |||||
w.getExpertName(), w.getCreateOn(), meetingTime, meeting.getMeetingAddress(), | |||||
meeting.getConnecter(), meeting.getContact()); | |||||
// 音信通消息 | |||||
SendSmsContext yxtContent = new SendSmsContext(); | |||||
yxtContent.setContent(msgContent); | |||||
yxtContent.setReceiveNumber(w.getMobile()); | |||||
yxtContents.add(yxtContent); | |||||
UserInfo info = userMap.get(w.getExpertId()); | |||||
// 发送工作通知 | |||||
if (info.getAccountId() != null) { | |||||
WorkNoticeInfo swn = getSendWorkNoticeInfo(info.getAccountId()); | |||||
swn.setMsg(msgContent); | |||||
workingNotices.add(swn); | |||||
Map<String, Object> map = new HashMap<>(); | |||||
map.put("meetingId", meeting.getId()); | |||||
Notify notify = getNotify(info.getId(), msgContent, map); | |||||
notifies.add(notify); | |||||
} | |||||
}); | |||||
notifyService.saveBatch(notifies); | |||||
yxtCallOrSmsHelper.sendSms(yxtContents); | |||||
workNoticeStagingService.addByWorkNotice(workingNotices, MsgTypeEnum.EXPERT_REVIEW); | |||||
} | |||||
} |
@@ -36,6 +36,7 @@ import com.ningdatech.pmapi.meeting.entity.req.*; | |||||
import com.ningdatech.pmapi.meeting.entity.vo.*; | import com.ningdatech.pmapi.meeting.entity.vo.*; | ||||
import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper; | ||||
import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper; | import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper; | ||||
import com.ningdatech.pmapi.meeting.helper.MeetingMsgHelper; | |||||
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | ||||
import com.ningdatech.pmapi.meeting.service.*; | import com.ningdatech.pmapi.meeting.service.*; | ||||
import com.ningdatech.pmapi.meeting.task.ExpertInviteTask; | import com.ningdatech.pmapi.meeting.task.ExpertInviteTask; | ||||
@@ -96,6 +97,7 @@ public class MeetingManage { | |||||
private final IDingOrganizationService dingOrganizationService; | private final IDingOrganizationService dingOrganizationService; | ||||
private final IExpertReviewService expertReviewService; | private final IExpertReviewService expertReviewService; | ||||
private final ExpertInviteHelper expertInviteHelper; | private final ExpertInviteHelper expertInviteHelper; | ||||
private final MeetingMsgHelper meetingMsgHelper; | |||||
private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; | private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; | ||||
private static final String MEETING_CREATE_KEY = "MEETING_CREATE:"; | private static final String MEETING_CREATE_KEY = "MEETING_CREATE:"; | ||||
@@ -826,7 +828,7 @@ public class MeetingManage { | |||||
.in(MeetingExpert::getId, currConfirmedMeIds) | .in(MeetingExpert::getId, currConfirmedMeIds) | ||||
.set(MeetingExpert::getConfirmedRoster, Boolean.TRUE); | .set(MeetingExpert::getConfirmedRoster, Boolean.TRUE); | ||||
meetingExpertService.update(meUpdate); | meetingExpertService.update(meUpdate); | ||||
// TODO 发送会议通知 | |||||
meetingMsgHelper.sendConfirmedRosterMsg(expertNoticing, meeting); | |||||
} finally { | } finally { | ||||
distributedLock.releaseLock(key); | distributedLock.releaseLock(key); | ||||
} | } | ||||
@@ -16,6 +16,7 @@ import com.ningdatech.pmapi.meeting.entity.dto.ExpertChooseDTO; | |||||
import com.ningdatech.pmapi.meeting.entity.dto.InviteCacheDTO; | import com.ningdatech.pmapi.meeting.entity.dto.InviteCacheDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO; | ||||
import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum; | ||||
import com.ningdatech.pmapi.meeting.helper.MeetingMsgHelper; | |||||
import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper; | ||||
import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage; | import com.ningdatech.pmapi.meeting.manage.ExpertInviteManage; | ||||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | ||||
@@ -74,6 +75,7 @@ public class ExpertInviteTask { | |||||
private final ExpertInviteManage expertInviteManage; | private final ExpertInviteManage expertInviteManage; | ||||
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | ||||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | ||||
private final MeetingMsgHelper meetingMsgHelper; | |||||
/** | /** | ||||
* 用来存入线程执行句柄, 停止定时任务时使用 | * 用来存入线程执行句柄, 停止定时任务时使用 | ||||
@@ -273,6 +275,7 @@ public class ExpertInviteTask { | |||||
if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) { | if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) { | ||||
log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt); | log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt); | ||||
currProxy().cancelByMeetingId(meetingId); | currProxy().cancelByMeetingId(meetingId); | ||||
meetingMsgHelper.sendInviteStopMsg(meeting.getCreateBy(), meetingId, meeting.getName()); | |||||
} | } | ||||
} | } | ||||
@@ -7,9 +7,11 @@ import com.ningdatech.pmapi.staging.model.entity.WorkNoticeStaging; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||
import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo; | import com.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo; | ||||
import java.util.List; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* 服务类 | |||||
* 服务类 | |||||
* </p> | * </p> | ||||
* | * | ||||
* @author CMM | * @author CMM | ||||
@@ -19,5 +21,15 @@ public interface INdWorkNoticeStagingService extends IService<WorkNoticeStaging> | |||||
Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging); | Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging); | ||||
public Boolean addByWorkNotice(WorkNoticeInfo workNoticeInfo, MsgTypeEnum msgType) ; | |||||
Boolean addByWorkNotice(WorkNoticeInfo workNoticeInfo, MsgTypeEnum msgType); | |||||
/** | |||||
* 批量保存工作通知 | |||||
* | |||||
* @param workNoticeInfos 工作通知内容 | |||||
* @param msgType 通知类型 | |||||
* @return 是否保存成功 | |||||
*/ | |||||
Boolean addByWorkNotice(List<WorkNoticeInfo> workNoticeInfos, MsgTypeEnum msgType); | |||||
} | } |
@@ -13,10 +13,12 @@ import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||
import java.util.List; | |||||
import java.util.stream.Collectors; | |||||
/** | /** | ||||
* <p> | * <p> | ||||
* 服务实现类 | |||||
* 服务实现类 | |||||
* </p> | * </p> | ||||
* | * | ||||
* @author CMM | * @author CMM | ||||
@@ -33,6 +35,7 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||||
/** | /** | ||||
* 增加 重试次数 和下次扫描时间 | * 增加 重试次数 和下次扫描时间 | ||||
* | |||||
* @param workNoticeStaging | * @param workNoticeStaging | ||||
* @return java.lang.Boolean | * @return java.lang.Boolean | ||||
* @author CMM | * @author CMM | ||||
@@ -41,22 +44,23 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||||
@Override | @Override | ||||
public Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging) { | public Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging) { | ||||
Integer retryTimes = workNoticeStaging.getRetryTimes() + 1; | Integer retryTimes = workNoticeStaging.getRetryTimes() + 1; | ||||
if(!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){ | |||||
if (!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)) { | |||||
log.info("没有对应重试间隔时间 添加重试信息失败"); | log.info("没有对应重试间隔时间 添加重试信息失败"); | ||||
return Boolean.FALSE; | return Boolean.FALSE; | ||||
} | } | ||||
Integer addSeconds = workNoticeFlowMapUtil.intervalTimeMap.get(retryTimes); | Integer addSeconds = workNoticeFlowMapUtil.intervalTimeMap.get(retryTimes); | ||||
Boolean dead = Boolean.FALSE; | Boolean dead = Boolean.FALSE; | ||||
//超过重试最大次数 dead置为 true | //超过重试最大次数 dead置为 true | ||||
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){ | |||||
if (retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0) { | |||||
dead = Boolean.TRUE; | dead = Boolean.TRUE; | ||||
} | } | ||||
LocalDateTime nextRetryTime = LocalDateTime.now().plusSeconds(addSeconds); | LocalDateTime nextRetryTime = LocalDateTime.now().plusSeconds(addSeconds); | ||||
return mapper.addRetryTimes(workNoticeStaging.getId(),retryTimes,nextRetryTime,dead); | |||||
return mapper.addRetryTimes(workNoticeStaging.getId(), retryTimes, nextRetryTime, dead); | |||||
} | } | ||||
/** | /** | ||||
* 在对应的流程处理后,增加一个工作通知到暂存表中 | * 在对应的流程处理后,增加一个工作通知到暂存表中 | ||||
* | |||||
* @param workNoticeInfo | * @param workNoticeInfo | ||||
* @param msgType | * @param msgType | ||||
* @return java.lang.Boolean | * @return java.lang.Boolean | ||||
@@ -80,4 +84,33 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||||
.build(); | .build(); | ||||
return this.save(workNoticeStaging); | return this.save(workNoticeStaging); | ||||
} | } | ||||
/** | |||||
* 在对应的流程处理后,增加一个工作通知到暂存表中 | |||||
* | |||||
* @param workNoticeInfo | |||||
* @param msgType | |||||
* @return java.lang.Boolean | |||||
* @author CMM | |||||
* @since 2023/02/28 20:02 | |||||
*/ | |||||
@Override | |||||
public Boolean addByWorkNotice(List<WorkNoticeInfo> workNoticeInfos, MsgTypeEnum msgType) { | |||||
List<WorkNoticeStaging> workNoticeInfoList = workNoticeInfos.stream() | |||||
.map(workNoticeInfo -> WorkNoticeStaging.builder() | |||||
.accountId(workNoticeInfo.getAccountId()) | |||||
.msg(workNoticeInfo.getMsg()) | |||||
.bizMsgId(workNoticeInfo.getBizMsgId()) | |||||
.organizationCode(workNoticeInfo.getOrganizationCode()) | |||||
.organizationName(workNoticeInfo.getOrganizationName()) | |||||
.receiverUserId(workNoticeInfo.getReceiverUserId()) | |||||
.msgType(msgType) | |||||
.createOn(LocalDateTime.now()) | |||||
.updateOn(LocalDateTime.now()) | |||||
.nextTime(LocalDateTime.now()) | |||||
.retryTimes(0) | |||||
.build()).collect(Collectors.toList()); | |||||
return saveBatch(workNoticeInfoList); | |||||
} | |||||
} | } |