package com.yifu.cloud.plus.v1.ekp.service.impl;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.IcbcConstants;
import com.icbc.api.UiIcbcClient;
import com.icbc.api.request.JftApiPayrollQueryDetailRequestV1;
import com.icbc.api.request.JftUiPayrollComfirmSubmitRequestV1;
import com.icbc.api.request.MybankEnterpriseAccountQuerybankinfoRequestV1;
import com.icbc.api.response.JftApiPayrollQueryDetailResponseV1;
import com.icbc.api.response.MybankEnterpriseAccountQuerybankinfoResponseV1;
import com.icbc.api.utils.IcbcSignature;
import com.icbc.api.utils.WebUtils;
import com.jcraft.jsch.*;
import com.yifu.cloud.plus.v1.ekp.config.IcbcIssueConfigProperties;
import com.yifu.cloud.plus.v1.ekp.entity.*;
import com.yifu.cloud.plus.v1.ekp.mapper.EkpSocialInfoMapper;
import com.yifu.cloud.plus.v1.ekp.service.*;
import com.yifu.cloud.plus.v1.ekp.vo.EkpBankAttaReturnVo;
import com.yifu.cloud.plus.v1.ekp.vo.EkpBankCodeConfiglVo;
import com.yifu.cloud.plus.v1.ekp.vo.EkpBankExcelVo;
import com.yifu.cloud.plus.v1.ekp.vo.EkpBankResultVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 聚富通到账通知交易流水查询
 *
 * @author huyc
 * @date 2024-05-23 11:21:56
 */
@Log4j2
@Service
@RequiredArgsConstructor
@EnableConfigurationProperties(IcbcIssueConfigProperties.class)
public class IcbcTransactionFlowIssueServiceImpl extends ServiceImpl<EkpSocialInfoMapper, EkpSocialInfo> implements IcbcTransactionFlowIssueService {

	@Autowired
	private IcbcIssueConfigProperties icbcConfigProperties;

	@Autowired
	private IcbcTransactionFlowQueryService icbcTransactionFlowQueryService;
	@Autowired
	private EkpBankPayTaskService ekpBankPayTaskService;
	@Autowired
	private EkpBankGrantDetailService ekpBankGrantDetailService;
	@Autowired
	private EkpBankAttaService ekpBankAttaService;
	@Autowired
	private EkpBankGrantLogService ekpBankGrantLogService;
	@Autowired
	private EkpBankGrantLogDetailService ekpBankGrantLogDetailService;
	@Autowired
	private EkpBankIcbcLogService ekpBankIcbcLogService;
	@Autowired
	private OSSUtil ossUtil;
	@Autowired
	private RedisUtil redisUtil;
	// 处理状态：00-提交成功，01-待银行处理 02-处理成功 03-处理失败，4-收方行处理中 5-收方行处理成功 6-收方行处理失败 7-收方行无法反馈
	protected final static Map<String, String> STATUS_MAP;

	static {
		STATUS_MAP = new HashMap<>();
		STATUS_MAP.put("00", "提交成功");
		STATUS_MAP.put("01", "待银行处理");
		STATUS_MAP.put("02", "处理成功");
		STATUS_MAP.put("03", "处理失败");
		STATUS_MAP.put("4", "收方行处理中");
		STATUS_MAP.put("5", "收方行处理成功");
		STATUS_MAP.put("6", "收方行处理失败");
		STATUS_MAP.put("7", "收方行无法反馈");
	}

	//1、网关公钥
	//private static final String APIGW_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIpiPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZERkx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4+EBpXo8gNiAFsNwIDAQAB";
	//2、appid
	//private static final String APP_ID = "11000000000000028685";
	//3、密钥对认证方式，公钥在API平台登记，此处为私钥
	//private static final String MY_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCEZYrhm3dBp3PqlMc9fBBEE8Tp8M34Yy6Ucs3FV/VahsdHaLe0kEPugf1twbt/hD4hdIwzUj/ZtG2BhusRiMptdlWtNKcIgFxaaFaKANKrIodeQjv0jjZvK9ugoQxmiM4gF5SGX2a847zohv/6TvAYiB9AI3tdKQTbj6I3pwmuO3cfzgU5IwepeguE4fxqnh7C19MEq4vXv0yBq/f43zQ2HBMS+KRgokNLUBqoEOyfaKkPL9ot+zISPwENQOLqQMZ1hczp5tEB2FeZecdzrzjeXkzPSy1ZJmNyNuOl+WG85aoeDJTQ7hx/g6KFA6zU2VBGUR7q4pXdGRslpa6KYETBAgMBAAECggEALkfElXqf5G5hocWiJAcDNJjog5JunX4mITREY9CMbrmgXYDofpDTfkMoUL6hCUEz6sPv4lzE/xgIE3gTIcz8Xek4p9Q480rTfbLtVU5WVgY65aMnjCROOOxO2MaTLCB0VVmIzLP6mNrPBUVzo48GdLzYl7YPgJA/J3T9EpEsXB/iAdjiv/VH9vOIW6WUlQUSceyNznf1rfwMJvHt7zb56IJGZMq9G6C5SUeqWbqbvNi+nL8yeu8fM/O/ERZJQBDwMXbRAPvhhcbDwVzpg4BRc7AVv0SLzy6ZA2+zLJmDe9F9uXmG6QQ4ra8mDqLeugDP9blKUOEm8JLIh7nzvhpNhQKBgQDK4ZEz1zui6GQsxsnbm24EvparfniPqDBS/V29MDZysXDmG123R22RA//BWC3m5cY+3vg0ayCGaXRrc9/V+u+jmwVfsR6XCM6WM2IZVVFBUzqKMlTKsZ4n3V/6pqBHG8++GUab5W6p/7NYI22xx0ZFObEt4EkaaaP7RzY6AVrtCwKBgQCnD6P24uR6VHN84lhyZl+iJW6azTd26AhaJ768wSl5rqN6N4AV9cXeAUKylPgMPvy+2mjNX7He0Oitb7/lrKK93/olmDQoHpqj1yZum8VVPiyEKk6qCoYYoHEloLPJDPRs6yiBjrO8oghHRuyJErKRN6IZC3Rq/mrXuDwrZYS84wKBgFn9wDisigly56xs6PD+esij+ZVMXhHq2rSVKlVW42/wgVGwZdt8VX9ztKiAgqve1BbjNFmcAytb74YSOgFic5Wwl6uglx8LiwdY93ShQY+maVsPhEj8jFjGe2JlMscX8QgzkfxowrOpdlXsMSYgbG0ccBkXWZXbsh8tsUH9g+WNAoGAbQ5avOo0uF603Uts7ZFC0Lia0Vcx499oxGG5s8Js7tBAS6I7bRp5xokQHz/8BRKBL52oWJklpgy+N6oBnU7rFgRGaZBITABedqIWppHtac4ihUyQ+ZPRIfZqpmOXuaFJVmjUkm6zimpD+TOlaX3ZL88fdDX0E3xuBtBwBuxIkH0CgYEAlXyBbG2/fVV/PDUVCAA+aeWstojR1ncDhJmFnENSk5I/y3mh+d+u4ZG3hmVQZfR1EYM+n9wPQ2LxqNpGPA8o4JK/MSfVKun4lBwjkergHzxWJ5AMuYL1DPrOtMPEqrTqOHfVzSZGsz9cMK4tDWETKKFBOM/5oSdGGW3oYvzcS0M=";

