@@ -9,6 +9,7 @@ import cn.hutool.json.JSONUtil; | |||
import com.hz.pm.api.common.util.EnvironmentUtil; | |||
import com.hz.pm.api.external.model.dto.*; | |||
import com.hz.pm.api.external.model.enumeration.MhDictType; | |||
import com.hz.pm.api.open.model.vo.MeetingExpertInfoVO; | |||
import com.ningdatech.basic.exception.BizException; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -56,6 +57,7 @@ public class MhApiClient { | |||
private static final String PURCHASE_NOTICE = "/buy_notice/saveBuyNoticeList"; | |||
private static final String PURCHASE_NOTICE_GET = "/buy_notice/getBuyIdeaList"; | |||
private static final String PUSH_MEETING_EXPERTS_DATA = "/meeting/saveData"; | |||
/** | |||
* 信创符合性测评报告相关接口 | |||
@@ -189,4 +191,18 @@ public class MhApiClient { | |||
throw BizException.wrap("获取测评报告失败"); | |||
} | |||
public void pushMeetingAndExpertsDataToMh(MeetingExpertInfoVO data) { | |||
if (environmentUtil.isDevEnv()) { | |||
return; | |||
} | |||
String requestUrl = mhApiHost + PUSH_MEETING_EXPERTS_DATA; | |||
String retBody = HttpUtil.post(requestUrl, JSONUtil.toJsonStr(data)); | |||
MhRetDTO<Object> retObj = JSONUtil.toBean(retBody, | |||
new TypeReference<MhRetDTO<Object>>() { | |||
}, false); | |||
if (!retObj.isOk()) { | |||
log.error("会议专家信息推送失败:{}", retBody); | |||
throw BizException.wrap("会议专家信息推送失败"); | |||
} | |||
} | |||
} |
@@ -1,5 +1,6 @@ | |||
package com.hz.pm.api.meeting.entity.dto; | |||
import io.swagger.annotations.ApiModelProperty; | |||
import lombok.Data; | |||
import java.time.LocalDateTime; | |||
@@ -27,4 +28,16 @@ public class ExpertInvitedRecordDTO { | |||
private LocalDateTime createOn; | |||
/** | |||
* 20240513 新增字段 | |||
*/ | |||
@ApiModelProperty("专家签到状态") | |||
private Boolean signStatus; | |||
@ApiModelProperty("专家签到时间") | |||
private LocalDateTime signTime; | |||
@ApiModelProperty("专家签到地点") | |||
private String signAddress; | |||
} |
@@ -50,4 +50,18 @@ public class InviteExpertListItemVO extends ExpertBasicInfoVO { | |||
@ApiModelProperty("通知时间") | |||
private LocalDateTime noticeTime; | |||
/** | |||
* 20240511 新增字段 | |||
*/ | |||
@ApiModelProperty("专家签到状态") | |||
private Boolean signStatus; | |||
@ApiModelProperty("专家签到时间") | |||
private LocalDateTime signTime; | |||
@ApiModelProperty("专家签到地点") | |||
private String signAddress; | |||
} |
@@ -87,4 +87,16 @@ public class MeetingByManagerVO { | |||
@ApiModelProperty("所有项目是否已上传评审结果") | |||
private Boolean allProjectReviewed; | |||
/** | |||
* 20240513 新增字段 | |||
*/ | |||
@ApiModelProperty("专家签到状态") | |||
private Boolean signStatus; | |||
@ApiModelProperty("专家签到时间") | |||
private LocalDateTime signTime; | |||
@ApiModelProperty("专家签到地点") | |||
private String signAddress; | |||
} |
@@ -2,6 +2,8 @@ package com.hz.pm.api.meeting.manage; | |||
import cn.hutool.core.bean.BeanUtil; | |||
import cn.hutool.core.collection.CollUtil; | |||
import cn.hutool.core.map.MapUtil; | |||
import cn.hutool.core.util.ObjUtil; | |||
import cn.hutool.core.util.ObjectUtil; | |||
import cn.hutool.core.util.StrUtil; | |||
import cn.hutool.crypto.SecureUtil; | |||
@@ -12,10 +14,12 @@ 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.google.common.collect.Sets; | |||
import com.hz.pm.api.common.helper.RegionCacheHelper; | |||
import com.hz.pm.api.common.model.constant.BizConst; | |||
import com.hz.pm.api.expert.entity.ExpertUserFullInfo; | |||
import com.hz.pm.api.expert.service.IExpertUserFullInfoService; | |||
import com.hz.pm.api.external.MhApiClient; | |||
import com.hz.pm.api.gov.service.IBelongOrgService; | |||
import com.hz.pm.api.meeting.builder.ExpertInviteBuilder; | |||
import com.hz.pm.api.meeting.builder.MeetingReviewProjectBuilder; | |||
@@ -35,12 +39,17 @@ import com.hz.pm.api.meeting.service.*; | |||
import com.hz.pm.api.meeting.task.ExpertRandomInviteTask; | |||
import com.hz.pm.api.meta.helper.DictionaryCache; | |||
import com.hz.pm.api.meta.helper.TagCache; | |||
import com.hz.pm.api.open.model.vo.ExpertInfoVO; | |||
import com.hz.pm.api.open.model.vo.MeetingExpertInfoVO; | |||
import com.hz.pm.api.organization.service.IDingOrganizationService; | |||
import com.hz.pm.api.projectlib.model.entity.Project; | |||
import com.hz.pm.api.projectlib.model.enumeration.status.ProjectStatus; | |||
import com.hz.pm.api.projectlib.service.IProjectService; | |||
import com.hz.pm.api.sys.model.dto.RegionDTO; | |||
import com.hz.pm.api.user.model.entity.UserInfo; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.hz.pm.api.user.security.model.UserInfoDetails; | |||
import com.hz.pm.api.user.service.IUserInfoService; | |||
import com.hz.pm.api.user.util.LoginUserUtil; | |||
import com.ningdatech.basic.exception.BizException; | |||
import com.ningdatech.basic.model.IdVo; | |||
@@ -94,6 +103,8 @@ public class MeetingManage { | |||
private final MeetingNotifyHelper meetingNotifyHelper; | |||
private final IMeetingExpertJudgeService expertJudgeService; | |||
private final IMeetingExpertJudgeService meetingExpertJudgeService; | |||
private final MhApiClient mhApiClient; | |||
private final IUserInfoService userInfoService; | |||
private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:"; | |||
@@ -347,6 +358,9 @@ public class MeetingManage { | |||
if (judge != null) { | |||
item.setJudgeScore(judge.getScore()); | |||
} | |||
item.setSignStatus(info.getSignStatus()); | |||
item.setSignTime(info.getSignTime()); | |||
item.setSignAddress(info.getSignAddress()); | |||
result.getRecords().add(item); | |||
}); | |||
return result; | |||
@@ -509,6 +523,9 @@ public class MeetingManage { | |||
ExpertInviteRule rule = ruleMap.get(me.getRuleId()); | |||
item.setInviteType(rule == null ? APPOINT.getCode() : rule.getInviteType()); | |||
item.setNoticeStatus(NOTICING.eq(me.getStatus()) ? "通知中" : "已通知"); | |||
item.setSignStatus(me.getSignStatus()); | |||
item.setSignTime(me.getSignTime()); | |||
item.setSignAddress(me.getSignAddress()); | |||
return item; | |||
}; | |||
List<ExpertInviteRule> inviteRules = inviteRuleService.listByMeetingId(meetingId); | |||
@@ -827,14 +844,17 @@ public class MeetingManage { | |||
if (!MeetingStatusEnum.NORMAL.eq(meeting.getStatus())) { | |||
throw BizException.wrap("请刷新后重试!"); | |||
} | |||
List<MeetingExpert> experts = meetingExpertService.listAgreedExperts(meetingId); | |||
if (!meeting.getConfirmedRoster()) { | |||
// 首次确认的 | |||
LambdaUpdateWrapper<Meeting> update = Wrappers.lambdaUpdate(Meeting.class); | |||
update.set(Meeting::getConfirmedRoster, Boolean.TRUE); | |||
update.eq(Meeting::getId, meetingId); | |||
meetingService.update(update); | |||
// 将已确认专家名单的当前会议信息和专家数据同步到信创 | |||
MeetingExpertInfoVO data = getMeetingExpertInfoVO(meeting, experts); | |||
mhApiClient.pushMeetingAndExpertsDataToMh(data); | |||
} | |||
List<MeetingExpert> experts = meetingExpertService.listAgreedExperts(meetingId); | |||
List<MeetingExpert> expertNoticing = experts.stream() | |||
.filter(w -> meeting.getConfirmedRoster() || !w.getConfirmedRoster()) | |||
.collect(Collectors.toList()); | |||
@@ -850,6 +870,47 @@ public class MeetingManage { | |||
} finally { | |||
distributedLock.releaseLock(key); | |||
} | |||
} | |||
private MeetingExpertInfoVO getMeetingExpertInfoVO(Meeting meeting, List<MeetingExpert> experts) { | |||
MeetingExpertInfoVO data = new MeetingExpertInfoVO(); | |||
data.setMeetingId(meeting.getId()); | |||
data.setStartTime(meeting.getStartTime()); | |||
data.setEndTime(meeting.getEndTime()); | |||
data.setMeetingName(meeting.getName()); | |||
data.setMeetingAddress(meeting.getMeetingAddress()); | |||
data.setConnecter(meeting.getConnecter()); | |||
data.setContact(meeting.getContact()); | |||
// 获取未签到的专家信息 | |||
List<MeetingExpert> expertList = experts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList()); | |||
Set<Long> userIds = expertList.stream().map(MeetingExpert::getExpertId).collect(Collectors.toSet()); | |||
List<UserInfo> userInfoList = userInfoService.list(Wrappers.lambdaQuery(UserInfo.class).in(UserInfo::getId, userIds)); | |||
Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, v -> v)); | |||
List<Long> userIdList = new ArrayList<>(userIds); | |||
List<ExpertUserFullInfo> expertUserFullInfos = expertUserFullInfoService.listByUserIds(userIdList); | |||
Map<Long, ExpertUserFullInfo> userFullInfoMap = MapUtil.newHashMap(); | |||
if(CollUtil.isNotEmpty(expertUserFullInfos)){ | |||
userFullInfoMap = expertUserFullInfos.stream().collect(Collectors.toMap(ExpertUserFullInfo::getUserId, v -> v)); | |||
} | |||
Map<Long, ExpertUserFullInfo> finalUserFullInfoMap = userFullInfoMap; | |||
data.setExpertInfoList(CollUtils.fieldList(experts, w -> { | |||
ExpertInfoVO expertInfoVO = new ExpertInfoVO(); | |||
expertInfoVO.setUserId(w.getExpertId()); | |||
expertInfoVO.setName(w.getExpertName()); | |||
expertInfoVO.setPhoneNo(w.getMobile()); | |||
ExpertUserFullInfo expertUserFullInfo = finalUserFullInfoMap.get(w.getExpertId()); | |||
if (Objects.nonNull(expertUserFullInfo)) { | |||
expertInfoVO.setMhExpertId(expertUserFullInfo.getMhExpertId()); | |||
} | |||
UserInfo userInfo = userInfoMap.get(w.getExpertId()); | |||
if (Objects.nonNull(userInfo)) { | |||
expertInfoVO.setMhUnitId(userInfo.getMhUnitId()); | |||
expertInfoVO.setMhUnitName(userInfo.getMhUnitName()); | |||
} | |||
return expertInfoVO; | |||
})); | |||
return data; | |||
} | |||
public PageVo<ReviewProjectDTO> pageReviewProject(ReviewProjectListReq req) { | |||
@@ -4,9 +4,10 @@ | |||
<select id="selectByExpertIdAndStatus" | |||
resultType="com.hz.pm.api.meeting.entity.dto.ExpertInvitedRecordDTO"> | |||
SELECT em.meeting_id meetingId, em.status, em.ID meetingExpertId | |||
SELECT em.meeting_id meetingId, em.status, em.ID meetingExpertId, | |||
em.sign_status signStatus,em.sign_time signTime, em.sign_address signAddress | |||
FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY meeting_id ORDER BY update_on DESC ) rowNumber, ID, expert_id, | |||
status, meeting_id | |||
status, meeting_id,sign_status, sign_time, sign_address | |||
FROM meeting_expert | |||
where expert_id = #{expertId} | |||
<if test="meetingIds != null and meetingIds.size > 0"> | |||
@@ -5,6 +5,7 @@ import java.util.List; | |||
import javax.validation.Valid; | |||
import com.hz.pm.api.open.model.po.ReqMeetingExpertSignPO; | |||
import org.springframework.validation.annotation.Validated; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import org.springframework.web.bind.annotation.RequestBody; | |||
@@ -38,8 +39,13 @@ public class OpenApiMeetingExpertInfoController { | |||
@PostMapping("/list") | |||
@ApiOperation("获取已抽取完成会议确定参加会议且未签到的专家信息列表") | |||
@WebLog | |||
public List<MeetingExpertInfoVO> infoList(@Valid @RequestBody ReqMeetingExpertInfoPO po) { | |||
return openMeetingExpertInfoManage.infoList(po); | |||
} | |||
@PostMapping("/sign") | |||
@ApiOperation("获取已抽取完成会议确定参加会议且未签到的专家信息列表") | |||
public String sign(@Valid @RequestBody ReqMeetingExpertSignPO po) { | |||
return openMeetingExpertInfoManage.sign(po); | |||
} | |||
} |
@@ -2,13 +2,23 @@ package com.hz.pm.api.open.manage; | |||
import java.security.MessageDigest; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.time.LocalDateTime; | |||
import java.util.*; | |||
import java.util.stream.Collectors; | |||
import cn.hutool.core.map.MapUtil; | |||
import com.hz.pm.api.expert.entity.ExpertUserFullInfo; | |||
import com.hz.pm.api.expert.model.dto.DictionaryVO; | |||
import com.hz.pm.api.expert.service.IExpertUserFullInfoService; | |||
import com.hz.pm.api.meeting.entity.enumeration.ExpertAttendStatusEnum; | |||
import com.hz.pm.api.meeting.entity.enumeration.ExpertInviteTypeEnum; | |||
import com.hz.pm.api.meeting.entity.enumeration.MeetingStatusByDashboard; | |||
import com.hz.pm.api.meeting.entity.enumeration.MeetingStatusEnum; | |||
import com.hz.pm.api.meta.model.dto.DictionaryDTO; | |||
import com.hz.pm.api.open.model.po.ReqMeetingExpertSignPO; | |||
import com.hz.pm.api.user.model.entity.UserInfo; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.ningdatech.basic.function.VUtils; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.stereotype.Component; | |||
@@ -53,23 +63,27 @@ public class OpenApiMeetingExpertInfoManage { | |||
private final IUserInfoService userInfoService; | |||
private final IExpertDictionaryService iExpertDictionaryService; | |||
private final DictionaryCache dictionaryCache; | |||
private final IExpertUserFullInfoService expertUserFullInfoService; | |||
public List<MeetingExpertInfoVO> infoList(ReqMeetingExpertInfoPO po) { | |||
String key = po.getKey(); | |||
// 校验传入的签名 | |||
if (!checkSign(key)){ | |||
throw new BizException("签名错误!"); | |||
} | |||
// 获取已经抽取完成 确认参加会议并且未签到的专家信息 | |||
// 获取已经抽取(指定)完成 确认参加会议并且未签到的专家信息 | |||
List<Meeting> meetingList = meetingService.list(Wrappers.lambdaQuery(Meeting.class) | |||
.eq(Meeting::getConfirmedRoster, true)); | |||
.eq(Meeting::getConfirmedRoster, Boolean.TRUE) | |||
.ne(Meeting::getStatus, MeetingStatusEnum.CANCELED.getCode())); | |||
if(CollUtil.isEmpty(meetingList)){ | |||
return Collections.emptyList(); | |||
} | |||
List<MeetingExpertInfoVO> result = Lists.newArrayList(); | |||
// 获取已抽取完成会议中未签到的专家信息 | |||
// 获取已抽取完成会议中同意参加但未签到的专家信息 | |||
List<Long> meetingIds = meetingList.stream().map(Meeting::getId).collect(Collectors.toList()); | |||
Map<Long, List<MeetingExpert>> meetingExpertMap = meetingExpertService.list(Wrappers.lambdaQuery(MeetingExpert.class) | |||
.in(MeetingExpert::getMeetingId, meetingIds) | |||
.eq(MeetingExpert::getConfirmedRoster, Boolean.TRUE) | |||
.eq(MeetingExpert::getStatus, ExpertAttendStatusEnum.AGREED.getCode()) | |||
.eq(MeetingExpert::getSignStatus, Boolean.FALSE)) | |||
.stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId)); | |||
Map<Long, Meeting> meetingMap = CollUtils.listToMap(meetingList, Meeting::getId); | |||
@@ -83,6 +97,12 @@ public class OpenApiMeetingExpertInfoManage { | |||
List<MeetingExpert> expertList = experts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList()); | |||
Set<Long> userIds = expertList.stream().map(MeetingExpert::getExpertId).collect(Collectors.toSet()); | |||
List<UserInfo> userInfoList = userInfoService.list(Wrappers.lambdaQuery(UserInfo.class).in(UserInfo::getId, userIds)); | |||
List<Long> userIdList = new ArrayList<>(userIds); | |||
List<ExpertUserFullInfo> expertUserFullInfos = expertUserFullInfoService.listByUserIds(userIdList); | |||
Map<Long, ExpertUserFullInfo> userFullInfoMap = MapUtil.newHashMap(); | |||
if(CollUtil.isNotEmpty(expertUserFullInfos)){ | |||
userFullInfoMap = expertUserFullInfos.stream().collect(Collectors.toMap(ExpertUserFullInfo::getUserId, v -> v)); | |||
} | |||
Set<String> employeeSet = Sets.newHashSet(); | |||
userInfoList = userInfoList.stream().filter(u -> employeeSet.add(u.getEmployeeCode())).collect(Collectors.toList()); | |||
List<UserFullInfoDTO> userFullInfos = userInfoHelper.getUserFullInfos(userInfoList); | |||
@@ -113,6 +133,7 @@ public class OpenApiMeetingExpertInfoManage { | |||
// 获取未签到的专家信息 | |||
List<MeetingExpert> expertUserList = meetingExperts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList()); | |||
if (CollUtil.isNotEmpty(expertUserList)){ | |||
Map<Long, ExpertUserFullInfo> finalUserFullInfoMap = userFullInfoMap; | |||
List<ExpertInfoVO> expertInfoVOList = expertUserList.stream().map(m -> { | |||
ExpertInfoVO expertInfoVO = new ExpertInfoVO(); | |||
expertInfoVO.setUserId(m.getExpertId()); | |||
@@ -123,6 +144,10 @@ public class OpenApiMeetingExpertInfoManage { | |||
expertInfoVO.setMhUnitId(userFullInfoDTO.getMhUnitId()); | |||
expertInfoVO.setMhUnitName(userFullInfoDTO.getMhUnitName()); | |||
} | |||
ExpertUserFullInfo expertUserFullInfo = finalUserFullInfoMap.get(m.getExpertId()); | |||
if (Objects.nonNull(expertUserFullInfo)){ | |||
expertInfoVO.setExpertId(expertUserFullInfo.getId()); | |||
} | |||
List<ExpertDictionary> dictionaries = dictMap.get(m.getExpertId()); | |||
if (CollUtil.isNotEmpty(dictionaries)){ | |||
List<DictionaryVO> dictionaryFieldInfos = dictionaries.stream().map(r -> { | |||
@@ -181,4 +206,27 @@ public class OpenApiMeetingExpertInfoManage { | |||
} | |||
return sb.toString(); | |||
} | |||
public String sign(ReqMeetingExpertSignPO po) { | |||
String key = po.getKey(); | |||
// 校验传入的签名 | |||
if (!checkSign(key)){ | |||
throw new BizException("签名错误!"); | |||
} | |||
Long meetingId = po.getMeetingId(); | |||
Long userId = po.getUserId(); | |||
LocalDateTime signTime = po.getSignTime(); | |||
String signAddress = po.getSignAddress(); | |||
// 获取会议专家信息 | |||
MeetingExpert meetingExpert = meetingExpertService.getByMeetingIdAndExpertId(meetingId, userId); | |||
// 更新专家签到信息 | |||
if (Objects.nonNull(meetingExpert)){ | |||
meetingExpert.setSignStatus(true); | |||
meetingExpert.setSignTime(signTime); | |||
meetingExpert.setSignAddress(signAddress); | |||
meetingExpertService.updateById(meetingExpert); | |||
return "success"; | |||
} | |||
return "fail"; | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
package com.hz.pm.api.open.model.po; | |||
import javax.validation.constraints.NotBlank; | |||
import javax.validation.constraints.NotNull; | |||
import com.ningdatech.basic.model.PagePo; | |||
import io.swagger.annotations.ApiModel; | |||
import io.swagger.annotations.ApiModelProperty; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Data; | |||
import lombok.NoArgsConstructor; | |||
import java.time.LocalDateTime; | |||
/** | |||
* @author CMM | |||
* @since 2024-05-10 | |||
*/ | |||
@ApiModel(description = "会议专家信息列表请求入参") | |||
@Data | |||
@AllArgsConstructor | |||
@NoArgsConstructor | |||
public class ReqMeetingExpertSignPO { | |||
@ApiModelProperty("校验公钥") | |||
@NotBlank(message = "秘钥不能为空") | |||
private String key; | |||
@ApiModelProperty("会议ID") | |||
@NotNull(message = "会议ID不能为空") | |||
private Long meetingId; | |||
@ApiModelProperty("专家用户ID") | |||
@NotNull(message = "专家用户ID不能为空") | |||
private Long userId; | |||
@ApiModelProperty("签到时间") | |||
@NotNull(message = "签到时间不能为空") | |||
private LocalDateTime signTime; | |||
@ApiModelProperty("签到地点") | |||
@NotBlank(message = "签到地点不能为空") | |||
private String signAddress; | |||
} |
@@ -15,6 +15,9 @@ import lombok.Data; | |||
@ApiModel("专家信息") | |||
public class ExpertInfoVO { | |||
@ApiModelProperty("专家id") | |||
private Long expertId; | |||
@ApiModelProperty("专家用户id") | |||
private Long userId; | |||
@@ -33,4 +36,7 @@ public class ExpertInfoVO { | |||
@ApiModelProperty(value = "单位id") | |||
private Long mhUnitId; | |||
@ApiModelProperty(value = "信创专家ID") | |||
private String mhExpertId; | |||
} |