package com.kcim.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.Constant;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.constants.ParameterConstant;
import com.kcim.common.constants.SQLParameter;
import com.kcim.common.enums.CustomSqlTypeEnum;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.*;
import com.kcim.dao.model.dto.PatientItemDepartmentGroupVo;
import com.kcim.dao.repository.*;
import com.kcim.service.CenterService;
import com.kcim.service.ProjectCostService;
import com.kcim.service.ResponsibilityDepartmentService;
import com.kcim.service.SqlService;
import com.kcim.vo.*;
import com.kcim.web.reponse.ProjectCostResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import static com.kcim.common.constants.Constant.ITEM_COST_COLUMN_TYPE;
import static com.kcim.common.enums.DefaultComputeColumnEnum.*;
import static com.kcim.service.impl.DrugMaterialCalculateServiceImpl.getVisitNoResponsibilityMaps;

/**
 * @program: CostAccount
 * @description: 项目成本计算实现类
 * @author: Wang.YS
 * @create: 2024-01-15 20:35
 **/
@Service("ProjectCostService")
@Slf4j
@AllArgsConstructor
public class ProjectCostServiceImpl implements ProjectCostService {
    private static final Integer LIMIT = 1000;
    ResponsibilityRepository responsibilityRepository;

    ComputeProjectCostRepository repository;

    ComputeProjectCostDetailRepository detailRepository;

    ComputeProjectGroupCostDetailRepository groupDetailRepository;
    /**
     * 项目导入数据
     */
    ImportPatientItemRepository importPatientItemRepository;

    ShareParamCostRepository shareParamCostRepository;

    ShareParamCostDetailRepository shareParamCostDetailRepository;

    /**
     * 科室损益
     */
    CostDepartmentProfitRepository costDepartmentProfitRepository;

    CostDepartmentProfitAccountRepository costDepartmentProfitAccountRepository;
    /**
     * 项目分摊参数设置
     */
    ShareParamTypeMapRepository shareParamTypeMapRepository;

    ComputeShareParamRepository computeShareParamRepository;

    ComputeProjectCostAccountRepository projectCostAccountRepository;

    ItemRepository itemRepository;

    ResponsibilityDepartmentRepository responsibilityDepartmentRepository;

    CenterService centerService;
    ComputePatientProjectCostRepository computePatientProjectCostRepository;

    ComputePatientProjectCostDetailRepository computePatientProjectCostDetailRepository;
    ComputePatientProjectGroupCostDetailRepository computePatientProjectGroupCostDetailRepository;

    ComputeStandShareParamRepository computeStandShareParamRepository;

    ComputeStandProjectCostRepository standProjectCostRepository;

    ComputeStandProjectCostDetailRepository standProjectCostDetailRepository;

    ComputeStandProjectGroupCostDetailRepository standProjectGroupCostDetailRepository;

    ComputeStandPatientProjectCostRepository computeStandPatientProjectCostRepository;

    ComputeStandPatientProjectCostDetailRepository computeStandPatientProjectCostDetailRepository;

    ComputeStandPatientProjectGroupCostDetailRepository computeStandPatientProjectGroupCostDetailRepository;

    SqlService sqlService;

    ResponsibilityDepartmentService responsibilityDepartmentService;

//    public ProjectCostServiceImpl(ResponsibilityDepartmentService responsibilityDepartmentService,SqlService sqlService,ResponsibilityRepository responsibilityRepository, ComputeProjectCostRepository repository, ComputeProjectCostDetailRepository detailRepository, ComputeProjectGroupCostDetailRepository groupDetailRepository, ImportPatientItemRepository importPatientItemRepository, ShareParamCostRepository shareParamCostRepository, ShareParamCostDetailRepository shareParamCostDetailRepository, CostDepartmentProfitRepository costDepartmentProfitRepository, ShareParamTypeMapRepository shareParamTypeMapRepository, ComputeShareParamRepository computeShareParamRepository, ItemRepository itemRepository, ResponsibilityDepartmentRepository responsibilityDepartmentRepository, CenterService centerService, ComputePatientProjectCostRepository computePatientProjectCostRepository, ComputePatientProjectCostDetailRepository computePatientProjectCostDetailRepository, ComputePatientProjectGroupCostDetailRepository computePatientProjectGroupCostDetailRepository, ComputeStandShareParamRepository computeStandShareParamRepository, ComputeStandProjectCostRepository standProjectCostRepository, ComputeStandProjectCostDetailRepository standProjectCostDetailRepository, ComputeStandProjectGroupCostDetailRepository standProjectGroupCostDetailRepository, ComputeStandPatientProjectCostRepository computeStandPatientProjectCostRepository, ComputeStandPatientProjectCostDetailRepository computeStandPatientProjectCostDetailRepository, ComputeStandPatientProjectGroupCostDetailRepository computeStandPatientProjectGroupCostDetailRepository) {
//        this.responsibilityRepository = responsibilityRepository;
//        this.repository = repository;
//        this.sqlService = sqlService;
//
//        this.detailRepository = detailRepository;
//        this.groupDetailRepository = groupDetailRepository;
//        this.importPatientItemRepository = importPatientItemRepository;
//        this.shareParamCostRepository = shareParamCostRepository;
//        this.shareParamCostDetailRepository = shareParamCostDetailRepository;
//        this.costDepartmentProfitRepository = costDepartmentProfitRepository;
//        this.shareParamTypeMapRepository = shareParamTypeMapRepository;
//        this.computeShareParamRepository = computeShareParamRepository;
//        this.itemRepository = itemRepository;
//        this.responsibilityDepartmentRepository = responsibilityDepartmentRepository;
//        this.centerService = centerService;
//        this.computePatientProjectCostRepository = computePatientProjectCostRepository;
//        this.computePatientProjectCostDetailRepository = computePatientProjectCostDetailRepository;
//        this.computePatientProjectGroupCostDetailRepository = computePatientProjectGroupCostDetailRepository;
//        this.computeStandShareParamRepository = computeStandShareParamRepository;
//        this.standProjectCostRepository = standProjectCostRepository;
//        this.standProjectCostDetailRepository = standProjectCostDetailRepository;
//        this.standProjectGroupCostDetailRepository = standProjectGroupCostDetailRepository;
//        this.computeStandPatientProjectCostRepository = computeStandPatientProjectCostRepository;
//        this.computeStandPatientProjectCostDetailRepository = computeStandPatientProjectCostDetailRepository;
//        this.computeStandPatientProjectGroupCostDetailRepository = computeStandPatientProjectGroupCostDetailRepository;
//        this.responsibilityDepartmentService=responsibilityDepartmentService;
//    }

    /**
     * 项目成本计算分页查询
     *
     * @param current        当前页
     * @param pageSize       页容量
     * @param computeDate    核算年月
     * @param itemType       项目分类
     * @param responsibility 责任中心代码
     * @param itemFilter     过滤条件（项目代码/名称）
     * @return 列表
     */
    @Override
    public Object getItemCostList(Integer current, Integer pageSize, String computeDate, String itemType, String responsibility, String itemFilter) {
        CommonParameterVo parameter = centerService.getParameter(ParameterConstant.ITEM_COST_DISPLAY);
        Page<ComputeProjectCost> projectCostPage = repository.getPage(current, pageSize, computeDate, itemType, responsibility, itemFilter);
        List<ComputeProjectCost> records = projectCostPage.getRecords();
        ProjectCostResponse response = new ProjectCostResponse();
        List<CommonTitleVo> titleVos = new ArrayList<>();
        titleVos.add(new CommonTitleVo(RESPONSIBILITY_CODE.getCode(), RESPONSIBILITY_CODE.getName()));
        titleVos.add(new CommonTitleVo(RESPONSIBILITY_NAME.getCode(), RESPONSIBILITY_NAME.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_CODE.getCode(), MEDICAL_ITEM_CODE.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_NAME.getCode(), MEDICAL_ITEM_NAME.getName()));
        titleVos.add(new CommonTitleVo(ITEM_TYPE.getCode(), ITEM_TYPE.getName()));
        titleVos.add(new CommonTitleVo(ITEM_COST.getCode(), ITEM_COST.getName()));
        handleDictTitle(titleVos);
        response.setTitle(titleVos);
        if (CollectionUtils.isEmpty(records)) {
            response.setPageData(new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current));
            return response;
        }
        List<Integer> collect1 = records.stream().map(ComputeProjectCost::getId).collect(Collectors.toList());
        List<ComputeProjectCostPageDto> projectDetails = detailRepository.getByProjectCostId(computeDate, collect1);
        List<List<ReportVo>> returnList = new ArrayList<>();
//按报表头组装值
        Map<String, List<ComputeProjectCostPageDto>> responsibilityGroup = projectDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getResponsibilityCode));
        Map<String, Map<String, Map<String, BigDecimal>>> computeResultResponsibilityMap = new HashMap<>();
        Map<String, Map<String, Map<String, BigDecimal>>> computeSingleResultResponsibilityMap = new HashMap<>();
        responsibilityGroup.forEach((k, v) -> {
            Map<String, List<ComputeProjectCostPageDto>> itemGroup = v.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getCode));
            Map<String, Map<String, BigDecimal>> computeResultItemMap = new HashMap<>();
            Map<String, Map<String, BigDecimal>> computeSingleResultItemMap = new HashMap<>();
            itemGroup.forEach((k1, v1) -> {
                Map<String, BigDecimal> computeResult = new HashMap<>();
                Map<String, BigDecimal> computeSingleResult = new HashMap<>();
                for (ComputeProjectCostPageDto computeProjectCostPageDto : v1) {
                    computeResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeResult());
                    computeSingleResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeSingleResult());
                }
                computeResultItemMap.put(k1, computeResult);
                computeSingleResultItemMap.put(k1, computeSingleResult);
            });
            computeResultResponsibilityMap.put(k, computeResultItemMap);
            computeSingleResultResponsibilityMap.put(k, computeSingleResultItemMap);
        });


        Map<String, String> typeNameMap = getTypeNameDict();
        records.forEach(record -> record.setItemTypeName(typeNameMap.get(record.getItemType())));
