Просмотр исходного кода

招聘端附件同步到员工档案

heyuan 3 месяцев назад
Родитель
Сommit
5babe3cebf

+ 0 - 12
guyitang.iml

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/websrc" isTestSource="false" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>

+ 99 - 0
websrc/com/kingdee/shr/recuritment/service/offer/ResumeConvertUtilEx.java

@@ -0,0 +1,99 @@
+package com.kingdee.shr.recuritment.service.offer;
+
+import com.kingdee.bos.BOSException;
+import com.kingdee.bos.Context;
+import com.kingdee.bos.dao.IObjectPK;
+import com.kingdee.bos.util.BOSUuid;
+import com.kingdee.eas.basedata.person.PersonInfo;
+import com.kingdee.eas.common.EASBizException;
+import com.kingdee.shr.preentry.PreEntryPersonFactory;
+import com.kingdee.shr.preentry.PreEntryPersonInfo;
+import com.kingdee.shr.recuritment.RecRegisterFactory;
+import com.kingdee.shr.recuritment.RecRegisterInfo;
+import com.kingdee.shr.recuritment.RecRegisterStateEnum;
+import com.kingdee.shr.recuritment.ResumeBaseRecInfo;
+import com.kingdee.shr.recuritment.app.util.convert.ResumeConvertUtil;
+import org.apache.log4j.Logger;
+
+/**
+ * @Description 简历转化工具类
+ * @Date 2025/9/18 19:58
+ * @Created by 59279
+ */
+public class ResumeConvertUtilEx extends ResumeConvertUtil {
+    private static final Logger logger = Logger.getLogger(ResumeConvertUtilEx.class);
+
+    /**
+     * 根据简历信息添加推荐注册记录。
+     * <p>
+     * 该方法会根据传入的简历信息创建预入职人员信息和推荐注册信息,并将这些信息保存到系统中。
+     * 同时还会调用服务同步简历数据到预入职人员信息中。
+     * </p>
+     *
+     * @param ctx    上下文对象,用于获取业务服务实例
+     * @param resume 简历基本信息对象,包含待处理的简历数据
+     * @throws BOSException 当业务操作过程中发生异常时抛出
+     */
+    public static void addRecRegisterByResume(Context ctx, ResumeBaseRecInfo resume) throws BOSException {
+        // 创建推荐注册信息和预入职人员信息对象
+        RecRegisterInfo newRecRegister = new RecRegisterInfo();
+        PreEntryPersonInfo personInfo = new PreEntryPersonInfo();
+
+        // 设置预入职人员基本信息
+        personInfo.setName(resume.getName());
+        personInfo.setIdCardNO(resume.getIdentityCardNo());
+        personInfo.setPassportNO(resume.getPassportNo());
+        personInfo.setBirthday(resume.getBirthday());
+        personInfo.setGender(resume.getGender());
+        personInfo.setNativePlace(resume.getNativePlace());
+        personInfo.setHighestDegree(resume.getHDegree());
+        personInfo.setNationality(resume.getNational());
+        personInfo.setFolk(resume.getFolk());
+        personInfo.setWed(resume.getWed());
+        personInfo.setPoliticalFace(resume.getPoliticalFace());
+        personInfo.setJobStartDate(resume.getWorkDate());
+
+        // 创建并设置人员信息主键
+        PersonInfo person = new PersonInfo();
+        String personId = BOSUuid.create(person.getBOSType()).toString();
+        person.setId(BOSUuid.read(personId));
+        personInfo.setPerson(person);
+
+        try {
+            // 保存预入职人员信息并获取主键
+            IObjectPK personPK = PreEntryPersonFactory.getLocalInstance(ctx).addnew(personInfo);
+            personInfo.setId(BOSUuid.read(personPK.toString()));
+
+            // 设置推荐注册信息的基本字段
+            String cellPhone = resume.getMobilePhone();
+            String email = resume.getEmail();
+            newRecRegister.setCellPhone(cellPhone);
+            newRecRegister.setEmail(email);
+            newRecRegister.setTalent(personInfo);
+            newRecRegister.setRecRegisterState(RecRegisterStateEnum.NOREGISTER);
+            newRecRegister.setName(resume.getName());
+
+            // 设置推荐注册信息的其他属性
+            BOSUuid id = BOSUuid.create((new RecRegisterInfo()).getBOSType());
+            newRecRegister.setId(id);
+            newRecRegister.setResumeBaseRec(resume);
+            newRecRegister.setIsLatest(true);
+            newRecRegister.setIsSendLogin(false);
+            newRecRegister.setNeedSendEmail(false);
+            newRecRegister.setNeedSendSms(false);
+            newRecRegister.setNumber(System.currentTimeMillis() + "");
+            newRecRegister.setRecRegisterState(RecRegisterStateEnum.NOREGISTER);
+
+            // 保存推荐注册信息
+            RecRegisterFactory.getLocalInstance(ctx).addnew(newRecRegister);
+
+            // 调用服务同步简历信息到预入职人员信息
+            ResumeSyncToPEPersonServiceEx resumeSyncToPEPersonServiceEx = new ResumeSyncToPEPersonServiceEx();
+            resumeSyncToPEPersonServiceEx.syncResumeToPEPerson(ctx, newRecRegister.getTalent(), resume);
+        } catch (EASBizException e) {
+            logger.error(e.getMessage());
+            throw new BOSException(e.getMessage());
+        }
+    }
+
+}

