Selaa lähdekoodia

1、增加身份证的识别ocr
2、优化知识图谱数据同步
3、增加职位的过期时间
4、优化面试邀约逻辑

rayson 9 kuukautta sitten
vanhempi
commit
5fc6b06430
18 muutettua tiedostoa jossa 216 lisäystä ja 41 poistoa
  1. 89 37
      citu-framework/citu-spring-boot-starter-baidu-aip/src/main/java/com/citu/framework/baiduaip/core/AipOcrClient.java
  2. 57 0
      citu-framework/citu-spring-boot-starter-baidu-aip/src/main/java/com/citu/framework/baiduaip/core/ocr/IDCardInfo.java
  3. 0 1
      menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/python/GraphApi.java
  4. 1 0
      menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/enums/ErrorCodeConstants.java
  5. 4 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobExportRespVO.java
  6. 3 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobPageReqVO.java
  7. 3 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobSaveReqVO.java
  8. 4 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedRespVO.java
  9. 3 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedSaveReqVO.java
  10. 3 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedSimpleRespVO.java
  11. 5 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/dataobject/job/JobAdvertisedDO.java
  12. 3 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/interview/InterviewInviteMapper.java
  13. 26 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/job/JobAdvertisedMapper.java
  14. 3 3
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/mq/consumer/GraphConsumer.java
  15. 4 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/interview/InterviewInviteServiceImpl.java
  16. 6 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/job/JobIntegrationServiceImpl.java
  17. 1 0
      menduner/menduner-system-biz/src/main/resources/i18n/messages_en_US.properties
  18. 1 0
      menduner/menduner-system-biz/src/main/resources/i18n/messages_zh_CN.properties

+ 89 - 37
citu-framework/citu-spring-boot-starter-baidu-aip/src/main/java/com/citu/framework/baiduaip/core/AipOcrClient.java

@@ -4,6 +4,7 @@ import cn.hutool.http.HttpUtil;
 import com.baidu.aip.ocr.AipOcr;
 import com.citu.framework.baiduaip.config.BaiduAipProperties;
 import com.citu.framework.baiduaip.core.ocr.BusinessLicenseOcr;
+import com.citu.framework.baiduaip.core.ocr.IDCardInfo;
 import com.citu.framework.common.util.date.DateUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.json.JSONObject;
@@ -27,6 +28,15 @@ public class AipOcrClient {
         this.client = new AipOcr(properties.getAppId(), properties.getApiKey(), properties.getSecretKey());
     }
 
