package com.kcim.service.impl;

import com.kcim.common.constants.Constant;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.constants.ParameterConstant;
import com.kcim.common.constants.SplitConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.ComputeDateUtils;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.*;
import com.kcim.dao.repository.*;
import com.kcim.service.AllocationQueryService;
import com.kcim.service.CenterService;
import com.kcim.service.IncomeCollectionService;
import com.kcim.service.StandardReportService;
import com.kcim.vo.*;
import com.kcim.web.reponse.ComputeProfitCollectResponse;
import com.kcim.web.reponse.StandardDeptCostCollectResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description:
 * @author: Wang.YS
 * @create: 2024-03-19 11:10
 **/
@Service("StandardReportService")
@Slf4j
@AllArgsConstructor
public class StandardReportServiceImpl implements StandardReportService {
    private static final String AMOUNT_FIELD = "amount";
    private static final String PERCENT_FIELD = "percent" ;

    ResponsibilityRepository responsibilityRepository;

    AllocationQueryService allocationQueryService;

    CenterService centerService;

    AccountingRepository accountingRepository;

    IncomeCollectionService incomeCollectionService;

    ShareParamValueRepository shareParamValueRepository;

    StandItemRepository standItemRepository;

    ItemRepository itemRepository;

    ComputeProjectCostAccountRepository computeProjectCostAccountRepository;

    ComputePatientCostAccountRepository computePatientCostAccountRepository;

    ResponsibilityDepartmentRepository responsibilityDepartmentRepository;
    
