/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the yifu4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.yifu.cloud.plus.v1.yifu.archives.service.impl;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasc.open.api.exception.ApiException;
import com.yifu.cloud.plus.v1.csp.vo.EmployeeRegistrationBatchErrorVo;
import com.yifu.cloud.plus.v1.csp.vo.TEmployeeContractDateVo;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysUser;
import com.yifu.cloud.plus.v1.yifu.archives.config.WxConfig;
import com.yifu.cloud.plus.v1.yifu.archives.constants.EmployeeConstants;
import com.yifu.cloud.plus.v1.yifu.archives.entity.*;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.*;
import com.yifu.cloud.plus.v1.yifu.archives.service.*;
import com.yifu.cloud.plus.v1.yifu.archives.utils.ContractTermCalculator;
import com.yifu.cloud.plus.v1.yifu.archives.vo.*;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ClientNameConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.SecurityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import com.yifu.cloud.plus.v1.yifu.common.core.util.bean.BeanCopyUtils;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.SocialDaprUtils;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.UpmsDaprUtils;
import com.yifu.cloud.plus.v1.yifu.common.mybatis.base.BaseEntity;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import com.yifu.cloud.plus.v1.yifu.insurances.util.LocalDateUtil;
import com.yifu.cloud.plus.v1.yifu.social.vo.TEmployeeInsuranceWorkDayVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 合同续签预派单信息
 *
 * @author fxj
 * @date 2026-02-05 15:45:40
 */
@Log4j2
@RequiredArgsConstructor
@Service
public class TEmployeeContractPreNewServiceImpl extends ServiceImpl<TEmployeeContractPreNewMapper, TEmployeeContractPreNew> implements TEmployeeContractPreNewService {

	@Autowired
	private TEmployeeContractInfoMapper contractInfoMapper;

	@Autowired
	private TEmpContractAlertMapper empContractAlertMapper;
	@Autowired
	private TContractAutoLogService contractAutoLogService;
	@Autowired
	private TEmployeeContractInfoService contractInfoService;

	private final FascService fascService;

	private final TEmployeeContractAuditService tEmployeeContractAuditService;

	@Autowired
	private WxConfig wxConfig;

	@Autowired
	private UpmsDaprUtils upmsDaprUtils;

	@Autowired
	private SocialDaprUtils socialDaprUtils;

	@Autowired
	private ContractTermCalculator calculator = new ContractTermCalculator();

	@Autowired
	private TAutoContractSchemeMapper contractSchemeMapper;

	@Autowired
	private TAutoContractRuleInfoMapper contractRuleInfoMapper;

	@Autowired
	private TEmployeeContractPreHistoryMapper preHistoryMapper;

	/**
	 * 合同续签预派单信息简单分页查询
	 *
	 * @param tEmployeeContractPreNew 合同续签预派单信息
	 * @return
	 */
	@Override
	public IPage<TEmployeeContractPreNew> getTEmployeeContractPreNewPage(Page<TEmployeeContractPreNew> page, TEmployeeContractPreNewSearchVo tEmployeeContractPreNew) {
		return baseMapper.getTEmployeeContractPreNewPage(page, tEmployeeContractPreNew);
	}

