diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java b/hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java index 79f7d13..338d1af 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java @@ -37,7 +37,9 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; "com.hz.pm.api.gov.controller", "com.hz.pm.api.dashboard.controller", "com.hz.pm.api.wps.controller", - "com.hz.pm.api.gov.controller" + "com.hz.pm.api.gov.controller", + "com.hz.pm.api.open.controller" + }) public class GlobalResponseHandler implements ResponseBodyAdvice { diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java index 93d72f6..8af77ae 100644 --- a/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java +++ b/hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java @@ -73,4 +73,18 @@ public class MeetingExpert implements Serializable { @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateOn; + /** + * 20240511 新增字段 + */ + @ApiModelProperty("专家签到状态") + private Boolean signStatus; + + @ApiModelProperty("专家签到时间") + private LocalDateTime signTime; + + @ApiModelProperty("专家签到地点") + private String signAddress; + + + } diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/open/controller/OpenApiMeetingExpertInfoController.java b/hz-pm-api/src/main/java/com/hz/pm/api/open/controller/OpenApiMeetingExpertInfoController.java new file mode 100644 index 0000000..5b40ae4 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/open/controller/OpenApiMeetingExpertInfoController.java @@ -0,0 +1,48 @@ +package com.hz.pm.api.open.controller; + + + +import javax.validation.Valid; + +import com.hz.pm.api.open.manage.OpenApiMeetingExpertInfoManage; +import com.hz.pm.api.open.model.po.ReqMeetingExpertInfoPO; +import com.hz.pm.api.open.model.vo.MeetingExpertInfoVO; +import com.ningdatech.basic.model.PageVo; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.ningdatech.log.annotation.WebLog; + +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + *

+ * 会议专家信息外部调用接口 + *

+ * @author CMM + * + */ +@Slf4j +@Validated +@RestController +@RequestMapping("/open/api/meeting-expert-info") +@RequiredArgsConstructor +public class OpenApiMeetingExpertInfoController { + + private final OpenApiMeetingExpertInfoManage openMeetingExpertInfoManage; + + @PostMapping("/list") + @ApiOperation("获取已抽取完成会议确定参加会议且未签到的专家信息列表") + @WebLog + public List infoList(@Valid @RequestBody ReqMeetingExpertInfoPO po) { + return openMeetingExpertInfoManage.infoList(po); + } +} diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/open/manage/OpenApiMeetingExpertInfoManage.java b/hz-pm-api/src/main/java/com/hz/pm/api/open/manage/OpenApiMeetingExpertInfoManage.java new file mode 100644 index 0000000..b66d3c8 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/open/manage/OpenApiMeetingExpertInfoManage.java @@ -0,0 +1,187 @@ +package com.hz.pm.api.open.manage; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.hz.pm.api.expert.assembler.ExpertUserInfoAssembler; +import com.hz.pm.api.expert.model.DictionaryFieldInfo; +import com.hz.pm.api.expert.model.dto.ExpertDictionaryDTO; +import com.hz.pm.api.meta.constant.ExpertDictTypeEnum; +import com.hz.pm.api.meta.helper.DictionaryCache; +import com.hz.pm.api.meta.model.dto.DictDTO; +import com.hz.pm.api.meta.model.entity.ExpertDictionary; +import com.hz.pm.api.meta.service.IExpertDictionaryService; +import com.hz.pm.api.user.entity.UserInfo; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Lists; +import com.hz.pm.api.common.helper.UserInfoHelper; +import com.hz.pm.api.meeting.entity.domain.Meeting; +import com.hz.pm.api.meeting.entity.domain.MeetingExpert; +import com.hz.pm.api.meeting.service.IMeetingExpertService; +import com.hz.pm.api.meeting.service.IMeetingService; +import com.hz.pm.api.open.model.po.ReqMeetingExpertInfoPO; +import com.hz.pm.api.open.model.vo.ExpertInfoVO; +import com.hz.pm.api.open.model.vo.MeetingExpertInfoVO; +import com.hz.pm.api.user.security.auth.model.UserFullInfoDTO; +import com.hz.pm.api.user.service.IUserInfoService; +import com.ningdatech.basic.exception.BizException; +import com.ningdatech.basic.util.CollUtils; + +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author CMM + * @since 2024/05/10 17:18 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class OpenApiMeetingExpertInfoManage { + + @Value("${hz-pm.interfaceKey}") + private String meetingExpertInfoKey; + + private final IMeetingService meetingService; + private final IMeetingExpertService meetingExpertService; + private final UserInfoHelper userInfoHelper; + private final IUserInfoService userInfoService; + private final IExpertDictionaryService iExpertDictionaryService; + private final DictionaryCache dictionaryCache; + public List infoList(ReqMeetingExpertInfoPO po) { + String key = po.getKey(); + // 校验传入的签名 + if (!checkSign(key)){ + throw new BizException("签名错误!"); + } + // 获取已经抽取完成 确认参加会议并且未签到的专家信息 + List meetingList = meetingService.list(Wrappers.lambdaQuery(Meeting.class) + .eq(Meeting::getConfirmedRoster, true)); + if(CollUtil.isEmpty(meetingList)){ + return Collections.emptyList(); + } + List result = Lists.newArrayList(); + // 获取已抽取完成会议中未签到的专家信息 + List meetingIds = meetingList.stream().map(Meeting::getId).collect(Collectors.toList()); + Map> meetingExpertMap = meetingExpertService.list(Wrappers.lambdaQuery(MeetingExpert.class) + .in(MeetingExpert::getMeetingId, meetingIds) + .eq(MeetingExpert::getSignStatus, Boolean.FALSE)) + .stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId)); + Map meetingMap = CollUtils.listToMap(meetingList, Meeting::getId); + List experts = Lists.newArrayList(); + for (Map.Entry> listEntry : meetingExpertMap.entrySet()) { + List value = listEntry.getValue(); + experts.addAll(value); + } + + // 获取未签到的专家信息 + List expertList = experts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList()); + Set userIds = expertList.stream().map(MeetingExpert::getExpertId).collect(Collectors.toSet()); + List userInfoList = userInfoService.list(Wrappers.lambdaQuery(UserInfo.class).in(UserInfo::getId, userIds)); + Set employeeSet = Sets.newHashSet(); + userInfoList = userInfoList.stream().filter(u -> employeeSet.add(u.getEmployeeCode())).collect(Collectors.toList()); + List userFullInfos = userInfoHelper.getUserFullInfos(userInfoList); + Set userIdSet = Sets.newHashSet(); + userFullInfos = userFullInfos.stream().filter(u -> userIdSet.add(u.getUserId())).collect(Collectors.toList()); + Map infoMap = userFullInfos.stream().collect(Collectors.toMap(UserFullInfoDTO::getUserId, v -> v)); + + List expertDictionaryList = iExpertDictionaryService.list(Wrappers.lambdaQuery(ExpertDictionary.class) + .eq(ExpertDictionary::getExpertInfoField, ExpertDictTypeEnum.EXPERT_TYPE.getKey()) + .in(ExpertDictionary::getUserId, userIdSet)); + Map> dictMap = expertDictionaryList.stream().collect(Collectors.groupingBy(ExpertDictionary::getUserId)); + + for (Map.Entry> entry : meetingExpertMap.entrySet()) { + MeetingExpertInfoVO vo = new MeetingExpertInfoVO(); + Long meetingId = entry.getKey(); + Meeting meeting = meetingMap.get(meetingId); + if (Objects.nonNull(meeting)){ + vo.setMeetingId(meeting.getId()); + vo.setStartTime(meeting.getStartTime()); + vo.setEndTime(meeting.getEndTime()); + vo.setMeetingName(meeting.getName()); + vo.setMeetingAddress(meeting.getMeetingAddress()); + vo.setConnecter(meeting.getConnecter()); + vo.setContact(meeting.getContact()); + } + List meetingExperts = entry.getValue(); + if (CollUtil.isNotEmpty(meetingExperts)){ + // 获取未签到的专家信息 + List expertUserList = meetingExperts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(expertUserList)){ + List expertInfoVOList = expertUserList.stream().map(m -> { + ExpertInfoVO expertInfoVO = new ExpertInfoVO(); + expertInfoVO.setUserId(m.getExpertId()); + expertInfoVO.setName(m.getExpertName()); + expertInfoVO.setPhoneNo(m.getMobile()); + UserFullInfoDTO userFullInfoDTO = infoMap.get(m.getExpertId()); + if (Objects.nonNull(userFullInfoDTO)){ + expertInfoVO.setOrganizationCode(userFullInfoDTO.getOrganizationCode()); + expertInfoVO.setOrganizationName(userFullInfoDTO.getOrganizationName()); + } + List dictionaries = dictMap.get(m.getExpertId()); + if (CollUtil.isNotEmpty(dictionaries)){ + List dictionaryFieldInfos = dictionaries.stream().map(r -> { + DictionaryFieldInfo dictionaryFieldInfo = new DictionaryFieldInfo(); + dictionaryFieldInfo.setDictionaryFieldName(r.getExpertInfoField()); + dictionaryFieldInfo.setDictionaryCode(r.getDictionaryCode()); + Optional dictionaryDTO = dictionaryCache.getByCode(r.getDictionaryCode()); + dictionaryDTO.ifPresent(dictDTO -> dictionaryFieldInfo.setDictionaryName(dictDTO.getName())); + return dictionaryFieldInfo; + }).collect(Collectors.toList()); + expertInfoVO.setExpertType(dictionaryFieldInfos); + } + return expertInfoVO; + }).collect(Collectors.toList()); + vo.setExpertInfoList(expertInfoVOList); + } + } + result.add(vo); + } + return result; + } + + private Boolean checkSign(String key) { + StringBuilder sb = new StringBuilder(); + sb.append("key=").append(meetingExpertInfoKey); + // 使用SHA-256进行加密 + String sign = null; + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] bytes = md.digest(sb.toString().getBytes()); + sign = bytesToHexString(bytes); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + if (sign == null || sign.length() <= 8) { + return false; + } + String signStr = sign.substring(sign.length() - 8); + return signStr.equals(key); + } + + /** + * 将字节数组转换为十六进制字符串 + * + * @param bytes 字节数组 + * @return 十六进制字符串 + */ + private static String bytesToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + sb.append("0"); + } + sb.append(hex); + } + return sb.toString(); + } +} diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/open/model/po/ReqMeetingExpertInfoPO.java b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/po/ReqMeetingExpertInfoPO.java new file mode 100644 index 0000000..1832469 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/po/ReqMeetingExpertInfoPO.java @@ -0,0 +1,28 @@ +package com.hz.pm.api.open.model.po; + +import javax.validation.constraints.NotBlank; + +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.util.Date; + +/** + * @author CMM + * @since 2024-05-10 + */ +@ApiModel(description = "会议专家信息列表请求入参") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ReqMeetingExpertInfoPO extends PagePo { + + @ApiModelProperty("校验公钥") + @NotBlank(message = "秘钥不能为空") + private String key; +} diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/ExpertInfoVO.java b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/ExpertInfoVO.java new file mode 100644 index 0000000..70387c2 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/ExpertInfoVO.java @@ -0,0 +1,41 @@ +package com.hz.pm.api.open.model.vo; + +import java.util.List; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; + +import com.hz.pm.api.expert.model.*; +import com.hz.pm.api.meta.model.ExpertRegionInfo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author CMM + * @date 2024/5/11 + */ +@Data +@ApiModel("专家信息") +public class ExpertInfoVO { + + @ApiModelProperty("专家用户id") + private Long userId; + + @ApiModelProperty(value = "专家类型") + private List expertType; + + @ApiModelProperty(value = "专家姓名") + private String name; + + @ApiModelProperty(value = "手机号") + private String phoneNo; + + @ApiModelProperty(value = "单位code") + private String organizationCode; + + @ApiModelProperty(value = "单位名称") + private String organizationName; + +} diff --git a/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/MeetingExpertInfoVO.java b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/MeetingExpertInfoVO.java new file mode 100644 index 0000000..6f4c9c4 --- /dev/null +++ b/hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/MeetingExpertInfoVO.java @@ -0,0 +1,49 @@ +package com.hz.pm.api.open.model.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 外部调用接口会议专家信息实体 + * + * @author CMM + * @since 2024/05/10 17:16 + */ +@Data +public class MeetingExpertInfoVO { + + + /** + * 会议信息 + */ + + @ApiModelProperty("会议ID") + private Long meetingId; + + @ApiModelProperty("会议开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("会议结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("会议名称") + private String meetingName; + + @ApiModelProperty("会议地址") + private String meetingAddress; + + @ApiModelProperty("联系人") + private String connecter; + + @ApiModelProperty("联系方式") + private String contact; + + /** + * 专家信息列表 + */ + @ApiModelProperty("专家信息列表") + private List expertInfoList; +} diff --git a/hz-pm-api/src/main/resources/application-dev.yml b/hz-pm-api/src/main/resources/application-dev.yml index 2403d57..7e540ec 100644 --- a/hz-pm-api/src/main/resources/application-dev.yml +++ b/hz-pm-api/src/main/resources/application-dev.yml @@ -43,7 +43,7 @@ spring: datasource: type: com.zaxxer.hikari.HikariDataSource driverClassName: dm.jdbc.driver.DmDriver - url: jdbc:dm://47.98.125.47:5236/HZ_PROJECT_MANAGEMENT?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8 + url: jdbc:dm://47.98.125.47:5236/HZ_PROJECT_MANAGEMENT1?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8 username: SYSDBA password: SYSDBA # 数据源 @@ -245,5 +245,8 @@ web: expert-registration: verify-code: check: false +# be942283f87c195de4d8d2a016e91378a0ef7cb533a6bff9ba0524700bacf423 +hz-pm: + interfaceKey: hz_meeting_expert_info diff --git a/hz-pm-api/src/main/resources/application-pre.yml b/hz-pm-api/src/main/resources/application-pre.yml index 57c8c9f..ac26a25 100644 --- a/hz-pm-api/src/main/resources/application-pre.yml +++ b/hz-pm-api/src/main/resources/application-pre.yml @@ -245,4 +245,7 @@ login: skip: true url: http://60.188.225.145:8080/login web: - url: http://60.188.225.145:8080 \ No newline at end of file + url: http://60.188.225.145:8080 +# be942283f87c195de4d8d2a016e91378a0ef7cb533a6bff9ba0524700bacf423 +hz-pm: + interfaceKey: hz_meeting_expert_info \ No newline at end of file diff --git a/hz-pm-api/src/main/resources/application-prod.yml b/hz-pm-api/src/main/resources/application-prod.yml index b33a13b..6515d70 100644 --- a/hz-pm-api/src/main/resources/application-prod.yml +++ b/hz-pm-api/src/main/resources/application-prod.yml @@ -241,4 +241,7 @@ login: skip: false url: http://60.188.225.145/login web: - url: http://60.188.225.145 \ No newline at end of file + url: http://60.188.225.145 +# be942283f87c195de4d8d2a016e91378a0ef7cb533a6bff9ba0524700bacf423 +hz-pm: + interfaceKey: hz_meeting_expert_info \ No newline at end of file diff --git a/hz-pm-api/src/main/resources/security/auth-dev.yml b/hz-pm-api/src/main/resources/security/auth-dev.yml index 7833ea3..ebfd945 100644 --- a/hz-pm-api/src/main/resources/security/auth-dev.yml +++ b/hz-pm-api/src/main/resources/security/auth-dev.yml @@ -70,6 +70,7 @@ security: - /api/v1/wps-convert/** - /api/v1/belong-org/business-strip/list - /expert/ephemeral/*/registration + - /open/api/** role-map: "engineer": "project_manager":