+ 95 - 0
websrc/com/kingdee/shr/recuritment/service/offer/ResumeSyncToPEPersonServiceEx.java

@@ -0,0 +1,95 @@
+package com.kingdee.shr.recuritment.service.offer;
+
+import com.kingdee.bos.BOSException;
+import com.kingdee.bos.Context;
+import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
+import com.kingdee.bos.metadata.entity.SelectorItemCollection;
+import com.kingdee.eas.base.attachment.AttachmentInfo;
+import com.kingdee.eas.common.EASBizException;
+import com.kingdee.eas.custom.beisen.utils.HRAttachmentUploadUtil;
+import com.kingdee.eas.custom.recuritment.utils.AttachmentUtils;
+import com.kingdee.shr.attachment.ISHRAttachmentExt;
+import com.kingdee.shr.attachment.SHRAttachmentExtCollection;
+import com.kingdee.shr.attachment.SHRAttachmentExtFactory;
+import com.kingdee.shr.attachment.SHRAttachmentExtInfo;
+import com.kingdee.shr.preentry.PreEntryPersonFactory;
+import com.kingdee.shr.preentry.PreEntryPersonInfo;
+import com.kingdee.shr.recuritment.*;
+import com.kingdee.shr.recuritment.app.service.ResumeSyncToPEPersonService;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @Description 简历同步预入职档案
+ * @Date 2025/9/18 19:53
+ * @Created by 59279
+ */
+public class ResumeSyncToPEPersonServiceEx extends ResumeSyncToPEPersonService {
+    private static Logger logger = LoggerFactory.getLogger(ResumeSyncToPEPersonServiceEx.class);
+
+    /**
+     * 同步简历信息到预入职人员信息中
+     *
+     * @param ctx    上下文对象
+     * @param person 预入职人员信息对象
+     * @param resume 简历基本信息对象
+     */
+    @Override
+    public void syncResumeToPEPerson(Context ctx, PreEntryPersonInfo person, ResumeBaseRecInfo resume) {
+        super.syncResumeToPEPerson(ctx, person, resume);
+        //简历id
+        try {
+            String resumeId = resume.getId().toString();
+            IRecApproval iRecApproval = RecApprovalFactory.getLocalInstance(ctx);
+            RecApprovalCollection recApprovalCollection =
+                    iRecApproval.getRecApprovalCollection("where resumeBaseRec = '" + resumeId + "'");
+            if (!recApprovalCollection.isEmpty()) {
+                //获取招聘审批信息
+                RecApprovalInfo recApprovalInfo = recApprovalCollection.get(0);
+                //获取背调信息
+                String personalScreening = recApprovalInfo.getPersonalScreening();
+                if (StringUtils.isNotBlank(personalScreening)) {
+                    person.put("personalScreening", personalScreening);
+                    SelectorItemCollection updateSic = new SelectorItemCollection();
+                    updateSic.add("personalScreening");
+                    //更新背调信息
+                    PreEntryPersonFactory.getLocalInstance(ctx).updatePartial(person, updateSic);
+                }
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+        if (person != null) {
+            logger.error("***************************同步简历附件到预入职开始***************************");
+            //预入职id
+            String id = person.getId().toString();
+            //简历id
+            String resumeId = resume.getId().toString();
+            try {
+                //删除简历附件
+                String filter = "where boid = '" + id + "' and (attachment.name like '%标准简历%' or attachment.name like '%面试评价%' or attachment.name like '%原始简历%' or attachment.name like '%背景调查审批表%' )";
+                AttachmentUtils.deleteAttachment(ctx, filter);
+                ISHRAttachmentExt ishrAttachmentExt = SHRAttachmentExtFactory.getLocalInstance(ctx);
+                SHRAttachmentExtCollection shrAttachmentExtCollection =
+                        ishrAttachmentExt.getSHRAttachmentExtCollection("select attachment.* where boID = '" + resumeId + "'");
+                String uipk = "hr.preentry.resume.base";//预入职人员_基本信息
+                for (int i = 0; i < shrAttachmentExtCollection.size(); i++) {
+                    SHRAttachmentExtInfo shrAttachmentExtInfo = shrAttachmentExtCollection.get(i);
+                    AttachmentInfo attachmentInfo = shrAttachmentExtInfo.getAttachment();
+                    if (attachmentInfo == null || attachmentInfo.getFile() == null) {
+                        continue;
+                    }
+                    String type = attachmentInfo.getSimpleName();
+                    String fileName = attachmentInfo.getName();
+                    byte[] file = attachmentInfo.getFile();
+                    //上传附件
+                    HRAttachmentUploadUtil.uploadAttachment(ctx, file, type, fileName, id, uipk, "null0");
+                }
+            } catch (Exception e) {
+                logger.error(e.getMessage(), e);
+            }
+            logger.error("***************************同步简历附件到预入职结束***************************");
+        }
+    }
+}

+ 209 - 0
websrc/com/kingdee/shr/recuritment/service/offer/SyncResumeToPreServiceEx.java

@@ -0,0 +1,209 @@
+package com.kingdee.shr.recuritment.service.offer;
+
+import com.kingdee.bos.BOSException;
+import com.kingdee.bos.Context;
+import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
+import com.kingdee.bos.metadata.data.SortType;
+import com.kingdee.bos.metadata.entity.*;
+import com.kingdee.bos.metadata.query.util.CompareType;
+import com.kingdee.eas.base.attachment.AttachmentInfo;
+import com.kingdee.eas.common.EASBizException;
+import com.kingdee.eas.custom.beisen.utils.HRAttachmentUploadUtil;
+import com.kingdee.eas.custom.recuritment.utils.AttachmentUtils;
+import com.kingdee.shr.attachment.ISHRAttachmentExt;
+import com.kingdee.shr.attachment.SHRAttachmentExtCollection;
+import com.kingdee.shr.attachment.SHRAttachmentExtFactory;
+import com.kingdee.shr.attachment.SHRAttachmentExtInfo;
+import com.kingdee.shr.base.syssetting.exception.SHRWebException;
+import com.kingdee.shr.preentry.*;
+import com.kingdee.shr.recuritment.*;
+import com.kingdee.shr.recuritment.app.util.ParamUtil;
+import com.kingdee.shr.recuritment.app.util.db.RecDBUtils;
+import com.kingdee.shr.recuritment.service.recRegister.RecRegisterService;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * @Description 同步简历到预入职
+ * @Date 2025/9/18 10:28
+ * @Created by 59279
+ */
+public class SyncResumeToPreServiceEx extends SyncResumeToPreService {
+    private Logger logger = Logger.getLogger(SyncResumeToPreServiceEx.class);
+
+    /**
+     * 根据简历信息添加新的预入职记录。
+     * <p>
+     * 该方法首先根据简历基础信息查询最新的招聘登记记录,如果不存在则创建一个新的招聘登记记录。
+     * 然后基于招聘登记记录或简历信息生成预入职信息,并更新相关状态。
+     * 同时将对应的招聘登记记录及简历标记为无效。
+     *
+     * @param ctx   上下文对象,用于获取业务服务实例
+     * @param offer 包含简历和预入职相关信息的 Offer 信息对象
+     * @param isSSC 是否为共享服务中心操作标识
+     * @return 返回创建的预入职信息对象
+     * @throws EASBizException 业务异常
+     * @throws BOSException    BOS框架异常
+     * @throws SHRWebException SHR Web服务异常
+     */
+    public PreEntryInfo addNewPreEntryByResume(Context ctx, OfferInfo offer, boolean isSSC) throws EASBizException, BOSException, SHRWebException {
+        // 构建查询条件:根据简历基础记录ID查找招聘登记记录
+        EntityViewInfo view = new EntityViewInfo();
+        FilterInfo filter = new FilterInfo();
+        filter.getFilterItems().add(new FilterItemInfo("resumeBaseRec", offer.getResumeBaseRec().getId().toString(), CompareType.EQUALS));
+        view.setFilter(filter);
+
+        // 设置查询字段选择器,包含所有字段、人才信息和简历基础信息
+        SelectorItemCollection selector = new SelectorItemCollection();
+        selector.add("*");
+        selector.add("talent.*");
+        selector.add("resumeBaseRec.*");
+        view.setSelector(selector);
+
+        // 设置排序规则:按创建时间降序排列
+        SorterItemCollection sorterColl = new SorterItemCollection();
+        SorterItemInfo sorterItemInfo = new SorterItemInfo("createTime");
+        sorterItemInfo.setSortType(SortType.DESCEND);
+        sorterColl.add(sorterItemInfo);
+        view.setSorter(sorterColl);
+
+        // 查询招聘登记记录集合
+        RecRegisterCollection coll = RecRegisterFactory.getLocalInstance(ctx).getRecRegisterCollection(view);
+
+        // 如果未查到记录,则尝试通过简历创建新的招聘登记记录并重新查询
+        if (RecDBUtils.isEmpty(coll)) {
+            ResumeBaseRecInfo resumeBaseRecInfo = ResumeBaseRecFactory.getLocalInstance(ctx).getResumeBaseRecInfo("select * where id='" + offer.getResumeBaseRec().getId().toString() + "'");
+            ResumeConvertUtilEx.addRecRegisterByResume(ctx, resumeBaseRecInfo);
+            coll = RecRegisterFactory.getLocalInstance(ctx).getRecRegisterCollection("select *,talent.*,resumeBaseRec.* where resumeBaseRec = '" + offer.getResumeBaseRec().getId().toString() + "' order by createTime desc");
+        }
+
+        PreEntryInfo preEntryInfo = null;
+
+        // 处理查询到的招聘登记记录
+        if (coll != null && coll.size() > 0) {
+            RecRegisterInfo recRegisterInfo = coll.get(0);
+
+            // 判断是否有关联的人才信息
+            if (recRegisterInfo.getTalent() != null) {
+                // 若 Offer 中已有预入职信息且已设置报到状态,则直接使用
+                if (offer.getPreEntry() != null && offer.getPreEntry().getCheckInState() != null) {
+                    preEntryInfo = offer.getPreEntry();
+                } else {
+                    // 否则基于招聘登记信息创建新的预入职信息
+                    preEntryInfo = this.addNewPreEntryByRecRegister(ctx, recRegisterInfo, offer.getPreEntryDate(), isSSC);
+                    offer.setPreEntry(preEntryInfo);
+                    OfferFactory.getLocalInstance(ctx).update(new ObjectUuidPK(offer.getId()), offer);
+                }
+            } else {
+                // 没有关联人才信息时,基于简历创建预入职信息
+                preEntryInfo = this.addNewPreEntryByResume(ctx, offer, isSSC, preEntryInfo);
+            }
+
+            // 将当前招聘登记记录及其关联的简历标记为无效
+            boolean result = RecRegisterService.getInstance().invalidRegister(ctx, recRegisterInfo);
+            if (result) {
+                recRegisterInfo.setRecRegisterState(RecRegisterStateEnum.INVALID);
+                RecRegisterFactory.getLocalInstance(ctx).update(new ObjectUuidPK(recRegisterInfo.getId()), recRegisterInfo);
+                ResumeBaseRecInfo resumeInfo = recRegisterInfo.getResumeBaseRec();
+                resumeInfo.setRecRegisterState(RecRegisterStateEnum.INVALID);
+                ResumeBaseRecFactory.getLocalInstance(ctx).update(new ObjectUuidPK(resumeInfo.getId()), resumeInfo);
+
+                // 根据配置决定是否更新文件状态
+                Integer registerEditWay = ParamUtil.getInstance().getRecRegisterEditWay(ctx);
+                if (registerEditWay == 2) {
+                    this.updateFileStateForSubmit(ctx, recRegisterInfo.getResumeBaseRec().getId().toString());
+                }
+            }
+        } else {
+            // 无招聘登记记录时,基于简历创建预入职信息
+            preEntryInfo = this.addNewPreEntryByResume(ctx, offer, isSSC, preEntryInfo);
+        }
+
+        // 标记简历为无效状态
+        RecRegisterService.getInstance().invalidResume(ctx, offer.getResumeBaseRec().getId().toString());
+
+        // 执行预入职后的后续处理逻辑
+        this.afterPreEntry(ctx, offer);
+
+        return preEntryInfo;
+    }
+
+
+    /**
+     * 同步简历信息到预入职人员信息
+     * <p>
+     * 该方法用于将简历中的各项信息同步到预入职人员对象中,包括基本信息、头像、联系方式、工作经历、学历、
+     * 项目经验、语言能力、证书等,并最终调用扩展服务完成简历与预入职人员的关联。
+     * </p>
+     *
+     * @param ctx    上下文对象,用于获取服务实例和传递上下文信息
+     * @param person 预入职人员信息对象,作为信息同步的目标对象
+     * @param resume 简历基础信息对象,作为信息同步的来源对象
+     */
+    public void syncResumeToPEPerson(Context ctx, PreEntryPersonInfo person, ResumeBaseRecInfo resume) {
+        super.syncResumeToPEPerson(ctx, person, resume);
+        if (person != null) {
+            logger.error("***************************同步简历附件到预入职开始***************************");
+            //预入职id
+            String id = person.getId().toString();
+            //简历id
+            String resumeId = resume.getId().toString();
+            try {
+                //删除简历附件
+                String filter = "where boid = '" + id + "' and (attachment.name like '%标准简历%' or attachment.name like '%面试评价%' or attachment.name like '%原始简历%' or attachment.name like '%背景调查审批表%' )";
+                AttachmentUtils.deleteAttachment(ctx, filter);
+                ISHRAttachmentExt ishrAttachmentExt = SHRAttachmentExtFactory.getLocalInstance(ctx);
+                SHRAttachmentExtCollection shrAttachmentExtCollection =
+                        ishrAttachmentExt.getSHRAttachmentExtCollection("select attachment.* where boID = '" + resumeId + "'");
+                String uipk = "hr.preentry.resume.base";//预入职人员_基本信息
+                for (int i = 0; i < shrAttachmentExtCollection.size(); i++) {
+                    SHRAttachmentExtInfo shrAttachmentExtInfo = shrAttachmentExtCollection.get(i);
+                    AttachmentInfo attachmentInfo = shrAttachmentExtInfo.getAttachment();
+                    if (attachmentInfo == null || attachmentInfo.getFile() == null) {
+                        continue;
+                    }
+                    String type = attachmentInfo.getSimpleName();
+                    String fileName = attachmentInfo.getName();
+                    byte[] file = attachmentInfo.getFile();
+                    //上传附件
+                    HRAttachmentUploadUtil.uploadAttachment(ctx, file, type, fileName, id, uipk, "null0");
+                }
+            } catch (Exception e) {
+                logger.error(e.getMessage(), e);
+            }
+            logger.error("***************************同步简历附件到预入职结束***************************");
+        }
+    }
+
+
+    /**
+     * 同步人员基本信息
+     *
+     * @param person 人员信息对象
+     * @param resume 简历基本信息对象
+     * @param ctx    上下文环境
+     * @return 同步后的人员信息对象
+     */
+    public PreEntryPersonInfo syncPersonBaseInfo(PreEntryPersonInfo person, ResumeBaseRecInfo resume, Context ctx) {
+        super.syncPersonBaseInfo(person, resume, ctx);
+        //简历id
+        try {
+            String resumeId = resume.getId().toString();
+            IRecApproval iRecApproval = RecApprovalFactory.getLocalInstance(ctx);
+            RecApprovalCollection recApprovalCollection =
+                    iRecApproval.getRecApprovalCollection("where resumeBaseRec = '" + resumeId + "'");
+            if (!recApprovalCollection.isEmpty()) {
+                //获取招聘审批信息
+                RecApprovalInfo recApprovalInfo = recApprovalCollection.get(0);
+                //获取背调信息
+                String personalScreening = recApprovalInfo.getPersonalScreening();
+                if (StringUtils.isNotBlank(personalScreening)) {
+                    person.put("personalScreening", personalScreening);
+                }
+            }
+        } catch (BOSException e) {
+            logger.error(e.getMessage(), e);
+        }
+        return person;
+    }
+}

+ 227 - 7
websrc/com/kingdee/shr/recuritment/web/handler/OfferListHandlerEx.java

@@ -1,16 +1,29 @@
 package com.kingdee.shr.recuritment.web.handler;
 
+import com.kingdee.bos.BOSException;
 import com.kingdee.bos.Context;
+import com.kingdee.bos.ctrl.reportone.r1.form.engine.x.util.StringUtil;
+import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
+import com.kingdee.bos.metadata.entity.*;
+import com.kingdee.bos.metadata.query.util.CompareType;
+import com.kingdee.eas.common.EASBizException;
 import com.kingdee.eas.custom.recuritment.task.BeisenTransferPhaseFacadeFactory;
 import com.kingdee.eas.custom.recuritment.task.IBeisenTransferPhaseFacade;
+import com.kingdee.shr.base.syssetting.api.bean.BatchMessageTipsBody;
+import com.kingdee.shr.base.syssetting.api.bean.BatchMessageTipsHeader;
 import com.kingdee.shr.base.syssetting.context.SHRContext;
 import com.kingdee.shr.base.syssetting.exception.SHRWebException;
 import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
+import com.kingdee.shr.recuritment.*;
+import com.kingdee.shr.recuritment.service.offer.SyncResumeToPreServiceEx;
 import com.kingdee.util.StringUtils;
+import org.apache.log4j.Logger;
 import org.springframework.ui.ModelMap;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @Description offer列表
@@ -18,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
  * @Created by Heyuan
  */
 public class OfferListHandlerEx extends OfferListHandler {
+    private static final Logger logger = Logger.getLogger(OfferListHandlerEx.class);
     private Context ctx = SHRContext.getInstance().getContext();
 
     /**
@@ -82,12 +96,19 @@ public class OfferListHandlerEx extends OfferListHandler {
     }
 
     /**
-     * 转标准预备入职
+     * 将指定的录用单据转为标准预备入职状态。
+     * <p>
+     * 该方法会根据传入的 billId 参数,批量处理多个录用单据。对每个单据执行以下操作:
+     * 1. 验证单据是否满足转预备入职条件;
+     * 2. 若验证通过且未放弃入职,则调用服务将简历同步至标准预备入职;
+     * 3. 记录每条数据的处理结果(成功或失败);
+     * 4. 最后尝试将录用状态同步到北森系统。
+     * </p>
      *
-     * @param request
-     * @param response
-     * @param modelMap
-     * @throws SHRWebException
+     * @param request  HTTP 请求对象,用于获取请求参数(如 billId)
+     * @param response HTTP 响应对象,用于输出响应内容
+     * @param modelMap Spring MVC 的模型映射对象,可用于传递数据到视图层(本方法未使用)
+     * @throws SHRWebException 当业务处理过程中发生异常时抛出
      */
     @Override
     public void toPrePersonAction(
@@ -95,11 +116,90 @@ public class OfferListHandlerEx extends OfferListHandler {
             HttpServletResponse response,
             ModelMap modelMap
     ) throws SHRWebException {
-        super.toPrePersonAction(request, response, modelMap);
+        // 获取请求中的 billId 参数
         String billIds = request.getParameter("billId");
+        Context ctx = getContext();
+        IOffer iOffer;
+        try {
+            // 获取 Offer 服务实例
+            iOffer = OfferFactory.getLocalInstance(ctx);
+        } catch (BOSException e) {
+            logger.error(e.getMessage(), e);
+            throw new SHRWebException("系统错误,请联系管理员");
+        }
+        int success = 0;
+        int failure = 0;
+        BatchMessageTipsHeader batchMessageTipsHeader = new BatchMessageTipsHeader();
+
+        // 如果 billIds 不为空,则按逗号分割并逐个处理
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(billIds)) {
+            String[] ids = billIds.split(",");
+            for (int i = 0; i < ids.length; ++i) {
+                BatchMessageTipsBody body = new BatchMessageTipsBody();
+                body.setId(ids[i]);
+                Map<String, Object> map = new HashMap();
+
+                try {
+                    // 执行校验逻辑
+                    this.checkPass(ids[i], map);
+                    String error = (String) map.get("errorMsg");
+
+                    // 如果没有错误信息,则继续处理
+                    if (org.apache.commons.lang3.StringUtils.isEmpty(error)) {
+                        // 查询 Offer 信息
+                        OfferInfo offer = iOffer.getOfferInfo("select resumeBaseRec,preEntry.*,preEntry.talent.*,preEntryDate where id = '" + ids[i] + "' ");
+
+                        // 如果该 Offer 没有被放弃入职
+                        if (!offer.isGiveUpEntry()) {
+                            SyncResumeToPreServiceEx syncResumeToPreServiceEx = new SyncResumeToPreServiceEx();
+                            // 添加标准预备入职记录
+                            syncResumeToPreServiceEx.addNewPreEntryByResume(ctx, offer, false);
+                        }
+
+                        ++success;
+                        body.setMuitTipsState(Boolean.TRUE);
+                        body.setMuitTipsMessage("操作成功!");
+                        batchMessageTipsHeader.addResult(body);
+                    } else {
+                        // 校验失败,记录失败原因
+                        ++failure;
+                        body.setMuitTipsState(Boolean.FALSE);
+                        body.setMuitTipsMessage(error);
+                        batchMessageTipsHeader.addResult(body);
+                    }
+                } catch (EASBizException e) {
+                    logger.error(e.getMessage(), e);
+                    ++failure;
+                    body.setMuitTipsState(Boolean.FALSE);
+                    body.setMuitTipsMessage("预入职失败!" + e.getMessage());
+                    batchMessageTipsHeader.addResult(body);
+                } catch (BOSException e) {
+                    logger.error(e.getMessage(), e);
+                    ++failure;
+                    body.setMuitTipsState(Boolean.FALSE);
+                    body.setMuitTipsMessage("预入职失败!" + e.getMessage());
+                    batchMessageTipsHeader.addResult(body);
+                } catch (SHRWebException e) {
+                    logger.error(e.getMessage(), e);
+                    ++failure;
+                    body.setMuitTipsState(Boolean.FALSE);
+                    body.setMuitTipsMessage("预入职失败!" + e.getMessage());
+                    batchMessageTipsHeader.addResult(body);
+                }
+            }
+        }
+
+        // 设置批量处理结果统计信息
+        batchMessageTipsHeader.setBillId(billIds);
+        batchMessageTipsHeader.setFailureCount(failure);
+        batchMessageTipsHeader.setSuccessCount(success);
+
+        // 输出处理结果
+        this.writeSuccessData(batchMessageTipsHeader);
+
+        // 同步录用报批状态至北森系统
         try {
             if (!StringUtils.isEmpty(billIds)) {
-                //同步录用报批状态至北森
                 IBeisenTransferPhaseFacade iBeisenTransferPhaseFacade =
                         BeisenTransferPhaseFacadeFactory.getLocalInstance(ctx);
                 iBeisenTransferPhaseFacade.syncOfferToBeisen(billIds, 0);
@@ -110,6 +210,126 @@ public class OfferListHandlerEx extends OfferListHandler {
         }
     }
 
+
+    /**
+     * 检查候选人是否可以进入下一步流程(如简历投递等),主要判断该候选人是否正在被其他职位流程占用。
+     * 如果候选人当前处于“简历筛选”或其他招聘环节,则不允许重复使用,并提示相关信息。
+     *
+     * @param billId 候选人简历的唯一标识ID
+     * @param map    用于返回错误信息的Map对象,若检查不通过会填充state和errorMsg字段
+     * @return true表示可以通过,false表示已被占用或存在冲突
+     * @throws SHRWebException 当业务逻辑异常或系统异常时抛出
+     */
+    private boolean checkPass(String billId, Map<String, Object> map) throws SHRWebException {
+        StringBuffer msgBuffer = new StringBuffer("");
+        try {
+            // 获取当前简历在途的应聘记录集合
+            ResumeBaseRecCollection resumeColl = this.getOnWayResume(billId);
+            if (resumeColl != null && resumeColl.size() > 0) {
+                ResumeBaseRecInfo resumeBaseRec = resumeColl.get(0);
+                // 判断当前简历所处的状态是否为“简历筛选”
+                if ("简历筛选".equals(resumeBaseRec.getResumeState().getResumeStateType().getName())) {
+                    msgBuffer.append("当前候选人已被:");
+                    String positionName = "";
+                    // 获取职位名称(优先取recuritPosition,其次hrJob)
+                    if (resumeBaseRec.getRecuritPosition() != null) {
+                        positionName = resumeBaseRec.getRecuritPosition().getName();
+                    } else if (resumeBaseRec.getHrJob() != null) {
+                        positionName = resumeBaseRec.getHrJob().getName();
+                    }
+                    msgBuffer.append(positionName);
+                    msgBuffer.append("职位(");
+                    msgBuffer.append(resumeBaseRec.getDepartment().getName());
+                    msgBuffer.append("部门)");
+                    msgBuffer.append("的简历筛选环节所抢,可联系操作人");
+
+                    // 添加操作人信息
+                    if (resumeBaseRec.getProposer() != null) {
+                        msgBuffer.append(resumeBaseRec.getProposer().getName() + "解锁!");
+                    } else {
+                        msgBuffer.append("解锁!");
+                    }
+                } else {
+                    // 当前简历处于其他招聘环节
+                    msgBuffer.append("当前候选人正在:");
+                    String positionName = "";
+
+                    // 获取职位名称(优先取recuritPosition,其次hrJob)
+                    if (resumeBaseRec.getRecuritPosition() != null) {
+                        positionName = resumeBaseRec.getRecuritPosition().getName();
+                    } else if (resumeBaseRec.getHrJob() != null) {
+                        positionName = resumeBaseRec.getHrJob().getName();
+                    }
+                    msgBuffer.append(positionName);
+                    msgBuffer.append("职位(");
+                    msgBuffer.append(resumeBaseRec.getDepartment().getName());
+                    msgBuffer.append("部门)的");
+                    msgBuffer.append(resumeBaseRec.getResumeState().getResumeStateType().getName());
+                    msgBuffer.append("环节应聘!当在该职位上应聘不通过,才可释放使用!");
+                    // 查询最近处理人信息
+                    ApplyRecordCollection applyRecordCollection = ApplyRecordFactory.getRemoteInstance().getApplyRecordCollection("select creator.name where resumeBaseRec ='" + resumeBaseRec.getId() + "' order by createTime desc");
+                    if (null != applyRecordCollection && applyRecordCollection.size() > 0) {
+                        msgBuffer.append("可联系简历当前或者上一处理人:”" + applyRecordCollection.get(0).getCreator().getName() + "“释放");
+                    }
+                }
+                // 将错误信息放入map中返回
+                map.put("state", "error");
+                map.put("errorMsg", msgBuffer.toString());
+                return false;
+            } else {
+                // 无在途应聘记录,允许继续操作
+                return true;
+            }
+        } catch (EASBizException e) {
+            logger.error(e.getMessage(), e);
+            throw new ShrWebBizException(e.getMessage(), e);
+        } catch (BOSException e) {
+            logger.error(e.getMessage(), e);
+            throw new ShrWebBizException(e.getMessage(), e);
+        }
+    }
+
+
+    /**
+     * 获取在途简历信息
+     *
+     * @param offerId 申请单ID
+     * @return 简历基础信息集合
+     * @throws BOSException    业务对象服务异常
+     * @throws EASBizException EAS业务异常
+     */
+    private ResumeBaseRecCollection getOnWayResume(String offerId) throws BOSException, EASBizException {
+        ResumeBaseRecCollection resumeColl = null;
+        SelectorItemCollection sel = new SelectorItemCollection();
+        sel.add(new SelectorItemInfo("*"));
+        sel.add(new SelectorItemInfo("resumeBaseRec.*"));
+        // 根据offerId获取申请单信息
+        OfferInfo offer = OfferFactory.getRemoteInstance().getOfferInfo(new ObjectUuidPK(offerId), sel);
+        String ifSimplePerson = offer.getResumeBaseRec().getIfSimplePerson();
+        if (!StringUtil.isEmpty(ifSimplePerson)) {
+            // 构造查询条件:相同简单人员标识、已处理状态、排除当前记录
+            EntityViewInfo evi = new EntityViewInfo();
+            FilterInfo filter = new FilterInfo();
+            filter.getFilterItems().add(new FilterItemInfo("ifSimplePerson", ifSimplePerson, CompareType.EQUALS));
+            filter.getFilterItems().add(new FilterItemInfo("TransactionState", TransactionStateEnum.PROCESSED.getValue(), CompareType.EQUALS));
+            filter.getFilterItems().add(new FilterItemInfo("id", offer.getResumeBaseRec().getId().toString(), CompareType.NOTEQUALS));
+            // 设置需要查询的字段
+            SelectorItemCollection sic = evi.getSelector();
+            sic.add(new SelectorItemInfo("department.name"));
+            sic.add(new SelectorItemInfo("recuritPosition.name"));
+            sic.add(new SelectorItemInfo("hrJob.name"));
+            sic.add(new SelectorItemInfo("resumeState.resumeStateType.name"));
+            sic.add(new SelectorItemInfo("proposer.name"));
+            evi.setFilter(filter);
+            evi.setSelector(sic);
+            // 执行查询获取在途简历集合
+            IResumeBaseRec iResumeBaseRec = ResumeBaseRecFactory.getRemoteInstance();
+            resumeColl = iResumeBaseRec.getResumeBaseRecCollection(evi);
+        }
+        return resumeColl;
+    }
+
+
     /**
      * 反终止
      *