/*
 *    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.salary.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
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.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ResultConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.DateUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.EasyExcelStyle;
import com.yifu.cloud.plus.v1.yifu.ekp.vo.EkpSalaryParamVo;
import com.yifu.cloud.plus.v1.yifu.insurances.vo.EkpSocialViewVo;
import com.yifu.cloud.plus.v1.yifu.salary.entity.TDeptSee;
import com.yifu.cloud.plus.v1.yifu.salary.entity.THaveSalaryNosocial;
import com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount;
import com.yifu.cloud.plus.v1.yifu.salary.mapper.SysConfigLimitMapper;
import com.yifu.cloud.plus.v1.yifu.salary.mapper.TDeptSeeMapper;
import com.yifu.cloud.plus.v1.yifu.salary.mapper.TSalaryAccountMapper;
import com.yifu.cloud.plus.v1.yifu.salary.service.TSalaryAccountService;
import com.yifu.cloud.plus.v1.yifu.salary.util.SalaryConstants;
import com.yifu.cloud.plus.v1.yifu.salary.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.compress.utils.Lists;
import org.apache.ibatis.annotations.Param;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 工资报账主表（工资条）
 *
 * @author hgw
 * @date 2022-08-05 11:40:14
 */
@Log4j2
@RequiredArgsConstructor
@Service
public class TSalaryAccountServiceImpl extends ServiceImpl<TSalaryAccountMapper, TSalaryAccount> implements TSalaryAccountService {
	@Autowired
	private TDeptSeeMapper deptSeeMapper;

	private AtomicInteger atomicInteger = new AtomicInteger(0);
	//初始化附件上传队列上限值
	private  int maxLimit = 1;

	private final SysConfigLimitMapper configLimitMapper;
	/**
	 * 工资报账主表（工资条）简单分页查询
	 *
	 * @param tSalaryAccount 工资报账主表（工资条）
	 * @return
	 */
	@Override
	public IPage<TSalaryAccount> getTSalaryAccountPage(Page<TSalaryAccount> page, TSalaryAccountSearchVo tSalaryAccount) {
		// 不可查询项目合集 fxj 2024-10-23 优化
		List<TDeptSee> depts = deptSeeMapper.selectList(Wrappers.<TDeptSee>query().lambda().eq(TDeptSee::getCanSee,CommonConstants.ONE_INT));
		List<String> deptNos = null;
		if (Common.isNotNull(depts)){
			deptNos = depts.stream().map(TDeptSee::getDeptNo).collect(Collectors.toList());
		}
		int count = baseMapper.getTSalaryAccountPageCount(tSalaryAccount,deptNos);
		if (count < 100000){
			return baseMapper.getTSalaryAccountPage(page, tSalaryAccount,deptNos);
		}else {
			List<String> ids = baseMapper.getTSalaryAccountPageIds((page.getCurrent()==0?0:(page.getCurrent()-1))*page.getSize(),tSalaryAccount,deptNos,page.getSize());
			List<TSalaryAccount> data = baseMapper.getTSalaryAccountPageDataByIds(tSalaryAccount,ids);
			IPage<TSalaryAccount> pageData = new Page<TSalaryAccount>();
			pageData.setCurrent(page.getCurrent());
			pageData.setTotal(count);
			pageData.setSize(page.getSize());
			pageData.setRecords(data);
			return pageData;
		}

	}

	/**
	 * @Description: 项目薪酬查询-工资条查询
	 * @Author: hgw
	 * @Date: 2025/4/18 16:01
	 * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount>
	 **/
	@Override
	public IPage<TSalaryAccount> getEmpAccountPage(Page<TSalaryAccount> page, TSalaryAccountSearchVo searchVo) {
		return baseMapper.getEmpAccountPage(page, searchVo);
	}

	/**
	 * @Description: HCM查询
	 * @Author: hgw
	 * @Date: 2025-5-20 20:37:48
	 * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount>
	 **/
	@Override
	public List<TSalaryAccount> getSalaryByIdCardList(@Param("idCardList") List<String> idCardList, @Param("salaryMonth") String salaryMonth) {
		return baseMapper.getSalaryByIdCardList(idCardList, salaryMonth);
	}