	/**
	 * 合同续签预派单信息批量导出
	 *
	 * @param searchVo 合同续签预派单信息
	 * @return
	 */
	@Override
	public void listExport(HttpServletResponse response, TEmployeeContractPreNewSearchVo searchVo) {
		String fileName = "合同续签预派单信息批量导出" + DateUtil.getThisTime() + ".xlsx";
		//获取要导出的列表
		List<TEmployeeContractPreNew> list = new ArrayList<>();
		long count = noPageCountDiy(searchVo);
		ServletOutputStream out = null;
		try {
			out = response.getOutputStream();
			response.setContentType(CommonConstants.MULTIPART_FORM_DATA);
			response.setCharacterEncoding("utf-8");
			response.setHeader(CommonConstants.CONTENT_DISPOSITION, CommonConstants.ATTACHMENT_FILENAME + URLEncoder.encode(fileName, CommonConstants.UTF8));
			// 这里 需要指定写用哪个class去写，然后写到第一个sheet，然后文件流会自动关闭
			//EasyExcel.write(out, TEmpBadRecord.class).sheet("不良记录").doWrite(list);
			ExcelWriter excelWriter = EasyExcel.write(out, TEmployeeContractPreNew.class).build();
			int index = 0;
			if (count > CommonConstants.ZERO_INT) {
				for (int i = 0; i <= count; ) {
					// 获取实际记录
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT);
					list = noPageDiy(searchVo);
					if (Common.isNotNull(list)) {
						ExcelUtil<TEmployeeContractPreNew> util = new ExcelUtil<>(TEmployeeContractPreNew.class);
						for (TEmployeeContractPreNew vo : list) {
							util.convertEntity(vo, null, null, null);
						}
					}
					if (Common.isNotNull(list)) {
						WriteSheet writeSheet = EasyExcel.writerSheet("合同续签预派单信息" + index).build();
						excelWriter.write(list, writeSheet);
						index++;
					}
					i = i + CommonConstants.EXCEL_EXPORT_LIMIT;
					if (Common.isNotNull(list)) {
						list.clear();
					}
				}
			} else {
				WriteSheet writeSheet = EasyExcel.writerSheet("合同续签预派单信息" + index).build();
				excelWriter.write(list, writeSheet);
			}
			if (Common.isNotNull(list)) {
				list.clear();
			}
			out.flush();
			excelWriter.finish();
		} catch (Exception e) {
			log.error("执行异常", e);
		} finally {
			try {
				if (null != out) {
					out.close();
				}
			} catch (IOException e) {
				log.error("执行异常", e);
			}
		}
	}

	@Override
	public List<TEmployeeContractPreNew> noPageDiy(TEmployeeContractPreNewSearchVo searchVo) {
		LambdaQueryWrapper<TEmployeeContractPreNew> wrapper = buildQueryWrapper(searchVo);
		List<String> idList =searchVo.getIds();
		if (Common.isNotNull(idList)) {
			wrapper.in(TEmployeeContractPreNew::getId, idList);
		}
		if (searchVo.getLimitStart() >= 0 && searchVo.getLimitEnd() > 0) {
			wrapper.last(" limit " + searchVo.getLimitStart() + "," + searchVo.getLimitEnd());
		}
		wrapper.orderByDesc(BaseEntity::getCreateTime);
		return baseMapper.selectList(wrapper);
	}

	private Long noPageCountDiy(TEmployeeContractPreNewSearchVo searchVo) {
		LambdaQueryWrapper<TEmployeeContractPreNew> wrapper = buildQueryWrapper(searchVo);
		List<String> idList = searchVo.getIds();
		if (Common.isNotNull(idList)) {
			wrapper.in(TEmployeeContractPreNew::getId, idList);
		}
		return baseMapper.selectCount(wrapper);
	}

	private LambdaQueryWrapper buildQueryWrapper(TEmployeeContractPreNewSearchVo entity) {
		LambdaQueryWrapper<TEmployeeContractPreNew> wrapper = Wrappers.lambdaQuery();
		if (ArrayUtil.isNotEmpty(entity.getCreateTimes())) {
			wrapper.ge(TEmployeeContractPreNew::getCreateTime, entity.getCreateTimes()[0])
					.le(TEmployeeContractPreNew::getCreateTime,
							entity.getCreateTimes()[1]);
		}
		if (Common.isNotNull(entity.getCreateName())) {
			wrapper.eq(TEmployeeContractPreNew::getCreateName, entity.getCreateName());
		}
		return wrapper;
	}
	/**
	 * @Author fxj
	 * @Description 合同待续签单个确认
	 * @Date 10:41 2026/2/9
	 * @Param
	 * @return
	**/
	@Override
	public R confirmRenewalContract(TEmployeeContractPreNewVo preVo) {
		if (!Common.isNotNull(preVo) || !Common.isNotNull(preVo.getContractId())) {
			return R.failed(CommonConstants.PARAM_INFO_ERROR);
		}
		TEmployeeContractInfo contract = contractInfoMapper.selectById(preVo.getContractId());
		if (contract == null){
			return R.failed(EmployeeConstants.DATA_CAN_NOT_FOUND);
		}
		long  preNewCount = 0;
		if (Common.isNotNull(preVo.getId())){
			preNewCount = baseMapper.selectCount(Wrappers.<TEmployeeContractPreNew>query().lambda()
					.eq(TEmployeeContractPreNew::getContractId, preVo.getContractId())
					.ne(TEmployeeContractPreNew::getId, preVo.getId()));
		}else {
			preNewCount = baseMapper.selectCount(Wrappers.<TEmployeeContractPreNew>query().lambda().eq(TEmployeeContractPreNew::getContractId, preVo.getContractId()));
		}
		if (preNewCount > CommonConstants.ZERO_INT){
			return R.failed("已存在确认数据，请确认后重试");
		}
		//电子签判断预计发起时间是否为当前时间的一个月前
		if (Common.isNotNull(preVo.getExpectedCollectionTime())
				&& CommonConstants.ZERO_STRING.equals(preVo.getSignType())
				&& null != preVo.getContractStart()){
			LocalDate reminderDate = LocalDateUtil.parseLocalDate(DateUtil.dateToString(preVo.getExpectedCollectionTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
			LocalDate contractStartDateNew = parseContractEndDate(preVo.getContractStart());
			if (null != contractStartDateNew && reminderDate.isAfter(contractStartDateNew.plusMonths(1))){
				return R.failed(EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR);
			}
		}
		//电子签判断合同开始时间是否为当前时间的一个月前
		if (Common.isNotNull(preVo.getContractStart())
				&& CommonConstants.ZERO_STRING.equals(preVo.getSignType())){
			LocalDate reminderDate = LocalDateUtil.parseLocalDate(DateUtil.dateToString(preVo.getContractStart(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
			LocalDate nowDate = LocalDate.now();
			if (null != nowDate && nowDate.isAfter(reminderDate.plusMonths(1))){
				return R.failed(EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO);
			}
		}
		////如果电子签是系统自动撤销对应的签署方式必须更新为 线下签
		TEmployeeContractPreNew preNew = null;
		if (Common.isNotNull(preVo.getId()) && CommonConstants.ZERO_STRING.equals(preVo.getSignType())){
			preNew = baseMapper.selectById(preVo.getId());
			if (preNew != null && CommonConstants.ELEVEN_STRING.equals(preNew.getProcessStatus())){
				return R.failed(EmployeeConstants.DATA_CONTRACT_CANCEL_MUST_OFFLINE_SIGN);
			}
		}
		//判断两个合同时间是否重合
		if (LocalDateUtil.hasOverlap(contract.getContractStart(),contract.getContractEnd(),preVo.getContractStart(),preVo.getContractEnd())){
			return R.failed(EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO);
		}
		TEmpContractAlert alert = empContractAlertMapper.selectOne(Wrappers.<TEmpContractAlert>query().lambda()
				.eq(TEmpContractAlert::getContractId,preVo.getContractId())
				.last(CommonConstants.LAST_ONE_SQL));
		if (null == alert){
			return R.failed("未找到合同续签待办信息");
		}
		TEmployeeContractPreNew pre = new TEmployeeContractPreNew();
		BeanCopyUtils.copyProperties(preVo,pre);
		pre.setProcessStatus(CommonConstants.ONE_STRING);
		pre.setCustomerUsername(alert.getCsName());
		pre.setCustomerUserLoginname(alert.getCsLoginName());
		pre.setDeptName(alert.getProject());
		pre.setDeptNo(alert.getProjectNo());
		pre.setEmployeeName(alert.getEmpName());
		pre.setEmpIdcard(alert.getEmpIdcard());
		pre.setDeptId(alert.getDeptId());
		pre.setEmpPhone(alert.getEmpPhone());
		pre.setEmployeeNature(alert.getEmpType());
		pre.setPosition(alert.getPost());
		pre.setIsUrg(CommonConstants.ZERO_STRING);
		pre.setOverFlag(CommonConstants.ONE_STRING);
		pre.setSignFlag(CommonConstants.ONE_STRING);
		String errorInfo = initDateInfo(pre,contract);
		if (null != errorInfo){
			return R.failed(errorInfo);
		}
		int res = -1;
		if (Common.isNotNull(pre.getId())){
			res = baseMapper.updateById(pre);
		}else {
			res = baseMapper.insert(pre);
		}
		if (res >= 0){
			return R.ok();
		}else {
			return R.failed(CommonConstants.RESULT_DATA_FAIL);
		}
	}
	/**
	 * @Author fxj
	 * @Description 入职待确认表 批量确认接收
	 * @Date 10:40 2026/2/9
	 * @Param
	 * @return
	**/
	@Override
	public R batchCconfirmRenewalContract(TEmployeeContractPreNewVo preVo) {
		if (!Common.isNotNull(preVo) || !Common.isNotNull(preVo.getContractIds())) {
			return R.failed(CommonConstants.PARAM_INFO_ERROR);
		}
		List<String> contractIds  = preVo.getContractIds();
		List<TEmployeeContractInfo> contractList = contractInfoMapper.selectBatchIds(contractIds);
		if (contractList == null || contractList.size() <= 0){
			return R.failed(EmployeeConstants.DATA_CAN_NOT_FOUND);
		}
		List<TEmpContractAlert> alertList = empContractAlertMapper.selectList(Wrappers.<TEmpContractAlert>query().lambda()
				.in(TEmpContractAlert::getContractId,contractIds)
				.groupBy(TEmpContractAlert::getContractId));
		Map<String, TEmpContractAlert> alertMap = new HashMap<>();
		if (alertList != null){
			alertMap = alertList.stream().filter(v -> v.getContractId() != null)
					.collect(Collectors.toMap(TEmpContractAlert::getContractId, v -> v));
		}
		List<TEmployeeContractPreNew> exsitPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query().lambda()
				.in(TEmployeeContractPreNew::getContractId,contractIds));
		Map<String, String> preMap = new HashMap<>();
		if (exsitPreList != null){
			preMap = exsitPreList.stream().filter(v -> v.getContractId() != null)
					.collect(Collectors.toMap(TEmployeeContractPreNew::getContractId,  v -> v.getId()));
		}
		TAutoContractScheme scheme = null;
		if (null != preVo.getConfigId()){
			scheme = contractSchemeMapper.selectById(preVo.getConfigId());
		}
		TAutoContractRuleInfo rule = null;
		if (null != scheme){
			rule = contractRuleInfoMapper.selectOne(Wrappers.<TAutoContractRuleInfo>query().lambda()
					.eq(TAutoContractRuleInfo::getDeptNo,scheme.getDeptNo())
					.last(CommonConstants.LAST_ONE_SQL));
		}
		TEmployeeContractPreNew pre = null;
		List<TEmployeeContractPreNew> preList = new ArrayList<>();
		List<TEmployeeAutoRegistCheckVo> errorList = new ArrayList<>();
		TEmployeeAutoRegistCheckVo checkVo;
		TEmpContractAlert alert = null;
		//已合同Id 组建map
		ContractAlertConfirmResVo temp = null;
		TEmployeeContractPreNewVo preVoTemp = null;
		for (TEmployeeContractInfo contract : contractList){
			preVoTemp= new TEmployeeContractPreNewVo();
			BeanCopyUtils.copyProperties(preVo,preVoTemp);
			alert = alertMap.get(contract.getId());
			temp = new ContractAlertConfirmResVo();
			temp.setContractId(contract.getId());
			temp.setContractEnd(null==contract.getContractEnd()?"":DateUtil.dateToString(contract.getContractEnd(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
			temp.setContractStart(null==contract.getContractStart()?"":DateUtil.dateToString(contract.getContractStart(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
			temp.setEmpIdcard(contract.getEmpIdcard());
			temp.setEmpName(contract.getEmpName());
			temp.setContractType(preVoTemp.getContractName());
			if ("0".equals(preVoTemp.getSignType())){
				temp.setSignType("电子签");
			}else {
				temp.setSignType("线下签");
			}
			temp.setSignatory(preVoTemp.getSignatory());

			checkVo = check(preMap, scheme, rule, alert, preVoTemp, contract);
			if (null != checkVo){
				if (null != temp ) {
					if (null != alert){
						temp.setDeptNo(alert.getProjectNo());
						temp.setDeptName(alert.getProject());
					}
					temp.setErrorMsg(checkVo.getErrorMsg());
					temp.setPost(preVoTemp.getPost());
					temp.setContractEndNew(null==preVoTemp.getContractEnd()?"":DateUtil.dateToString(preVoTemp.getContractEnd(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
					temp.setContractStartNew(null==preVoTemp.getContractStart()?"":DateUtil.dateToString(preVoTemp.getContractStart(), DateUtil.ISO_EXPANDED_DATE_FORMAT));
					temp.setSignType(preVoTemp.getSignType());
					checkVo.setConfirmVo(temp);
				}
				errorList.add(checkVo);
				continue;
			}
			pre = new TEmployeeContractPreNew();
			BeanCopyUtils.copyProperties(preVoTemp,pre);
			pre.setContractId(contract.getId());
			pre.setProcessStatus(CommonConstants.ONE_STRING);
			if (null != alert){
				pre.setCustomerUsername(alert.getCsName());
				pre.setCustomerUserLoginname(alert.getCsLoginName());
				pre.setDeptName(alert.getProject());
				pre.setDeptNo(alert.getProjectNo());
				pre.setEmployeeName(alert.getEmpName());
				pre.setEmpIdcard(alert.getEmpIdcard());
				pre.setDeptId(alert.getDeptId());
				pre.setEmpPhone(alert.getEmpPhone());
				pre.setEmployeeNature(alert.getEmpType());
				pre.setIsUrg(CommonConstants.ZERO_STRING);
				pre.setOverFlag(CommonConstants.ONE_STRING);
				pre.setSignFlag(CommonConstants.ONE_STRING);
			}

			preList.add(pre);
		}
		boolean res = false;
		if (preList != null && preList.size() > 0){
			res = this.saveBatch(preList);
		}else {
			res = true;
		}
		if (res){
			if (!errorList.isEmpty()) {
				EmployeeRegistrationBatchErrorVo batchErrorVo = new EmployeeRegistrationBatchErrorVo();
				batchErrorVo.setErrorList(errorList);
				return R.other(CommonConstants.TWO_INT, null, batchErrorVo);
			}else {
				return R.ok();
			}
		}else {
			return R.failed(CommonConstants.RESULT_DATA_FAIL);
		}
	}

	private TEmployeeAutoRegistCheckVo check(Map<String, String> preMap, TAutoContractScheme scheme,
						  TAutoContractRuleInfo rule,
						  TEmpContractAlert alert,
						  TEmployeeContractPreNewVo preVoTemp,
						  TEmployeeContractInfo contract) {
		String preId;
		String initError;
		if (null == alert){
			return buildErrorCheckVo(contract, preVoTemp, EmployeeConstants.ERROR_NO_ALERT_FOUND);
		}
		preId = preMap.get(contract.getId());
		if (Common.isNotNull(preId)){
			return buildErrorCheckVo(contract, preVoTemp, EmployeeConstants.ERROR_DUPLICATE_CONFIRM);
		}
		//初始化数据
		initError = initDateInfo(preVoTemp, contract);
		if (Common.isNotNull(initError)){
			return buildErrorCheckVo(contract, preVoTemp, initError);
		}

		//判断两个合同时间是否重合
		if (LocalDateUtil.hasOverlap(contract.getContractStart(), contract.getContractEnd(), preVoTemp.getContractStart(), preVoTemp.getContractEnd())){
			return buildErrorCheckVo(contract, preVoTemp, EmployeeConstants.DATA_CONTRACT_OVERLAP);
		}
		//如果电子签是系统自动撤销对应的签署方式必须更新为 线下签， 如果是批量确认 有已确认直接提示了不做这个判断
		//初始化岗位名称

		if (Common.isNotNull(preVoTemp.getConfigId()) && "固定岗位".equals(preVoTemp.getPost()) && null != scheme){
			preVoTemp.setPost(scheme.getPost());
		}else {
			//等于上一份合同的岗位明细
			preVoTemp.setPost(contract.getPost());
		}
		//处理预计发起时间

		//上一份合同到期前第5个工作日:  20251229（含）前第5个工作日_25年12月23日，若是已过去的时间，则按照当前日期（含）往后继续找工作日，若超过一个月后了，
		// 则也呈现，但是只能是线下签
		// 计算往前3个工作日
		if (null != rule && null != contract.getContractEnd()) {
			// 解析合同结束日期
			LocalDate contractEndDate = parseContractEndDate(contract.getContractEnd());
			if (null == contractEndDate) {
				return buildErrorCheckVo(contract, preVoTemp, "合同结束日期解析失败");
			}

			// 计算预计发起日期
			LocalDate reminderDate = calculateReminderDate(preVoTemp.getRenewalDateType(), contractEndDate);
			if (null == reminderDate) {
				return buildErrorCheckVo(contract, preVoTemp, "预计发起时间初始化失败");
			}

			// 当前时间之前调整提醒日期为最近工作日
			reminderDate = adjustToNearestWorkday(reminderDate);
			// 检查电子签是否超期(和续签的合同开始日期进行比较)
			if (null != preVoTemp.getContractStart() && CommonConstants.ZERO_STRING.equals(preVoTemp.getSignType())){
				LocalDate contractStartDateNew = parseContractEndDate(preVoTemp.getContractStart());
				if (null == contractStartDateNew) {
					return buildErrorCheckVo(contract, preVoTemp, "续签合同开始日期解析失败");
				}
				if (reminderDate.isAfter(contractStartDateNew.plusMonths(1))) {
					return buildErrorCheckVo(contract, preVoTemp, EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO);
				}
			}
			//reminderDate 设置15:20
			Date reminderDateNew =DateUtil.getDateByLocalDate(reminderDate);
			reminderDateNew.setHours(15);
			reminderDateNew.setMinutes(20);
			// 设置预计发起时间
			preVoTemp.setExpectedCollectionTime(reminderDateNew);
		}
		return null;
	}

	/**
	 * 解析合同结束日期
	 */
	private LocalDate parseContractEndDate(Date contractEnd) {
		try {
			return LocalDateUtil.parseLocalDate(DateUtil.dateToString(contractEnd, DateUtil.ISO_EXPANDED_DATE_FORMAT) + " 15:20");
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 根据规则类型计算提醒日期
	 */
	private LocalDate calculateReminderDate(String renewalDateType, LocalDate contractEndDate) {
		if (CommonConstants.ZERO_STRING.equals(renewalDateType)) {
			return calculateReminderWorkDaysBefore(contractEndDate, 5, 0);
		} else if (CommonConstants.ONE_STRING.equals(renewalDateType)) {
			return calculateReminderWorkDaysBefore(contractEndDate, 10, 1);
		}
		return null;
	}

	/**
	 * 判断是否强制走线下签
	 */
	private boolean shouldEnforceOfflineSign(LocalDate reminderDate, String signType) {
		return reminderDate.isBefore(LocalDate.now().plusMonths(1).minusDays(1))
				&& CommonConstants.ZERO_STRING.equals(signType);
	}

	/**
	 * 构建错误检查对象
	 */
	private TEmployeeAutoRegistCheckVo buildErrorCheckVo(TEmployeeContractInfo contract, TEmployeeContractPreNewVo preVo, String errorMsg) {
		TEmployeeAutoRegistCheckVo checkVo = new TEmployeeAutoRegistCheckVo();
		if (null != contract){
			checkVo.setEmployeeName(contract.getEmpName());
			checkVo.setEmpIdcard(contract.getEmpIdcard());
		}
		if (null != preVo){
			checkVo.setDeptName(preVo.getDeptName());
			checkVo.setDeptNo(preVo.getDeptNo());
		}
		checkVo.setType(EmployeeConstants.ERROR_TYPE_CONTRACT); // 可配置化处理
		checkVo.setErrorMsg(errorMsg);
		return checkVo;
	}

	/**
	 * 调整日期为最近工作日
	 */
	private LocalDate adjustToNearestWorkday(LocalDate date) {
		return date.isBefore(LocalDate.now()) ? calculateReminderWorkDaysBefore(LocalDate.now(), 1, 0) : date;
	}

	private String initDateInfo(TEmployeeContractPreNewVo preVo, TEmployeeContractInfo contract) {
		TEmployeeContractDateVo vo;
		//标准合同/劳务协议/实习协议/劳务派遣合同/非全日制/其他合同
		//1:"标准合同，3:“劳务协议”，5:“实习协议,8:“非全日制’，9:"补贴合同，13:’见习协议，18:“兼职协议”,19:”临时聘用合同，20:"劳务派遣合同’，21:’其他
		if (!CommonConstants.FIVE_STRING.equals(preVo.getContractType())){
			//合同开始日期=上一份合同截止日期+1日
			preVo.setContractStart(DateUtil.addDayByDate(contract.getContractEnd(),1));
			//单个确认中，针对预计合同发起时间、合同开始日期、合同截止日期的信息为显示具体日期，而批量确认显示的是规则文字，具体确认完毕至每条的续签信息中时，才显示具体日期 TODO
			//增加“合同开始日期规则、合同截止日期规则”信息
			//——合同开始日期规则，只有一种：等于上一份合同截止日期+1日，文字显示
			//——合同截止日期规则，有两种：①合同年限推算；②固定截止日期；
			//规则确定后，对应到人员头上，显示具体的合同开始日期、合同截止日期；
			if (Common.isNotNull(preVo.getContractEndType())){
				if (CommonConstants.ZERO_STRING.equals(preVo.getContractEndType())){
					//合同年限推算
					if (Common.isNotNull(preVo.getContractStart())
							&& Common.isEmpty(preVo.getContractEnd())
							&& Common.isNotNull(preVo.getContractDurationYear())
							&& Common.isNotNull(preVo.getContractDurationMonth())
					) {
						vo = new TEmployeeContractDateVo();
						vo.setMonthAfter(Integer.parseInt(Common.isEmpty(preVo.getContractDurationMonth()) ? "0": preVo.getContractDurationMonth()));
						vo.setYearAfter(Integer.parseInt(Common.isEmpty(preVo.getContractDurationYear()) ? "0": preVo.getContractDurationYear()));
						vo.setRegistDate(preVo.getContractStart());
						preVo.setContractEnd(this.addYearsMonths(vo));
					}
				} else if (CommonConstants.ONE_STRING.equals(preVo.getContractEndType())
						|| CommonConstants.THREE_STRING.equals(preVo.getContractEndType())){
					//处理合同年限
					ContractTermCalculator.ContractTerm term = calculator.calculateTerm(
							DateUtil.formatDatePatten(preVo.getContractStart(),DateUtil.ISO_EXPANDED_DATE_FORMAT),
							DateUtil.formatDatePatten(preVo.getContractEnd(),DateUtil.ISO_EXPANDED_DATE_FORMAT));
					if (term != null){
						preVo.setContractDurationYear(Integer.toString(term.getYears()));
						preVo.setContractDurationMonth(Integer.toString(term.getMonths()));
					}else {
						return "合同年限推算错误";
					}
				}
			}
		}
		if (CommonConstants.FIVE_STRING.equals(preVo.getContractType())){
			//处理实习协议
			preVo.setInternshipPeriodStart(DateUtil.addDayByDate(contract.getContractEnd(),1));
			preVo.setContractStart(DateUtil.addDayByDate(contract.getContractEnd(),1));
			if (Common.isNotNull(preVo.getInternshipPeriod())){
				vo = new TEmployeeContractDateVo();
				vo.setMonthAfter(Integer.parseInt(Common.isEmpty(preVo.getInternshipPeriod()) ? "0": preVo.getInternshipPeriod()));
				vo.setYearAfter(0);
				vo.setRegistDate(preVo.getInternshipPeriodStart());
				preVo.setInternshipPeriodEnd(this.addYearsMonths(vo));
				preVo.setContractEnd(preVo.getInternshipPeriodEnd());
			}
			if (Common.isNotNull(preVo.getInternshipPeriodStart()) && Common.isNotNull(preVo.getInternshipPeriodEnd())){
				if (preVo.getInternshipPeriodEnd().before(preVo.getInternshipPeriodStart())){
					return "实习结束日期需大于等于实习开始日期";
				}
			}
		}
		if (CommonConstants.TWENTY_STRING.equals(preVo.getContractType())){
			//处理务派遣合同： 先看上一份合同是否为劳务协议，如果是取值上一份合同的劳务协议结束日期
			Date initDate = contract.getContractEnd();
			if (Common.isNotNull(contract.getPreNewId())){
				TEmployeeContractPreNew preNew = baseMapper.selectOne(Wrappers.<TEmployeeContractPreNew>query().lambda()
						.eq(TEmployeeContractPreNew::getId, contract.getPreNewId())
						.last(CommonConstants.LAST_ONE_SQL));
				if (Common.isNotNull(preNew) && Common.isNotNull(preNew.getDispatchPeriodEnd())){
					initDate = preNew.getDispatchPeriodEnd();
				}
			}else {
				TEmployeeContractPreHistory pre = preHistoryMapper.selectOne(Wrappers.<TEmployeeContractPreHistory>query().lambda()
						.eq(TEmployeeContractPreHistory::getContractId,contract.getId())
						.last(CommonConstants.LAST_ONE_SQL));
				if (Common.isNotNull(pre) && Common.isNotNull(pre.getDispatchPeriodEnd())){
					initDate = pre.getDispatchPeriodEnd();
				}
			}
			preVo.setDispatchPeriodStart(DateUtil.addDayByDate(initDate,1));
			if (Common.isNotNull(preVo.getDispatchPeriodYear()) && Common.isNotNull(preVo.getDispatchPeriodMonth())){
				//校验劳务派遣的派遣年限必须为两年
				final int REQUIRED_SERVICE_YEARS = 2;
				int year = 0;
				try {
					year = Integer.parseInt(Common.isEmpty(preVo.getDispatchPeriodYear()) ? "0" : preVo.getDispatchPeriodYear().trim());
				} catch (NumberFormatException e) {
					return "劳务派遣的派遣年限格式不正确";
				}
				String dispatchMonth = preVo.getDispatchPeriodMonth();
				if ("12".equals(dispatchMonth)) {
					year = year + 1;
				}

				if (year < REQUIRED_SERVICE_YEARS) {
					return "劳务派遣合同的合同年限不能小于2年，请检查";
				}
				vo = new TEmployeeContractDateVo();
				vo.setMonthAfter(Integer.parseInt(Common.isEmpty(preVo.getDispatchPeriodMonth()) ? "0": preVo.getDispatchPeriodMonth()));
				vo.setYearAfter(Integer.parseInt(Common.isEmpty(preVo.getDispatchPeriodYear()) ? "0": preVo.getDispatchPeriodYear()));
				vo.setRegistDate(preVo.getDispatchPeriodStart());
				preVo.setDispatchPeriodEnd(this.addYearsMonths(vo));
			}
			if (Common.isNotNull(preVo.getDispatchPeriodStart()) && Common.isNotNull(preVo.getDispatchPeriodEnd())){
				if (preVo.getDispatchPeriodEnd().before(preVo.getDispatchPeriodStart())){
					return "派遣结束日期需大于等于派遣开始日期";
				}
			}
			//合同开始时间、合同截止时间  与派遣的合同开始时间、合同截止时间一致
			if (Common.isNotNull(preVo.getContractStart()) && Common.isNotNull(preVo.getDispatchPeriodStart())
					&& !preVo.getContractStart().equals(preVo.getDispatchPeriodStart())){
				return "合同开始日期与派遣开始日期不一致";
			}
			if (Common.isNotNull(preVo.getContractEnd()) && Common.isNotNull(preVo.getDispatchPeriodEnd())
					&& !preVo.getContractEnd().equals(preVo.getDispatchPeriodEnd())){
				return "合同截止日期与派遣截止日期不一致";
			}
		}
		//同商务合同一直 要 验证时间 截止时间大于等于开始时间、时间交叉
		if (Common.isNotNull(preVo.getContractStart()) && Common.isNotNull(preVo.getContractEnd())){
			if (preVo.getContractEnd().before(preVo.getContractStart())){
				return "合同截止日期需大于等于合同开始日期";
			}
		}
		//更新岗位名称
		return null;
	}
	private String initDateInfo(TEmployeeContractPreNew preVo, TEmployeeContractInfo contract) {
		TEmployeeContractDateVo vo;
		//标准合同/劳务协议/实习协议/劳务派遣合同/非全日制/其他合同
		//1:"标准合同，3:“劳务协议”，5:“实习协议,8:“非全日制’，9:"补贴合同，13:’见习协议，18:“兼职协议”,19:”临时聘用合同，20:"劳务派遣合同’，21:’其他

		if (CommonConstants.FIVE_STRING.equals(preVo.getContractType())){
			//处理实习协议
			preVo.setContractStart(preVo.getInternshipPeriodStart());
			preVo.setContractEnd(preVo.getInternshipPeriodEnd());

		}
		if (Common.isNotNull(preVo.getInternshipPeriodStart()) && Common.isNotNull(preVo.getInternshipPeriodEnd())){
			if (preVo.getInternshipPeriodEnd().before(preVo.getInternshipPeriodStart())){
				return "实习结束日期需大于等于实习开始日期";
			}
		}
		//同商务合同一直 要 验证时间 截止时间大于等于开始时间、时间交叉
		if (Common.isNotNull(preVo.getContractStart()) && Common.isNotNull(preVo.getContractEnd())){
			if (preVo.getContractEnd().before(preVo.getContractStart())){
				return "合同截止日期需大于等于合同开始日期";
			}
		}
		if (Common.isNotNull(preVo.getDispatchPeriodStart()) && Common.isNotNull(preVo.getDispatchPeriodEnd())){
			if (preVo.getDispatchPeriodEnd().before(preVo.getDispatchPeriodStart())){
				return "派遣结束日期需大于等于派遣开始日期";
			}
		}
		//更新岗位名称
		return null;
	}
	/**
	 * @Author fxj
	 * @Description 合同续签待签订信息单个/批量发起签署任务
	 *定时任务：1、每日定时发起合同签署任务-11:00、15:00、15:20——工作日，
	 * 会将发起失败、签署失败、审核不通过的“预计合同发起时间”为当日及之前日期的（空白的不在）
	 * 合同续签任务自动尝试发起，若发起失败后，将统一推送移动端消息提醒，并在续签待办列表，状态处增加小问号，可查询失败原因；
	 * @Date 18:35 2026/2/9
	 * @param type 1 手动 2 自动
	**/
	@Override
	public R dispatcherContract(List<String> idList,String  type) {
		List<TEmployeeContractPreNew> contractPreList;
		List<String> processStatus = Arrays.asList("0", "1", "3", "5", "7", "11", "10");
		if ("2".equals(type)) {
			//自动  待发起、发起失败、撤销签署-客服撤销、撤销签署-系统自动撤销、签署失败、审核不通过
			contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda().in(TEmployeeContractPreNew::getId, idList)
					.in(TEmployeeContractPreNew::getProcessStatus,processStatus ));
		} else {
			//手动
			contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda().in(TEmployeeContractPreNew::getId, idList)
					.in(TEmployeeContractPreNew::getProcessStatus, processStatus));
		}
		// 如果没有找到任何未处理的合同待派单数据，返回失败消息
		if (Common.isEmpty(contractPreList)) {
			return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
		}
		ContractAlertSearchVo searchVo = new ContractAlertSearchVo();
		searchVo.setPreIdList(idList);
		//获取返回信息
		List<TEmployeeContractPreNewDetailVo> exitsList = baseMapper.getDetailList(searchVo);
		Map<String, TEmployeeContractPreNewDetailVo> backInfoMap = new HashMap<>();
		if (Common.isNotNull(exitsList)) {
			for (TEmployeeContractPreNewDetailVo vo : exitsList) {
				backInfoMap.put(vo.getId(), vo);
			}
		}

		// 创建一个Map映射preId到TEmployeeContractPre对象
		Map<String, TEmployeeContractPreNew> preContractMap = contractPreList.stream()
				.collect(Collectors.toMap(TEmployeeContractPreNew::getId, pre -> pre));

		Map<String, String> loginNameMap = new HashMap<>();
		//发起派单
		List<ErrorMessage> errorMessageListAll = new ArrayList<>();
		List<EmployeeContractVO> excelVOList = baseMapper.getDisPatcherContractListRenew(idList,processStatus,type);

		// 拆分电子签和线下签
		List<EmployeeContractVO> electronicSignList = new ArrayList<>();
		List<EmployeeContractVO> offlineSignList = new ArrayList<>();

		if (Common.isNotNull(excelVOList) && !excelVOList.isEmpty()) {
			for (EmployeeContractVO contractVO : excelVOList) {
				TEmployeeContractPreNew contractPre = preContractMap.get(contractVO.getPreNewId());
				if (contractPre != null && "0".equals(contractPre.getSignType())) {
					// 电子签
					electronicSignList.add(contractVO);
				} else {
					// 线下签
					offlineSignList.add(contractVO);
				}
			}
		}

		// 按前端客服分组统计
		Map<String, CustomerStatistics> customerStatisticsMap = new HashMap<>();

		// 处理电子签合同
		if (!electronicSignList.isEmpty()) {
			LocalDate currentDate = LocalDate.now();

			for (EmployeeContractVO contractVO : electronicSignList) {
				TEmployeeContractPreNew contractPre = preContractMap.get(contractVO.getPreNewId());
				contractVO.setReNewSubmitter("自动化手动-"+ (null==contractPre.getCustomerUsername()?"":contractPre.getCustomerUsername()));
				if (contractPre != null && contractPre.getContractStart() != null) {
					if ("2".equals(type) && Common.isNotNull(contractPre.getCustomerUserLoginname()) &&
							null == loginNameMap.get(contractPre.getCustomerUserLoginname())) {
						UUID uuid = UUID.randomUUID();
						loginNameMap.put(contractPre.getCustomerUserLoginname(), uuid.toString());
					}
					// 获取或创建客服统计信息
					String customerLoginName = contractPre.getCustomerUserLoginname();
					CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerStatistics stats = new CustomerStatistics();
						stats.setCustomerUserLoginname(customerLoginName);
						stats.setCustomerUsername(contractPre.getCustomerUsername());
						return stats;
					});
					customerStats.setInitiatedCount(customerStats.getInitiatedCount() + 1);
					// 系统自动撤销状态的数据签订类型必须是线下签
					if (CommonConstants.ZERO_STRING.equals(contractPre.getSignType())
							&& CommonConstants.ELEVEN_STRING.equals(contractPre.getProcessStatus())){
						customerStats.setFailedCount(customerStats.getFailedCount() + 1);
						customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);
						// 更新processStatus为电子签发起失败
						LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPreNew::getId, contractPre.getId())
								.set(TEmployeeContractPreNew::getErrorTime, LocalDateTime.now())
								.set(TEmployeeContractPreNew::getErrorInfo, "系统自动撤销签署须走线下签！");
						this.update(updateWrapper);

						if ("2".equals(type)) {
							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
							contractAutoLog.setEmpName(contractPre.getEmployeeName());
							contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
							contractAutoLog.setMainId(contractPre.getId());
							contractAutoLog.setErrorInfo("系统自动撤销签署须走线下签！");
							contractAutoLogService.save(contractAutoLog);
						}

						// 添加错误信息
						ErrorMessage<TEmployeeContractPreNewDetailVo> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), "系统自动撤销签署须走线下签！");
						errorMessage.setData(backInfoMap.get(contractVO.getPreNewId()));
						errorMessageListAll.add(errorMessage);
						continue;
					}

					LocalDate localDate = contractPre.getContractStart().toInstant()
							.atZone(ZoneId.systemDefault())
							.toLocalDate();
					localDate = localDate.plusMonths(1)
							.minusDays(1);
					// 判断是否超过合同开始日期一个月  20260210 和倩倩确认：超过合同开始日期一个月算电子签发起失败 自动转线下签
					if (currentDate.isAfter(localDate)) {
						// 超过一个月，算电子签发起失败
						customerStats.setFailedCount(customerStats.getFailedCount() + 1);
						customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);

						// 更新processStatus为电子签发起失败
						LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPreNew::getId, contractPre.getId())
								.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.FIVE_STRING)
								.set(TEmployeeContractPreNew::getErrorInfo, EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO)
								.set(TEmployeeContractPreNew::getErrorTime, LocalDateTime.now());
						this.update(updateWrapper);

						if ("2".equals(type)) {
							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
							contractAutoLog.setEmpName(contractPre.getEmployeeName());
							contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
							contractAutoLog.setMainId(contractPre.getId());
							contractAutoLog.setErrorInfo(EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO);
							contractAutoLogService.save(contractAutoLog);
						}

						// 添加错误信息
						ErrorMessage<TEmployeeContractPreNewDetailVo> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), EmployeeConstants.DATA_CONTRACT_EXPECTED_SIGN_TIME_ERROR_TWO);
						errorMessage.setData(backInfoMap.get(contractVO.getPreNewId()));
						errorMessageListAll.add(errorMessage);
					} else {
						// 未超过一个月，先调用contractInfoService.importContract方法创建合同
						List<EmployeeContractVO> singleContractList = new ArrayList<>();
						singleContractList.add(contractVO);
						List<ErrorMessage> singleErrorMessageList = new ArrayList<>();
						// 调用合同导入方法
						contractInfoService.importContract(singleContractList, singleErrorMessageList);

						// 检查合同创建是否成功
						boolean contractCreateSuccess = singleErrorMessageList.stream()
								.allMatch(message -> message.getMessage().equals(CommonConstants.SAVE_SUCCESS));

						if (!contractCreateSuccess) {
							// 合同创建失败，统计错误并更新状态
							customerStats.setFailedCount(customerStats.getFailedCount() + 1);
							customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);

							String errorMsg = singleErrorMessageList.isEmpty() ? "合同创建失败" : singleErrorMessageList.get(0).getMessage();
							// 更新processStatus为电子签发起失败
							LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
							updateWrapper.eq(TEmployeeContractPreNew::getId, contractPre.getId())
									.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.FIVE_STRING)
									.set(TEmployeeContractPreNew::getErrorInfo, errorMsg)
									.set(TEmployeeContractPreNew::getErrorTime, LocalDateTime.now());
							this.update(updateWrapper);

							if ("2".equals(type)) {
								//生成快照数据
								TContractAutoLog contractAutoLog = new TContractAutoLog();
								contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
								contractAutoLog.setEmpName(contractPre.getEmployeeName());
								contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
								contractAutoLog.setErrorInfo(errorMsg);
								contractAutoLog.setMainId(contractPre.getId());
								contractAutoLogService.save(contractAutoLog);
							}
							// 添加错误信息
							ErrorMessage<TEmployeeContractPreNewDetailVo> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), errorMsg);
							errorMessage.setData(backInfoMap.get(contractVO.getPreNewId()));
							errorMessageListAll.add(errorMessage);
						} else {
							// 合同创建成功，继续调用FascService的submitContract方法
							R<String> result = null;
							TEmployeeContractPreNew contractPreTemp = baseMapper.selectById(contractPre.getId());
							// 复制一份快照
							try {
								result = fascService.submitContractRenew(contractPreTemp.getId() );
							} catch (Exception e) {
								// 更新合同：
								if (Common.isNotNull(contractPreTemp.getId())) {
									TEmployeeContractInfo empContract = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query().lambda()
											.eq(TEmployeeContractInfo::getPreNewId, contractPreTemp.getId())
											.eq(TEmployeeContractInfo::getDeleteFlag,CommonConstants.ZERO_STRING)
											.last(CommonConstants.LAST_ONE_SQL));
									if (null != empContract && empContract.getId() != null){
										empContract.setDeleteFlag(CommonConstants.ONE_INT);
										contractInfoService.updateById(empContract);
									}
								}
								log.error("法大大推送执行异常", e);
							}
							if (result == null || result.getCode() != CommonConstants.SUCCESS) {
								customerStats.setFailedCount(customerStats.getFailedCount() + 1);
								customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);
								String errorMsg = result != null ? result.getMsg() : "电子签发起失败";
								// 更新processStatus为电子签发起失败
								LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.eq(TEmployeeContractPreNew::getId, contractPreTemp.getId())
										.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.FIVE_STRING)
										.set(TEmployeeContractPreNew::getErrorInfo, errorMsg)
										.set(TEmployeeContractPreNew::getErrorTime, LocalDateTime.now());
								this.update(updateWrapper);
								// 更新合同：
								if (Common.isNotNull(contractPreTemp.getId())) {
									TEmployeeContractInfo empContract = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query().lambda()
											.eq(TEmployeeContractInfo::getPreNewId, contractPreTemp.getId())
											.eq(TEmployeeContractInfo::getDeleteFlag,CommonConstants.ZERO_STRING)
											.last(CommonConstants.LAST_ONE_SQL));
									if (null != empContract && empContract.getId() != null){
										empContract.setDeleteFlag(CommonConstants.ONE_INT);
										contractInfoService.updateById(empContract);
									}
								}

								if ("2".equals(type)) {
									//生成快照数据
									TContractAutoLog contractAutoLog = new TContractAutoLog();
									contractAutoLog.setContractId(loginNameMap.get(contractPreTemp.getCustomerUserLoginname()));
									contractAutoLog.setEmpName(contractPreTemp.getEmployeeName());
									contractAutoLog.setEmpIdcard(contractPreTemp.getEmpIdcard());
									contractAutoLog.setErrorInfo(errorMsg);
									contractAutoLog.setMainId(contractPreTemp.getId());
									contractAutoLogService.save(contractAutoLog);
								}
								// 添加错误信息
								ErrorMessage<TEmployeeContractPreNewDetailVo> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), errorMsg);
								errorMessage.setData(backInfoMap.get(contractVO.getPreNewId()));
								errorMessageListAll.add(errorMessage);
							} else {
								if (Common.isNotNull(contractPreTemp.getId()) && Common.isNotNull(result.getData())) {
									contractPreTemp.setRequestId(result.getData());
									baseMapper.updateById(contractPreTemp);
								}
								if (Common.isNotNull(contractPreTemp.getId())) {
									TEmployeeContractInfo empContract = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query().lambda()
											.eq(TEmployeeContractInfo::getPreNewId, contractPreTemp.getId())
											.eq(TEmployeeContractInfo::getDeleteFlag,CommonConstants.ZERO_STRING)
											.orderByDesc(BaseEntity::getCreateTime)
											.last(CommonConstants.LAST_ONE_SQL));
									if (null != empContract && empContract.getId() != null){
										TEmployeeContractAudit audit = new TEmployeeContractAudit();
										audit.setRootName("签署中");
										audit.setLinkId(empContract.getId());
										audit.setLinkType(CommonConstants.ONE_INT);
										audit.setCreateName("法大大电子签");
										audit.setCreateBy("1");
										tEmployeeContractAuditService.save(audit);
									}
									//更新合同的办理状态
									updateEmpContractAlertHandleStatus(contractPre.getContractId(), CommonConstants.ONE_STRING);
									// 更新processStatus为电子签发起失败
									LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
									updateWrapper.eq(TEmployeeContractPreNew::getId, contractPreTemp.getId())
											.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.SIX_STRING);
									this.update(updateWrapper);
								}
							}
						}
					}
				}
			}
		}

		// 处理线下签合同（走原逻辑）
		if (!offlineSignList.isEmpty()) {

			// 统计线下签的发起数量
			for (EmployeeContractVO contractVO : offlineSignList) {
				TEmployeeContractPreNew contractPre = preContractMap.get(contractVO.getPreNewId());
				if (contractPre != null) {
					String customerLoginName = contractPre.getCustomerUserLoginname();
					CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerStatistics stats = new CustomerStatistics();
						stats.setCustomerUserLoginname(customerLoginName);
						stats.setCustomerUsername(contractPre.getCustomerUsername());
						return stats;
					});
					customerStats.setInitiatedCount(customerStats.getInitiatedCount() + 1);
				}
			}

			List<EmployeeContractVO> disList;
			int k = 0;
			int i = (int) Math.ceil((double) offlineSignList.size() / CommonConstants.INTEGER_HUNDRED);
			for (int j = 0; j < i; j++) {
				if (j == i - 1) {
					disList = offlineSignList.subList(k, offlineSignList.size());
				} else {
					disList = offlineSignList.subList(k, k + 100);
				}
				k = k + 100;
				if (Common.isNotNull(disList)) {
					//调用批量派单接口100条处理一次，同原合同派单保持一致
					List<ErrorMessage> errorMessageList = new ArrayList<>();
					contractInfoService.importContract(disList, errorMessageList);
					if (!errorMessageList.stream().allMatch(message -> message.getMessage().equals(CommonConstants.SAVE_SUCCESS))) {
						errorMessageListAll.addAll(errorMessageList);
						//更新合同状态为5发起失败
						for (ErrorMessage errorMessage : errorMessageList) {
							if (!errorMessage.getMessage().equals(CommonConstants.SAVE_SUCCESS)) {
								EmployeeContractVO contractVO = disList.stream().filter(vo -> Objects.equals(vo.getRowIndex(), errorMessage.getLineNum())).collect(Collectors.toList()).get(0);

								// 获取合同预签订信息以便统计
								TEmployeeContractPreNew contractPre = preContractMap.get(contractVO.getPreNewId());
								if ("2".equals(type) && Common.isNotNull(contractPre.getCustomerUserLoginname()) &&
										null == loginNameMap.get(contractPre.getCustomerUserLoginname())) {
									UUID uuid = UUID.randomUUID();
									loginNameMap.put(contractPre.getCustomerUserLoginname(), uuid.toString());
								}
								if (contractPre != null) {
									String customerLoginName = contractPre.getCustomerUserLoginname();
									CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, key -> {
										CustomerStatistics stats = new CustomerStatistics();
										stats.setCustomerUserLoginname(customerLoginName);
										stats.setCustomerUsername(contractPre.getCustomerUsername());
										return stats;
									});
									customerStats.setFailedCount(customerStats.getFailedCount() + 1);
									customerStats.setOfflineSignFailedCount(customerStats.getOfflineSignFailedCount() + 1);
								}
								if ("2".equals(type)) {
									//生成快照数据
									TContractAutoLog contractAutoLog = new TContractAutoLog();
									contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
									contractAutoLog.setEmpName(contractPre.getEmployeeName());
									contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
									contractAutoLog.setErrorInfo(errorMessage.getMessage());
									contractAutoLog.setMainId(contractPre.getId());
									contractAutoLogService.save(contractAutoLog);
								}

								LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.in(TEmployeeContractPreNew::getId, contractVO.getPreNewId())
										.in(TEmployeeContractPreNew::getProcessStatus, CommonConstants.contractDIsStatus)
										.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.FIVE_STRING)
										.set(TEmployeeContractPreNew::getSignType, CommonConstants.ONE_STRING)
										.set(TEmployeeContractPreNew::getErrorInfo, errorMessage.getMessage())
										.set(TEmployeeContractPreNew::getErrorTime, LocalDateTime.now());
								// 执行更新操作
								errorMessage.setData(backInfoMap.get(contractVO.getPreNewId()));
								this.update(updateWrapper);
								//线下签发起失败 更新合同提醒为待处理
								LambdaUpdateWrapper<TEmpContractAlert> updateWrapperAlert = new LambdaUpdateWrapper<>();
								updateWrapperAlert.in(TEmpContractAlert::getContractId, contractVO.getContractId())
										.set(TEmpContractAlert::getHandleStatus, CommonConstants.ZERO_STRING);
								empContractAlertMapper.update(null, updateWrapperAlert);
							} else {
								//处理成功更新数据
								EmployeeContractVO contractVO = disList.stream().filter(vo -> Objects.equals(vo.getRowIndex(), errorMessage.getLineNum())).collect(Collectors.toList()).get(0);
								LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.in(TEmployeeContractPreNew::getId, contractVO.getPreNewId())
										.in(TEmployeeContractPreNew::getProcessStatus, CommonConstants.contractDIsStatus)
										.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.TWO_STRING)
										.set(TEmployeeContractPreNew::getSignType, CommonConstants.ONE_STRING);
								this.update(updateWrapper);
								//更新合同的办理状态
								updateEmpContractAlertHandleStatus(contractVO.getContractId(), CommonConstants.ONE_STRING);
							}
						}
					}
					if (errorMessageList.stream().allMatch(message -> message.getMessage().equals(CommonConstants.SAVE_SUCCESS))) {
						for (ErrorMessage errorMessage : errorMessageList) {
							if (errorMessage.getMessage().equals(CommonConstants.SAVE_SUCCESS)){
								//处理成功更新数据
								EmployeeContractVO contractVO = disList.stream().filter(vo -> Objects.equals(vo.getRowIndex(), errorMessage.getLineNum())).collect(Collectors.toList()).get(0);
								LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.eq(TEmployeeContractPreNew::getId, contractVO.getPreNewId())
										.in(TEmployeeContractPreNew::getProcessStatus, CommonConstants.contractDIsStatus)
										.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.TWO_STRING)
										.set(TEmployeeContractPreNew::getSignType, CommonConstants.ONE_STRING);
								this.update(updateWrapper);

								//更新合同的办理状态
								updateEmpContractAlertHandleStatus(contractVO.getContractId(), CommonConstants.ONE_STRING);
							}
						}
					}
				}
			}
		}
		//定时任务自动发起签合同失败消息
		if ("2".equals(type)) {
			// 为每个前端客服发送企微消息
			for (Map.Entry<String, CustomerStatistics> entry : customerStatisticsMap.entrySet()) {
				CustomerStatistics stats = entry.getValue();
				if (stats.getFailedCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成客服个人的汇总信息
					String customerSummaryInfo = String.format("合同签署发起份数：%d份，失败份数：%d份;\n" +
									"电子签失败份数：%d份，线下签失败份数：%d份;",
							stats.getInitiatedCount(),
							stats.getFailedCount(),
							stats.getElectronicSignFailedCount(),
							stats.getOfflineSignFailedCount());
					// 发送企微消息
					sendFailueMessageToWx(stats.getCustomerUserLoginname(), customerSummaryInfo, loginNameMap);
				}
			}
		}

		return R.ok(errorMessageListAll);
	}

	private Date addYearsMonths(TEmployeeContractDateVo vo) {
		if (vo == null || vo.getRegistDate() == null) return null;

		// 转换为LocalDate（自动处理时区）
		LocalDate localDate = vo.getRegistDate().toInstant()
				.atZone(ZoneId.systemDefault())
				.toLocalDate();
		// 添加年数和月数
		if (vo.getMonthAfter() ==0 && vo.getYearAfter() ==0) {
			// 转回Date类型
			return Date.from(localDate.atStartOfDay()
					.atZone(ZoneId.systemDefault())
					.toInstant());
		} else {
			localDate = localDate
					.plusYears(vo.getYearAfter())
					.plusMonths(vo.getMonthAfter())
					.minusDays(1);
			// 转回Date类型
			return Date.from(localDate.atStartOfDay()
					.atZone(ZoneId.systemDefault())
					.toInstant());
		}
	}

	//发送企业微信待办
	private void sendFailueMessageToWx(String loginName,String summary,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String id = loginNameMap.get(loginName);
			//按用户登录名称及时间查询详情数据
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid(), wxConfig.getDomainName() + "/auth/oauth/wxLogin", "79" + id);
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——合同续签发起失败提醒";
			description.append(summary).append("<br>");
			description.append("请及时至HRO系统处理，以免耽误签署进度！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}

	/**
	 * @Author fxj
	 * @Description 合同待签订撤销签署
	 * @Date 11:55 2026/2/10
	**/
	@Override
	public R revokeSign(List<TEmployeeAutoRegistRevokeVo> registRevokeVoList) {
		if (Common.isNotNull(registRevokeVoList)) {
			List<String> idList = registRevokeVoList.stream().map(TEmployeeAutoRegistRevokeVo::getId).collect(Collectors.toList());
			List<TEmployeeContractPreNew> contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda().in(TEmployeeContractPreNew::getId, idList)
					.ne(TEmployeeContractPreNew::getProcessStatus, CommonConstants.NINE_STRING)
					.ne(TEmployeeContractPreNew::getProcessStatus, CommonConstants.FOUR_STRING)
					.ne(TEmployeeContractPreNew::getProcessStatus, CommonConstants.TEN_STRING)
					.ne(TEmployeeContractPreNew::getProcessStatus, CommonConstants.ELEVEN_STRING)
					.ne(TEmployeeContractPreNew::getProcessStatus, CommonConstants.EIGHT_STRING));
			if (Common.isEmpty(contractPreList)) {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
			TEmployeeContractPreNew pre;
			TEmployeeContractInfo contractInfo = null;
			R<String> result;
			for (TEmployeeAutoRegistRevokeVo registRevokeVo : registRevokeVoList) {
				pre = baseMapper.selectById(registRevokeVo.getId());
				if (pre != null) {
					if (Common.isNotNull(pre.getSignType()) && CommonConstants.ZERO_STRING.equals(pre.getSignType())
							&& Common.isNotNull(pre.getRequestId())) {
						try {
							result = fascService.cancelTaskRenew(pre.getId());
							if (!R.isSuccess(result)) {
								// 产品暂未设计失败了怎么做
								return result;
							}
						} catch (ApiException e) {
							// 产品暂未设计失败了怎么做
							return R.failed("推送法大大失败！" + e.getMessage());
						}
					}
					if (Common.isNotNull(pre.getId())) {
						//如果存在合同申请审核数据，将状态更新成待提交
						contractInfo = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query()
								.lambda().eq(TEmployeeContractInfo::getPreNewId, pre.getId())
								.eq(TEmployeeContractInfo::getDeleteFlag, CommonConstants.ZERO_INT)
								.eq(TEmployeeContractInfo::getAuditStatus, CommonConstants.ONE_INT)
								.last(CommonConstants.LAST_ONE_SQL));
					}
					//电子待归档、线下签待归档、已完结的不能撤销签署
					if (Common.isNotNull(pre) && !CommonConstants.NINE_STRING.equals(pre.getProcessStatus()) &&
							!CommonConstants.FOUR_STRING.equals(pre.getProcessStatus()) &&
							!CommonConstants.EIGHT_STRING.equals(pre.getProcessStatus())) {
						//如果不是待确认和待发起，需要记录操作记录
						if (!CommonConstants.ZERO_STRING.equals(pre.getProcessStatus()) &&
								!CommonConstants.ONE_STRING.equals(pre.getProcessStatus()) &&
								Common.isNotNull(contractInfo)) {
							//找到最新的合同数据添加审核记录
							TEmployeeContractAudit audit = new TEmployeeContractAudit();
							audit.setRootName("撤销签署");
							audit.setLinkId(contractInfo.getId());
							audit.setLinkType(CommonConstants.ONE_INT);
							audit.setRemark(registRevokeVo.getReason());
							tEmployeeContractAuditService.save(audit);
						}
						pre.setProcessStatus(CommonConstants.TEN_STRING);
						pre.setSignFlag(CommonConstants.ZERO_STRING);
						pre.setRevokeReason(registRevokeVo.getReason());
						pre.setRevokeTime(new Date());
						baseMapper.updateById(pre);
						//更新合同续签待办提醒的办理状态为待办理
						updateEmpContractAlertHandleStatus(pre.getContractId(), CommonConstants.ZERO_STRING);
					}
					if (Common.isNotNull(contractInfo)) {
						contractInfo.setAuditStatus(CommonConstants.FIVE_INT);
						contractInfo.setInUse(CommonConstants.ONE_STRING);
						contractInfoService.updateById(contractInfo);
					}
				}
			}
		}
		return R.ok();
	}

	/**
	 * @Author fxj
	 * @Description 每日晚23:00自动撤销超时电子签署任务(当前时间超出当前合同开始日期一个月的数据)
	 * @Date 18:38 2026/2/10
	**/
	@Override
	public R autoRevokeElectronicSign() {
		try {
			// 查询符合条件的合同：状态为"签署中"(6) 且 为电子签任务(signType=0) 且 合同开始日期到当日正好一个月
			LocalDate currentDate = LocalDate.now();
			// 计算一个月前的日期（当前日期减去1个月再加1天）
			LocalDate oneMonthAgo = currentDate.minusMonths(1).plusDays(1);

			List<TEmployeeContractPreNew> contractsToRevoke = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda()
					.eq(TEmployeeContractPreNew::getProcessStatus, CommonConstants.SIX_STRING) // 签署中
					.eq(TEmployeeContractPreNew::getSignType, CommonConstants.ZERO_STRING) // 电子签
					.eq(TEmployeeContractPreNew::getContractStart, LocalDateTimeUtils.convertLDToDate(oneMonthAgo)) // 合同开始日期正好一个月前
			);

			if (Common.isEmpty(contractsToRevoke)) {
				return R.ok("未找到需要撤销的超时电子签署任务");
			}

			for (TEmployeeContractPreNew preNew : contractsToRevoke) {
				try {
					// 调用法大大撤销签署接口
					R<String> revokeResult = fascService.cancelTaskRenew(preNew.getId());

					if (revokeResult.getCode() == 200) {
						// 撤销成功：状态更新为"待发起"(1) 且 签署方式变更为"线下签"(1)
						LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPreNew::getId, preNew.getId())
								.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.ELEVEN_STRING) // 11 撤销签署-系统自动撤销
								.set(TEmployeeContractPreNew::getRevokeReason, "超时未签署自行变更为线下签")
								.set(TEmployeeContractPreNew::getChangeTypeReason, "超时未签署自行变更为线下签")
								.set(TEmployeeContractPreNew::getChangeTypeUser, "超管")
								.set(TEmployeeContractPreNew::getChangeTypeTime, DateUtil.getCurrentDateTime());
						this.update(updateWrapper);
						TEmployeeContractInfo contractInfo = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query()
								.lambda().eq(TEmployeeContractInfo::getPreNewId, preNew.getId())
								.eq(TEmployeeContractInfo::getDeleteFlag, CommonConstants.ZERO_INT)
								.orderByDesc(BaseEntity::getCreateTime)
								.last(CommonConstants.LAST_ONE_SQL));
						if (null != contractInfo){
							TEmployeeContractAudit audit = new TEmployeeContractAudit();
							audit.setRootName("续签-撤销签署");
							audit.setCreateName("系统自动撤销");
							audit.setLinkId(contractInfo.getId());
							audit.setLinkType(CommonConstants.ONE_INT);
							audit.setRemark("电子合同续签超过一个月未完成签署，系统自动撤销");
							tEmployeeContractAuditService.save(audit);
						}
						//更新合同续签待办提醒的办理状态为待办理
						updateEmpContractAlertHandleStatus(preNew.getContractId(), CommonConstants.ZERO_STRING);

					} else if ("已完成签署".equals(revokeResult.getMsg())) {
						// 撤销失败原因为已完成签署：更新为签署完成的"待归档"状态(8)
						LambdaUpdateWrapper<TEmployeeContractPreNew> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPreNew::getId, preNew.getId())
								.set(TEmployeeContractPreNew::getProcessStatus, CommonConstants.EIGHT_STRING); // 电子待归档
						this.update(updateWrapper);
						//更新合同续签待办提醒的办理状态为办理中
						updateEmpContractAlertHandleStatus(preNew.getContractId(), CommonConstants.ONE_STRING);

					} else {
						// 其他撤销失败原因
						log.error("合同ID：{}，撤销失败，原因：{}", preNew.getId(), revokeResult.getMsg());
					}

				} catch (Exception e) {
					log.error("处理合同ID：{}时发生异常", preNew.getId(), e);
				}
			}
			return R.ok();

		} catch (Exception e) {
			log.error("执行自动撤销超时电子签署任务时发生异常", e);
			return R.failed("执行自动撤销超时电子签署任务时发生异常：" + e.getMessage());
		}
	}

	/**
	 * @Author fxj
	 * @Description 更新合同续签待办的处理状态
	 * @Date 19:01 2026/2/10
	**/
	private void updateEmpContractAlertHandleStatus(String contractId, String handleStatus){
		//更新合同续签待办提醒的办理状态为待办理
		LambdaUpdateWrapper<TEmpContractAlert> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.eq(TEmpContractAlert::getContractId, contractId)
				.set(TEmpContractAlert::getHandleStatus, handleStatus);
		empContractAlertMapper.update(null, updateWrapper);
	}
	/**
	 * @Author fxj
	 * @Description tEmployeeContractPreNewService
	 * @Date 18:43 2026/2/10
	**/
	@Override
	public R notifyRevokedElectronicSign() {
		try {
			// 通过审计表查询前一日的撤销记录
			LocalDate yesterday = LocalDate.now().minusDays(1);
			Date yesterdayStart = LocalDateTimeUtils.convertLDToDate(yesterday);
			Date yesterdayEnd = LocalDateTimeUtils.convertLDToDate(yesterday.plusDays(1));

			// 查询前一日的撤销审计记录
			List<TEmployeeContractAudit> yesterdayAudits = tEmployeeContractAuditService.list(Wrappers.<TEmployeeContractAudit>query()
					.lambda()
					.eq(TEmployeeContractAudit::getRootName, "续签-撤销签署")
					.eq(TEmployeeContractAudit::getCreateName, "系统自动撤销")
					.eq(TEmployeeContractAudit::getLinkType, CommonConstants.ONE_INT)
					.ge(TEmployeeContractAudit::getCreateTime, yesterdayStart)
					.lt(TEmployeeContractAudit::getCreateTime, yesterdayEnd)
			);

			if (Common.isEmpty(yesterdayAudits)) {
				return R.ok("前一日未发现撤销的电子签署任务");
			}

			// 根据审计记录获取对应的合同ID列表
			List<String> contractIds = yesterdayAudits.stream()
					.map(TEmployeeContractAudit::getLinkId)
					.filter(Objects::nonNull)
					.collect(Collectors.toList());

			if (Common.isEmpty(contractIds)) {
				return R.ok("前一日撤销记录中未找到有效的合同ID");
			}
			List<TEmployeeContractInfo> contracts = contractInfoMapper.selectList(Wrappers.<TEmployeeContractInfo>query()
					.lambda()
					.in(TEmployeeContractInfo::getId, contractIds));
			List<String> preNewIds = null;
			if (!Common.isEmpty(contracts)){
				preNewIds = contracts.stream()
						.map(TEmployeeContractInfo::getPreNewId)
						.filter(Objects::nonNull)
						.collect(Collectors.toList());
			}
			if (Common.isEmpty(preNewIds)) {
				return R.ok("前一日撤销记录中未找到有效的PreNewID");
			}
			// 根据合同ID查询对应的合同预签订记录
			List<TEmployeeContractPreNew> revokedContracts = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda()
					.in(TEmployeeContractPreNew::getId, preNewIds)
					.eq(TEmployeeContractPreNew::getProcessStatus, CommonConstants.ELEVEN_STRING) // 撤销签署-系统自动撤销
					.eq(TEmployeeContractPreNew::getChangeTypeReason, "超时未签署自行变更为线下签")
			);

			if (Common.isEmpty(revokedContracts)) {
				return R.ok("前一日未发现撤销的电子签署任务");
			}

			// 按前端客服分组统计
			Map<String, CustomerRevokeStatistics> customerStatsMap = new HashMap<>();

			Map<String, String> loginNameMap = new HashMap<>();
			for (TEmployeeContractPreNew preNew : revokedContracts) {
				String customerLoginName = preNew.getCustomerUserLoginname();
				if (Common.isNotNull(customerLoginName)) {
					if (null == loginNameMap.get(customerLoginName)) {
						UUID uuid = UUID.randomUUID();
						loginNameMap.put(customerLoginName, uuid.toString());
					}
					CustomerRevokeStatistics stats = customerStatsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerRevokeStatistics newStats = new CustomerRevokeStatistics();
						newStats.setCustomerUserLoginname(customerLoginName);
						return newStats;
					});
					stats.setRevokedCount(stats.getRevokedCount() + 1);
					//生成快照数据
					TContractAutoLog contractAutoLog = new TContractAutoLog();
					contractAutoLog.setContractId(loginNameMap.get(customerLoginName));
					contractAutoLog.setEmpName(preNew.getEmployeeName());
					contractAutoLog.setEmpIdcard(preNew.getEmpIdcard());
					contractAutoLog.setPhone(preNew.getEmpPhone());
					contractAutoLog.setContractStartDate(preNew.getContractStart());
					contractAutoLog.setMainId(preNew.getId());
					contractAutoLogService.save(contractAutoLog);
				}
			}

			// 为每个前端客服发送通知
			for (Map.Entry<String, CustomerRevokeStatistics> entry : customerStatsMap.entrySet()) {
				CustomerRevokeStatistics stats = entry.getValue();
				if (stats.getRevokedCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成通知内容
					String notificationContent = String.format("距离合同开始日期已超过1个月，仍未完成合同签署（%d人），系统已自动撤回签署任务，点击可查看具体撤回清单",
							stats.getRevokedCount());

					// 发送企微通知
					sendRevokeNotificationToWx(stats.getCustomerUserLoginname(), notificationContent, loginNameMap);
				}
			}
			return R.ok();

		} catch (Exception e) {
			log.error("执行通知前端客服撤销电子签署情况任务时发生异常", e);
			return R.failed("执行通知前端客服撤销电子签署情况任务时发生异常：" + e.getMessage());
		}
	}

	/**
	 * 发送撤销通知到企微
	 * @param loginName 客服登录名
	 * @param content 通知内容
	 */
	private void sendRevokeNotificationToWx(String loginName, String content,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid()
					, wxConfig.getDomainName() + "/auth/oauth/wxLogin", "81" + loginNameMap.get(loginName));
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——电子合同续签超期自动撤回提醒";
			description.append(content).append("<br>");
			description.append("请及时进行线下签署，以免产生用工风险！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}

	/**
	 * @Author fxj
	 * @Description 每日早9点电子签合同即将超期提醒
	 * @Date 19:09 2026/2/10
	 **/
	@Override
	public R electronicSignExpiringReminder() {
		try {
			LocalDate today = LocalDate.now();
			if (!isWorkDay(today)){
				return R.ok("非工作日不执行");
			}

			// 查询所有状态为"签署中"(6)且为电子签(signType=0)的合同
			List<TEmployeeContractPreNew> signingContracts = baseMapper.selectList(Wrappers.<TEmployeeContractPreNew>query()
					.lambda()
					.eq(TEmployeeContractPreNew::getProcessStatus, CommonConstants.SIX_STRING) // 签署中
					.eq(TEmployeeContractPreNew::getSignType, CommonConstants.ZERO_STRING) // 电子签
			);

			if (Common.isEmpty(signingContracts)) {
				return R.ok("未找到签署中的电子签合同");
			}

			// 按前端客服分组统计需要提醒的合同
			Map<String, CustomerExpiringStatistics> customerStatsMap = new HashMap<>();

			Map<String, String> loginNameMap = new HashMap<>();
			for (TEmployeeContractPreNew contract : signingContracts) {
				if (contract.getContractStart() != null) {
					// 计算合同开始日期一个月的最后一天
					LocalDate localDate = contract.getContractStart().toInstant()
							.atZone(ZoneId.systemDefault())
							.toLocalDate();
					localDate = localDate.plusMonths(1)
							.minusDays(1);

					// 计算往前3个工作日
					List<LocalDate> reminderDates = calculateReminderWorkDays(localDate,3);

					// 判断今天是否是提醒日期之一
					if (reminderDates.contains(today)) {
						String customerLoginName = contract.getCustomerUserLoginname();
						if (Common.isNotNull(customerLoginName)) {
							if (null == loginNameMap.get(customerLoginName)) {
								UUID uuid = UUID.randomUUID();
								loginNameMap.put(customerLoginName, uuid.toString());
							}
							CustomerExpiringStatistics stats = customerStatsMap.computeIfAbsent(customerLoginName, k -> {
								CustomerExpiringStatistics newStats = new CustomerExpiringStatistics();
								newStats.setCustomerUserLoginname(customerLoginName);
								return newStats;
							});
							stats.setExpiringCount(stats.getExpiringCount() + 1);

							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(loginNameMap.get(customerLoginName));
							contractAutoLog.setEmpName(contract.getEmployeeName());
							contractAutoLog.setEmpIdcard(contract.getEmpIdcard());
							contractAutoLog.setPhone(contract.getEmpPhone());
							contractAutoLog.setContractStartDate(contract.getContractStart());
							contractAutoLog.setMainId(contract.getId());
							contractAutoLogService.save(contractAutoLog);
						}
						//更新催办和超期标识标识
						contract.setOverFlag(CommonConstants.ZERO_STRING);
					}
				}
			}

			// 为每个前端客服发送提醒
			for (Map.Entry<String, CustomerExpiringStatistics> entry : customerStatsMap.entrySet()) {
				CustomerExpiringStatistics stats = entry.getValue();
				if (stats.getExpiringCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成提醒内容
					String reminderContent = String.format("距离电子签续签到期还剩3天，仍未签署合同的员工数：%d人",
							stats.getExpiringCount());

					// 发送企微提醒
					sendExpiringReminderToWx(stats.getCustomerUserLoginname(), reminderContent,loginNameMap);
				}
			}

			return R.ok();

		} catch (Exception e) {
			log.error("执行续签待办电子签合同即将超期提醒任务时发生异常", e);
			return R.failed("执行续签待办电子签合同即将超期提醒任务时发生异常：" + e.getMessage());
		}
	}

	/**
	 * 发送即将超期提醒到企微
	 * @param loginName 客服登录名
	 * @param content 提醒内容
	 */
	private void sendExpiringReminderToWx(String loginName, String content,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid()
					, wxConfig.getDomainName() + "/auth/oauth/wxLogin", "80" + loginNameMap.get(loginName));
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——合同续签超期提醒";
			description.append(content).append("<br>");
			description.append("请及时提醒员工，尽快完成法大大签署任务！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}
	/**
	 * 计算合同开始日期一个月最后一天往前count个工作日的日期列表
	 * @param lastDay 入职一个月的最后一天
	 * @return 3个工作日的日期列表
	 */
	private List<LocalDate> calculateReminderWorkDays(LocalDate lastDay,int count) {
		List<LocalDate> reminderDates = new ArrayList<>();
		LocalDate currentDate = lastDay;
		int workDayCount = 0;

		// 往前找3个工作日
		while (workDayCount < count) {
			// 检查当前日期是否为工作日
			if (isWorkDay(currentDate)) {
				reminderDates.add(currentDate);
				workDayCount++;
			}
			// 往前一天
			currentDate = currentDate.minusDays(1);
		}

		// 按日期正序排列（最早的日期在前）
		Collections.reverse(reminderDates);
		return reminderDates;
	}
	/**
	 * @Author fxj
	 * @Description 往前找指定个工作日 含当前日期
	 * @param type 0 往前  1  往后
	 * @Date 19:24 2026/2/26
	 * @return
	**/
	private LocalDate calculateReminderWorkDaysBefore(LocalDate lastDay,int count,int type) {
		LocalDate currentDate = lastDay;
		int workDayCount = 0;
		// 往前找3个工作日
		while (workDayCount < count) {
			// 检查当前日期是否为工作日
			if (isWorkDay(currentDate)) {
				workDayCount++;
			}
			if (workDayCount == count){
				return currentDate;
			}
			// 往前一天
			currentDate = currentDate.minusDays(0==type?1:-1);
		}
		return currentDate;
	}
	/**
	 * 判断指定日期是否为工作日
	 * @param date 要检查的日期
	 * @return true-工作日，false-非工作日
	 */
	private boolean isWorkDay(LocalDate date) {
		TEmployeeInsuranceWorkDayVo workDayVo = new TEmployeeInsuranceWorkDayVo();
		workDayVo.setRegistDate(LocalDateTimeUtils.convertLDToDate(date));

		// 使用 THolidayInfoService 的 checkIsWorkDay 方法判断是否为假期
		// 如果是假期则不是工作日，否则是工作日
		R<Boolean> res = socialDaprUtils.checkIsWorkDay(workDayVo);
		// 添加空值检查，避免 NPE，并提高代码可读性
		if (res == null || res.getData() == null) {
			log.warn("checkIsWorkDay 返回结果为空，默认视为非工作日");
			return false;
		}
		// res.getData() 为 true 表示是假期（非工作日），为 false 表示是工作日
		return !res.getData();
	}

	/**
	 * @Author fxj
	 * @Description 自动化合同续签：一键催办
	 * @Date 19:30 2026/2/10
	**/
	@Override
	public R contractUrg(String id) {
		// 查询所有待催办的合同
		List<TContractAutoLog> signingContracts = contractAutoLogService.list(Wrappers.<TContractAutoLog>query()
				.lambda()
				.eq(TContractAutoLog::getContractId, id)
		);
		if (Common.isNotNull(signingContracts) && signingContracts.size() > 0) {
			try {
				for (TContractAutoLog log : signingContracts) {
					//查询合同待购买数据
					TEmployeeContractPreNew pre = baseMapper.selectById(log.getMainId());
					fascService.urgeTaskRenew(pre.getId());
					log.setIsUrg(CommonConstants.ZERO_STRING);
					contractAutoLogService.updateById(log);
				}
			} catch (Exception e) {
				log.error("发送法大大催办时发生异常", e);
			}
		}
		return R.ok();
	}

	/**
	 * @Author fxj
	 * @Description 通过preId查询合同续签已确认信息
	 * @Date 10:41 2026/2/11
	**/
	@Override
	public R<TEmployeeContractPreNew> getInfoByPreId(String preId) {
		return R.ok(baseMapper.selectById(preId));
	}

	@Override
	public R<List<TEmployeeContractPreNewDetailVo>> getDetailList(ContractAlertSearchVo tEmployeeContractPreNew) {
		//系统会自动拉取当前客服且“预计合同发起时间”为空的或为今日及今日之前的，续签状态为“待发起、发起失败、审核不通过、签署失败”的合同信息
		//续签状态,0待确认,1待发起,2线下签待审核,3线下签审核不通过4线下签待归档5发起失败6签署中7签署失败8电子待归档9（已归档-电子签+线下签）已完结10撤销签署 11系统自动撤销
		List<String> statusList = new ArrayList<>();
		statusList.add(CommonConstants.ONE_STRING);
		statusList.add(CommonConstants.FIVE_STRING);
		statusList.add(CommonConstants.TEN_STRING);
		statusList.add(CommonConstants.ELEVEN_STRING);
		statusList.add(CommonConstants.SEVEN_STRING);
		statusList.add(CommonConstants.THREE_STRING);
		tEmployeeContractPreNew.setStatusList(statusList);
		initSearchVo(tEmployeeContractPreNew);
		if (ArrayUtil.isNotEmpty(tEmployeeContractPreNew.getStartEndTimecreate())
				&& tEmployeeContractPreNew.getStartEndTimecreate().length == 2) {
			tEmployeeContractPreNew.setExpectedCollectionTimeStart(tEmployeeContractPreNew.getStartEndTimecreate()[0]);
			tEmployeeContractPreNew.setExpectedCollectionTimeEnd(tEmployeeContractPreNew.getStartEndTimecreate()[1]);
		}
		return R.ok(baseMapper.getDetailList(tEmployeeContractPreNew));
	}
	@Override
	public R<Integer> getDetailListCount(ContractAlertSearchVo tEmployeeContractPreNew) {
		//系统会自动拉取当前客服且“预计合同发起时间”为空的或为今日及今日之前的，续签状态为“待发起、发起失败、审核不通过、签署失败”的合同信息
		List<String> statusList = new ArrayList<>();
		statusList.add(CommonConstants.ONE_STRING);
		statusList.add(CommonConstants.FIVE_STRING);
		statusList.add(CommonConstants.TEN_STRING);
		statusList.add(CommonConstants.ELEVEN_STRING);
		statusList.add(CommonConstants.SEVEN_STRING);
		statusList.add(CommonConstants.THREE_STRING);
		tEmployeeContractPreNew.setStatusList(statusList);
		initSearchVo(tEmployeeContractPreNew);
		return R.ok(baseMapper.getDetailListCount(tEmployeeContractPreNew));
	}

	@Override
	public R getContractTerm(String startDate, String endDate) {
		if (Common.isEmpty(startDate) || Common.isEmpty(endDate)) {
			return R.failed(CommonConstants.PARAM_INFO_ERROR);
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
		try {
			Date parseStartDate = sdf.parse(startDate);
			Date parseEndDate = sdf.parse(endDate);
			if (parseStartDate.after(parseEndDate)){
				return R.ok( null);
			}
		}catch (Exception e){
			return R.ok( null);
		}
		ContractTermCalculator.ContractTerm term = calculator.calculateTerm(startDate, endDate);
		return R.ok( term);
	}

	public void initSearchVo(ContractAlertSearchVo searchVo) {
		YifuUser user = SecurityUtils.getUser();
		long roleId = 1839501715787390978L;
		boolean isSsc = this.haveRole(user, roleId);
		if (isSsc || CommonConstants.ZERO_STRING.equals(user.getSystemFlag())) {
			searchVo.setAuthSql(null);
			return;
		}
		//非管理员及SSC  走前端客服查询逻辑
		searchVo.setCustomerUserLoginname(user.getUsername());
	}
	public boolean haveRole(YifuUser user, long roleId) {
		List<Long> roleList = user.getClientRoleMap().get(ClientNameConstants.CLIENT_MVP);
		for (Long role : roleList) {
			if (role == roleId) {
				return true;
			}
		}
		return false;
	}
	@Override
	public R<TEmployeeContractInfo> getRenewContractByPreId(String preId) {
		return R.ok(contractInfoMapper.selectOne(Wrappers.<TEmployeeContractInfo>query()
				.lambda().eq(TEmployeeContractInfo::getPreId, preId)
				.orderByDesc(BaseEntity::getCreateTime)
				.last(CommonConstants.LAST_ONE_SQL)));
	}

	/**
	 * 续签确认提醒 9:00
	 * 续签确认提醒节点：
	 * 第一个时间：上一份合同截止日期前一个月往前找最近的工作日（若前一个月当天是工作日，那就取当日）；
	 * 第二个时间：合同截止日期（若为节假日，往前找最近的一个工作日）；
	 * 第三个时间：合同截止日期后一个月往前找第五个工作日（找不到就找第四、第三、第二、第一），都找不到，就不提醒
	 * 提醒至前端客服，点击提醒，提示：请至HRO系统及时进行合同确认，以免续签不及时！
	 * */
	@Override
	public R pushWxConfrimMessage() {
		try {
			LocalDate today = LocalDate.now();

			// 查询所有状态为自动化+待确认的合同提醒数据 （数据集减少优化：取值时间为当前时间前1个月+15天 后一个月+15天的数据）
			List<ContractAlertAutoVo> confirmContracts = empContractAlertMapper.getPushWxConfrimInfos();

			if (Common.isEmpty(confirmContracts)) {
				return R.ok("未找到待确认的续签待办");
			}

			// 按前端客服分组统计需要提醒的合同
			Map<String, String> loginNameMap = new HashMap<>();
			boolean  isSend = false;
			LocalDate localDate;
			List<LocalDate> reminderDates;
			for (ContractAlertAutoVo contract : confirmContracts) {
				if (contract.getContractEnd() != null) {
					isSend = false;
					//第一个时间：上一份合同截止日期前一个月往前找最近的工作日（若前一个月当天是工作日，那就取当日）；
					// 计算合同截止日期前一个月的最后一天 如 （截止2.5，前一个月1.4）
					localDate = contract.getContractEnd().toInstant()
							.atZone(ZoneId.systemDefault()).toLocalDate();
					localDate = localDate.minusMonths(1).minusDays(1);
					// 计算往前1个工作日
					reminderDates = calculateReminderWorkDays(localDate,1);
					isSend = reminderDates.contains(today);
					//第二个时间：合同截止日期（若为节假日，往前找最近的一个工作日）；
					if (!isSend){
						// 计算往前1个工作日
						localDate = contract.getContractEnd().toInstant()
								.atZone(ZoneId.systemDefault()).toLocalDate();
						reminderDates = calculateReminderWorkDays(localDate,1);
						isSend = reminderDates.contains(today);
					}
					//第三个时间：合同截止日期后一个月往前找第五个工作日（找不到就找第四、第三、第二、第一），都找不到，就不提醒
					if (!isSend){
						// 计算合同截止日期后一个月的最后一天
						localDate = contract.getContractEnd().toInstant()
								.atZone(ZoneId.systemDefault()).toLocalDate();
						localDate = localDate.plusMonths(1).minusDays(1);
						// 计算往前5个工作日
						reminderDates = calculateReminderWorkDays(localDate,5);
						isSend = reminderDates.contains(today);
					}
					// 判断今天是否是提醒日期之一
					if (isSend) {
						String customerLoginName = contract.getCsLoginName();
						if (Common.isNotNull(customerLoginName)) {
							if (null == loginNameMap.get(customerLoginName)) {
								UUID uuid = UUID.randomUUID();
								loginNameMap.put(customerLoginName, uuid.toString());
							}
						}
					}
				}
			}

			// 为每个前端客服发送提醒
			for (Map.Entry<String, String> entry : loginNameMap.entrySet()) {
				// 发送企微确认提醒
				sendRenewConfirmInfoToWx(entry.getKey());
			}

			return R.ok();

		} catch (Exception e) {
			log.error("执行续签待办确认提醒任务时发生异常", e);
			return R.failed("执行续签待办确认期提醒任务时发生异常：" + e.getMessage());
		}
	}
	/**
	 * 发送即将超期提醒到企微
	 * @param loginName 客服登录名
	 */
	private void sendRenewConfirmInfoToWx(String loginName) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid()
					, wxConfig.getDomainName() + "/auth/oauth/wxLogin", "66" + loginName);
			StringBuilder description = new StringBuilder();
			String title = "合同待续签确认";
			description.append("<br>");
			description.append("你有新的合同待续签，请及时确认！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}

	@Override
	public void pushDisConfrimContracts() {
		//非工作日直接跳过
		LocalDate today = LocalDate.now();
		if (!isWorkDay(today)){
			return;
		}
		//获取所有待派单的数据
		List<String> unDispatchList = baseMapper.getUnDispatchList();
		if (null != unDispatchList && !unDispatchList.isEmpty()) {
			try {
				this.dispatcherContract(unDispatchList,"2");
			} catch (Exception e) {
				log.error("执行异常", e);
			}
		}
	}

	/**
	 * @Author fxj
	 * @Description 按配置返回对应的预计发起时间
	 * @Date 10:30 2026/2/27
	 * @Param
	 * @return
	**/
	@Override
	public LocalDate getPreDateByConfigId(String configId, Date contractEnd){
		if (!Common.isNotNull(configId)){
			return  null;
		}
		TAutoContractScheme scheme = contractSchemeMapper.selectById(configId);
		if (null == scheme){
			return  null;
		}
		//处理预计发起时间
		TAutoContractRuleInfo rule = null;
		if (null != scheme){
			rule = contractRuleInfoMapper.selectOne(Wrappers.<TAutoContractRuleInfo>query().lambda()
					.eq(TAutoContractRuleInfo::getDeptNo,scheme.getDeptNo())
					.last(CommonConstants.LAST_ONE_SQL));
		}
		if (null == rule){
			return  null;
		}
		if (null != rule && null != contractEnd){
			//上一份合同到期前第5个工作日:  20251229（含）前第5个工作日_25年12月23日，若是已过去的时间，则按照当前日期（含）往后继续找工作日，若超过一个月后了，
			// 则也呈现，但是只能是线下签
			// 计算往前3个工作日
			if (null != rule && null != contractEnd) {
				// 解析合同结束日期
				LocalDate contractEndDate = parseContractEndDate(contractEnd);
				if (null == contractEndDate) {
					return null;
				}
				// 计算预计发起日期
				LocalDate reminderDate = calculateReminderDate(rule.getRenewalDateType(), contractEndDate);
				if (null == reminderDate) {
					return null;
				}
				// 当前时间之前调整提醒日期为最近工作日
				reminderDate = adjustToNearestWorkday(reminderDate);
				return reminderDate;
			}
		}
		return null;
	}

	@Override
	public void updateByIdAndUpdateAlert(TEmployeeContractPreNew preNew) {
		baseMapper.updateById(preNew);
		//已完成同步更新续签待办提醒为已办理.
		TEmpContractAlert alert = null;
		if (null != preNew.getContractId()){
			alert = empContractAlertMapper.selectOne(Wrappers.<TEmpContractAlert>query().lambda()
					.eq(TEmpContractAlert::getContractId,preNew.getContractId())
					.last(CommonConstants.LAST_ONE_SQL));
		}
		if (null != alert){
			//已完成
			if (preNew.getProcessStatus().equals(CommonConstants.dingleDigitStrArray[9])){
				alert.setHandleStatus(CommonConstants.dingleDigitStrArray[2]);
			}
			//撤销签署
			if (preNew.getProcessStatus().equals(CommonConstants.dingleDigitStrArray[10])){
				alert.setHandleStatus(CommonConstants.dingleDigitStrArray[0]);
			}
			//签署失败
			if (preNew.getProcessStatus().equals(CommonConstants.dingleDigitStrArray[7])){
				alert.setHandleStatus(CommonConstants.dingleDigitStrArray[0]);
			}
			if (null != alert){
				empContractAlertMapper.updateById(alert);
			}
		}
	}
}