//        for (ComputeProjectCost record : records) {
//            if (record.getItemType().equals(NumberConstant.ONE_S)) {
//                record.setItemTypeName("医师项目");
//            } else {
//                record.setItemTypeName("医技项目");
//            }
//        }
        for (ComputeProjectCost itemCode : records) {
            List<ReportVo> dataList = new ArrayList<>();
            for (CommonTitleVo titleVo : titleVos) {
                if (titleVo.getCode().equals(RESPONSIBILITY_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getResponsibilityCode()));
                } else if (titleVo.getCode().equals(RESPONSIBILITY_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getResponsibilityName()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getCode()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getName()));
                } else if (titleVo.getCode().equals(ITEM_TYPE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getItemTypeName()));
                } else if (titleVo.getCode().equals(ITEM_COST.getCode())) {
                    if (Objects.nonNull(parameter)) {
                        if (parameter.getValue().equals(NumberConstant.ONE_S)) {
                            //单个
                            dataList.add(getData(titleVo.getCode(), computeSingleResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                        } else {
                            //原计算结果
                            dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                        }
                    } else {
                        //原计算结果
                        dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                    }
                } else {
                    if (Objects.nonNull(parameter)) {
                        if (parameter.getValue().equals(NumberConstant.ONE_S)) {
                            //单个
                            dataList.add(getData(titleVo.getCode(), computeSingleResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                        } else {
                            //原计算结果
                            dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                        }
                    } else {
                        //原计算结果
                        dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                    }
                }
            }
            returnList.add(dataList);
        }
        PageUtils pageUtils = new PageUtils(returnList, Math.toIntExact(projectCostPage.getTotal()), pageSize, current);
        response.setPageData(pageUtils);
        return response;
    }
    private @NotNull Map<String, String> getTypeNameDict() {
        DictDataVo centerDict = centerService.getCenterDict(Constant.MED_SERVICE_ITEM_TYPE);
        List<DictDataVo> dataVoList = centerDict.getDataVoList();
        return dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b));
    }

    /**
     * 项目成本分摊计算
     * @param computeDate
     */
    @Override
    public void computeItemCost(String computeDate){
        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.ONE);
        //走系统计算逻辑
        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)){
            //根据参数判断是否走新的计算流程
            if(NumberConstant.ONE_S.equals(centerService.getParameterValue(ParameterConstant.USER_HOSP_ITEM_CALC))){
                //项目成本分摊计算
                calcItemCostAllocation(computeDate);
            }else{
                computeItemCostACtion(computeDate);
            }
        }
        //走自定义SQL计算逻辑
        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
            log.info("项目成本分摊计算完成开始执行后续处理脚本");
            //执行后续处理脚本
            execItemCostSQL(computeDate);
        }
    }

    /**
     * 计算项目成本     *
     *
     * @param computeDate 核算年月
     */
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void computeItemCostACtion(String computeDate) {
        SessionUserVO currentUser = UserContext.getCurrentUser();

        //获取收费项目数据（项目）
        checkImportItem(computeDate, currentUser);
        //判断是否进行过分摊参数计算
        long shareCount = computeShareParamRepository.getComputeShareParamCount(computeDate);
        if (shareCount == 0) {
            throw new CostException("未进行项目分摊参数计算，请先进行项目分摊参数计算，当前计算中止");
        }

        //获取项目成本分摊配置
        Map<String, Map<String, List<ShareParamCostVo>>> shareParamCostGroup = getShareParamProfit(computeDate);
//        Map<String, List<ShareParamCostVo>> shareParamCostGroup = paramCost.stream().collect(Collectors.groupingBy(ShareParamCostVo::getColumnCode));

        //医疗服务项目字典 科室代码-项目代码-项目
        Map<String, Map<String, Item>> itemMap = getItemMap();
        //获到科室与责任中心对照
        getResponsibilityMap result = getGetResponsibilityMap(currentUser);

        //组装分摊参数计算结果  项目分类-责任中心-分摊参数代码-分摊参数结果
        Map<String, Map<String, Map<String, BigDecimal>>> shareSum = new HashMap<>();
        //获取当月分摊参数计算汇总
        List<ComputeShareParamSumVo> computeShareParamSum = computeShareParamRepository.getComputeShareParamSum(computeDate);
        Map<String, List<ComputeShareParamSumVo>> collect1 = computeShareParamSum.stream().collect(Collectors.groupingBy(ComputeShareParamSumVo::getItemType));
        collect1.forEach((k, v) -> {
            Map<String, List<ComputeShareParamSumVo>> collect2 = v.stream().collect(Collectors.groupingBy(ComputeShareParamSumVo::getResponsibilityCode));
            Map<String, Map<String, BigDecimal>> map = new HashMap<>();
            collect2.forEach((k1, v1) -> {
                map.put(k1, v1.stream().collect(Collectors.toMap(ComputeShareParamSumVo::getShareParamCode, ComputeShareParamSumVo::getSum, (a, b) -> b)));
            });
            shareSum.put(k, map);
        });
        //获取分摊参数计算明细 计算占比
        List<ComputeShareParamDetailVo> computeShareParamDetailVos = computeShareParamRepository.getComputeShareParamDetail(computeDate);
        for (ComputeShareParamDetailVo detailVo : computeShareParamDetailVos) {
            Map<String, Map<String, BigDecimal>> ShareItemTypeMap = shareSum.get(detailVo.getItemType());
            Map<String, BigDecimal> stringBigDecimalMap = ShareItemTypeMap.get(detailVo.getResponsibilityCode());
            BigDecimal bigDecimalSum = stringBigDecimalMap.get(detailVo.getShareParamCode());
            detailVo.setSharePercent(getSharePercent(detailVo, bigDecimalSum));
        }
        // 组装分摊参数明细数据 项目类型-责任中心-项目代码-医嘱代码-参数代码-分子
        Map<String, Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>>> sharePercent = new HashMap<>();
        handleSharePercent(computeShareParamDetailVos, sharePercent);

        //汇总所有科室数据
        List<PatientItemDepartmentGroupVo> departAmountGroup = importPatientItemRepository.getDepartAmountGroup(computeDate, currentUser);
        Map<String, String> responsibilityCodeMap = result.responsibilityCodeMap;

        for (PatientItemDepartmentGroupVo departmentGroupVo : departAmountGroup) {
            departmentGroupVo.setResponsibilityCode(responsibilityCodeMap.get(departmentGroupVo.getExecuteDepartmentCode()));
        }
        List<PatientItemDepartmentGroupVo> collect2 = departAmountGroup.stream().filter(f -> StringUtils.isEmpty(f.getResponsibilityCode())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(collect2)){
            log.info("未对照执行科室代码列表："+collect2.stream().map(PatientItemDepartmentGroupVo::getExecuteDepartmentCode).collect(Collectors.toList()).toString());
            throw new CostException("存在执行科室与责任中心未对照数据");
        }
        Map<String, List<PatientItemDepartmentGroupVo>> collect = departAmountGroup.stream().collect(Collectors.groupingBy(PatientItemDepartmentGroupVo::getResponsibilityCode));
        Map<String, BigDecimal> responsibilitySum = new HashMap<>();

        collect.forEach((responsibilityCode, departmentGroupVos) -> {
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            departmentGroupVos.stream().<UnaryOperator<BigDecimal>>map(departmentGroupVo -> v -> v.add(departmentGroupVo.getAmount())).forEach(sum::updateAndGet);
            responsibilitySum.put(responsibilityCode, sum.get());
        });
        //作废上次计算记录
        repository.removeByComputeDate(computeDate, currentUser);
        detailRepository.removeByComputeDate(computeDate, currentUser);
        groupDetailRepository.removeByComputeDate(computeDate, currentUser);
        //主表公共对象
        ComputeProjectCost computeProjectCost = new ComputeProjectCost();
        computeProjectCost.setComputeDate(computeDate);
        computeProjectCost.setHospId(currentUser.getHospId());
        computeProjectCost.setCreateUser(String.valueOf(currentUser.getId()));
        computeProjectCost.setCreateTime(new Date());
        //明细表公共对象
        ComputeProjectCostDetail costDetail = new ComputeProjectCostDetail();
        costDetail.setComputeDate(computeDate);
        costDetail.setHospId(currentUser.getHospId());
        costDetail.setCreateUser(String.valueOf(currentUser.getId()));
        costDetail.setCreateTime(new Date());
        //汇总明细表对象
        ComputeProjectGroupCostDetail groupCostDetail = new ComputeProjectGroupCostDetail();
        groupCostDetail.setComputeDate(computeDate);
        groupCostDetail.setHospId(currentUser.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(currentUser.getId()));
        groupCostDetail.setCreateTime(new Date());
//        long itemSize = importPatientItemRepository.getItemGroupCount(computeDate, currentUser);
        Map<String, Map<String, PatientItemDepartmentGroupVo>> responsibilityItemGroupMap = getPatientItemGroup(computeDate, currentUser, responsibilityCodeMap);

        if(!CollectionUtils.isEmpty(responsibilityItemGroupMap)){
            List<ComputeProjectCost> saveCost = new ArrayList<>();
            List<ComputeProjectCostDetail> saveDetails = new ArrayList<>();
            List<ComputeProjectGroupCostDetail> saveGroupDetails = new ArrayList<>();
            AtomicInteger i = new AtomicInteger(1);
            responsibilityItemGroupMap.forEach((k,v)->{
                v.forEach((itemCode,item)->{
                    ComputeProjectCost itemCost = BeanUtil.convertObj(computeProjectCost, ComputeProjectCost.class);
                    itemCost.setCode(item.getItemCode());
                    itemCost.setName(item.getItemName());
                    Map<String, Item> departmentMap = itemMap.get(item.getExecuteDepartmentCode());
                    if (CollectionUtils.isEmpty(departmentMap)) {
                        return;
                    }
                    Item itemData = departmentMap.get(item.getItemCode());
                    if (Objects.isNull(itemData)) {
                        return;
                    }
                    itemCost.setItemType(itemData.getItemType());
                    itemCost.setResponsibilityCode(k);
                    itemCost.setResponsibilityName(result.responsibilityNameMap.get(item.getExecuteDepartmentCode()));

                    itemCost.setIndex(i.get());
                    saveCost.add(itemCost);
                    costDetail.setIndex(i.get());
                    groupCostDetail.setIndex(i.get());
                    List<ComputeProjectCostDetail> computeProjectCostDetails = setDetails(item, costDetail, itemCost, shareParamCostGroup, sharePercent, shareSum, responsibilitySum);
                    saveDetails.addAll(computeProjectCostDetails);
                    saveGroupDetails.addAll(setGroupDetails(groupCostDetail, computeProjectCostDetails));
                    i.getAndIncrement();
                });
            });

            if (!CollectionUtils.isEmpty(saveCost)) {
                //保存主表数据 并获取主键
                repository.saveBatch(saveCost, 500);
                Map<Integer, Integer> indexId = saveCost.stream().collect(Collectors.toMap(ComputeProjectCost::getIndex, ComputeProjectCost::getId, (a, b) -> b));
                //保存细项项目成本数据 添加主键关联
                if (!CollectionUtils.isEmpty(saveDetails)) {
                    Map<Integer, List<ComputeProjectCostDetail>> collectIndex = saveDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostDetail::getIndex));
                    List<ComputeProjectCostDetail> saveCostDetails = new ArrayList<>();
                    collectIndex.keySet().forEach(integer -> {
                        Integer costId = indexId.get(integer);
                        List<ComputeProjectCostDetail> details = collectIndex.get(integer);
                        details.forEach(detail -> detail.setProjectCostId(costId));
                        saveCostDetails.addAll(details);
                    });

                    detailRepository.saveBatch(saveCostDetails, 500);
                }
                //处理合并项目成本数据 添加主键关联
                if (!CollectionUtils.isEmpty(saveGroupDetails)) {
                    Map<Integer, List<ComputeProjectGroupCostDetail>> collectGroupIndex = saveGroupDetails.stream().collect(Collectors.groupingBy(ComputeProjectGroupCostDetail::getIndex));
                    List<ComputeProjectGroupCostDetail> saveGroupCostDetails = new ArrayList<>();
                    collectGroupIndex.keySet().forEach(integer -> {
                        Integer costId = indexId.get(integer);
                        List<ComputeProjectGroupCostDetail> details = collectGroupIndex.get(integer);
                        details.forEach(detail -> detail.setProjectCostId(costId));
                        saveGroupCostDetails.addAll(details);
                    });
                    saveGroupCostDetails.forEach(f -> f.setId(null));
                    groupDetailRepository.saveBatch(saveGroupCostDetails, 500);
                }


            }
        }
    }

    /**
     * 项目成本分摊计算
     * @param computeDate
     */
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void calcItemCostAllocation(String computeDate) {
        SessionUserVO currentUser = UserContext.getCurrentUser();
        //获取收费项目数据（项目）
        checkImportItem(computeDate, currentUser);
        //判断是否进行过分摊参数计算
        long shareCount = computeShareParamRepository.getComputeShareParamCount(computeDate);
        if (shareCount == 0) {
            throw new CostException("未进行项目分摊参数计算，请先进行项目分摊参数计算，当前计算中止");
        }

        //月度患者收费项目信息
        List<PatientItemDepartmentGroupVo> ptChargeItems = importPatientItemRepository.getByDepartGroupComputeDateItem(computeDate, currentUser);
        if (CollectionUtils.isEmpty(ptChargeItems)){
            throw new CostException("没有可计算的收费项目");
        }

        //项目成本分摊配置
        List<ShareParamCostVo> shareParamCostVos = shareParamCostRepository.getParamCost();
        if (CollectionUtils.isEmpty(shareParamCostVos)){
            throw new CostException("没有项目分摊配置信息无法分摊，请联系管理员");
        }
        //按成本列代码分组
        Map<String, List<ShareParamCostVo>> shareParamCostMap = shareParamCostVos.stream().collect(Collectors.groupingBy(ShareParamCostVo::getColumnCode));

        //获取科室损益报表数据
        List<CostDepartmentProfit> costDepartmentProfits = costDepartmentProfitRepository.getDepartmentProfit(computeDate);
        if (CollectionUtils.isEmpty(costDepartmentProfits)){
            throw new CostException("未进行科室损益计算，请先进行科室损益计算，当前计算中止");
        }
        //按报表类型+报表编码+责任中心分组
        Map<String, List<CostDepartmentProfit>> deptProfitGroup =costDepartmentProfits.stream().collect(Collectors.groupingBy(
                                cost ->String.format("%s-%s-%s",cost.getShareType(),cost.getReportNum(),cost.getResponsibilityCode())));

        //获取科室损益的会计科目金额
        List<CostDepartmentProfitAccount> deptPriftAccountList = costDepartmentProfitAccountRepository.getList(computeDate);
        Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap;
        if(CollectionUtils.isEmpty(deptPriftAccountList)){
            deptPriftAccountMap = new HashMap<>();
        }else{
            deptPriftAccountMap= deptPriftAccountList.stream().collect(Collectors.groupingBy(CostDepartmentProfitAccount::getDeptProfitId));
        }

        //获取责任中心的医疗服务项目字典
        List<Item> itemList = itemRepository.getRespItemList();
        Map<String, Map<String, List<Item>>> respItemGroup = itemList.stream()
                .collect(Collectors.groupingBy(Item::getResponsibilityCode,
                        Collectors.groupingBy(Item::getCode)));

        //项目成本分摊配置主表信息(项目成本列配置)
        List<ShareParamCost> ShareParamCosts = shareParamCostRepository.getList(null);
        Map<String, List<ShareParamCost>> shareParamCostGroup = ShareParamCosts.stream().collect(Collectors.groupingBy(ShareParamCost::getItemType));
        //分摊参数信息
        List<ComputeShareParamDetailVo> computeShareParamDetails = computeShareParamRepository.getComputeShareParamDetail(computeDate);
        Map<String, List<ComputeShareParamDetailVo>> shareParamDetailValueGroup = computeShareParamDetails.stream().collect(Collectors.groupingBy(
                cost -> String.format("%s-%s-%s", cost.getResponsibilityCode(), cost.getItemType(), cost.getCode())));
        //分摊参数按责任中心汇总信息
        List<ComputeShareParamDetailVo> computeShareParamDetailGroup = computeShareParamRepository.getComputeShareParamDetailGroup(computeDate);
        Map<String, List<ComputeShareParamDetailVo>> shareParamDetailGroup = computeShareParamDetailGroup.stream().collect(Collectors.groupingBy(
                cost -> String.format("%s-%s-%s", cost.getItemType(), cost.getShareParamCode(), cost.getResponsibilityCode())));
        //要计算的科室收费项目
        List<ComputeShareParamDetailVo> computeResponsibilityItems = computeShareParamRepository.getComputeResponsibilityItem(computeDate);

        //开始项目成本分摊计算
        List<ComputeProjectCost> computeProjectCosts=new ArrayList<>();
        List<ComputeProjectCostDetail> computeProjectCostDetails=new ArrayList<>();
        List<ComputeProjectGroupCostDetail> computeProjectGroupCostDetails=new ArrayList<>();
        //获取项目收入对应的分摊参数配置
        ShareParamTypeMap incomeShareParam = getIncomeShareParamTypeMap();
        //按项目类别+责任中心代码+项目代码逐个计算项目分摊金额
        computeResponsibilityItems.stream().forEach(responsibilityItem->{
            //创建项目成本主表对象
            ComputeProjectCost projectCost = createComputeProjectCost(computeDate, currentUser, responsibilityItem,respItemGroup);
            computeProjectCosts.add(projectCost);
            String shareParamDetailValueKey = String.format("%s-%s-%s", projectCost.getResponsibilityCode(),projectCost.getItemType(), projectCost.getCode());
            //获取项目对应分摊参数数值
            List<ComputeShareParamDetailVo> itemShareParams =shareParamDetailValueGroup.get(shareParamDetailValueKey);
            if (CollectionUtils.isEmpty(itemShareParams)){
                throw new CostException(String.format("找不到项目的[%s-%s]对应的分摊分摊参数，请重新计算分摊参数",projectCost.getItemType(),projectCost.getName()));
            }
            Map<String, List<ComputeShareParamDetailVo>> respShareParamValueMap = itemShareParams.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getShareParamCode));
            //取项目对应的分摊配置
            List<ShareParamCost> itemShareParamCost =shareParamCostGroup.get(projectCost.getItemType());
            if (CollectionUtils.isEmpty(itemShareParamCost)){
                throw new CostException(String.format("类型[%s]没有对应分摊配置，请联系管理员",projectCost.getItemType()));
            }
            List<ComputeProjectCostDetail> computeProjectCostDetailChilds=new ArrayList<>();
            //按项目分摊配置计算项目的所有项目成本列的分摊金额
            itemShareParamCost.stream().forEach(shareParamCost->{
                ComputeProjectCostDetail cmputeProjectCostDetail=createComputeProjectCostDetail(computeDate, currentUser,incomeShareParam,responsibilityItem,projectCost,
                                                        shareParamCost,shareParamCostMap,respShareParamValueMap,shareParamDetailGroup, deptProfitGroup, deptPriftAccountMap);
                computeProjectCostDetailChilds.add(cmputeProjectCostDetail);
            });
            computeProjectCostDetails.addAll(computeProjectCostDetailChilds);

            //按项目成本列类型分组
            Map<String, List<ComputeProjectCostDetail>> columnTypeGroup = computeProjectCostDetailChilds.stream()
                    .collect(Collectors.groupingBy(ComputeProjectCostDetail::getCostColumnType));
            columnTypeGroup.forEach((columnType, computeResult) -> {
                //创建项目成本汇总表对象
                ComputeProjectGroupCostDetail computeProjectGroupCostDetail = createComputeProjectGroupCostDetail(computeDate, currentUser, responsibilityItem, projectCost, columnType, computeResult);
                computeProjectGroupCostDetails.add(computeProjectGroupCostDetail);
            });
            //创建项目成本列的汇总表对象
            ComputeProjectGroupCostDetail itemCostGroupDetail = createComputeProjectGroupCostDetail(computeDate, currentUser, responsibilityItem, projectCost, ITEM_COST.getCode(), computeProjectCostDetailChilds);
            computeProjectGroupCostDetails.add(itemCostGroupDetail);
        });

        //没有任何可保存的数据
        if (CollectionUtils.isEmpty(computeProjectCosts)) {
            throw new CostException("没有任何可保存的数据");
        }

        //作废上次计算记录
        repository.removeByComputeDate(computeDate, currentUser);
        detailRepository.removeByComputeDate(computeDate, currentUser);
        groupDetailRepository.removeByComputeDate(computeDate, currentUser);
        projectCostAccountRepository.removeByComputeDate(computeDate, currentUser);

        //保存项目分摊主表对象数据
        repository.saveBatch(computeProjectCosts, 500);
        if (!CollectionUtils.isEmpty(computeProjectCostDetails)) {
            //保存项目分摊明细表对象数据
            computeProjectCostDetails.stream().forEach(projectCostDetail->projectCostDetail.setProjectCostId(projectCostDetail.getComputeProjectCost().getId()));
            detailRepository.batchInsert(computeProjectCostDetails);
        }
        if (!CollectionUtils.isEmpty(computeProjectGroupCostDetails)) {
            //保存项目分摊汇总表对象数据
            computeProjectGroupCostDetails.stream().forEach(projectCostDetail->projectCostDetail.setProjectCostId(projectCostDetail.getComputeProjectCost().getId()));
            groupDetailRepository.batchInsert(computeProjectGroupCostDetails);
        }
        //保存项目成本对应的会计科目信息
        saveProjectCostAccountList(computeProjectCosts);

    }

    /**
     * 保存项目成本对应的会计科目信息
     * @param computeProjectCosts
     */
    public void saveProjectCostAccountList(List<ComputeProjectCost> computeProjectCosts){
        List<ComputeProjectCostAccount> projectCostAccountList=new ArrayList<>();
        for (ComputeProjectCost projectCost : computeProjectCosts) {
            List<ComputeProjectCostAccount> itemAccountList =new ArrayList<>();
            itemAccountList.addAll(projectCost.getProjectCostAccountMap().values());
            if (CollectionUtils.isEmpty(itemAccountList)) {
                continue;
            }
            itemAccountList.forEach(itemAccount->{
                itemAccount.setProjectCostId(projectCost.getId());
                //计算单个项目的金额
                if(BigDecimal.ZERO.compareTo(projectCost.getQuantity()) == NumberConstant.ZERO){
                    itemAccount.setComputeSingleResult(BigDecimal.ZERO);
                }else{
                    BigDecimal divide = itemAccount.getComputeResult().divide(projectCost.getQuantity(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                    itemAccount.setComputeSingleResult(divide);
                }
            });
            projectCostAccountList.addAll(itemAccountList);
        }
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            return;
        }

        projectCostAccountRepository.batchInsert(projectCostAccountList);
    }

    /**
     * 获取项目收入对应的分摊参数配置
     * @return
     */
    public ShareParamTypeMap getIncomeShareParamTypeMap(){
        //分摊参数设置信息
        List<ShareParamTypeMap> shareParamTypeMaps = shareParamTypeMapRepository.getList();
        if(CollectionUtils.isEmpty(shareParamTypeMaps)){
            throw new CostException("没有分摊参数配置信息无法进行项目分摊计算");
        }
        Optional<ShareParamTypeMap> firstShareParamTypeMap = shareParamTypeMaps.stream().filter(shareParam -> shareParam.getSourceCode().equals(ITEM_INCOME.getCode())).findFirst();
        if(!firstShareParamTypeMap.isPresent()){
            throw new CostException("没有配置项目收入的分摊参数无法进行项目分摊计算");
        }
        return  firstShareParamTypeMap.get();
    }

    /**
     * 创建项目成本主表对象
     * @param computeDate
     * @param currentUser
     * @param responsibilityItem
     * @return
     */
    public ComputeProjectCost createComputeProjectCost(String computeDate,SessionUserVO currentUser,ComputeShareParamDetailVo responsibilityItem,Map<String, Map<String, List<Item>>> respItemGroup){
        //主表公共对象
        ComputeProjectCost computeProjectCost = new ComputeProjectCost();
        computeProjectCost.setComputeDate(computeDate);
        computeProjectCost.setHospId(currentUser.getHospId());
        computeProjectCost.setCreateUser(String.valueOf(currentUser.getId()));
        computeProjectCost.setCreateTime(new Date());
        computeProjectCost.setCode(responsibilityItem.getCode());
        computeProjectCost.setName(responsibilityItem.getName());
        computeProjectCost.setItemType(responsibilityItem.getItemType());
        computeProjectCost.setQuantity(responsibilityItem.getNum());
        computeProjectCost.setResponsibilityCode(responsibilityItem.getResponsibilityCode());
        computeProjectCost.setResponsibilityName(responsibilityItem.getResponsibilityName());
        Map<String, List<Item>> stringListMap = respItemGroup.get(responsibilityItem.getResponsibilityCode());
        if(stringListMap!=null&&stringListMap.containsKey(responsibilityItem.getCode())){
            computeProjectCost.setStandItemCode(stringListMap.get(responsibilityItem.getCode()).get(NumberConstant.ZERO).getStandItemCode());
        }
        computeProjectCost.setProjectCostAccountMap(new HashMap<>());
        return computeProjectCost;
    }

    /**
     * 创建项目成本明细表对象
     * @param computeDate 核算年月
     * @param currentUser 登录人信息
     * @param responsibilityItem 责任中心的项目汇总数据
     * @param computeProjectCost 主表对象
     * @param shareParamCost 分摊配置主表
     * @param shareParamCostVos 分摊配置明细
     * @param computeShareParamDetails 分摊参数计算明细
     * @param computeShareParamDetailGroup 分摊参数计算明细汇总
     * @param costDepartmentProfits 科室损益数据
     * @return
     */
    public ComputeProjectCostDetail createComputeProjectCostDetail(String computeDate,
                                                                   SessionUserVO currentUser,
                                                                   ShareParamTypeMap incomeShareParam,
                                                                   ComputeShareParamDetailVo responsibilityItem,
                                                                   ComputeProjectCost computeProjectCost,
                                                                   ShareParamCost shareParamCost,
                                                                   Map<String, List<ShareParamCostVo>> shareParamCostVos,
                                                                   Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails ,
                                                                   Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
                                                                   Map<String, List<CostDepartmentProfit>> costDepartmentProfits,
                                                                   Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap){
        //明细表公共对象
        ComputeProjectCostDetail costDetail = new ComputeProjectCostDetail();
        costDetail.setComputeDate(computeDate);
        costDetail.setHospId(currentUser.getHospId());
        costDetail.setCreateUser(String.valueOf(currentUser.getId()));
        costDetail.setCreateTime(new Date());
        costDetail.setComputeProjectCost(computeProjectCost);
        costDetail.setCostColumnCode(shareParamCost.getColumnCode());
        costDetail.setCostColumnType(shareParamCost.getColumnType());
        //获取对应分摊配置明细
        List<ShareParamCostVo> shareParamDetails = shareParamCostVos.get(shareParamCost.getColumnCode());
        if (CollectionUtils.isEmpty(shareParamDetails)){
            throw new CostException(String.format("[%s]没有对应分摊配置，请联系管理员",shareParamCost.getColumnName()));
        }
        String profitKey = String.format("%s-%s-%s",shareParamCost.getReportType(),shareParamCost.getProfitNum(),computeProjectCost.getResponsibilityCode());
        //根据主表配置找到对应的科室损益数据
        List<CostDepartmentProfit> departmentProfitList = costDepartmentProfits.get(profitKey);
        //没有对应的损益项目数据或者损益项目金额为0
        if(CollectionUtils.isEmpty(departmentProfitList)|| departmentProfitList.get(NumberConstant.ZERO).getAmount().equals(BigDecimal.ZERO)){
            costDetail.setComputeResult(BigDecimal.ZERO);
            costDetail.setComputeSingleResult(BigDecimal.ZERO);
            costDetail.setStandComputeResult(BigDecimal.ZERO);
            costDetail.setStandComputeSingleResult(BigDecimal.ZERO);
            return costDetail;
        }
        //按项目分摊配置计算项目的一个项目成本列的分摊金额
        BigDecimal itemAllocationAmount=calcItemAllocationAmount(incomeShareParam,computeProjectCost, departmentProfitList.get(NumberConstant.ZERO),
                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails,deptPriftAccountMap);
        costDetail.setComputeResult(itemAllocationAmount);

        //按项目分摊配置计算项目的一个项目成本列的标准法分摊金额
        BigDecimal itemStandAllocationAmount=calcItemStandAllocationAmount(incomeShareParam,computeProjectCost, departmentProfitList.get(NumberConstant.ZERO),
                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails,deptPriftAccountMap);
        costDetail.setStandComputeResult(itemStandAllocationAmount);

        //项目没有数量时，单个项目的分摊金额为0
        if(responsibilityItem.getNum().compareTo(BigDecimal.ZERO)==NumberConstant.ZERO){
            costDetail.setComputeSingleResult(BigDecimal.ZERO.setScale(NumberConstant.FOUR,RoundingMode.HALF_UP));
            costDetail.setStandComputeSingleResult(BigDecimal.ZERO.setScale(NumberConstant.FOUR,RoundingMode.HALF_UP));
        }else{
            //有数量数，单个项目的分摊金额=总分摊金额/数量
            costDetail.setComputeSingleResult(itemAllocationAmount.divide(responsibilityItem.getNum(),NumberConstant.FOUR,RoundingMode.HALF_UP));
            costDetail.setStandComputeSingleResult(itemStandAllocationAmount.divide(responsibilityItem.getNum(),NumberConstant.FOUR,RoundingMode.HALF_UP));
        }
        return costDetail;
    }

    /**
     * 计算项目的分摊金额
     * @param computeProjectCost 主表对象
     * @param costDepartmentProfit 科室损益数据
     * @param shareParamCostVos 分摊配置明细
     * @param computeShareParamDetailGroup 分摊参数计算明细汇总
     * @param computeShareParamDetails 分摊参数计算明细
     * @return
     */
    public BigDecimal calcItemAllocationAmount(ShareParamTypeMap incomeShareParam,
                                               ComputeProjectCost computeProjectCost,
                                               CostDepartmentProfit costDepartmentProfit,
                                               List<ShareParamCostVo> shareParamCostVos,
                                               Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
                                               Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails,
                                               Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap) {
        BigDecimal itemAllocationAmount=BigDecimal.ZERO;
        //按配置计算每个参数分摊金额
        for (ShareParamCostVo shareParamCostVo : shareParamCostVos) {
            //获取参数对应的责任中心汇总数据
            String shareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),shareParamCostVo.getShareParamCode(),computeProjectCost.getResponsibilityCode());
            List<ComputeShareParamDetailVo> shareParamTotalValueList = computeShareParamDetailGroup.get(shareParamKey);
            //责任中心的汇总数据为0时，按项目收入分摊
            if (CollectionUtils.isEmpty(shareParamTotalValueList)|| shareParamTotalValueList.get(NumberConstant.ZERO).getComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
                //获取项目对应的收入数据
                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(incomeShareParam.getShareParamCode());
                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                    throw new CostException(String.format("[%s-%s]没有收入数据无法分摊，请检查对应的收费项目数据及分摊参数计算结果数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                }
                String incomeShareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),incomeShareParam.getShareParamCode(),computeProjectCost.getResponsibilityCode());
                //有对应的收入数据
                if(computeShareParamDetailGroup.containsKey(incomeShareParamKey)){
                    //找到项目收入的责任中心汇总数据
                    List<ComputeShareParamDetailVo> incomeShareParamGroup = computeShareParamDetailGroup.get(incomeShareParamKey);
                    //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
                    BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getComputeResult())
                            .divide(incomeShareParamGroup.get(NumberConstant.ZERO).getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                    itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
                    //计算项目对应的会计科目金额
                    calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO),incomeShareParamGroup.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE ) ;
                }
            } else {

                //获取项目对应的分摊参数数据
                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(shareParamCostVo.getShareParamCode());
                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                    throw new CostException(String.format("[%s-%s]没有收入数据无法分摊，请检查对应的收费项目数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                }
                //分摊金额=损益项目金额*分摊参数占比*分摊参数数值/责任中心总分摊参数数值
                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getComputeResult())
                        .divide(shareParamTotalValueList.get(NumberConstant.ZERO).getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
                //计算项目对应的会计科目金额
                calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO), shareParamTotalValueList.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE );
            }
        }
        return  itemAllocationAmount;
    }

    /**
     * 计算项目对应的会计科目金额
     * @param computeProjectCost
     * @param costDepartmentProfit
     * @param shareParamCostVo
     * @param shareParamValueVo
     * @param shareParamTotalValueVo
     * @param deptPriftAccountMap
     * @param calcType 1:计算项目金额 2:计算项目标准金额
     */
    public void calcProjectAccountAmount(ComputeProjectCost computeProjectCost,
                                         CostDepartmentProfit costDepartmentProfit,
                                         ShareParamCostVo shareParamCostVo,
                                         ComputeShareParamDetailVo shareParamValueVo,
                                         ComputeShareParamDetailVo shareParamTotalValueVo,
                                         Map<Long,List<CostDepartmentProfitAccount>> deptPriftAccountMap,
                                         Integer calcType){
        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts = deptPriftAccountMap.get(costDepartmentProfit.getId());
        if(CollectionUtils.isEmpty(costDepartmentProfitAccounts)){
            return;
        }
        //排除掉无效数据
        if(StringUtils.isEmpty(computeProjectCost.getStandItemCode())){
            return;
        }
        for (CostDepartmentProfitAccount costDepartmentProfitAccount : costDepartmentProfitAccounts) {
            ComputeProjectCostAccount computeProjectCostAccount = new ComputeProjectCostAccount();
            computeProjectCostAccount.setProjectCostId(computeProjectCost.getId())
                    .setStandItemCode(computeProjectCost.getStandItemCode())
                    .setAccountType(costDepartmentProfitAccount.getAccountType())
                    .setCostType(costDepartmentProfitAccount.getCostType())
                    .setHospId(costDepartmentProfit.getHospId())
                    .setComputeDate(computeProjectCost.getComputeDate())
                    .setCreateUser(computeProjectCost.getCreateUser())
                    .setCreateTime(new Date())
                    .setUpdateUser(computeProjectCost.getUpdateUser())
                    .setUpdateTime(new Date())
                    .setDelFlag(NumberConstant.ZERO);

            BigDecimal paramAllocationAmount = BigDecimal.ZERO;
            if(BigDecimal.ZERO.compareTo(shareParamTotalValueVo.getComputeResult())!=NumberConstant.ZERO){
                paramAllocationAmount = costDepartmentProfitAccount.getAmount().multiply(shareParamCostVo.getPercent()).multiply(shareParamValueVo.getComputeResult())
                        .divide(shareParamTotalValueVo.getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
            }
            computeProjectCostAccount.setComputeResult(paramAllocationAmount);
            String accountKey=String.format("%s-%s",computeProjectCostAccount.getCostType(),computeProjectCostAccount.getAccountType());
            //判断当前科目是否已经存在
            if(computeProjectCost.getProjectCostAccountMap().containsKey(accountKey)){
                ComputeProjectCostAccount itemAccount = computeProjectCost.getProjectCostAccountMap().get(accountKey);
                if(NumberConstant.ONE.equals(calcType)){
                    itemAccount.setComputeResult(itemAccount.getComputeResult().add(computeProjectCostAccount.getComputeResult()));
                }else {
                    itemAccount.setStandComputeResult(itemAccount.getStandComputeResult().add(computeProjectCostAccount.getComputeResult()));
                }
            }else{
                computeProjectCost.getProjectCostAccountMap().put(accountKey,computeProjectCostAccount);
            }
        }

    }


    /**
     * 计算项目标准法的分摊金额
     * @param computeProjectCost 主表对象
     * @param costDepartmentProfit 科室损益数据
     * @param shareParamCostVos 分摊配置明细
     * @param computeShareParamDetailGroup 分摊参数计算明细汇总(按责任中心汇总)
     * @param computeShareParamDetails 分摊参数计算明细
     * @return
     */
    public  BigDecimal calcItemStandAllocationAmount(ShareParamTypeMap incomeShareParam,
                                                     ComputeProjectCost computeProjectCost,
                                                     CostDepartmentProfit costDepartmentProfit,
                                                     List<ShareParamCostVo> shareParamCostVos,
                                                     Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
                                                     Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails,
                                                     Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap){
        BigDecimal itemAllocationAmount=BigDecimal.ZERO;
        //按配置计算每个参数分摊金额
        for (ShareParamCostVo shareParamCostVo : shareParamCostVos) {
            //获取参数对应的责任中心汇总数据
            String shareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),shareParamCostVo.getShareParamCode(),computeProjectCost.getResponsibilityCode());
            List<ComputeShareParamDetailVo> shareParamTotalValueList = computeShareParamDetailGroup.get(shareParamKey);
            //责任中心的汇总数据为0时，按项目收入分摊
            if (CollectionUtils.isEmpty(shareParamTotalValueList)|| shareParamTotalValueList.get(NumberConstant.ZERO).getStandComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
                //获取项目对应的收入数据
                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(incomeShareParam.getShareParamCode());
                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                    throw new CostException(String.format("[%s-%s]没有收入数据无法分摊，请检查对应的收费项目数据及分摊参数计算结果数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                }
                String incomeShareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),incomeShareParam.getShareParamCode(),computeProjectCost.getResponsibilityCode());
                //有对应的收入数据
                if(computeShareParamDetailGroup.containsKey(incomeShareParamKey)){
                    //找到项目收入的责任中心汇总数据
                    List<ComputeShareParamDetailVo> incomeShareParamGroup = computeShareParamDetailGroup.get(incomeShareParamKey);
                    //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
                    BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getStandComputeResult())
                            .divide(incomeShareParamGroup.get(NumberConstant.ZERO).getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                    itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
                    //计算项目对应的会计科目金额
                    calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO),incomeShareParamGroup.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE ) ;
                }
            } else {
                //获取项目对应的分摊参数数据
                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(shareParamCostVo.getShareParamCode());
                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                    throw new CostException(String.format("[%s-%s]没有收入数据无法分摊，请检查对应的收费项目数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                }
                //分摊金额=损益项目金额*分摊参数占比*分摊参数数值/责任中心总分摊参数数值
                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getStandComputeResult())
                        .divide(shareParamTotalValueList.get(NumberConstant.ZERO).getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
                //计算项目对应的会计科目金额
                calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO), shareParamTotalValueList.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE );
            }
        }
        return  itemAllocationAmount;
    }


    /**
     * 创建项目成本汇总表对象
     * @param computeDate
     * @param currentUser
     * @param responsibilityItem
     * @param computeProjectCost
     * @param columnType
     * @param computeProjectCostDetails
     * @return
     */
    public ComputeProjectGroupCostDetail createComputeProjectGroupCostDetail(String computeDate,SessionUserVO currentUser,
                                                                             ComputeShareParamDetailVo responsibilityItem,ComputeProjectCost computeProjectCost,
                                                                             String columnType,List<ComputeProjectCostDetail> computeProjectCostDetails){
        //汇总明细表对象
        ComputeProjectGroupCostDetail groupCostDetail = new ComputeProjectGroupCostDetail();
        groupCostDetail.setComputeDate(computeDate);
        groupCostDetail.setHospId(currentUser.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(currentUser.getId()));
        groupCostDetail.setCreateTime(new Date());
        groupCostDetail.setComputeProjectCost(computeProjectCost);
        groupCostDetail.setType(columnType);
        //计算按列类型汇总的分摊金额
        BigDecimal computeResultGroup = computeProjectCostDetails.stream().collect(Collectors.mapping(ComputeProjectCostDetail::getComputeResult, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)));
        //计算按列类型汇总的标准法分摊金额
        BigDecimal standComputeResultGroup = computeProjectCostDetails.stream().collect(Collectors.mapping(ComputeProjectCostDetail::getStandComputeResult, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)));
        groupCostDetail.setComputeResult(computeResultGroup);
        groupCostDetail.setStandComputeResult(standComputeResultGroup);
        //项目没有数量时，单个项目的分摊金额为0
        if(responsibilityItem.getNum().compareTo(BigDecimal.ZERO)==NumberConstant.ZERO){
            groupCostDetail.setComputeSingleResult(BigDecimal.ZERO);
            groupCostDetail.setStandComputeSingleResult(BigDecimal.ZERO);
        }else{
            //有数量时，单个项目的金额=总金额/数量
            groupCostDetail.setComputeSingleResult(computeResultGroup.divide(responsibilityItem.getNum(),NumberConstant.FOUR,RoundingMode.HALF_UP));
            groupCostDetail.setStandComputeSingleResult(standComputeResultGroup.divide(responsibilityItem.getNum(),NumberConstant.FOUR,RoundingMode.HALF_UP));
        }
        return groupCostDetail;
    }

    /**
     * 执行项目成本计算后续处理SQL
     * @param computeDate
     */
    public void execItemCostSQL(String computeDate){
        Map<String,String> sqlParameter = new HashMap<>();
        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,computeDate);
        sqlService.autoExecuteSql(CustomSqlTypeEnum.FULL_PROJECT_COST_CALC.getCode(),sqlParameter);
    }

    private @NotNull Map<String, Map<String, PatientItemDepartmentGroupVo>> getPatientItemGroup(String computeDate, SessionUserVO currentUser, Map<String, String> responsibilityCodeMap) {
        List<PatientItemDepartmentGroupVo> items = importPatientItemRepository.getByDepartGroupComputeDateItem(computeDate, currentUser);
        //移除执行科室为空的
        List<PatientItemDepartmentGroupVo> removeDepartmentList = new ArrayList<>();
        for (PatientItemDepartmentGroupVo item : items) {
            if(StringUtils.isEmpty(item.getExecuteDepartmentCode())){
                removeDepartmentList.add(item);
            }
        }
        if(!CollectionUtils.isEmpty(removeDepartmentList)){
            List<String> logs = new ArrayList<>();
            for (PatientItemDepartmentGroupVo patientItemDepartmentGroupVo : removeDepartmentList) {
                logs.add(patientItemDepartmentGroupVo.getItemCode());
            }
            List<String> collect2 = logs.stream().distinct().collect(Collectors.toList());
            log.info("以下项目数据【{}】执行科室为空", collect2);
            items.removeAll(removeDepartmentList);
        }

        items.forEach(item -> item.setResponsibilityCode(responsibilityCodeMap.get(item.getExecuteDepartmentCode())));
        //移除责任中心为空的
        List<PatientItemDepartmentGroupVo> removeList = new ArrayList<>();
        for (PatientItemDepartmentGroupVo item : items) {
            if(StringUtils.isEmpty(item.getResponsibilityCode())){
                removeList.add(item);
            }
        }
        if(!CollectionUtils.isEmpty(removeList)){
            List<String> logs = new ArrayList<>();
            for (PatientItemDepartmentGroupVo patientItemDepartmentGroupVo : removeList) {
                logs.add(patientItemDepartmentGroupVo.getExecuteDepartmentCode());
            }
            List<String> collect2 = logs.stream().distinct().collect(Collectors.toList());
            log.info("以下执行科室【{}】科室代码未对照责任中心", collect2);
            items.removeAll(removeList);
        }


        Map<String, List<PatientItemDepartmentGroupVo>> collect2 = items.stream().collect(Collectors.groupingBy(PatientItemDepartmentGroupVo::getResponsibilityCode));
        Map<String,Map<String,PatientItemDepartmentGroupVo>> responsibilityItemGroupMap = new HashMap<>();
        collect2.forEach((k,v)->{
            Map<String, List<PatientItemDepartmentGroupVo>> collect3 = v.stream().collect(Collectors.groupingBy(PatientItemDepartmentGroupVo::getItemCode));
            if(!CollectionUtils.isEmpty(collect3)){
                Map<String,PatientItemDepartmentGroupVo> itemGroupMap = new HashMap<>();
                collect3.forEach((itemCode,itemList)->{
                    PatientItemDepartmentGroupVo vo = new PatientItemDepartmentGroupVo();
                    vo.setItemCode(itemCode);
                    vo.setItemName(itemList.get(0).getItemName());
                    vo.setResponsibilityCode(k);
                    AtomicReference<BigDecimal> sumNum = new AtomicReference<>(new BigDecimal("0.00"));
                    AtomicReference<BigDecimal> sumAmount  = new AtomicReference<>(new BigDecimal("0.0000"));
                    for (PatientItemDepartmentGroupVo vo1 : itemList) {
                        sumNum.updateAndGet(s -> s.add(vo1.getNum()));
                        sumAmount.updateAndGet(s -> s.add(vo1.getAmount()));
                    }
                    vo.setNum(sumNum.get());
                    vo.setAmount(sumAmount.get());
                    vo.setExecuteDepartmentCode(itemList.get(0).getExecuteDepartmentCode());
                    itemGroupMap.put(itemCode,vo);
                });
                responsibilityItemGroupMap.put(k,itemGroupMap);
            }

        });
        return responsibilityItemGroupMap;
    }

    private @NotNull getResponsibilityMap getGetResponsibilityMap(SessionUserVO currentUser) {
        List<VisitNoResponsibilityMap> patientResponsibility = getPatientResponsibility(currentUser);
        Map<String, String> responsibilityCodeMap = new HashMap<>();
        Map<String, String> responsibilityNameMap = new HashMap<>();
        patientResponsibility.forEach(visitNoResponsibilityMap -> {
            responsibilityCodeMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityCode());
            responsibilityNameMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityName());
        });
        return new getResponsibilityMap(responsibilityCodeMap, responsibilityNameMap);
    }
    private static class getResponsibilityMap {
        public final Map<String, String> responsibilityCodeMap;
        public final Map<String, String> responsibilityNameMap;

        public getResponsibilityMap(Map<String, String> responsibilityCodeMap, Map<String, String> responsibilityNameMap) {
            this.responsibilityCodeMap = responsibilityCodeMap;
            this.responsibilityNameMap = responsibilityNameMap;
        }
    }

    private @NotNull Map<String, Map<String, List<ShareParamCostVo>>> getShareParamProfit(String computeDate) {
        List<ShareParamCostVo> paramCost = shareParamCostRepository.getParamCost();
        if (CollectionUtils.isEmpty(paramCost)) {
            throw new CostException("未配置项目成本分摊设置，计算中止");
        }
        List<Long> profitId = paramCost.stream().map(ShareParamCostVo::getProfitId).map(Long::valueOf).collect(Collectors.toList());
        //获取科室损益报表数据
        List<CostDepartmentProfit> costDepartmentProfits = costDepartmentProfitRepository.getByProfitIds(computeDate, profitId);
        if (CollectionUtils.isEmpty(costDepartmentProfits)) {
            throw new CostException("未进行科室损益计算，请先进行科室损益计算，当前计算中止");
        }
        Map<Long, List<CostDepartmentProfit>> collect = costDepartmentProfits.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportId));
        //组装总额到项目分摊设置中
        for (ShareParamCostVo costVo : paramCost) {
            List<CostDepartmentProfit> profitData = collect.get(Long.valueOf(costVo.getProfitId()));
            Map<Long, Map<String, BigDecimal>> profitMap = new HashMap<>();
            if(!CollectionUtils.isEmpty(profitData)){
                profitMap.put(Long.valueOf(costVo.getProfitId()), profitData.stream().collect(Collectors.toMap(CostDepartmentProfit::getResponsibilityCode, CostDepartmentProfit::getAmount, (a, b) -> b)));
                costVo.setProfitData(profitMap);
            }else{
                log.info("分摊参数：{}profitId:{}在损益计算中未找到任何数据", costVo.getShareParamName(), costVo.getProfitId());
            }
        }
        //按项目分类-分摊参数代码-分摊参数汇总
        Map<String, List<ShareParamCostVo>> collect4 = paramCost.stream().collect(Collectors.groupingBy(ShareParamCostVo::getItemType));
        Map<String, Map<String, List<ShareParamCostVo>>> shareParamCostGroup = new HashMap<>();
        collect4.forEach((k, v) -> {
            shareParamCostGroup.put(k, v.stream().collect(Collectors.groupingBy(ShareParamCostVo::getColumnCode)));
        });
        return shareParamCostGroup;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void computePatientItemCost(String computeDate) {

//        Map<String,String> sqlParameter = new HashMap<>();
//        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,computeDate);
//        sqlService.autoExecuteSql(CustomSqlTypeEnum.PT_ITEM_COST_CALC.getCode(),sqlParameter);
//      暂时更换成自定义sql 执行 下面代码留用
        SessionUserVO currentUser = UserContext.getCurrentUser();
        //获取收费项目数据（项目）
        checkImportItem(computeDate, currentUser);
        //重置计算标志
        long itemCount = repository.itemCount(computeDate, currentUser);
        if (Objects.equals(itemCount, NumberConstant.ZERO_L)) {
            log.error("当前核算年月【{}】未进行项目成本计算，当前计算中止", computeDate);
            throw new CostException("当前核算年月【" + computeDate + "】未进行项目成本计算，计算中止");
        }
        //获到科室与责任中心对照
        List<VisitNoResponsibilityMap> patientResponsibility = getPatientResponsibility(currentUser);
        Map<String, String> responsibilityCodeMap = new HashMap<>();
        Map<String, String> responsibilityNameMap = new HashMap<>();
        patientResponsibility.forEach(visitNoResponsibilityMap -> {
            responsibilityCodeMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityCode());
            responsibilityNameMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityName());
        });
        //医疗服务项目字典 科室代码-项目代码-项目
        Map<String, Map<String, Item>> itemMap = getItemMap();
        //获取项目计算结果
        List<ProjectCostVo> projectCost = repository.getProjectCost(computeDate, currentUser);
        Map<String, List<ProjectCostVo>> collect = projectCost.stream().collect(Collectors.groupingBy(ProjectCostVo::getItemType));
        Map<String, Map<String, Map<String, List<ProjectCostVo>>>> projectCostGroup = new HashMap<>();
        collect.forEach((itemType, voList) -> {
            Map<String, List<ProjectCostVo>> collect1 = voList.stream().collect(Collectors.groupingBy(ProjectCostVo::getResponsibilityCode));
            Map<String, Map<String, List<ProjectCostVo>>> responsibilityGroup = new HashMap<>();
            collect1.forEach((responsibilityCode, vos) -> {
                responsibilityGroup.put(responsibilityCode, vos.stream().collect(Collectors.groupingBy(ProjectCostVo::getCode)));
            });
            projectCostGroup.put(itemType, responsibilityGroup);
        });
        //作废上次计算记录
        computePatientProjectCostRepository.removeByComputeDate(computeDate, currentUser);
        computePatientProjectCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        computePatientProjectGroupCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        long itemSize = importPatientItemRepository.getPatientItemGroupCount(computeDate, currentUser);
        long count = (itemSize + LIMIT - 1) / LIMIT;
        //主表公共对象
        ComputePatientProjectCost computeProjectCost = new ComputePatientProjectCost();
        computeProjectCost.setComputeDate(computeDate);
        computeProjectCost.setHospId(currentUser.getHospId());
        computeProjectCost.setCreateUser(String.valueOf(currentUser.getId()));
        computeProjectCost.setCreateTime(new Date());
        //明细表公共对象
        ComputePatientProjectCostDetail costDetail = new ComputePatientProjectCostDetail();
        costDetail.setComputeDate(computeDate);
        costDetail.setHospId(currentUser.getHospId());
        costDetail.setCreateUser(String.valueOf(currentUser.getId()));
        costDetail.setCreateTime(new Date());
        ComputePatientProjectGroupCostDetail groupCostDetail = new ComputePatientProjectGroupCostDetail();
        groupCostDetail.setComputeDate(computeDate);
        groupCostDetail.setHospId(currentUser.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(currentUser.getId()));
        groupCostDetail.setCreateTime(new Date());
        for (int j = 1; j <= count; j++) {
            List<ComputePatientProjectCost> saveCost = new ArrayList<>();
            List<ComputePatientProjectCostDetail> saveDetails = new ArrayList<>();
            List<ComputePatientProjectGroupCostDetail> saveGroupDetails = new ArrayList<>();
            List<PatientItemDepartmentGroupVo> patientItemGroupList = importPatientItemRepository.getPatientItemGroupList(j, LIMIT, computeDate, currentUser);
            if (!CollectionUtils.isEmpty(patientItemGroupList)) {
                for (int i = 0; i < patientItemGroupList.size(); i++) {
                    PatientItemDepartmentGroupVo item = patientItemGroupList.get(i);
                    ComputePatientProjectCost itemCost = BeanUtil.convertObj(computeProjectCost, ComputePatientProjectCost.class);
                    itemCost.setVisitNo(item.getVisitNo());
                    itemCost.setCode(item.getItemCode());
                    itemCost.setName(item.getItemName());
                    itemCost.setPatientNo(item.getPatientNo());
                    itemCost.setPatientName(item.getName());
                    Map<String, Item> departmentMap = itemMap.get(item.getExecuteDepartmentCode());
                    if (CollectionUtils.isEmpty(departmentMap)) {
                        continue;
                    }
                    Item itemData = departmentMap.get(item.getItemCode());
                    if (Objects.isNull(itemData)) {
                        continue;
                    }
                    itemCost.setItemType(itemData.getItemType());
                    itemCost.setResponsibilityCode(responsibilityCodeMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setResponsibilityName(responsibilityNameMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setDepartmentCode(item.getExecuteDepartmentCode());
                    itemCost.setDepartmentName(item.getExecuteDepartmentName());
                    itemCost.setIndex(i);
                    saveCost.add(itemCost);
                    costDetail.setIndex(i);
                    groupCostDetail.setIndex(i);
                    List<ComputePatientProjectCostDetail> computeProjectCostDetails = setPatientDetails(item, costDetail, itemCost, projectCostGroup);
                    saveDetails.addAll(computeProjectCostDetails);
                    saveGroupDetails.addAll(setPatientGroupDetails(item, groupCostDetail, computeProjectCostDetails));
                }
                if (!CollectionUtils.isEmpty(saveCost)) {
                    //保存主表数据 并获取主键
                    computePatientProjectCostRepository.saveBatch(saveCost, 500);
                    Map<Integer, Integer> indexId = saveCost.stream().collect(Collectors.toMap(ComputePatientProjectCost::getIndex, ComputePatientProjectCost::getId, (a, b) -> b));
                    //保存细项项目成本数据 添加主键关联
                    if (!CollectionUtils.isEmpty(saveDetails)) {
                        Map<Integer, List<ComputePatientProjectCostDetail>> collectIndex = saveDetails.stream().collect(Collectors.groupingBy(ComputePatientProjectCostDetail::getIndex));
                        List<ComputePatientProjectCostDetail> saveCostDetails = new ArrayList<>();
                        collectIndex.forEach((k, v) -> {
                            v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                            saveCostDetails.addAll(v);
                        });
                        saveCostDetails.forEach(f -> f.setId(null));
                        computePatientProjectCostDetailRepository.saveBatch(saveCostDetails, 500);
                    }
                    //处理合并项目成本数据 添加主键关联
                    if (!CollectionUtils.isEmpty(saveGroupDetails)) {
                        Map<Integer, List<ComputePatientProjectGroupCostDetail>> collectGroupIndex = saveGroupDetails.stream().collect(Collectors.groupingBy(ComputePatientProjectGroupCostDetail::getIndex));
                        List<ComputePatientProjectGroupCostDetail> saveGroupCostDetails = new ArrayList<>();
                        collectGroupIndex.forEach((k, v) -> {
                            v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                            saveGroupCostDetails.addAll(v);
                        });
                        saveGroupCostDetails.forEach(f -> f.setId(null));
                        computePatientProjectGroupCostDetailRepository.saveBatch(saveGroupCostDetails, 500);
                    }
                }
            }
        }

    }

    @Override
    public Object getPatientItemCostList(Integer current, Integer pageSize, String computeDate, String departmentFilter, String patientFilter) {
        Page<ComputePatientProjectCost> projectCostPage = computePatientProjectCostRepository.getPage(current, pageSize, computeDate, departmentFilter, patientFilter);
        List<ComputePatientProjectCost> records = projectCostPage.getRecords();
        ProjectCostResponse response = new ProjectCostResponse();
        List<CommonTitleVo> titleVos = new ArrayList<>();
        titleVos.add(new CommonTitleVo(VISITOR_CODE.getCode(), VISITOR_CODE.getName()));
        titleVos.add(new CommonTitleVo(PATIENT_CODE.getCode(), PATIENT_CODE.getName()));
        titleVos.add(new CommonTitleVo(PATIENT_NAME.getCode(), PATIENT_NAME.getName()));
        titleVos.add(new CommonTitleVo(DEPARTMENT_CODE.getCode(), DEPARTMENT_CODE.getName()));
        titleVos.add(new CommonTitleVo(DEPARTMENT_NAME.getCode(), DEPARTMENT_NAME.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_CODE.getCode(), MEDICAL_ITEM_CODE.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_NAME.getCode(), MEDICAL_ITEM_NAME.getName()));
        titleVos.add(new CommonTitleVo(ITEM_COST.getCode(), ITEM_COST.getName()));
        titleVos.add(new CommonTitleVo(ITEM_INCOME.getCode(), ITEM_INCOME.getName()));
        handleDictTitle(titleVos);
        response.setTitle(titleVos);
        if (CollectionUtils.isEmpty(records)) {
            response.setPageData(new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current));
            return response;
        }
        List<Integer> collect1 = records.stream().map(ComputePatientProjectCost::getId).collect(Collectors.toList());
        List<ComputeProjectCostPageDto> projectDetails = computePatientProjectCostDetailRepository.getByProjectCostId(computeDate, collect1);
        List<List<ReportVo>> returnList = new ArrayList<>();
        //按报表头组装值
        Map<String, List<ComputeProjectCostPageDto>> departmentGroup = projectDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getDepartmentCode));
        Map<String, Map<String, Map<String, Map<String, BigDecimal>>>> computeResultDepartmentMap = new HashMap<>();
        //按科室分组
        departmentGroup.forEach((k, v) -> {
            Map<String, List<ComputeProjectCostPageDto>> itemGroup = v.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getCode));
            Map<String, Map<String, Map<String, BigDecimal>>> computeResultItemMap = new HashMap<>();
            //按项目分组
            itemGroup.forEach((k1, v1) -> {
                Map<String, List<ComputeProjectCostPageDto>> visitGroup = v1.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getVisitNo));
                Map<String, Map<String, BigDecimal>> computeResultVisitMap = new HashMap<>();
                //按患者分组
                visitGroup.forEach((k2, v2) -> {
                    Map<String, BigDecimal> computeResult = new HashMap<>();
                    //按项目报表列分组
                    for (ComputeProjectCostPageDto computeProjectCostPageDto : v2) {
                        computeResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeResult());
                    }
                    computeResultVisitMap.put(k2, computeResult);
                });
                computeResultItemMap.put(k1, computeResultVisitMap);
            });
            computeResultDepartmentMap.put(k, computeResultItemMap);
        });
        for (ComputePatientProjectCost record : records) {
            if (record.getItemType().equals(NumberConstant.ONE_S)) {
                record.setItemTypeName("医师项目");
            } else {
                record.setItemTypeName("医技项目");
            }
        }
        for (ComputePatientProjectCost itemCode : records) {
            List<ReportVo> dataList = new ArrayList<>();
            for (CommonTitleVo titleVo : titleVos) {
                if (titleVo.getCode().equals(DEPARTMENT_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getDepartmentCode()));
                } else if (titleVo.getCode().equals(DEPARTMENT_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getDepartmentName()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getCode()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getName()));
                } else if (titleVo.getCode().equals(VISITOR_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getVisitNo()));
                } else if (titleVo.getCode().equals(PATIENT_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getPatientNo()));
                } else if (titleVo.getCode().equals(PATIENT_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getPatientName()));
                } else if (titleVo.getCode().equals(ITEM_INCOME.getCode())) {
                    if(computeResultDepartmentMap.isEmpty()){
                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
                    }else{
                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_INCOME.getCode())));
                    }
                } else if (titleVo.getCode().equals(ITEM_COST.getCode())) {
                    if(computeResultDepartmentMap.isEmpty()){
                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
                    }else{
                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_COST.getCode())));
                    }
                } else {
                    if(computeResultDepartmentMap.isEmpty()){
                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
                    }else{
                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(titleVo.getCode())));
                    }
                }
            }
            returnList.add(dataList);
        }
        PageUtils pageUtils = new PageUtils(returnList, Math.toIntExact(projectCostPage.getTotal()), pageSize, current);
        response.setPageData(pageUtils);
        return response;
    }

    /**
     * 标准项目成本计算分页查询
     *
     * @param current        当前页
     * @param pageSize       页容量
     * @param computeDate    核算年月
     * @param itemType       项目分类
     * @param responsibility 责任中心代码
     * @param itemFilter     过滤条件（项目代码/名称）
     * @return 列表
     */
    @Override
    public Object getStandItemCostList(Integer current, Integer pageSize, String computeDate, String itemType, String responsibility, String itemFilter) {
        CommonParameterVo parameter = centerService.getParameter(ParameterConstant.ITEM_COST_DISPLAY);
        Page<ComputeStandProjectCost> projectCostPage = standProjectCostRepository.getPage(current, pageSize, computeDate, itemType, responsibility, itemFilter);
        List<ComputeStandProjectCost> records = projectCostPage.getRecords();
        ProjectCostResponse response = new ProjectCostResponse();
        List<CommonTitleVo> titleVos = new ArrayList<>();
        titleVos.add(new CommonTitleVo(RESPONSIBILITY_CODE.getCode(), RESPONSIBILITY_CODE.getName()));
        titleVos.add(new CommonTitleVo(RESPONSIBILITY_NAME.getCode(), RESPONSIBILITY_NAME.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_CODE.getCode(), MEDICAL_ITEM_CODE.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_NAME.getCode(), MEDICAL_ITEM_NAME.getName()));
        titleVos.add(new CommonTitleVo(ITEM_TYPE.getCode(), ITEM_TYPE.getName()));
        titleVos.add(new CommonTitleVo(ITEM_COST.getCode(), ITEM_COST.getName()));
        handleDictTitle(titleVos);
        response.setTitle(titleVos);
        if (CollectionUtils.isEmpty(records)) {
            response.setPageData(new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current));
            return response;
        }
        List<Integer> collect1 = records.stream().map(ComputeStandProjectCost::getId).collect(Collectors.toList());
        List<ComputeProjectCostPageDto> projectDetails = standProjectCostDetailRepository.getByProjectCostId(computeDate, collect1);
        List<List<ReportVo>> returnList = new ArrayList<>();
        //按报表头组装值
        Map<String, List<ComputeProjectCostPageDto>> responsibilityGroup = projectDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getResponsibilityCode));
        Map<String, Map<String, Map<String, BigDecimal>>> computeResultResponsibilityMap = new HashMap<>();
        Map<String, Map<String, Map<String, BigDecimal>>> computeSingleResultResponsibilityMap = new HashMap<>();
        responsibilityGroup.forEach((k, v) -> {
            Map<String, List<ComputeProjectCostPageDto>> itemGroup = v.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getCode));
            Map<String, Map<String, BigDecimal>> computeResultItemMap = new HashMap<>();
            Map<String, Map<String, BigDecimal>> computeSingleResultItemMap = new HashMap<>();
            itemGroup.forEach((k1, v1) -> {
                Map<String, BigDecimal> computeResult = new HashMap<>();
                Map<String, BigDecimal> computeSingleResult = new HashMap<>();
                for (ComputeProjectCostPageDto computeProjectCostPageDto : v1) {
                    computeResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeResult());
                    computeSingleResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeSingleResult());
                }
                computeResultItemMap.put(k1, computeResult);
                computeSingleResultItemMap.put(k1, computeSingleResult);
            });
            computeResultResponsibilityMap.put(k, computeResultItemMap);
            computeSingleResultResponsibilityMap.put(k, computeSingleResultItemMap);
        });
        for (ComputeStandProjectCost record : records) {
            if (record.getItemType().equals(NumberConstant.ONE_S)) {
                record.setItemTypeName("医师项目");
            } else {
                record.setItemTypeName("医技项目");
            }
        }
        for (ComputeStandProjectCost itemCode : records) {
            List<ReportVo> dataList = new ArrayList<>();
            for (CommonTitleVo titleVo : titleVos) {
                if (titleVo.getCode().equals(RESPONSIBILITY_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getResponsibilityCode()));
                } else if (titleVo.getCode().equals(RESPONSIBILITY_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getResponsibilityName()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getCode()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getName()));
                } else if (titleVo.getCode().equals(ITEM_TYPE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getItemTypeName()));
                } else if (titleVo.getCode().equals(ITEM_COST.getCode())) {
                    if (Objects.nonNull(parameter)) {
                        if (parameter.getValue().equals(NumberConstant.ONE_S)) {
                            //单个
                            dataList.add(getData(titleVo.getCode(), computeSingleResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                        } else {
                            //原计算结果
                            dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                        }
                    } else {
                        //原计算结果
                        dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(ITEM_COST.getCode())));
                    }
                } else {
                    if (Objects.nonNull(parameter)) {
                        if (parameter.getValue().equals(NumberConstant.ONE_S)) {
                            //单个
                            dataList.add(getData(titleVo.getCode(), computeSingleResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                        } else {
                            //原计算结果
                            dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                        }
                    } else {
                        //原计算结果
                        dataList.add(getData(titleVo.getCode(), computeResultResponsibilityMap.get(itemCode.getResponsibilityCode()).get(itemCode.getCode()).get(titleVo.getCode())));
                    }
                }
            }
            returnList.add(dataList);
        }
        PageUtils pageUtils = new PageUtils(returnList, Math.toIntExact(projectCostPage.getTotal()), pageSize, current);
        response.setPageData(pageUtils);
        return response;
    }

    /**
     * 标准项目成本分摊计算
     * @param computeDate
     */
    @Override
    public void computeStandItemCost(String computeDate){
        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.THREE);
        //走系统计算逻辑
        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
            //标准项目成本分摊计算
            computeStandItemCostAction(computeDate);
        }
        //走自定义SQL计算逻辑
        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
            //执行标准法项目成本分摊计算后续处理脚本
            execStandItemCostSQL(computeDate);
        }
    }

    /**
     * 标准项目成本计算
     *
     * @param computeDate 核算年月
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void computeStandItemCostAction(String computeDate) {
        SessionUserVO currentUser = UserContext.getCurrentUser();
        //获取收费项目数据（项目）
        checkImportItem(computeDate, currentUser);
        //判断是否进行过分摊参数计算
        long shareCount = computeStandShareParamRepository.getComputeShareParamCount(computeDate);
        if (shareCount == 0) {
            throw new CostException("未进行标准项目分摊参数计算，请先进行项目分摊参数计算，当前计算中止");
        }
        //获取当月分摊参数计算汇总
        List<ComputeShareParamSumVo> computeShareParamSum = computeStandShareParamRepository.getComputeShareParamSum(computeDate);
        //获取项目成本分摊配置
        Map<String, Map<String, List<ShareParamCostVo>>> shareParamCostGroup = getShareParamProfit(computeDate);
        Map<String, Map<String, Item>> itemMap = getItemMap();
        //获到科室与责任中心对照
        List<VisitNoResponsibilityMap> patientResponsibility = getPatientResponsibility(currentUser);
        Map<String, String> responsibilityCodeMap = new HashMap<>();
        Map<String, String> responsibilityNameMap = new HashMap<>();
        patientResponsibility.forEach(visitNoResponsibilityMap -> {
            responsibilityCodeMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityCode());
            responsibilityNameMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityName());
        });
        //组装分摊参数计算结果  项目分类-责任中心-分摊参数代码-分摊参数结果
        Map<String, Map<String, Map<String, BigDecimal>>> shareSum = new HashMap<>();
        Map<String, List<ComputeShareParamSumVo>> collect1 = computeShareParamSum.stream().collect(Collectors.groupingBy(ComputeShareParamSumVo::getItemType));
        collect1.forEach((k, v) -> {
            Map<String, List<ComputeShareParamSumVo>> collect2 = v.stream().collect(Collectors.groupingBy(ComputeShareParamSumVo::getResponsibilityCode));
            Map<String, Map<String, BigDecimal>> map = new HashMap<>();
            collect2.forEach((k1, v1) -> {
                map.put(k1, v1.stream().collect(Collectors.toMap(ComputeShareParamSumVo::getShareParamCode, ComputeShareParamSumVo::getSum, (a, b) -> b)));
            });
            shareSum.put(k, map);
        });
        List<ComputeShareParamDetailVo> computeShareParamDetailVos = computeStandShareParamRepository.getComputeShareParamDetail(computeDate);
        for (ComputeShareParamDetailVo detailVo : computeShareParamDetailVos) {
            Map<String, Map<String, BigDecimal>> ShareItemTypeMap = shareSum.get(detailVo.getItemType());
            Map<String, BigDecimal> stringBigDecimalMap = ShareItemTypeMap.get(detailVo.getResponsibilityCode());
            BigDecimal bigDecimalSum = stringBigDecimalMap.get(detailVo.getShareParamCode());
            detailVo.setSharePercent(getSharePercent(detailVo, bigDecimalSum));
        }
        // 组装分摊参数明细数据 项目类型-责任中心-项目代码-医嘱代码-参数代码-分子
        Map<String, Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>>> sharePercent = new HashMap<>();
        handleSharePercent(computeShareParamDetailVos, sharePercent);
        //汇总所有科室数据
        List<PatientItemDepartmentGroupVo> departAmountGroup = importPatientItemRepository.getDepartAmountGroup(computeDate, currentUser);

        for (PatientItemDepartmentGroupVo departmentGroupVo : departAmountGroup) {
            departmentGroupVo.setResponsibilityCode(responsibilityCodeMap.get(departmentGroupVo.getExecuteDepartmentCode()));
        }
        Map<String, List<PatientItemDepartmentGroupVo>> collect = departAmountGroup.stream().collect(Collectors.groupingBy(PatientItemDepartmentGroupVo::getResponsibilityCode));
        Map<String, BigDecimal> responsibilitySum = new HashMap<>();

        collect.forEach((responsibilityCode, departmentGroupVos) -> {
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            departmentGroupVos.stream().<UnaryOperator<BigDecimal>>map(departmentGroupVo -> v -> v.add(departmentGroupVo.getAmount())).forEach(sum::updateAndGet);
            responsibilitySum.put(responsibilityCode, sum.get());
        });

        //作废上次计算记录
        standProjectCostRepository.removeByComputeDate(computeDate, currentUser);
        standProjectCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        standProjectGroupCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        //主表公共对象
        ComputeProjectCost computeProjectCost = new ComputeProjectCost();
        computeProjectCost.setComputeDate(computeDate);
        computeProjectCost.setHospId(currentUser.getHospId());
        computeProjectCost.setCreateUser(String.valueOf(currentUser.getId()));
        computeProjectCost.setCreateTime(new Date());
        //明细表公共对象
        ComputeProjectCostDetail costDetail = new ComputeProjectCostDetail();
        costDetail.setComputeDate(computeDate);
        costDetail.setHospId(currentUser.getHospId());
        costDetail.setCreateUser(String.valueOf(currentUser.getId()));
        costDetail.setCreateTime(new Date());
        //汇总明细表对象
        ComputeProjectGroupCostDetail groupCostDetail = new ComputeProjectGroupCostDetail();
        groupCostDetail.setComputeDate(computeDate);
        groupCostDetail.setHospId(currentUser.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(currentUser.getId()));
        groupCostDetail.setCreateTime(new Date());
        long itemSize = importPatientItemRepository.getItemGroupCount(computeDate, currentUser);
        long count = (itemSize + LIMIT - 1) / LIMIT;
//        long count = (itemSize + LIMIT - 1) / LIMIT;
        Map<String, Map<String, PatientItemDepartmentGroupVo>> responsibilityItemGroupMap = getPatientItemGroup(computeDate, currentUser, responsibilityCodeMap);


        if(!CollectionUtils.isEmpty(responsibilityItemGroupMap)){
            List<ComputeStandProjectCost> saveCost = new ArrayList<>();
            List<ComputeStandProjectCostDetail> saveDetails = new ArrayList<>();
            List<ComputeStandProjectGroupCostDetail> saveGroupDetails = new ArrayList<>();
            AtomicInteger i = new AtomicInteger(1);
            responsibilityItemGroupMap.forEach((k,v)->{
                v.forEach((itemCode,item)->{
                    ComputeProjectCost itemCost = BeanUtil.convertObj(computeProjectCost, ComputeProjectCost.class);
                    itemCost.setCode(item.getItemCode());
                    itemCost.setName(item.getItemName());
                    Map<String, Item> departmentMap = itemMap.get(item.getExecuteDepartmentCode());
                    if (CollectionUtils.isEmpty(departmentMap)) {
                        return;
                    }
                    Item itemData = departmentMap.get(item.getItemCode());
                    if (Objects.isNull(itemData)) {
                        return;

                    }
                    itemCost.setItemType(itemData.getItemType());
                    itemCost.setResponsibilityCode(responsibilityCodeMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setResponsibilityName(responsibilityNameMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setIndex(i.get());
                    ComputeStandProjectCost computeStandProjectCost = BeanUtil.convertObj(itemCost, ComputeStandProjectCost.class);
                    saveCost.add(computeStandProjectCost);
                    costDetail.setIndex(i.get());
                    groupCostDetail.setIndex(i.get());

                    List<ComputeProjectCostDetail> computeProjectCostDetails = setDetails(item, costDetail, itemCost, shareParamCostGroup, sharePercent, shareSum, responsibilitySum);
                    List<ComputeStandProjectCostDetail> computeStandProjectCostDetails = BeanUtil.convertList(computeProjectCostDetails, ComputeStandProjectCostDetail.class);
                    saveDetails.addAll(computeStandProjectCostDetails);
                    List<ComputeProjectGroupCostDetail> computeProjectGroupCostDetails = setGroupDetails(groupCostDetail, computeProjectCostDetails);
                    List<ComputeStandProjectGroupCostDetail> computeStandProjectGroupCostDetails = BeanUtil.convertList(computeProjectGroupCostDetails, ComputeStandProjectGroupCostDetail.class);

                    saveGroupDetails.addAll(computeStandProjectGroupCostDetails);
                    i.getAndIncrement();
                });
            });

            if (!CollectionUtils.isEmpty(saveCost)) {
                //保存主表数据 并获取主键
                standProjectCostRepository.saveBatch(saveCost, 500);
                Map<Integer, Integer> indexId = saveCost.stream().collect(Collectors.toMap(ComputeStandProjectCost::getIndex, ComputeStandProjectCost::getId, (a, b) -> b));
                //保存细项项目成本数据 添加主键关联
                if (!CollectionUtils.isEmpty(saveDetails)) {
                    Map<Integer, List<ComputeStandProjectCostDetail>> collectIndex = saveDetails.stream().collect(Collectors.groupingBy(ComputeStandProjectCostDetail::getIndex));
                    List<ComputeStandProjectCostDetail> saveCostDetails = new ArrayList<>();
                    collectIndex.forEach((k, v) -> {
                        v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                        saveCostDetails.addAll(v);
                    });
                    standProjectCostDetailRepository.saveBatch(saveCostDetails, 500);
                }
                //处理合并项目成本数据 添加主键关联
                if (!CollectionUtils.isEmpty(saveGroupDetails)) {
                    Map<Integer, List<ComputeStandProjectGroupCostDetail>> collectGroupIndex = saveGroupDetails.stream().collect(Collectors.groupingBy(ComputeStandProjectGroupCostDetail::getIndex));
                    List<ComputeStandProjectGroupCostDetail> saveGroupCostDetails = new ArrayList<>();
                    collectGroupIndex.forEach((k, v) -> {
                        v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                        saveGroupCostDetails.addAll(v);
                    });
                    saveGroupCostDetails.forEach(f -> f.setId(null));
                    standProjectGroupCostDetailRepository.saveBatch(saveGroupCostDetails, 500);
                }
            }
        }
    }

    /**
     * 执行标准法项目成本分摊计算后续处理脚本
     * @param computeDate
     */
    public  void execStandItemCostSQL(String computeDate){
        Map<String,String> sqlParameter = new HashMap<>();
        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,computeDate);
        sqlService.autoExecuteSql(CustomSqlTypeEnum.STAND_PROJECT_COST_CALC.getCode(),sqlParameter);
    }

    private static @NotNull BigDecimal getSharePercent(ComputeShareParamDetailVo detailVo, BigDecimal bigDecimalSum) {
        BigDecimal computeResult = detailVo.getComputeResult();
        BigDecimal sharePercent;
        if (bigDecimalSum != null) {
            if (bigDecimalSum.equals(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP))) {
                sharePercent = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP);
            } else {
                sharePercent = computeResult.divide(bigDecimalSum, 8, RoundingMode.HALF_UP);
            }
        } else {
            sharePercent = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP);
        }
        return sharePercent;
    }

    /**
     * 获到患者标准项目列表
     *
     * @param current          当前页
     * @param pageSize         页容量
     * @param computeDate      核算年月
     * @param departmentFilter 科室过滤条件
     * @param patientFilter    患者过滤条件
     * @return 患者标准项目列表
     */
    @Override
    public Object getPatientStandItemCostList(Integer current, Integer pageSize, String computeDate, String departmentFilter, String patientFilter) {
        Page<ComputeStandPatientProjectCost> projectCostPage = computeStandPatientProjectCostRepository.getPage(current, pageSize, computeDate, departmentFilter, patientFilter);
        List<ComputeStandPatientProjectCost> records = projectCostPage.getRecords();

        ProjectCostResponse response = new ProjectCostResponse();
        List<CommonTitleVo> titleVos = new ArrayList<>();
        titleVos.add(new CommonTitleVo(VISITOR_CODE.getCode(), VISITOR_CODE.getName()));
        titleVos.add(new CommonTitleVo(PATIENT_CODE.getCode(), PATIENT_CODE.getName()));
        titleVos.add(new CommonTitleVo(PATIENT_NAME.getCode(), PATIENT_NAME.getName()));
        titleVos.add(new CommonTitleVo(DEPARTMENT_CODE.getCode(), DEPARTMENT_CODE.getName()));
        titleVos.add(new CommonTitleVo(DEPARTMENT_NAME.getCode(), DEPARTMENT_NAME.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_CODE.getCode(), MEDICAL_ITEM_CODE.getName()));
        titleVos.add(new CommonTitleVo(MEDICAL_ITEM_NAME.getCode(), MEDICAL_ITEM_NAME.getName()));
        titleVos.add(new CommonTitleVo(ITEM_COST.getCode(), ITEM_COST.getName()));
        titleVos.add(new CommonTitleVo(ITEM_INCOME.getCode(), ITEM_INCOME.getName()));


        handleDictTitle(titleVos);
        response.setTitle(titleVos);
        if (CollectionUtils.isEmpty(records)) {
            response.setPageData(new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current));
            return response;
        }

        List<Integer> collect1 = records.stream().map(ComputeStandPatientProjectCost::getId).collect(Collectors.toList());
        List<ComputeProjectCostPageDto> projectDetails = computeStandPatientProjectCostRepository.getByProjectCostId(computeDate, collect1);

        List<List<ReportVo>> returnList = new ArrayList<>();
