@@ -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.helper.ExpertInviteHelper; | |||
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.service.*; | |||
import com.ningdatech.pmapi.meeting.task.ExpertInviteTask; | |||
@@ -96,6 +97,7 @@ public class MeetingManage { | |||
private final IDingOrganizationService dingOrganizationService; | |||
private final IExpertReviewService expertReviewService; | |||
private final ExpertInviteHelper expertInviteHelper; | |||
private final MeetingMsgHelper meetingMsgHelper; | |||
private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; | |||
private static final String MEETING_CREATE_KEY = "MEETING_CREATE:"; | |||
@@ -826,7 +828,7 @@ public class MeetingManage { | |||
.in(MeetingExpert::getId, currConfirmedMeIds) | |||
.set(MeetingExpert::getConfirmedRoster, Boolean.TRUE); | |||
meetingExpertService.update(meUpdate); | |||
// TODO 发送会议通知 | |||
meetingMsgHelper.sendConfirmedRosterMsg(expertNoticing, meeting); | |||
} finally { | |||
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.RandomInviteRuleDTO; | |||
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.manage.ExpertInviteManage; | |||
import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService; | |||
@@ -74,6 +75,7 @@ public class ExpertInviteTask { | |||
private final ExpertInviteManage expertInviteManage; | |||
private final IExpertInviteAvoidRuleService inviteAvoidRuleService; | |||
private final YxtCallOrSmsHelper yxtCallOrSmsHelper; | |||
private final MeetingMsgHelper meetingMsgHelper; | |||
/** | |||
* 用来存入线程执行句柄, 停止定时任务时使用 | |||
@@ -273,6 +275,7 @@ public class ExpertInviteTask { | |||
if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) { | |||
log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt); | |||
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.ningdatech.pmapi.todocenter.bean.entity.WorkNoticeInfo; | |||
import java.util.List; | |||
/** | |||
* <p> | |||
* 服务类 | |||
* 服务类 | |||
* </p> | |||
* | |||
* @author CMM | |||
@@ -19,5 +21,15 @@ public interface INdWorkNoticeStagingService extends IService<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 java.time.LocalDateTime; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
/** | |||
* <p> | |||
* 服务实现类 | |||
* 服务实现类 | |||
* </p> | |||
* | |||
* @author CMM | |||
@@ -33,6 +35,7 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||
/** | |||
* 增加 重试次数 和下次扫描时间 | |||
* | |||
* @param workNoticeStaging | |||
* @return java.lang.Boolean | |||
* @author CMM | |||
@@ -41,22 +44,23 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||
@Override | |||
public Boolean addRetryTimes(WorkNoticeStaging workNoticeStaging) { | |||
Integer retryTimes = workNoticeStaging.getRetryTimes() + 1; | |||
if(!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)){ | |||
if (!workNoticeFlowMapUtil.intervalTimeMap.containsKey(retryTimes)) { | |||
log.info("没有对应重试间隔时间 添加重试信息失败"); | |||
return Boolean.FALSE; | |||
} | |||
Integer addSeconds = workNoticeFlowMapUtil.intervalTimeMap.get(retryTimes); | |||
Boolean dead = Boolean.FALSE; | |||
//超过重试最大次数 dead置为 true | |||
if(retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0){ | |||
if (retryTimes.compareTo(StagingContant.Retry.MAX_RETRY_TIMES) > 0) { | |||
dead = Boolean.TRUE; | |||
} | |||
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 msgType | |||
* @return java.lang.Boolean | |||
@@ -80,4 +84,33 @@ public class NdWorkNoticeStagingServiceImpl extends ServiceImpl<NdWorkNoticeStag | |||
.build(); | |||
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); | |||
} | |||
} |