+    /**
+     * 获取words_result字段中的属性值
+     *
+     * @param key         属性名
+     * @param wordsResult words_result字段
+     **/
+    private String getWordsResultAttribute(String key, JSONObject wordsResult) {
+        return wordsResult.getJSONObject(key).getString("words");
+    }
 
     /**
      * 根据营业执照图片解析识别营业执照
@@ -36,50 +46,92 @@ public class AipOcrClient {
      **/
     public BusinessLicenseOcr businessLicense(String imageUrl) {
         try {
-        byte[] image = HttpUtil.downloadBytes(imageUrl);
-        JSONObject res = client.businessLicense(image, new HashMap<String, String>());
-        log.info("营业执照识别: {}", res);
-        // 获取words_result字段
-        JSONObject wordsResult = res.getJSONObject("words_result");
-        BusinessLicenseOcr businessLicenseOcr = new BusinessLicenseOcr();
-        // 接口返回的就是对象里面中文
-        businessLicenseOcr.setCode(getWordsResultAttribute("社会信用代码", wordsResult));
-        businessLicenseOcr.setName(getWordsResultAttribute("单位名称", wordsResult));
-        businessLicenseOcr.setType(getWordsResultAttribute("类型", wordsResult));
-        businessLicenseOcr.setAddress(getWordsResultAttribute("地址", wordsResult));
-        businessLicenseOcr.setRepresentative(getWordsResultAttribute("法人", wordsResult));
-        LocalDate date = DateUtils.of(getWordsResultAttribute("成立日期", wordsResult), DateUtils.FORMAT_YEAR_MONTH_DAY_CHINESE);
-        businessLicenseOcr.setEstablishmentTime(date.atStartOfDay());
-        businessLicenseOcr.setRegisteredCapital(getWordsResultAttribute("注册资本", wordsResult));
-        businessLicenseOcr.setApprovalTime(getWordsResultAttribute("核准日期", wordsResult));
-
-        businessLicenseOcr.setRegistrationAuthority(getWordsResultAttribute("登记机关", wordsResult));
-        businessLicenseOcr.setBusinessTerm(getWordsResultAttribute("有效期起始日期", wordsResult) + " 至 " + getWordsResultAttribute("有效期", wordsResult));
-        businessLicenseOcr.setBusinessScope(getWordsResultAttribute("经营范围", wordsResult));
-
-
-        // 其他属性
-        getWordsResultAttribute("组成形式", wordsResult);
-        getWordsResultAttribute("证件编号", wordsResult);
-        getWordsResultAttribute("实收资本", wordsResult);
-        getWordsResultAttribute("税务登记号", wordsResult);
-
-
-        return businessLicenseOcr;
-        }catch (Exception ex) {
+            byte[] image = HttpUtil.downloadBytes(imageUrl);
+            JSONObject res = client.businessLicense(image, new HashMap<String, String>());
+            log.info("营业执照识别: {}", res);
+            // 获取words_result字段
+            JSONObject wordsResult = res.getJSONObject("words_result");
+            BusinessLicenseOcr businessLicenseOcr = new BusinessLicenseOcr();
+            // 接口返回的就是对象里面中文
+            businessLicenseOcr.setCode(getWordsResultAttribute("社会信用代码", wordsResult));
+            businessLicenseOcr.setName(getWordsResultAttribute("单位名称", wordsResult));
+            businessLicenseOcr.setType(getWordsResultAttribute("类型", wordsResult));
+            businessLicenseOcr.setAddress(getWordsResultAttribute("地址", wordsResult));
+            businessLicenseOcr.setRepresentative(getWordsResultAttribute("法人", wordsResult));
+            LocalDate date = DateUtils.of(getWordsResultAttribute("成立日期", wordsResult), DateUtils.FORMAT_YEAR_MONTH_DAY_CHINESE);
+            businessLicenseOcr.setEstablishmentTime(date.atStartOfDay());
+            businessLicenseOcr.setRegisteredCapital(getWordsResultAttribute("注册资本", wordsResult));
+            businessLicenseOcr.setApprovalTime(getWordsResultAttribute("核准日期", wordsResult));
+
+            businessLicenseOcr.setRegistrationAuthority(getWordsResultAttribute("登记机关", wordsResult));
+            businessLicenseOcr.setBusinessTerm(getWordsResultAttribute("有效期起始日期", wordsResult) + " 至 " + getWordsResultAttribute("有效期", wordsResult));
+            businessLicenseOcr.setBusinessScope(getWordsResultAttribute("经营范围", wordsResult));
+
+
+            // 其他属性
+            getWordsResultAttribute("组成形式", wordsResult);
+            getWordsResultAttribute("证件编号", wordsResult);
+            getWordsResultAttribute("实收资本", wordsResult);
+            getWordsResultAttribute("税务登记号", wordsResult);
+
+
+            return businessLicenseOcr;
+        } catch (Exception ex) {
             ex.printStackTrace();
-            return null;
         }
+        return null;
     }
 
     /**
-     * 获取words_result字段中的属性值
+     * 根据身份证图片解析识别身份证信息
      *
-     * @param key         属性名
-     * @param wordsResult words_result字段
+     * @param frontUrl 身份证含照片的一面
+     * @param backUrl  身份证带国徽的一面
+     * @return IDCardInfo 身份证对象
      **/