	/**
	 * @Description: 代发任务确认提交
	 * @Author: huyc
	 * @Date: 2024-11-12
	 * @return: R
	 **/
	public R<String> submitIcbcTransactionFlow(String totalAmt, String totalCount, String wxNo
			, String url, String mdCode) {
		//应用方加密串
		UiIcbcClient client = new UiIcbcClient(icbcConfigProperties.getAppId(), IcbcConstants.SIGN_TYPE_RSA2,
				icbcConfigProperties.getAppPrivateKey(), IcbcConstants.CHARSET_UTF8);
		JftUiPayrollComfirmSubmitRequestV1 request = new JftUiPayrollComfirmSubmitRequestV1();
		request.setServiceUrl("https://gw.open.icbc.com.cn/ui/jft/ui/payroll/comfirmsubmit/V1");
		JftUiPayrollComfirmSubmitRequestV1.JjftUiPayrolComfirmSubmitRequestV1BizV1 bizContent =
				new JftUiPayrollComfirmSubmitRequestV1.JjftUiPayrolComfirmSubmitRequestV1BizV1();
		//appid
		bizContent.setAppId(icbcConfigProperties.getAppId());
		//HR系统名称
		bizContent.setAppName("HRO");
		//企业编号
		bizContent.setOutVendorId(icbcConfigProperties.getCompanyNo());
		//操作类型：1-受理 2-审核
		bizContent.setOprType("1");
		//总金额 oprType 为2时，非必输,金额单位分
		//bizContent.setTotalAmt("2")
		bizContent.setTotalAmt(totalAmt);
		//总笔数 oprType 为2时，非必输
		//bizContent.setTotalCount("2")
		bizContent.setTotalCount(totalCount);
		//批次号--每日批号不能重复,系统生成批次号
		//bizContent.setAppSerialno("WX203")
		bizContent.setAppSerialno(wxNo);
		//文件校验方式 1：sha256校验、2：sm3校验；上送为空默认按照sha256校验
		bizContent.setFileCheckSign("1");
		//客户本地文件路径 {企业编号}_{批次号}_{代发方式}_yyyyMMdd.xls 拼接起来总长不能超过36位
		//{平台编号}_{企业编号}_{批次号}_{代发方式}_yyyyMMdd .zip 压缩文件中，包含代发工资指令文件信息，为xls格式，xls文件名称同zip包文件名称
		bizContent.setLocalFilepath("D:/icbcFile/" + url);
		//文件md码
		//bizContent.setFileMdcode(getMdCode("D:/icbcFile/020101190_WX203_0_20241112.xls"))
		bizContent.setFileMdcode(mdCode);

		//文件类型：1-代发工资 2-报销
		bizContent.setFileType("1");
		bizContent.setNotifyUrl(null);
		bizContent.setAppRemark("备注");
		request.setBizContent(bizContent);
//		System.out.println("request: " + JSON.toJSONString(request))

		try {
			String result = client.buildPostForm(request);
			if (Common.isNotNull(result)) {
				return R.ok(result);
			}
		} catch (IcbcApiException e) {
			log.error("银企付款发放失败", e);
			return R.failed("发放失败");
		}
		return R.failed("发放失败！");
	}

	/**
	 * @Description: 代发任务批次明细查询
	 * @Author: huyc
	 * @Date: 2024-11-12
	 * @return: R
	 **/
	public JftApiPayrollQueryDetailResponseV1 selectIcbcTransactionFlowInfo(String wxNo, String startId, String endId) {

		DefaultIcbcClient client = new DefaultIcbcClient(icbcConfigProperties.getAppId(), IcbcConstants.SIGN_TYPE_RSA2,
				icbcConfigProperties.getAppPrivateKey(), IcbcConstants.CHARSET_UTF8, IcbcConstants.FORMAT_JSON,
				icbcConfigProperties.getApigwPublicKey(), IcbcConstants.ENCRYPT_TYPE_AES, icbcConfigProperties.getAesKey()
				, null, null);
		JftApiPayrollQueryDetailRequestV1 request = new JftApiPayrollQueryDetailRequestV1();
		request.setServiceUrl("https://gw.open.icbc.com.cn/api/jft/api/payroll/querydetail/V1");
		JftApiPayrollQueryDetailRequestV1.JftApiPayrollQueryDetailRequestV1Biz bizContent = new
				JftApiPayrollQueryDetailRequestV1.JftApiPayrollQueryDetailRequestV1Biz();
		bizContent.setAppId(icbcConfigProperties.getAppId());
		//企业编号
		bizContent.setOutVendorId(icbcConfigProperties.getCompanyNo());
		//查询类型:1 批次 2 批次明细
		bizContent.setType("2");
		//批次号，appSerialno为空时，必输
		// bizContent.setAppBatserialno("WX203")
		bizContent.setAppBatserialno(wxNo);
		//内部批次号，组成规则：批次号-顺序号，appBatserialno为空时必输
//		bizContent.setAppSerialno("WX04-1");
		//开始条数，如果送1，则返回排序的第一条开始，appBatserialno不为空时必输
		//bizContent.setStartId("0")
		bizContent.setStartId(startId);
		//结束条数，每次最多返回50条，返回条数按照结束-开始+1，appBatserialno不为空时必输
		//bizContent.setEndId("10")
		bizContent.setEndId(endId);
		request.setBizContent(bizContent);
		try {
			// 请求报文：下次改 appBatserialno 即可
			//{"bizContent":{"appBatserialno":"WX1737440304440","appId":"11000000000000028685","endId":"1","outVendorId":"020101190","startId":"0","type":"2"},"bizContentClass":"com.icbc.api.request.JftApiPayrollQueryDetailRequestV1$JftApiPayrollQueryDetailRequestV1Biz","extraParameters":{},"method":"POST","needEncrypt":false,"responseClass":"com.icbc.api.response.JftApiPayrollQueryDetailResponseV1","serviceUrl":"https://gw.open.icbc.com.cn/api/jft/api/payroll/querydetail/V1"}

			JftApiPayrollQueryDetailResponseV1 responseV1 = client.execute(request);
			if (Common.isNotNull(responseV1)) {
				return responseV1;
			}
		} catch (IcbcApiException e) {
			log.error("查询银企付款结果出错：", e);
		}
		return null;
	}