//按报表头组装值
        Map<String, List<ComputeProjectCostPageDto>> departmentGroup = projectDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getDepartmentCode));
        Map<String, Map<String, Map<String, Map<String, BigDecimal>>>> computeResultDepartmentMap = new HashMap<>();
        //按科室分组
        departmentGroup.forEach((k, v) -> {
            Map<String, List<ComputeProjectCostPageDto>> itemGroup = v.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getCode));
            Map<String, Map<String, Map<String, BigDecimal>>> computeResultItemMap = new HashMap<>();
            //按项目分组
            itemGroup.forEach((k1, v1) -> {
                Map<String, List<ComputeProjectCostPageDto>> visitGroup = v1.stream().collect(Collectors.groupingBy(ComputeProjectCostPageDto::getVisitNo));
                Map<String, Map<String, BigDecimal>> computeResultVisitMap = new HashMap<>();
                //按患者分组
                visitGroup.forEach((k2, v2) -> {
                    Map<String, BigDecimal> computeResult = new HashMap<>();
                    //按项目报表列分组
                    for (ComputeProjectCostPageDto computeProjectCostPageDto : v2) {
                        computeResult.put(computeProjectCostPageDto.getType(), computeProjectCostPageDto.getComputeResult());
                    }
                    computeResultVisitMap.put(k2, computeResult);
                });
                computeResultItemMap.put(k1, computeResultVisitMap);
            });
            computeResultDepartmentMap.put(k, computeResultItemMap);
        });
        for (ComputeStandPatientProjectCost record : records) {
            if (record.getItemType().equals(NumberConstant.ONE_S)) {
                record.setItemTypeName("医师项目");
            } else {
                record.setItemTypeName("医技项目");
            }
        }
        for (ComputeStandPatientProjectCost itemCode : records) {
            List<ReportVo> dataList = new ArrayList<>();
            for (CommonTitleVo titleVo : titleVos) {
                if (titleVo.getCode().equals(DEPARTMENT_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getDepartmentCode()));
                } else if (titleVo.getCode().equals(DEPARTMENT_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getDepartmentName()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getCode()));
                } else if (titleVo.getCode().equals(MEDICAL_ITEM_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getName()));
                } else if (titleVo.getCode().equals(VISITOR_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getVisitNo()));
                } else if (titleVo.getCode().equals(PATIENT_CODE.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getPatientNo()));
                } else if (titleVo.getCode().equals(PATIENT_NAME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), itemCode.getPatientName()));
                } else if (titleVo.getCode().equals(ITEM_INCOME.getCode())) {
                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_INCOME.getCode())));
                } else if (titleVo.getCode().equals(ITEM_COST.getCode())) {
                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_COST.getCode())));

                } else {
                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(titleVo.getCode())));
                }
            }
            returnList.add(dataList);
        }
        PageUtils pageUtils = new PageUtils(returnList, Math.toIntExact(projectCostPage.getTotal()), pageSize, current);
        response.setPageData(pageUtils);
        return response;
    }

    /**
     * 计算患者标准项目成本计算
     *
     * @param computeDate 核算年月
     */
    @Override
    public void computeStandPatientItemCost(String computeDate) {

        Map<String,String> sqlParameter = new HashMap<>();
        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,computeDate);
        sqlService.autoExecuteSql(CustomSqlTypeEnum.PT_STAND_ITEM_COST_CALC.getCode(),sqlParameter);

