Browse Source

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

master
CMM 6 months ago
parent
commit
121606f3c2
11 changed files with 383 additions and 4 deletions
  1. +3
    -1
      hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java
  2. +14
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java
  3. +48
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/open/controller/OpenApiMeetingExpertInfoController.java
  4. +187
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/open/manage/OpenApiMeetingExpertInfoManage.java
  5. +28
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/open/model/po/ReqMeetingExpertInfoPO.java
  6. +41
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/ExpertInfoVO.java
  7. +49
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/MeetingExpertInfoVO.java
  8. +4
    -1
      hz-pm-api/src/main/resources/application-dev.yml
  9. +4
    -1
      hz-pm-api/src/main/resources/application-pre.yml
  10. +4
    -1
      hz-pm-api/src/main/resources/application-prod.yml
  11. +1
    -0
      hz-pm-api/src/main/resources/security/auth-dev.yml

+ 3
- 1
hz-pm-api/src/main/java/com/hz/pm/api/common/handler/GlobalResponseHandler.java View File

@@ -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<Object> {



+ 14
- 0
hz-pm-api/src/main/java/com/hz/pm/api/meeting/entity/domain/MeetingExpert.java View File

@@ -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;



}

+ 48
- 0
hz-pm-api/src/main/java/com/hz/pm/api/open/controller/OpenApiMeetingExpertInfoController.java View File

@@ -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;

/**
* <p>
* 会议专家信息外部调用接口
* </p>
* @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<MeetingExpertInfoVO> infoList(@Valid @RequestBody ReqMeetingExpertInfoPO po) {
return openMeetingExpertInfoManage.infoList(po);
}
}

+ 187
- 0
hz-pm-api/src/main/java/com/hz/pm/api/open/manage/OpenApiMeetingExpertInfoManage.java View File

@@ -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<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));
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::getSignStatus, Boolean.FALSE))
.stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId));
Map<Long, Meeting> meetingMap = CollUtils.listToMap(meetingList, Meeting::getId);
List<MeetingExpert> experts = Lists.newArrayList();
for (Map.Entry<Long, List<MeetingExpert>> listEntry : meetingExpertMap.entrySet()) {
List<MeetingExpert> value = listEntry.getValue();
experts.addAll(value);
}

// 获取未签到的专家信息
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));
Set<String> employeeSet = Sets.newHashSet();
userInfoList = userInfoList.stream().filter(u -> employeeSet.add(u.getEmployeeCode())).collect(Collectors.toList());
List<UserFullInfoDTO> userFullInfos = userInfoHelper.getUserFullInfos(userInfoList);
Set<Long> userIdSet = Sets.newHashSet();
userFullInfos = userFullInfos.stream().filter(u -> userIdSet.add(u.getUserId())).collect(Collectors.toList());
Map<Long, UserFullInfoDTO> infoMap = userFullInfos.stream().collect(Collectors.toMap(UserFullInfoDTO::getUserId, v -> v));

List<ExpertDictionary> expertDictionaryList = iExpertDictionaryService.list(Wrappers.lambdaQuery(ExpertDictionary.class)
.eq(ExpertDictionary::getExpertInfoField, ExpertDictTypeEnum.EXPERT_TYPE.getKey())
.in(ExpertDictionary::getUserId, userIdSet));
Map<Long, List<ExpertDictionary>> dictMap = expertDictionaryList.stream().collect(Collectors.groupingBy(ExpertDictionary::getUserId));

for (Map.Entry<Long, List<MeetingExpert>> 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<MeetingExpert> meetingExperts = entry.getValue();
if (CollUtil.isNotEmpty(meetingExperts)){
// 获取未签到的专家信息
List<MeetingExpert> expertUserList = meetingExperts.stream().filter(m -> Boolean.FALSE.equals(m.getSignStatus())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(expertUserList)){
List<ExpertInfoVO> 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<ExpertDictionary> dictionaries = dictMap.get(m.getExpertId());
if (CollUtil.isNotEmpty(dictionaries)){
List<DictionaryFieldInfo> dictionaryFieldInfos = dictionaries.stream().map(r -> {
DictionaryFieldInfo dictionaryFieldInfo = new DictionaryFieldInfo();
dictionaryFieldInfo.setDictionaryFieldName(r.getExpertInfoField());
dictionaryFieldInfo.setDictionaryCode(r.getDictionaryCode());
Optional<DictDTO> 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();
}
}

+ 28
- 0
hz-pm-api/src/main/java/com/hz/pm/api/open/model/po/ReqMeetingExpertInfoPO.java View File

@@ -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;
}

+ 41
- 0
hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/ExpertInfoVO.java View File

@@ -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<DictionaryFieldInfo> expertType;

@ApiModelProperty(value = "专家姓名")
private String name;

@ApiModelProperty(value = "手机号")
private String phoneNo;

@ApiModelProperty(value = "单位code")
private String organizationCode;

@ApiModelProperty(value = "单位名称")
private String organizationName;

}

+ 49
- 0
hz-pm-api/src/main/java/com/hz/pm/api/open/model/vo/MeetingExpertInfoVO.java View File

@@ -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<ExpertInfoVO> expertInfoList;
}

+ 4
- 1
hz-pm-api/src/main/resources/application-dev.yml View File

@@ -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



+ 4
- 1
hz-pm-api/src/main/resources/application-pre.yml View File

@@ -245,4 +245,7 @@ login:
skip: true
url: http://60.188.225.145:8080/login
web:
url: http://60.188.225.145:8080
url: http://60.188.225.145:8080
# be942283f87c195de4d8d2a016e91378a0ef7cb533a6bff9ba0524700bacf423
hz-pm:
interfaceKey: hz_meeting_expert_info

+ 4
- 1
hz-pm-api/src/main/resources/application-prod.yml View File

@@ -241,4 +241,7 @@ login:
skip: false
url: http://60.188.225.145/login
web:
url: http://60.188.225.145
url: http://60.188.225.145
# be942283f87c195de4d8d2a016e91378a0ef7cb533a6bff9ba0524700bacf423
hz-pm:
interfaceKey: hz_meeting_expert_info

+ 1
- 0
hz-pm-api/src/main/resources/security/auth-dev.yml View File

@@ -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":


Loading…
Cancel
Save