	/**
	 * @Description: 根据银行卡号查询银行信息
	 * @Author: huyc
	 * @Date: 2024-11-12
	 * @return: R
	 **/
	@Override
	public R querybankinfo() {

		DefaultIcbcClient client = new DefaultIcbcClient(icbcConfigProperties.getAppId(), IcbcConstants.SIGN_TYPE_CA_SM_ICBC,
				icbcConfigProperties.getAppPrivateKey(), IcbcConstants.CHARSET_UTF8, IcbcConstants.FORMAT_JSON, null,
				null, null, icbcConfigProperties.getCaSm(), null);
		client.setIcbc_ca(icbcConfigProperties.getCaSmIcbc());
		try {
			MybankEnterpriseAccountQuerybankinfoRequestV1.MybankEnterpriseAccountQuerybankinfoRequestBizV1 bizContent =
					new MybankEnterpriseAccountQuerybankinfoRequestV1.MybankEnterpriseAccountQuerybankinfoRequestBizV1();
			MybankEnterpriseAccountQuerybankinfoRequestV1 request = new MybankEnterpriseAccountQuerybankinfoRequestV1();
			// 请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
			bizContent.setTransCode("QBKNC");
			// 当天
			String nowDate = DateUtil.getThisDay();
			bizContent.setTranDate(nowDate);
			bizContent.setTranTime("103231001");
			bizContent.setLanguage("zh_CN");
			bizContent.setfSeqNo("AHWX" + System.currentTimeMillis());
			//银行卡号
			bizContent.setCardNo("1302015209250019444");
			request.setServiceUrl("https://gw.open.icbc.com.cn/api/mybank/enterprise/account/querybankinfo/V1");
			request.setBizContent(bizContent);
			MybankEnterpriseAccountQuerybankinfoResponseV1 response = client.execute(request);
			if (response.isSuccess()) {
				// 业务成功处理
				return R.ok(response);
			} else {
				// 失败
				return R.failed("error");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.ok();
	}

	public R asyncNotice(HttpServletRequest request) throws Exception {

		//验签
		String api = "/icbcIssue/notifyUrl";
		boolean verifyFlag = verifySignData(request, api);
		String returnJson;
		if (verifyFlag) {// 验签成功
			log.info("解密...");
			String bizContent = dencrypt(request);
			log.info("解密后参数:" + bizContent);// 进行自己的处理,此处默认处理成功，返回通知方成功,return_code=0
			String copReturnCode = "0";// 通知合作方接收成功的返回码，固定
			String copReturnMsg = "success";// 合作方的返回信息，固定
			returnJson = sign(request, copReturnCode, copReturnMsg);
			log.error("通知响应json结果：{}", returnJson);
			return R.ok(returnJson);
		} else {// 验签失败
			String copReturnCode = "-12345";
			String copReturnMsg = "icbc jft sign not pass.";
			returnJson = sign(request, copReturnCode, copReturnMsg);
			log.error("通知响应json结果：{}", returnJson);
			return R.failed(returnJson);
		}
	}

	public String getMdCode(String filePath) {

		FileInputStream in = null;
		byte[] buffer = new byte[1024];
		String mdCode;
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			in = new FileInputStream(filePath);
			int len;
			while ((len = in.read(buffer, 0, 1024)) != -1) {
				digest.update(buffer, 0, len);
			}
			BigInteger bigInt = new BigInteger(1, digest.digest());
			mdCode = bigInt.toString();
			return mdCode;
		} catch (NoSuchAlgorithmException noSuchExc) {
			mdCode = null;
		} catch (IOException exception) {
			exception.printStackTrace();
			return null;
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException exc) {
					exc.printStackTrace();
				}
			}
		}
		return mdCode;
	}

	/**
	 * 验签方法
	 *
	 * @param request
	 * @param path
	 * @return
	 * @throws Exception
	 */
	private boolean verifySignData(HttpServletRequest request, String path) throws Exception {
		// 网关公钥
		Map<String, String> params = new HashMap<>();
		String api = request.getParameter("api");
		String from = request.getParameter("from");
		String appId = request.getParameter("app_id");
		String charset = request.getParameter("charset");
		String format = request.getParameter("format");
		//String encrypt_type = request.getParameter("encrypt_type");
		String timestamp = request.getParameter("timestamp");
		String bizContent = request.getParameter("biz_content");
		String signType = request.getParameter("sign_type");
		String sign = request.getParameter("sign");
		params.put("from", from);
		params.put("api", api);
		params.put("app_id", appId);
		params.put("charset", charset);
		params.put("format", format);
		//params.put("encrypt_type", encrypt_type);
		params.put("timestamp", timestamp);
		params.put("biz_content", bizContent);
		params.put("sign_type", signType);// 目前上行网关签名暂时仅支持RSA
		//验证工行上行网关RSA签名
		String signStr = WebUtils.buildOrderedSignStr(path, params);
		log.error("验签入参，signStr：[[{}]], sign_type：[[{}]], APIGW_PUBLIC_KEY：[[{}]], charset：[[{}]], sign：[[{}]]",
				signStr, signType, icbcConfigProperties.getApigwPublicKey(), sign);
		return IcbcSignature.verify(signStr, signType, icbcConfigProperties.getApigwPublicKey(), charset, sign);

	}

	/**
	 * 解密
	 *
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private String dencrypt(HttpServletRequest request) throws IOException {
		String bizContent = URLDecoder.decode(request.getParameter("biz_content"), "utf-8");
		// 解析请求数据map
		ObjectMapper mapper = new ObjectMapper();
		Map<String, String> transMap = mapper.readValue(bizContent, Map.class);
		// 获取报文密文信息
		String notifyData = transMap.get("notifyData");
		return new String(Base64.getDecoder().decode(notifyData));
	}

	/**
	 * 加签方法
	 *
	 * @param request
	 * @param copReturnCode
	 * @param copReturnMsg
	 * @return
	 * @throws Exception
	 */
	private String sign(HttpServletRequest request, String copReturnCode, String copReturnMsg) throws Exception {
		String msgId = new SimpleDateFormat("yyyyMMdd").format(new Date())
				+ new SimpleDateFormat("HHmmss").format(new Date());
		String responseBizContent = "{\"return_code\":\"" + copReturnCode + "\",\"return_msg\":\"" + copReturnMsg + "\""
				+ ",\"msg_id\":\"" + msgId + "\"}";
		String charset = request.getParameter("charset");// 调用过程使用的编码格式

		//商户对消息返回响应进行签名，签名方式需与在API平台登记APP的sign_type保持一致(目前基本都是RSA2)
		String signType = IcbcConstants.SIGN_TYPE_RSA2;
		String signStr = "\"response_biz_content\":" + responseBizContent + "," + "\"sign_type\":" + "\"" + signType
				+ "\"";
		String signParam = IcbcSignature.sign(signStr, signType, icbcConfigProperties.getAppPrivateKey(), charset);
		String returnJson = "{\"response_biz_content\":" + responseBizContent + ",\"sign_type\":\"" + signType + "\""
				+ ",\"sign\":\"" + signParam + "\"}";
		return returnJson;
	}

	/**
	 * @param fdId
	 * @param type 类型 1：主表附件；2：明细表附件
	 * @Description: 下载文件主入口
	 * @Author: hgw
	 * @Date: 2024/11/18 9:27
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<com.yifu.cloud.plus.v1.ekp.entity.EkpBankAtta>
	 **/
	@Override
	@Transactional
	public R<EkpBankAttaReturnVo> getIssueFileByFdId(String fdId, String type) {
		if (Common.isNotNull(fdId) && Common.isNotNull(type)) {
			String redisKey = "DOWN_BANK_"+fdId;
			// 返回EKP的Vo
			EkpBankAttaReturnVo vo = new EkpBankAttaReturnVo();

			List<EkpBankExcelVo> list;
			// 获取配置的行号
			Map<String, EkpBankCodeConfiglVo> bankMap = ekpBankGrantDetailService.getEkpBankCodeConfiglVo();
			// 1主表整体下载
			if (CommonConstants.ONE_STRING.equals(type)) {
				EkpBankPayTask main = ekpBankPayTaskService.getById(fdId);
				if (main == null) {
					return R.failed("未找到表数据！");
				} else if (Common.isNotNull(main.getFdDownloadNum()) && Common.isNotNull(main.getFdFailNum())
						&& (CommonConstants.ZERO_INT == main.getFdDownloadNum() || main.getFdDownloadNum().equals(main.getFdFailNum()))) {
					if (Common.isNotNull(redisUtil.get(redisKey))) {
						return R.failed("数据锁定中，请耐心等待！！");
					} else {
						redisUtil.set(redisKey, 600L);
					}
					// 新下载
					list = ekpBankGrantDetailService.getEkpBankExcelVoByIdAndMain(fdId);
					R<EkpBankAttaReturnVo> returnVoR = getNewFileByMain(fdId, type, vo, list, main, bankMap);
					redisUtil.remove(redisKey);
					return returnVoR;
				} else if (Common.isNotNull(main.getFdAttaSrc())) {
					// 取URL数据返回
					return getOldAttaUrl(vo, main.getFdAttaSrc(), main.getFdAttaName());
				}
			} else if (CommonConstants.TWO_STRING.equals(type)) {
				// 2明细表
				EkpBankGrantDetail detail = ekpBankGrantDetailService.getById(fdId);
				if (detail == null) {
					return R.failed("未找到表数据！");
				} else if (Common.isNotNull(detail.getFdDownloadNum()) && Common.isNotNull(detail.getFdFailNum())
						&& (CommonConstants.ZERO_INT == detail.getFdDownloadNum() || detail.getFdDownloadNum().equals(detail.getFdFailNum()))) {
					if (Common.isNotNull(redisUtil.get(redisKey))) {
						return R.failed("数据下载中，请耐心等待！");
					} else {
						redisUtil.set(redisKey, 600L);
					}
					// 新下载
					list = ekpBankGrantDetailService.getEkpBankExcelVoByIdAndDetail(fdId);
					R<EkpBankAttaReturnVo> returnVoR = getNewFileByDetail(fdId, type, vo, list, detail, bankMap);
					redisUtil.remove(redisKey);
					return returnVoR;
				} else if (Common.isNotNull(detail.getFdAttaSrc())) {
					// 取URL数据返回
					return getOldAttaUrl(vo, detail.getFdAttaSrc(), detail.getFdAttaName());
				}
			}
			return R.failed("请处理表数据的下载次数与失败次数，fdId=" + fdId + "；type=" + type);
		} else {
			return R.failed("ID、类型不可为空");
		}
	}

	/**
	 * @Description: 直接下载
	 * @Author: hgw
	 * @Date: 2024/11/20 17:17
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<com.yifu.cloud.plus.v1.ekp.vo.EkpBankAttaReturnVo>
	 **/
	private R<EkpBankAttaReturnVo> getOldAttaUrl(EkpBankAttaReturnVo vo, String srcStr, String attaName) {
		URL url = ossUtil.getObjectUrl(null, srcStr);
		vo.setFdAttaUrl(url.toString());
		vo.setFdAttaName(attaName);
		return R.ok(vo);
	}


	/**
	 * @param fdId 主键
	 * @param type 类型，1主表2明细表
	 * @param vo   返回EKP的Vo
	 * @param list 数据主体
	 * @param main 主表
	 * @Description: 保存主表
	 * @Author: hgw
	 * @Date: 2024/11/20 17:08
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<com.yifu.cloud.plus.v1.ekp.vo.EkpBankAttaReturnVo>
	 **/
	private R<EkpBankAttaReturnVo> getNewFileByMain(String fdId, String type, EkpBankAttaReturnVo vo
			, List<EkpBankExcelVo> list, EkpBankPayTask main, Map<String, EkpBankCodeConfiglVo> bankMap) {
		if (list != null && !list.isEmpty()) {
			EkpBankAtta atta = getNewFileCore(fdId, type, vo, list, bankMap);
			if (atta != null) {
				main.setFdAttaName(atta.getFdAttaName());
				main.setFdAttaSrc(atta.getFdAttaSrc());
				main.setFdAttaId(atta.getFdId());
				main.setFdDownloadNum(main.getFdDownloadNum() + 1);
				main.setFdWxNo(atta.getWxNo());
				main.setFdMdCode(atta.getMdCode());
				ekpBankPayTaskService.updateById(main);
				return R.ok(vo);
			}
		}
		return R.failed("未找到待发放的明细数据，下载失败！");
	}

	/**
	 * @param fdId 主键
	 * @param type 类型，1主表2明细表
	 * @param vo   返回EKP的Vo
	 * @param list 数据主体
	 * @param main 主表
	 * @Description: 保存明细表
	 * @Author: hgw
	 * @Date: 2024/11/20 17:08
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<com.yifu.cloud.plus.v1.ekp.vo.EkpBankAttaReturnVo>
	 **/
	private R<EkpBankAttaReturnVo> getNewFileByDetail(String fdId, String type, EkpBankAttaReturnVo vo
			, List<EkpBankExcelVo> list, EkpBankGrantDetail main, Map<String, EkpBankCodeConfiglVo> bankMap) {
		if (list != null && !list.isEmpty()) {
			EkpBankAtta atta = getNewFileCore(fdId, type, vo, list, bankMap);
			if (atta != null) {
				main.setFdAttaName(atta.getFdAttaName());
				main.setFdAttaSrc(atta.getFdAttaSrc());
				main.setFdAttaId(atta.getFdId());
				main.setFdDownloadNum(main.getFdDownloadNum() + 1);
				main.setFdWxNo(atta.getWxNo());
				main.setFdMdCode(atta.getMdCode());
				ekpBankGrantDetailService.updateById(main);
				return R.ok(vo);
			}
		}
		return R.failed("未找到待发放的明细数据，下载失败！！");
	}

	private EkpBankAtta getNewFileCore(String fdId, String type, EkpBankAttaReturnVo vo, List<EkpBankExcelVo> list
			, Map<String, EkpBankCodeConfiglVo> bankMap) {
		EkpBankCodeSet codeSet;
		R<EkpBankCodeSet> bankInfoQuery;
		EkpBankCodeConfiglVo bankVo;
		// 组装
		//工行的卡号bin list
		List<String> binList = baseMapper.getAllIcbcCardBinInfo();
		for (EkpBankExcelVo excelVo : list) {
			if (Common.isEmpty(excelVo.getFdRecipientBankCode())) {
				//工行的卡号通过bin来判断，如果是工行的卡号，则不需要行名行号
				// 检查长度是否足够
				boolean flag = false;
				if (Common.isNotNull(binList) && !binList.isEmpty() && excelVo.getFdPayeeAccount().length() >= 5) {
					for (String bin : binList) {
						if ((bin.length() == 5 && excelVo.getFdPayeeAccount().substring(0, 5).equals(bin)) ||
								(bin.length() == 6 && excelVo.getFdPayeeAccount().length() >= 6 &&
										excelVo.getFdPayeeAccount().substring(0, 6).equals(bin))) {
							excelVo.setFdRecipientBankCode(null);
							excelVo.setFdRecipientBank(null);
							flag = true;
							break;
						}
					}
				}
				if (!flag) {
					// 查询行号
					bankInfoQuery = icbcTransactionFlowQueryService.querybankinfo(excelVo.getFdPayeeAccount());
					if (bankInfoQuery != null && bankInfoQuery.getCode() == CommonConstants.SUCCESS && bankInfoQuery.getData() != null) {
						codeSet = bankInfoQuery.getData();
						excelVo.setFdRecipientBankCode(codeSet.getFdRecipientBankCode());
						excelVo.setFdRecipientBank(codeSet.getFdRecipientBank());
					} else if (Common.isNotNull(excelVo.getFdRecipientBank())) {
						bankVo = bankMap.get(excelVo.getFdRecipientBank());
						if (bankVo != null) {
							excelVo.setFdRecipientBankCode(bankVo.getFdRecipientBankCode());
							excelVo.setFdRecipientBank(bankVo.getFdRecipientBank());
						}
					}
				}
			}
		}
		String batchNo = "WX" + new Date().getTime();
		String cur = ekpBankGrantDetailService.getWxNoByWxNo(batchNo);
		if (Common.isNotNull(cur)) {
			batchNo = "WX" + new Date().getTime();
		}
		// 组装、上传文件
		return getEkpBankAttaVo(batchNo, vo, fdId, Integer.parseInt(type), list);
	}


	/**
	 * @param batchNo     批次号
	 * @param returnVo    返回EKP的Vo
	 * @param linkId      附件关联的id
	 * @param linkType    类型，1银企付款主表，2银企付款详情表
	 * @param accountList 数据list
	 * @Description: 生成文件，保存附件等
	 * @Author: hgw
	 * @Date: 2024/11/20 17:05
	 * @return: com.yifu.cloud.plus.v1.ekp.entity.EkpBankAtta
	 **/
	private <T> EkpBankAtta getEkpBankAttaVo(String batchNo, EkpBankAttaReturnVo returnVo, String linkId, Integer linkType, List<T> accountList) {

		//客户本地文件路径 {企业编号}_{批次号}_{代发方式}_yyyyMMdd.xls 拼接起来总长不能超过36位
		//bizContent.setLocalFilepath("D:/icbcFile/020101190_WX203_0_20241112.xls")

		InputStream templateIs = this.getClass().getResourceAsStream("/template/ekpBankTemplat.xls");

		String filePath = "ekpBankDownFile";
		String fileName = icbcConfigProperties.getCompanyNo() + "_" + batchNo + "_0_" + DateUtil.getThisDay() + CommonConstants.XLS;
		String key = filePath + "/" + fileName;

		EasyExcelFactory.write(filePath).withTemplate(templateIs).excelType(ExcelTypeEnum.XLS)
				.sheet("模板") // 根据需要选择或指定sheet名称
				.doWrite(accountList);

		//EasyExcelFactory.write(filePath, tClass).sheet(preFileName + "报表生成").doWrite(accountList)
		File file = new File(filePath);
		try (InputStream inputStream = new FileInputStream(file)) {

			// 调用上传服务
			boolean flag = ossUtil.uploadFileByStream(inputStream, key, null);
			if (flag) {
				log.info("文件：" + fileName + "上传至存储空间" + ossUtil.getBucketName() + "成功！");
				EkpBankAtta atta = new EkpBankAtta();
				atta.setFdAttaName(fileName);
				atta.setFdAttaSrc(key);
				atta.setFdAttaSize(file.length());
				atta.setFdCreateTime(LocalDateTime.now());
				atta.setFdLinkId(linkId);
				atta.setFdLinkType(linkType);
				atta.setMdCode(getMdCode(filePath));
				atta.setWxNo(batchNo);
				ekpBankAttaService.save(atta);
				URL url = ossUtil.getObjectUrl(null, key);
				returnVo.setFdAttaUrl(url.toString());
				returnVo.setFdAttaName(fileName);
				return atta;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//删除临时文件
			try {
				if (Common.isNotNull(file)) {
					org.apache.commons.io.FileUtils.forceDelete(file);
				}
				if (null != templateIs) {
					templateIs.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * @param response
	 * @Description: 验证下载文件的正确性
	 * @Author: hgw
	 * @Date: 2024/11/20 17:37
	 * @return: void
	 **/
	@Override
	public void exportAll(HttpServletResponse response) {
		List<EkpBankExcelVo> list = ekpBankGrantDetailService.getEkpBankExcelVoByIdAndMain("1");
		ServletOutputStream out = null;
		InputStream templateIs = null;
		try {
			out = response.getOutputStream();
			response.setContentType(CommonConstants.MULTIPART_FORM_DATA);
			response.setCharacterEncoding("utf-8");

			String batchNo = "WX203";
			String fileName = icbcConfigProperties.getCompanyNo() + "_" + batchNo + "_0_" + DateUtil.getThisDay() + CommonConstants.XLS;
			response.setHeader(CommonConstants.CONTENT_DISPOSITION, CommonConstants.ATTACHMENT_FILENAME + URLEncoder.encode(fileName, "UTF-8"));

			templateIs = this.getClass().getResourceAsStream("/template/ekpBankTemplat.xls");
			EasyExcelFactory.write(out).withTemplate(templateIs).excelType(ExcelTypeEnum.XLS)
					.sheet("模板") // 根据需要选择或指定sheet名称
					//.doFill(accountList, fillConfig)
					.doWrite(list);

			if (Common.isNotNull(list)) {
				list.clear();
			}
			out.flush();
		} catch (Exception e) {
			log.error("执行异常", e);
		} finally {
			try {
				if (null != out) {
					out.close();
				}
				if (null != templateIs) {
					templateIs.close();
				}
			} catch (IOException e) {
				log.error("执行异常", e);
			}
		}
	}

	/**
	 * @param fdId 主键
	 * @param type 类型 1：主表；2明细表
	 * @Description: 发放银企付款
	 * @Author: hgw
	 * @Date: 2024/11/22 14:13
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Override
	@Transactional
	public R<String> submitBankTask(String fdId, String type, String submitUser) {
		if (Common.isNotNull(fdId) && Common.isNotNull(type)) {
			String redisKey = "SUBMIT_BANK_"+fdId;
			if (Common.isNotNull(redisUtil.get(redisKey))) {
				return R.failed("数据锁定中，请耐心等待！");
			} else {
				redisUtil.set(redisKey, 600L);
			}
			try {
				// 1主表
				if (CommonConstants.ONE_STRING.equals(type)) {
					EkpBankPayTask main = ekpBankPayTaskService.getById(fdId);
					if (main == null) {
						redisUtil.remove(redisKey);
						return R.failed("未找到表数据！");
					}
					if (!"待发放".equals(main.getFdGrantStatus())) {
						redisUtil.remove(redisKey);
						return R.failed("状态不是待发放！");
					}
					if (Common.isNotNull(main.getFdDownloadNum()) && Common.isNotNull(main.getFdGrantNum())
							&& main.getFdDownloadNum() > main.getFdGrantNum()) {
						if (Common.isEmpty(main.getFdMoney())) {
							redisUtil.remove(redisKey);
							return R.failed("数据错误，无金额！");
						}
						int count = ekpBankGrantDetailService.getCountByIdAndMain(fdId);
						String totalAmt = String.valueOf(BigDecimalUtils.safeMultiply(main.getFdMoney(), new BigDecimal("100"), 0));
						String totalCount = String.valueOf(count);
						String wxNo = main.getFdWxNo();
						String url = main.getFdAttaName();
						String mdCode = main.getFdMdCode();
						R<String> returnR = submitIcbcTransactionFlow(totalAmt, totalCount, wxNo, url, mdCode);
						if (returnR.getCode() == CommonConstants.SUCCESS) {
							// 存储日志
							saveIcbcLogBaseInfoBySumbit(returnR.getData(), wxNo + "_main", fdId);
							// 发放次数+1，改主表或明细表“发放状态”为“发放中”
							main.setFdGrantStatus("发放中");
							main.setFdGrantNum(main.getFdGrantNum() + 1);
							main.setFdSubmitCashier(submitUser);
							ekpBankPayTaskService.updateById(main);
							// 同步更新明细的发放时间、发放状态
							ekpBankGrantDetailService.updateStatusByGrant(fdId);
							// 更新 工资支出 的 银企出纳名字
							ekpBankGrantDetailService.updateGongZiZhiChuTable(fdId, submitUser);
							ekpBankGrantDetailService.updateGongZiZhiChuMain(fdId, submitUser);
						}
						redisUtil.remove(redisKey);
						return returnR;
					} else {
						redisUtil.remove(redisKey);
						return R.failed("请检查主表的GrantNum！");
					}
				} else {
					// 2明细表
					EkpBankGrantDetail detail = ekpBankGrantDetailService.getById(fdId);
					if (detail == null) {
						redisUtil.remove(redisKey);
						return R.failed("未找到明细表数据！");
					}
					if (!"待发放".equals(detail.getFdHandleStatus())) {
						redisUtil.remove(redisKey);
						return R.failed("状态不是待发放！");
					}
					if (Common.isNotNull(detail.getFdDownloadNum()) && Common.isNotNull(detail.getFdGrantNum())
							&& detail.getFdDownloadNum() > detail.getFdGrantNum()) {
						if (Common.isEmpty(detail.getFdMoney())) {
							redisUtil.remove(redisKey);
							return R.failed("数据错误，无金额！");
						}
						String totalAmt = String.valueOf(BigDecimalUtils.safeMultiply(detail.getFdMoney(), new BigDecimal("100"), 0));
						String totalCount = "1";
						String wxNo = detail.getFdWxNo();
						String url = detail.getFdAttaName();
						String mdCode = detail.getFdMdCode();
						R<String> returnR = submitIcbcTransactionFlow(totalAmt, totalCount, wxNo, url, mdCode);
						if (returnR.getCode() == CommonConstants.SUCCESS) {
							// 存储日志
							saveIcbcLogBaseInfoBySumbit(returnR.getData(), wxNo, fdId);
							// 发放次数+1，改主表或明细表“发放状态”为“发放中”
							detail.setFdHandleStatus("发放中");
							detail.setFdCreateTime(LocalDateTime.now());
							detail.setFdGrantNum(detail.getFdGrantNum() + 1);
							ekpBankGrantDetailService.updateById(detail);
						}
						redisUtil.remove(redisKey);
						return returnR;
					} else {
						redisUtil.remove(redisKey);
						return R.failed("请检查明细表的GrantNum！");
					}
				}
			} catch (Exception e) {
				log.error("银企付款发放发放异常", e);
			} finally {
				redisUtil.remove(redisKey);
			}
		} else {
			return R.failed("传参错误！");
		}
		return R.failed("传参错误！！");
	}

	/**
	 * @Description: 每小时获取银企付款结果
	 * @Author: hgw
	 * @Date: 2024/11/22 17:00
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Override
	public R<String> doGetEkpBankStatus() {

		// 1：获取发放中的主表数据，查询工行接口
		List<EkpBankResultVo> mainList = ekpBankPayTaskService.getEkpBankMainByNeedResultMain();

		JftApiPayrollQueryDetailResponseV1 responseV1;

		// 发放日志
		List<EkpBankGrantLogDetail> logDetailList;
		EkpBankGrantLog logs;
		EkpBankGrantLogDetail logDetail;
		BigDecimal money;
		// 主表
		if (mainList != null && !mainList.isEmpty()) {
			int startNum;
			int endNum;
			List<JftApiPayrollQueryDetailResponseV1.JftApiPayrollDetail> dataList;
			List<EkpBankGrantDetail> detailDataList;
			EkpBankGrantDetail detailData;
			EkpBankPayTask main;
			List<EkpBankGrantDetail> oldDetailList;
			Map<String, EkpBankGrantDetail> oldMap;
			BigDecimal moneySuccess;
			BigDecimal moneyFail;
			BigDecimal moneyAll;
			int numSuccess;
			int numFail;
			List<EkpBankIcbcLog> icbcLogList = new ArrayList<>();
			for (EkpBankResultVo vo : mainList) {
				for (int i = 0; i < vo.getNum(); i += 49) {
					startNum = i;
					endNum = i + 49;
					if (endNum > vo.getNum()) {
						endNum = vo.getNum();
					}
					responseV1 = selectIcbcTransactionFlowInfo(vo.getFdWxNo(), String.valueOf(startNum), String.valueOf(endNum));
					if (Common.isNotNull(responseV1)) {
						// 生成工行接口数据记录
						setIcbcLogBaseInfo(responseV1, icbcLogList, vo.getFdWxNo() + "_" + startNum + "_" + endNum, vo.getFdId());
						// 返回码，交易成功返回0，正表示业务报错，负表示系统报错
						if ("0".equals(responseV1.getReturn_code())) {
							// 处理状态： 00-待提交,01-已提交 02-待授权 03-待银行处理, 04-处理成功，05-处理失败
							if ("04".equals(responseV1.getStatus())) {

								// 生成日志主表
								logs = new EkpBankGrantLog();
								saveNewEkpBankGrantLog(responseV1, vo, vo.getFdId(), logs);

								dataList = responseV1.getDatalist();
								oldDetailList = ekpBankGrantDetailService.getListByParentId(vo.getFdId());
								oldMap = new HashMap<>();
								if (oldDetailList != null && !oldDetailList.isEmpty()) {
									for (EkpBankGrantDetail temp : oldDetailList) {
										oldMap.put(temp.getFdSerialNumber(), temp);
									}
								}
								moneyAll = BigDecimal.ZERO;
								moneySuccess = BigDecimal.ZERO;
								moneyFail = BigDecimal.ZERO;
								numSuccess = 0;
								numFail = 0;
								if (dataList != null && !dataList.isEmpty()) {
									logDetailList = new ArrayList<>();
									detailDataList = new ArrayList<>();
									for (JftApiPayrollQueryDetailResponseV1.JftApiPayrollDetail data : dataList) {

										// 交易时间
										if (Common.isNotNull(data.getCompanyHandleTime())) {
											logs.setFdTransactionTime(DateUtil.stringToDateByFormat(data.getCompanyHandleTime(), DateUtil.DATETIME_PATTERN_SECOND));
										}
										money = BigDecimalUtils.safeDivide(new BigDecimal(data.getPayamt()), new BigDecimal("100"), 2);
										moneyAll = BigDecimalUtils.safeAdd(moneyAll, money);
										// 初始化日志明细
										logDetail = new EkpBankGrantLogDetail();
										setLogDetailBaseInfo(logs, money, logDetail, data);

										detailData = oldMap.get(data.getPlatDetailId());
										if (detailData != null) {
											// 收款人名称
											logDetail.setFdPayee(detailData.getFdPayeeName());
											// 收款银行
											logDetail.setFdRecipientBank(detailData.getFdRecipientBank());
											if ("02".equals(data.getResult()) || "5".equals(data.getResult())) {
												moneySuccess = BigDecimalUtils.safeAdd(moneySuccess, money);
												numSuccess++;
												detailData.setFdGrantStatus("发放成功");
											} else {
												moneyFail = BigDecimalUtils.safeAdd(moneyFail, money);
												numFail++;
												detailData.setFdGrantStatus("发放失败");
												detailData.setFdHandleStatus("");
												detailData.setFdFailureFeedback(data.getCompanyHandlerResult());
												// 批量更新中信银行表数据，使发放失败处理有数据出现
												ekpBankGrantDetailService.updateZhongXinStatus(detailData.getFdSalaryId(), detailData.getFdId(), data.getCompanyHandlerResult());
												ekpBankGrantDetailService.updateZhongXinMainStatus(detailData.getFdSalaryId(), detailData.getFdId(), data.getCompanyHandlerResult());
											}
											detailDataList.add(detailData);
										}
										logDetailList.add(logDetail);
									}
									ekpBankGrantLogDetailService.saveBatch(logDetailList);
									main = new EkpBankPayTask();
									main.setFdId(vo.getFdId());
									main.setFdGrantStatus("已发放");
									ekpBankPayTaskService.updateById(main);
									// 更新明细状态为成功或失败
									ekpBankGrantDetailService.updateBatchById(detailDataList);


								}
								if (numSuccess > 0) {
									moneyFail = BigDecimalUtils.safeSubtract(moneyAll, moneySuccess);
									numFail = vo.getNum() - numSuccess;
								}
								// 失败总金额
								logs.setFdFailFee(moneyFail);
								// 成功总金额
								logs.setFdSuccessFee(moneySuccess);
								// 总金额
								logs.setFdSumFee(moneyAll);
								// 失败总笔数
								logs.setFdTransactionFailTotal(numFail);
								// 成功总笔数
								logs.setFdTransactionSuccessTotal(numSuccess);
								ekpBankGrantLogService.updateById(logs);
							} else if ("05".equals(responseV1.getStatus())) {
								main = new EkpBankPayTask();
								// 2024-12-3 10:58:24 银企付款任务，定时获取结果，返回状态码05的，现在全部改为处理失败
								// ，取第一条结果里的原因展示在主列表上。@易服智享 孙兆松  @易服智享 金龙弟
								if (responseV1.getDatalist() != null && !responseV1.getDatalist().isEmpty()
										&& Common.isNotNull(responseV1.getDatalist().get(0).getCompanyHandlerResult())) {
									main.setFdErrorMsg(responseV1.getDatalist().get(0).getCompanyHandlerResult());
								} else {
									main.setFdErrorMsg(responseV1.getErrordesc());
								}
								main.setFdId(vo.getFdId());
								// 2024-11-29 16:55:32 经 项目经理王鹏 与 产品经理 孙兆松 沟通，将 “银企付款任务”列表的“发放状态”的值，由“拒绝授权”改为“处理失败”。
								main.setFdGrantStatus("处理失败");
								ekpBankPayTaskService.updateById(main);
								// 更新明细状态为 发放失败，原因为处理失败
								//ekpBankGrantDetailService.updateStatusByGrantFail(vo.getFdId())
							}
						}
					}
				}
			}
			if (!icbcLogList.isEmpty()) {
				ekpBankIcbcLogService.saveBatch(icbcLogList);
			}
		}

		// 2：获取主表已发放且明细表发放中的明细表数据，查询工行接口
		List<EkpBankResultVo> detailList = ekpBankPayTaskService.getEkpBankMainByNeedResultDetail();
		// 明细表
		if (detailList != null && !detailList.isEmpty()) {
			List<JftApiPayrollQueryDetailResponseV1.JftApiPayrollDetail> dataList;
			List<EkpBankGrantDetail> detailDataList = new ArrayList<>();
			EkpBankGrantDetail detailData;
			JftApiPayrollQueryDetailResponseV1.JftApiPayrollDetail data;
			List<EkpBankIcbcLog> icbcLogList = new ArrayList<>();
			for (EkpBankResultVo vo : detailList) {
				responseV1 = selectIcbcTransactionFlowInfo(vo.getFdWxNo(), "0", "1");
				if (Common.isNotNull(responseV1)) {
					// 生成工行接口数据记录
					setIcbcLogBaseInfo(responseV1, icbcLogList, vo.getFdWxNo(), vo.getFdId());
					// Return_code返回码，交易成功返回0，正表示业务报错，负表示系统报错
					// Status处理状态： 00-待提交,01-已提交 02-待授权 03-待银行处理, 04-处理成功，05-处理失败
					if ("0".equals(responseV1.getReturn_code()) && ("04".equals(responseV1.getStatus()) || "05".equals(responseV1.getStatus()))
							&& responseV1.getDatalist() != null && !responseV1.getDatalist().isEmpty()) {

						dataList = responseV1.getDatalist();
						// 明细只有一条
						data = dataList.get(0);

						money = BigDecimalUtils.safeDivide(new BigDecimal(data.getPayamt()), new BigDecimal("100"), 2);
						detailData = new EkpBankGrantDetail();
						detailData.setFdId(vo.getFdId());
						detailData.setFdSerialNumber(data.getPlatDetailId());

						// 生成日志主表
						logs = new EkpBankGrantLog();
						// 失败总金额
						logs.setFdFailFee(BigDecimal.ZERO);
						// 成功总金额
						logs.setFdSuccessFee(BigDecimal.ZERO);
						// 总金额
						logs.setFdSumFee(money);
						// 失败总笔数
						logs.setFdTransactionFailTotal(0);
						// 成功总笔数
						logs.setFdTransactionSuccessTotal(0);
						if ("02".equals(data.getResult()) || "5".equals(data.getResult())) {
							// 失败总笔数
							logs.setFdTransactionSuccessTotal(1);
							logs.setFdSuccessFee(money);
							detailData.setFdGrantStatus("发放成功");
							detailData.setFdHandleStatus("已处理");
						} else {
							// 失败总笔数
							logs.setFdTransactionFailTotal(1);
							// 失败总金额
							logs.setFdFailFee(money);
							detailData.setFdGrantStatus("发放失败");
							detailData.setFdHandleStatus("");
							detailData.setFdFailureFeedback(data.getCompanyHandlerResult());
							detailData.setFdFailNum(vo.getFdFailNum() + 1);
							// 批量更新中信银行表数据，使发放失败处理有数据出现
							ekpBankGrantDetailService.updateZhongXinStatus(vo.getFdSalaryId(), vo.getFdId(), data.getCompanyHandlerResult());
							ekpBankGrantDetailService.updateZhongXinMainStatus(vo.getFdSalaryId(), vo.getFdId(), data.getCompanyHandlerResult());
						}
						// 交易时间
						if (Common.isNotNull(data.getCompanyHandleTime())) {
							logs.setFdTransactionTime(DateUtil.stringToDateByFormat(data.getCompanyHandleTime(), DateUtil.DATETIME_PATTERN_SECOND));
						}
						saveNewEkpBankGrantLog(responseV1, vo, vo.getFdParentId(), logs);
						// 初始化日志明细
						logDetail = new EkpBankGrantLogDetail();
						setLogDetailBaseInfo(logs, money, logDetail, data);
						// 收款人名称
						logDetail.setFdPayee(vo.getFdPayeeName());
						logDetail.setFdRecipientBank(vo.getFdRecipientBank());
						ekpBankGrantLogDetailService.save(logDetail);
						detailDataList.add(detailData);
					}
				}
			}
			// 更新明细状态为成功或失败
			ekpBankGrantDetailService.updateBatchById(detailDataList);
			if (!icbcLogList.isEmpty()) {
				ekpBankIcbcLogService.saveBatch(icbcLogList);
			}
		}
		return R.ok();
	}

	/**
	 * 重写获取PDF文件的方法
	 * 该方法通过SFTP协议从工商银行的服务器下载PDF文件
	 * @Author: huych
	 * @Date: 2025/5/19 17:36
	 **/
	@Override
	public R getPdfFile() throws IOException {
		// 工商银行SFTP服务器地址
		String host = "gw.open.icbc.com.cn";
		// 工商银行SFTP服务器端口
		int port = 8001;
		// 登录用户名
		String username = "wxrl";
		// 私钥路径（用于身份验证）
		//E:\IdeaProjects\yifu_mvp\yifu-ekp\yifu-ekp-biz\src\main\resources\icbc\icbc
		String privateKeyPath = "";
		InputStream inputStream = getClass().getClassLoader().getResourceAsStream("icbc");
		if (inputStream == null) {
			throw new FileNotFoundException("资源未找到");
		}

		File tempFile = File.createTempFile("temp-", ".tmp");
		tempFile.deleteOnExit(); // JVM退出时删除临时文件

		try (FileOutputStream out = new FileOutputStream(tempFile)) {
			byte[] buffer = new byte[1024];
			int bytesRead;
			while ((bytesRead = inputStream.read(buffer)) != -1) {
				out.write(buffer, 0, bytesRead);
			}
		}
		privateKeyPath = tempFile.getAbsolutePath();

		// 远程目录路径
		log.info("秘钥文件目录: " + privateKeyPath);
		// 远程目录路径
		String remoteDir = "/JFTStatementDownload/download";
		Session session = null;
		ChannelSftp channelSftp = null;

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -1); // 获取前一天日期
		String targetDate = sdf.format(cal.getTime());
		cal.add(Calendar.DATE, -1); // 获取前两天日期
		String targetDateTwo = sdf.format(cal.getTime());
		try {
			JSch jsch = new JSch();
			// 添加私钥（注意：需要是没有密码保护的私钥）
			jsch.addIdentity(privateKeyPath);

			// 创建会话
			session = jsch.getSession(username, host, port);

			// 关闭严格的主机密钥检查（生产环境应配置known_hosts）设置为no,已有公私钥验证
			session.setConfig("StrictHostKeyChecking", "no");

			// 连接会话
			session.connect();

			// 创建SFTP通道
			channelSftp = (ChannelSftp) session.openChannel("sftp");
			channelSftp.connect();

			// 切换远程目录
			channelSftp.cd(remoteDir);

			// 列出目录文件
			Vector<ChannelSftp.LsEntry> files = channelSftp.ls("*");
			log.info("找到文件数量: " + files.size());

			// 下载所有文件
			//ESC 字符：在 Java 中，ESC 字符可以用 \u001B 表示。
			//如果输入字符串中可能包含连续的 ESC 字符（如 \u001B\u001B），split("\u001B") 会在结果数组中生成空字符串（""）。如果需要过滤掉空字符串，可以使用 split("\u001B", -1) 或后续处理。
			for (ChannelSftp.LsEntry entry : files) {
				if (!entry.getAttrs().isDir()) {
					String fileName = entry.getFilename();
					//找到存回单的压缩文件
					if (fileName.startsWith("Receipt_00_") && (fileName.contains(targetDate) || fileName.contains(targetDateTwo))
							&& fileName.endsWith(".zip")) {
						try {
							// 1. 处理压缩包文件
							String date = extractDateFromFileName(fileName);
							String indexFileName = "ReceiptIndex_00_" + date + ".bin";

							// 2. 查找对应的索引文件
							Optional<ChannelSftp.LsEntry> indexEntry = files.stream()
									.filter(e -> e.getFilename().equals(indexFileName))
									.findFirst();

							if (!indexEntry.isPresent()) {
								log.info("未找到对应的索引文件：{}", indexFileName);
								continue;
							}
							// 3. 创建临时目录
							String tempDir = System.getProperty("java.io.tmpdir") + "sftp_processing/" + System.currentTimeMillis() + "/";
							File dir = new File(tempDir);
							if (!dir.exists() && !dir.mkdirs()) {
								throw new IOException("Failed to create directory: " + tempDir);
							}
							log.info("临时目录: " + tempDir);

							// 4. 下载并解压压缩包
							String localZipPath = tempDir + fileName;
							channelSftp.get(fileName, localZipPath);
							String unzipDir = tempDir + "unzipped/";
							unzipFile(localZipPath, unzipDir);

							// 5. 下载并解析索引文件
							String localIndexPath = tempDir + indexFileName;
							channelSftp.get(indexFileName, localIndexPath);
							Map<String, String> salaryPdfMap = parseIndexFile(localIndexPath);

							// 6. 处理映射关系
							processPdfFiles(unzipDir, salaryPdfMap);

							// 7. 清理临时文件
							FileUtils.deleteDirectory(new File(tempDir));

						} catch (Exception e) {
							log.error("处理文件[{}]时发生错误：", fileName, e);
						}
					}
//					log.info("正在下载: " + fileName);
//					channelSftp.get(fileName, localPath + fileName);
				}
			}
		} catch (JSchException e) {
			// 如果认证失败，直接返回
			if (e.getMessage().contains("Auth fail")) {
				return R.failed("认证失败");
			}
		} catch (SftpException e) {
			// 如果SFTP操作失败，直接返回
			return R.failed(e.getMessage());
		} finally {
			// 确保通道和会话被正确关闭
			if (channelSftp != null && channelSftp.isConnected()) {
				channelSftp.exit();
			}
			if (session != null && session.isConnected()) {
				session.disconnect();
			}
		}
		return R.ok();
	}

	// 辅助方法定义
	private String extractDateFromFileName(String fileName) {
		Pattern pattern = Pattern.compile(".*_(\\d{8})_.*\\.zip");
		Matcher matcher = pattern.matcher(fileName);
		if (matcher.find()) {
			return matcher.group(1);
		}
		throw new IllegalArgumentException("无效的文件名格式：" + fileName);
	}

	private void unzipFile(String zipPath, String outputDir) throws IOException {
		byte[] buffer = new byte[1024];
		try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath))) {
			ZipEntry zipEntry = zis.getNextEntry();
			while (zipEntry != null) {
				File newFile = new File(outputDir, zipEntry.getName());

				// 防止Zip Slip攻击
				String canonicalPath = newFile.getCanonicalPath();
				if (!canonicalPath.startsWith(new File(outputDir).getCanonicalPath())) {
					throw new IOException("非法文件路径：" + zipEntry.getName());
				}

				if (zipEntry.isDirectory()) {
					newFile.mkdirs();
				} else {
					newFile.getParentFile().mkdirs();
					try (FileOutputStream fos = new FileOutputStream(newFile)) {
						int len;
						while ((len = zis.read(buffer)) > 0) {
							fos.write(buffer, 0, len);
						}
					}
				}
				zipEntry = zis.getNextEntry();
			}
		}
	}

	private Map<String, String> parseIndexFile(String indexPath) throws IOException {
		Map<String, String> mapping = new HashMap<>();
		char escChar = (char) 27;

		Files.lines(Paths.get(indexPath), StandardCharsets.UTF_8)
				.forEach(line -> {
					String[] parts = line.split(Pattern.quote(String.valueOf(escChar)));
					if (parts.length >= 4) {
						String salaryFile = parts[2].contains("_") ?
								parts[2].substring(parts[2].indexOf('_') + 1) :
								parts[2];
						mapping.put(salaryFile, parts[3]);
					}
				});

		return mapping;
	}

	private void processPdfFiles(String pdfDir, Map<String, String> mapping) {
		File directory = new File(pdfDir);
		File[] pdfFiles = directory.listFiles((dir, name) -> name.endsWith(".pdf"));

		if (pdfFiles == null) return;

		String filePath = "ekpBankDownPdfFile";
		EkpBankAtta attaOld;
		for (File pdfFile : pdfFiles) {
			String pdfName = pdfFile.getName();
			String salaryFileName = mapping.entrySet().stream()
					.filter(entry -> pdfName.equals(entry.getValue()))
					.findFirst()
					.map(Map.Entry::getKey)
					.orElse(null);

			if (salaryFileName != null) {
				//文件上传至阿里云，以便ekp服务调用
				try (InputStream inputStream = new FileInputStream(pdfFile)) {
					String key = filePath + "/" + pdfName;
					// 调用上传服务
					boolean flag = ossUtil.uploadFileByStream(inputStream, key, null);
					if (flag) {
						String linkId;
						int underscoreIndex = salaryFileName.indexOf('_');
						if (underscoreIndex != -1) {
							// 输出: WX1747376807702
							linkId = salaryFileName.substring(0, underscoreIndex);
						} else {
							// 处理没有下划线的情况（根据需求可选）
							linkId = salaryFileName;
						}
						log.info("文件：" + pdfName + "上传至存储空间" + ossUtil.getBucketName() + "成功！");
						//重复的过滤
						attaOld = ekpBankAttaService.getOne(Wrappers.<EkpBankAtta>query().lambda().
								eq(EkpBankAtta::getFdLinkId, linkId).last(CommonConstants.LAST_ONE_SQL));
						if (Common.isEmpty(attaOld)) {
							EkpBankAtta atta = new EkpBankAtta();
							atta.setFdAttaName(pdfName);
							atta.setFdAttaSrc(key);
							atta.setFdAttaSize(pdfFile.length());
							atta.setFdCreateTime(LocalDateTime.now());
							atta.setFdLinkId(linkId);
							atta.setFdLinkType(CommonConstants.THREE_INT);
							ekpBankAttaService.save(atta);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * @Description: 发放记录日志
	 * @Author: hgw
	 * @Date: 2024/11/27 17:36
	 * @return: void
	 **/
	private void saveIcbcLogBaseInfoBySumbit(String info
			, String fdWxNo, String fdId) {
		EkpBankIcbcLog icbcLog = new EkpBankIcbcLog();
		icbcLog.setFdCreateTime(LocalDateTime.now());
		icbcLog.setFdWxNo(fdWxNo);
		icbcLog.setFdParentId(fdId);
		icbcLog.setFdType(1);
		icbcLog.setFdLog(info);
		ekpBankIcbcLogService.save(icbcLog);
	}

	/**
	 * @Description: 获取结果记录入职
	 * @Author: hgw
	 * @Date: 2024/11/27 17:36
	 * @return: void
	 **/
	private void setIcbcLogBaseInfo(JftApiPayrollQueryDetailResponseV1 responseV1, List<EkpBankIcbcLog> icbcLogList
			, String fdWxNo, String fdId) {
		EkpBankIcbcLog icbcLog = new EkpBankIcbcLog();
		icbcLog.setFdCreateTime(LocalDateTime.now());
		icbcLog.setFdWxNo(fdWxNo);
		icbcLog.setFdParentId(fdId);
		icbcLog.setFdType(2);
		icbcLog.setFdLog(JSON.toJSONString(responseV1));
		icbcLogList.add(icbcLog);
	}

	/**
	 * @Description: 初始化日志明细
	 * @Author: hgw
	 * @Date: 2024/11/26 20:08
	 * @return: com.yifu.cloud.plus.v1.ekp.entity.EkpBankGrantLogDetail
	 **/
	private void setLogDetailBaseInfo(EkpBankGrantLog logs, BigDecimal money, EkpBankGrantLogDetail logDetail
			, JftApiPayrollQueryDetailResponseV1.JftApiPayrollDetail data) {
		// 指令状态
		logDetail.setFdCommandStatus(STATUS_MAP.get(data.getResult()));
		logDetail.setFdParentId(logs.getFdId());
		logDetail.setFdMoney(money);
		// 收款账号
		logDetail.setFdPayeeAccount(data.getRecDepAcc());
		logDetail.setFdRemark(data.getCompanyHandlerResult());
		// 汇款用途
		logDetail.setFdRemittancePurpose("工资");
	}

	/**
	 * @Description: 初始化生成日志主表
	 * @Author: hgw
	 * @Date: 2024/11/26 20:09
	 * @return: com.yifu.cloud.plus.v1.ekp.entity.EkpBankGrantLog
	 **/
	private void saveNewEkpBankGrantLog(JftApiPayrollQueryDetailResponseV1 responseV1, EkpBankResultVo vo
			, String parentId, EkpBankGrantLog logs) {
		logs.setFdBatchNumber(vo.getFdWxNo());
		logs.setFdParentId(parentId);
		logs.setFdBatchPackage(responseV1.getRemark());
		logs.setFdBusinessType("代发工资");
		logs.setFdCurrency("人民币");
		logs.setFdDrawee(vo.getFdBankName());
		logs.setFdPaymentAccount(vo.getFdBankAccount());
		logs.setFdSubmitTime(LocalDateTime.now());
		// 总笔数
		logs.setFdTransactionTotal(vo.getNum());
		ekpBankGrantLogService.save(logs);
	}

}