-    private String getWordsResultAttribute(String key, JSONObject wordsResult) {
-        return wordsResult.getJSONObject(key).getString("words");
+    public IDCardInfo idcard(String frontUrl, String backUrl) {
+        try {
+            byte[] front = HttpUtil.downloadBytes(frontUrl);
+            byte[] back = HttpUtil.downloadBytes(backUrl);
+            JSONObject frontRes = client.idcard(front, "front", new HashMap<String, String>());
+            JSONObject backRes = client.idcard(back, "back", new HashMap<String, String>());
+            log.info("身份证识别 - 头像面: {} \r\n 国徽面", frontRes, backRes);
+            IDCardInfo idCardInfo = new IDCardInfo();
+            // image_status
+            //  normal-识别正常
+            //  reversed_side-身份证正反面颠倒
+            //  non_idcard-上传的图片中不包含身份证
+            //  blurred-身份证模糊
+            //  other_type_card-其他类型证照
+            //  over_exposure-身份证关键字段反光或过曝
+            //  over_dark-身份证欠曝(亮度过低)
+            //  unknown-未知状态
+            if ("normal".equals(frontRes.getString("image_status"))) {
+                // 获取words_result字段
+                JSONObject wordsResult = frontRes.getJSONObject("words_result");
+                idCardInfo.setName(getWordsResultAttribute("姓名", wordsResult));
+                idCardInfo.setGender(getWordsResultAttribute("性别", wordsResult));
+                idCardInfo.setBirthDate(DateUtils.of(getWordsResultAttribute("出生", wordsResult),
+                        DateUtils.FORMAT_YEAR_MONTH_DAY_CHINESE));
+                idCardInfo.setAddress(getWordsResultAttribute("住址", wordsResult));
+                idCardInfo.setIdNumber(getWordsResultAttribute("公民身份号码", wordsResult));
+                idCardInfo.setEthnicity(getWordsResultAttribute("民族", wordsResult));
+
+            }
+            if ("normal".equals(backRes.getString("image_status"))) {
+                JSONObject wordsResult = backRes.getJSONObject("words_result");
+                idCardInfo.setIssuingAuthority(getWordsResultAttribute("签发机关", wordsResult));
+                idCardInfo.setIssueDate(DateUtils.of(getWordsResultAttribute("签发日期", wordsResult),
+                        DateUtils.FORMAT_YEAR_MONTH_DAY_CHINESE));
+                idCardInfo.setExpiryDate(DateUtils.of(getWordsResultAttribute("失效日期", wordsResult),
+                        DateUtils.FORMAT_YEAR_MONTH_DAY_CHINESE));
+
+            }
+            return idCardInfo;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return null;
     }
 
 

+ 57 - 0
citu-framework/citu-spring-boot-starter-baidu-aip/src/main/java/com/citu/framework/baiduaip/core/ocr/IDCardInfo.java

@@ -0,0 +1,57 @@
+package com.citu.framework.baiduaip.core.ocr;
+
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * 身份证信息
+ **/
+@Data
+public class IDCardInfo {
+
+    /**
+     * 姓名
+     **/
+    private String name;
+
+    /**
+     * 性别
+     **/
+    private String gender;
+
+    /**
+     * 民族
+     **/
+    private String ethnicity;
+
+    /**
+     * 出生日期
+     **/
+    private LocalDate birthDate;
+
+    /**
+     * 地址
+     **/
+    private String address;
+
+    /**
+     * 身份证号码
+     **/
+    private String idNumber;
+
+    /**
+     * 签发机关
+     **/
+    private String issuingAuthority;
+
+    /**
+     * 签发日期
+     **/
+    private LocalDate issueDate;
+
+    /**
+     * 失效日期
+     **/
+    private LocalDate expiryDate;
+}

+ 0 - 1
menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/python/GraphApi.java

@@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestBody;
 @Tag(name = "RPC 服务 - python 知识图谱")
 public interface GraphApi {
 
-    @Async
     @PostMapping("/rocket/receive/data")
     @Operation(summary = "发送数据到知识图谱")
     <T> CommonResult<Boolean> send(@RequestBody GraphSendDTO<T> sendDTO);

+ 1 - 0
menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/enums/ErrorCodeConstants.java

@@ -334,6 +334,7 @@ public interface ErrorCodeConstants {
 
     ErrorCode INTERVIEW_INVITE_TIME_OVERLAP = new ErrorCode(1_100_033_014, "该时间段已有其他面试者预约");
 
+    ErrorCode INTERVIEW_INVITE_TIME_LESS_THAN_NOW = new ErrorCode(1_100_033_015, "面试时间不能小于当前时间");
 
     // ========== 企业用户申请 1_100_034_000 ==========
     ErrorCode ENTERPRISE_USER_APPLY_NOT_EXISTS = new ErrorCode(1_100_034_001, "企业用户申请不存在");

+ 4 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobExportRespVO.java

@@ -82,6 +82,10 @@ public class AppRecruitJobExportRespVO {
     @ExcelProperty("职位要求")
     private String requirement;
 
+    @Schema(description = "过期时间")
+    @ExcelProperty("过期时间")
+    private LocalDateTime expireTime;
+
     @Schema(description = "是否置顶")
     @ExcelProperty("是否置顶")
     private Boolean top;

+ 3 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobPageReqVO.java

@@ -47,6 +47,9 @@ public class AppRecruitJobPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    @Schema(description = "是否获取过期的数据")
+    private boolean hasExpiredData;
+
     @Schema(description = "是否雇佣 (众聘)")
     private Boolean hire;
 

+ 3 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/recruit/job/vo/AppRecruitJobSaveReqVO.java

@@ -59,6 +59,9 @@ public class AppRecruitJobSaveReqVO {
     @Schema(description = "职位要求")
     private String requirement;
 
+    @Schema(description = "过期时间")
+    private LocalDateTime expireTime;
+
     @Schema(description = "工作地址")
     private String address;
 

+ 4 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedRespVO.java

@@ -83,6 +83,10 @@ public class JobAdvertisedRespVO {
     @ExcelProperty("职位要求")
     private String requirement;
 
+    @Schema(description = "过期时间")
+    @ExcelProperty("过期时间")
+    private LocalDateTime expireTime;
+
     @Schema(description = "是否置顶")
     @ExcelProperty("是否置顶")
     private Boolean top;

+ 3 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedSaveReqVO.java

@@ -70,6 +70,9 @@ public class JobAdvertisedSaveReqVO {
     @Schema(description = "工作地址")
     private String address;
 
+    @Schema(description = "过期时间")
+    private LocalDateTime expireTime;
+
     @Schema(description = "是否置顶")
     private Boolean top;
 

+ 3 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/job/JobAdvertisedSimpleRespVO.java

@@ -47,6 +47,9 @@ public class JobAdvertisedSimpleRespVO {
     @Schema(description = "是否雇佣 (众聘)")
     private Boolean hire;
 
+    @Schema(description = "过期时间")
+    private LocalDateTime expireTime;
+
     @Schema(description = "雇佣金额")
     private Long hirePrice;
 

+ 5 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/dataobject/job/JobAdvertisedDO.java

@@ -10,6 +10,7 @@ import com.citu.framework.tenant.core.db.TenantBaseDO;
 import lombok.*;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -91,6 +92,10 @@ public class JobAdvertisedDO extends TenantBaseDO {
      * 职位要求
      */
     private String requirement;
+    /**
+     * 过期时间
+     */
+    private LocalDateTime expireTime;
     /**
      * 是否置顶
      */

+ 3 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/interview/InterviewInviteMapper.java

@@ -254,6 +254,9 @@ public interface InterviewInviteMapper extends BaseMapperX<InterviewInviteDO> {
                 .eq(InterviewInviteDO::getInviteUserId, userId)
                 .eq(InterviewInviteDO::getJobId, jobId)
                 .eq(InterviewInviteDO::getTime, time)
+                // 排除已拒绝和已取消
+                .ne(InterviewInviteDO::getStatus, InterviewInviteStatusEnum.REJECTED.getStatus())
+                .ne(InterviewInviteDO::getStatus, InterviewInviteStatusEnum.CANCELLED.getStatus())
         ) > 0;
     }
 

+ 26 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/job/JobAdvertisedMapper.java

@@ -90,6 +90,7 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         LambdaQueryWrapperX<JobAdvertisedDO> query = new LambdaQueryWrapperX<>();
         query.eq(JobAdvertisedDO::getEnterpriseId, enterpriseId);
         query.eq(JobAdvertisedDO::getStatus, MendunerStatusEnum.ENABLE.getStatus());
+        notExpireTime(query);
         return selectList(query);
     }
 
@@ -110,6 +111,7 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         query.eqIfPresent(JobAdvertisedDO::getEnterpriseId, reqVO.getEnterpriseId());
         query.eqIfPresent(JobAdvertisedDO::getHire, reqVO.getHire());
         query.eqIfPresent(JobAdvertisedDO::getTop, reqVO.getTop());
+        notExpireTime(query);
 
         // 相识参数
         if (reqVO.getAcquainted()) {
@@ -155,6 +157,7 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         query.innerJoin(EnterpriseDO.class, EnterpriseDO::getId, JobAdvertisedDO::getEnterpriseId);
         query.eq(EnterpriseDO::getStatus, MendunerStatusEnum.ENABLE.getStatus());
         query.eq(JobAdvertisedDO::getStatus, MendunerStatusEnum.ENABLE.getStatus());
+        notExpireTime(query);
         query.orderByDesc(JobAdvertisedDO::getUpdateTime);
         query.groupBy(JobAdvertisedDO::getEnterpriseId);
         return selectJoinPage(pageParam, AppEnterpriseJobHomeRespVO.class, query);
@@ -195,6 +198,7 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         LambdaQueryWrapper<JobAdvertisedDO> query = new LambdaQueryWrapperX<JobAdvertisedDO>();
         query.in(JobAdvertisedDO::getEnterpriseId, ids);
         query.eq(JobAdvertisedDO::getStatus, MendunerStatusEnum.ENABLE.getStatus());
+        notExpireTime(query);
         return selectList(query);
     }
 
@@ -216,6 +220,12 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         query.eq(JobAdvertisedDO::getEnterpriseId, enterpriseId);
         query.eq(JobAdvertisedDO::getUserId, userId);
 
+        if (reqVO.isHasExpiredData()) {
+            // 获取过期的数据 当前时间小于过期时间
+            query.le(JobAdvertisedDO::getExpireTime, LocalDateTime.now());
+        } else {
+            notExpireTime(query);
+        }
         return selectPage(reqVO, query);
     }
 
@@ -357,4 +367,20 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         return selectJoinPage(reqVO, AppRecruitJobExportRespVO.class, query);
     }
 
+    /** 过滤过期的职位 **/
+    default void notExpireTime(MPJLambdaWrapperX<JobAdvertisedDO> query) {
+        query.and(wrapper -> wrapper
+                .ge(JobAdvertisedDO::getExpireTime, LocalDateTime.now())
+                .or()
+                .isNull(JobAdvertisedDO::getExpireTime)
+        );
+    }
+
+    default void notExpireTime(LambdaQueryWrapper<JobAdvertisedDO> query) {
+        query.and(wrapper -> wrapper
+                .ge(JobAdvertisedDO::getExpireTime, LocalDateTime.now())
+                .or()
+                .isNull(JobAdvertisedDO::getExpireTime)
+        );
+    }
 }

+ 3 - 3
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/mq/consumer/GraphConsumer.java

@@ -22,16 +22,16 @@ import javax.annotation.Resource;
         topic = GraphSendDTO.SYNC_GRAPH_TOPIC,
         consumerGroup = GraphSendDTO.SYNC_GRAPH_TOPIC + "_CONSUMER"
 )
-public class GraphConsumer implements RocketMQListener<GraphSendDTO> {
+public class GraphConsumer<T> implements RocketMQListener<GraphSendDTO<T>> {
 
     @Resource
     private GraphApi graphApi;
 
     @Override
-    @TenantIgnore
-    public void onMessage(GraphSendDTO message) {
+    public  void onMessage(GraphSendDTO<T> message) {
         log.info("GraphConsumer-接收到队列消息[{}]", message);
         graphApi.send(message).getCheckedData();
         log.info("GraphConsumer-消息处理完备[{}]", message);
     }
+
 }

+ 4 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/interview/InterviewInviteServiceImpl.java

@@ -214,6 +214,10 @@ public class InterviewInviteServiceImpl implements InterviewInviteService {
         Long enterpriseId = LoginUserContext.getEnterpriseId(loginUser);
         Long userId = LoginUserContext.getUserId(loginUser);
         InterviewInviteDO interviewInvite = BeanUtils.toBean(reqVO, InterviewInviteDO.class);
+        // 检查时间是否小于当前时间
+        if(LocalDateTime.now().isBefore(reqVO.getTime())) {
+            throw exception(INTERVIEW_INVITE_TIME_LESS_THAN_NOW);
+        }
         if(mapper.checkExistsTime(reqVO.getId(),enterpriseId, userId, reqVO.getJobId(),reqVO.getTime())) {
             // 该时间段已有其他面试者预约
             throw exception(INTERVIEW_INVITE_TIME_OVERLAP);

+ 6 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/job/JobIntegrationServiceImpl.java

@@ -49,6 +49,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -291,6 +293,10 @@ public class JobIntegrationServiceImpl implements JobIntegrationService {
             Long count = jobCvRelDOList.stream()
                     .filter(jobCvRelDO -> jobCvRelDO.getJobId().equals(job.getId())).count();
             respVO.setCount(count);
+            // 计算多少天后到期
+            if (null != job.getExpireTime()) {
+                respVO.setExpireDay(ChronoUnit.DAYS.between(LocalDateTime.now(), respVO.getExpireTime()));
+            }
             list.add(respVO);
 
         });

+ 1 - 0
menduner/menduner-system-biz/src/main/resources/i18n/messages_en_US.properties

@@ -250,6 +250,7 @@
 1_100_033_012=The current employee has not yet joined and cannot be settled
 1_100_033_013=Settlement function maintenance in progress
 1_100_033_014=Other interviewees have already made appointments during this time period
+1_100_033_015=The interview time cannot be less than the current time
 # ========== 企业用户申请 1_100_034_000 ==========
 1_100_034_001=Enterprise user application does not exist
 1_100_034_002=User application has been approved

+ 1 - 0
menduner/menduner-system-biz/src/main/resources/i18n/messages_zh_CN.properties

@@ -250,6 +250,7 @@
 1_100_033_012=当前员工还未入职,无法结算
 1_100_033_013=结算功能维护中
 1_100_033_014=该时间段已有其他面试者预约
+1_100_033_015=面试时间不能小于当前时间
 # ========== 企业用户申请 1_100_034_000 ==========
 1_100_034_001=企业用户申请不存在
 1_100_034_002=用户申请已审批