	/**
	 * @Author fxj
	 * @Description
	 * @Date 15:27 2024/10/23
	 * @Param type 0 报账批量导出  1 报账审核人导出 2: 项目薪酬查询-工资条查询导出
	 * @return
	**/
	@Override
	public void exportAsso(HttpServletResponse response, TSalaryAccountSearchVo searchVo,int type) {
		maxLimit = configLimitMapper.getSysConfigLimitByKey("DOWN_LOAD_MAX_LIMIT");
		if (atomicInteger.incrementAndGet() <= maxLimit){
			try {
				if (CommonConstants.ZERO_INT == type){
					listExportNew(response, searchVo);
				}else if (CommonConstants.ONE_INT == type){
					auditExport(response, searchVo);
				} else if (CommonConstants.TWO_INT == type){
					getEmpAccountExport(response, searchVo);
				}
			}catch (Exception e){
				log.error("导出异常：",e);
			}finally {
				atomicInteger.decrementAndGet();
			}
		}else {
			// 前面做了+1（atomicInteger.incrementAndGet()）这里也要-1
			atomicInteger.decrementAndGet();
			log.error("超出阈值："+ ResultConstants.FILE_DOWN_LOAD_DATA);
			exportError(response, ResultConstants.FILE_DOWN_LOAD_DATA);
		}

	}
	/**
	 * 工资报账主表（工资条）批量导出
	 *
	 * @return
	 */
	@Override
	public void listExport(HttpServletResponse response, TSalaryAccountSearchVo searchVo) {
		String fileName = "员工报账查询批量导出" + DateUtil.getThisTime() + CommonConstants.XLSX;
		//获取要导出的列表
		List<SalaryAccountExportVo> list = new ArrayList<>();
		// 不可查询项目合集 fxj 2024-10-23 优化
		List<TDeptSee> depts = deptSeeMapper.selectList(Wrappers.<TDeptSee>query().lambda().eq(TDeptSee::getCanSee,CommonConstants.ONE_INT));
		List<String> deptNos = null;
		if (Common.isNotNull(depts)){
			deptNos = depts.stream().map(TDeptSee::getDeptNo).collect(Collectors.toList());
		}
		long count = noPageCountDiyLast(searchVo,deptNos);
		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, "UTF-8"));
			//非管理员导出 大于100W 提示“导出量过大，请选择更多查询条件！如果确定要导出这些数据请联系系统管理员操作”
			if (count > 1000000) {
				out.write(CommonConstants.SOCIAL_EXPORT_LIMIT.getBytes("GBK"));
				out.close();
				return;
			}
			// 这里 需要指定写用哪个class去写，然后写到第一个sheet，然后文件流会自动关闭
			ExcelWriter excelWriter = EasyExcelFactory.write(out, TSalaryAccount.class).includeColumnFiledNames(searchVo.getExportFields()).build();
			int index = 0;
			WriteSheet writeSheet = null;
			if (count > CommonConstants.ZERO_INT) {
				List<String> ids = null;
				for (int i = 0; i <= count; i += CommonConstants.EXCEL_EXPORT_LIMIT_1) {
					// 获取实际记录
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT_1);
					if (count < 200000){
						list = noPageDiyLast(searchVo,deptNos);
					}else{
						ids = baseMapper.noPageDiyLastIds(searchVo,null,deptNos);
						if (Common.isNotNull(ids)){
							list = baseMapper.noPageDiyLastByIds(searchVo,ids);
						}else {
							list = new ArrayList<>();
						}
					}

					if (Common.isNotNull(list)) {
						if (i%CommonConstants.EXCEL_EXPORT_LIMIT==0){
							writeSheet = EasyExcelFactory.writerSheet("工资报账主表（工资条）" + index).build();
							index++;
						}
						excelWriter.write(list, writeSheet);
						list.clear();
					}
					if (Common.isNotNull(ids)){
						ids.clear();
					}
				}
			} else {
				writeSheet = EasyExcelFactory.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);
			}
		}
	}

	/**
	 * 导出员工报账查询结果到Excel
	 *
	 * @param response HTTP响应对象，用于输出Excel文件
	 * @param searchVo 搜索条件对象，用于查询工资账户信息
	 */
	public void listExportNew(HttpServletResponse response, TSalaryAccountSearchVo searchVo) {
		// 生成文件名，包含当前时间戳和文件扩展名
		String fileName = "员工报账查询批量导出" + DateUtil.getThisTime() + CommonConstants.XLSX;

		// 不可查询项目合集
		List<TDeptSee> depts = deptSeeMapper.selectList(Wrappers.<TDeptSee>query().lambda()
				.eq(TDeptSee::getCanSee, CommonConstants.ONE_INT));
		List<String> deptNos = null;
		if (Common.isNotNull(depts)) {
			deptNos = depts.stream().map(TDeptSee::getDeptNo).collect(Collectors.toList());
		}

		// 计算符合条件的记录总数
		long count = baseMapper.noPageCountDiyLastNew(searchVo,searchVo.getIdList(), deptNos);

		try (ServletOutputStream out = response.getOutputStream()) {
			response.setContentType(CommonConstants.MULTIPART_FORM_DATA);
			response.setCharacterEncoding("utf-8");
			response.setHeader(CommonConstants.CONTENT_DISPOSITION,
					CommonConstants.ATTACHMENT_FILENAME + URLEncoder.encode(fileName, "UTF-8"));

			// 非管理员导出大于100W提示
			if (count > 1000000) {
				out.write(CommonConstants.SOCIAL_EXPORT_LIMIT.getBytes("GBK"));
				return;
			}

			// 使用SXSSF模式，设置缓存行数为100，减少内存占用
			ExcelWriterBuilder writerBuilder = EasyExcel.write(out, TSalaryAccount.class)
					.registerWriteHandler(new SheetWriteHandler() {
						@Override
						public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
													 WriteSheetHolder writeSheetHolder) {
							// 启用SXSSF模式
							if (writeWorkbookHolder.getWorkbook() instanceof SXSSFWorkbook) {
								((SXSSFWorkbook) writeWorkbookHolder.getWorkbook()).setCompressTempFiles(true);
							}
						}
					})
					.autoCloseStream(true)
					.inMemory(false) // 设置为false以启用磁盘缓存
					.includeColumnFiledNames(searchVo.getExportFields());

			ExcelWriter excelWriter = writerBuilder.build();

			int sheetIndex = 0;
			WriteSheet writeSheet = EasyExcel.writerSheet("工资报账主表（工资条）" + sheetIndex).build();

			// 分批查询和写入
			if (count > CommonConstants.ZERO_INT) {
				int batchSize = 100000;
				int totalPages = (int) Math.ceil((double) count / batchSize);
				List<SalaryAccountExportVo> batchList;
				for (int page = 1; page <= totalPages; page++) {
					// 每10万条数据切换一个新sheet，防止单个sheet过大
					if ((page - 1) * batchSize % 100000 == 0 && (page - 1) * batchSize > 0) {
						sheetIndex++;
						writeSheet = EasyExcel.writerSheet("工资报账主表（工资条）" + sheetIndex).build();
					}

					// 设置分页参数
					searchVo.setLimitStart((page - 1) * batchSize);
					searchVo.setLimitEnd(batchSize);

					batchList = baseMapper.noPageDiyLastNew(searchVo,searchVo.getIdList(),deptNos);
					if (Common.isNotNull(batchList)) {
						excelWriter.write(batchList, writeSheet);
						// 及时清空批次数据
						batchList.clear();
					}
				}
			} else {
				excelWriter.write(new ArrayList<>(), writeSheet);
			}
			excelWriter.finish();
			out.flush();
		} catch (Exception e) {
			log.error("执行异常", e);
			throw new RuntimeException("导出失败", e);
		}
	}


	/**
	 * 审核人导出
	 *
	 * @return
	 */
	@Override
	public void auditExport(HttpServletResponse response, TSalaryAccountSearchVo searchVo) {
		String fileName = "员工报账导出" + DateUtil.getThisTime() + CommonConstants.XLSX;
		//获取要导出的列表
		List<TSalaryAccountExportVo> list = new ArrayList<>();
		long count = baseMapper.auditExportCountDiy(searchVo, searchVo.getIdList());
		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, "UTF-8"));
			//非管理员导出 大于100W 提示“导出量过大，请选择更多查询条件！如果确定要导出这些数据请联系系统管理员操作”
			if (count > 1000000) {
				out.write(CommonConstants.SOCIAL_EXPORT_LIMIT.getBytes("GBK"));
				out.close();
				return;
			}
			// 这里 需要指定写用哪个class去写，然后写到第一个sheet，然后文件流会自动关闭
			ExcelWriter excelWriter = EasyExcelFactory.write(out, TSalaryAccountExportVo.class).includeColumnFiledNames(searchVo.getExportFields()).build();
			int index = 0;
			WriteSheet writeSheet = null;
			if (count > CommonConstants.ZERO_INT) {
				Map<String,TSalaryAccountItemExportVo> itemExportVoMap = new HashMap<>();
				List<String> idList = null;
				List<String> idStandardList = null;
				List<TAuditExportStandardVo> standardItems = null;
				Map<String,TAuditExportStandardVo> itemStandardMap = new HashMap<>();
				Map<String,TAuditExportItemVo> itemAnnualBonusMap = new HashMap<>();
				Map<String,TAuditExportItemVo> itemPersionTaxMap = new HashMap<>();
				Map<String,TAuditExportItemVo> itemAnnuityMap = new HashMap<>();
				Map<String,TAuditExportItemVo> itemSubsidyMap = new HashMap<>();
				Map<String,TAuditExportItemVo> itemCarNoTaxMap = new HashMap<>();
				List<TSalaryAccountItemExportVo> items = null;
				List<TAuditExportItemVo> annualBonusItems;
				List<TAuditExportItemVo> exemptionPersionTaxItems;
				List<TAuditExportItemVo> enterpriseAnnuityItems;
				List<TAuditExportItemVo> phoneSubsidyItems;
				List<TAuditExportItemVo> carNoTaxItems;
				List<String> ids = null;
				for (int i = 0; i <= count; i += CommonConstants.EXCEL_EXPORT_LIMIT_1) {
					// 获取实际记录
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT_1);
					if (count < 200000){
						list = baseMapper.auditExportDiy(searchVo, searchVo.getIdList());
					}else{
						if (Common.isNotNull(searchVo.getIdList())){
							ids = searchVo.getIdList();
						}else {
							ids = baseMapper.auditExportDiyIds(searchVo, searchVo.getIdList());
						}
						if (Common.isNotNull(ids)){
							searchVo.setIdList(null);
							list = baseMapper.auditExportDiyByIds(ids);
						}else {
							list = new ArrayList<>();
						}
					}
					if (Common.isNotNull(ids)){
						ids.clear();
					}
					if (Common.isNotNull(list)) {
						//先把数据封装完成
						idList = list.stream().map(TSalaryAccountExportVo::getId).collect(Collectors.toList());
						idStandardList = list.stream().map(TSalaryAccountExportVo::getSalaryFormId).collect(Collectors.toList());
						//初始化明细数据MAP

						if (Common.isNotNull(idList)){
							items = baseMapper.auditExportSelectItems(idList);
							if (Common.isNotNull(items)){
								itemExportVoMap = items.stream().collect(Collectors.toMap(TSalaryAccountItemExportVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							items.clear();
							annualBonusItems = baseMapper.auditExportAnnualBonus(idList);
							if (Common.isNotNull(annualBonusItems)){
								itemAnnualBonusMap = annualBonusItems.stream().collect(Collectors.toMap(TAuditExportItemVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							annualBonusItems.clear();
							exemptionPersionTaxItems = baseMapper.auditExportExemptionPersionTax(idList);
							if (Common.isNotNull(exemptionPersionTaxItems)){
								itemPersionTaxMap = exemptionPersionTaxItems.stream().collect(Collectors.toMap(TAuditExportItemVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							exemptionPersionTaxItems.clear();
							enterpriseAnnuityItems = baseMapper.auditExportEnterpriseAnnuity(idList);
							if (Common.isNotNull(enterpriseAnnuityItems)){
								itemAnnuityMap = enterpriseAnnuityItems.stream().collect(Collectors.toMap(TAuditExportItemVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							enterpriseAnnuityItems.clear();
							phoneSubsidyItems = baseMapper.auditExportPhoneSubsidy(idList);
							if (Common.isNotNull(phoneSubsidyItems)){
								itemSubsidyMap = phoneSubsidyItems.stream().collect(Collectors.toMap(TAuditExportItemVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							phoneSubsidyItems.clear();
							carNoTaxItems = baseMapper.auditExportCarNoTax(idList);
							if (Common.isNotNull(carNoTaxItems)){
								itemCarNoTaxMap = carNoTaxItems.stream().collect(Collectors.toMap(TAuditExportItemVo::getSalaryAccountId,vo -> vo,(k1,k2) -> k1));
							}
							carNoTaxItems.clear();
						}
						if (Common.isNotNull(idStandardList)){
							standardItems = baseMapper.auditExportStandard(idStandardList);
							if (Common.isNotNull(standardItems)){
								itemStandardMap = standardItems.stream().collect(Collectors.toMap(TAuditExportStandardVo::getSalaryFormId,vo -> vo,(k1,k2) -> k1));
								standardItems.clear();
							}
						}

						//封装信息
						initResult(list, itemExportVoMap,itemStandardMap,itemAnnualBonusMap,itemPersionTaxMap,itemAnnuityMap,itemSubsidyMap,itemCarNoTaxMap);
						if (i%CommonConstants.EXCEL_EXPORT_LIMIT==0){
							writeSheet = EasyExcelFactory.writerSheet("工资报账" + index).build();
							index++;
						}
						excelWriter.write(list, writeSheet);
						list.clear();
					}
					clearMap(itemExportVoMap, idList, idStandardList, itemStandardMap, itemAnnualBonusMap, itemPersionTaxMap, itemAnnuityMap, itemSubsidyMap);
				}
			} else {
				writeSheet = EasyExcelFactory.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);
			}
		}
	}

	/**
	 * @Description: 项目薪酬查询-工资条查询导出
	 * @Author: hgw
	 * @Date: 2025-4-21 09:45:46
	 * @return: void
	 **/
	private void getEmpAccountExport(HttpServletResponse response, TSalaryAccountSearchVo searchVo) {
		String fileName = "工资条查询导出" + DateUtil.getThisTime() + CommonConstants.XLSX;
		//获取要导出的列表
		List<TSalaryAccountExportSpecialVo> list = new ArrayList<>();
		long count = baseMapper.getEmpAccountCount(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, "UTF-8"));
			//非管理员导出 大于10W 提示“导出量过大，请选择更多查询条件！如果确定要导出这些数据请联系系统管理员操作”
			if (count > 100000) {
				out.write(CommonConstants.SOCIAL_EXPORT_LIMIT.getBytes("GBK"));
				out.close();
				return;
			}

			List<String> titleAllList = baseMapper.getItemAllTitle(searchVo);
			List<List<String>> headList = Lists.newArrayList();
			String title = "工资月份,发放状态,结算月份,项目名称,员工姓名,银行卡号,开户行,身份证号,工资发放方式,社保扣缴月份" +
					",公积金扣缴月份,社保优先级,公积金优先级,年终奖扣税方案,是否扣除社保,是否扣除公积金";
			if (titleAllList != null && !titleAllList.isEmpty()) {
				for (String temp : titleAllList) {
					title += "," + temp;
				}
			}
			String[] strTemp = title.split(",");
			List<String> titleList;
			for (String temp : strTemp) {
				titleList = new ArrayList<>();
				titleList.add(temp);
				headList.add(titleList);
			}
			ExcelWriter excelWriter = EasyExcelFactory.write(out).registerWriteHandler(EasyExcelStyle.getBaseStyle())
					.head(headList).build();
			int index = 0;
			WriteSheet writeSheet = null;
			if (count > CommonConstants.ZERO_INT) {
				// 每次数据库查询条数
				int limit = 1000;
				int sheetIndex = 0;
				// 循环几次重新生成sheet(这里是循环10次，也就是10000条房一个sheet里)
				int cyclesNum = 10;
				// 固定的报账表列表
				List<TSalaryAccountExportSpecialVo> baseList;
				// 导出的全量内容列表
				List<List<String>> listContent = null;
				// 每一行的内容列表
				List<String> contentList = null;
				// 明细表总mvp
				Map<String, Map<String, String>> itemMap = null;
				// 每一行的mvp
				Map<String, String> tempMap;
				// 浮动的明细表
				List<TSalaryAccountExportSpecialItemVo> itemList = null;
				for (int i = 0; i < count; i += limit) {
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(limit);
					baseList = baseMapper.getEmpAccountExport(searchVo);
					listContent = new ArrayList<>();
					contentList = new ArrayList<>();
					if (baseList != null && !baseList.isEmpty()) {
						for (TSalaryAccountExportSpecialVo a : baseList) {
							contentList.add(a.getAccountId());
						}
						itemMap = new HashMap<>();
						tempMap = new HashMap<>();
						if (titleAllList != null && !titleAllList.isEmpty()) {
							itemList = baseMapper.getEmpAccountItemExport(searchVo.getSettlementMonth(), contentList);
							for (TSalaryAccountExportSpecialItemVo itemVo : itemList) {
								tempMap = itemMap.get(itemVo.getAccountId());
								if (tempMap == null) {
									tempMap = new HashMap<>();
								}
								tempMap.put(itemVo.getCnName(), itemVo.getTextValue());
								itemMap.put(itemVo.getAccountId(), tempMap);
							}
						}
						for (TSalaryAccountExportSpecialVo a : baseList) {
							contentList = new ArrayList<>();
							contentList.add(a.getExport1());
							contentList.add(a.getExport2());
							contentList.add(a.getExport3());
							contentList.add(a.getExport4());
							contentList.add(a.getExport5());
							contentList.add(a.getExport6());
							contentList.add(a.getExport7());
							contentList.add(a.getExport8());
							contentList.add(a.getExport9());
							contentList.add(a.getExport10());
							contentList.add(a.getExport11());
							contentList.add(a.getExport12());
							contentList.add(a.getExport13());
							contentList.add(a.getExport14());
							contentList.add(a.getExport15());
							contentList.add(a.getExport16());
							if (titleAllList != null && !titleAllList.isEmpty()) {
								tempMap = itemMap.get(a.getAccountId());
								for (String temp : titleAllList) {
									if (tempMap != null) {
										if (tempMap.get(temp) != null) {
											contentList.add(tempMap.get(temp));
										} else {
											contentList.add("");
										}
									} else {
										contentList.add("");
									}
								}
							}
							listContent.add(contentList);
						}
					}
					if (sheetIndex++ % cyclesNum == 0) {
						writeSheet = EasyExcelFactory.writerSheet("工资条" + index++).build();
					}
					excelWriter.write(listContent, writeSheet);
				}
				if (Common.isNotNull(listContent)) {
					listContent.clear();
				}
				if (Common.isNotNull(contentList)) {
					contentList.clear();
				}
				if (Common.isNotNull(itemMap)) {
					itemMap.clear();
				}
				if (Common.isNotNull(itemList)) {
					itemList.clear();
				}
			} else {
				writeSheet = EasyExcelFactory.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);
			}
		}
	}

	private void clearMap(Map<String, TSalaryAccountItemExportVo> itemExportVoMap, List<String> idList, List<String> idStandardList, Map<String, TAuditExportStandardVo> itemStandardMap, Map<String, TAuditExportItemVo> itemAnnualBonusMap, Map<String, TAuditExportItemVo> itemPersionTaxMap, Map<String, TAuditExportItemVo> itemAnnuityMap, Map<String, TAuditExportItemVo> itemSubsidyMap) {
		if (Common.isNotNull(idList)){
			idList.clear();
		}
		if (Common.isNotNull(idStandardList)){
			idStandardList.clear();
		}
		if (Common.isNotNull(itemExportVoMap)){
			itemExportVoMap.clear();
		}
		if (Common.isNotNull(itemStandardMap)){
			itemStandardMap.clear();
		}
		if (Common.isNotNull(itemAnnualBonusMap)){
			itemAnnualBonusMap.clear();
		}
		if (Common.isNotNull(itemPersionTaxMap)){
			itemPersionTaxMap.clear();
		}
		if (Common.isNotNull(itemAnnuityMap)){
			itemAnnuityMap.clear();
		}
		if (Common.isNotNull(itemSubsidyMap)){
			itemSubsidyMap.clear();
		}
	}

	private void initResult(List<TSalaryAccountExportVo> list,
							Map<String, TSalaryAccountItemExportVo> itemExportVoMap,
							Map<String,TAuditExportStandardVo> itemStandardMap,
							Map<String,TAuditExportItemVo> itemAnnualBonusMap,
							Map<String,TAuditExportItemVo>  itemPersionTaxMap,
							Map<String,TAuditExportItemVo>  itemAnnuityMap,
							Map<String,TAuditExportItemVo> itemSubsidyMap,
							Map<String,TAuditExportItemVo> itemCarNoTaxMap) {
		TSalaryAccountItemExportVo voTemp;
		TAuditExportStandardVo standardVo;
		TAuditExportItemVo itemVo;
		for (TSalaryAccountExportVo vo: list){
			voTemp = itemExportVoMap.get(vo.getId());
			if (Common.isNotNull(voTemp)){
				vo.setPdeductionMoney(voTemp.getPdeductionMoney());
				vo.setPdeductionDetail(voTemp.getPdeductionDetail());
			}
			standardVo = itemStandardMap.get(vo.getSalaryFormId());
			if (Common.isNotNull(standardVo)){
				vo.setStatus(standardVo.getStatus());
				vo.setBusinessPrimaryType(standardVo.getBusinessPrimaryTyp());
				vo.setBusinessSecondType(standardVo.getBusinessSecondType());
				vo.setBusinessThirdType(standardVo.getBusinessThirdType());
				//新增薪酬申请编号 fxj v1.7.10 2025-04-25
				vo.setApplyNo(standardVo.getApplyNo());
			}
			itemVo = itemAnnualBonusMap.get(vo.getId());
			if (Common.isNotNull(itemVo)){
				vo.setAnnualBonus(itemVo.getAnnualBonus());
			}
			itemVo = itemPersionTaxMap.get(vo.getId());
			if (Common.isNotNull(itemVo)){
				vo.setExemptionPersionTax(itemVo.getExemptionPersionTax());
			}
			itemVo = itemAnnuityMap.get(vo.getId());
			if (Common.isNotNull(itemVo)){
				vo.setEnterpriseAnnuity(itemVo.getEnterpriseAnnuity());
			}
			itemVo = itemSubsidyMap.get(vo.getId());
			if (Common.isNotNull(itemVo)){
				vo.setPhoneSubsidy(itemVo.getPhoneSubsidy());
			}
			// fxj 2025-02-28 车改补贴（不计税） MVP1.7.7
			itemVo = itemCarNoTaxMap.get(vo.getId());
			if (Common.isNotNull(itemVo)){
				vo.setCarNotTax(itemVo.getCarNoTax());
			}

		}
	}

	/**
	 * @Description: 根据工资id，返回报账明细（字段较少且有计算，其他地方勿用）
	 * @Author: hgw
	 * @Date: 2022/9/2 17:07
	 * @return: java.util.List<com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount>
	 **/
	@Override
	public List<TSalaryAccount> getListByIncome(String salaryId) {
		return baseMapper.getListByIncome(salaryId);
	}

	@Override
	public List<TSalaryAccount> noPageDiy(TSalaryAccountSearchVo searchVo) {
		return baseMapper.noPageDiy(searchVo,searchVo.getIdList());
	}

	@Override
	public List<SalaryAccountExportVo> noPageDiyLast(TSalaryAccountSearchVo searchVo,List<String> deptNos) {
		return baseMapper.noPageDiyLast(searchVo,searchVo.getIdList(),deptNos);
	}

	@Override
	public List<TSalaryAccount> getAccountListBySalaryId(TSalaryAccountSearchVo searchVo) {
		return baseMapper.getAccountListBySalaryId(searchVo);
	}

	@Override
	public List<String> getCardListBySalaryId(String salaryId) {
		return baseMapper.getCardListBySalaryId(salaryId);
	}

	@Override
	public List<String> getCardListBySalaryIdAndNotExists(String salaryId, String invoiceTitle, String settleMonth) {
		return baseMapper.getCardListBySalaryIdAndNotExists(salaryId, invoiceTitle, settleMonth);
	}

	@Override
	public Map<String, Integer> getAccountMapByKey(String invoiceTitle, String settleMonth, List<String> cardList) {
		Map<String, Integer> map = new HashMap<>();
		if (Common.isNotNull(cardList)) {
			List<String> keyList = baseMapper.getAccountListByKey(invoiceTitle, settleMonth, cardList);
			if (Common.isNotNull(keyList)) {
				for (String key : keyList) {
					map.put(key, CommonConstants.ONE_INT);
				}
			}
		}
		return map;
	}

	/**
	 * @param applyNo
	 * @Description: 导出报账专用hgw
	 * @Author: hgw
	 * @Date: 2024/4/18 11:00
	 * @return: java.util.List<com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount>
	 **/
	@Override
	public List<TSalaryAccountExportByEkpVo> getAccountListByApplyNo(String applyNo) {
		return baseMapper.getAccountListByApplyNo(applyNo);
	}

	private int noPageCountDiy(TSalaryAccountSearchVo searchVo) {
		return baseMapper.noPageCountDiy(searchVo,searchVo.getIdList());
	}

	private int noPageCountDiyLast(TSalaryAccountSearchVo searchVo,List<String> deptNos) {
		return baseMapper.noPageCountDiyLast(searchVo,searchVo.getIdList(),deptNos);
	}

	@Override
	public Map<String, Integer> getAccountCheckMap(String settleId, String settleMonth, String salaryType) {
		List<AccountCheckVo> list;
		if (CommonConstants.ZERO_STRING.equals(salaryType)) {
			list = baseMapper.getAccountCheckList(settleId, settleMonth);
		} else {
			list = baseMapper.getAccountCheckListLabor(settleId, settleMonth);
		}
		Map<String, Integer> map = new HashMap<>();
		if (list != null && !list.isEmpty()) {
			for (AccountCheckVo str : list) {
				map.put(str.getTitle() + CommonConstants.DOWN_LINE_STRING + str.getRelaySalary().setScale(2, BigDecimal.ROUND_HALF_UP), 1);
			}
		}
		return map;
	}

	@Override
	public Map<String, BigDecimal> getAccountSpecialMap(String invoiceTitle, String unitId, String salaryMonth) {
		List<AccountCheckVo> list = baseMapper.getAccountSpecialList(invoiceTitle, unitId, salaryMonth);
		Map<String, BigDecimal> map = new HashMap<>();
		if (list != null && !list.isEmpty()) {
			for (AccountCheckVo str : list) {
				map.put(str.getTitle(), str.getRelaySalary());
			}
		}
		return map;
	}

	/**
	 * @param empIdCard
	 * @param nowYear
	 * @Description: 获取当前年最小计税月
	 * @Author: hgw
	 * @Date: 2022/1/19 17:57
	 * @return: java.lang.String
	 **/
	@Override
	public String getMinTaxMonthByNowYear(String empIdCard, int nowYear) {
		return baseMapper.getMinTaxMonthByNowYear(empIdCard, nowYear);
	}

	@Override
	public Map<String, String> getMinTaxMonthByNowYearAndList(List<String> empIdCardList, int nowYear) {
		Map<String, String> taxMonthMap = new HashMap<>();
		if (empIdCardList != null && !empIdCardList.isEmpty()) {
			List<TSalaryAccount> list = baseMapper.getMinTaxMonthByNowYearAndList(empIdCardList, nowYear);
			if (list != null && !list.isEmpty()) {
				for (TSalaryAccount a : list) {
					taxMonthMap.put(a.getEmpIdcard(), a.getTaxMonth());
				}
			}
		}
		return taxMonthMap;
	}

	/**
	 * @Author fxj
	 * @Description 获取有工资无社保数据
	 * @Date 17:22 2022/8/16
	 * @Param
	 * @return
	**/
	@Override
	public List<THaveSalaryNosocial> getLastMonthTHaveSalaryNosocial(String month) {
		return baseMapper.getLastMonthTHaveSalaryNosocial(month,
				DateUtil.getYearAndMonth(month,-CommonConstants.ONE_INT),
				DateUtil.getYearAndMonth(month,-CommonConstants.TWO_INT));
	}

	@Override
	public List<String> getAccountYearCheckMap() {
		return baseMapper.getAccountYearCheckList();
	}

	@Override
	public List<EkpSalaryParamVo> getEkpSalaryParamList(String salaryId) {
		return baseMapper.getEkpSalaryParamList(salaryId);
	}

	@Override
	public void backSalaryBySalaryId(String salaryId) {
		baseMapper.backSalaryBySalaryId(salaryId);
	}

	@Override
	public Boolean updateSalarySettleStatus(List<EkpSocialViewVo> viewVoList) {
		TSalaryAccount account;
		try {
			if (!viewVoList.isEmpty()) {
				for (EkpSocialViewVo viewVo : viewVoList) {
					//根据明细id更新结算状态
					account = baseMapper.selectById(viewVo.getId());
					if (Common.isNotNull(account)) {
						if (CommonConstants.ZERO_STRING.equals(viewVo.getPayFlag())) {
							account.setIncomeSettleFlag(viewVo.getIncomeSettleFlag());
							account.setIncomeCollectFlag(viewVo.getIncomeCollectFlag());
						} else {
							account.setPaySettleFlag(viewVo.getPaySettleFlag());
							account.setPayCollectFlag(viewVo.getPayCollectFlag());
						}
						baseMapper.updateById(account);
					}
				}
			}
		} catch (Exception e) {
			log.error("更新薪资结算状态失败", e);
			return false;
		}
		return true;
	}

	/**
	 * @param page 分页
	 * @param settlementFormVo 结算单Vo
	 * @Description: B端薪酬第一个统计列表
	 * @Author: hgw
	 * @Date: 2020/8/21 11:38
	 * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.yifu.cloud.v1.hrms.api.vo.SettlementFormVo>
	 **/
	@Override
	public IPage<SettlementFormVo> getSettlementFormVoPage(Page<SettlementFormVo> page
			, SettlementFormVo settlementFormVo, List<String> settleDepartIdList){
		return baseMapper.getSettlementFormVoPage(page,settlementFormVo, settleDepartIdList);
	}

	/**
	 * @param salaryFormId 结算单id
	 * @Description: 工资详情-上面的统计
	 * @Author: hgw
	 * @Date: 2020-8-21 17:55:24
	 * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.yifu.cloud.v1.hrms.api.vo.SettlementFormVo>
	 **/
	@Override
	public SettlementFormVo getSettlementFormVoBySalaryFormId(String salaryFormId) {
		return baseMapper.getSettlementFormVoBySalaryFormId(salaryFormId);
	}

	/**
	 * @param page
	 * @param salaryAccountAndItemVo
	 * @Description:  获取报账以及薪资
	 * @Author: hgw
	 * @Date: 2020/8/21 15:32
	 * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.yifu.cloud.v1.hrms.api.vo.SalaryAccountAndItemVo>
	 **/
	@Override
	public IPage<SalaryAccountAndItemVo> getSalaryAccountAndItemVoPage(Page<SalaryAccountAndItemVo> page
			, SalaryAccountAndItemVo salaryAccountAndItemVo) {
		return baseMapper.getSalaryAccountAndItemVoPage(page, salaryAccountAndItemVo);
	}

	/**
	 * @param idList
	 * @Description: 根据idList获取报账信息
	 * @Author: hgw
	 * @Date: 2023/2/2 17:41
	 * @return: java.util.List<com.yifu.cloud.plus.v1.yifu.salary.entity.TSalaryAccount>
	 **/
	@Override
	public List<TSalaryAccount> getListByIdList(List<String> idList) {
		return baseMapper.getListByIdList(idList);
	}

	@Override
	public List<String> getAccountIdForProve(String startMouth, String endMouth, String emIdCard, String settleDepartId) {
		return baseMapper.getAccountIdForProve(startMouth, endMouth, emIdCard, settleDepartId);
	}
	@Override
	public List<String> getAccountMonthForProve(String startMouth, String endMouth, String emIdCard, String settleDepartId) {
		return baseMapper.getAccountMonthForProve(startMouth, endMouth, emIdCard, settleDepartId);
	}

	@Override
	public TSalaryAccountSumVo getAccountSumBySalaryId(String salaryId) {
		return baseMapper.getAccountSumBySalaryId(salaryId);
	}

	@Override
	public List<TSalaryAccount> allYearExport(TSalaryAccountSearchVo tSalaryAccount) {
		return baseMapper.allYearExport(tSalaryAccount);
	}

	@Override
	public List<TSalaryTypeThreeExportEkpVo> getAccountThreeListByApplyNo(String applyNo) {
		return baseMapper.getAccountThreeListByApplyNo(applyNo);
	}

	@Override
	public List<TSalaryTypeFourExportEkpVo> getAccountFourListByApplyNo(String applyNo) {
		return baseMapper.getAccountFourListByApplyNo(applyNo);
	}

	@Override
	public void exportError(HttpServletResponse response, String errorMessage) {
		String fileName = "导出异常" + DateUtil.getThisTime() + CommonConstants.XLSX;
		//获取要导出的列表
		List<ExportErrorVo> list = new ArrayList<>();
		list.add(new ExportErrorVo(errorMessage));
		long count = 0;
		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, "UTF-8"));
			// 这里 需要指定写用哪个class去写，然后写到第一个sheet，然后文件流会自动关闭
			ExcelWriter excelWriter = EasyExcelFactory.write(out, ExportErrorVo.class).build();
			int index = 0;
			WriteSheet writeSheet = EasyExcelFactory.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<TSalaryAccount> getIdCardListBySalaryId(String salaryId) {
		return baseMapper.getIdCardListBySalaryId(salaryId);
	}

	private String getTableName() {
		LocalDateTime now = LocalDateTime.now();
		int year = now.getYear();
		return SalaryConstants.TABLE_NAME_PRE + year;
	}
	// 获取上月减除费用，按项目
	@Override
	public Map<String, BigDecimal> getCostReductionToAll(String deptNo, String invoiceTitle) {
		Map<String, BigDecimal> map = new HashMap<>();
		LocalDateTime now = LocalDateTime.now();
		int month = now.getMonthValue();
		// 1月自动5000，不查不计算
		if (month != CommonConstants.ONE_INT) {
			String tableName = getTableName();
			String lastSettleMonth = DateUtil.addMonth(-1);
			List<KeyMoneyVo> list = baseMapper.getCostReductionToAll(deptNo, invoiceTitle, tableName, lastSettleMonth);
			if (Common.isNotNull(list)) {
				BigDecimal money;
				for (KeyMoneyVo vo : list) {
					money = vo.getMoneyValue();
					money = judgeMoneyAndAdd(money);
					map.put(vo.getKeyValue(), money);
				}
			}
		}
		return map;
	}

	private BigDecimal judgeMoneyAndAdd(BigDecimal money) {
		if (money != null) {
			money = money.add(SalaryConstants.COST_MONEY).setScale(CommonConstants.ZERO_INT, RoundingMode.HALF_UP);
			// 判断a是否超过60000，超过则返回6000
			if (money.compareTo(SalaryConstants.MAX_COST_MONEY) > CommonConstants.ZERO_INT) {
				money = SalaryConstants.MAX_COST_MONEY;
			}
		}
		return money;
	}

	// 获取上月减除费用，单个身份证的
	@Override
	public BigDecimal getCostReductionToCard(String idCard, String invoiceTitle) {
		String tableName = getTableName();
		String lastSettleMonth = DateUtil.addMonth(-1);
		LocalDateTime now = LocalDateTime.now();
		int month = now.getMonthValue();
		BigDecimal money = SalaryConstants.COST_MONEY;
		// 1月自动5000，不查不计算
		if (month != CommonConstants.ONE_INT) {
			money = baseMapper.getCostReductionToCard(idCard, invoiceTitle, tableName, lastSettleMonth);
			money = judgeMoneyAndAdd(money);
		}
		return money;
	}

}