/*     暂时更换成自定义sql 执行 下面代码留用
        SessionUserVO currentUser = UserContext.getCurrentUser();
        //获取收费项目数据（项目）
        checkImportItem(computeDate, currentUser);
        //重置计算标志
        long itemCount = standProjectCostRepository.itemCount(computeDate, currentUser);
        if (Objects.equals(itemCount, NumberConstant.ZERO_L)) {
            log.error("当前核算年月【{}】未进行标准项目成本计算，当前计算中止", computeDate);
            throw new CostException("当前核算年月【" + computeDate + "】未进行标准项目成本计算，计算中止");
        }
        //获到科室与责任中心对照
        List<VisitNoResponsibilityMap> patientResponsibility = getPatientResponsibility(currentUser);
        Map<String, String> responsibilityCodeMap = new HashMap<>();
        Map<String, String> responsibilityNameMap = new HashMap<>();
        patientResponsibility.forEach(visitNoResponsibilityMap -> {
            responsibilityCodeMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityCode());
            responsibilityNameMap.put(visitNoResponsibilityMap.getDepartmentCode(), visitNoResponsibilityMap.getResponsibilityName());
        });
        //医疗服务项目字典 科室代码-项目代码-项目
        Map<String, Map<String, Item>> itemMap = getItemMap();
        //获取项目计算结果
        List<ProjectCostVo> projectCost = standProjectCostRepository.getProjectCost(computeDate, currentUser);
        Map<String, List<ProjectCostVo>> collect = projectCost.stream().collect(Collectors.groupingBy(ProjectCostVo::getItemType));
        Map<String, Map<String, Map<String, List<ProjectCostVo>>>> projectCostGroup = new HashMap<>();
        collect.forEach((itemType, voList) -> {
            Map<String, List<ProjectCostVo>> collect1 = voList.stream().collect(Collectors.groupingBy(ProjectCostVo::getResponsibilityCode));
            Map<String, Map<String, List<ProjectCostVo>>> responsibilityGroup = new HashMap<>();
            collect1.forEach((responsibilityCode, vos) -> {
                responsibilityGroup.put(responsibilityCode, vos.stream().collect(Collectors.groupingBy(ProjectCostVo::getCode)));
            });
            projectCostGroup.put(itemType, responsibilityGroup);
        });
        //作废上次计算记录
        computeStandPatientProjectCostRepository.removeByComputeDate(computeDate, currentUser);
        computeStandPatientProjectCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        computeStandPatientProjectGroupCostDetailRepository.removeByComputeDate(computeDate, currentUser);
        long itemSize = importPatientItemRepository.getPatientItemGroupCount(computeDate, currentUser);
        long count = (itemSize + LIMIT - 1) / LIMIT;
        //主表公共对象
        ComputePatientProjectCost computeProjectCost = new ComputePatientProjectCost();
        computeProjectCost.setComputeDate(computeDate);
        computeProjectCost.setHospId(currentUser.getHospId());
        computeProjectCost.setCreateUser(String.valueOf(currentUser.getId()));
        computeProjectCost.setCreateTime(new Date());
        //明细表公共对象
        ComputePatientProjectCostDetail costDetail = new ComputePatientProjectCostDetail();
        costDetail.setComputeDate(computeDate);
        costDetail.setHospId(currentUser.getHospId());
        costDetail.setCreateUser(String.valueOf(currentUser.getId()));
        costDetail.setCreateTime(new Date());
        ComputePatientProjectGroupCostDetail groupCostDetail = new ComputePatientProjectGroupCostDetail();
        groupCostDetail.setComputeDate(computeDate);
        groupCostDetail.setHospId(currentUser.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(currentUser.getId()));
        groupCostDetail.setCreateTime(new Date());
        for (int j = 1; j <= count; j++) {
            List<ComputeStandPatientProjectCost> saveCost = new ArrayList<>();
            List<ComputeStandPatientProjectCostDetail> saveDetails = new ArrayList<>();
            List<ComputeStandPatientProjectGroupCostDetail> saveGroupDetails = new ArrayList<>();
            List<PatientItemDepartmentGroupVo> patientItemGroupList = importPatientItemRepository.getPatientItemGroupList(j, LIMIT, computeDate, currentUser);
            if (!CollectionUtils.isEmpty(patientItemGroupList)) {
                for (int i = 0; i < patientItemGroupList.size(); i++) {
                    PatientItemDepartmentGroupVo item = patientItemGroupList.get(i);
                    ComputePatientProjectCost itemCost = BeanUtil.convertObj(computeProjectCost, ComputePatientProjectCost.class);
                    itemCost.setVisitNo(item.getVisitNo());
                    itemCost.setCode(item.getItemCode());
                    itemCost.setName(item.getItemName());
                    itemCost.setPatientNo(item.getPatientNo());
                    itemCost.setPatientName(item.getName());
                    Map<String, Item> departmentMap = itemMap.get(item.getExecuteDepartmentCode());

                    if (CollectionUtils.isEmpty(departmentMap)) {
                        continue;
                    }
                    Item itemData = departmentMap.get(item.getItemCode());
                    if (Objects.isNull(itemData)) {
                        continue;
                    }
                    itemCost.setItemType(itemData.getItemType());
                    itemCost.setResponsibilityCode(responsibilityCodeMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setResponsibilityName(responsibilityNameMap.get(item.getExecuteDepartmentCode()));
                    itemCost.setDepartmentCode(item.getExecuteDepartmentCode());
                    itemCost.setDepartmentName(item.getExecuteDepartmentName());
                    itemCost.setIndex(i);
                    ComputeStandPatientProjectCost computeStandPatientProjectCost = BeanUtil.convertObj(itemCost, ComputeStandPatientProjectCost.class);
                    saveCost.add(computeStandPatientProjectCost);
                    costDetail.setIndex(i);
                    groupCostDetail.setIndex(i);
                    List<ComputePatientProjectCostDetail> computeProjectCostDetails = setPatientDetails(item, costDetail, itemCost, projectCostGroup);
                    List<ComputeStandPatientProjectCostDetail> computeStandPatientProjectCostDetails = BeanUtil.convertList(computeProjectCostDetails, ComputeStandPatientProjectCostDetail.class);
                    saveDetails.addAll(computeStandPatientProjectCostDetails);
                    List<ComputePatientProjectGroupCostDetail> computePatientProjectGroupCostDetails = setPatientGroupDetails(item, groupCostDetail, computeProjectCostDetails);
                    List<ComputeStandPatientProjectGroupCostDetail> computeStandPatientProjectGroupCostDetails = BeanUtil.convertList(computePatientProjectGroupCostDetails, ComputeStandPatientProjectGroupCostDetail.class);
                    saveGroupDetails.addAll(computeStandPatientProjectGroupCostDetails);
                }
                computeStandPatientProjectCostRepository.removeByComputeDate(computeDate, currentUser);
                computeStandPatientProjectCostDetailRepository.removeByComputeDate(computeDate, currentUser);
                computeStandPatientProjectGroupCostDetailRepository.removeByComputeDate(computeDate, currentUser);
                if (!CollectionUtils.isEmpty(saveCost)) {
                    //保存主表数据 并获取主键
                    computeStandPatientProjectCostRepository.saveBatch(saveCost, 500);
                    Map<Integer, Integer> indexId = saveCost.stream().collect(Collectors.toMap(ComputeStandPatientProjectCost::getIndex, ComputeStandPatientProjectCost::getId, (a, b) -> b));
                    //保存细项项目成本数据 添加主键关联
                    if (!CollectionUtils.isEmpty(saveDetails)) {
                        Map<Integer, List<ComputeStandPatientProjectCostDetail>> collectIndex = saveDetails.stream().collect(Collectors.groupingBy(ComputeStandPatientProjectCostDetail::getIndex));
                        List<ComputeStandPatientProjectCostDetail> saveCostDetails = new ArrayList<>();
                        collectIndex.forEach((k, v) -> {
                            v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                            saveCostDetails.addAll(v);
                        });
                        saveCostDetails.forEach(f -> f.setId(null));
                        computeStandPatientProjectCostDetailRepository.saveBatch(saveCostDetails, 500);
                    }
                    //处理合并项目成本数据 添加主键关联
                    if (!CollectionUtils.isEmpty(saveGroupDetails)) {
                        Map<Integer, List<ComputeStandPatientProjectGroupCostDetail>> collectGroupIndex = saveGroupDetails.stream().collect(Collectors.groupingBy(ComputeStandPatientProjectGroupCostDetail::getIndex));
                        List<ComputeStandPatientProjectGroupCostDetail> saveGroupCostDetails = new ArrayList<>();
                        collectGroupIndex.forEach((k, v) -> {
                            v.forEach(detail -> detail.setProjectCostId(indexId.get(k)));
                            saveGroupCostDetails.addAll(v);
                        });
                        saveGroupCostDetails.forEach(f -> f.setId(null));
                        computeStandPatientProjectGroupCostDetailRepository.saveBatch(saveGroupCostDetails, 500);
                    }
                }
            }
        }
*/
    }

    private void handleDictTitle(List<CommonTitleVo> titleVos) {
        DictDataVo dict = centerService.getDict(ITEM_COST_COLUMN_TYPE);
        if (Objects.isNull(dict)) {
            throw new CostException("未找到项目成本列类型字典");

        }
        List<DictDataVo> dataVoList = dict.getDataVoList();
        if (CollectionUtils.isEmpty(dataVoList)) {
            throw new CostException("未找到项目成本列类型字典");
        }
        dataVoList.stream().map(dataVo -> new CommonTitleVo(dataVo.getCode(), dataVo.getName())).forEach(titleVos::add);
    }

    /**
     * 组装患者成本计算明细
     *
     * @param item             患者项目
     * @param costDetail       明细对象
     * @param itemCost         患者项目主表对象
     * @param projectCostGroup 项目成本结果
     * @return 患者成本计算明细
     */
    private List<ComputePatientProjectCostDetail> setPatientDetails(PatientItemDepartmentGroupVo item, ComputePatientProjectCostDetail costDetail, ComputePatientProjectCost itemCost,
                                                                    Map<String, Map<String, Map<String, List<ProjectCostVo>>>> projectCostGroup) {


        List<ComputePatientProjectCostDetail> saveList = new ArrayList<>();
        Map<String, Map<String, List<ProjectCostVo>>> itemTypeGroup = projectCostGroup.get(itemCost.getItemType());
        if (!CollectionUtils.isEmpty(itemTypeGroup)) {
            Map<String, List<ProjectCostVo>> responsibilityGroup = itemTypeGroup.get(itemCost.getResponsibilityCode());
            if (!CollectionUtils.isEmpty(responsibilityGroup)) {
                List<ProjectCostVo> projectCostVos = responsibilityGroup.get(itemCost.getCode());
                if (!CollectionUtils.isEmpty(projectCostVos)) {
                    for (ProjectCostVo projectCostVo : projectCostVos) {
                        ComputePatientProjectCostDetail computeProjectCostDetail = BeanUtil.convertObj(costDetail, ComputePatientProjectCostDetail.class);
                        computeProjectCostDetail.setCostColumnCode(projectCostVo.getCostColumnCode());
                        computeProjectCostDetail.setCostColumnType(projectCostVo.getCostColumnType());
                        BigDecimal computeSingleResult = projectCostVo.getComputeSingleResult();
                        BigDecimal num = item.getNum();
                        computeProjectCostDetail.setComputeResult(Objects.nonNull(computeSingleResult) && Objects.nonNull(num) ? computeSingleResult.multiply(num) : BigDecimal.ZERO);
                        saveList.add(computeProjectCostDetail);
                    }
                }
            }
        }
        return saveList;
    }

    /**
     * 拼接报表显示值
     *
     * @param code 代码
     * @param name 名称
     * @return 报表项目
     */
    private ReportVo getData(String code, Object name) {
        ReportVo vo = new ReportVo();
        vo.setCode(code);
        vo.setValue(name);
        return vo;
    }

    /**
     * 校验月度患者项目导入数据
     *
     * @param computeDate 核算年月
     * @param currentUser 当前登录用户
     */
    private void checkImportItem(String computeDate, SessionUserVO currentUser) {
        long itemSize = importPatientItemRepository.getItemCount(computeDate, currentUser);
        if (Objects.equals(itemSize, NumberConstant.ZERO_L)) {
            log.error("当前核算年月【{}】未导入收费项目数据，计算中止", computeDate);
            throw new CostException("当前核算年月【" + computeDate + "】未导入收费项目数据，计算中止");
        }
    }

    private static void handleSharePercent(List<ComputeShareParamDetailVo> computeShareParamDetailVos,
                                           Map<String, Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>>> sharePercent) {
        Map<String, List<ComputeShareParamDetailVo>> shareItemGroup = computeShareParamDetailVos.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getItemType));
        //项目分类
        shareItemGroup.forEach((itemType, details) -> {
            if (!CollectionUtils.isEmpty(details)) {
                Map<String, List<ComputeShareParamDetailVo>> collect2 = details.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getResponsibilityCode));
                Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>> responseGroup = new HashMap<>();
                collect2.forEach((k, v) -> {
                    if (!CollectionUtils.isEmpty(v)) {
                        //项目代码
                        Map<String, List<ComputeShareParamDetailVo>> collect3 = v.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getCode));
                        Map<String, Map<String, List<ComputeShareParamDetailVo>>> itemCodeMap = new HashMap<>();
                        collect3.forEach((k1, v1) -> {
                            if (!CollectionUtils.isEmpty(v1)) {
                                itemCodeMap.put(k1, v1.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getShareParamCode)));
                            }
                        });
                        responseGroup.put(k, itemCodeMap);
                    }
                });
                sharePercent.put(itemType, responseGroup);
            }
        });
    }

    /**
     * 计算合并后的项目成本
     *
     * @param groupCostDetail           合并分组明细公共对象
     * @param computeProjectCostDetails 细项明细数据
     * @return 合并后项目成本
     */
    private List<ComputeProjectGroupCostDetail> setGroupDetails(ComputeProjectGroupCostDetail groupCostDetail, List<ComputeProjectCostDetail> computeProjectCostDetails) {
        List<ComputeProjectGroupCostDetail> saveList = new ArrayList<>();
        Map<String, List<ComputeProjectCostDetail>> collect = computeProjectCostDetails.stream().collect(Collectors.groupingBy(ComputeProjectCostDetail::getCostColumnType));
        collect.forEach((columnType, detailList) -> {
            ComputeProjectGroupCostDetail costDetail = BeanUtil.convertObj(groupCostDetail, ComputeProjectGroupCostDetail.class);
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            AtomicReference<BigDecimal> singleSum = new AtomicReference<>(new BigDecimal("0.0000"));
            for (ComputeProjectCostDetail detail : detailList) {
                sum.updateAndGet(v -> v.add(detail.getComputeResult()));
                singleSum.updateAndGet(v -> v.add(detail.getComputeSingleResult()));
            }
            costDetail.setType(columnType);
            costDetail.setComputeResult(sum.get());
            costDetail.setComputeSingleResult(singleSum.get());
            saveList.add(costDetail);
        });
        //其他成本列汇总
        if (!CollectionUtils.isEmpty(saveList)) {
            ComputeProjectGroupCostDetail costDetail = BeanUtil.convertObj(groupCostDetail, ComputeProjectGroupCostDetail.class);
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            AtomicReference<BigDecimal> singleSum = new AtomicReference<>(new BigDecimal("0.0000"));
            for (ComputeProjectGroupCostDetail detail : saveList) {
                sum.updateAndGet(v -> v.add(detail.getComputeResult()));
                singleSum.updateAndGet(v -> v.add(detail.getComputeSingleResult()));
            }
            costDetail.setType(ITEM_COST.getCode());
            costDetail.setComputeResult(sum.get());
            costDetail.setComputeSingleResult(singleSum.get());
            saveList.add(costDetail);
        }
        return saveList;
    }

    /**
     * 组装项目成本明细表
     *
     * @param item                患者项目
     * @param costDetail          项目成本明细
     * @param itemCost            项目成本主表
     * @param shareParamCostGroup 分摊参数计算数据
     * @param sharePercent        分摊参数占比及明细数据
     * @param shareSum            分摊参数汇总及科室损益数据
     * @param responsibilitySum   患者项目按责任中心汇总
     * @return 项目成本明细
     */
    private List<ComputeProjectCostDetail> setDetails(PatientItemDepartmentGroupVo item, ComputeProjectCostDetail costDetail,
                                                      ComputeProjectCost itemCost, Map<String, Map<String, List<ShareParamCostVo>>> shareParamCostGroup,
                                                      Map<String, Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>>> sharePercent,
                                                      Map<String, Map<String, Map<String, BigDecimal>>> shareSum, Map<String, BigDecimal> responsibilitySum) {
        // 项目列数值=成本总额*（ 分摊参数占比1*权重1+分摊参数占比2*权重3+...）变更
//        先乘后除公式
//
//        2.1 成本总额=损益表对应报表项目数值
//
//        2.2项目分摊参数数值加总=责任中心项目所有分摊参数数值加总
//
//        2.3项目列数值=成本总额*项目分摊参数数值1*权重1/项目分摊参数数值加总1+成本总额*项目分摊参数数值2*权重2/项目分摊参数数值加总2
        //sharePercent  责任中心-项目代码-参数代码-分子 -> 项目类型-责任中心-项目代码-医嘱代码-参数代码-分子->去掉医嘱代码
        //shareSum  责任中心-参数代码-分母 -> 项目分类-责任中心-分摊参数代码-分摊参数结果
        //shareParamCostGroup 按项目分类-分摊参数代码-分摊参数汇总
        //Map<Long, Map<String, BigDecimal>> profitData reportId-责任中心-值
        String responsibilityCode = itemCost.getResponsibilityCode();
        List<ComputeProjectCostDetail> saveList = new ArrayList<>();
        shareParamCostGroup.forEach((k, paramCostVos) -> {
            ComputeProjectCostDetail computeProjectCostDetail = BeanUtil.convertObj(costDetail, ComputeProjectCostDetail.class);
            if (!CollectionUtils.isEmpty(paramCostVos)) {
                paramCostVos.forEach((columnCode, shareParamCosts) -> {
                    computeProjectCostDetail.setCostColumnCode(columnCode);
                    for (ShareParamCostVo shareParamCostVo : shareParamCosts) {
                        if (!shareParamCostVo.getItemType().equals(itemCost.getItemType())) {
                            continue;
                        }
                        AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
                        AtomicReference<BigDecimal> singleSum = new AtomicReference<>(new BigDecimal("0.0000"));
                        ComputeProjectCostDetail detail = BeanUtil.convertObj(computeProjectCostDetail, ComputeProjectCostDetail.class);
                        detail.setCostColumnType(shareParamCostVo.getColumnType());
                        Map<Long, Map<String, BigDecimal>> profitData = shareParamCostVo.getProfitData();
                        if(!CollectionUtils.isEmpty(profitData)){
                            Map<String, BigDecimal> map = profitData.get(Long.valueOf(shareParamCostVo.getProfitId()));
                            String shareParamCode = shareParamCostVo.getShareParamCode();
                            BigDecimal percent = shareParamCostVo.getPercent();
                            if (!CollectionUtils.isEmpty(map)) {
                                //项目总额
                                BigDecimal amount = map.get(responsibilityCode);
                                if (amount != null) {
                                    //获取分摊参数占比
                                    Map<String, Map<String, Map<String, List<ComputeShareParamDetailVo>>>> itemTypeSharePercentGroup = sharePercent.get(k);
                                    if (!CollectionUtils.isEmpty(itemTypeSharePercentGroup)) {
                                        Map<String, Map<String, List<ComputeShareParamDetailVo>>> responsibilityCodeMap = itemTypeSharePercentGroup.get(responsibilityCode);
                                        Map<String, Map<String, BigDecimal>> itemTypeShareSumGroup = shareSum.get(k);
                                        if (!CollectionUtils.isEmpty(itemTypeShareSumGroup)) {
                                            Map<String, BigDecimal> shareSumTotal = itemTypeShareSumGroup.get(responsibilityCode);
                                            if (!CollectionUtils.isEmpty(shareSumTotal)) {
                                                //项目分摊参数加总
                                                BigDecimal totalPercent = shareSumTotal.get(shareParamCode);
                                                if (!totalPercent.equals(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP))) {
                                                    if (!CollectionUtils.isEmpty(responsibilityCodeMap)) {
                                                        Map<String, List<ComputeShareParamDetailVo>> itemCodeMap = responsibilityCodeMap.get(itemCost.getCode());
                                                        if (!CollectionUtils.isEmpty(itemCodeMap)) {
                                                            List<ComputeShareParamDetailVo> computeShareParamDetailVos = itemCodeMap.get(shareParamCode);
                                                            if (!CollectionUtils.isEmpty(computeShareParamDetailVos)) {
                                                                for (ComputeShareParamDetailVo vo : computeShareParamDetailVos) {
                                                                    //成本总额*项目分摊参数数值1*权重1/项目分摊参数数值加总1
                                                                    BigDecimal multiply = amount.multiply(vo.getComputeResult()).multiply(percent).divide(totalPercent, 4, RoundingMode.HALF_UP);
                                                                    sum.updateAndGet(v -> v.add(multiply));
                                                                    if (!vo.getNum().equals(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP))) {
                                                                        singleSum.updateAndGet(v -> v.add(multiply.divide(vo.getNum(), 4, RoundingMode.HALF_UP)));
                                                                    }
                                                                }
                                                            } else {
                                                                sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                                singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                            }
                                                        } else {
                                                            sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                            singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                        }
                                                    } else {
                                                        sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                        singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                    }
                                                } else {
                                                    //项目分摊汇总为0 按项目收入进行计算
                                                    if (!CollectionUtils.isEmpty(responsibilityCodeMap)) {
                                                        Map<String, List<ComputeShareParamDetailVo>> itemCodeMap = responsibilityCodeMap.get(itemCost.getCode());
                                                        BigDecimal totalAmount = responsibilitySum.get(responsibilityCode);
                                                        if (!CollectionUtils.isEmpty(itemCodeMap)) {
                                                            List<ComputeShareParamDetailVo> computeShareParamDetailVos = itemCodeMap.get(shareParamCode);
                                                            if (!CollectionUtils.isEmpty(computeShareParamDetailVos)) {
                                                                for (ComputeShareParamDetailVo vo : computeShareParamDetailVos) {
                                                                    //成本总额*项目分摊参数数值1*权重1/项目分摊参数数值加总1
                                                                    if(!totalAmount.equals(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP))){
                                                                        BigDecimal multiply = amount.multiply(item.getAmount()).multiply(percent).divide(totalAmount, 4, RoundingMode.HALF_UP);
                                                                        sum.updateAndGet(v -> v.add(multiply));
                                                                        if (!vo.getNum().equals(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP))) {
                                                                            singleSum.updateAndGet(v -> v.add(multiply.divide(vo.getNum(), 4, RoundingMode.HALF_UP)));
                                                                        }
                                                                    }else {
                                                                        sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                                        singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                                    }
                                                                }
                                                            } else {
                                                                sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                                singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                            }
                                                        } else {
                                                            sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                            singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                        }
                                                    } else {
                                                        sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                        singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                    }
                                                }
                                            } else {
                                                sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                                singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                            }
                                        } else {
                                            sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                            singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                        }
                                    } else {
                                        sum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                        singleSum.updateAndGet(v -> v.add(BigDecimal.ZERO));
                                    }
                                    detail.setComputeResult(sum.get());
                                    detail.setComputeSingleResult(singleSum.get());

                                } else {
                                    detail.setComputeResult(BigDecimal.ZERO);
                                    detail.setComputeSingleResult(BigDecimal.ZERO);
                                }
                            } else {
                                detail.setComputeResult(BigDecimal.ZERO);
                                detail.setComputeSingleResult(BigDecimal.ZERO);
                            }
                        }else {
                            detail.setComputeResult(BigDecimal.ZERO);
                            detail.setComputeSingleResult(BigDecimal.ZERO);
                        }

                        saveList.add(detail);
                    }
                });
            }
        });
        return saveList;
    }


    private List<ComputePatientProjectGroupCostDetail> setPatientGroupDetails(PatientItemDepartmentGroupVo item,
                                                                              ComputePatientProjectGroupCostDetail groupCostDetail,
                                                                              List<ComputePatientProjectCostDetail> computeProjectCostDetails) {
        List<ComputePatientProjectGroupCostDetail> saveList = new ArrayList<>();
        Map<String, List<ComputePatientProjectCostDetail>> collect = computeProjectCostDetails.stream().collect(Collectors.groupingBy(ComputePatientProjectCostDetail::getCostColumnType));
        collect.forEach((columnType, detailList) -> {
            ComputePatientProjectGroupCostDetail costDetail = BeanUtil.convertObj(groupCostDetail, ComputePatientProjectGroupCostDetail.class);
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            for (ComputePatientProjectCostDetail detail : detailList) {
                sum.updateAndGet(v -> v.add(detail.getComputeResult()));
            }
            costDetail.setType(columnType);
            costDetail.setComputeResult(sum.get());
            saveList.add(costDetail);
        });

        //其他成本列汇总
        if (!CollectionUtils.isEmpty(saveList)) {
            ComputePatientProjectGroupCostDetail computeProjectCostDetail = BeanUtil.convertObj(groupCostDetail, ComputePatientProjectGroupCostDetail.class);
            AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
            for (ComputePatientProjectGroupCostDetail detail : saveList) {
                sum.updateAndGet(v -> v.add(detail.getComputeResult()));
            }
            computeProjectCostDetail.setType(ITEM_COST.getCode());
            computeProjectCostDetail.setComputeResult(sum.get());
            saveList.add(computeProjectCostDetail);
        }
        //计算项目收入
        ComputePatientProjectGroupCostDetail computeProjectCostDetail = BeanUtil.convertObj(groupCostDetail, ComputePatientProjectGroupCostDetail.class);
        computeProjectCostDetail.setType(ITEM_INCOME.getCode());
        computeProjectCostDetail.setComputeResult(item.getAmount());
        saveList.add(computeProjectCostDetail);
        return saveList;
    }

    /**
     * 获取父类责任中心
     *
     * @param currentUser 当前登录用户
     * @return 父类责任中心
     */
    private List<VisitNoResponsibilityMap> getPatientResponsibility(SessionUserVO currentUser) {
        return getVisitNoResponsibilityMaps(currentUser, responsibilityDepartmentRepository, centerService, log);
    }

    /**
     * 获取医疗服务项目按科室代码-项目代码汇总
     *
     * @return 医疗服务项目字典
     */
    private Map<String, Map<String, Item>> getItemMap() {
        List<Item> list = itemRepository.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw new CostException("医疗服务项目未维护，请先添加医疗服务项目再进行计算，当前计算中止");
        }
        Map<String, List<Item>> collect = list.stream().collect(Collectors.groupingBy(Item::getDepartmentCode));
        Map<String, Map<String, Item>> map = new HashMap<>();
        collect.forEach((k, v) -> {
            map.put(k, v.stream().collect(Collectors.toMap(Item::getCode, item -> item, (a, b) -> b)));
        });
        return map;
    }
}