    /**
     * 科室直接成本表（医疗成本）
     * @param computeDate 核算年月
     * @return
     */
    @Override
    public List<DeptDirectMedicalCostVO> getDeptDirectMedicalCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);
        //获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getCostByDate(UserContext.getCurrentLoginHospId(), year, month, NumberConstant.ONE);
        if(CollectionUtils.isEmpty(allocationQueryList)){
            return new ArrayList<>();
        }
        //获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap = new HashMap<>();
        //转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectMedicalCostVO(deptDirectMedicalCostMap,allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<DeptDirectMedicalCostVO> deptDirectMedicalCostList = deptDirectMedicalCostMap.values().stream().collect(Collectors.toList());
        //创建医疗业务成本合计
        DeptDirectMedicalCostVO medicalBusinessTotal = createSubtotalVo(deptDirectMedicalCostList.get(NumberConstant.ZERO), "医疗业务成本合计", DeptDirectMedicalCostVO.class);
        //创建总计
        DeptDirectMedicalCostVO grandTotal = createSubtotalVo(deptDirectMedicalCostList.get(NumberConstant.ZERO), "总计", DeptDirectMedicalCostVO.class);
        //按responsibilitySort正序排序
        deptDirectMedicalCostList.sort(Comparator.comparing(DeptDirectMedicalCostVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));
        // 按标准分级分组
        Map<String, List<DeptDirectMedicalCostVO>> shareLevelGroup = deptDirectMedicalCostList.stream().collect(Collectors.groupingBy(DeptDirectMedicalCostVO::getStandardShareLevel));
        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort,Comparator.nullsLast(Comparator.reverseOrder())));
        // 创建各层级小计并按正确顺序插入
        List<DeptDirectMedicalCostVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<DeptDirectMedicalCostVO> deptDirectMedicalCostVOS = shareLevelGroup.get(shareLevel.getCode());
            if(CollectionUtils.isEmpty(deptDirectMedicalCostVOS)){
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(deptDirectMedicalCostVOS);
            // 创建小计对象
            DeptDirectMedicalCostVO subtotalVo = createSubtotalVo(deptDirectMedicalCostVOS.get(NumberConstant.ZERO),String.format("%s小计", shareLevel.getName()), DeptDirectMedicalCostVO.class);
            //将科室的金额加到小计对象中
            deptDirectMedicalCostVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 如果属于医疗业务成本的科室，则小计的金额加到医疗业务成本
            if(NumberConstant.ONE_S.equals(shareLevel.getValue())){
                addBigDecimalFields(subtotalVo, medicalBusinessTotal);
            }
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
            // 医疗业务成本加入到医疗辅助类小计后面
            if(NumberConstant.TWO_S.equals(shareLevel.getCode())){
                result.add(medicalBusinessTotal);
            }
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 科室直接成本表（全成本）
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<DeptFullDirectCostVO> getDeptFullDirectCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);
        
        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getCostByDate(UserContext.getCurrentLoginHospId(), year, month, NumberConstant.ONE);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String, DeptFullDirectCostVO> reportMap = new HashMap<>();
        // 转换为DeptDirectAllCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectAllCostVO(reportMap, allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<DeptFullDirectCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(DeptFullDirectCostVO::getResponsibilitySort, Comparator.nullsLast(Comparator.naturalOrder())));
        // 按标准分级分组
        Map<String, List<DeptFullDirectCostVO>> shareLevelGroup = reportList.stream().collect(Collectors.groupingBy(DeptFullDirectCostVO::getStandardShareLevel));
        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort, Comparator.nullsLast(Comparator.reverseOrder())));
        //创建医疗业务成本合计
        DeptFullDirectCostVO medicalBusinessTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "医疗业务成本合计", DeptFullDirectCostVO.class);
        //创建总计
        DeptFullDirectCostVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", DeptFullDirectCostVO.class);
        // 创建各层级小计并按正确顺序插入
        List<DeptFullDirectCostVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<DeptFullDirectCostVO> reportVOS = shareLevelGroup.get(shareLevel.getCode());
            if (CollectionUtils.isEmpty(reportVOS)) {
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(reportVOS);
            // 创建小计对象
            DeptFullDirectCostVO subtotalVo = createSubtotalVo(reportVOS.get(NumberConstant.ZERO),String.format("%s小计", shareLevel.getName()), DeptFullDirectCostVO.class);
            //将科室的金额加到小计对象中
            reportVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 如果属于医疗业务成本的科室，则小计的金额加到医疗业务成本
            if(NumberConstant.ONE_S.equals(shareLevel.getValue())){
                addBigDecimalFields(subtotalVo, medicalBusinessTotal);
            }
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
            // 医疗业务成本加入到医疗辅助类小计后面
            if(NumberConstant.TWO_S.equals(shareLevel.getCode())){
                result.add(medicalBusinessTotal);
            }
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 获取科室成本明细数据
     * @param computeDate 核算年月
     * @return
     */
    @Override
    public List<ClinicalDeptMedicalCostVO> getClinicalDeptMedicalCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);
        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String, ClinicalDeptMedicalCostVO> reportMap = new HashMap<>();
        // 添加科室成本明细（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptCostDetailVO(reportMap, allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<ClinicalDeptMedicalCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());
        // 创建合计对象
        ClinicalDeptMedicalCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO),"科室全成本合计",ClinicalDeptMedicalCostVO.class);
        //将科室的金额加到合计对象中
        reportList.forEach(item -> addBigDecimalFields(item, subtotalVo));
        // 合计加到列表最后面
        reportList.add(subtotalVo);
        return reportList;
    }

    /**
     * 获取临床服务类科室全成本报表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<ClinicalDeptFullCostVO> getClinicalDeptFullCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }

        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String, ClinicalDeptFullCostVO> reportMap = new HashMap<>();

        // 转换为ClinicalDeptFullCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addClinicalDeptFullCostVO(reportMap, allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<ClinicalDeptFullCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());

        // 创建合计对象
        ClinicalDeptFullCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO), "科室全成本合计", ClinicalDeptFullCostVO.class);

        // 将科室的金额加到合计对象中
        reportList.forEach(item -> addBigDecimalFields(item, subtotalVo));

        // 合计加到列表最后面
        reportList.add(subtotalVo);

        return reportList;
    }

    /**
     * 获取医院临床服务类科室全成本构成分析表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public ComputeProfitCollectResponse getClinicalDeptFullCostAnalysis(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        //获取科室收入
        List<IncomeCollection> responsibilityIncomeList = incomeCollectionService.getResponsibilitiesAccounts(year, month, UserContext.getCurrentLoginHospId());
        if (CollectionUtils.isEmpty(responsibilityIncomeList)) {
            throw new CostException("医院未归集本月收入数据");
        }
        Map<String, BigDecimal> responsibilityIncomeMap = responsibilityIncomeList.stream().collect(Collectors.toMap(IncomeCollection::getResponsibilityCode, IncomeCollection::getAmount));
        //获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        Map<String, List<ShareParamValue>> responsibilityParamValueMap = shareParamValueList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
        //获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap = new HashMap<>();
        //转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectMedicalCostVO(deptDirectMedicalCostMap,allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<DeptDirectMedicalCostVO> reportList = deptDirectMedicalCostMap.values().stream().collect(Collectors.toList());
        // 创建合计对象
        DeptDirectMedicalCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO), "科室合计", DeptDirectMedicalCostVO.class);
        subtotalVo.setResponsibilityCode("deptSubtotal");
        for (DeptDirectMedicalCostVO item : reportList) {
            //计算科室的收入及损益+床日成本及诊次成本
            calcDeptExpandCost(item, responsibilityIncomeMap, responsibilityParamValueMap, visitsBedDaysParamCode);
            // 将科室的金额加到合计对象中
            addBigDecimalFields(item, subtotalVo);
        }
        // 合计加到列表最后面
        reportList.add(subtotalVo);

        // 创建成本项目列表
        List<String> costItems = Arrays.asList(
                "人员经费", "卫生材料费", "药品费", "固定资产折旧费", "无形资产摊销费",
                "提取医疗风险基金", "其他医疗费用", "科室全成本合计","科室收入","收入-成本","床日成本","诊次成本"
        );
        //不要计算占比的项目列表
        List<String> noPercentCostItems = Arrays.asList(
                "科室收入","收入-成本","床日成本","诊次成本"
        );

        // 创建结果列表
        List<ReportFormCustomVo> resultData = new ArrayList<>();
        List<CommonResponsibilityReportVo> titleList = new ArrayList<>();

        // 提取科室名称作为列标题
        for (DeptDirectMedicalCostVO dept : reportList) {
            CommonResponsibilityReportVo title = new CommonResponsibilityReportVo();
            title.setResponsibilityName(dept.getResponsibilityName());
            title.setResponsibilityCode(dept.getResponsibilityCode());
            title.setSort(dept.getResponsibilitySort());
            //添加子级标题
            addCommonResponsibilityChild(title);
            //科室合计列需固定
            if(dept.getResponsibilityCode().equals(subtotalVo.getResponsibilityCode())){
                title.getChild().forEach(item -> item.setIsFixed(NumberConstant.ONE));
            }
            titleList.add(title);
        }

        // 遍历每个成本项目(列转行)
        for (String costItem : costItems) {
            ReportFormCustomVo itemVo = new ReportFormCustomVo();
            itemVo.setReportName(costItem);
            itemVo.setData(new ArrayList<>());
            // 遍历每个科室
            for (DeptDirectMedicalCostVO dept : reportList)  {
                //金额对象
                ReportVo amountReportVo = new ReportVo();
                amountReportVo.setCode(getResponsibilityAmountCode(dept.getResponsibilityCode()));
                //占比对象
                ReportVo percentReportVo = new ReportVo();
                percentReportVo.setCode(getResponsibilityPercentCode(dept.getResponsibilityCode()));
                //获取金额
                BigDecimal deptAmount = getDeptAmount(dept, costItem);
                // 设置金额和百分比
                amountReportVo.setValue(deptAmount);
                //要显示占比的字段才计算占比
                if(!noPercentCostItems.contains(costItem)){
                    //计算百分比
                    BigDecimal percent = getPercent(deptAmount, dept.getTotal());
                    percentReportVo.setValue(percent);
                }
                // 添加金额和百分比
                itemVo.getData().add(amountReportVo);
                itemVo.getData().add(percentReportVo);
            }
            resultData.add(itemVo);
        }

        ComputeProfitCollectResponse response = new ComputeProfitCollectResponse();
        response.setTitle(titleList);
        response.setData(resultData);

        return response;
    }

    /**
     * 获取医院科室成本分摊汇总表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalDeptCostAllocationVO> getHospitalDeptCostAllocation(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }

        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String, HospitalDeptCostAllocationVO> deptCostAllocationMap = new HashMap<>();

        // 转换为HospitalDeptCostAllocationVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addHospitalDeptCostAllocationVO(deptCostAllocationMap, allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<HospitalDeptCostAllocationVO> reportList = new ArrayList<>(deptCostAllocationMap.values());
        //创建总计
        HospitalDeptCostAllocationVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", HospitalDeptCostAllocationVO.class);
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(HospitalDeptCostAllocationVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));

        // 按标准分级分组
        Map<String, List<HospitalDeptCostAllocationVO>> shareLevelGroup = reportList.stream()
                .collect(Collectors.groupingBy(HospitalDeptCostAllocationVO::getStandardShareLevel));

        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort, Comparator.nullsLast(Comparator.reverseOrder())));

        // 创建各层级小计并按正确顺序插入
        List<HospitalDeptCostAllocationVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<HospitalDeptCostAllocationVO> deptCostAllocationVOS = shareLevelGroup.get(shareLevel.getCode());
            if (CollectionUtils.isEmpty(deptCostAllocationVOS)) {
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(deptCostAllocationVOS);
            // 创建小计对象
            HospitalDeptCostAllocationVO subtotalVo = createSubtotalVo(deptCostAllocationVOS.get(NumberConstant.ZERO), String.format("%s小计", shareLevel.getName()), HospitalDeptCostAllocationVO.class);
            //将科室的金额加到小计对象中
            deptCostAllocationVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 获取医院诊次成本构成表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalVisitCostCompositionVO> getHospitalVisitCostComposition(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAcountAccounts(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        //获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        //获取成本会计科目字典
        List<DictDataVo> accountingTypeDict = standCostDictMaps.getAccountingTypeDict();
        List<DictDataVo> costAccountingTypeDict = accountingTypeDict.stream().filter(dictDataVo -> NumberConstant.TWO_S.equals(dictDataVo.getValue())).collect(Collectors.toList());
        // 初始化成本项目映射
        Map<String, HospitalVisitCostCompositionVO> costItemMap =createHospitalVisitCostCompositionVO(costAccountingTypeDict);
        // 处理分配查询数据
        for (AllocationQuery allocationQuery : allocationQueryList) {
            String accountingCode = allocationQuery.getAccountingCode();
            Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
            if (account == null) {
                continue;
            }
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
            HospitalVisitCostCompositionVO vo = costItemMap.get(account.getType());
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(allocationQuery.getAmount()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(allocationQuery.getAmount()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(allocationQuery.getAmount()));
        }
        //获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();

        // 诊次分摊参数值
        BigDecimal visitParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ZERO]);
//        // 床日分摊参数值
//        BigDecimal bedDaysParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ONE]);

        //处理总计和药品小计
        HospitalVisitCostCompositionVO totalVo = new HospitalVisitCostCompositionVO();
        totalVo.setCostItem("总计");
        HospitalVisitCostCompositionVO drugTotalVo = new HospitalVisitCostCompositionVO();
        drugTotalVo.setCostItem("药品费");
        drugTotalVo.setChildren(new ArrayList<>());
        // 转成List便于处理
        List<HospitalVisitCostCompositionVO> reportList = costItemMap.values().stream().collect(Collectors.toList());
        for (HospitalVisitCostCompositionVO item : reportList) {
            //计算每诊次的医疗成本
            item.setMedicalCost(getPercent(item.getMedicalCost(),visitParamValue));
            //计算每诊次的医疗全成本
            item.setMedicalFullCost(getPercent(item.getMedicalFullCost(),visitParamValue));
            //计算每诊次的医院全成本
            item.setHospitalFullCost(getPercent(item.getHospitalFullCost(),visitParamValue));
            // 将金额加到总计对象中
            addBigDecimalFields(item, totalVo);
            /// 将金额加到药品对象中
            if(NumberConstant.THREE_S.equals(item.getCostType())){
                addBigDecimalFields(item, drugTotalVo);
                drugTotalVo.getChildren().add(item);
            }
        }
        drugTotalVo.getChildren().forEach(item -> reportList.remove(item));
        //添加到列表的指定位置
        reportList.add(NumberConstant.TWO,drugTotalVo);
        reportList.add(NumberConstant.ZERO,totalVo);
        return reportList;
    }
    /**
     * 获取医院科室诊次成本表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalVisitCostCompositionVO> getHospitalDeptVisitCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getRespAcountAccounts(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        // 获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();
        BigDecimal visitParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ZERO]);
        Map<String, List<ShareParamValue>> respParamValueList = shareParamValueList.stream()
                .collect(Collectors.groupingBy(item -> item.getResponsibilityCode()));
        // 处理 allocationQueryList 数据
        Map<String, HospitalVisitCostCompositionVO> deptVisitCostMap = new HashMap<>();

        for (AllocationQuery allocationQuery : allocationQueryList) {
            String responsibilityCode = allocationQuery.getResponsibilityCode();
            Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
            if (responsibility == null) {
                continue;
            }
            String accountingCode = allocationQuery.getAccountingCode();
            Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
            if (account == null) {
                continue;
            }
            //只处理临床科室
            if(NumberConstant.FOUR.equals(responsibility.getStandardShareLevel())){
                continue;
            }

            HospitalVisitCostCompositionVO vo = new HospitalVisitCostCompositionVO();
            if (deptVisitCostMap.containsKey(responsibilityCode)) {
                vo = deptVisitCostMap.get(responsibilityCode);
            } else {
                // 初始化科室信息
                vo.setResponsibilityCode(responsibility.getResponsibilityCode());
                vo.setResponsibilityName(responsibility.getResponsibilityName());
                vo.setResponsibilitySort(responsibility.getSort());
                // 初始化所有费用字段为0
                BeanUtil.initBigDecimalFieldsToZero(vo);
                deptVisitCostMap.put(responsibilityCode, vo);
            }
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(allocationQuery.getAmount()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(allocationQuery.getAmount()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(allocationQuery.getAmount()));
        }

        // 转成List便于处理
        List<HospitalVisitCostCompositionVO> reportList = new ArrayList<>(deptVisitCostMap.values());
        // 创建总计对象
        HospitalVisitCostCompositionVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", HospitalVisitCostCompositionVO.class);
        // 计算每诊次成本
        for (HospitalVisitCostCompositionVO item : reportList) {
            List<ShareParamValue> respShareParamValues = respParamValueList.get(item.getResponsibilityCode());
            if(CollectionUtils.isEmpty(respShareParamValues)){
                item.setServiceCount(BigDecimal.ZERO);
                item.setMedicalCost(BigDecimal.ZERO);
                item.setMedicalFullCost(BigDecimal.ZERO);
                item.setHospitalFullCost(BigDecimal.ZERO);
                continue;
            }
            BigDecimal respParamValue = getParamValue(respShareParamValues, visitsBedDaysParamCode[NumberConstant.ZERO]);
            item.setServiceCount(respParamValue);
            //计算每诊次的医疗成本
            item.setMedicalCost(getPercent(item.getMedicalCost(),respParamValue));
            //计算每诊次的医疗全成本
            item.setMedicalFullCost(getPercent(item.getMedicalFullCost(),respParamValue));
            //计算每诊次的医院全成本
            item.setHospitalFullCost(getPercent(item.getHospitalFullCost(),respParamValue));
            // 将各科室金额累加到总计对象
            addBigDecimalFields(item, grandTotal);
        }
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(HospitalVisitCostCompositionVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));
        // 添加总计行
        reportList.add(NumberConstant.ZERO,grandTotal);
        return reportList;
    }

    /**
     * 获取医院床日成本构成表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalVisitCostCompositionVO> getHospitalBedDayCostComposition(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAcountAccounts(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        //获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        //获取成本会计科目字典
        List<DictDataVo> accountingTypeDict = standCostDictMaps.getAccountingTypeDict();
        List<DictDataVo> costAccountingTypeDict = accountingTypeDict.stream().filter(dictDataVo -> NumberConstant.TWO_S.equals(dictDataVo.getValue())).collect(Collectors.toList());
        // 初始化成本项目映射
        Map<String, HospitalVisitCostCompositionVO> costItemMap =createHospitalVisitCostCompositionVO(costAccountingTypeDict);
        // 处理分配查询数据
        for (AllocationQuery allocationQuery : allocationQueryList) {
            String accountingCode = allocationQuery.getAccountingCode();
            Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
            if (account == null) {
                continue;
            }
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
            HospitalVisitCostCompositionVO vo = costItemMap.get(account.getType());
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(allocationQuery.getAmount()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(allocationQuery.getAmount()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(allocationQuery.getAmount()));
        }
        //获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();

        // 床日分摊参数值
        BigDecimal bedDaysParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ONE]);

        //处理总计和药品小计
        HospitalVisitCostCompositionVO totalVo = new HospitalVisitCostCompositionVO();
        totalVo.setCostItem("总计");
        HospitalVisitCostCompositionVO drugTotalVo = new HospitalVisitCostCompositionVO();
        drugTotalVo.setCostItem("药品费");
        drugTotalVo.setChildren(new ArrayList<>());
        // 转成List便于处理
        List<HospitalVisitCostCompositionVO> reportList = costItemMap.values().stream().collect(Collectors.toList());
        for (HospitalVisitCostCompositionVO item : reportList) {
            //计算每诊次的医疗成本
            item.setMedicalCost(getPercent(item.getMedicalCost(),bedDaysParamValue));
            //计算每诊次的医疗全成本
            item.setMedicalFullCost(getPercent(item.getMedicalFullCost(),bedDaysParamValue));
            //计算每诊次的医院全成本
            item.setHospitalFullCost(getPercent(item.getHospitalFullCost(),bedDaysParamValue));
            // 将金额加到总计对象中
            addBigDecimalFields(item, totalVo);
            /// 将金额加到药品对象中
            if(NumberConstant.THREE_S.equals(item.getCostType())){
                addBigDecimalFields(item, drugTotalVo);
                drugTotalVo.getChildren().add(item);
            }
        }
        //移除掉药品费(避免重复)
        drugTotalVo.getChildren().forEach(item -> reportList.remove(item));
        //添加到列表的指定位置
        reportList.add(NumberConstant.TWO,drugTotalVo);
        reportList.add(NumberConstant.ZERO,totalVo);
        return reportList;
    }

    /**
     * 获取医院科室床日成本表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalVisitCostCompositionVO> getHospitalDeptBedDayCost(String computeDate) {
        Integer year = ComputeDateUtils.getComputeYear(computeDate);
        Integer month = ComputeDateUtils.getComputeMonth(computeDate);

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getRespAcountAccounts(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }

        // 处理 allocationQueryList 数据
        Map<String, HospitalVisitCostCompositionVO> deptVisitCostMap = new HashMap<>();

        for (AllocationQuery allocationQuery : allocationQueryList) {
            String responsibilityCode = allocationQuery.getResponsibilityCode();
            Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
            if (responsibility == null) {
                continue;
            }
            String accountingCode = allocationQuery.getAccountingCode();
            Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
            if (account == null) {
                continue;
            }
            //只处理临床科室
            if(NumberConstant.FOUR.equals(responsibility.getStandardShareLevel())){
                continue;
            }

            HospitalVisitCostCompositionVO vo = new HospitalVisitCostCompositionVO();
            if (deptVisitCostMap.containsKey(responsibilityCode)) {
                vo = deptVisitCostMap.get(responsibilityCode);
            } else {
                // 初始化科室信息
                vo.setResponsibilityCode(responsibility.getResponsibilityCode());
                vo.setResponsibilityName(responsibility.getResponsibilityName());
                vo.setResponsibilitySort(responsibility.getSort());
                // 初始化所有费用字段为0
                BeanUtil.initBigDecimalFieldsToZero(vo);
                deptVisitCostMap.put(responsibilityCode, vo);
            }
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(allocationQuery.getAmount()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(allocationQuery.getAmount()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(allocationQuery.getAmount()));
        }

        // 转成List便于处理
        List<HospitalVisitCostCompositionVO> reportList = new ArrayList<>(deptVisitCostMap.values());
        // 获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();
        BigDecimal bedDaysParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ONE]);
        Map<String, List<ShareParamValue>> respParamValueList = shareParamValueList.stream()
                .collect(Collectors.groupingBy(item -> item.getResponsibilityCode()));
        // 创建总计对象
        HospitalVisitCostCompositionVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", HospitalVisitCostCompositionVO.class);
        // 计算每诊次成本
        for (HospitalVisitCostCompositionVO item : reportList) {
            List<ShareParamValue> respShareParamValues = respParamValueList.get(item.getResponsibilityCode());
            if(CollectionUtils.isEmpty(respShareParamValues)){
                item.setServiceCount(BigDecimal.ZERO);
                item.setMedicalCost(BigDecimal.ZERO);
                item.setMedicalFullCost(BigDecimal.ZERO);
                item.setHospitalFullCost(BigDecimal.ZERO);
                continue;
            }
            BigDecimal respParamValue = getParamValue(respShareParamValues, visitsBedDaysParamCode[NumberConstant.ZERO]);
            item.setServiceCount(respParamValue);
            //计算每诊次的医疗成本
            item.setMedicalCost(getPercent(item.getMedicalCost(),respParamValue));
            //计算每诊次的医疗全成本
            item.setMedicalFullCost(getPercent(item.getMedicalFullCost(),respParamValue));
            //计算每诊次的医院全成本
            item.setHospitalFullCost(getPercent(item.getHospitalFullCost(),respParamValue));
            // 将各科室金额累加到总计对象
            addBigDecimalFields(item, grandTotal);
        }
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(HospitalVisitCostCompositionVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));
        // 添加总计行
        reportList.add(NumberConstant.ZERO,grandTotal);
        return reportList;
    }


    /**
     * 获取医院医疗服务项目成本汇总表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalServiceProjectCostVO> getHospitalServiceProjectCost(String computeDate) {
        List<StandItem> standItemList = standItemRepository.getList();
        if(CollectionUtils.isEmpty(standItemList)){
            throw new CostException("标准医疗服务项目未维护，请先添加标准医疗服务项目");
        }
        List<Item> itemList = itemRepository.getList();
        if(CollectionUtils.isEmpty(itemList)){
            throw new CostException("医疗服务项目未维护，请先添加医疗服务项目");
        }
        //获取项目成本数据
        List<ComputeProjectCostAccount> projectCostAccountList = computeProjectCostAccountRepository.getList(computeDate);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算项目成本");
        }
        //把标准服务项目字典转成Map（第一层+第二层）
        List<Map<String, StandItem>> standItemMapDict = getStandItemMapDict(standItemList);
        // 记录项目类别对象
        Map<String, HospitalServiceProjectCostVO> projectCostMap = new HashMap<>();
        for (ComputeProjectCostAccount projectCostAccount : projectCostAccountList) {
            // 获取项目归属的项目类型
            StandItem projectItemType = getProjectItemType(projectCostAccount.getStandItemCode(),standItemMapDict);
            if(ObjectUtils.isEmpty(projectItemType)){
                continue;
            }
            //按项目类型累加数据
            String costType = projectCostAccount.getCostType();
            HospitalServiceProjectCostVO vo ;
            //已有的项目类别
            if (projectCostMap.containsKey(projectItemType.getCode())) {
                vo = projectCostMap.get(projectItemType.getCode());
            } else {
                //新建一个项目类别对象
                vo = convertToHospitalServiceProjectCostVO(projectItemType);
                projectCostMap.put(projectItemType.getCode(), vo);
            }
            //没有数据时跳过
            if(ObjectUtils.isEmpty(projectCostAccount.getComputeResult())){
                continue;
            }
            // 医疗成本
            if ("1".equals(costType)) {
                vo.setMedicalCost(vo.getMedicalCost().add(projectCostAccount.getComputeResult()));
            }
            // 医疗全成本
            if (!"3".equals(costType)) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(projectCostAccount.getComputeResult()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(projectCostAccount.getComputeResult()));
        }
        // 创建项目类别对象并组装层级
        List<HospitalServiceProjectCostVO> reportList = createProjectCategory(standItemMapDict,projectCostMap);
        return reportList;
    }

    /**
     * 获取医院医疗服务项目成本明细表数据
     *
     * @return 医疗服务项目成本明细列表
     */
    @Override
    public List<HospitalServiceProjectCostVO> getMedicalServiceCostDetail(String computeDate) {

        List<HospitalServiceProjectCostVO> projectCostAccountList = computeProjectCostAccountRepository.getMedicalServiceCostDetailList(computeDate);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算项目成本");
        }
        // 记录项目类别对象
        Map<String, HospitalServiceProjectCostVO> projectCostMap = new HashMap<>();
        for (HospitalServiceProjectCostVO projectCostAccount : projectCostAccountList) {
            //按项目类型累加数据
            String costType = projectCostAccount.getCostTypeCode();
            HospitalServiceProjectCostVO vo = new HospitalServiceProjectCostVO();
            //已有的项目类别
            if (projectCostMap.containsKey(projectCostAccount.getItemCode())) {
                vo = projectCostMap.get(projectCostAccount.getItemCode());
            } else {
                //新建一个项目类别对象
                vo = BeanUtil.convertObj(projectCostAccount, HospitalServiceProjectCostVO.class) ;
                // 初始化所有费用字段为0
                BeanUtil.initBigDecimalFieldsToZero(vo);
                projectCostMap.put(projectCostAccount.getItemCode(), vo);
            }
            //没有数据时跳过
            if(ObjectUtils.isEmpty(projectCostAccount.getHospitalFullCost())){
                continue;
            }
            // 医疗成本
            if ("1".equals(costType)) {
                vo.setMedicalCost(vo.getMedicalCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医疗全成本
            if (!"3".equals(costType)) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(projectCostAccount.getHospitalFullCost()));
            //服务量
            if(!ObjectUtils.isEmpty(projectCostAccount.getServiceVolume())){
                vo.setServiceVolume(projectCostAccount.getServiceVolume());
            }

        }
        List<HospitalServiceProjectCostVO> medServiceCostDetailList =new ArrayList<>(projectCostMap.values());
        // 计算每项目成本
        for (HospitalServiceProjectCostVO item : medServiceCostDetailList) {
            BigDecimal serviceVolume = item.getServiceVolume();
            if(ObjectUtils.isEmpty(serviceVolume)){
                item.setMedicalCost(BigDecimal.ZERO);
                item.setMedicalFullCost(BigDecimal.ZERO);
                item.setHospitalFullCost(BigDecimal.ZERO);
                continue;
            }
            //计算每项目的医疗成本
            item.setMedicalCost(getPercent(item.getMedicalCost(),serviceVolume));
            //计算每项目的医疗全成本
            item.setMedicalFullCost(getPercent(item.getMedicalFullCost(),serviceVolume));
            //计算每项目的医院全成本
            item.setHospitalFullCost(getPercent(item.getHospitalFullCost(),serviceVolume));
        }
        return medServiceCostDetailList;
    }

    public List<DiseaseCostDetailVO> getDiseaseCostDetail(String computeDate, String diseaseFilter) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDiseaseCostDetailList(computeDate,diseaseFilter);
        if (CollectionUtils.isEmpty(projectCostAccountList)) {
            throw new CostException("找不到满足条件的数据");
        }
        return getDiseaseCostDetail( computeDate,projectCostAccountList);
    }

    public List<DiseaseCostDetailVO> getDiseaseCostDetail(String computeDate, List<DiseaseCostDetailVO> projectCostAccountList){
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 记录项目类别对象
        Map<String, DiseaseCostDetailVO> diseaseCostMap = new HashMap<>();
        for (DiseaseCostDetailVO projectCostAccount : projectCostAccountList) {
            //按项目类型累加数据
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(projectCostAccount.getCostTypeCode());
            DiseaseCostDetailVO vo = new DiseaseCostDetailVO();
            //已有的项目类别
            if (diseaseCostMap.containsKey(projectCostAccount.getItemCode())) {
                vo = diseaseCostMap.get(projectCostAccount.getItemCode());
            } else {
                vo= BeanUtil.convertObj(projectCostAccount, DiseaseCostDetailVO.class) ;
                BeanUtil.initBigDecimalFieldsToZero(vo);
                //新建一个项目类别对象
                diseaseCostMap.put(projectCostAccount.getItemCode(), vo);
            }
            //没有数据时跳过
            if(ObjectUtils.isEmpty(projectCostAccount.getHospitalFullCost())){
                continue;
            }
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(projectCostAccount.getHospitalFullCost()));
            if(!ObjectUtils.isEmpty(projectCostAccount.getServiceVolume())){
                // 服务量
                vo.setServiceVolume(projectCostAccount.getServiceVolume());
            }
        }
        List<DiseaseCostDetailVO> medServiceCostDetailList =new ArrayList<>(diseaseCostMap.values());
        try {
            //计算单个病种的成本
            medServiceCostDetailList.forEach(vo -> {
                vo.setMedicalCost(getPercent(vo.getMedicalCost(),vo.getServiceVolume()));
                vo.setMedicalFullCost(getPercent(vo.getMedicalFullCost(),vo.getServiceVolume()));
                vo.setHospitalFullCost(getPercent(vo.getHospitalFullCost(),vo.getServiceVolume()));
            });
        }catch (Exception e){
            log.error("计算病种成本时发生异常",e);
        }
        medServiceCostDetailList.sort(Comparator.comparing(DiseaseCostDetailVO::getItemCode));
        return medServiceCostDetailList;
    }


    /**
     * 获取医院病种成本明细表数据
     *
     * @return 病种成本明细列表
     */
    @Override
    public List<DiseaseCostDetailVO> getDiseaseCostDetail(String computeDate) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDiseaseCostDetailList(computeDate,null);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }
        return getDiseaseCostDetail( computeDate,projectCostAccountList);
    }

    public List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(String computeDate, String diseaseFilter) {

        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDiseaseCostCompositionDetail(computeDate, diseaseFilter);
        if (CollectionUtils.isEmpty(projectCostAccountList)) {
            throw new CostException("找不到满足条件的数据");
        }
        return getDiseaseCostCompositionDetail(computeDate,projectCostAccountList);
    }

    public List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(String computeDate, List<DiseaseCostDetailVO> projectCostAccountList) {
        // 记录项目类别对象
        Map<String, DiseaseCostDetailVO> diseaseCostMap = new HashMap<>();
        for (DiseaseCostDetailVO projectCostAccount : projectCostAccountList) {
            //按项目类型累加数据
            String accountType = projectCostAccount.getCostTypeCode();
            DiseaseCostDetailVO vo ;
            //已有的项目类别
            if (diseaseCostMap.containsKey(projectCostAccount.getItemCode())) {
                vo = diseaseCostMap.get(projectCostAccount.getItemCode());
            } else {
                vo = new DiseaseCostDetailVO();
                vo.setItemCode(projectCostAccount.getItemCode());
                vo.setItemName(projectCostAccount.getItemName());
                BeanUtil.initBigDecimalFieldsToZero(vo);
                //新建一个项目类别对象
                diseaseCostMap.put(projectCostAccount.getItemCode(), vo);
            }
            //按会计科目类型累加费用
            addAccountTypeExpense(accountType, projectCostAccount.getHospitalFullCost(), vo);
            //累加数量
            vo.setServiceVolume(vo.getServiceVolume().add(projectCostAccount.getServiceVolume()));
        }
        List<DiseaseCostDetailVO> diseaseCostDetailList =new ArrayList<>(diseaseCostMap.values());
        //按会计科目类型计算占比
        diseaseCostDetailList.forEach(vo -> setAccountTypeExpenseRatio(vo));
        diseaseCostDetailList.sort(Comparator.comparing(DiseaseCostDetailVO::getItemCode));
        return diseaseCostDetailList;
    }


    /**
     * 获取病种成本构成明细表数据
     *
     * @return 病种成本明细列表，包含各病种的成本明细及总计行
     */
    @Override
    public List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(String computeDate) {

        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDiseaseCostCompositionDetail(computeDate,null);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }
       return getDiseaseCostCompositionDetail(computeDate,projectCostAccountList);
    }

    public StandardDeptCostCollectResponse getDeptDiseaseCostCompositionDetail(String computeDate, String diseaseFilter) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDeptDiseaseCostCompositionDetail(computeDate,diseaseFilter);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("找不到满足条件的数据");
        }
        return getDeptDiseaseCostCompositionDetail( computeDate,projectCostAccountList);
    }

    public StandardDeptCostCollectResponse getDeptDiseaseCostCompositionDetail(String computeDate,List<DiseaseCostDetailVO> projectCostAccountList) {
        //科室责任中心对照数据
        List<ResponsibilityDepartIdVO> responsibilityDepartment = responsibilityDepartmentRepository.getResponsibility(UserContext.getHospId());
        Map<String, List<ResponsibilityDepartIdVO>> deptRespMap = responsibilityDepartment.stream()
                .filter(r -> r.getDepartmentCode() != null) // 过滤掉departmentCode为null的记录
                .collect(Collectors.groupingBy(ResponsibilityDepartIdVO::getDepartmentCode));
        //设置科室对应的责任中心
        for (DiseaseCostDetailVO diseaseCostDetailVO : projectCostAccountList) {
            List<ResponsibilityDepartIdVO> responsibilityDepartIdVOList = deptRespMap.get(diseaseCostDetailVO.getDepartmentCode());
            if(CollectionUtils.isEmpty(responsibilityDepartIdVOList)){
                continue;
            }
            ResponsibilityDepartIdVO responsibilityDepartVO = responsibilityDepartIdVOList.get(NumberConstant.ZERO);
            diseaseCostDetailVO.setResponsibilityCode(responsibilityDepartVO.getResponsibilityCode());
            diseaseCostDetailVO.setResponsibilityName(responsibilityDepartVO.getResponsibilityName());
        }
        //按责任中心分组
        Map<String, List<DiseaseCostDetailVO>> deptPtAccountGroup = projectCostAccountList.stream()
                .filter(d -> d.getResponsibilityCode() != null) // 过滤掉responsibilityCode为null的记录
                .collect(Collectors.groupingBy(DiseaseCostDetailVO::getResponsibilityCode));

        List<CommonResponsibilityReportVo> titleList = new ArrayList<>();
        // 提取科室名称作为列标题
        deptPtAccountGroup.forEach((deptCode, deptPtAccountList) -> {
            if(!CollectionUtils.isEmpty(deptPtAccountList)){
                CommonResponsibilityReportVo title = new CommonResponsibilityReportVo();
                DiseaseCostDetailVO vo = deptPtAccountList.get(NumberConstant.ZERO);
                title.setResponsibilityName(vo.getResponsibilityName());
                title.setResponsibilityCode(vo.getResponsibilityCode());
                title.setSort(NumberConstant.ONE);
                //添加子级标题
                addCommonResponsibilityChild(title);
                titleList.add(title);
            }

        });
        //按科室名称排序
        titleList.sort(Comparator.comparing(CommonResponsibilityReportVo::getResponsibilityName));
        // 记录项目类别对象
        Map<String, StandardReportFormCustomVo> diseaseCostMap = new HashMap<>();
        // 遍历每个项目生成科室金额
        for (DiseaseCostDetailVO costItem : projectCostAccountList) {
            StandardReportFormCustomVo itemVo ;
            if(diseaseCostMap.containsKey(costItem.getItemCode())){
                itemVo=diseaseCostMap.get(costItem.getItemCode());
            }else{
                itemVo = new StandardReportFormCustomVo();
                itemVo.setReportName(costItem.getItemName());
                itemVo.setReportCode(costItem.getItemCode());
                itemVo.setData(new ArrayList<>());
                itemVo.setTotalValue(BigDecimal.ZERO);
                diseaseCostMap.put(costItem.getItemCode(),itemVo);
            }
            Optional<ReportVo> respItem = itemVo.getData().stream().filter(vo -> vo.getCode().equals(getResponsibilityAmountCode(costItem.getResponsibilityCode()))).findFirst();
            //已包含此责任中心的项目,直接将金额加到已有的项目上
            if(respItem.isPresent()){
                BigDecimal value = (BigDecimal) respItem.get().getValue();
                respItem.get().setValue(value.add(costItem.getHospitalFullCost()));
            }else{
                //金额对象
                ReportVo amountReportVo = new ReportVo();
                amountReportVo.setCode(getResponsibilityAmountCode(costItem.getResponsibilityCode()));
                // 设置金额
                amountReportVo.setValue(costItem.getHospitalFullCost());
                // 添加金额
                itemVo.getData().add(amountReportVo);
            }
            //计算总额
            itemVo.setTotalValue(itemVo.getTotalValue().add(costItem.getHospitalFullCost()));
        }

        List<StandardReportFormCustomVo> diseaseCostDetailList =new ArrayList<>(diseaseCostMap.values());

        diseaseCostDetailList.sort(Comparator.comparing(StandardReportFormCustomVo::getReportCode));

        // 遍历每个成本项目(列转行)
        for (StandardReportFormCustomVo costItem : diseaseCostDetailList) {
            if(CollectionUtils.isEmpty(costItem.getData())){
                continue;
            }
            List<ReportVo> dataList =new ArrayList<>();
            dataList.addAll(costItem.getData());
            for (ReportVo amountReportVo : dataList) {
                //占比对象
                ReportVo percentReportVo = new ReportVo();
                percentReportVo.setCode(amountReportVo.getCode().replace(AMOUNT_FIELD, PERCENT_FIELD));
                //计算百分比
                BigDecimal percent = getPercent((BigDecimal)amountReportVo.getValue() , costItem.getTotalValue());
                percentReportVo.setValue(percent);
                // 添加百分比
                costItem.getData().add(percentReportVo);
            }
        }
        StandardDeptCostCollectResponse response = new StandardDeptCostCollectResponse();
        response.setTitle(titleList);
        response.setData(diseaseCostDetailList);

        return response;
    }

    /**
     * 获取服务单元病种成本构成明细表数据
     * @param computeDate
     * @return
     */
    @Override
    public StandardDeptCostCollectResponse getDeptDiseaseCostCompositionDetail(String computeDate) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDeptDiseaseCostCompositionDetail(computeDate,null);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }
        return getDeptDiseaseCostCompositionDetail( computeDate,projectCostAccountList);
    }

    /**
     * 获取医院DRG成本明细表数据
     *
     * @param computeDate 核算年月
     * @return DRG成本明细列表
     */
    @Override
    public List<DiseaseCostDetailVO> getDrgCostDetail(String computeDate) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDrgCostDetailList(computeDate);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 记录项目类别对象
        Map<String, DiseaseCostDetailVO> drgeCostMap = new HashMap<>();
        for (DiseaseCostDetailVO projectCostAccount : projectCostAccountList) {
            //按项目类型累加数据
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(projectCostAccount.getCostTypeCode());
            DiseaseCostDetailVO vo ;
            //已有的项目类别
            if (drgeCostMap.containsKey(projectCostAccount.getItemCode())) {
                vo = drgeCostMap.get(projectCostAccount.getItemCode());
            } else {
                vo=BeanUtil.convertObj(projectCostAccount,DiseaseCostDetailVO.class);
                BeanUtil.initBigDecimalFieldsToZero(vo);
                //新建一个项目类别对象
                drgeCostMap.put(projectCostAccount.getItemCode(), vo);
            }
            //没有数据时跳过
            if(ObjectUtils.isEmpty(projectCostAccount.getHospitalFullCost())){
                continue;
            }
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(projectCostAccount.getHospitalFullCost()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(projectCostAccount.getHospitalFullCost()));
            // 服务量
            vo.setServiceVolume(projectCostAccount.getServiceVolume());
        }
        List<DiseaseCostDetailVO> drgeCostDetailList = new ArrayList<>(drgeCostMap.values());
        //计算单个DRG的成本
        drgeCostDetailList.forEach(vo -> {
            vo.setMedicalCost(getPercent( vo.getMedicalCost(),vo.getServiceVolume()));
            vo.setMedicalFullCost(getPercent(vo.getMedicalFullCost(),vo.getServiceVolume()));
            vo.setHospitalFullCost(getPercent(vo.getHospitalFullCost(),vo.getServiceVolume()));
        });
        drgeCostDetailList.sort(Comparator.comparing(DiseaseCostDetailVO::getItemCode));
        return drgeCostDetailList;
    }

    /**
     * 获取DRG成本构成明细表数据
     * @param computeDate
     * @return
     */
    @Override
    public List<DiseaseCostDetailVO> getDrgCostCompositionDetail(String computeDate) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDrgCostCompositionDetail(computeDate);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }
        // 记录项目类别对象
        Map<String, DiseaseCostDetailVO> diseaseCostMap = new HashMap<>();
        for (DiseaseCostDetailVO projectCostAccount : projectCostAccountList) {
            //按项目类型累加数据
            String accountType = projectCostAccount.getCostTypeCode();
            DiseaseCostDetailVO vo ;
            //已有的项目类别
            if (diseaseCostMap.containsKey(projectCostAccount.getItemCode())) {
                vo = diseaseCostMap.get(projectCostAccount.getItemCode());
            } else {
                vo = new DiseaseCostDetailVO();
                vo.setItemCode(projectCostAccount.getItemCode());
                vo.setItemName(projectCostAccount.getItemName());
                BeanUtil.initBigDecimalFieldsToZero(vo);
                //新建一个项目类别对象
                diseaseCostMap.put(projectCostAccount.getItemCode(), vo);
            }
            //按会计科目类型累加费用
            addAccountTypeExpense(accountType, projectCostAccount.getHospitalFullCost(), vo);
            //累加数量
            vo.setServiceVolume(vo.getServiceVolume().add(projectCostAccount.getServiceVolume()));
        }
        List<DiseaseCostDetailVO> diseaseCostDetailList =new ArrayList<>(diseaseCostMap.values());
        //按会计科目类型计算占比
        diseaseCostDetailList.forEach(vo -> setAccountTypeExpenseRatio(vo));
        return diseaseCostDetailList;
    }

    /**
     * 获取科室DRG成本构成明细表数据
     * @param computeDate
     * @return
     */
    @Override
    public StandardDeptCostCollectResponse getDeptDrgCostCompositionDetail(String computeDate) {
        List<DiseaseCostDetailVO> projectCostAccountList = computePatientCostAccountRepository.getDeptDrgCostCompositionDetail(computeDate);
        if(CollectionUtils.isEmpty(projectCostAccountList)){
            throw new CostException("请先计算患者成本");
        }

        //科室责任中心对照数据
        List<ResponsibilityDepartIdVO> responsibilityDepartment = responsibilityDepartmentRepository.getResponsibility(UserContext.getHospId());
        Map<String, List<ResponsibilityDepartIdVO>> deptRespMap = responsibilityDepartment.stream().filter(r -> r.getDepartmentCode() != null).collect(Collectors.groupingBy(ResponsibilityDepartIdVO::getDepartmentCode));
        //设置科室对应的责任中心
        for (DiseaseCostDetailVO diseaseCostDetailVO : projectCostAccountList) {
            List<ResponsibilityDepartIdVO> responsibilityDepartIdVOList = deptRespMap.get(diseaseCostDetailVO.getDepartmentCode());
            if(CollectionUtils.isEmpty(responsibilityDepartIdVOList)){
                continue;
            }
            ResponsibilityDepartIdVO responsibilityDepartVO = responsibilityDepartIdVOList.get(NumberConstant.ZERO);
            diseaseCostDetailVO.setResponsibilityCode(responsibilityDepartVO.getResponsibilityCode());
            diseaseCostDetailVO.setResponsibilityName(responsibilityDepartVO.getResponsibilityName());
        }

        Map<String, List<DiseaseCostDetailVO>> deptPtAccountGroup = projectCostAccountList.stream().filter(r -> r.getResponsibilityCode() != null).collect(Collectors.groupingBy(DiseaseCostDetailVO::getResponsibilityCode));

        List<CommonResponsibilityReportVo> titleList = new ArrayList<>();
        // 提取科室名称作为列标题
        deptPtAccountGroup.forEach((deptCode, deptPtAccountList) -> {
            if(!CollectionUtils.isEmpty(deptPtAccountList)){
                CommonResponsibilityReportVo title = new CommonResponsibilityReportVo();
                DiseaseCostDetailVO vo = deptPtAccountList.get(NumberConstant.ZERO);
                title.setResponsibilityName(vo.getDepartmentName());
                title.setResponsibilityCode(vo.getResponsibilityCode());
                title.setSort(NumberConstant.ONE);
                //添加子级标题
                addCommonResponsibilityChild(title);
                titleList.add(title);
            }
        });
        //按科室名称排序
        titleList.sort(Comparator.comparing(CommonResponsibilityReportVo::getResponsibilityName));

        // 记录项目类别对象
        Map<String, StandardReportFormCustomVo> diseaseCostMap = new HashMap<>();
        // 遍历每个项目生成科室金额
        for (DiseaseCostDetailVO costItem : projectCostAccountList) {
            StandardReportFormCustomVo itemVo ;
            if(diseaseCostMap.containsKey(costItem.getItemCode())){
                itemVo=diseaseCostMap.get(costItem.getItemCode());
            }else{
                itemVo = new StandardReportFormCustomVo();
                itemVo.setReportName(costItem.getItemName());
                itemVo.setReportCode(costItem.getItemCode());
                itemVo.setData(new ArrayList<>());
                itemVo.setTotalValue(BigDecimal.ZERO);
                diseaseCostMap.put(costItem.getItemCode(), itemVo);
            }
            //金额对象
            ReportVo amountReportVo = new ReportVo();
            amountReportVo.setCode(getResponsibilityAmountCode(costItem.getResponsibilityCode()));
            // 设置金额
            amountReportVo.setValue(costItem.getHospitalFullCost());
            // 添加金额
            itemVo.getData().add(amountReportVo);
            //计算总额
            itemVo.setTotalValue(itemVo.getTotalValue().add(costItem.getHospitalFullCost()));
        }

        List<StandardReportFormCustomVo> diseaseCostDetailList =new ArrayList<>(diseaseCostMap.values());

        // 遍历每个成本项目(列转行)
        for (StandardReportFormCustomVo costItem : diseaseCostDetailList) {
            if(CollectionUtils.isEmpty(costItem.getData())){
                continue;
            }
            List<ReportVo> dataList =new ArrayList<>();
            dataList.addAll(costItem.getData());
            for (ReportVo amountReportVo :dataList) {
                //占比对象
                ReportVo percentReportVo = new ReportVo();
                percentReportVo.setCode(amountReportVo.getCode().replace(AMOUNT_FIELD, PERCENT_FIELD));
                //计算百分比
                BigDecimal percent = getPercent((BigDecimal)amountReportVo.getValue() , costItem.getTotalValue());
                percentReportVo.setValue(percent);
                // 添加百分比
                costItem.getData().add(percentReportVo);
            }
        }
        StandardDeptCostCollectResponse response = new StandardDeptCostCollectResponse();
        response.setTitle(titleList);
        response.setData(diseaseCostDetailList);

        return response;
    }

    /**
     * 按会计科目类型计算占比
     * @param vo
     */
    public void setAccountTypeExpenseRatio(DiseaseCostDetailVO vo){
        vo.setPersonnelExpenseRatio(getPercent(vo.getPersonnelExpense(),vo.getTotalCost()));
        vo.setDrugExpenseRatio(getPercent(vo.getDrugExpense(),vo.getTotalCost()));
        vo.setMedicalMaterialExpenseRatio(getPercent(vo.getMedicalMaterialExpense(),vo.getTotalCost()));
        vo.setFixedAssetDepreciationRatio(getPercent(vo.getFixedAssetDepreciation(),vo.getTotalCost()));
        vo.setIntangibleAssetAmortizationRatio(getPercent(vo.getIntangibleAssetAmortization(),vo.getTotalCost()));
        vo.setMedicalRiskFundRatio(getPercent(vo.getMedicalRiskFund(),vo.getTotalCost()));
        vo.setOtherMedicalExpensesRatio(getPercent(vo.getOtherMedicalExpenses(),vo.getTotalCost()));
    }

    /**
     * 按会计科目类型累加费用
     * @param accountType
     * @param expense
     * @param vo
     */
    public void addAccountTypeExpense(String accountType, BigDecimal expense,DiseaseCostDetailVO vo) {
        // 根据费用类型累加到对应字段
        switch (accountType) {
            case "1":
                vo.setPersonnelExpense(vo.getPersonnelExpense().add(expense));
                break;
            case "2":
                vo.setMedicalMaterialExpense(vo.getMedicalMaterialExpense().add(expense));
                break;
            case "3":
                vo.setDrugExpense(vo.getDrugExpense().add(expense));
                break;
            case "4":
                vo.setFixedAssetDepreciation(vo.getFixedAssetDepreciation().add(expense));
                break;
            case "5":
                vo.setIntangibleAssetAmortization(vo.getIntangibleAssetAmortization().add(expense));
                break;
            case "6":
                vo.setMedicalRiskFund(vo.getMedicalRiskFund().add(expense));
                break;
            case "7":
                vo.setOtherMedicalExpenses(vo.getOtherMedicalExpenses().add(expense));
                break;
            default:
                break;
        }
        vo.setTotalCost(vo.getTotalCost().add(expense));
    }

    /**
     * 获取项目归属的项目类型
     * @param standItemCode
     * @param standItemMapDict
     * @return
     */
    public StandItem getProjectItemType(String standItemCode,List<Map<String, StandItem>> standItemMapDict) {
        //不在完整字典里 返回null
        if(!standItemMapDict.get(NumberConstant.ZERO).containsKey(standItemCode)){
            return null;
        }
        //第一层的项目
        if(standItemMapDict.get(NumberConstant.ONE).containsKey(standItemCode)){
            return standItemMapDict.get(NumberConstant.ONE).get(standItemCode);
        }
        //第二层的项目
        if(standItemMapDict.get(NumberConstant.TWO).containsKey(standItemCode)){
            return standItemMapDict.get(NumberConstant.TWO).get(standItemCode);
        }
        //其他层的项目需要递归找到所属的第二层
        StandItem standItem = standItemMapDict.get(NumberConstant.ZERO).get(standItemCode);
        return  getProjectItemType(standItem.getParentCode(),standItemMapDict);
    }



    /**
     * 生成完整字典、第一层、第二层的code映射字典
     * @param standItemList
     * @return
     */
    public List<Map<String,StandItem>> getStandItemMapDict(List<StandItem> standItemList) {
        List<Map<String,StandItem>> mapList=new ArrayList<>();
        if(CollectionUtils.isEmpty(standItemList)){
            Map<String,StandItem> map = new HashMap<>();
            Map<String,StandItem> firstMap = new HashMap<>();
            Map<String,StandItem> secondMap = new HashMap<>();
            mapList.add(map);
            mapList.add(firstMap);
            mapList.add(secondMap);
            return mapList;
        }
        // 构建完整字典code到StandItem的映射
        Map<String, StandItem> standItemMap = standItemList.stream()
                .collect(Collectors.toMap(StandItem::getCode, item -> item));
        mapList.add(standItemMap);
        List<StandItem> firstLevel = standItemList.stream().filter(item -> NumberConstant.ZERO_S.equals(item.getParentCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(firstLevel)){
            Map<String,StandItem> firstMap = new HashMap<>();
            Map<String,StandItem> secondMap = new HashMap<>();
            mapList.add(firstMap);
            mapList.add(secondMap);
            return mapList;
        }
        // 构建第一层code到StandItem的映射
        Map<String, StandItem> firstLevelMap = firstLevel.stream()
                .collect(Collectors.toMap(StandItem::getCode, item -> item));
        mapList.add(firstLevelMap);
        List<StandItem> secondLevel= standItemList.stream().filter(item -> firstLevelMap.containsKey(item.getParentCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(secondLevel)){
            Map<String,StandItem> secondMap = new HashMap<>();
            mapList.add(secondMap);
            return mapList;
        }
        // 构建第二层code到StandItem的映射
        Map<String, StandItem> secondLevelMap = secondLevel.stream()
                .collect(Collectors.toMap(StandItem::getCode, item -> item));
        mapList.add(secondLevelMap);
        return mapList;
    }
    


    /**
     * 根据标准项目字典创建项目类别
     * @param standItemMapDict 标准项目字典
     * @return 项目类别
     */
    private List<HospitalServiceProjectCostVO> createProjectCategory(List<Map<String, StandItem>> standItemMapDict,Map<String, HospitalServiceProjectCostVO> projectCostMap ) {
        if(CollectionUtils.isEmpty(standItemMapDict.get(NumberConstant.ONE))){
            return new ArrayList<>();
        }
        List<StandItem> sencodLevel=new ArrayList<>(standItemMapDict.get(NumberConstant.TWO).values());
        List<StandItem> firstLevel =new ArrayList<>(standItemMapDict.get(NumberConstant.ONE).values());
        //按序号排序
        firstLevel.sort(Comparator.comparing(StandItem::getSort));
        List<HospitalServiceProjectCostVO> hospitalServiceProjectCostVOS =firstLevel.stream().map( item->convertToHospitalServiceProjectCostVO(item)).collect(Collectors.toList());
        for (HospitalServiceProjectCostVO item : hospitalServiceProjectCostVOS) {
            //先加自己的
            if(projectCostMap.containsKey(item.getItemCode())){
                addBigDecimalFields(projectCostMap.get(item.getItemCode()), item);
            }
            if(CollectionUtils.isEmpty(sencodLevel)){
                continue;
            }
            //第一层对应的第二层数据
            List<StandItem> children = sencodLevel.stream().filter(child -> item.getItemCode().equals(child.getParentCode())).collect(Collectors.toList());
            if(CollectionUtils.isEmpty( children)){
                continue;
            }
            //按序号排序
            children.sort(Comparator.comparing(StandItem::getSort));
            item.setChildren(new ArrayList<>());
            for (StandItem child : children) {
                HospitalServiceProjectCostVO childProject ;
                //优先取已有的数据
                if(projectCostMap.containsKey(child.getCode())){
                    childProject=projectCostMap.get(child.getCode());
                }else{
                    childProject = convertToHospitalServiceProjectCostVO(child);
                }
                //加给第一层
                addBigDecimalFields(childProject, item);
                item.getChildren().add(childProject);
            }
        }
        return  hospitalServiceProjectCostVOS;
    }

    public HospitalServiceProjectCostVO convertToHospitalServiceProjectCostVO(StandItem standItem){
        HospitalServiceProjectCostVO vo = new HospitalServiceProjectCostVO();
        vo.setItemCode(standItem.getCode());
        vo.setItemName(standItem.getName());
        // 初始化所有费用字段为0
        BeanUtil.initBigDecimalFieldsToZero(vo);
        return vo;
    }

    /**
     * 获取可是指定项目的金额
     * @param dept
     * @param costItem
     * @return
     */
    public  BigDecimal getDeptAmount(DeptDirectMedicalCostVO dept,String costItem) {
        BigDecimal amount = BigDecimal.ZERO;
        switch (costItem) {
            case "人员经费":
                amount = dept.getPersonnelExpense();
                break;
            case "卫生材料费":
                amount = dept.getHealthMaterialFee();
                break;
            case "药品费":
                amount = dept.getDrugFee();
                break;
            case "固定资产折旧费":
                amount =dept.getFixedAssetDepreciation();
                break;
            case "无形资产摊销费":
                amount = dept.getIntangibleAssetAmortization();
                break;
            case "提取医疗风险基金":
                amount = dept.getMedicalRiskFundExtraction();
                break;
            case "其他医疗费用":
                amount = dept.getOtherMedicalExpenses();
                break;
            case "科室全成本合计":
                amount = dept.getTotal();
                break;
            case "科室收入":
                amount = dept.getIncome();
                break;
            case "收入-成本":
                amount = dept.getProfit();
                break;
            case "诊次成本":
                amount = dept.getVisitsCost();
                break;
            case "床日成本":
                amount = dept.getBedDaysCost();
                break;
            default:
                break;
        }
        return amount;
    }

    /**
     * 计算科室的收入及损益+床日成本及诊次成本
     * @param item
     * @param responsibilityIncomeMap
     * @param responsibilityParamValueMap
     * @param visitsBedDaysParamCode
     */
    private void calcDeptExpandCost(DeptDirectMedicalCostVO item,
                                    Map<String, BigDecimal> responsibilityIncomeMap,
                                    Map<String, List<ShareParamValue>> responsibilityParamValueMap,
                                    String[] visitsBedDaysParamCode) {
        //计算科室的收入及损益
        if(responsibilityIncomeMap.containsKey(item.getResponsibilityCode())){
            item.setIncome(responsibilityIncomeMap.get(item.getResponsibilityCode()));
            item.setProfit(item.getIncome().subtract(item.getTotal()));
        }else{
            item.setIncome(BigDecimal.ZERO);
            item.setProfit(item.getIncome().subtract(item.getTotal()));
        }
        //计算科室的床日成本及诊次成本
        if(responsibilityParamValueMap.containsKey(item.getResponsibilityCode())){
            List<ShareParamValue> shareParamValues = responsibilityParamValueMap.get(item.getResponsibilityCode());

            // 诊次分摊参数值
            BigDecimal visitParamValue = getParamValue(shareParamValues, visitsBedDaysParamCode[NumberConstant.ZERO]);
            // 床日分摊参数值
            BigDecimal bedDaysParamValue = getParamValue(shareParamValues, visitsBedDaysParamCode[NumberConstant.ONE]);
            // 计算诊次成本及床日成本
            item.setVisitsCost(getPercent(item.getTotal(),visitParamValue));
            item.setBedDaysCost(getPercent(item.getTotal(),bedDaysParamValue));
        }else{
            item.setBedDaysCost(BigDecimal.ZERO);
            item.setVisitsCost(BigDecimal.ZERO);
        }
    }


    /**
     * 获取百分比
     * @param amount
     * @param total
     * @return
     */
    public BigDecimal getPercent(BigDecimal amount,BigDecimal total){
        if(total.compareTo(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)) == 0){
            return BigDecimal.ZERO;
        }
        return amount.divide(total,4, RoundingMode.HALF_UP);
    }

    /**
     * 获取责任中心金额字段
     * @param responsibilityCode
     * @return
     */
    public String getResponsibilityAmountCode(String responsibilityCode){
        return String.format("%s_%s", responsibilityCode, AMOUNT_FIELD);
    }

    /**
     * 获取责任中心占比字段
     * @param responsibilityCode
     * @return
     */
    public String getResponsibilityPercentCode(String responsibilityCode){
        return String.format("%s_%s", responsibilityCode, PERCENT_FIELD);
    }

    /**
     * 添加全成本构成表标题的子级标题
     * @param commonResponsibility
     */
    public void addCommonResponsibilityChild(CommonResponsibilityReportVo commonResponsibility) {
        commonResponsibility.setChild(new ArrayList<>());
        CommonResponsibilityReportVo amount=new CommonResponsibilityReportVo();
        amount.setResponsibilityCode(getResponsibilityAmountCode(commonResponsibility.getResponsibilityCode() ));
        amount.setResponsibilityName("金额");
        amount.setSort(NumberConstant.ZERO);
        amount.setDataType(NumberConstant.ONE);
        amount.setDataTypeName("数值");
        amount.setDecimalPlace(NumberConstant.TWO);
        amount.setPermil(NumberConstant.ONE);
        amount.setIsFixed(NumberConstant.ZERO);
        commonResponsibility.getChild().add( amount);
        CommonResponsibilityReportVo percent=new CommonResponsibilityReportVo();
        percent.setResponsibilityCode(getResponsibilityPercentCode(commonResponsibility.getResponsibilityCode()));
        percent.setResponsibilityName("占比");
        percent.setSort(NumberConstant.ONE);
        percent.setDataType(NumberConstant.TWO);
        percent.setDataTypeName("百分比");
        percent.setDecimalPlace(NumberConstant.TWO);
        percent.setPermil(NumberConstant.ZERO);
        percent.setIsFixed(NumberConstant.ZERO);
        commonResponsibility.getChild().add( percent);
    }

    /**
     * 添加临床服务类科室全成本明细
     * @param reportMap
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addClinicalDeptFullCostVO(Map<String, ClinicalDeptFullCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        ClinicalDeptFullCostVO reportVO = new ClinicalDeptFullCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            // 生成科室成本报表信息
            initDeptCostReport(reportVO, responsibility, accountType, costType, standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
            reportMap.put(allocationQuery.getResponsibilityCode(), reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (costType.getValue()) {
            case "1":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setMedicalCostTotalDirect(reportVO.getMedicalCostTotalDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setMedicalCostTotalIndirect(reportVO.getMedicalCostTotalIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicalCostTotal(reportVO.getMedicalCostTotal().add(allocationQuery.getAmount()));
                break;
            case "2":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setFinancialProjectFundsDirect(reportVO.getFinancialProjectFundsDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setFinancialProjectFundsIndirect(reportVO.getFinancialProjectFundsIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setFinancialProjectFunds(reportVO.getFinancialProjectFunds().add(allocationQuery.getAmount()));
                break;
            case "3":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setNonPeerFinancialFundsDirect(reportVO.getNonPeerFinancialFundsDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setNonPeerFinancialFundsIndirect(reportVO.getNonPeerFinancialFundsIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setNonPeerFinancialFunds(reportVO.getNonPeerFinancialFunds().add(allocationQuery.getAmount()));
                break;
            case "4":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setEducationalExpensesDirect(reportVO.getEducationalExpensesDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setEducationalExpensesIndirect(reportVO.getEducationalExpensesIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setEducationalExpenses(reportVO.getEducationalExpenses().add(allocationQuery.getAmount()));
                break;
            case "5":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setAssetDisposalFeesDirect(reportVO.getAssetDisposalFeesDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setAssetDisposalFeesIndirect(reportVO.getAssetDisposalFeesIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setAssetDisposalFees(reportVO.getAssetDisposalFees().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }

        // 不是医院全成本的都是医疗全成本
        if (!NumberConstant.THREE_S.equals(costType.getExpandOne())) {
            if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                reportVO.setMedicalTotalCostDirect(reportVO.getMedicalTotalCostDirect().add(allocationQuery.getAmount()));
            } else {
                reportVO.setMedicalTotalCostIndirect(reportVO.getMedicalTotalCostIndirect().add(allocationQuery.getAmount()));
            }
            reportVO.setMedicalTotalCost(reportVO.getMedicalTotalCost().add(allocationQuery.getAmount()));
        }

        // 医院全成本合计
        if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
            reportVO.setHospitalTotalCostDirect(reportVO.getHospitalTotalCostDirect().add(allocationQuery.getAmount()));
        } else {
            reportVO.setHospitalTotalCostIndirect(reportVO.getHospitalTotalCostIndirect().add(allocationQuery.getAmount()));
        }
        reportVO.setHospitalTotalCost(reportVO.getHospitalTotalCost().add(allocationQuery.getAmount()));
    }

    /**
     * 添加科室成本明细
     * @param reportMap 
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addDeptCostDetailVO(Map<String, ClinicalDeptMedicalCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        ClinicalDeptMedicalCostVO reportVO = new ClinicalDeptMedicalCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            //生成科室成本报表信息
            initDeptCostReport(reportVO, responsibility, accountType, costType, standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
            reportMap.put(allocationQuery.getResponsibilityCode(), reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (accountType.getExpandOne())  {
            case "1":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setPersonnelDirectCost(reportVO.getPersonnelDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setPersonnelIndirectCost(reportVO.getPersonnelIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setPersonnelTotalCost(reportVO.getPersonnelTotalCost().add(allocationQuery.getAmount()));
                break;
            case "2":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setHealthMaterialDirectCost(reportVO.getHealthMaterialDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setHealthMaterialIndirectCost(reportVO.getHealthMaterialIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setHealthMaterialTotalCost(reportVO.getHealthMaterialTotalCost().add(allocationQuery.getAmount()));
                break;
            case "3":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setMedicineDirectCost(reportVO.getMedicineDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setMedicineIndirectCost(reportVO.getMedicineIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicineTotalCost(reportVO.getMedicineTotalCost().add(allocationQuery.getAmount()));
                break;
            case "4":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setFixedAssetDepreciationDirectCost(reportVO.getFixedAssetDepreciationDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setFixedAssetDepreciationIndirectCost(reportVO.getFixedAssetDepreciationIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setFixedAssetDepreciationTotalCost(reportVO.getFixedAssetDepreciationTotalCost().add(allocationQuery.getAmount()));
                break;
            case "5":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setIntangibleAssetAmortizationDirectCost(reportVO.getIntangibleAssetAmortizationDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setIntangibleAssetAmortizationIndirectCost(reportVO.getIntangibleAssetAmortizationIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setIntangibleAssetAmortizationTotalCost(reportVO.getIntangibleAssetAmortizationTotalCost().add(allocationQuery.getAmount()));
                break;
            case "6":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setMedicalRiskReserveDirectCost(reportVO.getMedicalRiskReserveDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setMedicalRiskReserveIndirectCost(reportVO.getMedicalRiskReserveIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicalRiskReserveTotalCost(reportVO.getMedicalRiskReserveTotalCost().add(allocationQuery.getAmount()));
                break;
            case "7":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setOtherMedicalExpensesDirectCost(reportVO.getOtherMedicalExpensesDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setOtherMedicalExpensesIndirectCost(reportVO.getOtherMedicalExpensesIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setOtherMedicalExpensesTotalCost(reportVO.getOtherMedicalExpensesTotalCost().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }
        //添加合计
        if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
            reportVO.setTotalDirectCost(reportVO.getTotalDirectCost().add(allocationQuery.getAmount()));
        }else{
            reportVO.setTotalIndirectCost(reportVO.getTotalIndirectCost().add(allocationQuery.getAmount()));
        }
        reportVO.setTotalCost(reportVO.getTotalCost().add(allocationQuery.getAmount()));
    }


    /**
     * 生成科室成本报表信息
     * @param reportVO
     * @param responsibility
     * @param accountType
     * @param costType
     * @param standardShareLevel
     */
    private void initDeptCostReport(BaseDeptCostReportVO reportVO,
                                    Responsibility responsibility,
                                    DictDataVo accountType,
                                    DictDataVo costType,
                                    DictDataVo standardShareLevel) {
        reportVO.setStandardShareLevel(responsibility.getStandardShareLevel());
        reportVO.setResponsibilityName(responsibility.getResponsibilityName());
        reportVO.setResponsibilityCode(responsibility.getResponsibilityCode());
        reportVO.setResponsibilitySort(responsibility.getSort());
        reportVO.setCostType(costType.getCode());
        reportVO.setStandCostType(costType.getExpandOne());
        reportVO.setAccountType(accountType.getCode());
        reportVO.setStandAccountType(accountType.getExpandOne());
        reportVO.setShareLevelSort(standardShareLevel.getSort());
    }

    /**
     * 获取所有的标准字典数据并转换所有需要的映射数据
     * @return 包含所有映射数据的DTO对象
     */
    private StandCostDictMapVO getStandCostDictMaps() {
        StandCostDictMapVO dataMaps = new StandCostDictMapVO();
        List<Responsibility> responsibilityList = responsibilityRepository.getList(UserContext.getCurrentLoginHospId());
        DictDataVo accountingTypeDict = centerService.getDict(Constant.ACCOUNTING_TYPE);
        DictDataVo costTypeDict = centerService.getDict(Constant.STANDARD_COST_CATEGORIES);
        DictDataVo standardShareLevelDict = centerService.getDict(Constant.STANDARD_SHARE_LEVEL);
        List<Accounting> allCostAccounting = accountingRepository.getAllCostAccounting();

        // 添加 null 检查
        if (responsibilityList == null) {
            responsibilityList = new ArrayList<>();
        }
        if (allCostAccounting == null) {
            allCostAccounting = new ArrayList<>();
        }

        // 创建一个映射，用于快速查找责任中心的科室类型，过滤掉 null 对象，过滤掉 responsibilityCode 为 null 的对象
        Map<String, Responsibility> responsibilityMap = responsibilityList.stream()
                .filter(Objects::nonNull)
                .filter(r -> r.getResponsibilityCode() != null)
                .collect(Collectors.toMap(Responsibility::getResponsibilityCode, o -> o));

        // 创建一个映射，用于快速查找会计科目的类型，过滤掉 null 对象，过滤掉 accountingCode 为 null 的对象
        Map<String, Accounting> accountingMap = allCostAccounting.stream()
                .filter(Objects::nonNull)
                .filter(a -> a.getAccountingCode() != null)
                .collect(Collectors.toMap(Accounting::getAccountingCode, o -> o));

        // 添加 null 检查并创建映射
        List<DictDataVo> accountingTypeDictList = (accountingTypeDict != null && accountingTypeDict.getDataVoList() != null)
                ? accountingTypeDict.getDataVoList() : new ArrayList<>();

        List<DictDataVo> costTypeDictList = (costTypeDict != null && costTypeDict.getDataVoList() != null)
                ? costTypeDict.getDataVoList() : new ArrayList<>();

        List<DictDataVo> standardShareLevelDictList = (standardShareLevelDict != null && standardShareLevelDict.getDataVoList() != null)
                ? standardShareLevelDict.getDataVoList() : new ArrayList<>();

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> accountingTypeMap = accountingTypeDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> costTypeMap = costTypeDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> standardShareLevelMap = standardShareLevelDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        dataMaps.setResponsibilityDict(responsibilityList);
        dataMaps.setCostAccountingDict(allCostAccounting);
        dataMaps.setCostTypeDict(costTypeDictList);
        dataMaps.setAccountingTypeDict(accountingTypeDictList);
        dataMaps.setStandardShareLevelDict(standardShareLevelDictList);
        dataMaps.setAccountingMap(accountingMap);
        dataMaps.setCostTypeMap(costTypeMap);
        dataMaps.setResponsibilityMap(responsibilityMap);
        dataMaps.setStandardShareLevelMap(standardShareLevelMap);
        dataMaps.setAccountingTypeMap(accountingTypeMap);
        return dataMaps;
    }


    /**
     *  转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
     * @param allocationQuery
     * @param standCostDictMaps
     * @return
     */
    public void addDeptDirectMedicalCostVO(Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap,
                                           AllocationQuery allocationQuery,
                                           StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }
        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }
        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
        //只处理医疗成本
        if(!NumberConstant.ONE_S.equals(costType.getExpandOne()) ){
            return;
        }
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());
        DeptDirectMedicalCostVO deptDirectMedicalCostVO= new DeptDirectMedicalCostVO();
        if(deptDirectMedicalCostMap.containsKey(responsibility.getResponsibilityCode())){
            deptDirectMedicalCostVO=deptDirectMedicalCostMap.get(responsibility.getResponsibilityCode());
        }else{
            initDeptCostReport(deptDirectMedicalCostVO, responsibility,accountType, costType,standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(deptDirectMedicalCostVO);
            deptDirectMedicalCostMap.put(responsibility.getResponsibilityCode(),deptDirectMedicalCostVO);
        }
        // 根据费用类型累加到对应字段
        switch (accountType.getExpandOne()) {
            case "1":
                deptDirectMedicalCostVO.setPersonnelExpense(deptDirectMedicalCostVO.getPersonnelExpense().add((allocationQuery.getAmount())));
                break;
            case "2":
                deptDirectMedicalCostVO.setHealthMaterialFee(deptDirectMedicalCostVO.getHealthMaterialFee().add((allocationQuery.getAmount())));
                break;
            case "3":
                deptDirectMedicalCostVO.setDrugFee(deptDirectMedicalCostVO.getDrugFee().add((allocationQuery.getAmount())));
                break;
            case "4":
                deptDirectMedicalCostVO.setFixedAssetDepreciation(deptDirectMedicalCostVO.getFixedAssetDepreciation().add((allocationQuery.getAmount())));
                break;
            case "5":
                deptDirectMedicalCostVO.setIntangibleAssetAmortization(deptDirectMedicalCostVO.getIntangibleAssetAmortization().add((allocationQuery.getAmount())));
                break;
            case "6":
                deptDirectMedicalCostVO.setMedicalRiskFundExtraction(deptDirectMedicalCostVO.getMedicalRiskFundExtraction().add((allocationQuery.getAmount())));
                break;
            case "7":
                deptDirectMedicalCostVO.setOtherMedicalExpenses(deptDirectMedicalCostVO.getOtherMedicalExpenses().add((allocationQuery.getAmount())));
                break;
            default:
                break;
        }
        // 更新总计
        deptDirectMedicalCostVO.setTotal(deptDirectMedicalCostVO.getTotal().add(allocationQuery.getAmount()));
    }



    /**
     * 转换为DeptDirectAllCostVO（一个责任中心只一条记录）
     * @param reportMap
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addDeptDirectAllCostVO(Map<String, DeptFullDirectCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }
        
        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }
        
        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(String.valueOf(account.getCostType()));
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        DeptFullDirectCostVO reportVO = new DeptFullDirectCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            initDeptCostReport(reportVO, responsibility,accountType, costType,standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
            reportMap.put(allocationQuery.getResponsibilityCode(),reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (costType.getValue()) {
            case "1":
                reportVO.setMedicalCostTotal(reportVO.getMedicalCostTotal().add(allocationQuery.getAmount()));
                break;
            case "2":
                reportVO.setFinancialProjectFunds(reportVO.getFinancialProjectFunds().add(allocationQuery.getAmount()));
                break;
            case "3":
                reportVO.setNonPeerFinancialFunds(reportVO.getNonPeerFinancialFunds().add(allocationQuery.getAmount()));
                break;
            case "4":
                reportVO.setEducationalExpenses(reportVO.getEducationalExpenses().add(allocationQuery.getAmount()));
                break;
            case "5":
                reportVO.setAssetDisposalFees(reportVO.getAssetDisposalFees().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }
        //不是医院全成本的都是医疗全成本
        if(!NumberConstant.THREE_S.equals(costType.getExpandOne())){
            // 医疗全成本合计
            reportVO.setMedicalTotalCost(reportVO.getMedicalTotalCost().add(allocationQuery.getAmount()));
        }
        // 医院全成本合计
        reportVO.setHospitalTotalCost(reportVO.getHospitalTotalCost().add(allocationQuery.getAmount()));
    }
    

    /**
     * 合并两个科室成本
     * @param source 源对象
     * @param target 目标对象
     */
    public <T> void addBigDecimalFields(T source, T target) {
        if (source == null || target == null) {
            return;
        }
        Class<?> clazz = target.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.getType().equals(BigDecimal.class)) {
                field.setAccessible(true);
                try {
                    BigDecimal sourceValue = (BigDecimal) field.get(source);
                    BigDecimal targetValue = (BigDecimal) field.get(target);

                    BigDecimal result = (targetValue == null ? BigDecimal.ZERO : targetValue)
                            .add(sourceValue == null ? BigDecimal.ZERO : sourceValue);

                    field.set(target, result);
                } catch (IllegalAccessException e) {
                    log.error("合并科室成本时发生错误", e);
                }
            }
        }
    }


    /**
     * 通用创建小计对象方法
     * @param source 源对象
     * @param totalName 小计名称
     * @param clazz 目标类类型
     * @return 小计对象
     */
    public <T> T createSubtotalVo(T source, String totalName, Class<T> clazz) {
        if (source == null) {
            return null;
        }
        T target = BeanUtil.convertObj(source, clazz);
        // 使用反射设置责任代码和名称
        try {
            clazz.getMethod("setResponsibilityCode", String.class).invoke(target, totalName);
            clazz.getMethod("setResponsibilityName", String.class).invoke(target, totalName);
        } catch (Exception e) {
            log.error("设置责任代码和名称时发生错误", e);
        }
        // 初始化所有费用字段为0
        BeanUtil.initBigDecimalFieldsToZero(target);
        return target;
    }

    // 新增方法，用于设置科室金额
    private void putDepartmentAmount(ClinicalDeptFullCostVO vo, String deptName, BigDecimal amount) {
        try {
            Field field = vo.getClass().getDeclaredField(deptName);
            field.setAccessible(true);
            field.set(vo, amount);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("设置科室金额时发生错误", e);
        }
    }

    /**
     * 获取诊次床日分摊参数代码
     * @return
     */
    public String[] getVisitsBedDaysParamCode(){
        String parameterValue = centerService.getParameterValue(ParameterConstant.VISITS_BED_DAYS_PARAM_CODE);
        if(StringUtils.isEmpty(parameterValue)||Constant.EMPTY_STR.equals(parameterValue)){
            throw new CostException("请配置诊次床日分摊参数代码");
        }
        String[] split = parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE);
        if(!NumberConstant.TWO.equals(split.length)){
            throw new CostException("配置的诊次床日分摊参数代码不正确");
        }
        return split;
    }

    /**
     * 添加医院科室成本分摊数据
     * @param deptCostAllocationMap 科室成本分摊Map
     * @param allocationQuery 分摊查询对象
     * @param standCostDictMaps 标准字典数据
     */
    private void addHospitalDeptCostAllocationVO(Map<String, HospitalDeptCostAllocationVO> deptCostAllocationMap,
                                                 AllocationQuery allocationQuery,
                                                 StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        String sourceResponsibilityCode = allocationQuery.getResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return;
        }

        Responsibility sourceResponsibility = standCostDictMaps.getResponsibilityMap().get(sourceResponsibilityCode);
        if (sourceResponsibility == null) {
            return;
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return;
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return;
        }

        HospitalDeptCostAllocationVO costAllocationVO = new HospitalDeptCostAllocationVO();
        if (deptCostAllocationMap.containsKey(responsibilityCode)) {
            costAllocationVO = deptCostAllocationMap.get(responsibilityCode);
        } else {
            // 初始化VO对象
            costAllocationVO.setResponsibilityName(responsibility.getResponsibilityName());
            costAllocationVO.setResponsibilityCode(responsibility.getResponsibilityCode());
            costAllocationVO.setResponsibilitySort(responsibility.getSort());
            costAllocationVO.setStandardShareLevel(responsibility.getStandardShareLevel());

            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(costAllocationVO);
            deptCostAllocationMap.put(responsibilityCode, costAllocationVO);
        }

        // 直接成本
        if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
            costAllocationVO.setDirectCost(
                    (costAllocationVO.getDirectCost() == null ? BigDecimal.ZERO : costAllocationVO.getDirectCost())
                            .add(allocationQuery.getAmount()));
        }else{
            //如果分摊层级和目标层级一样加到直接成本
            if(sourceResponsibility.getStandardShareLevel().equals(responsibility.getStandardShareLevel())){
                costAllocationVO.setDirectCost(
                        (costAllocationVO.getDirectCost() == null ? BigDecimal.ZERO : costAllocationVO.getDirectCost())
                                .add(allocationQuery.getAmount()));
            }else{
                switch (sourceResponsibility.getStandardShareLevel())
                {
                    case "1":
                        // 行政后勤类科室成本
                        costAllocationVO.setAllocatedAdminCost(
                                (costAllocationVO.getAllocatedAdminCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedAdminCost())
                                        .add(allocationQuery.getAmount()));
                        break;
                    case "2":
                        // 辅助支持类科室成本
                        costAllocationVO.setAllocatedSupportCost(
                                (costAllocationVO.getAllocatedSupportCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedSupportCost())
                                        .add(allocationQuery.getAmount()));
                        break;
                    case "3":
                        // 技术类科室成本
                        costAllocationVO.setAllocatedTechCost(
                                (costAllocationVO.getAllocatedTechCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedTechCost())
                                        .add(allocationQuery.getAmount()));
                        break;
                }
                //小计
                costAllocationVO.setSubtotal(
                        (costAllocationVO.getSubtotal() == null ? BigDecimal.ZERO : costAllocationVO.getSubtotal())
                                .add(allocationQuery.getAmount()));
            }
        }
        // 医疗类科室成本
        costAllocationVO.setMedicalCost(
                (costAllocationVO.getMedicalCost() == null ? BigDecimal.ZERO : costAllocationVO.getMedicalCost())
                        .add(allocationQuery.getAmount()));
        deptCostAllocationMap.put(responsibilityCode, costAllocationVO);
    }


    /**
     * 获取指定分摊参数的数值
     * @param shareParamValues
     * @param paramCode
     * @return
     */
    public BigDecimal getParamValue(List<ShareParamValue> shareParamValues, String paramCode){
        BigDecimal sum = shareParamValues.stream()
                .filter(shareParamValue -> shareParamValue.getShareParamCode().equals(paramCode))
                .map(ShareParamValue::getValueNum)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return sum;
    }

    /**
     * 创建医院诊次成本构成表数据
     * @param costAccountingTypeDict
     * @return
     */
    public Map<String, HospitalVisitCostCompositionVO> createHospitalVisitCostCompositionVO(List<DictDataVo> costAccountingTypeDict) {
        // 初始化成本项目映射
        Map<String, HospitalVisitCostCompositionVO> costItemMap = new HashMap<>();
        for (DictDataVo dictDataVo : costAccountingTypeDict) {
            HospitalVisitCostCompositionVO vo = new HospitalVisitCostCompositionVO();
            vo.setCostCode(dictDataVo.getCode());
            vo.setCostItem(dictDataVo.getName());
            vo.setCostType(dictDataVo.getExpandOne());
            vo.setMedicalCost(BigDecimal.ZERO);
            vo.setMedicalFullCost(BigDecimal.ZERO);
            vo.setHospitalFullCost(BigDecimal.ZERO);
            costItemMap.put(dictDataVo.getCode(), vo);
        }
        return costItemMap;
    }

    @Override
    public Object getDiseaseCostDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter) {
        // 获取完整数据列表
        List<DiseaseCostDetailVO> fullList;
        if (StringUtils.isEmpty(diseaseFilter)) {
            fullList = getDiseaseCostDetail(computeDate);
        } else {
            fullList = getDiseaseCostDetail(computeDate, diseaseFilter);
        }
        
        // 手动分页
        int total = fullList.size();
        int startIndex = (current - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, total);
        
        // 获取当前页数据
        List<DiseaseCostDetailVO> pageList = new ArrayList<>();
        if (startIndex < total) {
            pageList = fullList.subList(startIndex, endIndex);
        }
        
        return new PageUtils(pageList, total, pageSize, current);
    }

    @Override
    public Object getDiseaseCostCompositionDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter) {
        // 获取完整数据列表
        List<DiseaseCostDetailVO> fullList ;
        if (StringUtils.isEmpty(diseaseFilter)) {
            fullList = getDiseaseCostCompositionDetail(computeDate);
        } else {
            fullList = getDiseaseCostCompositionDetail(computeDate,diseaseFilter);
        }
        // 手动分页
        int total = fullList.size();
        int startIndex = (current - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, total);
        
        // 获取当前页数据
        List<DiseaseCostDetailVO> pageList = new ArrayList<>();
        if (startIndex < total) {
            pageList = fullList.subList(startIndex, endIndex);
        }
        
        return new PageUtils(pageList, total, pageSize, current);
    }

    @Override
    public Object getDeptDiseaseCostCompositionDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter) {
        // 获取完整数据
        StandardDeptCostCollectResponse fullData ;
        if (StringUtils.isEmpty(diseaseFilter)) {
            fullData = getDeptDiseaseCostCompositionDetail(computeDate);
        } else {
            fullData = getDeptDiseaseCostCompositionDetail(computeDate,diseaseFilter);
        }
        // 对数据进行分页
        List<StandardReportFormCustomVo> fullList = fullData.getData();
        int total = fullList.size();
        int startIndex = (current - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, total);
        
        // 获取当前页数据
        List<StandardReportFormCustomVo> pageList = new ArrayList<>();
        if (startIndex < total) {
            pageList = fullList.subList(startIndex, endIndex);
        }
        
        // 构造分页结果
        StandardDeptCostCollectResponse pageData = new StandardDeptCostCollectResponse();
        pageData.setTitle(fullData.getTitle());
        pageData.setData(pageList);
        pageData.setCurrent(current);
        pageData.setPageSize(pageSize);
        pageData.setTotalCount( total);
        pageData.setTotalPage((int)Math.ceil((double)total/pageSize));
        return pageData;
    }


}