64 Komitmen accfa93483 ... 622c9fcd65

Pembuat SHA1 Pesan Tanggal
  wangyongsheng 622c9fcd65 Merge branch 'jiangyongmin' of http://47.97.198.219:3000/wangyongsheng/kcim-cost into master_cloud 4 hari lalu
  wangyongsheng 7ab966064a 字典路由调整 4 hari lalu
  JammeyJiang de37ee13fc 临床服务类科室全成本构成分析表d的收入及诊次/床日成本计算不正确的问题修复 2 minggu lalu
  JammeyJiang 7d927bda78 医院科室直接成本表只显示人员经费的问题处理 2 minggu lalu
  JammeyJiang eb0e12e76f 病种报表的三个分页接口添加检索字段 3 minggu lalu
  JammeyJiang 4b1067f490 病种报表的三个分页接口添加检索字段 3 minggu lalu
  JammeyJiang 234cc301bc 添加病种报表的三个分页接口 3 minggu lalu
  JammeyJiang 853d551a7b 调整病种成本相关三个标准报表的数据生成逻辑 1 bulan lalu
  JammeyJiang 8c9f22375b 优化项目成本分摊计算逻辑 1 bulan lalu
  JammeyJiang 8895843cba 调整科室损益的会计科目金额计算逻辑 1 bulan lalu
  JammeyJiang cd0488031c 添加动态列数据类型及是否固定的字段返回 1 bulan lalu
  JammeyJiang 7d78c39ba6 按会计科目分摊时的分摊及损益计算逻辑的批量保存优化 1 bulan lalu
  JammeyJiang c00def9e81 优化分摊计算的逻辑 1 bulan lalu
  JammeyJiang 3fee003b1e 添加按会计科目计算科室损益报表数据 1 bulan lalu
  JammeyJiang 0d2b461fcb 标准成本报表-DRG报表/病种报表接口添加 2 bulan lalu
  JammeyJiang 59dbe88805 科室标准报表和诊次/床日标准报表接口添加 2 bulan lalu
  JammeyJiang 1b555a4f34 获取患者收费项目-患者列表添加分页入参 2 bulan lalu
  JammeyJiang e2864c28aa 获取患者收费项目-患者列表添加分页入参 2 bulan lalu
  JammeyJiang aec206a0f6 添加公式对应的报表列数据为空的情况处理 2 bulan lalu
  JammeyJiang a5f118d3a6 调整配置 2 bulan lalu
  JammeyJiang d447ad8f94 添加三个DRG成本明细表相关代码 2 bulan lalu
  JammeyJiang 5ad11f5e67 添加医院服务单元病种成本构成明细表相关代码 2 bulan lalu
  JammeyJiang 6f1605fa49 添加医院病种成本明细表相关代码 2 bulan lalu
  JammeyJiang 601638aa91 添加医院服务项目成本明细表相关代码 2 bulan lalu
  JammeyJiang b8960d4030 添加医院医疗服务项目成本汇总表相关代码 2 bulan lalu
  JammeyJiang c4fffe8fb5 添加医院科室床日成本表相关代码 3 bulan lalu
  JammeyJiang cb20b42a6c 添加医院科室诊次成本表相关代码 3 bulan lalu
  JammeyJiang 1b27380249 添加医院诊次成本构成表相关代码 3 bulan lalu
  JammeyJiang cb9644df7e 添加医院科室成本分摊汇总表相关代码 3 bulan lalu
  JammeyJiang b24f3bbe9c 添加医院临床服务类科室全成本构成分析表相关代码 3 bulan lalu
  JammeyJiang 1c743eee4a 添加临床科室医疗成本表(全成本)相关代码 3 bulan lalu
  JammeyJiang a819a1b6b1 添加临床科室医疗成本表相关代码 3 bulan lalu
  JammeyJiang 65ed2d7ac3 添加临床科室医疗成本表相关代码 3 bulan lalu
  JammeyJiang 10a49b767c 添加标准报表-科室直接成本相关代码 3 bulan lalu
  JammeyJiang 94da3e696b 添加多月份的全院其他收支的填充逻辑 3 bulan lalu
  JammeyJiang b329e50929 PFM知识库导入的异常处理 3 bulan lalu
  JammeyJiang 7237bd6b41 合并科室损益和全院损益计算的报表类型参数 3 bulan lalu
  JammeyJiang a2716f4c3a 添加按年月排序 3 bulan lalu
  JammeyJiang aa70eb8cda 添加是否月累计及审计月的标志控制 3 bulan lalu
  JammeyJiang 8fe0fc24e8 添加参数控制哪些损益报表需要用脚本计算 3 bulan lalu
  JammeyJiang 2667250bb7 添加是否允许下钻字段出参 3 bulan lalu
  JammeyJiang 7778ec45fd 添加全院损益多月份查询接口功能 3 bulan lalu
  JammeyJiang 5264281e02 添加多月份全院损益数据查询接口代码 4 bulan lalu
  JammeyJiang e8b8f80ab2 全院损益计算添加同环比计算 4 bulan lalu
  JammeyJiang c271558d6d 同环比改成同环比增长率 4 bulan lalu
  JammeyJiang 2008351c9d 1、添加月累计的数值计算及样式组装 2、多sheet页导入无法关闭文件流的问题处理 4 bulan lalu
  JammeyJiang 43f77f8eb0 科室损益计算添加同环比计算逻辑 4 bulan lalu
  JammeyJiang 689703e16c 科室损益计算添加同环比计算逻辑 4 bulan lalu
  JammeyJiang a8f8ce540e 调整分摊算法的事务控制 4 bulan lalu
  JammeyJiang ada478edc7 按会计科目分摊逻辑添加责任中心并行分摊逻辑 4 bulan lalu
  JammeyJiang 47ac9b7778 添加一个Excel的多个sheet页导入功能 4 bulan lalu
  JammeyJiang bb04d4185d 添加一个Excel的多个sheet页导入功能 4 bulan lalu
  JammeyJiang 8d6ae26f61 添加获取年度科室损益数据相关接口 4 bulan lalu
  JammeyJiang 1f0277af43 添加获取年度科室损益数据相关接口 4 bulan lalu
  wangyongsheng dacb779bdc 1添加cid 与usrId 绑定功能 6 bulan lalu
  JammeyJiang e949206868 添加科室损益计算-报表数据不显示占比时的金额层处理 6 bulan lalu
  JammeyJiang 2ec0b3c624 添加损益报表的数据格式控制 6 bulan lalu
  JammeyJiang d63c6835b9 添加指定目标责任中心分摊的相关功能 7 bulan lalu
  JammeyJiang 32e94bb1c1 添加按会计科目分摊相关代码 7 bulan lalu
  JammeyJiang 041d1fb5d7 添加按会计科目相关代码 7 bulan lalu
  JammeyJiang 8762a2f3a2 添加分摊设置改成主从形式相关代码 7 bulan lalu
  JammeyJiang 1076c5c799 添加参数控制项目成本计算流程的计算方式 8 bulan lalu
  JammeyJiang 1dd3df452d 调整作废上次项目成本计算记录的时机 8 bulan lalu
  JammeyJiang 50e5eea39e 添加参数控制是否开启全院通用项目的项目成本计算功能 9 bulan lalu
100 mengubah file dengan 9102 tambahan dan 305 penghapusan
  1. 6 0
      Dockerfile
  2. 10 0
      pom.xml
  3. 28 0
      src/main/java/com/kcim/common/config/AsyncConfig.java
  4. 5 0
      src/main/java/com/kcim/common/constants/CommonConstant.java
  5. 4 0
      src/main/java/com/kcim/common/constants/Constant.java
  6. 28 0
      src/main/java/com/kcim/common/constants/ParameterConstant.java
  7. 133 0
      src/main/java/com/kcim/common/constants/SplitConstant.java
  8. 31 1
      src/main/java/com/kcim/common/util/BeanUtil.java
  9. 33 0
      src/main/java/com/kcim/common/util/PageUtils.java
  10. 6 3
      src/main/java/com/kcim/dao/mapper/AllocationMapper.java
  11. 27 2
      src/main/java/com/kcim/dao/mapper/AllocationQueryMapper.java
  12. 129 0
      src/main/java/com/kcim/dao/mapper/BatchInsertProvider.java
  13. 71 0
      src/main/java/com/kcim/dao/mapper/ComputePatientCostAccountMapper.java
  14. 25 0
      src/main/java/com/kcim/dao/mapper/ComputeProjectCostAccountMapper.java
  15. 1 1
      src/main/java/com/kcim/dao/mapper/ComputeProjectCostDetailMapper.java
  16. 1 2
      src/main/java/com/kcim/dao/mapper/ComputeProjectGroupCostDetailMapper.java
  17. 16 0
      src/main/java/com/kcim/dao/mapper/CostAccountShareDetailMapper.java
  18. 16 0
      src/main/java/com/kcim/dao/mapper/CostAccountShareParamMapper.java
  19. 16 0
      src/main/java/com/kcim/dao/mapper/CostAccountShareTargetMapper.java
  20. 16 0
      src/main/java/com/kcim/dao/mapper/CostDepartmentProfitAccountMapper.java
  21. 16 2
      src/main/java/com/kcim/dao/mapper/CostDepartmentProfitMapper.java
  22. 11 4
      src/main/java/com/kcim/dao/mapper/CostIncomeGroupMapper.java
  23. 24 0
      src/main/java/com/kcim/dao/mapper/GenericBatchMapper.java
  24. 1 1
      src/main/java/com/kcim/dao/mapper/ImportPatientItemMapper.java
  25. 2 0
      src/main/java/com/kcim/dao/mapper/IncomeCollectionMapper.java
  26. 10 2
      src/main/java/com/kcim/dao/mapper/ItemMapper.java
  27. 14 5
      src/main/java/com/kcim/dao/model/Allocation.java
  28. 13 5
      src/main/java/com/kcim/dao/model/AllocationQuery.java
  29. 91 0
      src/main/java/com/kcim/dao/model/ComputePatientCostAccount.java
  30. 18 0
      src/main/java/com/kcim/dao/model/ComputeProjectCost.java
  31. 104 0
      src/main/java/com/kcim/dao/model/ComputeProjectCostAccount.java
  32. 74 0
      src/main/java/com/kcim/dao/model/CostAccountShareDetail.java
  33. 85 0
      src/main/java/com/kcim/dao/model/CostAccountShareParam.java
  34. 74 0
      src/main/java/com/kcim/dao/model/CostAccountShareTarget.java
  35. 37 0
      src/main/java/com/kcim/dao/model/CostDepartmentProfit.java
  36. 87 0
      src/main/java/com/kcim/dao/model/CostDepartmentProfitAccount.java
  37. 30 0
      src/main/java/com/kcim/dao/model/HospProfitAndLoss.java
  38. 6 0
      src/main/java/com/kcim/dao/model/Item.java
  39. 22 0
      src/main/java/com/kcim/dao/model/ReportForm.java
  40. 2 1
      src/main/java/com/kcim/dao/model/Responsibility.java
  41. 15 6
      src/main/java/com/kcim/dao/model/StandItem.java
  42. 47 0
      src/main/java/com/kcim/dao/model/dto/ParamContainerDTO.java
  43. 18 0
      src/main/java/com/kcim/dao/model/dto/ReportFormEditDTO.java
  44. 18 0
      src/main/java/com/kcim/dao/model/dto/ReportFormSaveDTO.java
  45. 7 0
      src/main/java/com/kcim/dao/repository/AccountingRepository.java
  46. 3 4
      src/main/java/com/kcim/dao/repository/ComputeLastProfitDateRepository.java
  47. 51 0
      src/main/java/com/kcim/dao/repository/ComputePatientCostAccountRepository.java
  48. 45 0
      src/main/java/com/kcim/dao/repository/ComputeProjectCostAccountRepository.java
  49. 2 1
      src/main/java/com/kcim/dao/repository/ComputeProjectCostDetailRepository.java
  50. 2 3
      src/main/java/com/kcim/dao/repository/ComputeProjectGroupCostDetailRepository.java
  51. 78 0
      src/main/java/com/kcim/dao/repository/CostAccountShareDetailRepository.java
  52. 77 0
      src/main/java/com/kcim/dao/repository/CostAccountShareParamRepository.java
  53. 77 0
      src/main/java/com/kcim/dao/repository/CostAccountShareTargetRepository.java
  54. 50 0
      src/main/java/com/kcim/dao/repository/CostDepartmentProfitAccountRepository.java
  55. 10 2
      src/main/java/com/kcim/dao/repository/ImportPatientItemRepository.java
  56. 8 0
      src/main/java/com/kcim/dao/repository/ItemRepository.java
  57. 7 0
      src/main/java/com/kcim/service/AllocationQueryService.java
  58. 7 0
      src/main/java/com/kcim/service/CenterService.java
  59. 15 0
      src/main/java/com/kcim/service/CostAccountShareDetailService.java
  60. 15 0
      src/main/java/com/kcim/service/CostAccountShareParamService.java
  61. 15 0
      src/main/java/com/kcim/service/CostAccountShareService.java
  62. 15 0
      src/main/java/com/kcim/service/CostAccountShareTargetService.java
  63. 2 0
      src/main/java/com/kcim/service/CostDepartmentProfitService.java
  64. 2 0
      src/main/java/com/kcim/service/HospProfitAndLossService.java
  65. 2 0
      src/main/java/com/kcim/service/IncomeCollectionService.java
  66. 11 0
      src/main/java/com/kcim/service/KpiComputeImportService.java
  67. 1 1
      src/main/java/com/kcim/service/PatientItemImportService.java
  68. 161 0
      src/main/java/com/kcim/service/StandardReportService.java
  69. 43 5
      src/main/java/com/kcim/service/impl/AllocationQueryServiceImpl.java
  70. 721 30
      src/main/java/com/kcim/service/impl/AllocationServiceImpl.java
  71. 78 0
      src/main/java/com/kcim/service/impl/BaseBatchServiceImpl.java
  72. 27 1
      src/main/java/com/kcim/service/impl/CenterServiceImpl.java
  73. 12 0
      src/main/java/com/kcim/service/impl/ComputeMedicalDepartmentProfitServiceImpl.java
  74. 14 0
      src/main/java/com/kcim/service/impl/CostAccountShareDetailServiceImpl.java
  75. 14 0
      src/main/java/com/kcim/service/impl/CostAccountShareParamServiceImpl.java
  76. 258 11
      src/main/java/com/kcim/service/impl/CostAccountShareServiceImpl.java
  77. 15 0
      src/main/java/com/kcim/service/impl/CostAccountShareTargetService.java
  78. 4 2
      src/main/java/com/kcim/service/impl/CostCostingGroupServiceImpl.java
  79. 1365 50
      src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java
  80. 30 6
      src/main/java/com/kcim/service/impl/CostIncomeGroupServiceImpl.java
  81. 641 18
      src/main/java/com/kcim/service/impl/HospProfitAndLossServiceImpl.java
  82. 5 0
      src/main/java/com/kcim/service/impl/IncomeCollectionServiceImpl.java
  83. 228 9
      src/main/java/com/kcim/service/impl/KpiComputeImportServiceImpl.java
  84. 7 5
      src/main/java/com/kcim/service/impl/PatientItemImportServiceImpl.java
  85. 305 114
      src/main/java/com/kcim/service/impl/ProjectCostServiceImpl.java
  86. 7 0
      src/main/java/com/kcim/service/impl/ReportFormServiceImpl.java
  87. 3 0
      src/main/java/com/kcim/service/impl/ReportServiceImpl.java
  88. 28 8
      src/main/java/com/kcim/service/impl/ShareParamServiceImpl.java
  89. 2478 0
      src/main/java/com/kcim/service/impl/StandardReportServiceImpl.java
  90. 14 0
      src/main/java/com/kcim/vo/AllocationQueryReportVO.java
  91. 60 0
      src/main/java/com/kcim/vo/BaseDeptCostReportVO.java
  92. 118 0
      src/main/java/com/kcim/vo/ClinicalDeptFullCostVO.java
  93. 133 0
      src/main/java/com/kcim/vo/ClinicalDeptMedicalCostVO.java
  94. 26 0
      src/main/java/com/kcim/vo/CommonResponsibilityReportVo.java
  95. 14 0
      src/main/java/com/kcim/vo/CommonTitleReportVo.java
  96. 7 0
      src/main/java/com/kcim/vo/CostDepartmentProfitVO.java
  97. 45 0
      src/main/java/com/kcim/vo/CostProfitVo.java
  98. 74 0
      src/main/java/com/kcim/vo/DeptDirectMedicalCostVO.java
  99. 47 0
      src/main/java/com/kcim/vo/DeptFullDirectCostVO.java
  100. 197 0
      src/main/java/com/kcim/vo/DiseaseCostDetailVO.java

+ 6 - 0
Dockerfile

@@ -0,0 +1,6 @@
+FROM openjdk:8-jdk-alpine
+LABEL authors="KCIM"
+RUN  ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+COPY ./target/kcim-cost-0.0.1-SNAPSHOT.jar ./data/app/kcim-cost-0.0.1-SNAPSHOT.jar
+EXPOSE 8083
+ENTRYPOINT ["java","-jar","./data/app/kcim-cost-0.0.1-SNAPSHOT.jar"]

+ 10 - 0
pom.xml

@@ -20,6 +20,7 @@
         <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
         <fastjson2.version>2.0.23</fastjson2.version>
         <nacos.version>2.2.8.RELEASE</nacos.version>
+        <spring-cloud-alibaba.version>2.2.8.RELEASE</spring-cloud-alibaba.version>
         <openfeign.version>2.2.9.RELEASE</openfeign.version>
         <saToken.version>1.31.0</saToken.version>
         <easypoi.version>4.3.0</easypoi.version>
@@ -335,6 +336,15 @@
             <artifactId>metastore</artifactId>
             <version>8.3.0.0-371</version>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+            <version>${spring-cloud-alibaba.version}</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 28 - 0
src/main/java/com/kcim/common/config/AsyncConfig.java

@@ -0,0 +1,28 @@
+package com.kcim.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2025-07-04 19:15
+ **/
+
+@Configuration
+public class AsyncConfig {
+    @Bean("asyncTaskExecutor")
+    public Executor asyncTaskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(10);
+        executor.setMaxPoolSize(20);
+        executor.setQueueCapacity(50);
+        executor.setThreadNamePrefix("Async-");
+        executor.initialize();
+        return executor;
+    }
+}

+ 5 - 0
src/main/java/com/kcim/common/constants/CommonConstant.java

@@ -91,6 +91,11 @@ public final class CommonConstant {
      */
     public static final String SEPARATOR_BlankSpace = " ";
 
+    /**
+     * 分割符-竖杆
+     */
+    public static final String SEPARATOR_VERTICAL = "\\|";
+
 
     /**
      * 常量A

+ 4 - 0
src/main/java/com/kcim/common/constants/Constant.java

@@ -191,6 +191,10 @@ public interface Constant {
      * 会计科目类别
      */
     String ACCOUNTING_TYPE = "ACCOUNTING_TYPE";
+    /**
+     * 标准成本类别
+     */
+    String STANDARD_COST_CATEGORIES = "STANDARD_COST_CATEGORIES";
     /**
      * 标准分摊层级
      */

+ 28 - 0
src/main/java/com/kcim/common/constants/ParameterConstant.java

@@ -37,5 +37,33 @@ public interface ParameterConstant {
      */
     Long USER_REPORT_AUTHOR_ABLE = 1862419414851391488L;
 
+    /**
+     * 项目成本计算是否启用全院通用项目计算功能
+     */
+    Long USER_HOSP_ITEM_CALC=1889925898824716288L;
+
+    /**
+     * 项目成本计算方式
+     */
+    Long ITEM_CALC_TYPE=1902923430831984640L;
+
+    /**
+     * 成本分摊计算的分摊方式 1按责任中心分摊 2按会计科目分摊
+     */
+    Long ALLOCATION_TYPE=1907261486460440576L;
 
+    /**
+     * 科室及全院损益及对应的报表界面是否显示占比字段 0否 1是
+     */
+    Long SHOW_PERCENT=1851077044079824896L;
+
+    /**
+     * 需要用脚本计算的科室损益及全院损益报表类型
+     */
+    Long SQL_CALC_REPORT_TYPE =1943243153054240768L;
+
+    /**
+     * 诊次床日分摊参数代码
+     */
+    Long VISITS_BED_DAYS_PARAM_CODE =1955568425220837376L;
 }

+ 133 - 0
src/main/java/com/kcim/common/constants/SplitConstant.java

@@ -0,0 +1,133 @@
+package com.kcim.common.constants;
+
+/**
+* @program: performace
+* @description: 分隔符常量
+* @author: Wang.YS
+* @create: 2023-01-08 21:55
+**/
+
+public interface SplitConstant {
+    /**
+     * 分割符-分号(半角)
+     */
+     String SEPARATOR_SEMICOLON = ";";
+
+    /**
+     * 分割符-右箭头
+     */
+     String RIGHT_ARROWS = "→";
+
+    /**
+     * 分割符-分号(全角)
+     */
+     String SEPARATOR_SEMICOLON_C = ";";
+
+    /**
+     * 分割符-冒号
+     */
+     String SEPARATOR_NUMBER = ":";
+
+    /**
+     * 分割符-冒号
+     */
+     String SEPARATOR_NUMBER_C = ":";
+
+    /**
+     *  分割符-下划线
+     */
+     String SEPARATOR_UNDERLINE = "_";
+    /**
+     * 分割符-竖线
+     */
+     String SEPARATOR_VERTICALLINE="\\|";
+
+    /**
+     * 分割符-逗号
+     */
+     String SEPARATOR_COMMA = ",";
+
+    /**
+     * 分割符-逗号
+     */
+     String SEPARATOR_COMMA_C = ",";
+
+
+    /**
+     * 分割符-反斜杠
+     */
+     String SEPARATOR_BACKSLASH = "/";
+
+    /**
+     * 分割符-反斜杠
+     */
+     String SEPARATOR_BACKSLASH_C = "、";
+
+    /**
+     * 分割符-横杠
+     */
+     String SEPARATOR_WHIPPTREE = "-";
+
+
+    /**
+     * 分割符-波浪号
+     */
+     String SEPARATOR_WAVE = "~";
+
+    /**
+     * 分割符-分号
+     */
+     String SEPARATOR_POINT = ".";
+
+    /**
+     * 分割符-分号
+     */
+     String SEPARATOR_POINT_C = "。";
+
+    /**
+     * 分割符-空格
+     */
+     String SEPARATOR_BlankSpace = " ";
+
+
+    /**
+     * 常量A
+     */
+     String SEPARATOR_A = "A";
+    /**
+     * 左括号
+     */
+     String LEFT_PARENTHESES = "(";
+    /**
+     * 左括号
+     */
+     String LEFT_PARENTHESES_C = "(";
+    /**
+     * 右括号
+     */
+     String RIGHT_PARENTHESES = ")";
+
+    /**
+     * 右括号
+     */
+     String RIGHT_PARENTHESES_C = ")";
+    /**
+     * 导管表默认时间
+     */
+     String ZERO_POINT = "0001-01-01 00:00:00";
+
+    /**
+     * 分隔符 - 乘号
+     */
+     String MULTIPLICATION_SIGN = "×";
+
+
+    /**
+     * 分隔符 - 加号
+     */
+
+     String MULTIPLICATION_PLUS = "\\+";
+
+     String PERCENT = "%";
+
+}

+ 31 - 1
src/main/java/com/kcim/common/util/BeanUtil.java

@@ -5,6 +5,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.util.CollectionUtils;
 
 import java.lang.reflect.Field;
+import java.math.BigDecimal;
 import java.util.*;
 
 @Slf4j
@@ -111,6 +112,35 @@ public final class BeanUtil {
         return target;
     }
 
+    /**
+     * 将对象中所有BigDecimal类型的字段设置为0
+     *
+     * @param target 目标对象
+     * @param <T>    对象类型
+     * @return 设置后的对象
+     */
+    public static <T> T initBigDecimalFieldsToZero(T target) {
+        if (target == null) {
+            return null;
+        }
+
+        Class<?> clazz = target.getClass();
+        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
+            Field[] fields = clazz.getDeclaredFields();
+            for (Field field : fields) {
+                if (field.getType().equals(BigDecimal.class)) {
+                    field.setAccessible(true);
+                    try {
+                        field.set(target, BigDecimal.ZERO);
+                    } catch (IllegalAccessException e) {
+                        log.error("设置BigDecimal字段默认值异常", e);
+                    }
+                }
+            }
+        }
+        return target;
+    }
+
     private static class CacheFieldMap {
         private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();
 
@@ -147,4 +177,4 @@ public final class BeanUtil {
         BeanUtils.copyProperties(source, result);
         return result;
     }
-}
+}

+ 33 - 0
src/main/java/com/kcim/common/util/PageUtils.java

@@ -205,5 +205,38 @@ public class PageUtils implements Serializable {
 		return list.subList(fromIndex,toIndex);
 	}
 
+	public static <T> List<T> getPageList(List<T> list,int current,int pageSize){
+		if(list ==null){
+			return new ArrayList<>();
+		}
+		if(list.size() == 0){
+			return  list;
+		}
+		if(current ==0){
+			current = 1;
+		}
+		//记录总数
+		int count = list.size();
+		//页数
+		int pageCount = 0;
+		if(count % pageSize==0){
+			pageCount = count / pageSize;
+		}else {
+			pageCount = count / pageSize + 1;
+		}
+		int fromIndex = 0;
+		int toIndex = 0;
+		if(current>pageCount){
+			return new ArrayList<>();
+		}
+		if(current != pageCount){
+			fromIndex = (current - 1)*pageSize;
+			toIndex = fromIndex + pageSize;
+		}else {
+			fromIndex = (current - 1)*pageSize;
+			toIndex = count;
+		}
+		return list.subList(fromIndex,toIndex);
+	}
 
 }

+ 6 - 3
src/main/java/com/kcim/dao/mapper/AllocationMapper.java

@@ -2,8 +2,6 @@ package com.kcim.dao.mapper;
 
 
 import com.kcim.dao.model.Allocation;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.kcim.vo.AfterAllocationVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
@@ -18,7 +16,7 @@ import java.util.List;
  * @date 2021-08-25 08:45:06
  */
 @Mapper
-public interface AllocationMapper extends BaseMapper<Allocation> {
+public interface AllocationMapper extends GenericBatchMapper<Allocation> {
 
     /**
      * 分摊后查询列表
@@ -76,4 +74,9 @@ public interface AllocationMapper extends BaseMapper<Allocation> {
     List<Allocation> getAllSortLevel(@Param("hospId") Long hospId,
                                      @Param("year") int year,
                                      @Param("month") int month);
+
+    List<Allocation> getLevelSortAllocation(@Param("hospId") Long hospId,
+                                     @Param("year") int year,
+                                     @Param("month") int month,
+                                     @Param("shareLevelId") Long shareLevelId);
 }

+ 27 - 2
src/main/java/com/kcim/dao/mapper/AllocationQueryMapper.java

@@ -1,7 +1,6 @@
 package com.kcim.dao.mapper;
 
 import com.kcim.dao.model.AllocationQuery;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.kcim.vo.CodeAndNameVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
@@ -16,7 +15,7 @@ import java.util.List;
  * @date 2021-08-26 08:51:45
  */
 @Mapper
-public interface AllocationQueryMapper extends BaseMapper<AllocationQuery> {
+public interface AllocationQueryMapper extends GenericBatchMapper<AllocationQuery> {
 
     BigDecimal getTotalMoney(@Param("dateYear") int dateYear, @Param("month") int month, @Param("hospId") Long hospId);
 
@@ -30,4 +29,30 @@ public interface AllocationQueryMapper extends BaseMapper<AllocationQuery> {
 
     BigDecimal getTotalByAccountAndRespCode(@Param("hospId") Long hospId, @Param("dateYear") int dateYear, @Param("month") int month, @Param("accountCode") String accountCode, @Param("responsibilityCode") String responsibilityCode);
 
+    /**
+     * 获取医院所有会计科目成本(临床层的)
+     * @param hospId
+     * @param dateYear
+     * @param month
+     * @return
+     */
+    List<AllocationQuery> getAcountAccounts(@Param("hospId") Long hospId, @Param("dateYear") int dateYear, @Param("month") int month);
+
+    /**
+     * 获取医院各责任中心所有会计科目成本
+     * @param hospId
+     * @param dateYear
+     * @param month
+     * @return
+     */
+    List<AllocationQuery> getRespAcountAccounts(@Param("hospId") Long hospId, @Param("dateYear") int dateYear, @Param("month") int month);
+
+    /**
+     * 获取医院各责任中心不同来源类型的会计科目成本
+     * @param hospId
+     * @param dateYear
+     * @param month
+     * @return
+     */
+    List<AllocationQuery> getRespOriginAcountAccounts(@Param("hospId") Long hospId, @Param("dateYear") int dateYear, @Param("month") int month);
 }

+ 129 - 0
src/main/java/com/kcim/dao/mapper/BatchInsertProvider.java

@@ -0,0 +1,129 @@
+package com.kcim.dao.mapper;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.apache.ibatis.annotations.Param;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 动态生成批量插入SQL,通过反射解析实体类注解
+ * 优化生成的SQL语句以提高批量插入性能
+ */
+public class BatchInsertProvider {
+
+    /**
+     * 生成批量插入SQL
+     * @param list 实体列表(必须传入非空列表,否则无法解析表结构)
+     * @param <T> 实体类型
+     * @return 动态生成的SQL语句
+     */
+    public <T> String insertBatch(@Param("list") List<T> list) {
+        // 确保我们有一个标准的ArrayList,以处理SubList等特殊情况
+        List<T> standardList = new ArrayList<>(list);
+        long timeMillis = System.currentTimeMillis();
+        if (standardList.isEmpty()) {
+            throw new IllegalArgumentException("批量插入的列表不能为空");
+        }
+
+        // 获取实体类信息
+        Class<?> entityClass = standardList.get(0).getClass();
+        // 获取表名(优先使用@TableName注解,否则用类名)
+        TableName tableNameAnnotation = entityClass.getAnnotation(TableName.class);
+        String tableName = tableNameAnnotation != null ? tableNameAnnotation.value() : entityClass.getSimpleName();
+
+        // 收集所有需要处理的字段(统一字段列表)
+        List<Field> validFields = new ArrayList<>();
+        Field[] fields = entityClass.getDeclaredFields();
+        boolean haveDelFlag = Arrays.stream(fields).anyMatch(field ->"delFlag".equals(field.getName())|| "del_flag".equals(field.getName()));
+        
+        for (Field field : fields) {
+            // 跳过static和final字段,如serialVersionUID
+            if (java.lang.reflect.Modifier.isStatic(field.getModifiers()) || java.lang.reflect.Modifier.isFinal(field.getModifiers())) {
+                continue;
+            }
+
+            TableField fieldAnnotation = field.getAnnotation(TableField.class);
+            // 跳过非数据库字段
+            if (fieldAnnotation != null && !fieldAnnotation.exist()) {
+                continue;
+            }
+
+            validFields.add(field);
+        }
+
+        // 解析所有数据库字段(基于统一的validFields列表)
+        StringBuilder columns = new StringBuilder();
+        for (Field field : validFields) {
+            // 获取数据库字段名(优先使用@TableField注解,否则用驼峰转下划线)
+            String columnName;
+            TableField fieldAnnotation = field.getAnnotation(TableField.class);
+            if (fieldAnnotation != null && !"".equals(fieldAnnotation.value())) {
+                columnName = fieldAnnotation.value();
+            } else {
+                columnName = camelToUnderline(field.getName());
+            }
+
+            // 为字段名添加反引号,避免MySQL保留字冲突
+            columns.append("`").append(columnName).append("`,");
+        }
+
+        // 移除最后一个逗号
+        if (columns.length() > 0) {
+            columns.setLength(columns.length() - 1);
+        }
+
+        // 生成VALUES部分 - 直接构建适合MyBatis @InsertProvider使用的SQL
+        StringBuilder valueSql = new StringBuilder();
+        valueSql.append("<foreach collection=\"list\" item=\"item\" separator=\",\">");
+        valueSql.append("(");
+        for (Field field : validFields) {
+            String fieldName = field.getName();
+
+            // 特殊字段处理逻辑
+            if ("delFlag".equals(fieldName) && haveDelFlag) {
+                // 当haveDelFlag为true时,设置del_flag=0
+                valueSql.append("0,");
+            } else if ("deleteTime".equals(fieldName) && !haveDelFlag) {
+                // 当haveDelFlag为false时,设置delete_time=0
+                valueSql.append("0,");
+            } else if (("createTime".equals(fieldName) || "updateTime".equals(fieldName))&& !haveDelFlag) {
+                // 无论haveDelFlag如何,create_time和update_time等于timeMillis
+                valueSql.append(timeMillis).append(",");
+            } else {
+                // 使用实体类属性名(MyBatis会自动映射)
+                valueSql.append("#{item.").append(fieldName).append("},");
+            }
+        }
+        // 移除最后一个逗号
+        if (valueSql.charAt(valueSql.length() - 1) == ',') {
+            valueSql.setLength(valueSql.length() - 1);
+        }
+        valueSql.append(")");
+        valueSql.append("</foreach>");
+
+        // 拼接完整SQL - 添加<script>标签确保MyBatis正确解析动态SQL
+        return "<script>INSERT INTO " + tableName + " (" + columns + ") VALUES " + valueSql + "</script>";
+    }
+
+    // 驼峰转下划线(适配数据库命名规范)
+    private String camelToUnderline(String camelCase) {
+        if (camelCase == null || camelCase.isEmpty()) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(Character.toLowerCase(camelCase.charAt(0)));
+        for (int i = 1; i < camelCase.length(); i++) {
+            char c = camelCase.charAt(i);
+            if (Character.isUpperCase(c)) {
+                sb.append("_").append(Character.toLowerCase(c));
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}

+ 71 - 0
src/main/java/com/kcim/dao/mapper/ComputePatientCostAccountMapper.java

@@ -0,0 +1,71 @@
+package com.kcim.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.kcim.dao.model.ComputePatientCostAccount;
+import com.kcim.vo.DiseaseCostDetailVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 患者成本的会计科目金额表
+ * 
+ * @author Wang.YS
+ * @date 2025-08-22 17:57:23
+ */
+@Mapper
+public interface ComputePatientCostAccountMapper extends BaseMapper<ComputePatientCostAccount> {
+
+
+    /**
+     * 获取疾病成本明细
+     * @param computeDate
+     * @param hospId
+     * @param diseaseFilter
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDiseaseCostDetailList(@Param("computeDate") String computeDate, @Param("hospId") Long hospId, String diseaseFilter);
+
+    /**
+     * 获取疾病成本构成明细
+     * @param computeDate
+     * @param hospId
+     * @param diseaseFilter
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(@Param("computeDate") String computeDate, @Param("hospId") Long hospId, String diseaseFilter);
+
+    /**
+     * 获取服务单元疾病成本构成明细
+     * @param computeDate
+     * @param hospId
+     * @param diseaseFilter
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDeptDiseaseCostCompositionDetail(@Param("computeDate") String computeDate, @Param("hospId") Long hospId, String diseaseFilter);
+
+    /**
+     * 获取DRG成本明细
+     * @param computeDate
+     * @param hospId
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDrgCostDetailList(@Param("computeDate") String computeDate, @Param("hospId") Long hospId);
+
+    /**
+     * 获取DRG成本构成明细
+     * @param computeDate
+     * @param hospId
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDrgCostCompositionDetail(@Param("computeDate") String computeDate, @Param("hospId") Long hospId);
+
+    /**
+     * 获取服务单元DRG成本构成明细
+     * @param computeDate
+     * @param hospId
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDeptDrgCostCompositionDetail(@Param("computeDate") String computeDate, @Param("hospId") Long hospId);
+}

+ 25 - 0
src/main/java/com/kcim/dao/mapper/ComputeProjectCostAccountMapper.java

@@ -0,0 +1,25 @@
+package com.kcim.dao.mapper;
+
+import com.kcim.dao.model.ComputeProjectCostAccount;
+import com.kcim.vo.HospitalServiceProjectCostVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 项目成本的会计科目金额表
+ * 
+ * @author Wang.YS
+ * @date 2025-08-22 17:57:23
+ */
+@Mapper
+public interface ComputeProjectCostAccountMapper extends GenericBatchMapper<ComputeProjectCostAccount> {
+
+    /**
+     * @param computeDate
+     * @param hospId
+     * @return
+     */
+    List<HospitalServiceProjectCostVO> getMedicalServiceCostDetailList(@Param("computeDate") String computeDate, @Param("hospId") Long hospId);
+}

+ 1 - 1
src/main/java/com/kcim/dao/mapper/ComputeProjectCostDetailMapper.java

@@ -15,7 +15,7 @@ import java.util.List;
  * @date 2024-01-15 20:23:56
  */
 @Mapper
-public interface ComputeProjectCostDetailMapper extends BaseMapper<ComputeProjectCostDetail> {
+public interface ComputeProjectCostDetailMapper extends GenericBatchMapper<ComputeProjectCostDetail> {
 
     List<ComputeProjectCostPageDto> getByProjectCostId(@Param("computeDate") String computeDate,
                                                        @Param("hospId") Long hospId,

+ 1 - 2
src/main/java/com/kcim/dao/mapper/ComputeProjectGroupCostDetailMapper.java

@@ -1,7 +1,6 @@
 package com.kcim.dao.mapper;
 
 import com.kcim.dao.model.ComputeProjectGroupCostDetail;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 /**
@@ -11,6 +10,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @date 2024-01-19 15:53:57
  */
 @Mapper
-public interface ComputeProjectGroupCostDetailMapper extends BaseMapper<ComputeProjectGroupCostDetail> {
+public interface ComputeProjectGroupCostDetailMapper extends GenericBatchMapper<ComputeProjectGroupCostDetail> {
 	
 }

+ 16 - 0
src/main/java/com/kcim/dao/mapper/CostAccountShareDetailMapper.java

@@ -0,0 +1,16 @@
+package com.kcim.dao.mapper;
+
+import com.kcim.dao.model.CostAccountShareDetail;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 成本分摊对应的会计科目
+ * 
+ * @author Wang.YS
+ * @date 2025-03-28 14:06:13
+ */
+@Mapper
+public interface CostAccountShareDetailMapper extends BaseMapper<CostAccountShareDetail> {
+	
+}

+ 16 - 0
src/main/java/com/kcim/dao/mapper/CostAccountShareParamMapper.java

@@ -0,0 +1,16 @@
+package com.kcim.dao.mapper;
+
+import com.kcim.dao.model.CostAccountShareParam;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 成本分摊对应的分摊参数
+ * 
+ * @author Wang.YS
+ * @date 2025-03-28 14:06:12
+ */
+@Mapper
+public interface CostAccountShareParamMapper extends BaseMapper<CostAccountShareParam> {
+	
+}

+ 16 - 0
src/main/java/com/kcim/dao/mapper/CostAccountShareTargetMapper.java

@@ -0,0 +1,16 @@
+package com.kcim.dao.mapper;
+
+import com.kcim.dao.model.CostAccountShareTarget;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 成本分摊对应的分摊目标责任中心
+ * 
+ * @author Wang.YS
+ * @date 2025-04-03 11:13:36
+ */
+@Mapper
+public interface CostAccountShareTargetMapper extends BaseMapper<CostAccountShareTarget> {
+	
+}

+ 16 - 0
src/main/java/com/kcim/dao/mapper/CostDepartmentProfitAccountMapper.java

@@ -0,0 +1,16 @@
+package com.kcim.dao.mapper;
+
+import com.kcim.dao.model.CostDepartmentProfitAccount;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 科室损益的会计科目金额表
+ * 
+ * @author Wang.YS
+ * @date 2025-09-19 14:14:25
+ */
+@Mapper
+public interface CostDepartmentProfitAccountMapper extends GenericBatchMapper<CostDepartmentProfitAccount> {
+	
+}

+ 16 - 2
src/main/java/com/kcim/dao/mapper/CostDepartmentProfitMapper.java

@@ -1,10 +1,12 @@
 package com.kcim.dao.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.kcim.dao.model.CostDepartmentProfit;
+import com.kcim.vo.CostProfitVo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * 科室损益计算
  * 
@@ -12,10 +14,22 @@ import org.apache.ibatis.annotations.Param;
  * @date 2021-08-24 16:24:08
  */
 @Mapper
-public interface CostDepartmentProfitMapper extends BaseMapper<CostDepartmentProfit> {
+public interface CostDepartmentProfitMapper extends GenericBatchMapper<CostDepartmentProfit> {
 
 
     Integer getMaxYear(@Param("hospId") Long hospId);
 
     Integer getMaxMonth(@Param("hospId") Long hospId, @Param("year") Integer year);
+
+
+    List<CostProfitVo> getAnnualSummaryByYearRange(@Param("startYear") Integer startYear,
+                                                @Param("endYear") Integer endYear,
+                                                @Param("hospId") Long hospId,
+                                                @Param("reportType") Integer reportType,
+                                                @Param("responsibilityCode") String responsibilityCode);
+
+    List<CostProfitVo> getAnnualSummaryByYear(@Param("year") Integer year,
+                                              @Param("hospId") Long hospId,
+                                              @Param("reportType") Integer reportType,
+                                              @Param("responsibilityCode") String responsibilityCode);
 }

+ 11 - 4
src/main/java/com/kcim/dao/mapper/CostIncomeGroupMapper.java

@@ -1,14 +1,13 @@
 package com.kcim.dao.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.kcim.dao.model.CostIncomeGroup;
-import com.kcim.vo.CollectionVO;
-import com.kcim.vo.CommonDepartVo;
-import com.kcim.vo.CostIncomeGroupAllAmountBO;
-import com.kcim.vo.CostIncomeGroupAllAmountVO;
+import com.kcim.vo.*;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -58,4 +57,12 @@ public interface CostIncomeGroupMapper extends BaseMapper<CostIncomeGroup> {
     List<CostIncomeGroup> selectHistoryList(@Param("hospId") Long hospId,@Param("id") Long id);
 
     void reducingHistory(@Param("id") Long id,@Param("hospId") Long hospId,@Param("list") List<Long> list);
+
+    List<CostIncomeGroup>  getOrderDeptProductList(Page<PatientInfoVo> page, @Param("year") Integer year, @Param("month") Integer month, @Param("departmentCode") String departmentCode, @Param("hospId") Long hospId, @Param("filter") String filter);
+
+    List<CostIncomeGroup> getExecDeptProductList(@Param("page") Page<PatientInfoVo> page, @Param("year") Integer year, @Param("month") Integer month, @Param("departmentCode") String departmentCode, @Param("hospId") Long hospId, @Param("filter") String filter);
+
+    BigDecimal getTotalAmount(@Param("year") Integer year, @Param("month") Integer month, @Param("departmentCode") String departmentCode, @Param("hospId") Long hospId);
+
+    BigDecimal getDeptTotalAmount(@Param("year") Integer year, @Param("month") Integer month, @Param("departmentCode") String departmentCode, @Param("hospId") Long hospId);
 }

+ 24 - 0
src/main/java/com/kcim/dao/mapper/GenericBatchMapper.java

@@ -0,0 +1,24 @@
+package com.kcim.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.InsertProvider;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 通用批量插入接口,继承BaseMapper保留原有CRUD功能
+ * @param <T> 实体类泛型
+ */
+public interface GenericBatchMapper<T> extends BaseMapper<T> {
+
+    /**
+     * 通用批量插入方法
+     * @param list 实体列表
+     * @return 插入成功的记录数
+     */
+    @InsertProvider(type = BatchInsertProvider.class, method = "insertBatch")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    int insertBatch(@Param("list") List<T> list);
+}

+ 1 - 1
src/main/java/com/kcim/dao/mapper/ImportPatientItemMapper.java

@@ -27,7 +27,7 @@ public interface ImportPatientItemMapper extends BaseMapper<ImportPatientItem> {
     List<PatientItemVo> getAllGroupByOrder(@Param("computeDate") String computeDate,
                                            @Param("hospId") Long hospId);
 
-    List<PatientInfoVo> getPatientItemPatientInfo(@Param("computeDate") String computeDate,
+    List<PatientInfoVo> getPatientItemPatientInfo(Page<PatientInfoVo> page, @Param("computeDate") String computeDate,
                                                   @Param("filter") String filter,
                                                   @Param("hospId") Long hospId);
 

+ 2 - 0
src/main/java/com/kcim/dao/mapper/IncomeCollectionMapper.java

@@ -63,4 +63,6 @@ public interface IncomeCollectionMapper extends BaseMapper<IncomeCollection> {
 
     BigDecimal getCountByResponsibilitiesAndAccounts(@Param("responsibilityCodes") List<String> responsibilityCodes, @Param("accountingCodes") List<String> accountingCodes, @Param("hospId") Long hospId, @Param("date") String date);
 
+    List<IncomeCollection> getResponsibilitiesAccounts(@Param("year") int year, @Param("month") int month, @Param("hospId") Long hospId);
+
 }

+ 10 - 2
src/main/java/com/kcim/dao/mapper/ItemMapper.java

@@ -1,8 +1,11 @@
 package com.kcim.dao.mapper;
 
-import com.kcim.dao.model.Item;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.kcim.dao.model.Item;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * 收费项目管理
@@ -12,5 +15,10 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface ItemMapper extends BaseMapper<Item> {
-	
+    /**
+     * 获取责任中心的医疗服务项目字典
+     * @param hospId
+     * @return
+     */
+	public List<Item> getRespItemList(@Param("hospId") Long hospId);
 }

+ 14 - 5
src/main/java/com/kcim/dao/model/Allocation.java

@@ -3,16 +3,14 @@ package com.kcim.dao.model;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+
 /**
  * 成本分摊后表
  * 
@@ -94,6 +92,7 @@ public class Allocation implements Serializable {
 	/**
 	 * 分摊参数名称
 	 */
+
 	private String shareParamName;
 	/**
 	 * 分摊参数数值
@@ -112,6 +111,16 @@ public class Allocation implements Serializable {
 
 	private Long targetShareLevelId;
 
+	/**
+	 * 会计科目Code
+	 */
+	private String accountCode;
+
+	/**
+	 * 会计科目名称
+	 */
+	private String accountName;
+
 	/**
 	 * 
 	 */

+ 13 - 5
src/main/java/com/kcim/dao/model/AllocationQuery.java

@@ -3,16 +3,14 @@ package com.kcim.dao.model;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
-
-import java.math.BigDecimal;
-import java.io.Serializable;
-import java.util.Date;
-
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+
 /**
  * 
  * 
@@ -99,4 +97,14 @@ public class AllocationQuery implements Serializable {
 
 	private Integer shareType;
 
+//	/**
+//	 * 标准科室分类(来自责任中心)
+//	 */
+//	private String standardShareLevel;
+//
+//	/**
+//	 * 费用类型(来自会计科目字典)
+//	 */
+//	private String expandOne;
+
 }

+ 91 - 0
src/main/java/com/kcim/dao/model/ComputePatientCostAccount.java

@@ -0,0 +1,91 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 患者成本的会计科目金额表
+ * 
+ * @author Wang.YS
+
+ * @date 2025-08-22 17:57:23
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("compute_patient_cost_account")
+public class ComputePatientCostAccount implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Integer id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 核算年月
+	 */
+	private String computeDate;
+	/**
+	 * 项目成本主键
+	 */
+	private Integer patientCostId;
+	/**
+	 * 成本类别
+	 */
+	private String costType;
+	/**
+	 * 会计科目类别
+	 */
+	private String accountType;
+	/**
+	 * 计算结果
+	 */
+	private BigDecimal computeResult;
+	/**
+	 * 标准法计算结果
+	 */
+	private BigDecimal standComputeResult;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 18 - 0
src/main/java/com/kcim/dao/model/ComputeProjectCost.java

@@ -10,7 +10,9 @@ import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
+import java.util.Map;
 
 /**
  * 完全成本法项目成本计算表
@@ -74,6 +76,12 @@ public class ComputeProjectCost implements Serializable {
 	 * 责任中心名称
 	 */
 	private String responsibilityName;
+
+	/**
+	 * 数量
+	 */
+	private BigDecimal quantity;
+
 	/**
 	 * 创建人
 	 */
@@ -108,6 +116,16 @@ public class ComputeProjectCost implements Serializable {
 	private Integer index;
 
 
+	/**
+	 * 项目成本的会计科目表
+	 */
+	@TableField(exist = false)
+	Map<String,ComputeProjectCostAccount> projectCostAccountMap;
 
+	/**
+	 * 标准项目代码
+	 */
+	@TableField(exist = false)
+	private String standItemCode;
 
 }

+ 104 - 0
src/main/java/com/kcim/dao/model/ComputeProjectCostAccount.java

@@ -0,0 +1,104 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 项目成本的会计科目金额表
+ * 
+ * @author Wang.YS
+
+ * @date 2025-08-22 17:57:23
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("compute_project_cost_account")
+public class ComputeProjectCostAccount implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Integer id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 核算年月
+	 */
+	private String computeDate;
+	/**
+	 * 项目成本主键
+	 */
+	private Integer projectCostId;
+	/**
+	 * 标准项目代码
+	 */
+	private String standItemCode;
+	/**
+	 * 成本类别
+	 */
+	private String costType;
+	/**
+	 * 会计科目类别
+	 */
+	private String accountType;
+
+	/**
+	 * 计算结果
+	 */
+	private BigDecimal computeResult;
+	/**
+	 * 单个计算结果
+	 */
+	private BigDecimal computeSingleResult;
+	/**
+	 * 标准法计算结果
+	 */
+	private BigDecimal standComputeResult;
+	/**
+	 * 标准法单个计算结果
+	 */
+	private BigDecimal standComputeSingleResult;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 74 - 0
src/main/java/com/kcim/dao/model/CostAccountShareDetail.java

@@ -0,0 +1,74 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 成本分摊对应的会计科目
+ * 
+ * @author Wang.YS
+
+ * @date 2025-03-28 14:06:13
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("cost_account_share_detail")
+public class CostAccountShareDetail implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 成本分摊参数对应表的ID
+	 */
+	private Long accountShareId;
+	/**
+	 * 会计科目代码
+	 */
+	private String accountingCode;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 85 - 0
src/main/java/com/kcim/dao/model/CostAccountShareParam.java

@@ -0,0 +1,85 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 成本分摊对应的分摊参数
+ * 
+ * @author Wang.YS
+
+ * @date 2025-03-28 14:06:12
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("cost_account_share_param")
+public class CostAccountShareParam implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 成本分摊参数对应表的ID
+	 */
+	private Long accountShareId;
+	/**
+	 * 分摊参数代码
+	 */
+	private String shareParamCode;
+	/**
+	 * 分摊参数代码
+	 */
+	@TableField(exist = false)
+	private String shareParamName;
+	/**
+	 * 分摊参数占比
+	 */
+	private BigDecimal shareParamProportion;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 74 - 0
src/main/java/com/kcim/dao/model/CostAccountShareTarget.java

@@ -0,0 +1,74 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 成本分摊对应的分摊目标责任中心
+ * 
+ * @author Wang.YS
+
+ * @date 2025-04-03 11:13:36
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("cost_account_share_target")
+public class CostAccountShareTarget implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 成本分摊参数对应表的ID
+	 */
+	private Long accountShareId;
+	/**
+	 * 目标责任中心代码
+	 */
+	private String targetResponsibilityCode;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 37 - 0
src/main/java/com/kcim/dao/model/CostDepartmentProfit.java

@@ -11,6 +11,7 @@ import lombok.experimental.Accessors;
 
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.util.List;
 
 /**
  * 科室损益计算
@@ -115,5 +116,41 @@ public class CostDepartmentProfit implements Serializable {
 
 	private BigDecimal percent;
 
+	/**
+	 * 预算金额
+	 */
+	private BigDecimal budgetAmount;
+
+	/**
+	 * 上期金额
+	 */
+	private BigDecimal prevPeriodAmount;
+
+	/**
+	 * 同期金额
+	 */
+	private BigDecimal samePeriodAmount;
+
+	/**
+	 * 完成率
+	 */
+	private BigDecimal completionRate;
+
+	/**
+	 * 环比
+	 */
+	private BigDecimal momRate;
+
+	/**
+	 * 同比
+	 */
+	private BigDecimal yoyRate;
+
+	/**
+	 * 会计科目金额列表
+	 */
+	@TableField(exist = false)
+	private List<CostDepartmentProfitAccount> costDepartmentProfitAccounts;
+
 
 }

+ 87 - 0
src/main/java/com/kcim/dao/model/CostDepartmentProfitAccount.java

@@ -0,0 +1,87 @@
+package com.kcim.dao.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 科室损益的会计科目金额表
+ * 
+ * @author Wang.YS
+
+ * @date 2025-09-19 14:14:25
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@TableName("cost_department_profit_account")
+public class CostDepartmentProfitAccount implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@TableId
+	private Integer id;
+	/**
+	 * 医院id
+	 */
+	private Long hospId;
+	/**
+	 * 核算年月
+	 */
+	private String computeDate;
+	/**
+	 * 项目成本主键
+	 */
+	private Long deptProfitId;
+	/**
+	 * 成本类别
+	 */
+	private String costType;
+	/**
+	 * 会计科目类别
+	 */
+	private String accountType;
+	/**
+	 * 金额
+	 */
+	private BigDecimal amount;
+	/**
+	 * 创建人
+	 */
+	private String createUser;
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+	/**
+	 * 更新人
+	 */
+	private String updateUser;
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+	/**
+	 * 删除人
+	 */
+	private String deleteUser;
+	/**
+	 * 删除时间
+	 */
+	private Date deleteTime;
+	/**
+	 * 删除标志  0正常 1作废
+	 */
+	private Integer delFlag;
+
+}

+ 30 - 0
src/main/java/com/kcim/dao/model/HospProfitAndLoss.java

@@ -95,4 +95,34 @@ public class HospProfitAndLoss implements Serializable {
     private String parentResponsibilityCode;
     @TableField(exist = false)
     private String parentResponsibilityName;
+
+    /**
+     * 预算金额
+     */
+    private BigDecimal budgetAmount;
+
+    /**
+     * 上期金额
+     */
+    private BigDecimal prevPeriodAmount;
+
+    /**
+     * 同期金额
+     */
+    private BigDecimal samePeriodAmount;
+
+    /**
+     * 完成率
+     */
+    private BigDecimal completionRate;
+
+    /**
+     * 环比
+     */
+    private BigDecimal momRate;
+
+    /**
+     * 同比
+     */
+    private BigDecimal yoyRate;
 }

+ 6 - 0
src/main/java/com/kcim/dao/model/Item.java

@@ -167,4 +167,10 @@ public class Item implements Serializable {
 	private String departmentName;
 	@TableField(exist = false)
 	private StandItem standItem;
+
+	/**
+	 * 责任中心代码
+	 */
+	@TableField(exist = false)
+	private String responsibilityCode;
 }

+ 22 - 0
src/main/java/com/kcim/dao/model/ReportForm.java

@@ -103,4 +103,26 @@ public class ReportForm implements Serializable {
      */
     private Integer hide;
 
+    /**
+     * 数据类型:0未知 1数值 2百分比
+     */
+    private Integer dataType;
+
+
+    /**
+     * 数据类型名称
+     */
+    @TableField(exist = false)
+    private String dataTypeName;
+
+    /**
+     * 小数位
+     */
+    private Integer decimalPlace;
+
+    /**
+     * 是否有千分号
+     */
+    private Integer permil;
+
 }

+ 2 - 1
src/main/java/com/kcim/dao/model/Responsibility.java

@@ -70,6 +70,7 @@ public class Responsibility implements Serializable {
 	 * 分摊级别 如果是顶层默认为0
 	 */
 	private Integer shareLevel;
+
 	/**
 	 * 分摊级别名称
 	 */
@@ -95,7 +96,7 @@ public class Responsibility implements Serializable {
 	}
 
 	/**
-	 * 标准分摊层级
+	 * 标准分摊层级 标准分摊层级代码 1.行政后勤类,2.医疗辅助类,3.医疗技术类,4.临床服务类
 	 */
 	private String standardShareLevel;
 	@TableField(exist = false)

+ 15 - 6
src/main/java/com/kcim/dao/model/StandItem.java

@@ -4,18 +4,17 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
-
-import java.math.BigDecimal;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
 /**
  * 标准项目管理
  * 
@@ -90,6 +89,16 @@ public class StandItem implements Serializable {
 
 	private String itemType;
 
+	/**
+	 * 父级项目代码
+	 */
+	private String parentCode;
+
+	/**
+	 * 顺序号
+	 */
+	private Integer sort;
+
 	@TableField(exist = false)
 	private String itemTypeName;
 

+ 47 - 0
src/main/java/com/kcim/dao/model/dto/ParamContainerDTO.java

@@ -0,0 +1,47 @@
+package com.kcim.dao.model.dto;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * 泛型参数容器,可动态添加任意类型对象
+ * @author Administrator
+ */
+public class ParamContainerDTO {
+    /**
+     * 参数
+     */
+    private Map<String, Object> params = new HashMap<>();
+
+    /**
+     * 添加参数
+     * @param key
+     * @param value
+     * @param <T>
+     */
+    public <T> void put(String key, T value) {
+        params.put(key, value);
+    }
+
+    /**
+     * 获取参数(带类型转换)
+     * @param key
+     * @param <T>
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T get(String key) {
+        return (T) params.get(key);
+    }
+
+    /**
+     * 判断是否包含某个参数
+     * @param key
+     * @return
+     */
+    public boolean contains(String key) {
+        return params.containsKey(key);
+    }
+}

+ 18 - 0
src/main/java/com/kcim/dao/model/dto/ReportFormEditDTO.java

@@ -52,5 +52,23 @@ public class ReportFormEditDTO {
      */
     private Integer hide;
 
+    /**
+     * 数据类型:0未知 1数值 2百分比
+     */
+    private Integer dataType;
+
+    /**
+     * 数据类型名称
+     */
+    private String dataTypeName;
 
+    /**
+     * 小数位
+     */
+    private Integer decimalPlace;
+
+    /**
+     * 是否有千分号 0否 1是
+     */
+    private Integer permil;
 }

+ 18 - 0
src/main/java/com/kcim/dao/model/dto/ReportFormSaveDTO.java

@@ -48,5 +48,23 @@ public class ReportFormSaveDTO {
      */
     private Integer hide;
 
+    /**
+     * 数据类型:0未知 1数值 2百分比
+     */
+    private Integer dataType;
+
+    /**
+     * 数据类型名称
+     */
+    private String dataTypeName;
 
+    /**
+     * 小数位
+     */
+    private Integer decimalPlace;
+
+    /**
+     * 是否有千分号
+     */
+    private Integer permil;
 }

+ 7 - 0
src/main/java/com/kcim/dao/repository/AccountingRepository.java

@@ -41,6 +41,13 @@ public class AccountingRepository extends ServiceImpl<AccountingMapper, Accounti
         return this.list(queryWrapper);
     }
 
+    public List<Accounting> getAllCostAccounting() {
+        LambdaQueryWrapper<Accounting> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Accounting::getHospId, UserContext.getHospId());
+        queryWrapper.eq(Accounting::getAccountingType, NumberConstant.TWO);
+        return this.list(queryWrapper);
+    }
+
     public List<Accounting> getList(Integer accountType) {
         LambdaQueryWrapper<Accounting> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(Accounting::getHospId, UserContext.getHospId());

+ 3 - 4
src/main/java/com/kcim/dao/repository/ComputeLastProfitDateRepository.java

@@ -2,7 +2,6 @@ package com.kcim.dao.repository;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.kcim.common.util.UserContext;
 import com.kcim.dao.mapper.ComputeLastProfitDateMapper;
 import com.kcim.dao.model.ComputeLastProfitDate;
 import org.springframework.stereotype.Repository;
@@ -25,13 +24,13 @@ public class ComputeLastProfitDateRepository extends ServiceImpl<ComputeLastProf
     }
 
 
-    public void saveLastComputeDate(Long hospId,String computeDate) {
+    public void saveLastComputeDate(Long hospId,String computeDate,Long userId) {
         ComputeLastProfitDate lastComputeDate = getLastComputeDate(hospId);
         if(Objects.nonNull(lastComputeDate)){
             //当前院区已有记录 更新
             lastComputeDate.setComputeDate(computeDate);
             lastComputeDate.setUpdateTime(new Date());
-            lastComputeDate.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+            lastComputeDate.setUpdateUser(String.valueOf(userId));
             this.updateById(lastComputeDate);
         }else {
             //当前院区无记录 新增
@@ -39,7 +38,7 @@ public class ComputeLastProfitDateRepository extends ServiceImpl<ComputeLastProf
             computeLastProfitDate.setHospId(hospId);
             computeLastProfitDate.setComputeDate(computeDate);
             computeLastProfitDate.setCreateTime(new Date());
-            computeLastProfitDate.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+            computeLastProfitDate.setCreateUser(String.valueOf(userId));
             this.save(computeLastProfitDate);
         }
     }

+ 51 - 0
src/main/java/com/kcim/dao/repository/ComputePatientCostAccountRepository.java

@@ -0,0 +1,51 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.ComputePatientCostAccountMapper;
+import com.kcim.dao.model.ComputePatientCostAccount;
+import com.kcim.vo.DiseaseCostDetailVO;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2023-11-27 17:52
+ **/
+@Repository
+public class ComputePatientCostAccountRepository extends ServiceImpl<ComputePatientCostAccountMapper, ComputePatientCostAccount> {
+    public List<ComputePatientCostAccount> getList(String computeDate) {
+        LambdaQueryWrapper<ComputePatientCostAccount> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ComputePatientCostAccount::getHospId, UserContext.getHospId());
+        queryWrapper.eq(ComputePatientCostAccount::getComputeDate, computeDate);
+        return this.list(queryWrapper);
+    }
+
+    public List<DiseaseCostDetailVO> getDiseaseCostDetailList(String computeDate, String diseaseFilter) {
+        return this.baseMapper.getDiseaseCostDetailList(computeDate, UserContext.getHospId(), diseaseFilter);
+    }
+
+    public List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(String computeDate, String diseaseFilter) {
+        return this.baseMapper.getDiseaseCostCompositionDetail(computeDate, UserContext.getHospId(), diseaseFilter);
+    }
+
+    public List<DiseaseCostDetailVO> getDeptDiseaseCostCompositionDetail(String computeDate, String diseaseFilter) {
+        return this.baseMapper.getDeptDiseaseCostCompositionDetail(computeDate, UserContext.getHospId(), diseaseFilter);
+    }
+
+    public List<DiseaseCostDetailVO> getDrgCostDetailList(String computeDate) {
+        return this.baseMapper.getDrgCostDetailList(computeDate, UserContext.getHospId());
+    }
+
+    public List<DiseaseCostDetailVO> getDrgCostCompositionDetail(String computeDate) {
+        return this.baseMapper.getDrgCostCompositionDetail(computeDate, UserContext.getHospId());
+    }
+
+    public List<DiseaseCostDetailVO> getDeptDrgCostCompositionDetail(String computeDate) {
+        return this.baseMapper.getDeptDrgCostCompositionDetail(computeDate, UserContext.getHospId());
+    }
+}

+ 45 - 0
src/main/java/com/kcim/dao/repository/ComputeProjectCostAccountRepository.java

@@ -0,0 +1,45 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.ComputeProjectCostAccountMapper;
+import com.kcim.dao.model.ComputeProjectCostAccount;
+import com.kcim.service.impl.BaseBatchServiceImpl;
+import com.kcim.vo.HospitalServiceProjectCostVO;
+import com.kcim.vo.SessionUserVO;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2023-11-27 17:52
+ **/
+@Repository
+public class ComputeProjectCostAccountRepository extends BaseBatchServiceImpl<ComputeProjectCostAccountMapper, ComputeProjectCostAccount> {
+    public List<ComputeProjectCostAccount> getList(String computeDate) {
+        LambdaQueryWrapper<ComputeProjectCostAccount> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ComputeProjectCostAccount::getHospId, UserContext.getHospId());
+        queryWrapper.eq(ComputeProjectCostAccount::getComputeDate, computeDate);
+        return this.list(queryWrapper);
+    }
+
+    public List<HospitalServiceProjectCostVO> getMedicalServiceCostDetailList(String computeDate) {
+        return this.baseMapper.getMedicalServiceCostDetailList(computeDate, UserContext.getHospId());
+    }
+
+    public void removeByComputeDate(String computeDate, SessionUserVO currentUser) {
+        UpdateWrapper<ComputeProjectCostAccount> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(ComputeProjectCostAccount::getDelFlag, 0)
+                .eq(ComputeProjectCostAccount::getHospId, currentUser.getHospId())
+                .eq(ComputeProjectCostAccount::getComputeDate, computeDate)
+                .set(ComputeProjectCostAccount::getDeleteTime,new Date())
+                .set(ComputeProjectCostAccount::getDeleteUser,String.valueOf(currentUser.getId()))
+                .set(ComputeProjectCostAccount::getDelFlag, 1);
+        this.update(updateWrapper);
+    }
+}

+ 2 - 1
src/main/java/com/kcim/dao/repository/ComputeProjectCostDetailRepository.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kcim.common.util.UserContext;
 import com.kcim.dao.mapper.ComputeProjectCostDetailMapper;
 import com.kcim.dao.model.ComputeProjectCostDetail;
+import com.kcim.service.impl.BaseBatchServiceImpl;
 import com.kcim.vo.ComputeProjectCostPageDto;
 import com.kcim.vo.SessionUserVO;
 import org.springframework.stereotype.Repository;
@@ -19,7 +20,7 @@ import java.util.List;
  * @create: 2024-01-15 20:32
  **/
 @Repository
-public class ComputeProjectCostDetailRepository extends ServiceImpl<ComputeProjectCostDetailMapper, ComputeProjectCostDetail> {
+public class ComputeProjectCostDetailRepository extends BaseBatchServiceImpl<ComputeProjectCostDetailMapper, ComputeProjectCostDetail> {
 
 
     public void removeByComputeDate(String computeDate, SessionUserVO currentUser) {

+ 2 - 3
src/main/java/com/kcim/dao/repository/ComputeProjectGroupCostDetailRepository.java

@@ -1,10 +1,9 @@
 package com.kcim.dao.repository;
 
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kcim.dao.mapper.ComputeProjectGroupCostDetailMapper;
-import com.kcim.dao.model.ComputeProjectCostDetail;
 import com.kcim.dao.model.ComputeProjectGroupCostDetail;
+import com.kcim.service.impl.BaseBatchServiceImpl;
 import com.kcim.vo.SessionUserVO;
 import org.springframework.stereotype.Repository;
 
@@ -17,7 +16,7 @@ import java.util.Date;
  * @create: 2024-01-19 15:58
  **/
 @Repository
-public class ComputeProjectGroupCostDetailRepository extends ServiceImpl<ComputeProjectGroupCostDetailMapper, ComputeProjectGroupCostDetail> {
+public class ComputeProjectGroupCostDetailRepository extends BaseBatchServiceImpl<ComputeProjectGroupCostDetailMapper, ComputeProjectGroupCostDetail> {
     public void removeByComputeDate(String computeDate, SessionUserVO currentUser) {
 
         UpdateWrapper<ComputeProjectGroupCostDetail> updateWrapper = new UpdateWrapper<>();

+ 78 - 0
src/main/java/com/kcim/dao/repository/CostAccountShareDetailRepository.java

@@ -0,0 +1,78 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.CostAccountShareDetailMapper;
+import com.kcim.dao.model.CostAccountShareDetail;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2024-04-03 14:49
+ **/
+@Repository
+public class CostAccountShareDetailRepository extends ServiceImpl<CostAccountShareDetailMapper, CostAccountShareDetail> {
+
+    /**
+     * 获取指定分摊设置对应的会计科目
+     * @param accountShareId
+     * @return
+     */
+    public List<CostAccountShareDetail> getCostAccountShareDetail(Long accountShareId) {
+        LambdaQueryWrapper<CostAccountShareDetail> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CostAccountShareDetail::getHospId, UserContext.getHospId());
+        queryWrapper.eq(CostAccountShareDetail::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            queryWrapper.eq(CostAccountShareDetail::getAccountShareId, accountShareId);
+        }
+        return this.list(queryWrapper);
+    }
+
+    /**
+     * 作废指定分摊设置对应的会计科目
+     * @param accountShareId
+     * @return
+     */
+    public boolean delCostAccountShareDetail(Long accountShareId) {
+        LambdaUpdateWrapper<CostAccountShareDetail> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareDetail::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareDetail::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareDetail::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareDetail::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareDetail::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            updateWrapper.eq(CostAccountShareDetail::getAccountShareId, accountShareId);
+        }
+        return this.update(updateWrapper);
+    }
+
+    /**
+     * 批量删除指定分摊设置对应的会计科目
+     * @param accountShareIdList
+     * @return
+     */
+    public boolean delCostAccountShareDetailList(List<Long> accountShareIdList) {
+        LambdaUpdateWrapper<CostAccountShareDetail> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareDetail::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareDetail::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareDetail::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareDetail::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareDetail::getDelFlag, NumberConstant.ZERO);
+        if(!CollectionUtils.isEmpty(accountShareIdList)) {
+            updateWrapper.in(CostAccountShareDetail::getAccountShareId, accountShareIdList);
+        }
+        return this.update(updateWrapper);
+    }
+}

+ 77 - 0
src/main/java/com/kcim/dao/repository/CostAccountShareParamRepository.java

@@ -0,0 +1,77 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.CostAccountShareParamMapper;
+import com.kcim.dao.model.CostAccountShareParam;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2024-04-03 14:49
+ **/
+@Repository
+public class CostAccountShareParamRepository extends ServiceImpl<CostAccountShareParamMapper, CostAccountShareParam> {
+    /**
+     * 获取指定分摊设置对应的分摊参数
+     * @param accountShareId
+     * @return
+     */
+    public List<CostAccountShareParam> getCostAccountShareParam(Long accountShareId) {
+        LambdaQueryWrapper<CostAccountShareParam> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CostAccountShareParam::getHospId, UserContext.getHospId());
+        queryWrapper.eq(CostAccountShareParam::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            queryWrapper.eq(CostAccountShareParam::getAccountShareId, accountShareId);
+        }
+        return this.list(queryWrapper);
+    }
+
+    /**
+     * 作废指定分摊设置对应的分摊参数
+     * @param accountShareId
+     * @return
+     */
+    public boolean delCostAccountParamDetail(Long accountShareId) {
+        LambdaUpdateWrapper<CostAccountShareParam> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareParam::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareParam::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareParam::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareParam::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareParam::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            updateWrapper.eq(CostAccountShareParam::getAccountShareId, accountShareId);
+        }
+        return this.update(updateWrapper);
+    }
+
+    /**
+     * 批量删除指定分摊设置对应的分摊参数
+     * @param accountShareIdList
+     * @return
+     */
+    public boolean delCostAccountShareParamList(List<Long> accountShareIdList) {
+        LambdaUpdateWrapper<CostAccountShareParam> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareParam::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareParam::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareParam::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareParam::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareParam::getDelFlag, NumberConstant.ZERO);
+        if(!CollectionUtils.isEmpty(accountShareIdList)) {
+            updateWrapper.in(CostAccountShareParam::getAccountShareId, accountShareIdList);
+        }
+        return this.update(updateWrapper);
+    }
+}

+ 77 - 0
src/main/java/com/kcim/dao/repository/CostAccountShareTargetRepository.java

@@ -0,0 +1,77 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.CostAccountShareTargetMapper;
+import com.kcim.dao.model.CostAccountShareTarget;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2024-04-03 14:49
+ **/
+@Repository
+public class CostAccountShareTargetRepository extends ServiceImpl<CostAccountShareTargetMapper, CostAccountShareTarget> {
+    /**
+     * 获取指定分摊设置对应的目标责任中心
+     * @param accountShareId
+     * @return
+     */
+    public List<CostAccountShareTarget> getCostAccountShareTarget(Long accountShareId) {
+        LambdaQueryWrapper<CostAccountShareTarget> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CostAccountShareTarget::getHospId, UserContext.getHospId());
+        queryWrapper.eq(CostAccountShareTarget::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            queryWrapper.eq(CostAccountShareTarget::getAccountShareId, accountShareId);
+        }
+        return this.list(queryWrapper);
+    }
+
+    /**
+     * 作废指定分摊设置对应的目标责任中心
+     * @param accountShareId
+     * @return
+     */
+    public boolean delCostAccountShareTarget(Long accountShareId) {
+        LambdaUpdateWrapper<CostAccountShareTarget> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareTarget::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareTarget::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareTarget::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareTarget::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareTarget::getDelFlag, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)) {
+            updateWrapper.eq(CostAccountShareTarget::getAccountShareId, accountShareId);
+        }
+        return this.update(updateWrapper);
+    }
+
+    /**
+     * 批量删除指定分摊设置对应的目标责任中心
+     * @param accountShareIdList
+     * @return
+     */
+    public boolean delCostAccountShareTargetList(List<Long> accountShareIdList) {
+        LambdaUpdateWrapper<CostAccountShareTarget> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.set(CostAccountShareTarget::getDelFlag,NumberConstant.ONE);
+        updateWrapper.set(CostAccountShareTarget::getDeleteUser,UserContext.getCurrentUser().getId());
+        updateWrapper.set(CostAccountShareTarget::getDeleteTime,new Date());
+
+        updateWrapper.eq(CostAccountShareTarget::getHospId, UserContext.getHospId());
+        updateWrapper.eq(CostAccountShareTarget::getDelFlag, NumberConstant.ZERO);
+        if(!CollectionUtils.isEmpty(accountShareIdList)) {
+            updateWrapper.in(CostAccountShareTarget::getAccountShareId, accountShareIdList);
+        }
+        return this.update(updateWrapper);
+    }
+}

+ 50 - 0
src/main/java/com/kcim/dao/repository/CostDepartmentProfitAccountRepository.java

@@ -0,0 +1,50 @@
+package com.kcim.dao.repository;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.util.UserContext;
+import com.kcim.dao.mapper.CostDepartmentProfitAccountMapper;
+import com.kcim.dao.model.CostDepartmentProfitAccount;
+import com.kcim.service.impl.BaseBatchServiceImpl;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @program: CostAccount
+ * @description:
+ * @author: Wang.YS
+ * @create: 2023-11-27 17:52
+ **/
+@Repository
+public class CostDepartmentProfitAccountRepository extends BaseBatchServiceImpl<CostDepartmentProfitAccountMapper, CostDepartmentProfitAccount> {
+    public List<CostDepartmentProfitAccount> getList(String computeDate) {
+        LambdaQueryWrapper<CostDepartmentProfitAccount> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CostDepartmentProfitAccount::getHospId, UserContext.getHospId());
+        queryWrapper.eq(CostDepartmentProfitAccount::getComputeDate, computeDate);
+        return this.list(queryWrapper);
+    }
+
+
+    /**
+     * 删除科室损益的会计科目金额表
+     * @param computeDate
+     * @return
+     */
+    public boolean deleteDeptProfitAccount(String computeDate) {
+        return deleteDeptProfitAccountWithUser(UserContext.getHospId(),computeDate,UserContext.getCurrentUser().getId());
+    }
+
+    public boolean deleteDeptProfitAccountWithUser(Long hospId,String computeDate,Long userId) {
+        LambdaUpdateWrapper<CostDepartmentProfitAccount> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(CostDepartmentProfitAccount::getHospId, hospId);
+        updateWrapper.eq(CostDepartmentProfitAccount::getComputeDate, computeDate);
+        updateWrapper.eq(CostDepartmentProfitAccount::getDelFlag, NumberConstant.ZERO);
+        updateWrapper.set(CostDepartmentProfitAccount::getDelFlag, NumberConstant.ONE);
+        updateWrapper.set(CostDepartmentProfitAccount::getDeleteTime,new Date());
+        updateWrapper.set(CostDepartmentProfitAccount::getDeleteUser, userId);
+        return this.update(updateWrapper);
+    }
+}

+ 10 - 2
src/main/java/com/kcim/dao/repository/ImportPatientItemRepository.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.util.PageUtils;
 import com.kcim.common.util.UserContext;
 import com.kcim.dao.mapper.ImportPatientItemMapper;
 import com.kcim.dao.model.ImportPatientItem;
@@ -171,8 +172,15 @@ public class ImportPatientItemRepository extends ServiceImpl<ImportPatientItemMa
         return this.list(queryWrapper);
     }
 
-    public List<PatientInfoVo> getPatientItemPatientInfo(String computeDate, String filter) {
-        return this.baseMapper.getPatientItemPatientInfo(computeDate, filter, UserContext.getHospId());
+    public PageUtils getPatientItemPatientInfo(Integer current, Integer pageSize,String computeDate, String filter) {
+        Page<PatientInfoVo> page = new Page<>(current,pageSize);
+        List<PatientInfoVo> byPage = this.baseMapper.getPatientItemPatientInfo(page,computeDate, filter, UserContext.getHospId());
+        if(!CollectionUtils.isEmpty(byPage)){
+            page.setRecords(byPage);
+        }
+        PageUtils pageUtils = new PageUtils(page);
+        pageUtils.setList(byPage);
+        return pageUtils;
     }
 
     public void removePatientItemByFileId(String computeDate, Long fileId) {

+ 8 - 0
src/main/java/com/kcim/dao/repository/ItemRepository.java

@@ -81,6 +81,14 @@ public class ItemRepository extends ServiceImpl<ItemMapper, Item> {
         }
     }
 
+    /**
+     * 获取责任中心的医疗服务项目字典
+     * @return
+     */
+    public List<Item> getRespItemList(){
+        return this.baseMapper.getRespItemList(UserContext.getHospId());
+    }
+
     public List<Item> getList() {
         LambdaQueryWrapper<Item> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(Item::getHospId, UserContext.getHospId());

+ 7 - 0
src/main/java/com/kcim/service/AllocationQueryService.java

@@ -45,13 +45,20 @@ public interface AllocationQueryService extends IService<AllocationQuery> {
      */
     List<AllocationQuery> getAllByDate(Long hospId, int year, int month);
 
+    List<AllocationQuery> getCostByDate(Long hospId, int year, int month,int originType);
+
     List<AllocationQuery> getByDate(int year, int month, Long hospId, List<Long> levelSorts);
 
     List<AllocationQuery> getByDateAndResp(int year, int month, Long hospId, String responsibilityCode);
 
     List<AllocationQuery> getByDateRespn(int year, int month, Long hospId, List<Long> shareLevelId, String responsibilityCode);
 
+    List<AllocationQuery> getAcountAccounts(Long hospId, int dateYear, int month);
+
+    List<AllocationQuery> getRespAcountAccounts(Long hospId, int dateYear, int month);
 
+    List<AllocationQuery> getRespOriginAcountAccounts(Long hospId, int dateYear, int month);
 
+    void batchInsertAllocationQuery(List<AllocationQuery> allocationQueryList);
 }
 

+ 7 - 0
src/main/java/com/kcim/service/CenterService.java

@@ -39,6 +39,13 @@ public interface CenterService {
      */
     String getParameterValue(Long parameterCode);
 
+    /**
+     * 获取指定Code的参数指定序号的数值,
+     * @param parameterCode
+     * @return
+     */
+    String getParameterValueByIndex(Long parameterCode,int index);
+
     List<KCClassVo>  getKCClass();
 
     List<SysDepartment>  getDepartmentByDepartmentIds(List<Long> departmentIds);

+ 15 - 0
src/main/java/com/kcim/service/CostAccountShareDetailService.java

@@ -0,0 +1,15 @@
+package com.kcim.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.kcim.dao.model.CostAccountShareDetail;
+
+/**
+ * 成本分摊对应的会计科目
+ *
+ * @author Wang.YS
+ * @date 2025-03-28 14:06:13
+ */
+public interface CostAccountShareDetailService extends IService<CostAccountShareDetail> {
+
+}
+

+ 15 - 0
src/main/java/com/kcim/service/CostAccountShareParamService.java

@@ -0,0 +1,15 @@
+package com.kcim.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.kcim.dao.model.CostAccountShareParam;
+
+/**
+ * 成本分摊对应的分摊参数
+ *
+ * @author Wang.YS
+ * @date 2025-03-28 14:06:12
+ */
+public interface CostAccountShareParamService extends IService<CostAccountShareParam> {
+
+}
+

+ 15 - 0
src/main/java/com/kcim/service/CostAccountShareService.java

@@ -10,6 +10,7 @@ import com.kcim.dao.model.dto.CostAccountShareSaveDto;
 import com.kcim.dao.model.dto.ShareParamEditDto;
 import com.kcim.vo.CostShareParamStatusVO;
 import com.kcim.vo.ShareParamProportionVO;
+import com.kcim.vo.ShareTargetMapVo;
 
 import java.util.List;
 
@@ -97,5 +98,19 @@ public interface CostAccountShareService extends IService<CostAccountShare> {
     void deleteByIds(List<Long> asList);
     List<CostAccountShare> getAll();
 
+    /**
+     * 同步分摊参数设置
+     * @param direction 1主表向明细表同步 2明细表向主表同步
+     * @param accountShareId
+     * @return
+     */
+    void synCostAccountShare(Integer direction, Long accountShareId);
+
+
+    /**
+     * 添加分摊设置对应的目标责任中心
+     * @param shareTargetMapVo
+     */
+    void applyAccountShareTarget(ShareTargetMapVo shareTargetMapVo);
 }
 

+ 15 - 0
src/main/java/com/kcim/service/CostAccountShareTargetService.java

@@ -0,0 +1,15 @@
+package com.kcim.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.kcim.dao.model.CostAccountShareTarget;
+
+/**
+ * 成本分摊对应的分摊目标责任中心
+ *
+ * @author Wang.YS
+ * @date 2025-04-03 11:13:36
+ */
+public interface CostAccountShareTargetService extends IService<CostAccountShareTarget> {
+
+}
+

+ 2 - 0
src/main/java/com/kcim/service/CostDepartmentProfitService.java

@@ -71,5 +71,7 @@ public interface CostDepartmentProfitService extends IService<CostDepartmentProf
     Object getRedirectData(String computeDate, Long reportId, Long hospId, String reportType, String responsibilityCode);
 
     Object getComputeProfitCollect(String computeDate, Long hospId, String reportType);
+
+    Object getBatchComputeProfitListByYear(String startYear, String endYear, String reportType, String responsibilityCode);
 }
 

+ 2 - 0
src/main/java/com/kcim/service/HospProfitAndLossService.java

@@ -60,5 +60,7 @@ public interface HospProfitAndLossService extends IService<HospProfitAndLoss> {
     Object getHospProfitResponsibilities(String responsibilityName);
 
     Object getHospProfitList(String computeDate, Long hospId, String reportType);
+
+    Object getBatchHospProfitList(String beginComputeDate, String endComputeDate, Long hospId, Integer reportType);
 }
 

+ 2 - 0
src/main/java/com/kcim/service/IncomeCollectionService.java

@@ -71,5 +71,7 @@ public interface IncomeCollectionService extends IService<IncomeCollection> {
     List<IncomeCollection> getCollectionsByDate(int year, int month, Long hospId);
 
     List<IncomeCollection> getCollectionsByDateAndResp(int year, int month, Long hospId, String responsibilityCode);
+
+    List<IncomeCollection> getResponsibilitiesAccounts(int year, int month, Long hospId);
 }
 

+ 11 - 0
src/main/java/com/kcim/service/KpiComputeImportService.java

@@ -1,7 +1,10 @@
 package com.kcim.service;
 
+import com.kcim.vo.SheetImportResultVO;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.List;
+
 /**
  * @program: CostAccount
  * @description:
@@ -41,4 +44,12 @@ public interface KpiComputeImportService {
      * @param id 记录id
      */
     void recoverImport(Integer id);
+
+    /**
+     * 批量导入数据
+     * @param computeDate 核算年月
+     * @param file 导入文件
+     * @return 导入结果列表
+     */
+    List<SheetImportResultVO> importMultipleSheets(String computeDate, MultipartFile file);
 }

+ 1 - 1
src/main/java/com/kcim/service/PatientItemImportService.java

@@ -43,7 +43,7 @@ public interface PatientItemImportService {
 
     void removePatientItem(String computeDate);
 
-    Object getPatientItemPatientInfo(String filter, String computeDate);
+    Object getPatientItemPatientInfo(Integer current, Integer pageSize,String filter, String computeDate);
 
     void removePatientItemByFileId(String computeDate,Long fileId);
 

+ 161 - 0
src/main/java/com/kcim/service/StandardReportService.java

@@ -0,0 +1,161 @@
+package com.kcim.service;
+
+import com.kcim.vo.*;
+import com.kcim.web.reponse.ComputeProfitCollectResponse;
+import com.kcim.web.reponse.StandardDeptCostCollectResponse;
+
+import java.util.List;
+
+public interface StandardReportService {
+
+    /**
+     * 科室直接成本表(医疗成本)
+     * @param computeDate
+     */
+    List<DeptDirectMedicalCostVO> getDeptDirectMedicalCost(String computeDate);
+    /**
+     * 科室直接成本表(全成本)
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<DeptFullDirectCostVO> getDeptFullDirectCost(String computeDate);
+
+    /**
+     * 获取临床服务类科室全成本(医疗成本)
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<ClinicalDeptMedicalCostVO> getClinicalDeptMedicalCost(String computeDate);
+
+    /**
+     * 获取临床服务类科室全成本(全成本)
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<ClinicalDeptFullCostVO> getClinicalDeptFullCost(String computeDate);
+
+    /**
+     * 获取医院临床服务类科室全成本构成分析表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    ComputeProfitCollectResponse getClinicalDeptFullCostAnalysis(String computeDate);
+
+    /**
+     * 获取医院科室成本分摊汇总表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<HospitalDeptCostAllocationVO> getHospitalDeptCostAllocation(String computeDate) ;
+
+    /**
+     * 获取医院诊次成本构成表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<HospitalVisitCostCompositionVO> getHospitalVisitCostComposition(String computeDate);
+
+    /**
+     * 获取医院科室诊次成本表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<HospitalVisitCostCompositionVO> getHospitalDeptVisitCost(String computeDate);
+    /**
+     * 获取医院床日成本构成表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<HospitalVisitCostCompositionVO> getHospitalBedDayCostComposition(String computeDate);
+    /**
+     * 获取医院科室床日成本表数据
+     * @param computeDate 核算年月
+     * @return 报表数据
+     */
+    List<HospitalVisitCostCompositionVO> getHospitalDeptBedDayCost(String computeDate);
+
+    /**
+     * 获取医院服务项目成本表数据
+     * @param computeDate
+     * @return
+     */
+    List<HospitalServiceProjectCostVO> getHospitalServiceProjectCost(String computeDate);
+
+    /**
+     * 获取医院服务项目成本明细表数据
+     * @param computeDate
+     * @return
+     */
+    List<HospitalServiceProjectCostVO> getMedicalServiceCostDetail(String computeDate);
+
+    /**
+     * 获取病种成本明细表数据
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDiseaseCostDetail(String computeDate);
+
+    /**
+     * 分页获取病种成本明细表数据
+     * @param current 当前页码
+     * @param pageSize 每页大小
+     * @param computeDate 核算年月
+     * @param diseaseFilter 病种筛选条件(编码或名称)
+     * @return 分页数据
+     */
+    Object getDiseaseCostDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter);
+
+    /**
+     * 获取病种成本构成明细表数据
+     * @param computeDate
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDiseaseCostCompositionDetail(String computeDate);
+
+    /**
+     * 分页获取病种成本构成明细表数据
+     * @param current 当前页码
+     * @param pageSize 每页大小
+     * @param computeDate 核算年月
+     * @param diseaseFilter 病种筛选条件(编码或名称)
+     * @return 分页数据
+     */
+    Object getDiseaseCostCompositionDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter);
+
+    /**
+     * 获取服务单元病种成本构成明细表数据
+     * @param computeDate
+     * @return
+     */
+    StandardDeptCostCollectResponse getDeptDiseaseCostCompositionDetail(String computeDate);
+    
+    /**
+     * 分页获取服务单元病种成本构成明细表数据
+     * @param current 当前页码
+     * @param pageSize 每页大小
+     * @param computeDate 核算年月
+     * @param diseaseFilter 病种筛选条件(编码或名称)
+     * @return 分页数据
+     */
+    Object getDeptDiseaseCostCompositionDetailByPage(Integer current, Integer pageSize, String computeDate, String diseaseFilter);
+
+    /**
+     * 获取DRG成本明细表数据
+     * @param computeDate
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDrgCostDetail(String computeDate);
+
+    /**
+     * 获取DRG成本构成明细表数据
+     * @param computeDate
+     * @return
+     */
+    List<DiseaseCostDetailVO> getDrgCostCompositionDetail(String computeDate);
+
+    /**
+     * 获取服务单元DRG成本构成明细表数据
+     * @param computeDate
+     * @return
+     */
+    StandardDeptCostCollectResponse getDeptDrgCostCompositionDetail(String computeDate);
+}

+ 43 - 5
src/main/java/com/kcim/service/impl/AllocationQueryServiceImpl.java

@@ -1,13 +1,11 @@
 package com.kcim.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.kcim.vo.CodeAndNameVO;
 import com.kcim.dao.mapper.AllocationQueryMapper;
+import com.kcim.dao.model.AllocationQuery;
 import com.kcim.service.AllocationQueryService;
+import com.kcim.vo.CodeAndNameVO;
 import org.springframework.stereotype.Service;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-
-import com.kcim.dao.model.AllocationQuery;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -15,7 +13,7 @@ import java.util.stream.Collectors;
 
 
 @Service("allocationQueryService")
-public class AllocationQueryServiceImpl extends ServiceImpl<AllocationQueryMapper, AllocationQuery> implements AllocationQueryService {
+public class AllocationQueryServiceImpl extends BaseBatchServiceImpl<AllocationQueryMapper, AllocationQuery> implements AllocationQueryService {
 
 
     /**
@@ -58,6 +56,26 @@ public class AllocationQueryServiceImpl extends ServiceImpl<AllocationQueryMappe
         return baseMapper.getTotalByAccountAndRespCode(hospId, dateYear, month, accountCode, responsibilityCode);
     }
 
+    @Override
+    public List<AllocationQuery> getAcountAccounts(Long hospId, int dateYear, int month) {
+        return baseMapper.getAcountAccounts(hospId, dateYear, month);
+    }
+
+    @Override
+    public List<AllocationQuery> getRespAcountAccounts(Long hospId, int dateYear, int month) {
+        return baseMapper.getRespAcountAccounts(hospId, dateYear, month);
+    }
+
+    @Override
+    public List<AllocationQuery> getRespOriginAcountAccounts(Long hospId, int dateYear, int month) {
+        return baseMapper.getRespOriginAcountAccounts(hospId, dateYear, month);
+    }
+
+    @Override
+    public void batchInsertAllocationQuery(List<AllocationQuery> allocationQueryList) {
+         this.batchInsert(allocationQueryList);
+    }
+
     /**
      * 获取这个月的分摊数据
      *
@@ -77,6 +95,26 @@ public class AllocationQueryServiceImpl extends ServiceImpl<AllocationQueryMappe
         return list;
     }
 
+    /**
+     * 获取指定类型的成本数据
+     * @param hospId
+     * @param year
+     * @param month
+     * @param originType 来源类型:1.分摊前,2.分摊后
+     * @return
+     */
+    @Override
+    public List<AllocationQuery> getCostByDate(Long hospId, int year, int month, int originType) {
+        List<AllocationQuery> list = this.list(
+                new LambdaQueryWrapper<AllocationQuery>()
+                        .eq(AllocationQuery::getDateYear, year)
+                        .eq(AllocationQuery::getDateMonth, month)
+                        .eq(AllocationQuery::getHospId, hospId)
+                        .eq(AllocationQuery::getOriginType, originType)
+        );
+        return list;
+    }
+
     @Override
     public List<AllocationQuery> getByDate(int year, int month, Long hospId, List<Long> levelSorts) {
         return this.list(

+ 721 - 30
src/main/java/com/kcim/service/impl/AllocationServiceImpl.java

@@ -7,8 +7,8 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.poi.excel.ExcelWriter;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.constants.ParameterConstant;
 import com.kcim.common.constants.SQLParameter;
 import com.kcim.common.enums.CustomSqlTypeEnum;
 import com.kcim.common.exception.CostException;
@@ -19,25 +19,32 @@ import com.kcim.common.util.UserContext;
 import com.kcim.dao.mapper.AllocationMapper;
 import com.kcim.dao.model.*;
 import com.kcim.dao.model.dto.StartDTO;
+import com.kcim.dao.repository.CostAccountShareDetailRepository;
+import com.kcim.dao.repository.CostAccountShareParamRepository;
+import com.kcim.dao.repository.CostAccountShareTargetRepository;
 import com.kcim.dao.repository.ResponsibilityRepository;
 import com.kcim.service.*;
 import com.kcim.vo.*;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @Slf4j
+@AllArgsConstructor
 @Service("allocationService")
-public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocation> implements AllocationService {
+public class AllocationServiceImpl extends BaseBatchServiceImpl<AllocationMapper, Allocation> implements AllocationService {
     //    @Value("${file.serverPath}")
 //    private String fileTempPath;
 //
@@ -55,18 +62,22 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
 
     private final SqlService sqlService;
 
-    public AllocationServiceImpl(CostCostingGroupService costCostingGroupService, CostShareLevelService shareLevelService, ResponsibilityService responsibilityService, CostAccountShareService accountShareService, ShareParamValueService shareParamValueService, CostShareParamService shareParamService, AllocationQueryService allocationQueryService, ResponsibilityRepository responsibilityRepository, CenterService centerService, SqlService sqlService) {
-        this.costCostingGroupService = costCostingGroupService;
-        this.shareLevelService = shareLevelService;
-        this.responsibilityService = responsibilityService;
-        this.accountShareService = accountShareService;
-        this.shareParamValueService = shareParamValueService;
-        this.shareParamService = shareParamService;
-        this.allocationQueryService = allocationQueryService;
-        this.responsibilityRepository = responsibilityRepository;
-        this.centerService = centerService;
-        this.sqlService = sqlService;
-    }
+    private final CostAccountShareDetailRepository costAccountShareDetailRepository;
+    private final CostAccountShareParamRepository costAccountShareParamRepository;
+    private final CostAccountShareTargetRepository costAccountShareTargetRepository;
+
+//    public AllocationServiceImpl(CostCostingGroupService costCostingGroupService, CostShareLevelService shareLevelService, ResponsibilityService responsibilityService, CostAccountShareService accountShareService, ShareParamValueService shareParamValueService, CostShareParamService shareParamService, AllocationQueryService allocationQueryService, ResponsibilityRepository responsibilityRepository, CenterService centerService, SqlService sqlService) {
+//        this.costCostingGroupService = costCostingGroupService;
+//        this.shareLevelService = shareLevelService;
+//        this.responsibilityService = responsibilityService;
+//        this.accountShareService = accountShareService;
+//        this.shareParamValueService = shareParamValueService;
+//        this.shareParamService = shareParamService;
+//        this.allocationQueryService = allocationQueryService;
+//        this.responsibilityRepository = responsibilityRepository;
+//        this.centerService = centerService;
+//        this.sqlService = sqlService;
+//    }
 
     /**
      * 分摊成本数据
@@ -75,8 +86,696 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
      * @param hospId   医院id
      */
     @Override
-    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
     public void startAllocation(StartDTO startDTO, Long hospId) {
+        //获取分摊方式
+        String parameterValue = centerService.getParameterValue(ParameterConstant.ALLOCATION_TYPE);
+        if (NumberConstant.ONE_S.equals(parameterValue)) {
+            //开始按责任中心分摊成本
+            startCostAllocation(startDTO, hospId);
+        }
+        else if (NumberConstant.TWO_S.equals(parameterValue)) {
+            //按会计科目分摊
+            startAccountAllocation(startDTO, hospId);
+        }
+        //执行分摊后续处理脚本
+        execAllocationSQL(startDTO);
+    }
+
+    /**
+     * 按会计科目分摊
+     * @param startDTO
+     */
+    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
+    public void startAccountAllocation(StartDTO startDTO, Long hospId){
+        long timeMillis = System.currentTimeMillis();
+        // 得到这个月的所有导入的成本数据
+        List<CostCostingGroup> costingGroups = costCostingGroupService.getByYearAndDate(startDTO.getYear(), startDTO.getMonth(), hospId);
+        // 没有重新导入
+        if (costingGroups.isEmpty()) {
+            throw new CostException("本月分摊数据未导入");
+        }
+        // 导入数据按责任中心归类
+        Map<String, List<CostCostingGroup>> respDirectCostMap = costingGroups.stream().collect(Collectors.groupingBy(CostCostingGroup::getResponsibilityCode));
+        // 得到这个月导入的成本分摊参数值列表
+        List<ShareParamValue> respParamValueList = shareParamValueService.getListByYearAndMonth(startDTO.getYear(), startDTO.getMonth(), hospId);
+        if (respParamValueList.isEmpty()) {
+            throw new CostException("本月成本分摊参数值未导入");
+        }
+        Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup = respParamValueList.stream()
+                .collect(Collectors.groupingBy(
+                        ShareParamValue::getResponsibilityCode,
+                        Collectors.groupingBy(ShareParamValue::getShareParamCode)
+                ));
+        // 得到这个医院所有的分摊层级列表排序
+        List<CostShareLevelVO> shareLevelVOs = shareLevelService.getAll(hospId);
+        if (CollUtil.isEmpty(shareLevelVOs)) {
+            throw new CostException("请先设置医院分摊层级");
+        }
+        //优化循环调用  责任中心  分摊层级对应
+        //成本分摊字典
+        List<CostShareParamVO> costShareParamList = shareParamService.getAll(hospId);
+        if (CollUtil.isEmpty(costShareParamList)) {
+            throw new CostException("请先设置分摊参数字典");
+        }
+        Map<String,String> ShareParamNameMap = costShareParamList.stream().collect(Collectors.toMap(CostShareParamVO::getShareParamCode, CostShareParamVO::getShareParamName, (a, b) -> b));
+
+        //责任中心
+        List<Responsibility> responsibilityList = responsibilityRepository.getList(hospId);
+        if (CollUtil.isEmpty(responsibilityList)) {
+            throw new CostException("请先设置责任中心");
+        }
+        //按shareId分组
+        Map<Long, List<Responsibility>> responsibilityShareIdMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getShareId));
+        //按责任中心代码分组
+        Map<String, List<Responsibility>> responsibilityCodeMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getResponsibilityCode));
+        //分摊参数对应
+        List<CostAccountShare> accountShareList = accountShareService.getAll();
+        if (CollUtil.isEmpty(accountShareList)) {
+            throw new CostException("请先设置责任中心分摊参数对应");
+        }
+        //责任中心的分摊参数对应设置
+        Map<String, List<CostAccountShare>> accountShareResponsibilityMap = accountShareList.stream().collect(Collectors.groupingBy(CostAccountShare::getResponsibilityCode));
+        //分摊设置对应的分摊参数明细
+        List<CostAccountShareParam> costAccountShareParamList = costAccountShareParamRepository.getCostAccountShareParam(null);
+        if (CollUtil.isEmpty(costAccountShareParamList)) {
+            throw new CostException("请先设置责任中心的分摊参数");
+        }
+        //设置分摊参数名称
+        costAccountShareParamList.forEach(shareParam->shareParam.setShareParamName(ShareParamNameMap.get(shareParam.getShareParamCode())));
+        //按分摊设置ID分组
+        Map<Long, List<CostAccountShareParam>> costAccountShareParamMap = costAccountShareParamList.stream().collect(Collectors.groupingBy(CostAccountShareParam::getAccountShareId));
+        //分摊设置对应的会计科目明细
+        List<CostAccountShareDetail> costAccountShareDetailList = costAccountShareDetailRepository.getCostAccountShareDetail(null);
+        Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap =new HashMap<>();
+        //全部都是合并计算时会有会计科目明细为空的情况
+        if(!CollectionUtils.isEmpty(costAccountShareDetailList)) {
+            costAccountShareDetailMap=costAccountShareDetailList.stream().collect(Collectors.groupingBy(CostAccountShareDetail::getAccountShareId));
+        }
+
+        //分摊设置对应的目标责任中心
+        List<CostAccountShareTarget> costAccountShareTargetList = costAccountShareTargetRepository.getCostAccountShareTarget(null);
+        Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap =new HashMap<>();
+        //全部没有指定分摊时会有目标责任中心为空的情况
+        if(!CollectionUtils.isEmpty(costAccountShareTargetList)) {
+            costAccountShareTargetMap=costAccountShareTargetList.stream().collect(Collectors.groupingBy(CostAccountShareTarget::getAccountShareId));
+        }
+        //分摊成本列表
+        List<Allocation> allocationCostList=new ArrayList<>();
+        //逐级分摊
+        for (CostShareLevelVO shareLevelVO : shareLevelVOs) {
+            List<Allocation> shareLevelAllocationList = allocationShareLevelCost(startDTO, shareLevelVO, responsibilityList, responsibilityShareIdMap, respDirectCostMap, respParamValueGroup,
+                    accountShareResponsibilityMap, costAccountShareParamMap, costAccountShareDetailMap, costAccountShareTargetMap,allocationCostList, timeMillis,hospId);
+            allocationCostList.addAll(shareLevelAllocationList);
+        }
+        //没有任何分摊数据
+        if(CollectionUtils.isEmpty(allocationCostList)){
+            log.error("没有任何分摊数据......");
+            return;
+        }
+        // 删除该年月已经分摊过的数据
+        removeData(startDTO, hospId);
+        //保存分摊结果信息
+        this.batchInsert(allocationCostList);
+        //保存分摊结果查询表
+        applyAllocationQuery(startDTO,respDirectCostMap,allocationCostList,responsibilityCodeMap);
+    }
+
+    public void batchSaveAllocation(List<Allocation> allocationList) {
+        if (CollUtil.isEmpty(allocationList)) {
+            return;
+        }
+        // 调整批次大小,根据数据库性能测试确定最佳值
+        int batchSize = 5000;
+        // 分批次保存
+        for (int i = 0; i < allocationList.size(); i += batchSize) {
+            int end = Math.min(i + batchSize, allocationList.size());
+            this.saveBatch(allocationList.subList(i, end));
+        }
+    }
+
+    /**
+     * 一个分摊层级的分摊计算
+     * @param startDTO 分摊年月所在对象
+     * @param shareLevelVO 分摊层级
+     * @param responsibilityList 责任中心字典
+     * @param responsibilityShareIdMap 各分摊层级的责任中心
+     * @param respDirectCostMap 直接成本
+     * @param respParamValueGroup 分摊参数数值
+     * @param accountShareResponsibilityMap 分摊参数对应
+     * @param costAccountShareParamMap 分摊设置对应的分摊参数
+     * @param costAccountShareDetailMap 分摊设置对应的会计科目
+     * @param allocationCostList 间接成本
+     * @param timeMillis 时间戳
+     * @return
+     */
+    public List<Allocation> allocationShareLevelCost(StartDTO startDTO, CostShareLevelVO shareLevelVO,
+                                                     List<Responsibility> responsibilityList,
+                                                     Map<Long, List<Responsibility>> responsibilityShareIdMap,
+                                                     Map<String, List<CostCostingGroup>> respDirectCostMap ,
+                                                     Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
+                                                     Map<String,List<CostAccountShare>> accountShareResponsibilityMap,
+                                                     Map<Long, List<CostAccountShareParam>> costAccountShareParamMap,
+                                                     Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap,
+                                                     Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap,
+                                                     List<Allocation> allocationCostList,
+                                                     long timeMillis, Long hospId){
+        //分摊成本列表
+        List<Allocation> allocationList=new ArrayList<>();
+        // 分摊层级id
+        Long levelId = shareLevelVO.getId();
+        // 目标分摊层级,可能不存在
+        String targetLevel = shareLevelVO.getTargetLevel();
+        if (StrUtil.isBlank(targetLevel)) {
+            throw new CostException("未设置目标层级");
+        }
+        //目标分摊层级
+        List<String> targetLevelList = Arrays.stream(targetLevel.split(StrUtil.COMMA)).collect(Collectors.toList());
+        //目标层级是自己的不需要做分摊处理
+        if(NumberConstant.ONE.equals(targetLevelList.size())&&Integer.valueOf(targetLevelList.get(NumberConstant.ZERO)).equals(shareLevelVO.getLeverSort())){
+            return allocationList;
+        }
+        // 得到该分摊层级下责任中心列表,如果不存在,下一个
+        List<Responsibility> responsibilities = responsibilityShareIdMap.get(levelId);
+        if (CollectionUtils.isEmpty(responsibilities)) {
+            return allocationList;
+        }
+
+        //目标责任中心列表 - 优化:预先创建Map以提高查找效率
+        Map<String, Responsibility> targetResponsibilityMap = responsibilityList.stream()
+                .filter(responsibility -> targetLevelList.contains(String.valueOf(responsibility.getShareLevel())))
+                .collect(Collectors.toMap(Responsibility::getResponsibilityCode, Function.identity(), (a, b) -> a));
+
+        if (targetResponsibilityMap.isEmpty()) {
+            throw new CostException(String.format("[%s-%s]的分摊目标层级没有对应的责任中心",shareLevelVO.getLeverSort(),shareLevelVO.getShareName()));
+        }
+
+        // 优化:预先创建间接成本的Map以提高查找效率
+        Map<String, List<Allocation>> indirectCostMap = allocationCostList.stream()
+                .collect(Collectors.groupingBy(Allocation::getTargetResponsibilityCode));
+
+        // 按责任中心逐个开始分摊(并行)
+        allocationList = responsibilities.parallelStream().flatMap(responsibility ->  allocationResponsibilityCost(startDTO, shareLevelVO, responsibility, targetResponsibilityMap, respDirectCostMap, respParamValueGroup,
+                    accountShareResponsibilityMap, costAccountShareParamMap, costAccountShareDetailMap,costAccountShareTargetMap, indirectCostMap, timeMillis,hospId).stream()).collect(Collectors.toList());
+        return allocationList;
+    }
+
+
+    /**
+     * 分摊一个责任中心的成本
+     * @param startDTO 分摊年月所在对象
+     * @param shareLevelVO 分摊层级
+     * @param responsibility 责任中心
+     * @param respDirectCostMap 直接成本
+     * @param respParamValueGroup 分摊参数数值
+     * @param accountShareResponsibilityMap 分摊参数对应
+     * @param costAccountShareParamMap 分摊设置对应的分摊参数
+     * @param costAccountShareDetailMap 分摊设置对应的会计科目
+     * @param indirectCostMap 间接成本
+     * @param timeMillis 时间戳
+     */
+    public List<Allocation> allocationResponsibilityCost(StartDTO startDTO,
+                                             CostShareLevelVO shareLevelVO,
+                                             Responsibility responsibility,
+                                             Map<String, Responsibility> targetResponsibilityMap ,
+                                             Map<String, List<CostCostingGroup>> respDirectCostMap ,
+                                             Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
+                                             Map<String,List<CostAccountShare>> accountShareResponsibilityMap,
+                                             Map<Long, List<CostAccountShareParam>> costAccountShareParamMap,
+                                             Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap,
+                                             Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap,
+                                             Map<String, List<Allocation>> indirectCostMap,
+                                             long timeMillis, Long hospId){
+        //分摊结果列表
+        List<Allocation> allocationList=new ArrayList<>();
+        // 得到分摊参数对应记录,不存在,下一个
+        List<CostAccountShare> accountShares = accountShareResponsibilityMap.get(responsibility.getResponsibilityCode());
+        if (CollectionUtils.isEmpty(accountShares)) {
+            return allocationList;
+        }
+        // 计算方式 0是合并计算  1是分开计算
+        Integer calcType = shareLevelVO.getCalcType();
+        //合并计算时不应该有多个分摊设置
+        if(NumberConstant.ZERO.equals(calcType) &&NumberConstant.ONE!=accountShares.size()){
+            throw new CostException(String.format("[%s-%s]的分摊设置有问题,合并计算的责任中心只允许设置一个分摊配置",responsibility.getResponsibilityCode(),responsibility.getResponsibilityName()));
+        }
+        //间接成本
+        List<Allocation> respIndirectCostList =indirectCostMap.get(responsibility.getResponsibilityCode());
+        //直接成本
+        List<CostCostingGroup> respDirectCostList = respDirectCostMap.get(responsibility.getResponsibilityCode());
+        //按分摊设置逐个计算
+        for (CostAccountShare accountShare : accountShares) {
+            //分摊设置对应的直接成本
+            List<CostCostingGroup> paramDirectCostList=new ArrayList<>();
+            //分摊设置对应的间接成本
+            List<Allocation> paramIndirectCostList=new ArrayList<>();
+            //获取分摊设置对应的目标责任中心
+            List<Responsibility> shareTargetRespCodeList = getShareTargetResponsibility(accountShare, targetResponsibilityMap, costAccountShareTargetMap);
+            //所有目标责任中心的责任中心代码列表
+            List<String> targetResponsibilityCodeList = shareTargetRespCodeList.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList());
+            //合并计算
+            if(NumberConstant.ZERO.equals(calcType)){
+                //合并计算时分摊参数的成本=责任中心的成本
+                paramDirectCostList=respDirectCostList;
+                paramIndirectCostList=respIndirectCostList;
+            }else{
+                //分摊设置对应的会计科目
+                List<String> accountList = costAccountShareDetailMap.get(accountShare.getId()).stream().map(CostAccountShareDetail::getAccountingCode).collect(Collectors.toList());
+                if(!CollectionUtils.isEmpty(respDirectCostList)) {
+                    //获取分摊设置对应的直接成本
+                    paramDirectCostList = respDirectCostList.stream().filter(respDirectCost -> accountList.contains(respDirectCost.getAccountCode())).collect(Collectors.toList());
+                }
+                //只有包含分摊成本的才有间接成本
+                if(NumberConstant.ONE.equals(accountShare.getIsShareCost())){
+                    paramIndirectCostList=respIndirectCostList;
+                }
+            }
+            //分摊设置对应的分摊参数
+            List<CostAccountShareParam> costAccountShareParams = costAccountShareParamMap.get(accountShare.getId());
+            //按分摊参数逐个计算所有目标责任中心的分摊金额
+            for (CostAccountShareParam shareParam : costAccountShareParams) {
+                //获取所有目标责任中心的分摊参数数值信息
+                List<ShareParamValue> targetResponsibilityParamList =getTargetResponsibilityParamList( respParamValueGroup,targetResponsibilityCodeList,shareParam);
+                if(CollectionUtils.isEmpty(targetResponsibilityParamList)){
+                    throw new CostException(String.format("[%s-%s]的目标责任中心找不到对应的参数数值,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
+                }
+                //按分摊参数计算每个会计科目分摊到的金额
+                List<Allocation> allocationParamCosts = allocationParamCostCalc(startDTO, shareLevelVO, responsibility, shareTargetRespCodeList, paramDirectCostList,
+                        paramIndirectCostList, accountShares.get(NumberConstant.ZERO), shareParam, targetResponsibilityParamList, timeMillis, hospId);
+                allocationList.addAll(allocationParamCosts);
+            }
+        }
+        return allocationList;
+    }
+
+    /**
+     * 获取所有目标责任中心的分摊参数数值信息
+     * @param respParamValueGroup
+     * @param targetResponsibilityCodeList
+     * @param shareParam
+     * @return
+     */
+    public List<ShareParamValue> getTargetResponsibilityParamList(
+            Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
+            List<String> targetResponsibilityCodeList,
+            CostAccountShareParam shareParam) {
+
+        List<ShareParamValue> targetResponsibilityParamList = new ArrayList<>();
+        String shareParamCode = shareParam.getShareParamCode();
+
+        for (String targetResponsibilityCode : targetResponsibilityCodeList) {
+            Map<String, List<ShareParamValue>> shareParamValueMap = respParamValueGroup.get(targetResponsibilityCode);
+            if (shareParamValueMap != null) {
+                List<ShareParamValue> shareParamValues = shareParamValueMap.get(shareParamCode);
+                if (shareParamValues != null) {
+                    targetResponsibilityParamList.addAll(shareParamValues);
+                }
+            }
+        }
+        return targetResponsibilityParamList;
+    }
+
+
+    /**
+     * 获取分摊设置的目标责任中心
+     * @param accountShare
+     * @param levelTargetResponsibilityMap
+     * @param costAccountShareTargetMap
+     * @return
+     */
+    public List<Responsibility> getShareTargetResponsibility(CostAccountShare accountShare,
+                                                             Map<String, Responsibility> levelTargetResponsibilityMap,
+                                                             Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap){
+        //获取分摊设置对应的目标责任中心
+        List<CostAccountShareTarget> shareTargetResponsibilityList=costAccountShareTargetMap.get(accountShare.getId());
+        if(CollectionUtils.isEmpty(shareTargetResponsibilityList)){
+            return new ArrayList<>(levelTargetResponsibilityMap.values());
+        }
+        //筛选出指定的目标责任中心
+        List<String> shareTargetRespCodeList = shareTargetResponsibilityList.stream().map(CostAccountShareTarget::getTargetResponsibilityCode).collect(Collectors.toList());
+        List<Responsibility> shareTargetRespList = new ArrayList<>();
+        for (String shareTargetRespCode : shareTargetRespCodeList) {
+            Responsibility levelTargetResponsibility = levelTargetResponsibilityMap.get(shareTargetRespCode);
+            if (levelTargetResponsibility == null) {
+                continue;
+            }
+            shareTargetRespList.add(levelTargetResponsibility);
+        }
+        if(CollectionUtils.isEmpty(shareTargetRespList)){
+            throw new CostException(String.format("[%s-%s]找不到对应的目标责任中心,无法继续分摊",accountShare.getResponsibilityName(),accountShare.getAlias()));
+        }
+        return shareTargetRespList;
+    }
+
+    /**
+     * 按分摊参数计算每个会计科目分摊到的金额
+     * @param startDTO 分摊年月所在对象
+     * @param shareLevelVO 分摊层级
+     * @param responsibility 责任中心
+     * @param targetResponsibilityList 目标责任中心列表
+     * @param respDirectCostList 直接成本
+     * @param respIndirectCostList 间接成本
+     * @param costAccountShare 分摊参数对应
+     * @param shareParam 分摊参数
+     * @param targetResponsibilityParamList 目标责任中心的分摊参数数值列表
+     * @param timeMillis 时间戳
+     * @return
+     */
+    public List<Allocation> allocationParamCostCalc(StartDTO startDTO,
+                                               CostShareLevelVO shareLevelVO,
+                                               Responsibility responsibility,
+                                               List<Responsibility> targetResponsibilityList,
+                                               List<CostCostingGroup> respDirectCostList,
+                                               List<Allocation> respIndirectCostList,
+                                               CostAccountShare costAccountShare,
+                                               CostAccountShareParam shareParam,
+                                               List<ShareParamValue> targetResponsibilityParamList,
+                                               long timeMillis, Long hospId){
+        //重新定义一个列表用于合并直接成本和间接成本
+        List<CostCostingGroup> respCostList=new ArrayList<>();
+        //添加直接成本
+        if(!CollectionUtils.isEmpty(respDirectCostList)){
+            respCostList.addAll(respDirectCostList);
+        }
+        //添加间接成本
+        if(!CollectionUtils.isEmpty(respIndirectCostList)){
+            //转成直接成本的对象
+            List<CostCostingGroup> respIndirectCosts = BeanUtil.convertList(respIndirectCostList, CostCostingGroup.class);
+            respCostList.addAll(respIndirectCosts);
+        }
+        //计算所有目标责任中心的分摊参数加总
+        BigDecimal totalParamValue= targetResponsibilityParamList.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
+        if (NumberConstant.ZERO.equals(totalParamValue.compareTo(BigDecimal.ZERO))){
+            throw new CostException(String.format("[%s-%s]的目标责任中心参数数值加总为0,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
+        }
+        //按责任中心分组,方便取到对应责任中心的分摊参数数值
+        Map<String, List<ShareParamValue>> targetRespParamGroup = targetResponsibilityParamList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
+        //创建accountCode到accountName的映射
+        Map<String, String> accountCodeNameMap = respCostList.stream().collect(Collectors.toMap(CostCostingGroup::getAccountCode,
+                CostCostingGroup::getAccountName,
+                (existing, replacement) -> replacement // 处理重复键的情况,保留最后一个值
+                ));
+        //按会计科目分组,相同会计科目一起分摊
+        Map<String, BigDecimal> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode,
+                        Collectors.reducing(BigDecimal.ZERO,CostCostingGroup::getAmount,BigDecimal::add)));
+        //参数占比
+        BigDecimal paramRate = shareParam.getShareParamProportion().divide(new BigDecimal(NumberConstant.ONE_HUNDRED), NumberConstant.FOUR, RoundingMode.HALF_UP);
+        //分摊结果列表
+        List<Allocation> allocationList=new ArrayList<>();
+        for (Responsibility targetResponsibility : targetResponsibilityList){
+            List<ShareParamValue> targetRespParamValues = targetRespParamGroup.get(targetResponsibility.getResponsibilityCode());
+            //目标责任中心的分摊参数数值
+            BigDecimal targetRespParamValue = BigDecimal.ZERO;
+            if(!CollectionUtils.isEmpty(targetRespParamValues)) {
+                targetRespParamValue = targetRespParamValues.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
+            }
+            //没有参数数值就不分摊计算了,不然数据会很多
+            if(NumberConstant.ZERO.equals(BigDecimal.ZERO.compareTo(targetRespParamValue))){
+                continue;
+            }
+            //计算分摊参数比例
+            BigDecimal shareParamRate =  targetRespParamValue.divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
+
+            for (Map.Entry<String, BigDecimal> entry : respDirectCostGroup.entrySet()) {
+                String accountCode = entry.getKey();
+                BigDecimal totalAmount = entry.getValue();
+                //没有金额的会计科目就不分摊计算了,不然数据会很多
+                if(NumberConstant.ZERO.equals(BigDecimal.ZERO.compareTo(totalAmount))){
+                    continue;
+                }
+                //计算分摊到的金额=目标责任中心的分摊参数数值*会计科目总金额/所有目标责任中心的分摊参数数值加总*参数比例
+                BigDecimal targetAmount = targetRespParamValue.multiply(totalAmount).multiply(paramRate).divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
+                //生成分摊结果的对象
+                Allocation targetAllocation =  createAllocation(startDTO, shareLevelVO, responsibility, targetResponsibility, costAccountShare,  shareParam,timeMillis,hospId);
+                targetAllocation.setAmount(targetAmount)
+                        .setTotalAmount(totalAmount)
+                        .setShareParamValueNum(targetRespParamValue)
+                        .setShareParamRate(shareParamRate)
+                        .setAccountCode(accountCode)
+                        .setAccountName(accountCodeNameMap.get(accountCode));
+                allocationList.add(targetAllocation);
+            }
+        }
+        return allocationList;
+    }
+
+    /**
+     * 按分摊参数计算每个会计科目分摊到的金额(多线程)
+     * @param startDTO 分摊年月所在对象
+     * @param shareLevelVO 分摊层级
+     * @param responsibility 责任中心
+     * @param targetResponsibilityList 目标责任中心列表
+     * @param respDirectCostList 直接成本
+     * @param respIndirectCostList 间接成本
+     * @param costAccountShare 分摊参数对应
+     * @param shareParam 分摊参数
+     * @param targetResponsibilityParamList 目标责任中心的分摊参数数值列表
+     * @param timeMillis 时间戳
+     * @return
+     */
+    public List<Allocation> synAllocationParamCostCalc(StartDTO startDTO,
+                                                    CostShareLevelVO shareLevelVO,
+                                                    Responsibility responsibility,
+                                                    List<Responsibility> targetResponsibilityList,
+                                                    List<CostCostingGroup> respDirectCostList,
+                                                    List<Allocation> respIndirectCostList,
+                                                    CostAccountShare costAccountShare,
+                                                    CostAccountShareParam shareParam,
+                                                    List<ShareParamValue> targetResponsibilityParamList,
+                                                    long timeMillis, Long hospId){
+        //重新定义一个列表用于合并直接成本和间接成本
+        List<CostCostingGroup> respCostList=new ArrayList<>();
+        //添加直接成本
+        if(!CollectionUtils.isEmpty(respDirectCostList)){
+            respCostList.addAll(respDirectCostList);
+        }
+        //添加间接成本
+        if(!CollectionUtils.isEmpty(respIndirectCostList)){
+            //转成直接成本的对象
+            List<CostCostingGroup> respIndirectCosts = BeanUtil.convertList(respIndirectCostList, CostCostingGroup.class);
+            respCostList.addAll(respIndirectCosts);
+        }
+        //计算所有目标责任中心的分摊参数加总
+        BigDecimal totalParamValue= targetResponsibilityParamList.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
+        if (NumberConstant.ZERO.equals(totalParamValue.compareTo(BigDecimal.ZERO))){
+            throw new CostException(String.format("[%s-%s]的目标责任中心参数数值加总为0,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
+        }
+
+        //按责任中心分组,方便取到对应责任中心的分摊参数数值
+        Map<String, BigDecimal> targetRespParamGroup=targetResponsibilityParamList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode,Collectors.reducing(BigDecimal.ZERO, ShareParamValue::getValueNum, BigDecimal::add)));
+
+        //创建accountCode到accountName的映射
+        Map<String, String> accountCodeNameMap = respCostList.stream().collect(Collectors.toMap(
+                CostCostingGroup::getAccountCode,
+                CostCostingGroup::getAccountName,
+                (existing, replacement) -> replacement // 处理重复键的情况,保留最后一个值
+        ));
+
+        //按会计科目分组,相同会计科目一起分摊并计算总金额
+        Map<String, BigDecimal> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(
+                CostCostingGroup::getAccountCode,
+                Collectors.reducing(BigDecimal.ZERO, CostCostingGroup::getAmount, BigDecimal::add)
+        ));
+
+        //预计算参数比例,避免在循环中重复计算
+        BigDecimal paramRate = shareParam.getShareParamProportion()
+                .divide(new BigDecimal(NumberConstant.ONE_HUNDRED), NumberConstant.FOUR, RoundingMode.HALF_UP);
+
+        //分摊结果列表(使用线程安全的列表)
+        List<Allocation> allocationList = Collections.synchronizedList(new ArrayList<>());
+
+        //使用并行流处理目标责任中心
+        targetResponsibilityList.parallelStream().forEach(targetResponsibility -> {
+            //目标责任中心的分摊参数数值
+            BigDecimal targetRespParamValue = targetRespParamGroup.get(targetResponsibility.getResponsibilityCode());
+            if(ObjectUtils.isEmpty(targetRespParamValue)){
+                return;
+            }
+            //计算分摊参数比例
+            BigDecimal shareParamRate = targetRespParamValue.divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
+            //预计算基础金额,避免在内层循环中重复计算
+            BigDecimal baseAmount = targetRespParamValue.multiply(paramRate).divide(totalParamValue, NumberConstant.SIX, RoundingMode.HALF_UP);
+            //遍历每个会计科目
+            respDirectCostGroup.entrySet().parallelStream().forEach(entry -> {
+                String accountCode = entry.getKey();
+                BigDecimal totalAmount = entry.getValue();
+                //计算分摊到的金额=目标责任中心的分摊参数数值*会计科目总金额/所有目标责任中心的分摊参数数值加总*参数比例
+                //优化:使用预计算的baseAmount
+                BigDecimal targetAmount = totalAmount.multiply(baseAmount);
+                //生成分摊结果的对象
+                Allocation targetAllocation = createAllocation(startDTO, shareLevelVO, responsibility, targetResponsibility, costAccountShare,  shareParam,timeMillis,hospId);
+                targetAllocation.setAmount(targetAmount)
+                        .setTotalAmount(totalAmount)
+                        .setShareParamValueNum(targetRespParamValue)
+                        .setShareParamRate(shareParamRate)
+                        .setAccountCode(accountCode)
+                        .setAccountName(accountCodeNameMap.get(accountCode));
+                //同步添加到结果列表
+                synchronized(allocationList) {
+                    allocationList.add(targetAllocation);
+                }
+            });
+        });
+
+        return new ArrayList<>(allocationList); //返回普通ArrayList
+    }
+
+
+    /**
+     * 创建分摊结果对象
+     * @param startDTO
+     * @param shareLevelVO
+     * @param responsibility
+     * @param targetResponsibility
+     * @param costAccountShare
+     * @param shareParam
+     * @param timeMillis
+     * @param hospId
+     * @return
+     */
+    public Allocation createAllocation(StartDTO startDTO,
+                                       CostShareLevelVO shareLevelVO,
+                                       Responsibility responsibility,
+                                       Responsibility targetResponsibility,
+                                       CostAccountShare costAccountShare,
+                                       CostAccountShareParam shareParam,
+                                       long timeMillis,
+                                       Long hospId) {
+        Allocation targetAllocation = new Allocation();
+        targetAllocation.setDateMonth(startDTO.getMonth())
+                .setDateYear(startDTO.getYear())
+                .setLevelSort(shareLevelVO.getLeverSort())
+                .setLevelName(shareLevelVO.getShareName())
+                .setHospId(hospId)
+                .setResponsibilityCode(responsibility.getResponsibilityCode())
+                .setResponsibilityName(responsibility.getResponsibilityName())
+                .setAccountShareId(costAccountShare.getId())
+//                .setAmount(targetAmount)
+                .setCreateTime(timeMillis)
+                .setTargetResponsibilityCode(targetResponsibility.getResponsibilityCode())
+                .setTargetResponsibilityName(targetResponsibility.getResponsibilityName())
+                .setShareParamCode(shareParam.getShareParamCode())
+                .setShareParamName(shareParam.getShareParamName())
+//                .setTotalAmount(totalAmount)
+//                .setShareParamValueNum(targetRespParamValue)
+//                .setShareParamRate(shareParamRate)
+                .setShareLevelId(responsibility.getShareId())
+                .setTargetShareLevelId(targetResponsibility.getShareId());
+//                .setAccountCode(accountCode)
+//                .setAccountName(accountCodeNameMap.get(accountCode));
+        return targetAllocation;
+    }
+
+
+    /**
+     * 保存分摊结果查询表
+     * @param startDTO 分摊年月所在对象
+     * @param respDirectCostMap 责任中心的直接成本
+     * @param allocationCostList 所有责任中心的间接成本
+     * @param responsibilityCodeMap 责任中心字典
+     */
+    public void applyAllocationQuery(StartDTO startDTO, Map<String, List<CostCostingGroup>> respDirectCostMap ,List<Allocation> allocationCostList,Map<String, List<Responsibility>> responsibilityCodeMap){
+        List<AllocationQuery> allocationQueryList=new ArrayList<>();
+        //处理直接成本,直接成本可能是多次导入的没有按会计科目汇总的,需按责任中心+会计科目汇总保存
+        respDirectCostMap.forEach((respCode,respCostList)->{
+            List<AllocationQuery> directAllocationQueryList = createDirectAllocationQuery(startDTO, respCode, respCostList, responsibilityCodeMap);
+            allocationQueryList.addAll(directAllocationQueryList);
+        });
+        //处理间接成本,间接成本肯定是按会计科目汇总的,可直接生成对象
+        for (Allocation indirectCost : allocationCostList) {
+            AllocationQuery indirectAllocationQuery = createIndirectAllocationQuery(startDTO, indirectCost);
+            allocationQueryList.add(indirectAllocationQuery);
+        }
+        if(CollectionUtils.isEmpty(allocationQueryList)){
+            log.error("没有任何分摊结果数据......");
+            return;
+        }
+        //保存分摊结果查询对象信息
+        allocationQueryService.batchInsertAllocationQuery(allocationQueryList);
+    }
+
+    /**
+     * 创建直接成本的分摊结果查询对象
+     * @param startDTO 分摊年月所在对象
+     * @param respCode 责任中心代码
+     * @param respCostList 责任中心的直接成本数据
+     * @param responsibilityCodeMap 责任中心字典
+     * @return
+     */
+    public List<AllocationQuery> createDirectAllocationQuery(StartDTO startDTO,String respCode,List<CostCostingGroup> respCostList, Map<String, List<Responsibility>> responsibilityCodeMap){
+        List<AllocationQuery> allocationQueryList=new ArrayList<>();
+        if(!responsibilityCodeMap.containsKey(respCode)){
+            log.error(String.format("[%s-%s]的责任中心数据已过期",respCode,respCostList.get(NumberConstant.ZERO).getResponsibilityName()));
+            return allocationQueryList;
+        }
+        //责任中心数据
+        Responsibility responsibility=responsibilityCodeMap.get(respCode).get(NumberConstant.ZERO);
+        //按会计科目代码分组
+        Map<String, List<CostCostingGroup>> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode));
+        //按会计科目逐个生成分摊结果查询对象
+        respDirectCostGroup.forEach((respAccountCode,respAccountCostList)->{
+            CostCostingGroup firtsDirectCost = respAccountCostList.get(NumberConstant.ZERO);
+            //汇总金额
+            BigDecimal totalAccountCost = respAccountCostList.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+            //创建分摊结果查询对象
+            AllocationQuery allocationQuery = new AllocationQuery();
+            allocationQuery.setDateYear(startDTO.getYear()).setDateMonth(startDTO.getMonth())
+                    .setHospId(UserContext.getHospId()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
+                    .setCreateTime(System.currentTimeMillis())
+                    .setLevelSort(responsibility.getShareLevel()).setLevelName(responsibility.getShareName())
+                    .setTargetResponsibilityCode(responsibility.getResponsibilityCode())
+                    .setTargetResponsibilityName(responsibility.getResponsibilityName())
+                    .setShareLevelId(responsibility.getShareId())
+                    .setOriginId(firtsDirectCost.getId()).setOriginType(Long.valueOf(NumberConstant.ONE)).setAmount(totalAccountCost)
+                    .setAccountingCode(firtsDirectCost.getAccountCode()).setAccountingName(firtsDirectCost.getAccountName());
+            allocationQueryList.add(allocationQuery);
+        });
+        return allocationQueryList;
+    }
+
+    /**
+     * 创建间接成本的分摊结果查询对象
+     * @param startDTO 分摊年月所在对象
+     * @param indirectCost 间接成本对象
+     * @return
+     */
+    public AllocationQuery createIndirectAllocationQuery(StartDTO startDTO,Allocation indirectCost){
+        AllocationQuery allocationQuery = new AllocationQuery();
+        allocationQuery.setDateYear(startDTO.getYear()).setDateMonth(startDTO.getMonth())
+                .setHospId(UserContext.getHospId()).setResponsibilityCode(indirectCost.getResponsibilityCode())
+                .setResponsibilityName(indirectCost.getResponsibilityName())
+                .setOriginId(indirectCost.getId()).setOriginType(Long.valueOf(NumberConstant.TWO)).setAmount(indirectCost.getAmount())
+                .setAccountingCode(indirectCost.getAccountCode()).setAccountingName(indirectCost.getAccountName())
+                .setCreateTime(System.currentTimeMillis())
+                .setLevelSort(indirectCost.getLevelSort()).setLevelName(indirectCost.getLevelName())
+                .setTargetResponsibilityCode(indirectCost.getTargetResponsibilityCode())
+                .setTargetResponsibilityName(indirectCost.getTargetResponsibilityName())
+                .setShareLevelId(indirectCost.getShareLevelId());
+        return allocationQuery;
+    }
+
+    /**
+     * 执行分摊后续处理脚本
+     * @param startDTO
+     */
+    public void execAllocationSQL(StartDTO startDTO){
+        //执行分摊后续处理脚本
+        Map<String,String> sqlParameter = new HashMap<>();
+        if(startDTO.getMonth()<10){
+            sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-0"+startDTO.getMonth());
+        }else{
+            sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-"+startDTO.getMonth());
+        }
+        sqlService.autoExecuteSql(CustomSqlTypeEnum.COST_ALLOCATION_CALC.getCode(),sqlParameter);
+    }
+
+
+    /**
+     * 按责任中心分摊
+     * @param startDTO
+     * @param hospId
+     */
+    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
+    public  void startCostAllocation(StartDTO startDTO, Long hospId){
         long timeMillis = System.currentTimeMillis();
         // 得到这个月的所有导入的成本数据
         List<CostCostingGroup> costingGroups = costCostingGroupService.getByYearAndDate(startDTO.getYear(), startDTO.getMonth(), hospId);
@@ -207,14 +906,14 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
                                 String valueResponsibilityCode = paramValue.getResponsibilityCode();
                                 //优化循环调用
                                 String targetRespName = responsibilityNameMap.get(valueResponsibilityCode);
-    //                            String targetRespName = responsibilityService.getByCode(valueResponsibilityCode, hospId);
+                                //                            String targetRespName = responsibilityService.getByCode(valueResponsibilityCode, hospId);
                                 Long targetShareLevelId = responsibilityShareIdDictMap.get(valueResponsibilityCode);
-    //                            Long targetShareLevelId = responsibilityService.getLevelIdByCode(valueResponsibilityCode, hospId);
+                                //                            Long targetShareLevelId = responsibilityService.getLevelIdByCode(valueResponsibilityCode, hospId);
                                 if (Objects.isNull(targetShareLevelId)) {
                                     throw new CostException("目标责任中心分摊层级异常");
                                 }
                                 String shareParamName = ShareParamNameMap.get(paramValue.getShareParamCode());
-    //                            String shareParamName = shareParamService.getByCode(paramValue.getShareParamCode(), hospId);
+                                //                            String shareParamName = shareParamService.getByCode(paramValue.getShareParamCode(), hospId);
                                 targetAllocation.setDateMonth(startDTO.getMonth()).setDateYear(startDTO.getYear()).setLevelSort(shareLevelVO.getLeverSort())
                                         .setLevelName(shareLevelVO.getShareName()).setHospId(hospId).setResponsibilityCode(responsibility.getResponsibilityCode())
                                         .setResponsibilityName(responsibility.getResponsibilityName()).setAccountShareId(accountShareId).setAmount(targetAmount)
@@ -244,15 +943,6 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
         // 入cost_allocation_query 表 便于后续操作
         this.saveAllocationQuery(list, hospId, startDTO.getYear(), startDTO.getMonth(),shareLevelVOs,accountShareList);
 
-        Map<String,String> sqlParameter = new HashMap<>();
-        if(startDTO.getMonth()<10){
-            sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-0"+startDTO.getMonth());
-
-        }else{
-            sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-"+startDTO.getMonth());
-
-        }
-        sqlService.autoExecuteSql(CustomSqlTypeEnum.COST_ALLOCATION_CALC.getCode(),sqlParameter);
     }
 
     private void removeData(StartDTO startDTO, Long hospId) {
@@ -823,9 +1513,10 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
             throw new CostException(500, "参数异常");
         }
         // 处理第几次分摊计算值
-        List<Allocation> allocationList = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
-                .eq(Allocation::getHospId, hospId).eq(Allocation::getLevelSort, levelSort).eq(Allocation::getShareLevelId, shareLevelId).eq(Allocation::getDateYear, year)
-                .eq(Allocation::getDateMonth, month));
+//        List<Allocation> allocationList = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
+//                .eq(Allocation::getHospId, hospId).eq(Allocation::getLevelSort, levelSort).eq(Allocation::getShareLevelId, shareLevelId).eq(Allocation::getDateYear, year)
+//                .eq(Allocation::getDateMonth, month));
+        List<Allocation> allocationList =baseMapper.getLevelSortAllocation(hospId,year,month,shareLevelId);
         // 找会计科室的时候使用的
         List<Allocation> allocations = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
                 .eq(Allocation::getHospId, hospId).eq(Allocation::getDateYear, year)

+ 78 - 0
src/main/java/com/kcim/service/impl/BaseBatchServiceImpl.java

@@ -0,0 +1,78 @@
+package com.kcim.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.dao.mapper.GenericBatchMapper;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.function.BiFunction;
+
+/**
+ * 通用批量插入服务基类
+ * @param <T> 实体类类型
+ * @param <M> Mapper接口类型(需继承GenericBatchMapper)
+ */
+public abstract class BaseBatchServiceImpl<M extends GenericBatchMapper<T>, T>
+        extends ServiceImpl<M, T>{
+
+    /**
+     * 默认批次大小(可根据表结构调整)
+     */
+    private int batchSize = 1000;
+
+    /**
+     * 设置批次大小
+     */
+    public void setBatchSize(int batchSize) {
+        this.batchSize = batchSize;
+    }
+
+    /**
+     * 批量插入数据(适合中等数据量)
+     * @param dataList 要插入的数据列表
+     * @return 总插入条数
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public int batchInsert(List<T> dataList) {
+        if (dataList == null || dataList.isEmpty()) {
+            return 0;
+        }
+
+        int total = dataList.size();
+        int batches = (total + batchSize - 1) / batchSize;
+
+        for (int i = 0; i < batches; i++) {
+            int start = i * batchSize;
+            int end = Math.min(start + batchSize, total);
+            baseMapper.insertBatch(dataList.subList(start, end));
+        }
+
+        return total;
+    }
+
+    /**
+     * 分页加载并插入大数据量(避免OOM)
+     * @param dataProvider 数据提供器(分页加载数据的回调函数)
+     * @return 总插入条数
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public int batchInsertByPage(BiFunction<Integer, Integer, List<T>> dataProvider) {
+        int page = 0;
+        int total = 0;
+
+        while (true) {
+            // 调用回调函数加载当前页数据
+            List<T> dataBatch = dataProvider.apply(page, batchSize);
+            if (dataBatch.isEmpty()) {
+                break; // 数据加载完成
+            }
+
+            // 插入当前页数据
+            baseMapper.insertBatch(dataBatch);
+            total += dataBatch.size();
+            page++;
+        }
+
+        return total;
+    }
+}

+ 27 - 1
src/main/java/com/kcim/service/impl/CenterServiceImpl.java

@@ -1,7 +1,9 @@
 package com.kcim.service.impl;
 
 import com.alibaba.fastjson2.JSON;
+import com.kcim.common.constants.CommonConstant;
 import com.kcim.common.constants.Constant;
+import com.kcim.common.constants.NumberConstant;
 import com.kcim.common.exception.CostException;
 import com.kcim.dao.model.dto.SysDepartment;
 import com.kcim.endPoint.CenterEndPoint;
@@ -14,6 +16,7 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -99,7 +102,7 @@ public class CenterServiceImpl implements CenterService {
         try {
             Object dict = endPoint.getParameter(LOCAL_SYSTEM_ID, parameterCode);
             CommonParameterVo commonParameterVo = JSON.parseObject(JSON.toJSONString(dict), CommonParameterVo.class);
-            if(ObjectUtils.isEmpty(commonParameterVo)||ObjectUtils.isEmpty(commonParameterVo.getValue())) {
+            if(ObjectUtils.isEmpty(commonParameterVo)|| StringUtils.isEmpty(commonParameterVo.getValue())) {
                 return Constant.EMPTY_STR;
             }
             return  commonParameterVo.getValue();
@@ -108,6 +111,29 @@ public class CenterServiceImpl implements CenterService {
         }
     }
 
+    /**
+     * 获取指定Code的参数指定序号的数值
+     * @param parameterCode
+     * @param index
+     * @return
+     */
+    @Override
+    public String getParameterValueByIndex(Long parameterCode, int index) {
+        try {
+            if(ObjectUtils.isEmpty(index)) {
+                index = NumberConstant.ZERO;
+            }
+            String parameterValue = getParameterValue(parameterCode);
+            String[] split = parameterValue.split(CommonConstant.SEPARATOR_VERTICAL);
+            if(split.length>index){
+                return split[index];
+            }
+            return Constant.EMPTY_STR;
+        }catch (Exception e){
+            throw new CostException(e.getMessage());
+        }
+    }
+
     @Override
     public List<KCClassVo> getKCClass() {
         Object kcClass = endPoint.getKCClass(null);

+ 12 - 0
src/main/java/com/kcim/service/impl/ComputeMedicalDepartmentProfitServiceImpl.java

@@ -103,6 +103,7 @@ public class ComputeMedicalDepartmentProfitServiceImpl implements ComputeMedical
         if(CollectionUtils.isEmpty(byReportType)){
             throw new CostException("未找到【"+reportType+"】对应的报表项目");
         }
+        Map<Long, List<ReportForm>> reportIdMap = byReportType.stream().collect(Collectors.groupingBy(ReportForm::getId));
         Map<Long,Integer> sortMap = new HashMap<>();
         Map<Long,Integer> hideMap = new HashMap<>();
         for (ReportForm reportForm : byReportType) {
@@ -167,6 +168,16 @@ public class ComputeMedicalDepartmentProfitServiceImpl implements ComputeMedical
             vo.setNum(profit.getReportNum());
             vo.setReportType(Integer.valueOf(reportType));
             vo.setSort(profit.getSort());
+            List<ReportForm> profitReportFormList = reportIdMap.get(profit.getReportId());
+            if(!CollectionUtils.isEmpty(profitReportFormList)) {
+                vo.setDataType(profitReportFormList.get(NumberConstant.ZERO).getDataType());
+                vo.setDecimalPlace(profitReportFormList.get(NumberConstant.ZERO).getDecimalPlace());
+                vo.setPermil(profitReportFormList.get(NumberConstant.ZERO).getPermil());
+            }else {
+                vo.setDataType(NumberConstant.ONE);
+                vo.setDecimalPlace(NumberConstant.TWO);
+                vo.setPermil(NumberConstant.ONE);
+            }
             reportFormProfitVos.add(vo);
         }
 
@@ -369,6 +380,7 @@ public class ComputeMedicalDepartmentProfitServiceImpl implements ComputeMedical
         //通过查询的最下层责任中心 找到其所有父类责任中心
         List<MedicalResponsibilityVo> parentResponseList = new ArrayList<>();
         for (MedicalResponsibilityVo responsibility : computeResponsibityList) {
+            log.info(String.format("查询责任中心{%s}的父级ID{%s}", responsibility.getResponsibilityCode(),responsibility.getParentId()));
             if (responsibility.getParentId().equals(NumberConstant.ZERO_L)) {
                 parentResponseList.add(responsibility);
             } else {

+ 14 - 0
src/main/java/com/kcim/service/impl/CostAccountShareDetailServiceImpl.java

@@ -0,0 +1,14 @@
+package com.kcim.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.dao.mapper.CostAccountShareDetailMapper;
+import com.kcim.dao.model.CostAccountShareDetail;
+import com.kcim.service.CostAccountShareDetailService;
+import org.springframework.stereotype.Service;
+
+
+@Service("costAccountShareDetailService")
+public class CostAccountShareDetailServiceImpl extends ServiceImpl<CostAccountShareDetailMapper, CostAccountShareDetail> implements CostAccountShareDetailService {
+
+
+}

+ 14 - 0
src/main/java/com/kcim/service/impl/CostAccountShareParamServiceImpl.java

@@ -0,0 +1,14 @@
+package com.kcim.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.kcim.dao.mapper.CostAccountShareParamMapper;
+import com.kcim.dao.model.CostAccountShareParam;
+import com.kcim.service.CostAccountShareParamService;
+import org.springframework.stereotype.Service;
+
+
+@Service("costAccountShareParamService")
+public class CostAccountShareParamServiceImpl extends ServiceImpl<CostAccountShareParamMapper, CostAccountShareParam> implements CostAccountShareParamService {
+
+
+}

+ 258 - 11
src/main/java/com/kcim/service/impl/CostAccountShareServiceImpl.java

@@ -13,16 +13,17 @@ import com.kcim.common.util.JacksonUtil;
 import com.kcim.common.util.PageUtils;
 import com.kcim.common.util.UserContext;
 import com.kcim.dao.mapper.CostAccountShareMapper;
-import com.kcim.dao.model.Accounting;
-import com.kcim.dao.model.CostAccountShare;
-import com.kcim.dao.model.CostShareLevel;
-import com.kcim.dao.model.Responsibility;
+import com.kcim.dao.model.*;
 import com.kcim.dao.model.dto.AccountShareCopyDto;
 import com.kcim.dao.model.dto.CostAccountShareEditDto;
 import com.kcim.dao.model.dto.CostAccountShareSaveDto;
 import com.kcim.dao.model.dto.ShareParamEditDto;
+import com.kcim.dao.repository.CostAccountShareDetailRepository;
+import com.kcim.dao.repository.CostAccountShareParamRepository;
+import com.kcim.dao.repository.CostAccountShareTargetRepository;
 import com.kcim.service.*;
 import com.kcim.vo.*;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
@@ -37,6 +38,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 @Slf4j
+@AllArgsConstructor
 @Service("costAccountShareService")
 public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMapper, CostAccountShare> implements CostAccountShareService {
 
@@ -48,13 +50,19 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
 
     private final CostShareParamService costShareParamService;
 
+    private final CostAccountShareDetailRepository costAccountShareDetailRepository;
+    private final CostAccountShareParamRepository costAccountShareParamRepository;
+    private final CostAccountShareTargetRepository costAccountShareTargetRepository;
 
-    public CostAccountShareServiceImpl(ResponsibilityService responsibilityService, AccountingService accountingService, CostShareLevelService costShareLevelService, CostShareParamService costShareParamService) {
-        this.responsibilityService = responsibilityService;
-        this.accountingService = accountingService;
-        this.costShareLevelService = costShareLevelService;
-        this.costShareParamService = costShareParamService;
-    }
+
+//    public CostAccountShareServiceImpl(CostAccountShareParamService costAccountShareParamService,CostAccountShareDetailService costAccountShareDetailService,ResponsibilityService responsibilityService, AccountingService accountingService, CostShareLevelService costShareLevelService, CostShareParamService costShareParamService) {
+//        this.responsibilityService = responsibilityService;
+//        this.accountingService = accountingService;
+//        this.costShareLevelService = costShareLevelService;
+//        this.costShareParamService = costShareParamService;
+//        this.costAccountShareDetailService = costAccountShareDetailService;
+//        this.costAccountShareParamService = costAccountShareParamService;
+//    }
 
     /**
      * 分页查询责任中心成本对照相关数据
@@ -157,6 +165,8 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
         costAccountShareRequest.setHospId(hospId);
         costAccountShareRequest.setCreateTime(System.currentTimeMillis());
         baseMapper.insert(costAccountShareRequest);
+        //提交分摊设置对应的会计科目
+        applyShareParamProportion(costAccountShareRequest.getId(),costAccountShareRequest.getAccountingCodes());
     }
 
     /**
@@ -278,6 +288,38 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
         BeanUtil.convertObj(accountShareEditDto, costAccountShare);
         costAccountShare.setId(costAccountShareEditDto.getId());
         baseMapper.updateById(costAccountShare);
+        //提交分摊设置对应的会计科目
+        applyShareParamProportion(costAccountShare.getId(),costAccountShare.getAccountingCodes());
+    }
+
+    /**
+     * 提交分摊设置对应的会计科目
+     * @param accountShareId
+     * @param accountingCodes
+     */
+    public void applyShareParamProportion(Long accountShareId , String accountingCodes ){
+        if(StringUtils.isEmpty(accountingCodes)){
+            //先作废上次的数据
+            costAccountShareDetailRepository.delCostAccountShareDetail(accountShareId);
+            return;
+        }
+        List<String> accountingCodeList = Arrays.stream(accountingCodes.split(StrUtil.COMMA)).collect(Collectors.toList());
+        applyAccountShareDetail(accountShareId,accountingCodeList);
+    }
+
+
+    /**
+     * 提交分摊设置对应的会计科目
+     * @param accountShareId
+     * @param accountingCodeList
+     */
+    public void applyAccountShareDetail(Long accountShareId , List<String> accountingCodeList){
+        //先作废上次的数据
+        costAccountShareDetailRepository.delCostAccountShareDetail(accountShareId);
+        //保存新的分摊参数
+        List<CostAccountShareDetail> costAccountShareDetailList = accountingCodeList.stream().map(accountingCode ->
+                createCostAccountShareDetail(accountShareId,accountingCode)).collect(Collectors.toList());
+        costAccountShareDetailRepository.saveBatch(costAccountShareDetailList);
     }
 
 
@@ -331,6 +373,8 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
             String paramList = JacksonUtil.obj2StrPretty(shareParamProportionVOList);
 
             costAccountShare.setParamList(paramList);
+            //提交分摊参数
+            applyShareParamProportion(shareParamEditDto);
         } else {
             costAccountShare.setParamList(null);
         }
@@ -338,6 +382,20 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
         baseMapper.updateById(costAccountShare);
     }
 
+    /**
+     * 提交分摊参数
+     * @param shareParamEditDto
+     */
+    public void applyShareParamProportion(ShareParamEditDto shareParamEditDto){
+        //先作废上次的数据
+        costAccountShareParamRepository.delCostAccountParamDetail(shareParamEditDto.getId());
+        //保存新的分摊参数
+        List<ShareParamProportionVO> newShareParamList = shareParamEditDto.getShareParamProportionVOList();
+        List<CostAccountShareParam> costAccountShareParamList = newShareParamList.stream().map(newShareParam ->
+                createCostAccountShareParam(shareParamEditDto.getId(),newShareParam.getShareParamCode(),newShareParam.getShareParamPopout())).collect(Collectors.toList());
+        costAccountShareParamRepository.saveBatch(costAccountShareParamList);
+    }
+
     /**
      * 获取责任中心成本表的分摊参数的集合
      *
@@ -422,7 +480,10 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
             accountShareList.add(accountShareRequest);
         });
         this.saveBatch(accountShareList);
-
+        //主表向明细表同步
+        synMainCostAccountShare(accountShareList);
+        //复制目标责任中心设置
+        copyCostAccountShareTarget(accountShareCopyDto,accountShareList);
     }
 
     /**
@@ -500,6 +561,8 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
     public void deleteByIds(List<Long> idList) {
         this.removeByIds(idList);
+        costAccountShareDetailRepository.delCostAccountShareDetailList(idList);
+        costAccountShareParamRepository.delCostAccountShareParamList(idList);
     }
 
     @Override
@@ -510,4 +573,188 @@ public class CostAccountShareServiceImpl extends ServiceImpl<CostAccountShareMap
         );
     }
 
+    /**
+     *
+     * @param direction 1主表向明细表同步 2明细表向主表同步
+     * @param accountShareId
+     */
+    @Override
+    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
+    public void synCostAccountShare(Integer direction, Long accountShareId) {
+        if(NumberConstant.ONE.equals(direction)){
+            synMainCostAccountShare(direction,accountShareId);
+        }
+    }
+
+    /**
+     * 主表向明细表同步
+     * @param direction
+     * @param accountShareId
+     */
+    public void synMainCostAccountShare(Integer direction, Long accountShareId) {
+        List<CostAccountShare> costAccountShareList = getCostAccountShareList(accountShareId);
+        if (CollectionUtils.isEmpty(costAccountShareList)) {
+            return;
+        }
+        synMainCostAccountShare(costAccountShareList);
+    }
+
+    /**
+     * 主表向明细表同步
+     * @param costAccountShareList
+     */
+    public void synMainCostAccountShare(List<CostAccountShare> costAccountShareList){
+        //生成分摊设置对应的会计科目对象
+        List<CostAccountShareDetail> fullCostAccountShareDetailList=new ArrayList<>();
+        //生成分摊设置对应的分摊参数对象
+        List<CostAccountShareParam> fullCostAccountShareParamList=new ArrayList<>();
+        //按主表的数据逐个转成会计科目对象和分摊参数对象
+        costAccountShareList.stream().forEach(costAccountShare->{
+            //处理会计科目
+            String accountingCodes = costAccountShare.getAccountingCodes();
+            if(!StringUtils.isEmpty(accountingCodes)){
+                List<String> accountingCodeList = Arrays.stream(accountingCodes.split(StrUtil.COMMA)).collect(Collectors.toList());
+                List<CostAccountShareDetail> costAccountShareDetailList = accountingCodeList.stream().map(accountingCode ->
+                        createCostAccountShareDetail(costAccountShare.getId(),accountingCode)).collect(Collectors.toList());
+                fullCostAccountShareDetailList.addAll(costAccountShareDetailList);
+            }
+
+            //处理分摊参数
+            String paramList = costAccountShare.getParamList();
+            if(!StringUtils.isEmpty(paramList)) {
+                List<ShareParamProportionVO> shareParamProportionVOS = JacksonUtil.str2ObjList(paramList, new TypeReference<List<ShareParamProportionVO>>() {
+                });
+                List<CostAccountShareParam> costAccountShareParamList = shareParamProportionVOS.stream().map(shareParamProportion ->
+                                createCostAccountShareParam(costAccountShare.getId(), shareParamProportion.getShareParamCode(), shareParamProportion.getShareParamPopout())).
+                        collect(Collectors.toList());
+                fullCostAccountShareParamList.addAll(costAccountShareParamList);
+            }
+        });
+        //作废原来的数据
+        List<Long> accountShareIdList = costAccountShareList.stream().map(CostAccountShare::getId).collect(Collectors.toList());
+        costAccountShareDetailRepository.delCostAccountShareDetailList(accountShareIdList);
+        costAccountShareParamRepository.delCostAccountShareParamList(accountShareIdList);
+        //保存会计科目对象
+        if (!CollectionUtils.isEmpty(fullCostAccountShareDetailList)) {
+            costAccountShareDetailRepository.saveBatch(fullCostAccountShareDetailList,NumberConstant.ONE_HUNDRED);
+        }
+        //保存分摊参数对象
+        if (!CollectionUtils.isEmpty(fullCostAccountShareParamList)) {
+            costAccountShareParamRepository.saveBatch(fullCostAccountShareParamList,NumberConstant.ONE_HUNDRED);
+        }
+    }
+
+    /**
+     * 创建分摊设置对应的会计科目对象
+     * @param accountShareId
+     * @param accountingCode
+     * @return
+     */
+    public CostAccountShareDetail createCostAccountShareDetail(Long accountShareId,String accountingCode){
+        CostAccountShareDetail costAccountShareDetail = new CostAccountShareDetail();
+        costAccountShareDetail.setHospId(UserContext.getHospId());
+        costAccountShareDetail.setAccountShareId(accountShareId);
+        costAccountShareDetail.setAccountingCode(accountingCode);
+        costAccountShareDetail.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+        costAccountShareDetail.setCreateTime(new Date());
+        return costAccountShareDetail;
+    }
+
+    /**
+     * 创建分摊设置对应的分摊参数对象
+     * @param accountShareId
+     * @param shareParamCode
+     * @param shareParamProportion
+     * @return
+     */
+    public CostAccountShareParam createCostAccountShareParam(Long accountShareId,String shareParamCode,BigDecimal shareParamProportion) {
+        CostAccountShareParam costAccountShareParam = new CostAccountShareParam();
+        costAccountShareParam.setHospId(UserContext.getHospId());
+        costAccountShareParam.setAccountShareId(accountShareId);
+        costAccountShareParam.setShareParamCode(shareParamCode);
+        costAccountShareParam.setShareParamProportion(shareParamProportion);
+        costAccountShareParam.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+        costAccountShareParam.setCreateTime(new Date());
+        return costAccountShareParam;
+    }
+
+    /**
+     * 获取所有的分摊参数配置
+     * @return
+     */
+    public  List<CostAccountShare> getCostAccountShareList(Long accountShareId){
+        LambdaQueryWrapper<CostAccountShare> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(CostAccountShare::getHospId, UserContext.getHospId());
+        queryWrapper.eq(CostAccountShare::getDeleteTime, NumberConstant.ZERO);
+        if(!ObjectUtils.isEmpty(accountShareId)){
+            queryWrapper.eq(CostAccountShare::getId, accountShareId);
+        }
+        return baseMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 复制目标责任中心设置
+     * @param accountShareCopyDto
+     * @param accountShareList
+     */
+    public void copyCostAccountShareTarget(AccountShareCopyDto accountShareCopyDto,List<CostAccountShare> accountShareList){
+        //没有指定的复制目标
+        if(CollectionUtils.isEmpty(accountShareList)){
+            return;
+        }
+        List<CostAccountShareTarget> costAccountShareTargetList = costAccountShareTargetRepository.getCostAccountShareTarget(accountShareCopyDto.getId());
+        //没有设置指定的分摊目标责任中心
+        if(CollectionUtils.isEmpty(costAccountShareTargetList)){
+            return;
+        }
+        //逐个分摊设置复制目标责任中心
+        List<CostAccountShareTarget> copyCostAccountShareTargetList=new ArrayList<>();
+        for (CostAccountShare costAccountShare : accountShareList) {
+            List<CostAccountShareTarget> copyTargetList = costAccountShareTargetList.stream().map(target -> createCostAccountShareTarget(costAccountShare.getId(), target.getTargetResponsibilityCode())).collect(Collectors.toList());
+            copyCostAccountShareTargetList.addAll(copyTargetList);
+        }
+        //保存复制的数据
+        if(CollectionUtils.isEmpty(copyCostAccountShareTargetList)) {
+            costAccountShareTargetRepository.saveBatch(copyCostAccountShareTargetList);
+        }
+    }
+
+    @Override
+    public void applyAccountShareTarget(ShareTargetMapVo shareTargetMapVo) {
+        applyAccountShareTarget(shareTargetMapVo.getAccountShareId(),shareTargetMapVo.getTargetRespCodeList());
+    }
+    /**
+     * 提交分摊设置对应的目标责任中心
+     * @param accountShareId
+     * @param respCodeList
+     */
+    public void applyAccountShareTarget(Long accountShareId , List<String> respCodeList){
+        //先作废上次的数据
+        costAccountShareTargetRepository.delCostAccountShareTarget(accountShareId);
+        //没有新的目标责任中心时不用处理
+        if(CollectionUtils.isEmpty(respCodeList)){
+            return;
+        }
+        //保存新的目标责任中心
+        List<CostAccountShareTarget> costAccountShareTargetList = respCodeList.stream().map(respCode ->
+                createCostAccountShareTarget(accountShareId, respCode)).collect(Collectors.toList());
+        costAccountShareTargetRepository.saveBatch(costAccountShareTargetList);
+    }
+
+    /**
+     * 生成分摊设置对应的目标责任中心对象
+     * @param accountShareId
+     * @param targetResponsibilityCode
+     * @return
+     */
+    public CostAccountShareTarget createCostAccountShareTarget(Long accountShareId,String targetResponsibilityCode) {
+        CostAccountShareTarget costAccountShareTarget = new CostAccountShareTarget();
+        costAccountShareTarget.setHospId(UserContext.getHospId());
+        costAccountShareTarget.setAccountShareId(accountShareId);
+        costAccountShareTarget.setTargetResponsibilityCode(targetResponsibilityCode);
+        costAccountShareTarget.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+        costAccountShareTarget.setCreateTime(new Date());
+        return costAccountShareTarget;
+    }
+
 }

+ 15 - 0
src/main/java/com/kcim/service/impl/CostAccountShareTargetService.java

@@ -0,0 +1,15 @@
+package com.kcim.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.kcim.dao.model.CostAccountShareTarget;
+
+/**
+ * 成本分摊对应的分摊目标责任中心
+ *
+ * @author Wang.YS
+ * @date 2025-04-03 11:13:36
+ */
+public interface CostAccountShareTargetService extends IService<CostAccountShareTarget> {
+
+}
+

+ 4 - 2
src/main/java/com/kcim/service/impl/CostCostingGroupServiceImpl.java

@@ -24,6 +24,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.math.BigDecimal;
@@ -124,11 +125,12 @@ public class CostCostingGroupServiceImpl extends ServiceImpl<CostCostingGroupMap
 
         List<AllocationVO> list = baseMapper.queryAllocation(startIndex, pageSize, year, month, hospId);
         list.forEach(i -> {
-            List<Allocation> collections = allocationMapper.selectList(new LambdaQueryWrapper<Allocation>().eq(Allocation::getDateYear, i.getYear())
+            Allocation allocation = allocationMapper.selectOne(new LambdaQueryWrapper<Allocation>().eq(Allocation::getDateYear, i.getYear())
                     .eq(Allocation::getDateMonth, i.getMonth())
                     .eq(Allocation::getHospId, hospId)
+                    .last("LIMIT 1")
             );
-            if (!collections.isEmpty()) {
+            if (!ObjectUtils.isEmpty(allocation)) {
                 i.setIsAllocation(true);
             }
         });

+ 1365 - 50
src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java

@@ -12,10 +12,8 @@ import cn.hutool.poi.excel.ExcelWriter;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.ImmutableMap;
-import com.kcim.common.constants.NumberConstant;
-import com.kcim.common.constants.SQLParameter;
+import com.kcim.common.constants.*;
 import com.kcim.common.enums.CustomSqlTypeEnum;
 import com.kcim.common.enums.DateStyleEnum;
 import com.kcim.common.enums.ErrorCodeEnum;
@@ -28,14 +26,14 @@ import com.kcim.common.util.excel.entity.ColEntity;
 import com.kcim.common.util.excel.entity.TitleEntity;
 import com.kcim.dao.mapper.CostDepartmentProfitMapper;
 import com.kcim.dao.model.*;
-import com.kcim.dao.repository.ComputeLastProfitDateRepository;
-import com.kcim.dao.repository.CostDepartmentProfitRepository;
+import com.kcim.dao.repository.*;
 import com.kcim.service.*;
 import com.kcim.vo.*;
 import com.kcim.web.reponse.BatchCostProfitResponse;
 import com.kcim.web.reponse.ComputeProfitCollectResponse;
 import com.kcim.web.reponse.CostProfitRedirectResponse;
 import com.kcim.web.reponse.ProfitReportResponse;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.FileItemFactory;
@@ -51,6 +49,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
@@ -73,7 +72,8 @@ import static com.kcim.common.constants.ParameterConstant.MEDICAL_TECHNIQUES_SHA
 
 @Service("costDepartmentProfitService")
 @Slf4j
-public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentProfitMapper, CostDepartmentProfit> implements CostDepartmentProfitService {
+@AllArgsConstructor
+public class CostDepartmentProfitServiceImpl extends BaseBatchServiceImpl<CostDepartmentProfitMapper, CostDepartmentProfit> implements CostDepartmentProfitService {
 
 //    @Value("${file.filelocal}")
 //    private String hospProfitReportUrl;
@@ -111,8 +111,12 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 
     private final CostAccountShareService costAccountShareService;
 
-    private final UserResponsibilityRightService userResponsibilityRightService ;
+    private final UserResponsibilityRightService userResponsibilityRightService;
 
+    ResponsibilityRepository responsibilityRepository;
+
+    CostDepartmentProfitAccountRepository costDepartmentProfitAccountRepository;
+    AccountingRepository accountingRepository;
 
     private final SqlService sqlService;
     private final String AMOUNT = "金额";
@@ -122,26 +126,26 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
     private final String AMOUNT_FIELD = "amount";
 
     private final String PERCENT_FIELD = "percent";
-
-    public CostDepartmentProfitServiceImpl(ReportFormService reportFormService, IncomeCollectionService incomeCollectionService, CostShareLevelService costShareLevelService, ResponsibilityService responsibilityService, ReportRelationService reportRelationService, AllocationService allocationService, AllocationQueryService allocationQueryService, FileRecordService fileRecordService, MinioConfig minioConfig, MinioFileUtil minioFileUtil, CenterService centerService, CostDepartmentProfitRepository costDepartmentProfitRepository, ComputeLastProfitDateRepository computeLastProfitDateRepository, AccountingService accountingService, CostAccountShareService costAccountShareService, SqlService sqlService,UserResponsibilityRightService userResponsibilityRightService) {
-        this.reportFormService = reportFormService;
-        this.incomeCollectionService = incomeCollectionService;
-        this.costShareLevelService = costShareLevelService;
-        this.responsibilityService = responsibilityService;
-        this.reportRelationService = reportRelationService;
-        this.allocationService = allocationService;
-        this.allocationQueryService = allocationQueryService;
-        this.fileRecordService = fileRecordService;
-        this.minioConfig = minioConfig;
-        this.minioFileUtil = minioFileUtil;
-        this.centerService = centerService;
-        this.costDepartmentProfitRepository = costDepartmentProfitRepository;
-        this.computeLastProfitDateRepository = computeLastProfitDateRepository;
-        this.accountingService = accountingService;
-        this.costAccountShareService = costAccountShareService;
-        this.sqlService = sqlService;
-        this.userResponsibilityRightService=userResponsibilityRightService;
-    }
+//
+//    public CostDepartmentProfitServiceImpl(ReportFormService reportFormService, IncomeCollectionService incomeCollectionService, CostShareLevelService costShareLevelService, ResponsibilityService responsibilityService, ReportRelationService reportRelationService, AllocationService allocationService, AllocationQueryService allocationQueryService, FileRecordService fileRecordService, MinioConfig minioConfig, MinioFileUtil minioFileUtil, CenterService centerService, CostDepartmentProfitRepository costDepartmentProfitRepository, ComputeLastProfitDateRepository computeLastProfitDateRepository, AccountingService accountingService, CostAccountShareService costAccountShareService, SqlService sqlService, UserResponsibilityRightService userResponsibilityRightService) {
+//        this.reportFormService = reportFormService;
+//        this.incomeCollectionService = incomeCollectionService;
+//        this.costShareLevelService = costShareLevelService;
+//        this.responsibilityService = responsibilityService;
+//        this.reportRelationService = reportRelationService;
+//        this.allocationService = allocationService;
+//        this.allocationQueryService = allocationQueryService;
+//        this.fileRecordService = fileRecordService;
+//        this.minioConfig = minioConfig;
+//        this.minioFileUtil = minioFileUtil;
+//        this.centerService = centerService;
+//        this.costDepartmentProfitRepository = costDepartmentProfitRepository;
+//        this.computeLastProfitDateRepository = computeLastProfitDateRepository;
+//        this.accountingService = accountingService;
+//        this.costAccountShareService = costAccountShareService;
+//        this.sqlService = sqlService;
+//        this.userResponsibilityRightService = userResponsibilityRightService;
+//    }
 
     /**
      * 查询科室损益数据
@@ -346,7 +350,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
                 i.setAmount(setSubtotal(i, costShareLevelList, listMap, list, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList, allList));
             } else if (NumberConstant.FOUR.equals(calcType)) {
                 // TODO 按照计算公式进行计算
-//                i.setAmount(setCalculation(i, list, costShareLevelList, listMap, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList, allList));
+                i.setAmount(setCalculation(i, list, costShareLevelList, listMap, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList, allList));
             } else if (NumberConstant.FIVE.equals(calcType)) {
                 // TODO  按照责任中心进行计算
                 i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList, allList));
@@ -1112,11 +1116,29 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
     }
 
     @Override
-    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
     public void computeProfit(String computeDate, Long hospId, String reportType) {
+        //需要用代码计算时
+        if(IsNeedCalc(reportType)){
+            String parameterValue = centerService.getParameterValue(ParameterConstant.ALLOCATION_TYPE);
+            if (NumberConstant.ONE_S.equals(parameterValue)) {
+                //按责任中心分摊的科室损益计算
+                computeProfitAction(computeDate, hospId, reportType);
+            }else if (NumberConstant.TWO_S.equals(parameterValue)) {
+                //按会计科目分摊的科室损益计算
+                calcDeptProfit(computeDate, hospId, reportType);
+            }
+            //计算同环比
+            handleSpecificMonthsCalculation(hospId, computeDate, reportType);
+        }
+        execDeptProfitSql(computeDate, reportType);
+    }
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    public void computeProfitAction(String computeDate, Long hospId, String reportType) {
 //        DateTime parse = DateUtil.parse(computeDate);
 //        int year = DateUtil.year(parse);
 //        int month = DateUtil.month(parse) + 1;
+        Long userId = UserContext.getCurrentUser().getId();
         Integer year = ComputeDateUtils.getComputeYear(computeDate);
         Integer month = ComputeDateUtils.getComputeMonth(computeDate);
         // 先查询指定条件的报表数据  查询损益表的数据
@@ -1200,14 +1222,238 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 
         this.saveBatch(costDepartmentProfits);
         //记录最后一次 损益计算日期
-        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
+        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate,userId);
+    }
+
+    /**
+     * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
+     *
+     * @param hospId      院区ID
+     * @param computeDate 日期字符串,格式:YYYY-MM
+     * @param shareType   报表类型
+     */
+    public void handleSpecificMonthsCalculation(Long hospId, String computeDate, String shareType) {
+        // 解析输入的年月
+        Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
+        Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
+        // 计算需要处理的期间信息
+        List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
+
+        // 获取所有相关的期间数据
+        Map<String, List<CostDepartmentProfit>> allDataMap = loadAllPeriodData(hospId, shareType, periods);
+
+        // 对每个期间执行计算
+        for (PeriodInfoVO period : periods) {
+            String currentKey = buildPeriodKey(period.getYear(), period.getMonth());
+            if (allDataMap.containsKey(currentKey) && !CollectionUtils.isEmpty(allDataMap.get(currentKey))) {
+                List<CostDepartmentProfit> currentRecords = allDataMap.get(currentKey);
+                List<CostDepartmentProfit> prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth());
+                List<CostDepartmentProfit> lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth());
+
+                // 执行批量计算
+                calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords);
+            }
+        }
+    }
+
+    /**
+     * 构建所有需要处理的期间信息
+     */
+    private List<PeriodInfoVO> calculateAllRelatedPeriods(int baseYear, int baseMonth) {
+        List<PeriodInfoVO> result = new ArrayList<>();
+
+        // 添加当前期间
+        result.add(calculatePeriodInfo(baseYear, baseMonth));
+
+        // 下个月
+        int nextMonth = baseMonth + 1;
+        int nextMonthYear = baseYear;
+        if (baseMonth == 12) {
+            nextMonth = 1;
+            nextMonthYear += 1;
+        }
+        result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
+
+        // 明年同月
+        result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
+
+        return result;
+    }
+
+    /**
+     * 构建单个期间的信息(当前月、上月、去年同期)
+     */
+    private PeriodInfoVO calculatePeriodInfo(int year, int month) {
+        PeriodInfoVO info = new PeriodInfoVO();
 
-        Map<String,String> sqlParameter = new HashMap<>();
-        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,computeDate);
-        sqlParameter.put(SQLParameter.REPORT_TYPE_CODE,reportType);
-        sqlService.autoExecuteSql(CustomSqlTypeEnum.DEPT_PROFIT_CALC.getCode(),sqlParameter);
+        info.setYear( year);
+        info.setMonth( month);
+
+        // 上期
+        if (month == 1) {
+            info.setPrevYear(year - 1);
+            info.setPrevMonth(12);
+        } else {
+            info.setPrevYear( year);
+            info.setPrevMonth(month - 1);
+        }
+
+        // 同期
+        info.setLastYear(year - 1);
+        info.setLastMonth( month);
+
+        return info;
+    }
+
+    /**
+     * 加载所有相关期间的数据(去重处理)
+     */
+    private Map<String, List<CostDepartmentProfit>> loadAllPeriodData(Long hospId, String shareType, List<PeriodInfoVO> periods) {
+        Set<String> allPeriodKeys = new HashSet<>();
+
+        // 收集所有需要查询的年月组合
+        for (PeriodInfoVO period : periods) {
+            allPeriodKeys.add(buildPeriodKey(period.getYear(), period.getMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getPrevYear(), period.getPrevMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getLastYear(), period.getLastMonth()));
+        }
+
+        // 去重后查询
+        Map<String, List<CostDepartmentProfit>> result = new HashMap<>();
+        Set<String> processedKeys = new HashSet<>(); // 已处理的键集合
+
+        for (String key : allPeriodKeys) {
+            if (!processedKeys.contains(key)) {
+                int[] ym = parsePeriodKey(key);
+                List<CostDepartmentProfit> records = getPeriodRecords(hospId, shareType, ym[0], ym[1]);
+                result.put(key, records);
+                processedKeys.add(key); // 标记为已处理
+            }
+        }
+
+        return result;
     }
 
+
+    /**
+     * 获取指定期间的数据
+     *
+     * @param hospId    院区ID
+     * @param shareType 报表类型
+     * @param year      年份
+     * @param month     月份
+     * @return 符合条件的数据列表
+     */
+    private List<CostDepartmentProfit> getPeriodRecords(Long hospId, String shareType, int year, int month) {
+        return this.list(new QueryWrapper<CostDepartmentProfit>().lambda()
+                .eq(CostDepartmentProfit::getHospId, hospId)
+                .eq(CostDepartmentProfit::getShareType, shareType)
+                .eq(CostDepartmentProfit::getYear, year)
+                .eq(CostDepartmentProfit::getMonth, month)
+                .eq(CostDepartmentProfit::getDeleteTime, 0));
+    }
+
+    /**
+     * 根据年月获取对应的数据(从内存中查找)
+     */
+    private List<CostDepartmentProfit> getPeriodData(Map<String, List<CostDepartmentProfit>> dataMap, int year, int month) {
+        String key = buildPeriodKey(year, month);
+        return dataMap.getOrDefault(key, Collections.emptyList());
+    }
+
+    /**
+     * 批量计算同环比及同期金额(使用预加载数据)
+     */
+    public void calculatePeriodComparisonWithPreloadedData(
+            List<CostDepartmentProfit> currentRecords,
+            List<CostDepartmentProfit> prevRecords,
+            List<CostDepartmentProfit> lastYearRecords) {
+
+        if (CollectionUtils.isEmpty(currentRecords)) {
+            return;
+        }
+
+        // 创建责任码+报表编号到记录的映射
+        Map<String, CostDepartmentProfit> prevMap = new HashMap<>();
+        for (CostDepartmentProfit record : prevRecords) {
+            String key = buildRecordKey(record);
+            prevMap.put(key, record);
+        }
+
+        Map<String, CostDepartmentProfit> lastYearMap = new HashMap<>();
+        for (CostDepartmentProfit record : lastYearRecords) {
+            String key = buildRecordKey(record);
+            lastYearMap.put(key, record);
+        }
+
+        // 批量更新数据
+        for (CostDepartmentProfit record : currentRecords) {
+            String key = buildRecordKey(record);
+            CostDepartmentProfit prevRecord = prevMap.get(key);
+            CostDepartmentProfit lastYearRecord = lastYearMap.get(key);
+
+            // 设置上期和同期金额
+            record.setPrevPeriodAmount(prevRecord != null ? prevRecord.getAmount() : BigDecimal.ZERO);
+            record.setSamePeriodAmount(lastYearRecord != null ? lastYearRecord.getAmount() : BigDecimal.ZERO);
+
+            // 计算环比和同比
+            record.setMomRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getPrevPeriodAmount()));
+            record.setYoyRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getSamePeriodAmount()));
+        }
+
+        // 批量更新数据库
+        this.updateBatchById(currentRecords);
+    }
+
+    /**
+     * 构建期间键(用于存储和检索数据)
+     */
+    private String buildPeriodKey(int year, int month) {
+        return year + "_" + month;
+    }
+
+    /**
+     * 解析期间键为年月数组
+     */
+    private int[] parsePeriodKey(String key) {
+        String[] parts = key.split("_");
+        return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1])};
+    }
+
+    /**
+     * 构建记录的唯一标识键(责任码 + 报表编号)
+     */
+    private String buildRecordKey(CostDepartmentProfit record) {
+        return record.getResponsibilityCode() + "_" + record.getReportNum();
+    }
+
+    /**
+     * 安全地计算百分比:避免除零错误
+     */
+    private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
+        if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
+        return bigDecimal;
+    }
+
+
+
+    /**
+     * 执行科室损益后续脚本
+     *
+     * @param computeDate
+     * @param reportType
+     */
+    public void execDeptProfitSql(String computeDate, String reportType) {
+        Map<String, String> sqlParameter = new HashMap<>();
+        sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE, computeDate);
+        sqlParameter.put(SQLParameter.REPORT_TYPE_CODE, reportType);
+        sqlService.autoExecuteSql(CustomSqlTypeEnum.DEPT_PROFIT_CALC.getCode(), sqlParameter);
+    }
+
+
     private DictDataVo getDictDataVo(String reportType) {
         DictDataVo dict = centerService.getDict(PROFIT_REPORT_TYPE);
         if (Objects.isNull(dict)) {
@@ -1246,8 +1492,14 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         if (CollUtil.isEmpty(reportFormList)) {
             throw new CostException(500, "损益表未找到");
         }
-        List<CommonTitleReportVo> commonTitleReportVos = reportFormList.stream().map(reportForm -> new CommonTitleReportVo(reportForm.getId(), reportForm.getParentId(), reportForm.getReportName(), reportForm.getSort())).collect(Collectors.toList());
-
+        List<CommonTitleReportVo> commonTitleReportVos = reportFormList.stream().map(reportForm -> {
+            CommonTitleReportVo commonTitleReportVo = new CommonTitleReportVo(reportForm.getId(), reportForm.getParentId(), reportForm.getReportName(), reportForm.getSort());
+            commonTitleReportVo.setDataType(reportForm.getDataType());
+            commonTitleReportVo.setDecimalPlace(reportForm.getDecimalPlace());
+            commonTitleReportVo.setPermil(reportForm.getPermil());
+            return commonTitleReportVo;
+        }).collect(Collectors.toList());
+//        List<CommonTitleReportVo> commonTitleReportVos = BeanUtil.convertList(reportFormList,CommonTitleReportVo.class);
         Map<Long, List<CommonTitleReportVo>> collect = commonTitleReportVos.stream().collect(Collectors.groupingBy(CommonTitleReportVo::getParentReportId));
         List<CommonTitleReportVo> titleReportVoList = collect.get(NumberConstant.ZERO_L);
         for (CommonTitleReportVo reportVo : titleReportVoList) {
@@ -1278,9 +1530,9 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         Map<Long, List<CostDepartmentProfit>> collectGroup = departmentProfits.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportId));
         for (ReportForm reportForm : reportFormList) {
             Integer hide = reportForm.getHide();
-            if(hide.equals(NumberConstant.ONE)){
+            if (hide.equals(NumberConstant.ONE)) {
                 List<CostDepartmentProfit> costDepartmentProfits = collectGroup.get(reportForm.getId());
-                if(!CollectionUtils.isEmpty(costDepartmentProfits)) {
+                if (!CollectionUtils.isEmpty(costDepartmentProfits)) {
                     filterProfit.addAll(costDepartmentProfits);
                 }
             }
@@ -1305,7 +1557,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             throw new CostException("未找到对应分摊层级责任中心");
         }
         //获取授权的责任中心
-        responsibilityList=userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
+        responsibilityList = userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
         //获取当前院区所有的责任中心
         List<Responsibility> responsibilityAllList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
                 .eq(Responsibility::getHospId, hospId));
@@ -1619,7 +1871,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             throw new CostException("未找到对应分摊层级责任中心");
         }
         //获取授权的责任中心
-        responsibilityList=userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
+        responsibilityList = userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
         List<Responsibility> responsibilityAllList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
                 .eq(Responsibility::getHospId, hospId));
         Map<Long, Responsibility> map = responsibilityAllList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b));
@@ -1703,10 +1955,10 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         Map<Long, List<CostDepartmentProfit>> collect1 = departmentProfits.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportId));
         for (ReportForm reportForm : reportFormList) {
             Integer hide = reportForm.getHide();
-            if(hide.equals(NumberConstant.ONE)){
+            if (hide.equals(NumberConstant.ONE)) {
 //                filterProfit.addAll(collect1.get(reportForm.getId()));
                 List<CostDepartmentProfit> costDepartmentProfits = collect1.get(reportForm.getId());
-                if(!CollectionUtils.isEmpty(costDepartmentProfits)) {
+                if (!CollectionUtils.isEmpty(costDepartmentProfits)) {
                     filterProfit.addAll(costDepartmentProfits);
                 }
             }
@@ -1715,11 +1967,22 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 
         Map<Long, Integer> sortMap = reportFormList.stream().collect(Collectors.toMap(ReportForm::getId, ReportForm::getSort, (a, b) -> b));
         Map<Long, String> descriptionMap = reportFormList.stream().collect(Collectors.toMap(ReportForm::getId, reportForm -> !StringUtils.isEmpty(reportForm.getDescription()) ? reportForm.getDescription() : "", (a, b) -> b));
+        Map<Long, List<ReportForm>> reportIdMap = reportFormList.stream().collect(Collectors.groupingBy(ReportForm::getId));
 
         List<CostProfitVo> costProfitVos = BeanUtil.convertList(filterProfit, CostProfitVo.class);
         costProfitVos.forEach(profitVo -> {
             profitVo.setDescription(descriptionMap.get(profitVo.getReportId()));
             profitVo.setSort(sortMap.get(profitVo.getReportId()));
+            List<ReportForm> profitReportFormList = reportIdMap.get(profitVo.getReportId());
+            if (!CollectionUtils.isEmpty(profitReportFormList)) {
+                profitVo.setDataType(profitReportFormList.get(NumberConstant.ZERO).getDataType());
+                profitVo.setDecimalPlace(profitReportFormList.get(NumberConstant.ZERO).getDecimalPlace());
+                profitVo.setPermil(profitReportFormList.get(NumberConstant.ZERO).getPermil());
+            } else {
+                profitVo.setDataType(NumberConstant.ONE);
+                profitVo.setDecimalPlace(NumberConstant.TWO);
+                profitVo.setPermil(NumberConstant.ONE);
+            }
         });
         Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
         List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
@@ -1773,15 +2036,16 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             if (CollUtil.isEmpty(reportFormList)) {
                 throw new CostException(500, "损益表未找到");
             }
+            Map<Long, List<ReportForm>> reportIdMap = reportFormList.stream().collect(Collectors.groupingBy(ReportForm::getId));
             List<CostDepartmentProfit> filterProfit = new ArrayList<>();
 
             Map<Long, List<CostDepartmentProfit>> collect1 = departmentProfits.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportId));
             for (ReportForm reportForm : reportFormList) {
                 Integer hide = reportForm.getHide();
-                if(hide.equals(NumberConstant.ONE)){
+                if (hide.equals(NumberConstant.ONE)) {
 //                    filterProfit.addAll(collect1.get(reportForm.getId()));
                     List<CostDepartmentProfit> costDepartmentProfits = collect1.get(reportForm.getId());
-                    if(!CollectionUtils.isEmpty(costDepartmentProfits)) {
+                    if (!CollectionUtils.isEmpty(costDepartmentProfits)) {
                         filterProfit.addAll(costDepartmentProfits);
                     }
                 }
@@ -1794,6 +2058,16 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             costProfitVos.forEach(profitVo -> {
                 profitVo.setDescription(descriptionMap.get(profitVo.getReportId()));
                 profitVo.setSort(sortMap.get(profitVo.getReportId()));
+                List<ReportForm> profitReportFormList = reportIdMap.get(profitVo.getReportId());
+                if (!CollectionUtils.isEmpty(profitReportFormList)) {
+                    profitVo.setDataType(profitReportFormList.get(NumberConstant.ZERO).getDataType());
+                    profitVo.setDecimalPlace(profitReportFormList.get(NumberConstant.ZERO).getDecimalPlace());
+                    profitVo.setPermil(profitReportFormList.get(NumberConstant.ZERO).getPermil());
+                } else {
+                    profitVo.setDataType(NumberConstant.ONE);
+                    profitVo.setDecimalPlace(NumberConstant.TWO);
+                    profitVo.setPermil(NumberConstant.ONE);
+                }
             });
             Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
             List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
@@ -1810,6 +2084,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             BatchCostProfitResponse response = new BatchCostProfitResponse();
             response.setComputeDate(beginComputeDate);
             response.setProfitVoList(costProfitParentVos);
+            response.setAllowDrillDown(true);
             responses.add(response);
             return responses;
         } else {
@@ -1819,6 +2094,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
                 throw new CostException("开始日期不能大于结束日期");
             }
             List<String> intervalMonthList = DateUtils.getIntervalMonthList(date, endDate);
+            List<CostProfitVo> allCostProfitVo=new ArrayList<>();
             if (!CollectionUtils.isEmpty(intervalMonthList)) {
                 for (String computeDates : intervalMonthList) {
                     Integer year = ComputeDateUtils.getComputeYear(computeDates);
@@ -1835,15 +2111,16 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
                     if (CollUtil.isEmpty(reportFormList)) {
                         throw new CostException(500, "损益表未找到");
                     }
+                    Map<Long, List<ReportForm>> reportIdMap = reportFormList.stream().collect(Collectors.groupingBy(ReportForm::getId));
                     List<CostDepartmentProfit> filterProfit = new ArrayList<>();
 
                     Map<Long, List<CostDepartmentProfit>> collect1 = departmentProfits.stream().collect(Collectors.groupingBy(CostDepartmentProfit::getReportId));
                     for (ReportForm reportForm : reportFormList) {
                         Integer hide = reportForm.getHide();
-                        if(hide.equals(NumberConstant.ONE)){
+                        if (hide.equals(NumberConstant.ONE)) {
 //                            filterProfit.addAll(collect1.get(reportForm.getId()));
                             List<CostDepartmentProfit> costDepartmentProfits = collect1.get(reportForm.getId());
-                            if(!CollectionUtils.isEmpty(costDepartmentProfits)) {
+                            if (!CollectionUtils.isEmpty(costDepartmentProfits)) {
                                 filterProfit.addAll(costDepartmentProfits);
                             }
                         }
@@ -1855,7 +2132,19 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
                     costProfitVos.forEach(profitVo -> {
                         profitVo.setDescription(descriptionMap.get(profitVo.getReportId()));
                         profitVo.setSort(sortMap.get(profitVo.getReportId()));
+                        List<ReportForm> profitReportFormList = reportIdMap.get(profitVo.getReportId());
+                        if (!CollectionUtils.isEmpty(profitReportFormList)) {
+                            profitVo.setDataType(profitReportFormList.get(NumberConstant.ZERO).getDataType());
+                            profitVo.setDecimalPlace(profitReportFormList.get(NumberConstant.ZERO).getDecimalPlace());
+                            profitVo.setPermil(profitReportFormList.get(NumberConstant.ZERO).getPermil());
+                        } else {
+                            profitVo.setDataType(NumberConstant.ONE);
+                            profitVo.setDecimalPlace(NumberConstant.TWO);
+                            profitVo.setPermil(NumberConstant.ONE);
+                        }
                     });
+                    //记录所有月份的科室损益数据
+                    allCostProfitVo.addAll(costProfitVos);
                     Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
                     List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
                     collect.remove(NumberConstant.ZERO_L);
@@ -1871,8 +2160,19 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
                     BatchCostProfitResponse response = new BatchCostProfitResponse();
                     response.setComputeDate(computeDates);
                     response.setProfitVoList(costProfitParentVos);
+                    response.setAllowDrillDown(true);
                     responses.add(response);
                 }
+                //获取月度汇总数据
+                List<CostProfitVo> costProfitVos = generateSummaryForMultipleMonths(allCostProfitVo);
+                if(!CollectionUtils.isEmpty(costProfitVos)){
+                    BatchCostProfitResponse response = new BatchCostProfitResponse();
+                    response.setComputeDate(String.format("%s至%s", beginComputeDate, endComputeDate));
+                    response.setProfitVoList(costProfitVos);
+                    response.setAllowDrillDown(false);
+                    response.setMonthlyAccumulation(true);
+                    responses.add(NumberConstant.ZERO,response);
+                }
                 return responses;
 
             } else {
@@ -1881,6 +2181,69 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
     }
 
+    /**
+     * 获取树状结构的科室损益数据
+     * @param costProfitVos
+     * @return
+     */
+    public List<CostProfitVo> getCostProfitVoTree(List<CostProfitVo> costProfitVos){
+        // 参数校验
+        if (CollectionUtils.isEmpty(costProfitVos)) {
+            return Collections.emptyList();
+        }
+        Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
+        List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
+        collect.remove(NumberConstant.ZERO_L);
+        for (CostProfitVo costProfitVo : costProfitParentVos) {
+            List<CostProfitVo> costProfitVo1 = collect.get(costProfitVo.getReportId());
+            if (!CollectionUtils.isEmpty(costProfitVo1)) {
+                costProfitVo.setChildren(setChildren(costProfitVo1, collect));
+            }
+        }
+        if (!CollectionUtils.isEmpty(costProfitParentVos)) {
+            costProfitParentVos.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
+        }
+        return  costProfitParentVos;
+    }
+
+    /**
+     * 生成多月份汇总的科室损益数据
+     *
+     * @param allCostProfitVo 原始数据列表
+     * @return 汇总后的科室损益数据
+     */
+    private List<CostProfitVo> generateSummaryForMultipleMonths(List<CostProfitVo> allCostProfitVo){
+        // 参数校验
+        if (CollectionUtils.isEmpty(allCostProfitVo)) {
+            return Collections.emptyList();
+        }
+        List<CostProfitVo> profitVoList=new ArrayList<>() ;
+        Map<Long, List<CostProfitVo>> reportGroup = allCostProfitVo.stream().collect(Collectors.groupingBy(CostProfitVo::getReportId));
+        reportGroup.forEach((reportId, profitVos) -> {
+            CostProfitVo costProfitVo = BeanUtil.convertObj(profitVos.get(NumberConstant.ZERO), CostProfitVo.class);
+            BigDecimal totalAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalBudgetAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getBudgetAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalPrevPeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getPrevPeriodAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalSamePeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getSamePeriodAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            costProfitVo.setAmount(totalAmount);
+            costProfitVo.setBudgetAmount(totalBudgetAmount);
+            costProfitVo.setPrevPeriodAmount(totalPrevPeriodAmount);
+            costProfitVo.setSamePeriodAmount(totalSamePeriodAmount);
+            costProfitVo.setCompletionRate(calculateRate(costProfitVo.getAmount(), costProfitVo.getBudgetAmount()));
+            costProfitVo.setMomRate(calculateRate(costProfitVo.getAmount().subtract(costProfitVo.getPrevPeriodAmount()), costProfitVo.getPrevPeriodAmount()));
+            costProfitVo.setYoyRate(calculateRate(costProfitVo.getAmount().subtract(costProfitVo.getSamePeriodAmount()), costProfitVo.getSamePeriodAmount()));
+            profitVoList.add(costProfitVo);
+        });
+        //转成树状结构
+        List<CostProfitVo> costProfitVoTree = getCostProfitVoTree(profitVoList);
+        return costProfitVoTree;
+    }
+
+
     @Override
     public Object getRedirectData(String computeDate, Long reportId, Long hospId, String reportType, String responsibilityCode) {
         //查询报表项目
@@ -2167,7 +2530,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             throw new CostException("未找到对应分摊层级责任中心");
         }
         //获取授权的责任中心
-        responsibilityList=userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
+        responsibilityList = userResponsibilityRightService.getAuthorizedResponsibility(responsibilityList);
         List<Responsibility> responsibilityAllList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
                 .eq(Responsibility::getHospId, hospId));
         Map<Long, Responsibility> map = responsibilityAllList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b));
@@ -2201,7 +2564,14 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             if (!CollectionUtils.isEmpty(responsibilities)) {
                 commonResponsibilityReportVo.setChild(getChildTitle(responsibilities, responsibilityGroup));
             } else {
-                commonResponsibilityReportVo.setChild(setDefalutChildList(responsibility));
+                //要显示占比时自动生成默认金额占比层
+                if (IsShowPercent()) {
+                    commonResponsibilityReportVo.setChild(setDefalutChildList(responsibility));
+                } else {
+                    //不显示占比时,直接责任中心作为金额层
+                    commonResponsibilityReportVo.setResponsibilityCode(commonResponsibilityReportVo.getResponsibilityCode() + AMOUNT_FIELD);
+                }
+
             }
             list.add(commonResponsibilityReportVo);
         }
@@ -2531,6 +2901,30 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 
     }
 
+    /**
+     * 是否显示占比
+     *
+     * @return
+     */
+    public boolean IsShowPercent() {
+        String parameterValue = centerService.getParameterValue(ParameterConstant.SHOW_PERCENT);
+        return NumberConstant.ONE_S.equals(parameterValue);
+    }
+
+    /**
+     * 是否需要代码计算
+     * @return
+     */
+    public boolean IsNeedCalc(String reportType) {
+        String parameterValue = centerService.getParameterValue(ParameterConstant.SQL_CALC_REPORT_TYPE);
+        if(StringUtils.isEmpty(parameterValue)){
+            return true;
+        }
+        //不需计算的报表类型列表
+        List<String> nonCalcReportTypeList = Arrays.stream(parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE)).collect(Collectors.toList());
+        return !nonCalcReportTypeList.contains(reportType);
+    }
+
     private List<CommonResponsibilityReportVo> getChildTitle(List<Responsibility> responsibilities, Map<Long, List<Responsibility>> responsibilityGroup) {
         List<CommonResponsibilityReportVo> list = new ArrayList<>();
         for (Responsibility responsibility : responsibilities) {
@@ -2542,8 +2936,15 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             if (!CollectionUtils.isEmpty(responsibilityChild)) {
                 commonResponsibilityReportVo.setChild(getChildTitle(responsibilityChild, responsibilityGroup));
             } else {
-                //添加金额占比
-                commonResponsibilityReportVo.setChild(setDefalutChildList(responsibility));
+//                //添加金额占比
+//                commonResponsibilityReportVo.setChild(setDefalutChildList(responsibility));
+                //要显示占比时自动生成默认金额占比层
+                if (IsShowPercent()) {
+                    commonResponsibilityReportVo.setChild(setDefalutChildList(responsibility));
+                } else {
+                    //不显示占比时,直接责任中心作为金额层
+                    commonResponsibilityReportVo.setResponsibilityCode(commonResponsibilityReportVo.getResponsibilityCode() + AMOUNT_FIELD);
+                }
             }
             list.add(commonResponsibilityReportVo);
         }
@@ -3136,4 +3537,918 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
         T.sort(Comparator.comparing(CostResponsibilityProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
     }
+
+    @Override
+    public Object getBatchComputeProfitListByYear(String startYear, String endYear, String reportType, String responsibilityCode) {
+        Integer integerReportType = Integer.valueOf(reportType);
+        Long hospId = UserContext.getHospId();
+        List<BatchCostProfitResponse> responses = new ArrayList<>();
+        // 解析起止年份
+        int startY = Integer.parseInt(startYear);
+        int endY = Integer.parseInt(endYear);
+
+        if (startY > endY) {
+            throw new CostException(500, "起始年份不能大于结束年份");
+        }
+        // 获取报表配置
+        List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
+                .eq(ReportForm::getHospId, hospId)
+                .eq(ReportForm::getDeleteTime, NumberConstant.ZERO)
+                .eq(ReportForm::getReportType, integerReportType));
+        if (CollUtil.isEmpty(reportFormList)) {
+            throw new CostException(500, "损益表未找到");
+        }
+        Map<Long, ReportForm> reportMap = reportFormList.stream()
+                .collect(Collectors.toMap(ReportForm::getId, report -> report));
+        // 取非隐藏的报表项目ID
+        List<Long> activeReportIdList = reportFormList.stream()
+                .filter(report -> NumberConstant.ONE.equals(report.getHide()))
+                .map(ReportForm::getId)
+                .collect(Collectors.toList());
+
+        // 获取当前年份和上一年度的汇总数据(一次性查询)
+        List<CostProfitVo> summaryList = this.baseMapper.getAnnualSummaryByYearRange(startY, endY, hospId, integerReportType, responsibilityCode);
+        List<CostProfitVo> preYearSummaryList = this.baseMapper.getAnnualSummaryByYearRange(startY - 1, endY - 1, hospId, integerReportType, responsibilityCode);
+
+        // 按年份分组处理数据
+        Map<Integer, List<CostProfitVo>> currentYearMap = new HashMap<>();
+        Map<Integer, List<CostProfitVo>> preYearMap = new HashMap<>();
+
+        // 将结果按年份分组
+        if (!CollectionUtils.isEmpty(summaryList)) {
+            currentYearMap = summaryList.stream()
+                    .collect(Collectors.groupingBy(CostProfitVo::getYear));
+        }
+
+        if (!CollectionUtils.isEmpty(preYearSummaryList)) {
+            preYearMap = preYearSummaryList.stream()
+                    .collect(Collectors.groupingBy(CostProfitVo::getYear));
+        }
+
+        // 遍历每个年份进行数据处理
+        for (int year = startY; year <= endY; year++) {
+            int previousYear = year - 1;
+
+            List<CostProfitVo> currentYearList = currentYearMap.get(year);
+            List<CostProfitVo> previousYearList = preYearMap.get(previousYear);
+
+            if (CollectionUtils.isEmpty(currentYearList)) {
+                continue;
+            }
+
+            // 只处理非隐藏的项目
+            List<CostProfitVo> activeCostProfitVo = currentYearList.stream()
+                    .filter(vo -> activeReportIdList.contains(vo.getReportId()))
+                    .collect(Collectors.toList());
+            if (CollectionUtils.isEmpty(activeCostProfitVo)) {
+                continue;
+            }
+
+            // 创建映射以便快速查找上一年的数据
+            Map<Long, CostProfitVo> preYearCostProfitMap = new HashMap<>();
+            if (!CollectionUtils.isEmpty(previousYearList)) {
+                preYearCostProfitMap = previousYearList.stream()
+                        .collect(Collectors.toMap(CostProfitVo::getReportId, costProfitVo -> costProfitVo));
+            }
+
+            // 计算完成率、环比、同比
+            for (CostProfitVo vo : activeCostProfitVo) {
+                // 设置同期数据
+                if (preYearCostProfitMap.containsKey(vo.getReportId())) {
+                    vo.setSamePeriodAmount(preYearCostProfitMap.get(vo.getReportId()).getAmount());
+                } else {
+                    vo.setSamePeriodAmount(BigDecimal.ZERO);
+                }
+
+                vo.setCompletionRate(calculateRate(vo.getAmount(), vo.getBudgetAmount()));
+                vo.setMomRate(calculateRate(vo.getAmount().subtract(vo.getPrevPeriodAmount()), vo.getPrevPeriodAmount()));
+                vo.setYoyRate(calculateRate(vo.getAmount().subtract(vo.getSamePeriodAmount()), vo.getSamePeriodAmount()));
+
+                // 设置报表相关属性
+                ReportForm reportForm = reportMap.get(vo.getReportId());
+                if (reportForm != null) {
+                    vo.setDescription(reportForm.getDescription());
+                    vo.setSort(reportForm.getSort());
+                    vo.setPermil(reportForm.getPermil());
+                    vo.setDataType(reportForm.getDataType());
+                    vo.setDecimalPlace(reportForm.getDecimalPlace());
+                }
+            }
+
+            // 构建树状结构
+            Map<Long, List<CostProfitVo>> collect = activeCostProfitVo.stream()
+                    .collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
+            List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
+            collect.remove(NumberConstant.ZERO_L);
+
+            if (!CollectionUtils.isEmpty(costProfitParentVos)) {
+                costProfitParentVos.forEach(parentVo -> {
+                    parentVo.setChildren(collect.get(parentVo.getReportId()));
+                });
+                costProfitParentVos.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
+            }
+
+            BatchCostProfitResponse response = new BatchCostProfitResponse();
+            response.setComputeDate(String.valueOf(year));
+            response.setProfitVoList(costProfitParentVos);
+            response.setAllowDrillDown(false);
+            responses.add(response);
+        }
+
+        return responses;
+    }
+
+
+    /**
+     * 安全地计算百分比:避免除零错误
+     */
+    private BigDecimal calculateRate(BigDecimal current, BigDecimal base) {
+        if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal rate = current.divide(base, 4, RoundingMode.HALF_UP);
+        return rate.setScale(4, RoundingMode.HALF_UP);
+    }
+
+    /**
+     * 计算科室损益
+     * @param computeDate
+     * @param hospId
+     * @param reportType
+     */
+    private void calcDeptProfit(String computeDate, Long hospId, String reportType) {
+        //获取科室损益计算所需的数据
+        ProfitCalculationDataVo profitCalculationData = getProfitCalculationData(computeDate, hospId, reportType);
+        //计算科室损益
+        List<CostDepartmentProfitVO> costDepartmentProfitVOS = calcDeptProfit(profitCalculationData);
+        // 添加数据
+        List<CostDepartmentProfit> costDepartmentProfits = BeanUtil.convertList(costDepartmentProfitVOS, CostDepartmentProfit.class);
+        //统一创建时间
+        long l = System.currentTimeMillis();
+        costDepartmentProfits.forEach(i -> {
+            i.setCreateTime(l);
+        });
+        // 删除这个年月的数据
+        deleteDeptProfit(profitCalculationData.getYear(),profitCalculationData.getMonth(),reportType ,hospId);
+        costDepartmentProfitAccountRepository.deleteDeptProfitAccountWithUser(hospId,computeDate,profitCalculationData.getCurrentUserID());
+        //保存科室损益数据
+        this.batchInsert(costDepartmentProfits);
+        //处理科室损益的会计科目金额数据
+        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts=new ArrayList<>();
+        for (CostDepartmentProfit deptProfit : costDepartmentProfits) {
+            deptProfit.getCostDepartmentProfitAccounts().forEach(account -> {
+                account.setDeptProfitId(deptProfit.getId());
+                account.setComputeDate(computeDate);
+                account.setHospId(hospId);
+            });
+            costDepartmentProfitAccounts.addAll(deptProfit.getCostDepartmentProfitAccounts());
+        }
+        //保存科室损益的会计科目金额数据
+        costDepartmentProfitAccountRepository.batchInsert(costDepartmentProfitAccounts);
+        //记录最后一次 损益计算日期
+        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate,profitCalculationData.getCurrentUserID());
+    }
+
+    /**
+     * 获取科室损益计算所需的数据
+     * @param computeDate
+     * @param hospId
+     * @param reportType
+     * @return
+     */
+    public ProfitCalculationDataVo getProfitCalculationData(String computeDate, Long hospId, String reportType) {
+        ProfitCalculationDataVo profitCalculationData = new ProfitCalculationDataVo();
+        profitCalculationData.setCurrentUserID(UserContext.getCurrentUser().getId());
+        Integer year = ComputeDateUtils.getComputeYear(computeDate);
+        Integer month = ComputeDateUtils.getComputeMonth(computeDate);
+
+        // 获取指定类型的报表配置
+        List<ReportForm> reportFormList = getReportForm(reportType);
+        if (CollUtil.isEmpty(reportFormList)) {
+            throw new CostException(500, "损益表未找到");
+        }
+        //获取报表设置明细
+        List<ReportRelation> reportRelation = getReportRelation();
+        Map<Long, List<ReportRelation>> reportRelationMap = reportRelation.stream().collect(Collectors.groupingBy(ReportRelation::getReportId));
+
+        // 查询最后一个层级的责任中心
+        List<CostShareLevel> costShareLevelList = getCostShareLevelList();
+        if (CollUtil.isEmpty(costShareLevelList)) {
+            throw new CostException(500, "分摊层级未设置");
+        }
+
+        //获取指定报表对应的责任中心
+        List<Responsibility> responsibilityList = getReportResponsibilityList(reportType);
+
+        // 获取归集后的收入数据
+        List<IncomeCollection> incomeList = getIncomeCollectionList(year,month);
+        if (CollUtil.isEmpty(incomeList)) {
+            throw new CostException(500, "归集后数据不存在");
+        }
+        Map<String, Map<String, List<IncomeCollection>>> respIncomeGroup = incomeList.stream()
+                .collect(Collectors.groupingBy(
+                        IncomeCollection::getResponsibilityCode,
+                        Collectors.groupingBy(IncomeCollection::getAccountingCode)
+                ));
+
+
+        // 获取分摊后数据
+        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(hospId,year,month);
+        if (CollUtil.isEmpty(allocationQueryList)) {
+            throw new CostException(500, "分摊后数据不存在");
+        }
+
+        DictDataVo accountingTypeDict = centerService.getDict(Constant.ACCOUNTING_TYPE);
+        DictDataVo costTypeDict = centerService.getDict(Constant.STANDARD_COST_CATEGORIES);
+        List<Accounting> allCostAccounting = accountingRepository.getAllCostAccounting();
+
+        // 创建一个映射,用于快速查找会计科目的类型,过滤掉 null 对象,过滤掉 accountingCode 为 null 的对象
+        Map<String, Accounting> accountingMap = allCostAccounting.stream()
+                .filter(Objects::nonNull)
+                .filter(a -> a.getAccountingCode() != null)
+                .collect(Collectors.toMap(Accounting::getAccountingCode, o -> o));
+
+        List<DictDataVo> accountingTypeDictList = (accountingTypeDict != null && accountingTypeDict.getDataVoList() != null)
+                ? accountingTypeDict.getDataVoList() : new ArrayList<>();
+
+        List<DictDataVo> costTypeDictList = (costTypeDict != null && costTypeDict.getDataVoList() != null)
+                ? costTypeDict.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));
+
+        // 封装数据
+        List<AllocationQueryReportVO> allocationQueryReportVOList = BeanUtil.convertList(allocationQueryList, AllocationQueryReportVO.class);
+        allocationQueryReportVOList.forEach(i -> {
+            i.setAccountingCodes(Arrays.asList(i.getAccountingCode().split(StrUtil.COMMA)));
+            i.setAccountingNames(Arrays.asList(i.getAccountingName().split(StrUtil.COMMA)));
+            //构建会计科目的成本类型及会计科目类型
+            Accounting accounting = accountingMap.get(i.getAccountingCode());
+            if(ObjectUtils.isEmpty( accounting)){
+                return;
+            }
+            DictDataVo costType = costTypeMap.get(String.valueOf(accounting.getCostType()));
+            if(!ObjectUtils.isEmpty( costType)){
+                i.setCostType(costType.getExpandOne());
+            }
+            DictDataVo accountingType = accountingTypeMap.get(String.valueOf(accounting.getCostType()));
+            if(!ObjectUtils.isEmpty( accountingType)){
+                i.setAccountType(accountingType.getExpandOne());
+            }
+        });
+
+        //责任中心+会计科目分组
+        Map<String, Map<String, List<AllocationQueryReportVO>>> respAccountCostGroup = allocationQueryReportVOList.stream()
+                .collect(Collectors.groupingBy(
+                        AllocationQueryReportVO::getTargetResponsibilityCode,
+                        Collectors.groupingBy(AllocationQueryReportVO::getAccountingCode)
+                ));
+
+        //责任中心+来源责任中心分组
+        Map<String, Map<String, List<AllocationQueryReportVO>>> respSourceCostGroup = allocationQueryReportVOList.stream()
+                .collect(Collectors.groupingBy(
+                        AllocationQueryReportVO::getTargetResponsibilityCode,
+                        Collectors.groupingBy(AllocationQueryReportVO::getResponsibilityCode)
+                ));
+        //责任中心+分摊层级分组
+        Map<String, Map<Long, List<AllocationQueryReportVO>>> respShareLevelCostGroup = allocationQueryReportVOList.stream()
+                .collect(Collectors.groupingBy(
+                        AllocationQueryReportVO::getTargetResponsibilityCode,
+                        Collectors.groupingBy(AllocationQueryReportVO::getShareLevelId)
+                ));
+
+        // 查询分摊的报表数据 后面的计算方式需要使用 小计等需要使用
+        List<Allocation> allocationList = allocationService.getByDate( year, month, hospId);
+        if (CollUtil.isEmpty(allocationList)) {
+            throw new CostException(500, "分摊报表数据不存在");
+        }
+        profitCalculationData.setComputeDate(computeDate);
+        profitCalculationData.setYear(year);
+        profitCalculationData.setMonth(month);
+        profitCalculationData.setHospId(hospId);
+        profitCalculationData.setReportType(reportType);
+        profitCalculationData.setReportFormList(reportFormList);
+        profitCalculationData.setReportRelationList(reportRelation);
+        profitCalculationData.setReportRelationMap(reportRelationMap);
+        profitCalculationData.setCostShareLevelList(costShareLevelList);
+        profitCalculationData.setResponsibilityList(responsibilityList);
+        profitCalculationData.setRespIncomeGroup(respIncomeGroup);
+        profitCalculationData.setRespAccountCostGroup(respAccountCostGroup);
+        profitCalculationData.setRespSourceCostGroup(respSourceCostGroup);
+        profitCalculationData.setRespShareLevelCostGroup(respShareLevelCostGroup);
+        return profitCalculationData;
+    }
+
+    /**
+     * 计算科室损益
+     * @param profitCalculationData
+     * @return
+     */
+    private List<CostDepartmentProfitVO> calcDeptProfit(ProfitCalculationDataVo profitCalculationData) {
+        List<ReportForm> firstLevelReports = profitCalculationData.getReportFormList().stream().filter(i -> NumberConstant.ZERO.equals(i.getParentId().intValue())).collect(Collectors.toList());
+        if(CollectionUtils.isEmpty(firstLevelReports)){
+            throw new CostException(500, "未找到第一层报表项目,请检查报表配置");
+        }
+        //按顺序号排序
+        firstLevelReports.sort(Comparator.comparing(ReportForm::getSort, Comparator.nullsLast(Integer::compareTo)));
+        Map<Long, List<ReportForm>> reportParentGroup = profitCalculationData.getReportFormList().stream().collect(Collectors.groupingBy(ReportForm::getParentId));
+        List<CostDepartmentProfitVO> costDepartmentProfitVOList = new ArrayList<>();
+        //循环设置子级报表项目
+        for (ReportForm reportForm : firstLevelReports) {
+            setChildReport(reportForm,reportParentGroup);
+        }
+        //虚拟一个最上层的节点方便循环嵌套计算
+        ReportForm baseReport=new ReportForm();
+        baseReport.setId(NumberConstant.ZERO_L);
+        baseReport.setChild(firstLevelReports);
+        //按责任中心计算科室损益
+//        for (Responsibility responsibility : profitCalculationData.getResponsibilityList()) {
+//            Map<Integer,CostDepartmentProfitVO> costDepartmentProfitMap=new HashMap<>();
+//            //计算责任中心的所有报表项目
+//            for (ReportForm reportForm : firstLevelReports) {
+//                calcRespReportAmount(responsibility, reportForm,profitCalculationData, costDepartmentProfitMap);
+//            }
+//            //添加到结果集合
+//            costDepartmentProfitVOList.addAll(costDepartmentProfitMap.values());
+//        }
+        //按责任中心计算科室损益(并行)
+        List<CostDepartmentProfitVO> result = profitCalculationData.getResponsibilityList().parallelStream()
+                .map(responsibility -> {
+                    Map<Integer, CostDepartmentProfitVO> costDepartmentProfitMap = new HashMap<>();
+                    // 计算责任中心的所有报表项目
+                    calcRespReportAmount(responsibility, baseReport, profitCalculationData, costDepartmentProfitMap);
+                    return new ArrayList<>(costDepartmentProfitMap.values());
+                })
+                .flatMap(List::stream)
+                .collect(Collectors.toList());
+
+        costDepartmentProfitVOList.addAll(result);
+        return costDepartmentProfitVOList;
+    }
+
+    /**
+     * 循环设置子级报表项目
+     * @param reportForm
+     * @param reportParentGroup
+     */
+    public void setChildReport(ReportForm reportForm ,Map<Long, List<ReportForm>> reportParentGroup){
+        List<ReportForm> childReportForms = reportParentGroup.get(reportForm.getId());
+        if(CollUtil.isEmpty(childReportForms)){
+            return;
+        }
+        reportForm.setChild(childReportForms);
+        for (ReportForm cildReportForm : childReportForms) {
+            setChildReport(cildReportForm,reportParentGroup);
+        }
+    }
+
+
+    /**
+     * 计算指定责任中心指定报表项目的金额(优先计算子级,再按顺序号计算非公式项,最后计算公式项)
+     * @param profitCalculationData
+     * @param costDepartmentProfitMap
+     * @param parentReport
+     * @param responsibility
+     */
+    public void calcRespReportAmount(Responsibility responsibility,
+                                 ReportForm parentReport ,
+                                 ProfitCalculationDataVo profitCalculationData,
+                                 Map<Integer,CostDepartmentProfitVO> costDepartmentProfitMap){
+        //有子级的优先计算子级
+        if(!CollUtil.isEmpty(parentReport.getChild())){
+            //计算报表项目的金额
+            for (ReportForm reportForm : parentReport.getChild()) {
+                //计算子级的金额
+                calcRespReportAmount(responsibility,reportForm,profitCalculationData,costDepartmentProfitMap);
+            }
+            //找出所有类型不是计算公式且不是不设置的报表项
+            List<ReportForm> calcReportList = parentReport.getChild().stream().filter(i ->!NumberConstant.ZERO.equals(i.getCalcType())&& !NumberConstant.THREE.equals(i.getCalcType())).collect(Collectors.toList());
+            //优先计算类型为非计算公式的报表项
+            if (!CollUtil.isEmpty(calcReportList)){
+                for (ReportForm reportForm : calcReportList) {
+                    calcReportAmount(responsibility,reportForm,profitCalculationData,costDepartmentProfitMap);
+                }
+            }
+            //找出所有类型为计算公式的报表项
+            List<ReportForm> formulaReportList = parentReport.getChild().stream().filter(i -> NumberConstant.THREE.equals(i.getCalcType())).collect(Collectors.toList());
+            //再计算类型为计算公式的报表项
+            if (!CollUtil.isEmpty(formulaReportList)){
+                for (ReportForm reportForm : formulaReportList) {
+                    calcReportAmount(responsibility,reportForm,profitCalculationData,costDepartmentProfitMap);
+                }
+            }
+        }
+        //虚拟的最上层不需要计算
+        if(!NumberConstant.ZERO_L.equals(parentReport.getId())) {
+            //再计算自己
+            calcReportAmount(responsibility, parentReport, profitCalculationData, costDepartmentProfitMap);
+        }
+    }
+
+
+    /**
+     * 计算一个报表项目的金额
+     * @param profitCalculationData
+     * @param costDepartmentProfitMap
+     * @param reportForm
+     */
+    public void calcReportAmount(Responsibility responsibility,ReportForm reportForm,ProfitCalculationDataVo profitCalculationData,Map<Integer,CostDepartmentProfitVO> costDepartmentProfitMap){
+        Integer calcType = reportForm.getCalcType();
+        CostDepartmentProfitVO costDepartmentProfitVO = createCostDepartmentProfitVO(responsibility,reportForm,profitCalculationData);
+        switch (calcType){
+            case 1:
+                if(NumberConstant.ONE.equals(reportForm.getCostType())){
+                    //按收入会计科目计算
+                    setIncomeAccountReportValue(costDepartmentProfitVO,profitCalculationData,responsibility,reportForm);
+                }else{
+                    //按成本会计科目计算
+                    setCostAccountReportValue(costDepartmentProfitVO,profitCalculationData, responsibility, reportForm);
+                }
+                break;
+            case 2:
+                //按分摊层级计算
+                setShareLevelReportValue(costDepartmentProfitVO,profitCalculationData,responsibility,reportForm);
+                break;
+            case 4:
+                //按公式计算
+                setFormulaReportValue(costDepartmentProfitVO,costDepartmentProfitMap,responsibility,reportForm);
+                break;
+            case 5:
+                //按责任中心计算
+                setResponsibilityReportValue(costDepartmentProfitVO,profitCalculationData,costDepartmentProfitMap,responsibility,reportForm);
+                break;
+        }
+        //记录下已计算好的报表项目
+        if(!costDepartmentProfitMap.containsKey(reportForm.getNum())){
+            costDepartmentProfitMap.put(reportForm.getNum(),costDepartmentProfitVO);
+        }
+    }
+
+    /**
+     * 创建一个科室损益计算结果对象
+     * @param responsibility
+     * @param reportForm
+     * @param profitCalculationData
+     * @return
+     */
+    public CostDepartmentProfitVO createCostDepartmentProfitVO(Responsibility responsibility,ReportForm reportForm,ProfitCalculationDataVo profitCalculationData){
+        CostDepartmentProfitVO costDepartmentProfitVO = new CostDepartmentProfitVO();
+        costDepartmentProfitVO.setYear(profitCalculationData.getYear());
+        costDepartmentProfitVO.setMonth(profitCalculationData.getMonth());
+        costDepartmentProfitVO.setReportId(reportForm.getId());
+        costDepartmentProfitVO.setReportNum(reportForm.getNum());
+        costDepartmentProfitVO.setCalcType(reportForm.getCalcType());
+        costDepartmentProfitVO.setReportName(reportForm.getReportName());
+        costDepartmentProfitVO.setCalcFormula(reportForm.getCalcFormula());
+        costDepartmentProfitVO.setReportParentId(reportForm.getParentId());
+        costDepartmentProfitVO.setResponsibilityCode(responsibility.getResponsibilityCode());
+        costDepartmentProfitVO.setResponsibilityName(responsibility.getResponsibilityName());
+        costDepartmentProfitVO.setCostType(NumberConstant.ONE);
+        costDepartmentProfitVO.setIncomeType(NumberConstant.ONE);
+        costDepartmentProfitVO.setHospId(profitCalculationData.getHospId());
+        costDepartmentProfitVO.setShareType(Integer.valueOf(profitCalculationData.getReportType()));
+        costDepartmentProfitVO.setType(reportForm.getCostType());
+        costDepartmentProfitVO.setFraction(reportForm.getFraction());
+        costDepartmentProfitVO.setAmount(BigDecimal.ZERO);
+        costDepartmentProfitVO.setCostDepartmentProfitAccounts(new ArrayList<>());
+        return costDepartmentProfitVO;
+    }
+
+    /**
+     * 获取按责任中心计算结果
+     * @param profitCalculationData
+     * @param costDepartmentProfitMap
+     * @param reportForm
+     * @return
+     */
+    private void setResponsibilityReportValue(CostDepartmentProfitVO costDepartmentProfitVO, ProfitCalculationDataVo profitCalculationData, Map<Integer, CostDepartmentProfitVO> costDepartmentProfitMap, Responsibility responsibility, ReportForm reportForm) {
+        List<ReportRelation> reportRelationList = profitCalculationData.getReportRelationMap().get(reportForm.getId());
+        if(CollectionUtils.isEmpty(reportRelationList)){
+            return ;
+        }
+        // 获取对应的会计科目信息  筛选会计科目的Code
+        List<String> responsibilityCodeList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
+        // 获取指定责任中心的分摊数据
+        Map<String, List<AllocationQueryReportVO>> respSourceCostMap = profitCalculationData.getRespSourceCostGroup().get(responsibility.getResponsibilityCode());
+        if(ObjectUtils.isEmpty(respSourceCostMap) || respSourceCostMap.isEmpty()){
+            return ;
+        }
+        //获取指定会计科目的分摊数据
+        List<AllocationQueryReportVO> reportVOList=new ArrayList<>();
+        responsibilityCodeList.forEach(respCode -> {
+            if(respSourceCostMap.containsKey(respCode)){
+                reportVOList.addAll(respSourceCostMap.get(respCode));
+            }
+        });
+        if(CollectionUtils.isEmpty(reportVOList)){
+            return ;
+        }
+        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts = calculateCostByTypeAndAccount(reportVOList);
+        BigDecimal totalAmount = costDepartmentProfitAccounts.stream()
+                .map(CostDepartmentProfitAccount::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        costDepartmentProfitVO.setAmount(totalAmount);
+        costDepartmentProfitVO.setCostDepartmentProfitAccounts(costDepartmentProfitAccounts);
+    }
+
+    /**
+     * 获取按公式计算结果
+     * @param responsibility
+     * @param costDepartmentProfitMap
+     * @param reportForm
+     * @return
+     */
+    private void setFormulaReportValue(CostDepartmentProfitVO costDepartmentProfitVO,Map<Integer, CostDepartmentProfitVO> costDepartmentProfitMap,Responsibility responsibility, ReportForm reportForm) {
+        // 获取当前报表的计算方式  [1]+[2]类型/ [1]-[2] [1]*[2] [1]/[2]
+        String formula = reportForm.getCalcFormula();
+        if (StrUtil.isBlank(formula)) {
+            costDepartmentProfitVO.setAmount(BigDecimal.ZERO);
+            costDepartmentProfitVO.setCostDepartmentProfitAccounts(new ArrayList<>());
+            return ;
+        }
+
+        String responsibilityCode = responsibility.getResponsibilityCode();
+
+        // 找出公式当中所有代码
+        String replace = formula.replace("[", "")
+                .replace("]", "")
+                .replace("-", ",")
+                .replace("+", ",")
+                .replace("*", ",")
+                .replace("/", ",");
+
+        ArrayList<String> codeList = CollUtil.newArrayList(replace.split(","));
+        Map<Integer, String> codeMap = new ConcurrentHashMap<>();
+        for (int j = 0; j < codeList.size(); j++) {
+            codeMap.put(j, codeList.get(j));
+        }
+
+        List<String> expressions = ReUtil.findAll("[^0-9]", "+" + formula.replace("[", "")
+                        .replace("]", "").trim(), 0)
+                .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
+
+        // 得到预算表达式 得到所有表达式的Map  +  -  *  / 相关的
+        Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
+        for (int k = 0; k < expressions.size(); k++) {
+            expressionMap.put(k, expressions.get(k));
+        }
+
+        // 数字的索引和表达式的索引累加计算
+        Set<Integer> codeSet = codeMap.keySet();
+        List<Integer> codes = new ArrayList<>(codeSet);
+        AtomicReference<BigDecimal> totalAmount = new AtomicReference<>(BigDecimal.ZERO);
+        List<CostDepartmentProfitAccount> baseDeptProfitAccounts=new ArrayList<>();
+        for (int i = 0; i < codes.size(); i++) {
+            // 编号
+            String code = codeMap.get(i);
+            CostDepartmentProfitVO reportData = costDepartmentProfitMap.get(Integer.valueOf(code));
+
+            // 检查报表数据是否存在且属于当前责任中心
+            if (reportData == null || !responsibilityCode.equals(reportData.getResponsibilityCode())) {
+                continue;
+            }
+
+            BigDecimal amount = reportData.getAmount();
+            if (amount == null) {
+                amount = BigDecimal.ZERO;
+            }
+
+            String str = expressionMap.get(i);
+            if (str.equals("+")) {
+                baseDeptProfitAccounts=calculateAccountAmounts(baseDeptProfitAccounts,reportData.getCostDepartmentProfitAccounts(),NumberConstant.ONE);
+                totalAmount.set(totalAmount.get().add(amount));
+            } else if (str.contains("-")) {
+                baseDeptProfitAccounts=calculateAccountAmounts(baseDeptProfitAccounts,reportData.getCostDepartmentProfitAccounts(),NumberConstant.NEGATIVE);
+                totalAmount.set(totalAmount.get().subtract(amount));
+            } else if (str.contains("*")) {
+                totalAmount.set(totalAmount.get().multiply(amount));
+            } else if (str.contains("/")) {
+                if (amount.compareTo(BigDecimal.ZERO) == 0) {
+                    log.error("报表项【" + reportForm.getReportName() + "】公式除数为0,报表编号为【" + code + "】");
+                    totalAmount.set(BigDecimal.ZERO);
+                    break;
+                } else {
+                    totalAmount.set(totalAmount.get().divide(amount, 6, RoundingMode.HALF_UP));
+                }
+            }
+        }
+        //有乘除算法的只要赋值,不用设置会计科目金额
+        if(formula.contains("*")||formula.contains("/")){
+            costDepartmentProfitVO.setAmount(totalAmount.get());
+            costDepartmentProfitVO.setCostDepartmentProfitAccounts(new ArrayList<>());
+        }else{
+            costDepartmentProfitVO.setAmount(totalAmount.get());
+            costDepartmentProfitVO.setCostDepartmentProfitAccounts(baseDeptProfitAccounts);
+        }
+
+    }
+
+    /**
+     * 对两个CostDepartmentProfitVO对象的costDepartmentProfitAccounts列表进行加减运算
+     * 按照相同的costType和accountType进行合并计算,只处理amount字段
+     *
+     * @param firstList 第一个CostDepartmentProfitVO对象
+     * @param secondList 第二个CostDepartmentProfitVO对象
+     * @param operation 运算符,1表示加法,-1表示减法
+     * @return 运算结果列表
+     */
+    public List<CostDepartmentProfitAccount> calculateAccountAmounts(
+            List<CostDepartmentProfitAccount> firstList,
+            List<CostDepartmentProfitAccount> secondList,
+            int operation) {
+
+        // 处理空列表情况
+        firstList = firstList != null ?firstList : new ArrayList<>();
+        secondList = secondList != null ?secondList: new ArrayList<>();
+
+        // 创建结果列表,先复制第一个列表的所有元素
+        List<CostDepartmentProfitAccount> result = firstList.stream()
+                .map(account -> {
+                    CostDepartmentProfitAccount copy = new CostDepartmentProfitAccount();
+                    copy.setCostType(account.getCostType());
+                    copy.setAccountType(account.getAccountType());
+                    copy.setAmount(account.getAmount() != null ? account.getAmount() : BigDecimal.ZERO);
+                    return copy;
+                })
+                .collect(Collectors.toList());
+
+        // 处理第二个列表中的每个元素
+        for (CostDepartmentProfitAccount secondAccount : secondList) {
+            if (secondAccount.getAmount() == null) {
+                continue; // 跳过金额为空的记录
+            }
+
+            // 查找是否在结果列表中已有相同costType和accountType的记录
+            boolean found = false;
+            for (CostDepartmentProfitAccount resultAccount : result) {
+                if (Objects.equals(resultAccount.getCostType(), secondAccount.getCostType()) &&
+                        Objects.equals(resultAccount.getAccountType(), secondAccount.getAccountType())) {
+
+                    // 找到匹配项,进行加减运算
+                    BigDecimal firstAmount = resultAccount.getAmount() != null ? resultAccount.getAmount() : BigDecimal.ZERO;
+                    BigDecimal secondAmount = secondAccount.getAmount() != null ? secondAccount.getAmount() : BigDecimal.ZERO;
+
+                    if (operation == 1) {
+                        resultAccount.setAmount(firstAmount.add(secondAmount));
+                    } else if (operation == -1) {
+                        resultAccount.setAmount(firstAmount.subtract(secondAmount));
+                    }
+
+                    found = true;
+                    break;
+                }
+            }
+
+            // 如果未找到匹配项,则添加新记录
+            if (!found) {
+                CostDepartmentProfitAccount newAccount = new CostDepartmentProfitAccount();
+                newAccount.setCostType(secondAccount.getCostType());
+                newAccount.setAccountType(secondAccount.getAccountType());
+
+                // 加法直接添加金额,减法添加负金额
+                if (operation == 1) {
+                    newAccount.setAmount(secondAccount.getAmount() != null ? secondAccount.getAmount() : BigDecimal.ZERO);
+                } else if (operation == -1) {
+                    BigDecimal amount = secondAccount.getAmount() != null ? secondAccount.getAmount() : BigDecimal.ZERO;
+                    newAccount.setAmount(amount.negate()); // 设置为负值
+                }
+                result.add(newAccount);
+            }
+        }
+
+        return result;
+    }
+
+
+    /**
+     * 获取按分摊层级计算结果
+     * @param profitCalculationData
+     * @param reportForm
+     * @return
+     */
+    private void setShareLevelReportValue(CostDepartmentProfitVO costDepartmentProfitVO, ProfitCalculationDataVo profitCalculationData, Responsibility responsibility, ReportForm reportForm) {
+        List<ReportRelation> reportRelationList = profitCalculationData.getReportRelationMap().get(reportForm.getId());
+        if(CollectionUtils.isEmpty(reportRelationList)){
+            return ;
+        }
+        // 获取对应的会计科目信息  筛选会计科目的Code
+        List<Long> shareLevelIdList = reportRelationList.stream().map(o->Long.valueOf(o.getRelationCode())).collect(Collectors.toList());
+        // 获取指定责任中心的分摊数据
+        Map<Long, List<AllocationQueryReportVO>> respShareLevelCostMap = profitCalculationData.getRespShareLevelCostGroup().get(responsibility.getResponsibilityCode());
+        if(ObjectUtils.isEmpty(respShareLevelCostMap) || respShareLevelCostMap.isEmpty()){
+            return ;
+        }
+        //获取指定会计科目的分摊数据
+        List<AllocationQueryReportVO> reportVOList=new ArrayList<>();
+        shareLevelIdList.forEach(shareLevelId -> {
+            if(respShareLevelCostMap.containsKey(shareLevelId)){
+                reportVOList.addAll(respShareLevelCostMap.get(shareLevelId));
+            }
+        });
+        if(CollectionUtils.isEmpty(reportVOList)){
+            return ;
+        }
+        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts = calculateCostByTypeAndAccount(reportVOList);
+        BigDecimal totalAmount = costDepartmentProfitAccounts.stream()
+                .map(CostDepartmentProfitAccount::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        costDepartmentProfitVO.setAmount(totalAmount);
+        costDepartmentProfitVO.setCostDepartmentProfitAccounts(costDepartmentProfitAccounts);
+    }
+
+
+    /**
+     * 按收入会计科目计算
+     * @param costDepartmentProfitVO
+     * @param profitCalculationData
+     * @param responsibility
+     * @param reportForm
+     */
+    private void setIncomeAccountReportValue(CostDepartmentProfitVO costDepartmentProfitVO,ProfitCalculationDataVo profitCalculationData, Responsibility responsibility,ReportForm reportForm) {
+        List<ReportRelation> reportRelationList = profitCalculationData.getReportRelationMap().get(reportForm.getId());
+        if(CollectionUtils.isEmpty(reportRelationList)){
+            return ;
+        }
+        // 获取对应的会计科目信息  筛选会计科目的Code
+        List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
+        // 获取指定责任中心的收入数据
+        Map<String, List<IncomeCollection>> respAccountIncomeMap = profitCalculationData.getRespIncomeGroup().get(responsibility.getResponsibilityCode());
+        if(ObjectUtils.isEmpty(respAccountIncomeMap) || respAccountIncomeMap.isEmpty()){
+            return ;
+        }
+        //获取指定会计科目的收入数据
+        List<IncomeCollection> reportVOList=new ArrayList<>();
+        accountList.forEach(accountCode -> {
+            if(respAccountIncomeMap.containsKey(accountCode)){
+                reportVOList.addAll(respAccountIncomeMap.get(accountCode));
+            }
+        });
+        if(CollectionUtils.isEmpty(reportVOList)){
+            return ;
+        }
+        BigDecimal totalAmount = reportVOList.stream()
+                .map(IncomeCollection::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        costDepartmentProfitVO.setAmount(totalAmount);
+    }
+
+    /**
+     *获取按成本会计科目计算的结果
+     * @param profitCalculationData
+     * @param responsibility
+     * @param reportForm
+     * @return
+     */
+    private void setCostAccountReportValue(CostDepartmentProfitVO costDepartmentProfitVO, ProfitCalculationDataVo profitCalculationData, Responsibility responsibility, ReportForm reportForm) {
+        List<ReportRelation> reportRelationList = profitCalculationData.getReportRelationMap().get(reportForm.getId());
+        if(CollectionUtils.isEmpty(reportRelationList)){
+            return ;
+        }
+        // 获取对应的会计科目信息  筛选会计科目的Code
+        List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
+        // 获取指定责任中心的分摊数据
+        Map<String, List<AllocationQueryReportVO>> respAccountCostMap = profitCalculationData.getRespAccountCostGroup().get(responsibility.getResponsibilityCode());
+        if(ObjectUtils.isEmpty(respAccountCostMap) || respAccountCostMap.isEmpty()){
+            return ;
+        }
+        //获取指定会计科目的分摊数据
+        List<AllocationQueryReportVO> reportVOList=new ArrayList<>();
+        accountList.forEach(accountCode -> {
+            if(respAccountCostMap.containsKey(accountCode)){
+                reportVOList.addAll(respAccountCostMap.get(accountCode));
+            }
+        });
+        if(CollectionUtils.isEmpty(reportVOList)){
+            return ;
+        }
+        //获取指定成本类别(全部/直接/间接)的分摊数据
+        List<AllocationQueryReportVO> collect = reportVOList.stream().filter(m -> NumberConstant.ZERO.equals(reportForm.getCostType()) || reportForm.getCostType().equals(m.getOriginType().intValue())).collect(Collectors.toList());
+        if (CollUtil.isEmpty(reportVOList)) {
+            return ;
+        }
+        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts = calculateCostByTypeAndAccount(reportVOList);
+        BigDecimal totalAmount = costDepartmentProfitAccounts.stream()
+                .map(CostDepartmentProfitAccount::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        costDepartmentProfitVO.setAmount(totalAmount);
+        costDepartmentProfitVO.setCostDepartmentProfitAccounts(costDepartmentProfitAccounts);
+    }
+
+    /**
+     * 将分摊结果按会计科目类别+成本类别分组汇总
+     * @param reportVOList
+     * @return
+     */
+    public List<CostDepartmentProfitAccount> calculateCostByTypeAndAccount(List<AllocationQueryReportVO> reportVOList) {
+        // 按costType+accountType分组计算各组的金额amount
+        Map<String, BigDecimal> groupedAmounts = reportVOList.stream()
+                .collect(Collectors.groupingBy(
+                        vo -> vo.getCostType() + "_" + vo.getAccountType(),
+                        Collectors.reducing(
+                                BigDecimal.ZERO,
+                                AllocationQueryReportVO::getAmount,
+                                BigDecimal::add
+                        )
+                ));
+
+        // 按组生成CostDepartmentProfitAccount对象
+        return groupedAmounts.entrySet().stream()
+                .map(entry -> {
+                    String[] keys = entry.getKey().split("_", 2);
+                    CostDepartmentProfitAccount account = new CostDepartmentProfitAccount();
+                    account.setCostType(keys[0]);
+                    account.setAccountType(keys[1]);
+                    account.setAmount(entry.getValue());
+                    return account;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 获取指定类型的报表配置
+     * @param reportType
+     * @return
+     */
+    public List<ReportForm> getReportForm(String reportType){
+        List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
+                .eq(ReportForm::getHospId,  UserContext.getHospId())
+                .eq(ReportForm::getReportType, reportType));
+        return reportFormList;
+    }
+
+    /**
+     * 获取报表关系
+     * @return
+     */
+    public List<ReportRelation> getReportRelation(){
+        List<ReportRelation> list = reportRelationService.list(new QueryWrapper<ReportRelation>().lambda().eq(ReportRelation::getHospId, UserContext.getHospId()));
+        return list;
+    }
+
+    /**
+     * 获取指定报表对应的责任中心
+     * @param reportType
+     * @return
+     */
+    public List<Responsibility> getReportResponsibilityList(String reportType){
+        DictDataVo dataVo = getDictDataVo(reportType);
+        Long id = Long.valueOf(dataVo.getExpandOne());
+        List<Responsibility> list = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
+                .eq(Responsibility::getHospId, UserContext.getHospId())
+                .eq(Responsibility::getIsGatherCenter, 2)
+                .eq(Responsibility::getDeleteTime, 0)
+                .eq(Responsibility::getShareId, id));
+        return list;
+    }
+
+
+    /**
+     * 获取分摊层级字典
+     * @return
+     */
+    public List<CostShareLevel> getCostShareLevelList(){
+        List<CostShareLevel> costShareLevelList =  costShareLevelService.list(new QueryWrapper<CostShareLevel>().lambda()
+                .eq(CostShareLevel::getHospId, UserContext.getHospId()).orderByDesc(CostShareLevel::getLeverSort));
+        return costShareLevelList;
+    }
+
+    /**
+     * 获取归集后的收入数据
+     * @param year
+     * @param month
+     * @return
+     */
+    public List<IncomeCollection> getIncomeCollectionList(Integer year, Integer month) {
+        List<IncomeCollection> list = incomeCollectionService.list(new QueryWrapper<IncomeCollection>().lambda()
+                .eq(IncomeCollection::getHospId, UserContext.getHospId())
+                .eq(year > 0, IncomeCollection::getYear, year).eq(month > 0, IncomeCollection::getMonth, month));
+        return list;
+    }
+
+
+    /**
+     * 删除指定月份的科室损益数据
+     * @param year
+     * @param month
+     * @param reportType
+     */
+    public void deleteDeptProfit(Integer year, Integer month,String reportType,Long hospId) {
+        // 删除这个年月的数据
+        this.remove(new QueryWrapper<CostDepartmentProfit>().lambda().eq(CostDepartmentProfit::getHospId, hospId)
+                .eq(CostDepartmentProfit::getYear, year).eq(CostDepartmentProfit::getMonth, month).eq(CostDepartmentProfit::getShareType, Integer.valueOf(reportType)));
+    }
+
 }

+ 30 - 6
src/main/java/com/kcim/service/impl/CostIncomeGroupServiceImpl.java

@@ -18,10 +18,7 @@ import com.kcim.common.util.*;
 import com.kcim.dao.mapper.CostIncomeGroupMapper;
 import com.kcim.dao.model.*;
 import com.kcim.service.*;
-import com.kcim.vo.CommonDepartVo;
-import com.kcim.vo.CostIncomeGroupAllAmountVO;
-import com.kcim.vo.CostIncomeGroupBeforeVO;
-import com.kcim.vo.IncomeErrorMessage;
+import com.kcim.vo.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
@@ -96,6 +93,12 @@ public class CostIncomeGroupServiceImpl extends ServiceImpl<CostIncomeGroupMappe
      */
     @Override
     public PageUtils queryList(Integer current, Integer pageSize, String dateTime, String responsibilityCode, String productCode, Long hospId, Integer type, String filter, String departmentCode) {
+//       return getDeptIncomeList(current, pageSize, dateTime, responsibilityCode, productCode, hospId, type, filter, departmentCode);
+        return getDeptProductList(current, pageSize, dateTime, departmentCode, productCode, hospId, type, filter);
+    }
+
+
+    public PageUtils getDeptIncomeList(Integer current, Integer pageSize, String dateTime, String responsibilityCode, String productCode, Long hospId, Integer type, String filter, String departmentCode) {
         // 先检验当前年月是否存在数据
         int year = 0;
         int month = 0;
@@ -107,7 +110,7 @@ public class CostIncomeGroupServiceImpl extends ServiceImpl<CostIncomeGroupMappe
         Page<CostIncomeGroup> costIncomeGroupPage = new Page<>(current, pageSize);
         Page<CostIncomeGroup> pages = new Page<>();
         if(type.equals(NumberConstant.ONE)){
-             pages = this.page(costIncomeGroupPage, new QueryWrapper<CostIncomeGroup>().lambda()
+            pages = this.page(costIncomeGroupPage, new QueryWrapper<CostIncomeGroup>().lambda()
                     .eq(Objects.nonNull(hospId), CostIncomeGroup::getHospId, hospId)
                     .eq(!NumberConstant.ZERO.equals(year), CostIncomeGroup::getDateYear, year)
                     .eq(!NumberConstant.ZERO.equals(month), CostIncomeGroup::getDateMonth, month)
@@ -138,7 +141,7 @@ public class CostIncomeGroupServiceImpl extends ServiceImpl<CostIncomeGroupMappe
         }
         List<CostIncomeGroup> list = new ArrayList<>();
         if(type.equals(NumberConstant.ONE)) {
-             list = this.list(new QueryWrapper<CostIncomeGroup>().lambda()
+            list = this.list(new QueryWrapper<CostIncomeGroup>().lambda()
                     .eq(Objects.nonNull(hospId), CostIncomeGroup::getHospId, hospId)
                     .eq(!NumberConstant.ZERO.equals(year), CostIncomeGroup::getDateYear, year)
                     .eq(!NumberConstant.ZERO.equals(month), CostIncomeGroup::getDateMonth, month)
@@ -185,6 +188,27 @@ public class CostIncomeGroupServiceImpl extends ServiceImpl<CostIncomeGroupMappe
         return pageUtils;
     }
 
+
+    public PageUtils getDeptProductList(Integer current, Integer pageSize, String computeDate, String departmentCode, String productCode, Long hospId, Integer type, String filter) {
+        Integer year = ComputeDateUtils.getComputeYear(computeDate);
+        Integer month = ComputeDateUtils.getComputeMonth(computeDate);
+
+        Page<PatientInfoVo> page = new Page<>(current,pageSize);
+        List<CostIncomeGroup> orderDeptProductList;
+        //按开单科室查询
+        if(NumberConstant.ONE.equals( type)){
+            orderDeptProductList = this.baseMapper.getOrderDeptProductList(page, year, month, departmentCode, hospId, filter);
+        }else{
+            orderDeptProductList = this.baseMapper.getExecDeptProductList(page, year, month, departmentCode, hospId, filter);
+        }
+        BigDecimal totalAmount=this.baseMapper.getTotalAmount(year, month, departmentCode, hospId);
+        BigDecimal departmentAmount=this.baseMapper.getDeptTotalAmount(year, month, departmentCode, hospId);
+        PageUtils pageUtils = new PageUtils(page);
+        pageUtils.setList(orderDeptProductList);
+        pageUtils.setTotalAmount(totalAmount);
+        pageUtils.setDepartmentAmount(departmentAmount);
+        return pageUtils;
+    }
     private static AtomicReference<BigDecimal> setAmount(List<CostIncomeGroupAllAmountVO> costIncomeGroupAllAmountVoS) {
         AtomicReference<BigDecimal> totalAmount = new AtomicReference<>(new BigDecimal("0.0000"));
         costIncomeGroupAllAmountVoS.forEach(i -> {

+ 641 - 18
src/main/java/com/kcim/service/impl/HospProfitAndLossServiceImpl.java

@@ -11,27 +11,20 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.ImmutableMap;
-import com.kcim.common.constants.Constant;
-import com.kcim.common.constants.NumberConstant;
-import com.kcim.common.constants.SQLParameter;
+import com.kcim.common.constants.*;
 import com.kcim.common.enums.*;
 import com.kcim.common.exception.CostException;
 import com.kcim.common.file.MinioConfig;
 import com.kcim.common.file.MinioFileUtil;
-import com.kcim.common.util.BeanUtil;
-import com.kcim.common.util.DateUtils;
-import com.kcim.common.util.PageUtils;
-import com.kcim.common.util.UserContext;
+import com.kcim.common.util.*;
 import com.kcim.common.util.excel.ExcelPoiUtil;
 import com.kcim.common.util.excel.entity.ColEntity;
 import com.kcim.common.util.excel.entity.TitleEntity;
 import com.kcim.dao.mapper.HospProfitAndLossMapper;
 import com.kcim.dao.model.*;
 import com.kcim.service.*;
-import com.kcim.vo.AllocationQueryReportVO;
-import com.kcim.vo.HospProfitAndLossVo;
-import com.kcim.vo.HospProfitVO;
-import com.kcim.vo.RelationVO;
+import com.kcim.vo.*;
+import com.kcim.web.reponse.BatchCostProfitResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.FileItemFactory;
@@ -42,6 +35,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
 
@@ -79,6 +74,8 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
     private final FileRecordService fileRecordService;
     private final SqlService sqlService;
 
+    private final CenterService centerService;
+
     private final MinioConfig minioConfig;
 
     private final MinioFileUtil minioFileUtil;
@@ -91,7 +88,13 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
                                         CostShareLevelService shareLevelService,
                                         CostOtherPaymentsDataService otherPaymentsDataService,
                                         ResponsibilityService responsibilityService,
-                                        CostAccountShareService accountShareService, FileRecordService fileRecordService, MinioConfig minioConfig, MinioFileUtil minioFileUtil,SqlService sqlService) {
+                                        CostAccountShareService accountShareService,
+                                        FileRecordService fileRecordService,
+                                        MinioConfig minioConfig,
+                                        MinioFileUtil minioFileUtil,
+                                        SqlService sqlService,
+                                        CenterService centerService
+    ) {
         this.reportFormService = reportFormService;
         this.collectionService = collectionService;
         this.allocationQueryService = allocationQueryService;
@@ -105,6 +108,7 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
         this.minioConfig = minioConfig;
         this.minioFileUtil = minioFileUtil;
         this.sqlService=sqlService;
+        this.centerService=centerService;
     }
 
 
@@ -194,8 +198,18 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
      * @param reportType 报表类型
      */
     @Override
+    public void calcHospProfit(String date, Long hospId, Integer reportType){
+        //需要用代码计算全院损益时
+        if(IsNeedCalc(reportType)){
+            //计算全院损益
+            calcHospProfitAction(date,hospId,reportType);
+            //计算同环比
+            handleSpecificMonthsCalculation(hospId, date, reportType);
+        }
+        execHospProfitSql(date,reportType);
+    }
     @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
-    public void calcHospProfit(String date, Long hospId, Integer reportType) {
+    public void calcHospProfitAction(String date, Long hospId, Integer reportType) {
         List<Responsibility> leafResp = responsibilityService.getLeafResp(hospId);
         DateTime parse = DateUtil.parse(date);
         int year = DateUtil.year(parse);
@@ -378,13 +392,28 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
         // 处理医院其他收支
         List<CostOtherPaymentsData> otherPaymentsDatas = otherPaymentsDataService.getByMonth(year, month, hospId);
         if (!otherPaymentsDatas.isEmpty()) {
-            otherPaymentsDatas.forEach(ele -> {
+            Optional<ReportForm> firstLossReport = reportForms.stream().filter(f -> NumberConstant.ONE.equals(f.getIsLoss())).findFirst();
+            if(!firstLossReport.isPresent()){
+                throw new CostException("全院损益报表配置有误,未设置损益项目");
+            }
+            Optional<HospProfitAndLoss> firstHospProfitAndLoss = list.stream().filter(f -> firstLossReport.get().getNum().equals(f.getReportNum())).findFirst();
+            if(!firstHospProfitAndLoss.isPresent()){
+                throw new CostException("全院损益报表配置有误,未找到配置的损益项目");
+            }
+            for (CostOtherPaymentsData ele : otherPaymentsDatas) {
                 HospProfitAndLoss loss = new HospProfitAndLoss();
                 loss.setDateYear(year).setDateMonth(month).setReportName(ele.getPaymentsName()).setReportNum((int) (-ele.getId()))
                         .setCreateTime(System.currentTimeMillis()).setAmount(ele.getTotalAmount()).setHospId(hospId)
-                        .setResponsibilityName("全院").setResponsibilityCode("-1").setPercent(null);
+                        .setResponsibilityName("全院").setResponsibilityCode("-1").setPercent(null).setOriginType(NumberConstant.ONE);
+                if( NumberConstant.ONE.equals(ele.getPaymentsType()) ) {
+                    //全院损益项目加上收入
+                    firstHospProfitAndLoss.get().setAmount(firstHospProfitAndLoss.get().getAmount().add(ele.getTotalAmount()));
+                }else{
+                    //全院损益项目减去支出
+                    firstHospProfitAndLoss.get().setAmount(firstHospProfitAndLoss.get().getAmount().subtract(ele.getTotalAmount()));
+                }
                 list.add(loss);
-            });
+            }
         }
         long l = System.currentTimeMillis();
         list.forEach(i -> {
@@ -392,11 +421,247 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
             i.setReportType(reportType);
         });
         this.saveBatch(list);
-        Map<String,String> sqlParameter = new HashMap<>();
 
+    }
+
+    /**
+     * 是否需要代码计算
+     * @return
+     */
+    public boolean IsNeedCalc(Integer reportType) {
+        String parameterValue = centerService.getParameterValue(ParameterConstant.SQL_CALC_REPORT_TYPE);
+        if(StringUtils.isEmpty(parameterValue)){
+            return true;
+        }
+        //不需计算的报表类型列表
+        List<String> nonCalcReportTypeList = Arrays.stream(parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE)).collect(Collectors.toList());
+        return !nonCalcReportTypeList.contains(String.valueOf(reportType));
+    }
+
+    /**
+     * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
+     *
+     * @param hospId      院区ID
+     * @param computeDate 日期字符串,格式:YYYY-MM
+     * @param shareType   报表类型
+     */
+    public void handleSpecificMonthsCalculation(Long hospId, String computeDate, Integer shareType) {
+        // 解析输入的年月
+        Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
+        Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
+        // 计算需要处理的期间信息
+        List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
+
+        // 获取所有相关的期间数据
+        Map<String, List<HospProfitAndLoss>> allDataMap = loadAllPeriodData(hospId, shareType, periods);
+
+        // 对每个期间执行计算
+        for (PeriodInfoVO period : periods) {
+            String currentKey = buildPeriodKey(period.getYear(), period.getMonth());
+            if (allDataMap.containsKey(currentKey) && !CollectionUtils.isEmpty(allDataMap.get(currentKey))) {
+                List<HospProfitAndLoss> currentRecords = allDataMap.get(currentKey);
+                List<HospProfitAndLoss> prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth());
+                List<HospProfitAndLoss> lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth());
+
+                // 执行批量计算
+                calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords);
+            }
+        }
+    }
+
+    /**
+     * 构建所有需要处理的期间信息
+     */
+    private List<PeriodInfoVO> calculateAllRelatedPeriods(int baseYear, int baseMonth) {
+        List<PeriodInfoVO> result = new ArrayList<>();
+
+        // 添加当前期间
+        result.add(calculatePeriodInfo(baseYear, baseMonth));
+
+        // 下个月
+        int nextMonth = baseMonth + 1;
+        int nextMonthYear = baseYear;
+        if (baseMonth == 12) {
+            nextMonth = 1;
+            nextMonthYear += 1;
+        }
+        result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
+
+        // 明年同月
+        result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
+
+        return result;
+    }
+
+    /**
+     * 构建单个期间的信息(当前月、上月、去年同期)
+     */
+    private PeriodInfoVO calculatePeriodInfo(int year, int month) {
+        PeriodInfoVO info = new PeriodInfoVO();
+
+        info.setYear( year);
+        info.setMonth( month);
+
+        // 上期
+        if (month == 1) {
+            info.setPrevYear(year - 1);
+            info.setPrevMonth(12);
+        } else {
+            info.setPrevYear( year);
+            info.setPrevMonth(month - 1);
+        }
+
+        // 同期
+        info.setLastYear(year - 1);
+        info.setLastMonth( month);
+
+        return info;
+    }
+
+    /**
+     * 加载所有相关期间的数据(去重处理)
+     */
+    private Map<String, List<HospProfitAndLoss>> loadAllPeriodData(Long hospId, Integer shareType, List<PeriodInfoVO> periods) {
+        Set<String> allPeriodKeys = new HashSet<>();
+
+        // 收集所有需要查询的年月组合
+        for (PeriodInfoVO period : periods) {
+            allPeriodKeys.add(buildPeriodKey(period.getYear(), period.getMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getPrevYear(), period.getPrevMonth()));
+            allPeriodKeys.add(buildPeriodKey(period.getLastYear(), period.getLastMonth()));
+        }
+
+        // 去重后查询
+        Map<String, List<HospProfitAndLoss>> result = new HashMap<>();
+        Set<String> processedKeys = new HashSet<>(); // 已处理的键集合
+
+        for (String key : allPeriodKeys) {
+            if (!processedKeys.contains(key)) {
+                int[] ym = parsePeriodKey(key);
+                List<HospProfitAndLoss> records = getPeriodRecords(hospId, shareType, ym[0], ym[1]);
+                result.put(key, records);
+                processedKeys.add(key); // 标记为已处理
+            }
+        }
+
+        return result;
+    }
+
+
+    /**
+     * 获取指定期间的数据
+     *
+     * @param hospId    院区ID
+     * @param shareType 报表类型
+     * @param year      年份
+     * @param month     月份
+     * @return 符合条件的数据列表
+     */
+    private List<HospProfitAndLoss> getPeriodRecords(Long hospId, Integer shareType, int year, int month) {
+        return this.list(new QueryWrapper<HospProfitAndLoss>().lambda()
+                .eq(HospProfitAndLoss::getHospId, hospId)
+                .eq(HospProfitAndLoss::getReportType, shareType)
+                .eq(HospProfitAndLoss::getDateYear, year)
+                .eq(HospProfitAndLoss::getDateMonth, month)
+                .eq(HospProfitAndLoss::getDeleteTime, 0));
+    }
+
+    /**
+     * 根据年月获取对应的数据(从内存中查找)
+     */
+    private List<HospProfitAndLoss> getPeriodData(Map<String, List<HospProfitAndLoss>> dataMap, int year, int month) {
+        String key = buildPeriodKey(year, month);
+        return dataMap.getOrDefault(key, Collections.emptyList());
+    }
+
+    /**
+     * 批量计算同环比及同期金额(使用预加载数据)
+     */
+    public void calculatePeriodComparisonWithPreloadedData(
+            List<HospProfitAndLoss> currentRecords,
+            List<HospProfitAndLoss> prevRecords,
+            List<HospProfitAndLoss> lastYearRecords) {
+
+        if (CollectionUtils.isEmpty(currentRecords)) {
+            return;
+        }
+
+        // 创建报表编号到记录的映射
+        Map<String, HospProfitAndLoss> prevMap = new HashMap<>();
+        for (HospProfitAndLoss record : prevRecords) {
+            String key = buildRecordKey(record);
+            prevMap.put(key, record);
+        }
+
+        Map<String, HospProfitAndLoss> lastYearMap = new HashMap<>();
+        for (HospProfitAndLoss record : lastYearRecords) {
+            String key = buildRecordKey(record);
+            lastYearMap.put(key, record);
+        }
+
+        // 批量更新数据
+        for (HospProfitAndLoss record : currentRecords) {
+            String key = buildRecordKey(record);
+            HospProfitAndLoss prevRecord = prevMap.get(key);
+            HospProfitAndLoss lastYearRecord = lastYearMap.get(key);
+
+            // 设置上期和同期金额
+            record.setPrevPeriodAmount(prevRecord != null ? prevRecord.getAmount() : BigDecimal.ZERO);
+            record.setSamePeriodAmount(lastYearRecord != null ? lastYearRecord.getAmount() : BigDecimal.ZERO);
+
+            // 计算环比和同比
+            record.setMomRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getPrevPeriodAmount()));
+            record.setYoyRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getSamePeriodAmount()));
+        }
+
+        // 批量更新数据库
+        this.updateBatchById(currentRecords);
+    }
+
+    /**
+     * 构建期间键(用于存储和检索数据)
+     */
+    private String buildPeriodKey(int year, int month) {
+        return year + "_" + month;
+    }
+
+    /**
+     * 解析期间键为年月数组
+     */
+    private int[] parsePeriodKey(String key) {
+        String[] parts = key.split("_");
+        return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1])};
+    }
+
+    /**
+     * 构建记录的唯一标识键(责任码 + 报表编号)
+     */
+    private String buildRecordKey(HospProfitAndLoss record) {
+        return String.valueOf(record.getReportNum());
+    }
+
+    /**
+     * 安全地计算百分比:避免除零错误
+     */
+    private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
+        if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
+        return bigDecimal;
+    }
+
+    /**
+     * 执行全院损益后续脚本
+     * @param date
+     * @param reportType
+     */
+    public void execHospProfitSql(String date,Integer reportType){
+        Map<String,String> sqlParameter = new HashMap<>();
         sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE, DateUtils.StringToString(date, DateStyleEnum.YYYY_MM));
-        sqlParameter.put(SQLParameter.REPORT_TYPE_CODE,reportType.toString());
+        sqlParameter.put(SQLParameter.REPORT_TYPE_CODE,String.valueOf(reportType));
         sqlService.autoExecuteSql(CustomSqlTypeEnum.HOSP_PROFIT_CALC.getCode(),sqlParameter);
+
     }
 
     // 计算公式中钱
@@ -1295,6 +1560,364 @@ public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossM
 
     }
 
+    @Override
+    public Object getBatchHospProfitList(String beginComputeDate, String endComputeDate, Long hospId, Integer reportType) {
+        List<HospProfitAndLoss> hospProfitAndLossByDateRange = getHospProfitAndLossByDateRange(beginComputeDate, endComputeDate,reportType);
+        if (CollectionUtils.isEmpty(hospProfitAndLossByDateRange)) {
+            throw new CostException(500, "未进行全院损益计算");
+        }
+        //获取全院损益表配置信息
+        List<ReportForm> reportFormList=getReportFormList(hospId,reportType);
+        if (CollectionUtils.isEmpty(reportFormList)) {
+            throw new CostException(500, "未找到全院损益表配置");
+        }
+        //按年-月进行分组
+        Map<String, List<HospProfitAndLoss>> groupedByYearMonth = hospProfitAndLossByDateRange.stream()
+                .collect(Collectors.groupingBy(
+                        item -> item.getDateYear() + "-" + (item.getDateMonth() < 10 ? "0" + item.getDateMonth() : item.getDateMonth())
+                ));
+        List<BatchCostProfitResponse> responses = new ArrayList<>();
+        List<CostProfitVo> allCostProfitVo=new ArrayList<>();
+        //按年-月处理科室损益数据
+        for (Map.Entry<String, List<HospProfitAndLoss>> entry : groupedByYearMonth.entrySet()){
+            List<HospProfitAndLoss> hospProfitAndLossList = entry.getValue();
+            //转换成成本损益数据
+            List<CostProfitVo> costProfitVos = convertToCostProfitVoList(hospProfitAndLossList, reportFormList,allCostProfitVo);
+            //生成出参样式
+            BatchCostProfitResponse response = new BatchCostProfitResponse();
+            //第13月为审计月份
+            if(hospProfitAndLossList.get(0).getDateMonth()==13){
+                response.setComputeDate(String.format("%s-%s", hospProfitAndLossList.get(0).getDateYear(), "12A"));
+                response.setAuditMonth(true);
+                response.setMonthlyAccumulation(false);
+            }else {
+                response.setComputeDate(entry.getKey());
+                response.setAuditMonth(false);
+                response.setMonthlyAccumulation(false);
+            }
+            response.setProfitVoList(costProfitVos);
+            response.setAllowDrillDown(false);
+            responses.add(response);
+        }
+        responses.sort(Comparator.comparing(BatchCostProfitResponse::getComputeDate));
+        //起止年月不同时代表有多月份需要处理月累计
+        if(!beginComputeDate.equals(endComputeDate)){
+            //获取月度汇总数据
+            List<CostProfitVo> costProfitVos = generateSummaryForMultipleMonths(allCostProfitVo);
+            //填充全院其他收支
+            fillHopsOhterProfit(costProfitVos,responses);
+            if(!CollectionUtils.isEmpty(costProfitVos)){
+                BatchCostProfitResponse response = new BatchCostProfitResponse();
+                response.setComputeDate(String.format("%s至%s", beginComputeDate, endComputeDate));
+                response.setProfitVoList(costProfitVos);
+                response.setAllowDrillDown(false);
+                response.setMonthlyAccumulation(true);
+                response.setAuditMonth(false);
+                responses.add(NumberConstant.ZERO,response);
+            }
+        }
+
+        return responses;
+    }
+
+    /**
+     * 填充全院其他收支
+     * @param multipleMonthsProfitVos
+     * @param responses
+     */
+    public void fillHopsOhterProfit(List<CostProfitVo> multipleMonthsProfitVos,List<BatchCostProfitResponse> responses) {
+        //获取累计月全院其他收支节点
+        Optional<CostProfitVo> firstHopsOhterProfit = multipleMonthsProfitVos.stream().filter(costProfitVo -> costProfitVo.getReportId().equals(-1L)).findFirst();
+        if(!firstHopsOhterProfit.isPresent()||CollectionUtils.isEmpty(firstHopsOhterProfit.get().getChildren())){
+            return;
+        }
+        CostProfitVo standCostProfitVo = firstHopsOhterProfit.get();
+        for (BatchCostProfitResponse response : responses) {
+            //获取月度的全院其他收支节点
+            Optional<CostProfitVo> firstOhterProfit = response.getProfitVoList().stream().filter(costProfitVo -> costProfitVo.getReportId().equals(-1L)).findFirst();
+            //没有全院其他收支的添加一个空数据的全院其他收支
+            if(!firstOhterProfit.isPresent()||CollectionUtils.isEmpty(firstOhterProfit.get().getChildren())){
+                CostProfitVo costProfitVo = BeanUtil.convertObj(standCostProfitVo, CostProfitVo.class);
+                costProfitVo.setChildren(new ArrayList<>());
+                //添加缺失的全院其他收支项目到月度数据中
+                for (CostProfitVo missChildCostProfitVo : standCostProfitVo.getChildren()) {
+                    CostProfitVo newCostProfitVo = BeanUtil.convertObj(missChildCostProfitVo, CostProfitVo.class);
+                    combineReportAndProfitAmount(newCostProfitVo,null);
+                    costProfitVo.getChildren().add(newCostProfitVo);
+                }
+                response.getProfitVoList().add(costProfitVo);
+                continue;
+            }
+            //找出月度缺失的全院其他收支
+            List<CostProfitVo> missChilds = standCostProfitVo.getChildren().stream().filter(standChildCostProfitVo -> !firstOhterProfit.get().getChildren().stream().anyMatch(childCostProfitVo -> standChildCostProfitVo.getReportId().equals(childCostProfitVo.getReportId()))).collect(Collectors.toList());
+            if(CollectionUtils.isEmpty(missChilds)){
+                continue;
+            }
+            //添加缺失的全院其他收支项目到月度数据中
+            for (CostProfitVo missChildCostProfitVo : missChilds) {
+                CostProfitVo costProfitVo = BeanUtil.convertObj(missChildCostProfitVo, CostProfitVo.class);
+                combineReportAndProfitAmount(costProfitVo,null);
+                firstOhterProfit.get().getChildren().add(costProfitVo);
+            }
+        }
+    }
+
+    /**
+     * 生成多月份汇总的科室损益数据
+     *
+     * @param allCostProfitVo 原始数据列表
+     * @return 汇总后的科室损益数据
+     */
+    private List<CostProfitVo> generateSummaryForMultipleMonths(List<CostProfitVo> allCostProfitVo){
+        // 参数校验
+        if (CollectionUtils.isEmpty(allCostProfitVo)) {
+            return Collections.emptyList();
+        }
+        //排除掉13月的数据
+        List<CostProfitVo> activeCostProfitVo = allCostProfitVo.stream().filter(profitVo -> profitVo.getMonth() != 13).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(activeCostProfitVo)) {
+            return Collections.emptyList();
+        }
+        List<CostProfitVo> profitVoList=new ArrayList<>() ;
+        Map<Long, List<CostProfitVo>> reportGroup = allCostProfitVo.stream().collect(Collectors.groupingBy(CostProfitVo::getReportId));
+        reportGroup.forEach((reportId, profitVos) -> {
+            CostProfitVo costProfitVo = BeanUtil.convertObj(profitVos.get(NumberConstant.ZERO), CostProfitVo.class);
+            BigDecimal totalAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalBudgetAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getBudgetAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalPrevPeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getPrevPeriodAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal totalSamePeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getSamePeriodAmount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            costProfitVo.setChildren(null);
+            costProfitVo.setAmount(totalAmount);
+            costProfitVo.setBudgetAmount(totalBudgetAmount);
+            costProfitVo.setPrevPeriodAmount(totalPrevPeriodAmount);
+            costProfitVo.setSamePeriodAmount(totalSamePeriodAmount);
+            costProfitVo.setCompletionRate(calculateProfitRate(costProfitVo.getAmount(), costProfitVo.getBudgetAmount()));
+            costProfitVo.setMomRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getPrevPeriodAmount()), costProfitVo.getPrevPeriodAmount()));
+            costProfitVo.setYoyRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getSamePeriodAmount()), costProfitVo.getSamePeriodAmount()));
+            profitVoList.add(costProfitVo);
+        });
+        //转成树状结构
+        List<CostProfitVo> costProfitVoTree = converToCostProfitVoTree(profitVoList);
+        return costProfitVoTree;
+    }
+
+    /**
+     * 转换为多层级样式全院损益数据
+     * @param hospProfitAndLossList
+     * @param reportFormList
+     * @return
+     */
+    public  List<CostProfitVo> convertToCostProfitVoList(List<HospProfitAndLoss> hospProfitAndLossList,List<ReportForm> reportFormList,List<CostProfitVo> allCostProfitVo ){
+        //全院其他收支项目
+        List<HospProfitAndLoss> otherHospProfitAndLoss = hospProfitAndLossList.stream().filter(i -> NumberConstant.ONE.equals(i.getOriginType())).collect(Collectors.toList());
+        //按报表项目编号map
+        Map<Integer, HospProfitAndLoss> hospProfitAndLossMap = hospProfitAndLossList.stream().collect(Collectors.toMap(HospProfitAndLoss::getReportNum, b -> b));
+        //报表项目转换成多层级损益对象
+        List<CostProfitVo> costProfitVos =reportFormList.stream().map(reportForm -> reportFormToProfitVo(reportForm)).collect(Collectors.toList());
+        //组装全院损益及报表项目信息
+        for (CostProfitVo profitVo : costProfitVos) {
+            //处理年月数据
+            profitVo.setYear(hospProfitAndLossList.get(0).getDateYear());
+            profitVo.setMonth(hospProfitAndLossList.get(0).getDateMonth());
+            //添加损益数据
+            HospProfitAndLoss hospProfitAndLoss = hospProfitAndLossMap.get(profitVo.getReportNum());
+            //组装全院损益及报表项目金额信息
+            combineReportAndProfitAmount(profitVo,hospProfitAndLoss);
+        }
+        //有全院其他收支时添加全院其他收支
+        if(!CollectionUtils.isEmpty(otherHospProfitAndLoss)){
+            //找到配置的损益项目
+            Optional<ReportForm> firstLossReport = reportFormList.stream().filter(i -> NumberConstant.ONE.equals(i.getIsLoss())).findFirst();
+            if(!firstLossReport.isPresent()){
+                throw new CostException(500, "全院损益报表配置有误,未设置损益项目");
+            }
+            //生成一个虚拟的全院其他收支
+            CostProfitVo otherProfit = getOtherProfit(reportFormList);
+            //处理年月数据
+            otherProfit.setYear(otherHospProfitAndLoss.get(NumberConstant.ZERO).getDateYear());
+            otherProfit.setMonth(otherHospProfitAndLoss.get(NumberConstant.ZERO).getDateMonth());
+            costProfitVos.add(otherProfit);
+            ReportForm reportForm = firstLossReport.get();
+            for (int i = 0; i < otherHospProfitAndLoss.size(); i++) {
+                HospProfitAndLoss hospProfitAndLoss = otherHospProfitAndLoss.get(i);
+                CostProfitVo costProfitVo =reportFormToProfitVo(reportForm);
+                //组装全院损益及报表项目金额信息
+                combineReportAndProfitAmount(costProfitVo,hospProfitAndLoss);
+                //处理年月数据
+                costProfitVo.setYear(hospProfitAndLoss.getDateYear());
+                costProfitVo.setMonth(hospProfitAndLoss.getDateMonth());
+                //全院其他收支项目放在虚拟的全院其他收支下
+                costProfitVo.setSort(i);
+                //添加一个负数作为虚拟的报表项目编号
+                Integer reportNum =hospProfitAndLoss.getReportNum();
+                costProfitVo.setReportNum(reportNum);
+                costProfitVo.setId(reportNum.longValue());
+                costProfitVo.setReportId(reportNum.longValue());
+                costProfitVo.setReportName(hospProfitAndLoss.getReportName());
+                costProfitVo.setReportParentId(otherProfit.getReportId());
+                costProfitVos.add(costProfitVo);
+            }
+        }
+        //记录所有月份的损益数据
+        allCostProfitVo.addAll(costProfitVos);
+        //转成树状结构的损益数据
+        List<CostProfitVo> costProfitVoTree = converToCostProfitVoTree(costProfitVos);
+        return costProfitVoTree;
+    }
+
+    /**
+     * 生成一个虚拟的全院其他收支
+     * @param reportFormList
+     * @return
+     */
+    public CostProfitVo getOtherProfit(List<ReportForm> reportFormList) {
+        //全院其他收支
+        CostProfitVo hospProfitVO = reportFormToProfitVo(reportFormList.get(NumberConstant.ZERO));
+        hospProfitVO.setId(-1L);
+        hospProfitVO.setReportId(-1L);
+        hospProfitVO.setReportNum(-1);
+        hospProfitVO.setReportParentId(0L);
+        hospProfitVO.setReportName("全院其他收支");
+        hospProfitVO.setSort(reportFormList.size());
+        return hospProfitVO;
+    }
+
+    /**
+     * 报表项目转换成多层级损益对象
+     * @param reportForm
+     * @return
+     */
+    public CostProfitVo reportFormToProfitVo(ReportForm reportForm){
+        CostProfitVo profitVo = new CostProfitVo();
+        profitVo.setId(reportForm.getId());
+        profitVo.setReportId(reportForm.getId());
+        profitVo.setReportName(reportForm.getReportName());
+        profitVo.setReportParentId(reportForm.getParentId());
+        profitVo.setReportNum(reportForm.getNum());
+        profitVo.setCalcType(reportForm.getCalcType());
+        profitVo.setCalcFormula(reportForm.getCalcFormula());
+        profitVo.setCostType(reportForm.getCostType());
+        profitVo.setShareType(reportForm.getReportType());
+        profitVo.setSort(reportForm.getSort());
+        profitVo.setDescription(reportForm.getDescription());
+        profitVo.setDataType(reportForm.getDataType());
+        profitVo.setDecimalPlace(reportForm.getDecimalPlace());
+        profitVo.setPermil(reportForm.getPermil());
+        return profitVo;
+    }
+
+    /**
+     * 组装全院损益及报表项目的金额信息
+     * @param profitVo
+     * @param hospProfitAndLoss
+     */
+    public void combineReportAndProfitAmount(CostProfitVo profitVo, HospProfitAndLoss hospProfitAndLoss) {
+        if (ObjectUtils.isEmpty(hospProfitAndLoss)) {
+            profitVo.setAmount(BigDecimal.ZERO);
+            profitVo.setSamePeriodAmount(BigDecimal.ZERO);
+            profitVo.setPrevPeriodAmount(BigDecimal.ZERO);
+            profitVo.setBudgetAmount(BigDecimal.ZERO);
+            profitVo.setYoyRate(BigDecimal.ZERO);
+            profitVo.setMomRate(BigDecimal.ZERO);
+            profitVo.setCompletionRate(BigDecimal.ZERO);
+        } else {
+            profitVo.setAmount(hospProfitAndLoss.getAmount());
+            profitVo.setSamePeriodAmount(hospProfitAndLoss.getSamePeriodAmount());
+            profitVo.setPrevPeriodAmount(hospProfitAndLoss.getPrevPeriodAmount());
+            profitVo.setBudgetAmount(hospProfitAndLoss.getBudgetAmount());
+            profitVo.setYoyRate(hospProfitAndLoss.getYoyRate());
+            profitVo.setMomRate(hospProfitAndLoss.getMomRate());
+            profitVo.setCompletionRate(hospProfitAndLoss.getCompletionRate());
+        }
+    }
+
+    /**
+     * 转成树状结构的损益数据
+     * @param costProfitVos
+     * @return
+     */
+    public List<CostProfitVo> converToCostProfitVoTree(List<CostProfitVo> costProfitVos){
+        // 参数校验
+        if (CollectionUtils.isEmpty(costProfitVos)) {
+            return Collections.emptyList();
+        }
+        Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
+        List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
+        collect.remove(NumberConstant.ZERO_L);
+        for (CostProfitVo costProfitVo : costProfitParentVos) {
+            List<CostProfitVo> costProfitVo1 = collect.get(costProfitVo.getReportId());
+            if (!CollectionUtils.isEmpty(costProfitVo1)) {
+                costProfitVo.setChildren(setChildrenProfitVo(costProfitVo1, collect));
+            }
+        }
+        if (!CollectionUtils.isEmpty(costProfitParentVos)) {
+            costProfitParentVos.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
+        }
+        return  costProfitParentVos;
+    }
+
+    private List<CostProfitVo> setChildrenProfitVo(List<CostProfitVo> child, Map<Long, List<CostProfitVo>> collect) {
+        for (CostProfitVo costProfitVo : child) {
+            if (!CollectionUtils.isEmpty(collect.get(costProfitVo.getReportId()))) {
+                costProfitVo.setChildren(setChildrenProfitVo(collect.get(costProfitVo.getReportId()), collect));
+            }
+        }
+        if (!CollectionUtils.isEmpty(child)) {
+            child.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
+        }
+        return child;
+    }
+
+    /**
+     * 获取全院损益表配置信息
+     * @param hospId
+     * @param reportType
+     * @return
+     */
+    public List<ReportForm> getReportFormList(Long hospId,Integer reportType ) {
+        List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
+                .eq(ReportForm::getHospId, hospId)
+                .eq(ReportForm::getReportType, reportType)
+                .eq(ReportForm::getDeleteTime , NumberConstant.ZERO)
+                .eq(ReportForm::getHide, NumberConstant.ONE));
+        return  reportFormList;
+    }
+
+
+    /**
+     * 获取指定年月区间的全院损益数据
+     * @param beginComputeDate
+     * @param endComputeDate
+     * @return
+     */
+    public List<HospProfitAndLoss> getHospProfitAndLossByDateRange(String beginComputeDate, String endComputeDate, Integer reportType) {
+        // 解析开始和结束时间
+        int startYear = Integer.parseInt(beginComputeDate.split("-")[0]);
+        int startMonth = Integer.parseInt(beginComputeDate.split("-")[1]);
+        int endYear = Integer.parseInt(endComputeDate.split("-")[0]);
+        int endMonth = Integer.parseInt(endComputeDate.split("-")[1]);
+
+        if( startYear * 100 + startMonth> endYear * 100 + endMonth){
+            throw new CostException("开始时间不能大于结束时间");
+        }
+        //如果截止月份是12月要自动添加第13月的数据
+        if(endMonth==12)
+        {
+            endMonth=13;
+        }
+        List<HospProfitAndLoss> list = this.list(new QueryWrapper<HospProfitAndLoss>().lambda()
+                .eq(HospProfitAndLoss::getDeleteTime, NumberConstant.ZERO)
+                .eq(HospProfitAndLoss::getHospId, UserContext.getHospId())
+                .eq(HospProfitAndLoss::getReportType, reportType)
+                .apply("(date_year * 100 + date_month) >= {0}", startYear * 100 + startMonth)
+                .apply("(date_year * 100 + date_month) <= {0}", endYear * 100 + endMonth));
+        return list;
+    }
+
     private static @NotNull HospProfitVO getHospProfitVO(List<HospProfitAndLoss> hospAllList, int i,int reportType) {
         HospProfitAndLoss hospProfitAndLoss = hospAllList.get(i);
         HospProfitVO hospProfitVO1 = new HospProfitVO();

+ 5 - 0
src/main/java/com/kcim/service/impl/IncomeCollectionServiceImpl.java

@@ -440,4 +440,9 @@ public class IncomeCollectionServiceImpl
         );
         return list;
     }
+
+    @Override
+    public List<IncomeCollection> getResponsibilitiesAccounts(int year, int month, Long hospId) {
+        return baseMapper.getResponsibilitiesAccounts(year, month, hospId);
+    }
 }

+ 228 - 9
src/main/java/com/kcim/service/impl/KpiComputeImportServiceImpl.java

@@ -18,15 +18,14 @@ import com.kcim.service.CenterService;
 import com.kcim.service.KpiComputeImportService;
 import com.kcim.vo.CommonTitleVo;
 import com.kcim.vo.DictDataVo;
+import com.kcim.vo.SheetImportResultVO;
 import com.kcim.vo.UserInfoVO;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.apache.ibatis.jdbc.SqlRunner;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -39,6 +38,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
@@ -168,7 +169,7 @@ public class KpiComputeImportServiceImpl implements KpiComputeImportService {
             assert fileName != null;
             File file1 = new File(fileName);
             FileUtils.copyInputStreamToFile(file.getInputStream(), file1);
-            String excelSql = readExcelSql(file1, tableName, id);
+            String excelSql = readExcelSql(file1, tableName, id, computeDate);
             SqlRunner sqlRunner = new SqlRunner(getConnection());
             sqlRunner.insert(excelSql);
 
@@ -240,6 +241,220 @@ public class KpiComputeImportServiceImpl implements KpiComputeImportService {
         }
     }
 
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
+    public List<SheetImportResultVO> importMultipleSheets(String computeDate, MultipartFile file) {
+        List<CommonTitleVo> tableList = (List<CommonTitleVo>) getTableList();
+        String fileName = file.getOriginalFilename();
+        String uploadFileUrl = uploadFile(file, fileName);
+        List<SheetImportResultVO> sheetResults = new ArrayList<>();
+        try {
+            // 使用系统临时目录显式创建临时文件
+            File tempDir = new File(System.getProperty("java.io.tmpdir"));
+            File tempFile = new File(tempDir, "excel-" + UUID.randomUUID() + ".tmp");
+
+            // 确保文件存在并正确关闭流
+            try (InputStream inputStream = file.getInputStream()) {
+                Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            }
+
+            try (Workbook workbook = WorkbookFactory.create(tempFile)) {
+                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
+                    Sheet sheet = workbook.getSheetAt(i);
+                    String sheetName = sheet.getSheetName();
+
+                    SheetImportResultVO resultItem = new SheetImportResultVO();
+                    resultItem.setSheetName(sheetName);
+                    resultItem.setSheetIndex(i);
+
+                    Optional<CommonTitleVo> mapping = tableList.stream()
+                            .filter(t -> t.getName().equals(sheetName))
+                            .findFirst();
+
+                    if (!mapping.isPresent()) {
+                        log.warn("未找到sheet页 '{%s}' 对应的数据表配置,跳过导入", sheetName);
+                        resultItem.setSuccess(false);
+                        resultItem.setErrorMessage("未找到对应的数据库表配置");
+                        sheetResults.add(resultItem);
+                        continue;
+                    }
+
+                    String tableName = mapping.get().getCode();
+                    resultItem.setTableName(tableName);
+
+                    try {
+                        KpiComputeImport kpiComputeImport = new KpiComputeImport();
+                        kpiComputeImport.setComputeDate(computeDate);
+                        kpiComputeImport.setImportStatus(NumberConstant.ZERO);
+                        kpiComputeImport.setCreateTime(new Date());
+                        kpiComputeImport.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
+                        kpiComputeImport.setUrl(uploadFileUrl);
+                        kpiComputeImport.setTableName(tableName);
+                        kpiComputeImport.setFileName(String.format("%s_%s", fileName, sheetName));
+                        kpiComputeImport.setHospId(UserContext.getCurrentLoginHospId());
+                        kpiComputeImport.setDelFlag(NumberConstant.ZERO);
+
+                        repository.save(kpiComputeImport);
+
+                        insertExcelDataForSheet(kpiComputeImport.getId(), tableName, file, fileName, computeDate, sheet);
+
+                        resultItem.setSuccess(true);
+                        resultItem.setImportId(kpiComputeImport.getId());
+                        resultItem.setImportTime(kpiComputeImport.getCreateTime());
+
+                    } catch (Exception e) {
+                        log.error(String.format("sheet页 '%s' 导入失败: %s", sheetName, e.getMessage()));
+                        resultItem.setSuccess(false);
+                        resultItem.setErrorMessage("导入失败: " + e.getMessage());
+                    }
+                    sheetResults.add(resultItem);
+                }
+            } finally {
+                // 删除临时文件
+                if (tempFile.exists()) {
+                    tempFile.delete();
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("导入发生异常: " + e.getMessage(), e);
+        }
+        return sheetResults;
+    }
+
+
+    @SneakyThrows
+    private void insertExcelDataForSheet(Integer id, String tableName, MultipartFile file, String fileName, String computeDate, Sheet sheet) {
+        // 将MultipartFile转换为InputStream
+        InputStream inputStream = file.getInputStream();
+
+        // 这里假设有一个方法可以从给定的InputStream和sheet对象中读取SQL语句
+        List<String> excelSql = readExcelSqlFromSheet(inputStream, sheet, tableName, id, computeDate);
+
+        // 执行SQL插入操作
+        SqlRunner sqlRunner = new SqlRunner(getConnection());
+        for (String sql : excelSql) {
+            sqlRunner.insert(sql);
+        }
+
+        // 更新新增人和时间
+        String updateSql = "UPDATE `" + tableName + "` SET " +
+                "`create_user` = '" + UserContext.getCurrentUser().getId() + "', " +
+                "`create_time` = '" + DateUtils.formatDate2String(new Date()) + "' " +
+                "WHERE `import_id` = '" + id + "';";
+        sqlRunner.run(updateSql);
+    }
+
+    private static final int BATCH_SIZE = 500; // 每批次插入的记录数
+
+    private List<String> readExcelSqlFromSheet(InputStream inputStream, Sheet sheet, String tableName, Integer id, String computeDate) throws IOException {
+        List<String> sqlList = new ArrayList<>();
+        boolean firstRow = true;
+        Row headerRow = null;
+        DataFormatter dataFormatter = new DataFormatter();
+        int rowCount = 0;
+        boolean hasComputeDateField = false;
+
+        // 第一次遍历获取字段信息并判断是否有 compute_date 字段
+        for (Row row : sheet) {
+            if (rowCount == 0) {
+                headerRow = row;
+                // 检查字段中是否包含 compute_date
+                for (int i = 0; i < headerRow.getLastCellNum(); i++) {
+                    Cell headerCell = headerRow.getCell(i);
+                    if (headerCell != null && "compute_date".equals(headerCell.getStringCellValue())) {
+                        hasComputeDateField = true;
+                        break;
+                    }
+                }
+                rowCount++;
+                continue;
+            }
+            break; // 只需要读取第一行判断字段
+        }
+
+        // 第二次遍历处理数据行
+        StringBuilder currentBatchValues = new StringBuilder();
+        int batchCount = 0;
+        // 新增变量用于记录实际数据行数
+        int actualRowCount = 0;
+
+        for (Row row : sheet) {
+            if (actualRowCount < 2) {
+                actualRowCount++;
+                continue; // 跳过前两行(标题行 + 说明行)
+            }
+
+            StringBuilder valueSb = new StringBuilder();
+            valueSb.append("(");
+
+            for (int i = 0; i < row.getLastCellNum(); i++) {
+                if (i > 0) {
+                    valueSb.append(", ");
+                }
+                Cell cell = row.getCell(i);
+                if (cell == null) {
+                    valueSb.append("NULL");
+                    continue;
+                }
+                cell.setCellType(CellType.STRING);
+                valueSb.append("'").append(cell.getStringCellValue().replace("'", "''")).append("'");
+            }
+
+            // 添加 import_id 和 hosp_id
+            valueSb.append(", ").append(id)
+                    .append(", ").append(UserContext.getCurrentLoginHospId());
+
+            // 如果字段中没有 compute_date,才手动添加
+            if (!hasComputeDateField) {
+                valueSb.append(", '").append(computeDate).append("'");
+            }
+
+            valueSb.append(")");
+
+            if (batchCount == 0) {
+                // 构建字段名部分
+                currentBatchValues.setLength(0); // 清空之前的缓存
+                currentBatchValues.append("INSERT INTO `").append(tableName).append("` (");
+
+                for (int i = 0; i < headerRow.getLastCellNum(); i++) {
+                    if (i > 0) {
+                        currentBatchValues.append(", ");
+                    }
+                    Cell headerCell = headerRow.getCell(i);
+                    currentBatchValues.append("`").append(headerCell.getStringCellValue()).append("`");
+                }
+
+                currentBatchValues.append(", `import_id`, `hosp_id`");
+                if (!hasComputeDateField) {
+                    currentBatchValues.append(", `compute_date`");
+                }
+                currentBatchValues.append(") VALUES ");
+            } else {
+                currentBatchValues.append(", ");
+            }
+
+            currentBatchValues.append(valueSb.toString());
+            batchCount++;
+
+            // 如果达到批次大小,保存当前批次并重置
+            if (batchCount >= BATCH_SIZE) {
+                sqlList.add(currentBatchValues.toString());
+                batchCount = 0;
+            }
+
+            actualRowCount++; // 使用独立变量追踪实际行数
+        }
+
+        // 添加最后一批未满的数据
+        if (batchCount > 0) {
+            sqlList.add(currentBatchValues.toString());
+        }
+
+        return sqlList;
+    }
+
+
     /**
      * 复原导入数据
      *
@@ -273,7 +488,7 @@ public class KpiComputeImportServiceImpl implements KpiComputeImportService {
         }
     }
 
-    public static String readExcelSql(File file, String tableName, Integer id) throws IOException {
+    public static String readExcelSql(File file, String tableName, Integer id, String computeDate) throws IOException {
         // 获取excel工作簿对象
         String sql = null;
         String fileName = file.getName();
@@ -315,7 +530,7 @@ public class KpiComputeImportServiceImpl implements KpiComputeImportService {
                     i++;
                 }
                 //组装记录表和hospId
-                setCommonData(id, dataList);
+                setCommonData(id, dataList, computeDate);
                 sql = insertFromMap(dataList, tableName);
 
             }
@@ -356,17 +571,21 @@ public class KpiComputeImportServiceImpl implements KpiComputeImportService {
                     }
                     i++;
                 }
-                setCommonData(id, dataList);
+                setCommonData(id, dataList, computeDate);
                 sql = insertFromMap(dataList, tableName);
             }
         }
         return sql;
     }
 
-    private static void setCommonData(Integer id, List<Map<String, Object>> dataList) {
+    private static void setCommonData(Integer id, List<Map<String, Object>> dataList, String computeDate) {
         if (!CollectionUtils.isEmpty(dataList)) {
             dataList.forEach(stringObjectMap -> {
                 stringObjectMap.put("hosp_id", UserContext.getCurrentLoginHospId());
+                //Excel字段里没有传核算年月的,用传入的核算年月
+                if (!stringObjectMap.containsKey("compute_date")) {
+                    stringObjectMap.put("compute_date", computeDate);
+                }
                 stringObjectMap.put("import_id", id);
             });
         }

+ 7 - 5
src/main/java/com/kcim/service/impl/PatientItemImportServiceImpl.java

@@ -24,11 +24,10 @@ import com.kcim.service.CenterService;
 import com.kcim.service.CostIncomeFileService;
 import com.kcim.service.PatientItemImportService;
 import com.kcim.vo.DictDataVo;
-import com.kcim.vo.PatientInfoVo;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
@@ -41,7 +40,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.net.URLEncoder;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import static com.kcim.common.constants.Constant.CHARGE_ITEM_TYPE;
@@ -259,8 +261,8 @@ public class PatientItemImportServiceImpl implements PatientItemImportService {
     }
 
     @Override
-    public List<PatientInfoVo> getPatientItemPatientInfo(String filter, String computeDate) {
-        return repository.getPatientItemPatientInfo(computeDate,filter);
+    public PageUtils getPatientItemPatientInfo(Integer current, Integer pageSize, String filter, String computeDate) {
+        return repository.getPatientItemPatientInfo(current, pageSize, computeDate,filter);
     }
 
     /**

+ 305 - 114
src/main/java/com/kcim/service/impl/ProjectCostServiceImpl.java

@@ -19,6 +19,7 @@ import com.kcim.service.ResponsibilityDepartmentService;
 import com.kcim.service.SqlService;
 import com.kcim.vo.*;
 import com.kcim.web.reponse.ProjectCostResponse;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.jetbrains.annotations.NotNull;
 import org.springframework.stereotype.Service;
@@ -47,6 +48,7 @@ import static com.kcim.service.impl.DrugMaterialCalculateServiceImpl.getVisitNoR
  **/
 @Service("ProjectCostService")
 @Slf4j
+@AllArgsConstructor
 public class ProjectCostServiceImpl implements ProjectCostService {
     private static final Integer LIMIT = 1000;
     ResponsibilityRepository responsibilityRepository;
@@ -69,6 +71,8 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      * 科室损益
      */
     CostDepartmentProfitRepository costDepartmentProfitRepository;
+
+    CostDepartmentProfitAccountRepository costDepartmentProfitAccountRepository;
     /**
      * 项目分摊参数设置
      */
@@ -76,6 +80,8 @@ public class ProjectCostServiceImpl implements ProjectCostService {
 
     ComputeShareParamRepository computeShareParamRepository;
 
+    ComputeProjectCostAccountRepository projectCostAccountRepository;
+
     ItemRepository itemRepository;
 
     ResponsibilityDepartmentRepository responsibilityDepartmentRepository;
@@ -104,34 +110,34 @@ public class ProjectCostServiceImpl implements ProjectCostService {
 
     ResponsibilityDepartmentService responsibilityDepartmentService;
 
-    public ProjectCostServiceImpl(ResponsibilityDepartmentService responsibilityDepartmentService,SqlService sqlService,ResponsibilityRepository responsibilityRepository, ComputeProjectCostRepository repository, ComputeProjectCostDetailRepository detailRepository, ComputeProjectGroupCostDetailRepository groupDetailRepository, ImportPatientItemRepository importPatientItemRepository, ShareParamCostRepository shareParamCostRepository, ShareParamCostDetailRepository shareParamCostDetailRepository, CostDepartmentProfitRepository costDepartmentProfitRepository, ShareParamTypeMapRepository shareParamTypeMapRepository, ComputeShareParamRepository computeShareParamRepository, ItemRepository itemRepository, ResponsibilityDepartmentRepository responsibilityDepartmentRepository, CenterService centerService, ComputePatientProjectCostRepository computePatientProjectCostRepository, ComputePatientProjectCostDetailRepository computePatientProjectCostDetailRepository, ComputePatientProjectGroupCostDetailRepository computePatientProjectGroupCostDetailRepository, ComputeStandShareParamRepository computeStandShareParamRepository, ComputeStandProjectCostRepository standProjectCostRepository, ComputeStandProjectCostDetailRepository standProjectCostDetailRepository, ComputeStandProjectGroupCostDetailRepository standProjectGroupCostDetailRepository, ComputeStandPatientProjectCostRepository computeStandPatientProjectCostRepository, ComputeStandPatientProjectCostDetailRepository computeStandPatientProjectCostDetailRepository, ComputeStandPatientProjectGroupCostDetailRepository computeStandPatientProjectGroupCostDetailRepository) {
-        this.responsibilityRepository = responsibilityRepository;
-        this.repository = repository;
-        this.sqlService = sqlService;
-
-        this.detailRepository = detailRepository;
-        this.groupDetailRepository = groupDetailRepository;
-        this.importPatientItemRepository = importPatientItemRepository;
-        this.shareParamCostRepository = shareParamCostRepository;
-        this.shareParamCostDetailRepository = shareParamCostDetailRepository;
-        this.costDepartmentProfitRepository = costDepartmentProfitRepository;
-        this.shareParamTypeMapRepository = shareParamTypeMapRepository;
-        this.computeShareParamRepository = computeShareParamRepository;
-        this.itemRepository = itemRepository;
-        this.responsibilityDepartmentRepository = responsibilityDepartmentRepository;
-        this.centerService = centerService;
-        this.computePatientProjectCostRepository = computePatientProjectCostRepository;
-        this.computePatientProjectCostDetailRepository = computePatientProjectCostDetailRepository;
-        this.computePatientProjectGroupCostDetailRepository = computePatientProjectGroupCostDetailRepository;
-        this.computeStandShareParamRepository = computeStandShareParamRepository;
-        this.standProjectCostRepository = standProjectCostRepository;
-        this.standProjectCostDetailRepository = standProjectCostDetailRepository;
-        this.standProjectGroupCostDetailRepository = standProjectGroupCostDetailRepository;
-        this.computeStandPatientProjectCostRepository = computeStandPatientProjectCostRepository;
-        this.computeStandPatientProjectCostDetailRepository = computeStandPatientProjectCostDetailRepository;
-        this.computeStandPatientProjectGroupCostDetailRepository = computeStandPatientProjectGroupCostDetailRepository;
-        this.responsibilityDepartmentService=responsibilityDepartmentService;
-    }
+//    public ProjectCostServiceImpl(ResponsibilityDepartmentService responsibilityDepartmentService,SqlService sqlService,ResponsibilityRepository responsibilityRepository, ComputeProjectCostRepository repository, ComputeProjectCostDetailRepository detailRepository, ComputeProjectGroupCostDetailRepository groupDetailRepository, ImportPatientItemRepository importPatientItemRepository, ShareParamCostRepository shareParamCostRepository, ShareParamCostDetailRepository shareParamCostDetailRepository, CostDepartmentProfitRepository costDepartmentProfitRepository, ShareParamTypeMapRepository shareParamTypeMapRepository, ComputeShareParamRepository computeShareParamRepository, ItemRepository itemRepository, ResponsibilityDepartmentRepository responsibilityDepartmentRepository, CenterService centerService, ComputePatientProjectCostRepository computePatientProjectCostRepository, ComputePatientProjectCostDetailRepository computePatientProjectCostDetailRepository, ComputePatientProjectGroupCostDetailRepository computePatientProjectGroupCostDetailRepository, ComputeStandShareParamRepository computeStandShareParamRepository, ComputeStandProjectCostRepository standProjectCostRepository, ComputeStandProjectCostDetailRepository standProjectCostDetailRepository, ComputeStandProjectGroupCostDetailRepository standProjectGroupCostDetailRepository, ComputeStandPatientProjectCostRepository computeStandPatientProjectCostRepository, ComputeStandPatientProjectCostDetailRepository computeStandPatientProjectCostDetailRepository, ComputeStandPatientProjectGroupCostDetailRepository computeStandPatientProjectGroupCostDetailRepository) {
+//        this.responsibilityRepository = responsibilityRepository;
+//        this.repository = repository;
+//        this.sqlService = sqlService;
+//
+//        this.detailRepository = detailRepository;
+//        this.groupDetailRepository = groupDetailRepository;
+//        this.importPatientItemRepository = importPatientItemRepository;
+//        this.shareParamCostRepository = shareParamCostRepository;
+//        this.shareParamCostDetailRepository = shareParamCostDetailRepository;
+//        this.costDepartmentProfitRepository = costDepartmentProfitRepository;
+//        this.shareParamTypeMapRepository = shareParamTypeMapRepository;
+//        this.computeShareParamRepository = computeShareParamRepository;
+//        this.itemRepository = itemRepository;
+//        this.responsibilityDepartmentRepository = responsibilityDepartmentRepository;
+//        this.centerService = centerService;
+//        this.computePatientProjectCostRepository = computePatientProjectCostRepository;
+//        this.computePatientProjectCostDetailRepository = computePatientProjectCostDetailRepository;
+//        this.computePatientProjectGroupCostDetailRepository = computePatientProjectGroupCostDetailRepository;
+//        this.computeStandShareParamRepository = computeStandShareParamRepository;
+//        this.standProjectCostRepository = standProjectCostRepository;
+//        this.standProjectCostDetailRepository = standProjectCostDetailRepository;
+//        this.standProjectGroupCostDetailRepository = standProjectGroupCostDetailRepository;
+//        this.computeStandPatientProjectCostRepository = computeStandPatientProjectCostRepository;
+//        this.computeStandPatientProjectCostDetailRepository = computeStandPatientProjectCostDetailRepository;
+//        this.computeStandPatientProjectGroupCostDetailRepository = computeStandPatientProjectGroupCostDetailRepository;
+//        this.responsibilityDepartmentService=responsibilityDepartmentService;
+//    }
 
     /**
      * 项目成本计算分页查询
@@ -257,11 +263,23 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      */
     @Override
     public void computeItemCost(String computeDate){
-        //项目成本分摊计算
-        calcItemCostAllocation(computeDate);
-        log.info("项目成本分摊计算完成开始执行后续处理脚本");
-        //执行后续处理脚本
-        execItemCostSQL(computeDate);
+        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.ONE);
+        //走系统计算逻辑
+        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)){
+            //根据参数判断是否走新的计算流程
+            if(NumberConstant.ONE_S.equals(centerService.getParameterValue(ParameterConstant.USER_HOSP_ITEM_CALC))){
+                //项目成本分摊计算
+                calcItemCostAllocation(computeDate);
+            }else{
+                computeItemCostACtion(computeDate);
+            }
+        }
+        //走自定义SQL计算逻辑
+        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            log.info("项目成本分摊计算完成开始执行后续处理脚本");
+            //执行后续处理脚本
+            execItemCostSQL(computeDate);
+        }
     }
 
     /**
@@ -443,11 +461,7 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         if (shareCount == 0) {
             throw new CostException("未进行项目分摊参数计算,请先进行项目分摊参数计算,当前计算中止");
         }
-        //医疗服务项目字典
-        List<Item> itemList = itemRepository.getList();
-        if (CollectionUtils.isEmpty(itemList)) {
-            throw new CostException("医疗服务项目未维护,请先添加医疗服务项目再进行计算,当前计算中止");
-        }
+
         //月度患者收费项目信息
         List<PatientItemDepartmentGroupVo> ptChargeItems = importPatientItemRepository.getByDepartGroupComputeDateItem(computeDate, currentUser);
         if (CollectionUtils.isEmpty(ptChargeItems)){
@@ -459,24 +473,46 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         if (CollectionUtils.isEmpty(shareParamCostVos)){
             throw new CostException("没有项目分摊配置信息无法分摊,请联系管理员");
         }
+        //按成本列代码分组
+        Map<String, List<ShareParamCostVo>> shareParamCostMap = shareParamCostVos.stream().collect(Collectors.groupingBy(ShareParamCostVo::getColumnCode));
 
-        //作废上次计算记录
-        repository.removeByComputeDate(computeDate, currentUser);
-        detailRepository.removeByComputeDate(computeDate, currentUser);
-        groupDetailRepository.removeByComputeDate(computeDate, currentUser);
+        //获取科室损益报表数据
+        List<CostDepartmentProfit> costDepartmentProfits = costDepartmentProfitRepository.getDepartmentProfit(computeDate);
+        if (CollectionUtils.isEmpty(costDepartmentProfits)){
+            throw new CostException("未进行科室损益计算,请先进行科室损益计算,当前计算中止");
+        }
+        //按报表类型+报表编码+责任中心分组
+        Map<String, List<CostDepartmentProfit>> deptProfitGroup =costDepartmentProfits.stream().collect(Collectors.groupingBy(
+                                cost ->String.format("%s-%s-%s",cost.getShareType(),cost.getReportNum(),cost.getResponsibilityCode())));
+
+        //获取科室损益的会计科目金额
+        List<CostDepartmentProfitAccount> deptPriftAccountList = costDepartmentProfitAccountRepository.getList(computeDate);
+        Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap;
+        if(CollectionUtils.isEmpty(deptPriftAccountList)){
+            deptPriftAccountMap = new HashMap<>();
+        }else{
+            deptPriftAccountMap= deptPriftAccountList.stream().collect(Collectors.groupingBy(CostDepartmentProfitAccount::getDeptProfitId));
+        }
+
+        //获取责任中心的医疗服务项目字典
+        List<Item> itemList = itemRepository.getRespItemList();
+        Map<String, Map<String, List<Item>>> respItemGroup = itemList.stream()
+                .collect(Collectors.groupingBy(Item::getResponsibilityCode,
+                        Collectors.groupingBy(Item::getCode)));
 
         //项目成本分摊配置主表信息(项目成本列配置)
         List<ShareParamCost> ShareParamCosts = shareParamCostRepository.getList(null);
-        //科室责任中心对照信息
-        List<ResponsibilityDepartIdVO> responsibilityDeptMaps = responsibilityDepartmentService.getResponsibilityDepart();
+        Map<String, List<ShareParamCost>> shareParamCostGroup = ShareParamCosts.stream().collect(Collectors.groupingBy(ShareParamCost::getItemType));
         //分摊参数信息
         List<ComputeShareParamDetailVo> computeShareParamDetails = computeShareParamRepository.getComputeShareParamDetail(computeDate);
+        Map<String, List<ComputeShareParamDetailVo>> shareParamDetailValueGroup = computeShareParamDetails.stream().collect(Collectors.groupingBy(
+                cost -> String.format("%s-%s-%s", cost.getResponsibilityCode(), cost.getItemType(), cost.getCode())));
         //分摊参数按责任中心汇总信息
         List<ComputeShareParamDetailVo> computeShareParamDetailGroup = computeShareParamRepository.getComputeShareParamDetailGroup(computeDate);
+        Map<String, List<ComputeShareParamDetailVo>> shareParamDetailGroup = computeShareParamDetailGroup.stream().collect(Collectors.groupingBy(
+                cost -> String.format("%s-%s-%s", cost.getItemType(), cost.getShareParamCode(), cost.getResponsibilityCode())));
         //要计算的科室收费项目
         List<ComputeShareParamDetailVo> computeResponsibilityItems = computeShareParamRepository.getComputeResponsibilityItem(computeDate);
-        //获取科室损益报表数据
-        List<CostDepartmentProfit> costDepartmentProfits = costDepartmentProfitRepository.getDepartmentProfit(computeDate);
 
         //开始项目成本分摊计算
         List<ComputeProjectCost> computeProjectCosts=new ArrayList<>();
@@ -487,16 +523,17 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         //按项目类别+责任中心代码+项目代码逐个计算项目分摊金额
         computeResponsibilityItems.stream().forEach(responsibilityItem->{
             //创建项目成本主表对象
-            ComputeProjectCost projectCost = createComputeProjectCost(computeDate, currentUser, responsibilityItem);
+            ComputeProjectCost projectCost = createComputeProjectCost(computeDate, currentUser, responsibilityItem,respItemGroup);
             computeProjectCosts.add(projectCost);
+            String shareParamDetailValueKey = String.format("%s-%s-%s", projectCost.getResponsibilityCode(),projectCost.getItemType(), projectCost.getCode());
             //获取项目对应分摊参数数值
-            List<ComputeShareParamDetailVo> itemShareParams = computeShareParamDetails.stream().filter(shareParamGroup -> shareParamGroup.getResponsibilityCode().equals(projectCost.getResponsibilityCode())
-                    && shareParamGroup.getCode().equals(projectCost.getCode()) && shareParamGroup.getItemType().equals(projectCost.getItemType())).collect(Collectors.toList());
+            List<ComputeShareParamDetailVo> itemShareParams =shareParamDetailValueGroup.get(shareParamDetailValueKey);
             if (CollectionUtils.isEmpty(itemShareParams)){
                 throw new CostException(String.format("找不到项目的[%s-%s]对应的分摊分摊参数,请重新计算分摊参数",projectCost.getItemType(),projectCost.getName()));
             }
+            Map<String, List<ComputeShareParamDetailVo>> respShareParamValueMap = itemShareParams.stream().collect(Collectors.groupingBy(ComputeShareParamDetailVo::getShareParamCode));
             //取项目对应的分摊配置
-            List<ShareParamCost> itemShareParamCost = ShareParamCosts.stream().filter(shareParamCost -> shareParamCost.getItemType().equals(projectCost.getItemType())).collect(Collectors.toList());
+            List<ShareParamCost> itemShareParamCost =shareParamCostGroup.get(projectCost.getItemType());
             if (CollectionUtils.isEmpty(itemShareParamCost)){
                 throw new CostException(String.format("类型[%s]没有对应分摊配置,请联系管理员",projectCost.getItemType()));
             }
@@ -504,7 +541,7 @@ public class ProjectCostServiceImpl implements ProjectCostService {
             //按项目分摊配置计算项目的所有项目成本列的分摊金额
             itemShareParamCost.stream().forEach(shareParamCost->{
                 ComputeProjectCostDetail cmputeProjectCostDetail=createComputeProjectCostDetail(computeDate, currentUser,incomeShareParam,responsibilityItem,projectCost,
-                        shareParamCost,shareParamCostVos,itemShareParams,computeShareParamDetailGroup,costDepartmentProfits);
+                                                        shareParamCost,shareParamCostMap,respShareParamValueMap,shareParamDetailGroup, deptProfitGroup, deptPriftAccountMap);
                 computeProjectCostDetailChilds.add(cmputeProjectCostDetail);
             });
             computeProjectCostDetails.addAll(computeProjectCostDetailChilds);
@@ -526,21 +563,59 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         if (CollectionUtils.isEmpty(computeProjectCosts)) {
             throw new CostException("没有任何可保存的数据");
         }
+
+        //作废上次计算记录
+        repository.removeByComputeDate(computeDate, currentUser);
+        detailRepository.removeByComputeDate(computeDate, currentUser);
+        groupDetailRepository.removeByComputeDate(computeDate, currentUser);
+        projectCostAccountRepository.removeByComputeDate(computeDate, currentUser);
+
         //保存项目分摊主表对象数据
         repository.saveBatch(computeProjectCosts, 500);
         if (!CollectionUtils.isEmpty(computeProjectCostDetails)) {
             //保存项目分摊明细表对象数据
             computeProjectCostDetails.stream().forEach(projectCostDetail->projectCostDetail.setProjectCostId(projectCostDetail.getComputeProjectCost().getId()));
-            detailRepository.saveBatch(computeProjectCostDetails, 500);
+            detailRepository.batchInsert(computeProjectCostDetails);
         }
         if (!CollectionUtils.isEmpty(computeProjectGroupCostDetails)) {
             //保存项目分摊汇总表对象数据
             computeProjectGroupCostDetails.stream().forEach(projectCostDetail->projectCostDetail.setProjectCostId(projectCostDetail.getComputeProjectCost().getId()));
-            groupDetailRepository.saveBatch(computeProjectGroupCostDetails, 500);
+            groupDetailRepository.batchInsert(computeProjectGroupCostDetails);
         }
+        //保存项目成本对应的会计科目信息
+        saveProjectCostAccountList(computeProjectCosts);
 
+    }
 
+    /**
+     * 保存项目成本对应的会计科目信息
+     * @param computeProjectCosts
+     */
+    public void saveProjectCostAccountList(List<ComputeProjectCost> computeProjectCosts){
+        List<ComputeProjectCostAccount> projectCostAccountList=new ArrayList<>();
+        for (ComputeProjectCost projectCost : computeProjectCosts) {
+            List<ComputeProjectCostAccount> itemAccountList =new ArrayList<>();
+            itemAccountList.addAll(projectCost.getProjectCostAccountMap().values());
+            if (CollectionUtils.isEmpty(itemAccountList)) {
+                continue;
+            }
+            itemAccountList.forEach(itemAccount->{
+                itemAccount.setProjectCostId(projectCost.getId());
+                //计算单个项目的金额
+                if(BigDecimal.ZERO.compareTo(projectCost.getQuantity()) == NumberConstant.ZERO){
+                    itemAccount.setComputeSingleResult(BigDecimal.ZERO);
+                }else{
+                    BigDecimal divide = itemAccount.getComputeResult().divide(projectCost.getQuantity(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+                    itemAccount.setComputeSingleResult(divide);
+                }
+            });
+            projectCostAccountList.addAll(itemAccountList);
+        }
+        if(CollectionUtils.isEmpty(projectCostAccountList)){
+            return;
+        }
 
+        projectCostAccountRepository.batchInsert(projectCostAccountList);
     }
 
     /**
@@ -567,7 +642,7 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      * @param responsibilityItem
      * @return
      */
-    public ComputeProjectCost createComputeProjectCost(String computeDate,SessionUserVO currentUser,ComputeShareParamDetailVo responsibilityItem){
+    public ComputeProjectCost createComputeProjectCost(String computeDate,SessionUserVO currentUser,ComputeShareParamDetailVo responsibilityItem,Map<String, Map<String, List<Item>>> respItemGroup){
         //主表公共对象
         ComputeProjectCost computeProjectCost = new ComputeProjectCost();
         computeProjectCost.setComputeDate(computeDate);
@@ -577,8 +652,14 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         computeProjectCost.setCode(responsibilityItem.getCode());
         computeProjectCost.setName(responsibilityItem.getName());
         computeProjectCost.setItemType(responsibilityItem.getItemType());
+        computeProjectCost.setQuantity(responsibilityItem.getNum());
         computeProjectCost.setResponsibilityCode(responsibilityItem.getResponsibilityCode());
         computeProjectCost.setResponsibilityName(responsibilityItem.getResponsibilityName());
+        Map<String, List<Item>> stringListMap = respItemGroup.get(responsibilityItem.getResponsibilityCode());
+        if(stringListMap!=null&&stringListMap.containsKey(responsibilityItem.getCode())){
+            computeProjectCost.setStandItemCode(stringListMap.get(responsibilityItem.getCode()).get(NumberConstant.ZERO).getStandItemCode());
+        }
+        computeProjectCost.setProjectCostAccountMap(new HashMap<>());
         return computeProjectCost;
     }
 
@@ -595,9 +676,17 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      * @param costDepartmentProfits 科室损益数据
      * @return
      */
-    public ComputeProjectCostDetail createComputeProjectCostDetail(String computeDate,SessionUserVO currentUser,ShareParamTypeMap incomeShareParam,ComputeShareParamDetailVo responsibilityItem,ComputeProjectCost computeProjectCost,ShareParamCost shareParamCost,
-                                                                   List<ShareParamCostVo> shareParamCostVos,List<ComputeShareParamDetailVo> computeShareParamDetails ,
-                                                                   List<ComputeShareParamDetailVo> computeShareParamDetailGroup,List<CostDepartmentProfit> costDepartmentProfits){
+    public ComputeProjectCostDetail createComputeProjectCostDetail(String computeDate,
+                                                                   SessionUserVO currentUser,
+                                                                   ShareParamTypeMap incomeShareParam,
+                                                                   ComputeShareParamDetailVo responsibilityItem,
+                                                                   ComputeProjectCost computeProjectCost,
+                                                                   ShareParamCost shareParamCost,
+                                                                   Map<String, List<ShareParamCostVo>> shareParamCostVos,
+                                                                   Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails ,
+                                                                   Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
+                                                                   Map<String, List<CostDepartmentProfit>> costDepartmentProfits,
+                                                                   Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap){
         //明细表公共对象
         ComputeProjectCostDetail costDetail = new ComputeProjectCostDetail();
         costDetail.setComputeDate(computeDate);
@@ -608,16 +697,15 @@ public class ProjectCostServiceImpl implements ProjectCostService {
         costDetail.setCostColumnCode(shareParamCost.getColumnCode());
         costDetail.setCostColumnType(shareParamCost.getColumnType());
         //获取对应分摊配置明细
-        List<ShareParamCostVo> shareParamDetails = shareParamCostVos.stream().filter(shareParamDetail -> shareParamDetail.getColumnCode().equals(shareParamCost.getColumnCode())).collect(Collectors.toList());
+        List<ShareParamCostVo> shareParamDetails = shareParamCostVos.get(shareParamCost.getColumnCode());
         if (CollectionUtils.isEmpty(shareParamDetails)){
             throw new CostException(String.format("[%s]没有对应分摊配置,请联系管理员",shareParamCost.getColumnName()));
         }
+        String profitKey = String.format("%s-%s-%s",shareParamCost.getReportType(),shareParamCost.getProfitNum(),computeProjectCost.getResponsibilityCode());
         //根据主表配置找到对应的科室损益数据
-        Optional<CostDepartmentProfit> firstDepartmentProfit = costDepartmentProfits.stream().filter(departmentProfit -> String.valueOf(departmentProfit.getShareType()).equals(shareParamCost.getReportType()) &&
-                String.valueOf(departmentProfit.getReportNum()).equals(shareParamCost.getProfitNum()) &&
-                departmentProfit.getResponsibilityCode().equals(computeProjectCost.getResponsibilityCode())).findFirst();
+        List<CostDepartmentProfit> departmentProfitList = costDepartmentProfits.get(profitKey);
         //没有对应的损益项目数据或者损益项目金额为0
-        if(!firstDepartmentProfit.isPresent()||firstDepartmentProfit.get().getAmount().equals(BigDecimal.ZERO)){
+        if(CollectionUtils.isEmpty(departmentProfitList)|| departmentProfitList.get(NumberConstant.ZERO).getAmount().equals(BigDecimal.ZERO)){
             costDetail.setComputeResult(BigDecimal.ZERO);
             costDetail.setComputeSingleResult(BigDecimal.ZERO);
             costDetail.setStandComputeResult(BigDecimal.ZERO);
@@ -625,13 +713,13 @@ public class ProjectCostServiceImpl implements ProjectCostService {
             return costDetail;
         }
         //按项目分摊配置计算项目的一个项目成本列的分摊金额
-        BigDecimal itemAllocationAmount=calcItemAllocationAmount(incomeShareParam,computeProjectCost,firstDepartmentProfit.get(),
-                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails);
+        BigDecimal itemAllocationAmount=calcItemAllocationAmount(incomeShareParam,computeProjectCost, departmentProfitList.get(NumberConstant.ZERO),
+                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails,deptPriftAccountMap);
         costDetail.setComputeResult(itemAllocationAmount);
 
         //按项目分摊配置计算项目的一个项目成本列的标准法分摊金额
-        BigDecimal itemStandAllocationAmount=calcItemStandAllocationAmount(incomeShareParam,computeProjectCost,firstDepartmentProfit.get(),
-                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails);
+        BigDecimal itemStandAllocationAmount=calcItemStandAllocationAmount(incomeShareParam,computeProjectCost, departmentProfitList.get(NumberConstant.ZERO),
+                shareParamDetails,computeShareParamDetailGroup,computeShareParamDetails,deptPriftAccountMap);
         costDetail.setStandComputeResult(itemStandAllocationAmount);
 
         //项目没有数量时,单个项目的分摊金额为0
@@ -655,44 +743,118 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      * @param computeShareParamDetails 分摊参数计算明细
      * @return
      */
-    public  BigDecimal calcItemAllocationAmount(ShareParamTypeMap incomeShareParam,ComputeProjectCost computeProjectCost,CostDepartmentProfit costDepartmentProfit,List<ShareParamCostVo> shareParamCostVos,
-                                                List<ComputeShareParamDetailVo> computeShareParamDetailGroup,List<ComputeShareParamDetailVo> computeShareParamDetails){
+    public BigDecimal calcItemAllocationAmount(ShareParamTypeMap incomeShareParam,
+                                               ComputeProjectCost computeProjectCost,
+                                               CostDepartmentProfit costDepartmentProfit,
+                                               List<ShareParamCostVo> shareParamCostVos,
+                                               Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
+                                               Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails,
+                                               Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap) {
         BigDecimal itemAllocationAmount=BigDecimal.ZERO;
         //按配置计算每个参数分摊金额
-        for (ShareParamCostVo shareParamCostVo : shareParamCostVos) {//获取参数对应的责任中心汇总数据
-            Optional<ComputeShareParamDetailVo> firstShareParamGroup = computeShareParamDetailGroup.stream().filter(shareParamGroup -> shareParamGroup.getItemType().equals(computeProjectCost.getItemType()) &&
-                    shareParamGroup.getResponsibilityCode().equals(computeProjectCost.getResponsibilityCode()) && shareParamGroup.getShareParamCode().equals(shareParamCostVo.getShareParamCode())).findFirst();
+        for (ShareParamCostVo shareParamCostVo : shareParamCostVos) {
+            //获取参数对应的责任中心汇总数据
+            String shareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),shareParamCostVo.getShareParamCode(),computeProjectCost.getResponsibilityCode());
+            List<ComputeShareParamDetailVo> shareParamTotalValueList = computeShareParamDetailGroup.get(shareParamKey);
             //责任中心的汇总数据为0时,按项目收入分摊
-            if (!firstShareParamGroup.isPresent() || firstShareParamGroup.get().getComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
+            if (CollectionUtils.isEmpty(shareParamTotalValueList)|| shareParamTotalValueList.get(NumberConstant.ZERO).getComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
                 //获取项目对应的收入数据
-                Optional<ComputeShareParamDetailVo> firstComputeShareParamDetail = computeShareParamDetails.stream().filter(computeShareParamDetailVo ->
-                        computeShareParamDetailVo.getShareParamCode().equals(incomeShareParam.getShareParamCode())).findFirst();
-                if (!firstComputeShareParamDetail.isPresent()) {
+                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(incomeShareParam.getShareParamCode());
+                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                     throw new CostException(String.format("[%s-%s]没有收入数据无法分摊,请检查对应的收费项目数据及分摊参数计算结果数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                 }
-                //找到项目收入的责任中心汇总数据
-                ComputeShareParamDetailVo incomeShareParamGroup = computeShareParamDetailGroup.stream().filter(shareParamGroup -> shareParamGroup.getItemType().equals(computeProjectCost.getItemType()) &&
-                        shareParamGroup.getResponsibilityCode().equals(computeProjectCost.getResponsibilityCode()) && shareParamGroup.getShareParamCode().equals(incomeShareParam.getShareParamCode())).findFirst().get();
-                //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
-                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(firstComputeShareParamDetail.get().getComputeResult())
-                        .divide(incomeShareParamGroup.getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
-                itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                String incomeShareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),incomeShareParam.getShareParamCode(),computeProjectCost.getResponsibilityCode());
+                //有对应的收入数据
+                if(computeShareParamDetailGroup.containsKey(incomeShareParamKey)){
+                    //找到项目收入的责任中心汇总数据
+                    List<ComputeShareParamDetailVo> incomeShareParamGroup = computeShareParamDetailGroup.get(incomeShareParamKey);
+                    //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
+                    BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getComputeResult())
+                            .divide(incomeShareParamGroup.get(NumberConstant.ZERO).getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+                    itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                    //计算项目对应的会计科目金额
+                    calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO),incomeShareParamGroup.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE ) ;
+                }
             } else {
+
                 //获取项目对应的分摊参数数据
-                Optional<ComputeShareParamDetailVo> firstComputeShareParamDetail = computeShareParamDetails.stream().filter(computeShareParamDetailVo ->
-                        computeShareParamDetailVo.getShareParamCode().equals(shareParamCostVo.getShareParamCode())).findFirst();
-                if (!firstComputeShareParamDetail.isPresent()) {
+                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(shareParamCostVo.getShareParamCode());
+                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                     throw new CostException(String.format("[%s-%s]没有收入数据无法分摊,请检查对应的收费项目数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                 }
                 //分摊金额=损益项目金额*分摊参数占比*分摊参数数值/责任中心总分摊参数数值
-                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(firstComputeShareParamDetail.get().getComputeResult())
-                        .divide(firstShareParamGroup.get().getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getComputeResult())
+                        .divide(shareParamTotalValueList.get(NumberConstant.ZERO).getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                 itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                //计算项目对应的会计科目金额
+                calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO), shareParamTotalValueList.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE );
             }
         }
         return  itemAllocationAmount;
     }
 
+    /**
+     * 计算项目对应的会计科目金额
+     * @param computeProjectCost
+     * @param costDepartmentProfit
+     * @param shareParamCostVo
+     * @param shareParamValueVo
+     * @param shareParamTotalValueVo
+     * @param deptPriftAccountMap
+     * @param calcType 1:计算项目金额 2:计算项目标准金额
+     */
+    public void calcProjectAccountAmount(ComputeProjectCost computeProjectCost,
+                                         CostDepartmentProfit costDepartmentProfit,
+                                         ShareParamCostVo shareParamCostVo,
+                                         ComputeShareParamDetailVo shareParamValueVo,
+                                         ComputeShareParamDetailVo shareParamTotalValueVo,
+                                         Map<Long,List<CostDepartmentProfitAccount>> deptPriftAccountMap,
+                                         Integer calcType){
+        List<CostDepartmentProfitAccount> costDepartmentProfitAccounts = deptPriftAccountMap.get(costDepartmentProfit.getId());
+        if(CollectionUtils.isEmpty(costDepartmentProfitAccounts)){
+            return;
+        }
+        //排除掉无效数据
+        if(StringUtils.isEmpty(computeProjectCost.getStandItemCode())){
+            return;
+        }
+        for (CostDepartmentProfitAccount costDepartmentProfitAccount : costDepartmentProfitAccounts) {
+            ComputeProjectCostAccount computeProjectCostAccount = new ComputeProjectCostAccount();
+            computeProjectCostAccount.setProjectCostId(computeProjectCost.getId())
+                    .setStandItemCode(computeProjectCost.getStandItemCode())
+                    .setAccountType(costDepartmentProfitAccount.getAccountType())
+                    .setCostType(costDepartmentProfitAccount.getCostType())
+                    .setHospId(costDepartmentProfit.getHospId())
+                    .setComputeDate(computeProjectCost.getComputeDate())
+                    .setCreateUser(computeProjectCost.getCreateUser())
+                    .setCreateTime(new Date())
+                    .setUpdateUser(computeProjectCost.getUpdateUser())
+                    .setUpdateTime(new Date())
+                    .setDelFlag(NumberConstant.ZERO);
+
+            BigDecimal paramAllocationAmount = BigDecimal.ZERO;
+            if(BigDecimal.ZERO.compareTo(shareParamTotalValueVo.getComputeResult())!=NumberConstant.ZERO){
+                paramAllocationAmount = costDepartmentProfitAccount.getAmount().multiply(shareParamCostVo.getPercent()).multiply(shareParamValueVo.getComputeResult())
+                        .divide(shareParamTotalValueVo.getComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+            }
+            computeProjectCostAccount.setComputeResult(paramAllocationAmount);
+            String accountKey=String.format("%s-%s",computeProjectCostAccount.getCostType(),computeProjectCostAccount.getAccountType());
+            //判断当前科目是否已经存在
+            if(computeProjectCost.getProjectCostAccountMap().containsKey(accountKey)){
+                ComputeProjectCostAccount itemAccount = computeProjectCost.getProjectCostAccountMap().get(accountKey);
+                if(NumberConstant.ONE.equals(calcType)){
+                    itemAccount.setComputeResult(itemAccount.getComputeResult().add(computeProjectCostAccount.getComputeResult()));
+                }else {
+                    itemAccount.setStandComputeResult(itemAccount.getStandComputeResult().add(computeProjectCostAccount.getComputeResult()));
+                }
+            }else{
+                computeProjectCost.getProjectCostAccountMap().put(accountKey,computeProjectCostAccount);
+            }
+        }
+
+    }
+
+
     /**
      * 计算项目标准法的分摊金额
      * @param computeProjectCost 主表对象
@@ -702,40 +864,50 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      * @param computeShareParamDetails 分摊参数计算明细
      * @return
      */
-    public  BigDecimal calcItemStandAllocationAmount(ShareParamTypeMap incomeShareParam,ComputeProjectCost computeProjectCost,CostDepartmentProfit costDepartmentProfit,List<ShareParamCostVo> shareParamCostVos,
-                                                List<ComputeShareParamDetailVo> computeShareParamDetailGroup,List<ComputeShareParamDetailVo> computeShareParamDetails){
+    public  BigDecimal calcItemStandAllocationAmount(ShareParamTypeMap incomeShareParam,
+                                                     ComputeProjectCost computeProjectCost,
+                                                     CostDepartmentProfit costDepartmentProfit,
+                                                     List<ShareParamCostVo> shareParamCostVos,
+                                                     Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetailGroup,
+                                                     Map<String, List<ComputeShareParamDetailVo>> computeShareParamDetails,
+                                                     Map<Long, List<CostDepartmentProfitAccount>> deptPriftAccountMap){
         BigDecimal itemAllocationAmount=BigDecimal.ZERO;
         //按配置计算每个参数分摊金额
         for (ShareParamCostVo shareParamCostVo : shareParamCostVos) {
             //获取参数对应的责任中心汇总数据
-            Optional<ComputeShareParamDetailVo> firstShareParamGroup = computeShareParamDetailGroup.stream().filter(shareParamGroup -> shareParamGroup.getItemType().equals(computeProjectCost.getItemType()) &&
-                    shareParamGroup.getResponsibilityCode().equals(computeProjectCost.getResponsibilityCode()) && shareParamGroup.getShareParamCode().equals(shareParamCostVo.getShareParamCode())).findFirst();
+            String shareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),shareParamCostVo.getShareParamCode(),computeProjectCost.getResponsibilityCode());
+            List<ComputeShareParamDetailVo> shareParamTotalValueList = computeShareParamDetailGroup.get(shareParamKey);
             //责任中心的汇总数据为0时,按项目收入分摊
-            if (!firstShareParamGroup.isPresent() || firstShareParamGroup.get().getStandComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
+            if (CollectionUtils.isEmpty(shareParamTotalValueList)|| shareParamTotalValueList.get(NumberConstant.ZERO).getStandComputeResult().compareTo(BigDecimal.ZERO) == NumberConstant.ZERO) {
                 //获取项目对应的收入数据
-                Optional<ComputeShareParamDetailVo> firstComputeShareParamDetail = computeShareParamDetails.stream().filter(computeShareParamDetailVo ->
-                        computeShareParamDetailVo.getShareParamCode().equals(incomeShareParam.getShareParamCode())).findFirst();
-                if (!firstComputeShareParamDetail.isPresent()) {
+                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(incomeShareParam.getShareParamCode());
+                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                     throw new CostException(String.format("[%s-%s]没有收入数据无法分摊,请检查对应的收费项目数据及分摊参数计算结果数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                 }
-                //找到项目收入的责任中心汇总数据
-                ComputeShareParamDetailVo incomeShareParamGroup = computeShareParamDetailGroup.stream().filter(shareParamGroup -> shareParamGroup.getItemType().equals(computeProjectCost.getItemType()) &&
-                        shareParamGroup.getResponsibilityCode().equals(computeProjectCost.getResponsibilityCode()) && shareParamGroup.getShareParamCode().equals(incomeShareParam.getShareParamCode())).findFirst().get();
-                //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
-                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(firstComputeShareParamDetail.get().getStandComputeResult())
-                        .divide(incomeShareParamGroup.getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
-                itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                String incomeShareParamKey = String.format("%s-%s-%s",computeProjectCost.getItemType(),incomeShareParam.getShareParamCode(),computeProjectCost.getResponsibilityCode());
+                //有对应的收入数据
+                if(computeShareParamDetailGroup.containsKey(incomeShareParamKey)){
+                    //找到项目收入的责任中心汇总数据
+                    List<ComputeShareParamDetailVo> incomeShareParamGroup = computeShareParamDetailGroup.get(incomeShareParamKey);
+                    //分摊金额=损益项目金额*分摊参数占比*收入/责任中心总收入
+                    BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getStandComputeResult())
+                            .divide(incomeShareParamGroup.get(NumberConstant.ZERO).getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+                    itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                    //计算项目对应的会计科目金额
+                    calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO),incomeShareParamGroup.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE ) ;
+                }
             } else {
                 //获取项目对应的分摊参数数据
-                Optional<ComputeShareParamDetailVo> firstComputeShareParamDetail = computeShareParamDetails.stream().filter(computeShareParamDetailVo ->
-                        computeShareParamDetailVo.getShareParamCode().equals(shareParamCostVo.getShareParamCode())).findFirst();
-                if (!firstComputeShareParamDetail.isPresent()) {
+                List<ComputeShareParamDetailVo> computeShareParamDetailList = computeShareParamDetails.get(shareParamCostVo.getShareParamCode());
+                if (CollectionUtils.isEmpty(computeShareParamDetailList)) {
                     throw new CostException(String.format("[%s-%s]没有收入数据无法分摊,请检查对应的收费项目数据", computeProjectCost.getResponsibilityName(), computeProjectCost.getName()));
                 }
                 //分摊金额=损益项目金额*分摊参数占比*分摊参数数值/责任中心总分摊参数数值
-                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(firstComputeShareParamDetail.get().getStandComputeResult())
-                        .divide(firstShareParamGroup.get().getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
+                BigDecimal paramAllocationAmount = costDepartmentProfit.getAmount().multiply(shareParamCostVo.getPercent()).multiply(computeShareParamDetailList.get(NumberConstant.ZERO).getStandComputeResult())
+                        .divide(shareParamTotalValueList.get(NumberConstant.ZERO).getStandComputeResult(), NumberConstant.FOUR, RoundingMode.HALF_UP);
                 itemAllocationAmount = itemAllocationAmount.add(paramAllocationAmount);
+                //计算项目对应的会计科目金额
+                calcProjectAccountAmount( computeProjectCost, costDepartmentProfit, shareParamCostVo, computeShareParamDetailList.get(NumberConstant.ZERO), shareParamTotalValueList.get(NumberConstant.ZERO), deptPriftAccountMap,NumberConstant.ONE );
             }
         }
         return  itemAllocationAmount;
@@ -1112,11 +1284,23 @@ public class ProjectCostServiceImpl implements ProjectCostService {
                 } else if (titleVo.getCode().equals(PATIENT_NAME.getCode())) {
                     dataList.add(getData(titleVo.getCode(), itemCode.getPatientName()));
                 } else if (titleVo.getCode().equals(ITEM_INCOME.getCode())) {
-                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_INCOME.getCode())));
+                    if(computeResultDepartmentMap.isEmpty()){
+                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
+                    }else{
+                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_INCOME.getCode())));
+                    }
                 } else if (titleVo.getCode().equals(ITEM_COST.getCode())) {
-                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_COST.getCode())));
+                    if(computeResultDepartmentMap.isEmpty()){
+                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
+                    }else{
+                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(ITEM_COST.getCode())));
+                    }
                 } else {
-                    dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(titleVo.getCode())));
+                    if(computeResultDepartmentMap.isEmpty()){
+                        dataList.add(getData(titleVo.getCode(),BigDecimal.ZERO));
+                    }else{
+                        dataList.add(getData(titleVo.getCode(), computeResultDepartmentMap.get(itemCode.getDepartmentCode()).get(itemCode.getCode()).get(itemCode.getVisitNo()).get(titleVo.getCode())));
+                    }
                 }
             }
             returnList.add(dataList);
@@ -1241,10 +1425,17 @@ public class ProjectCostServiceImpl implements ProjectCostService {
      */
     @Override
     public void computeStandItemCost(String computeDate){
-        //标准项目成本分摊计算
-        computeStandItemCostAction(computeDate);
-        //执行标准法项目成本分摊计算后续处理脚本
-        execStandItemCostSQL(computeDate);
+        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.THREE);
+        //走系统计算逻辑
+        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //标准项目成本分摊计算
+            computeStandItemCostAction(computeDate);
+        }
+        //走自定义SQL计算逻辑
+        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //执行标准法项目成本分摊计算后续处理脚本
+            execStandItemCostSQL(computeDate);
+        }
     }
 
     /**

+ 7 - 0
src/main/java/com/kcim/service/impl/ReportFormServiceImpl.java

@@ -69,6 +69,13 @@ public class ReportFormServiceImpl extends ServiceImpl<ReportFormMapper, ReportF
             } else if (i.getCalcType() == 5) {
                 reportFormVO.setShowAddRelation(3);
             }
+            if (i.getDataType() == 1) {
+                reportFormVO.setDataTypeName("数值");
+            } else if (i.getDataType() == 2) {
+                reportFormVO.setDataTypeName("百分比");
+            } else {
+                reportFormVO.setDataTypeName("未知");
+            }
             return reportFormVO;
         }).collect(Collectors.toList());
 

+ 3 - 0
src/main/java/com/kcim/service/impl/ReportServiceImpl.java

@@ -371,6 +371,9 @@ public class ReportServiceImpl implements ReportService {
             if (Objects.isNull(o)) {
                 continue;
             }
+            if (StringUtils.isEmpty(o)) {
+                o=BigDecimal.ZERO;
+            }
             BigDecimal amount = new BigDecimal(o.toString());
             String str = expressionMap.get(i);
             if (str.equals("+")) {

+ 28 - 8
src/main/java/com/kcim/service/impl/ShareParamServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.kcim.common.constants.Constant;
 import com.kcim.common.constants.NumberConstant;
+import com.kcim.common.constants.ParameterConstant;
 import com.kcim.common.constants.SQLParameter;
 import com.kcim.common.enums.CustomSqlTypeEnum;
 import com.kcim.common.exception.CostException;
@@ -149,10 +150,22 @@ public class ShareParamServiceImpl implements ShareParamService {
      */
     @Override
     public void computeShareParamCost(String computeDate){
-        //完全法项目分摊参数计算
-        calcShareParamCost(computeDate);
-        //执行完全法项目分摊参数计算后续处理脚本
-        execShareParamCostSQL(computeDate);
+        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.ZERO);
+        //走系统计算逻辑
+        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //根据参数判断是否走新的计算流程
+            if (NumberConstant.ONE_S.equals(centerService.getParameterValue(ParameterConstant.USER_HOSP_ITEM_CALC))) {
+                //完全法项目分摊参数计算
+                calcShareParamCost(computeDate);
+            } else {
+                computeShareParamCostAction(computeDate);
+            }
+        }
+        //走自定义SQL计算逻辑
+        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //执行完全法项目分摊参数计算后续处理脚本
+            execShareParamCostSQL(computeDate);
+        }
     }
 
     /**
@@ -814,10 +827,17 @@ public class ShareParamServiceImpl implements ShareParamService {
      */
     @Override
     public void computeStandShareParamCost(String computeDate){
-        //标准法项目分摊参数计算
-        computeStandShareParamCostAction(computeDate);
-        //执行标准法项目分摊参数计算后续处理脚本
-        execStandShareParamCostSQL(computeDate);
+        String parameterValue = centerService.getParameterValueByIndex(ParameterConstant.ITEM_CALC_TYPE,NumberConstant.TWO);
+        //走系统计算逻辑
+        if(StringUtils.isEmpty(parameterValue)|| NumberConstant.ONE_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //标准法项目分摊参数计算
+            computeStandShareParamCostAction(computeDate);
+        }
+        //走自定义SQL计算逻辑
+        if(NumberConstant.TWO_S.equals(parameterValue)||NumberConstant.THREE_S.equals(parameterValue)) {
+            //执行标准法项目分摊参数计算后续处理脚本
+            execStandShareParamCostSQL(computeDate);
+        }
     }
 
     /**

+ 2478 - 0
src/main/java/com/kcim/service/impl/StandardReportServiceImpl.java

@@ -0,0 +1,2478 @@
+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;
+    }
+
+
+}

+ 14 - 0
src/main/java/com/kcim/vo/AllocationQueryReportVO.java

@@ -67,4 +67,18 @@ public class AllocationQueryReportVO {
      * 会计科目名称集合
      */
     private List<String> accountingNames;
+
+    /**
+     * 成本类别
+     */
+    private String costType;
+    /**
+     * 会计科目类别
+     */
+    private String accountType;
+
+    /**
+     * 来源分摊层级ID
+     */
+    private Long shareLevelId;
 }

+ 60 - 0
src/main/java/com/kcim/vo/BaseDeptCostReportVO.java

@@ -0,0 +1,60 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+/**
+ * 科室成本明细视图对象
+ */
+@Data
+public class BaseDeptCostReportVO {
+    /**
+     * 科室标准分级
+     */
+    private String standardShareLevel;
+
+    /**
+     * 科室名称
+     */
+    private String responsibilityName;
+
+    /**
+     * 科室代码
+     */
+    private String responsibilityCode;
+
+    /**
+     * 科室排序
+     */
+    private Integer responsibilitySort;
+
+    /**
+     * 成本类型代码
+     */
+    private String costType;
+
+    /**
+     * 标准成本类型
+     */
+    private String standCostType;
+
+    /**
+     * 会计类型代码
+     */
+    private String accountType;
+
+    /**
+     * 标准会计类型
+     */
+    private String standAccountType;
+
+    /**
+     * 标准分级排序
+     */
+    private Integer shareLevelSort;
+
+    /**
+     * 来源类型:1.分摊前,2.分摊后
+     */
+    private Long originType;
+
+}

+ 118 - 0
src/main/java/com/kcim/vo/ClinicalDeptFullCostVO.java

@@ -0,0 +1,118 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 临床服务类科室全成本报表VO类
+ * 用于封装临床科室的各类成本数据,包括医疗成本、财政项目拨款经费、非同级财政拨款项目经费等
+ */
+@Data
+public class ClinicalDeptFullCostVO extends BaseDeptCostReportVO {
+
+    /**
+     * 医疗成本合计 - 直接成本
+     */
+    private BigDecimal medicalCostTotalDirect = BigDecimal.ZERO;
+
+    /**
+     * 医疗成本合计 - 间接成本
+     */
+    private BigDecimal medicalCostTotalIndirect = BigDecimal.ZERO;
+
+    /**
+     * 医疗成本合计 - 全成本
+     */
+    private BigDecimal medicalCostTotal = BigDecimal.ZERO;
+
+    /**
+     * 财政项目拨款经费形成的各项费用 - 直接成本
+     */
+    private BigDecimal financialProjectFundsDirect = BigDecimal.ZERO;
+
+    /**
+     * 财政项目拨款经费形成的各项费用 - 间接成本
+     */
+    private BigDecimal financialProjectFundsIndirect = BigDecimal.ZERO;
+
+    /**
+     * 财政项目拨款经费形成的各项费用 - 全成本
+     */
+    private BigDecimal financialProjectFunds = BigDecimal.ZERO;
+
+    /**
+     * 非同级财政拨款项目经费形成的各项费用 - 直接成本
+     */
+    private BigDecimal nonPeerFinancialFundsDirect = BigDecimal.ZERO;
+
+    /**
+     * 非同级财政拨款项目经费形成的各项费用 - 间接成本
+     */
+    private BigDecimal nonPeerFinancialFundsIndirect = BigDecimal.ZERO;
+
+    /**
+     * 非同级财政拨款项目经费形成的各项费用 - 全成本
+     */
+    private BigDecimal nonPeerFinancialFunds = BigDecimal.ZERO;
+
+    /**
+     * 医疗全成本合计 - 直接成本
+     */
+    private BigDecimal medicalTotalCostDirect = BigDecimal.ZERO;
+
+    /**
+     * 医疗全成本合计 - 间接成本
+     */
+    private BigDecimal medicalTotalCostIndirect = BigDecimal.ZERO;
+
+    /**
+     * 医疗全成本合计 - 全成本
+     */
+    private BigDecimal medicalTotalCost = BigDecimal.ZERO;
+
+    /**
+     * 科教经费形成的各项费用 - 直接成本
+     */
+    private BigDecimal educationalExpensesDirect = BigDecimal.ZERO;
+
+    /**
+     * 科教经费形成的各项费用 - 间接成本
+     */
+    private BigDecimal educationalExpensesIndirect = BigDecimal.ZERO;
+
+    /**
+     * 科教经费形成的各项费用 - 全成本
+     */
+    private BigDecimal educationalExpenses = BigDecimal.ZERO;
+
+    /**
+     * 资产处置费用、上缴上级费用、对附属单位补助费用、其他费用等 - 直接成本
+     */
+    private BigDecimal assetDisposalFeesDirect = BigDecimal.ZERO;
+
+    /**
+     * 资产处置费用、上缴上级费用、对附属单位补助费用、其他费用等 - 间接成本
+     */
+    private BigDecimal assetDisposalFeesIndirect = BigDecimal.ZERO;
+
+    /**
+     * 资产处置费用、上缴上级费用、对附属单位补助费用、其他费用等 - 全成本
+     */
+    private BigDecimal assetDisposalFees = BigDecimal.ZERO;
+
+    /**
+     * 医院全成本合计 - 直接成本
+     */
+    private BigDecimal hospitalTotalCostDirect = BigDecimal.ZERO;
+
+    /**
+     * 医院全成本合计 - 间接成本
+     */
+    private BigDecimal hospitalTotalCostIndirect = BigDecimal.ZERO;
+
+    /**
+     * 医院全成本合计 - 全成本
+     */
+    private BigDecimal hospitalTotalCost = BigDecimal.ZERO;
+}

+ 133 - 0
src/main/java/com/kcim/vo/ClinicalDeptMedicalCostVO.java

@@ -0,0 +1,133 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 科室成本明细视图对象
+ */
+@Data
+public class ClinicalDeptMedicalCostVO extends BaseDeptCostReportVO{
+
+    /**
+     * 人员经费(直接成本)
+     */
+    private BigDecimal personnelDirectCost;
+
+    /**
+     * 人员经费(间接成本)
+     */
+    private BigDecimal personnelIndirectCost;
+
+    /**
+     * 人员经费(全成本)
+     */
+    private BigDecimal personnelTotalCost;
+
+    /**
+     * 卫生材料费(直接成本)
+     */
+    private BigDecimal healthMaterialDirectCost;
+
+    /**
+     * 卫生材料费(间接成本)
+     */
+    private BigDecimal healthMaterialIndirectCost;
+
+    /**
+     * 卫生材料费(全成本)
+     */
+    private BigDecimal healthMaterialTotalCost;
+
+    /**
+     * 药品费(直接成本)
+     */
+    private BigDecimal medicineDirectCost;
+
+    /**
+     * 药品费(间接成本)
+     */
+    private BigDecimal medicineIndirectCost;
+
+    /**
+     * 药品费(全成本)
+     */
+    private BigDecimal medicineTotalCost;
+
+    /**
+     * 固定资产折旧费(直接成本)
+     */
+    private BigDecimal fixedAssetDepreciationDirectCost;
+
+    /**
+     * 固定资产折旧费(间接成本)
+     */
+    private BigDecimal fixedAssetDepreciationIndirectCost;
+
+    /**
+     * 固定资产折旧费(全成本)
+     */
+    private BigDecimal fixedAssetDepreciationTotalCost;
+
+    /**
+     * 无形资产摊销费(直接成本)
+     */
+    private BigDecimal intangibleAssetAmortizationDirectCost;
+
+    /**
+     * 无形资产摊销费(间接成本)
+     */
+    private BigDecimal intangibleAssetAmortizationIndirectCost;
+
+    /**
+     * 无形资产摊销费(全成本)
+     */
+    private BigDecimal intangibleAssetAmortizationTotalCost;
+
+    /**
+     * 提取医疗风险基金(直接成本)
+     */
+    private BigDecimal medicalRiskReserveDirectCost;
+
+    /**
+     * 提取医疗风险基金(间接成本)
+     */
+    private BigDecimal medicalRiskReserveIndirectCost;
+
+    /**
+     * 提取医疗风险基金(全成本)
+     */
+    private BigDecimal medicalRiskReserveTotalCost;
+
+    /**
+     * 其他医疗费用(直接成本)
+     */
+    private BigDecimal otherMedicalExpensesDirectCost;
+
+    /**
+     * 其他医疗费用(间接成本)
+     */
+    private BigDecimal otherMedicalExpensesIndirectCost;
+
+    /**
+     * 其他医疗费用(全成本)
+     */
+    private BigDecimal otherMedicalExpensesTotalCost;
+
+    /**
+     * 合计(直接成本)
+     */
+    private BigDecimal totalDirectCost;
+
+    /**
+     * 合计(间接成本)
+     */
+    private BigDecimal totalIndirectCost;
+
+    /**
+     * 合计(全成本)
+     */
+    private BigDecimal totalCost;
+
+}

+ 26 - 0
src/main/java/com/kcim/vo/CommonResponsibilityReportVo.java

@@ -18,5 +18,31 @@ public class CommonResponsibilityReportVo {
 
     private Integer sort;
 
+    /**
+     * 数据类型:0未知 1数值 2百分比
+     */
+    private Integer dataType;
+
+
+    /**
+     * 数据类型名称
+     */
+    private String dataTypeName;
+
+    /**
+     * 小数位
+     */
+    private Integer decimalPlace;
+
+    /**
+     * 是否有千分号
+     */
+    private Integer permil;
+
+    /**
+     * 是否固定 0不固定 1固定
+     */
+    private Integer isFixed;
+
     private List<CommonResponsibilityReportVo> child;
 }

+ 14 - 0
src/main/java/com/kcim/vo/CommonTitleReportVo.java

@@ -20,6 +20,20 @@ public class CommonTitleReportVo {
     private String reportName;
 
     private Integer sort;
+    /**
+     * 数据类型:0未知 1数值 2百分比
+     */
+    private Integer dataType;
+
+    /**
+     * 小数位
+     */
+    private Integer decimalPlace;
+
+    /**
+     * 是否有千分号
+     */
+    private Integer permil;
 
     private List<CommonTitleReportVo> childTitle;
 

+ 7 - 0
src/main/java/com/kcim/vo/CostDepartmentProfitVO.java

@@ -1,10 +1,12 @@
 package com.kcim.vo;
 
+import com.kcim.dao.model.CostDepartmentProfitAccount;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 /**
  * @author 李加喜
@@ -72,4 +74,9 @@ public class CostDepartmentProfitVO {
     private Integer type;
 
     private Integer fraction;
+
+    /**
+     * 会计科目金额列表
+     */
+    private List<CostDepartmentProfitAccount> costDepartmentProfitAccounts;
 }

+ 45 - 0
src/main/java/com/kcim/vo/CostProfitVo.java

@@ -104,4 +104,49 @@ public class CostProfitVo implements Serializable {
 
 	private List<ReportVo> data;
 
+	/**
+	 * 数据类型:0未知 1数值 2百分比
+	 */
+	private Integer dataType;
+
+	/**
+	 * 小数位
+	 */
+	private Integer decimalPlace;
+
+	/**
+	 * 是否有千分号
+	 */
+	private Integer permil;
+
+	/**
+	 * 预算金额
+	 */
+	private BigDecimal budgetAmount;
+
+	/**
+	 * 上期金额
+	 */
+	private BigDecimal prevPeriodAmount;
+
+	/**
+	 * 同期金额
+	 */
+	private BigDecimal samePeriodAmount;
+
+	/**
+	 * 完成率
+	 */
+	private BigDecimal completionRate;
+
+	/**
+	 * 环比
+	 */
+	private BigDecimal momRate;
+
+	/**
+	 * 同比
+	 */
+	private BigDecimal yoyRate;
+
 }

+ 74 - 0
src/main/java/com/kcim/vo/DeptDirectMedicalCostVO.java

@@ -0,0 +1,74 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 科室直接成本表(医疗成本)
+ * @author Administrator
+ */
+@Data
+public class DeptDirectMedicalCostVO extends BaseDeptCostReportVO{
+
+    /**
+     * 人员经费
+     */
+    private BigDecimal personnelExpense;
+
+    /**
+     * 卫生材料费
+     */
+    private BigDecimal healthMaterialFee;
+
+    /**
+     * 药品费
+     */
+    private BigDecimal drugFee;
+
+    /**
+     * 固定资产折旧费
+     */
+    private BigDecimal fixedAssetDepreciation;
+
+    /**
+     * 无形资产摊销费
+     */
+    private BigDecimal intangibleAssetAmortization;
+
+    /**
+     * 提取医疗风险基金
+     */
+    private BigDecimal medicalRiskFundExtraction;
+
+    /**
+     * 其他医疗费用
+     */
+    private BigDecimal otherMedicalExpenses;
+
+    /**
+     * 合计
+     */
+    private BigDecimal total;
+
+    /**
+     * 科室收入
+     */
+    private BigDecimal income;
+
+    /**
+     * 损益=收入-成本
+     */
+    private BigDecimal profit;
+
+    /**
+     * 床日成本
+     */
+    private BigDecimal bedDaysCost;
+
+    /**
+     * 诊次成本
+     */
+    private BigDecimal visitsCost;
+
+}

+ 47 - 0
src/main/java/com/kcim/vo/DeptFullDirectCostVO.java

@@ -0,0 +1,47 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 截图报表数据封装类
+ */
+@Data
+public class DeptFullDirectCostVO extends BaseDeptCostReportVO {
+
+    /**
+     * 医疗成本合计
+     */
+    private BigDecimal medicalCostTotal;
+
+    /**
+     * 财政项目拨款经费形成的各项费用
+     */
+    private BigDecimal financialProjectFunds;
+
+    /**
+     * 非同级财政拨款项目经费形成的各项费用
+     */
+    private BigDecimal nonPeerFinancialFunds;
+
+    /**
+     * 医疗全成本合计
+     */
+    private BigDecimal medicalTotalCost;
+
+    /**
+     * 科教经费形成的各项费用
+     */
+    private BigDecimal educationalExpenses;
+
+    /**
+     * 资产处置费用、上缴上级费用、对附属单位补助费用、其他费用等
+     */
+    private BigDecimal assetDisposalFees;
+
+    /**
+     * 医院全成本合计
+     */
+    private BigDecimal hospitalTotalCost;
+}

+ 197 - 0
src/main/java/com/kcim/vo/DiseaseCostDetailVO.java

@@ -0,0 +1,197 @@
+package com.kcim.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 医院病种成本明细表 VO 类
+ * <p>
+ * 用于封装病种成本明细数据,包括病种的基础信息和各项费用明细
+ * 该类主要用于医院病种成本构成明细表的展示
+ * </p>
+ * 
+ * @author system
+ * @since 1.0.0
+ */
+@Data
+public class DiseaseCostDetailVO {
+    /**
+     * 病种编码
+     * <p>
+     * 病种的唯一标识编码,用于区分不同的病种类型
+     * </p>
+     */
+    private String itemCode;
+
+    /**
+     * 病种名称
+     * <p>
+     * 病种的中文名称描述
+     * </p>
+     */
+    private String itemName;
+
+    /**
+     * 科室代码
+     */
+    private String departmentCode;
+
+    /**
+     * 科室名称
+     */
+    private String departmentName;
+
+    /**
+     * 成本类型代码
+     */
+    private String costTypeCode;
+
+    /**
+     * 服务量
+     * <p>
+     * 该病种的服务次数或数量统计
+     * </p>
+     */
+    private BigDecimal serviceVolume;
+
+    /**
+     * 每诊次医疗成本金额
+     */
+    private BigDecimal medicalCost;
+
+
+    /**
+     * 每诊次医疗全成本金额
+     */
+    private BigDecimal medicalFullCost;
+
+    /**
+     * 每诊次医院全成本金额
+     */
+    private BigDecimal hospitalFullCost;
+    
+    /**
+     * 总费用
+     * <p>
+     * 该病种产生的所有费用总和
+     * </p>
+     */
+    private BigDecimal totalCost;
+
+    /**
+     * 人员经费
+     * <p>
+     * 用于支付医务人员工资、奖金、津贴等的费用
+     * </p>
+     */
+    private BigDecimal personnelExpense;
+    
+    /**
+     * 人员经费占比
+     * <p>
+     * 人员经费占总费用的比例
+     * </p>
+     */
+    private BigDecimal personnelExpenseRatio;
+
+    /**
+     * 药品费
+     */
+    private BigDecimal drugExpense;
+
+    /**
+     * 药品费占比
+     */
+    private BigDecimal drugExpenseRatio;
+
+    /**
+     * 卫生材料费
+     * <p>
+     * 消耗性医疗用品、一次性医疗器材等材料费用
+     * </p>
+     */
+    private BigDecimal medicalMaterialExpense;
+    
+    /**
+     * 卫生材料费占比
+     * <p>
+     * 卫生材料费占总费用的比例
+     * </p>
+     */
+    private BigDecimal medicalMaterialExpenseRatio;
+
+    /**
+     * 固定资产折旧
+     * <p>
+     * 医疗设备、房屋建筑等固定资产的折旧费用
+     * </p>
+     */
+    private BigDecimal fixedAssetDepreciation;
+    
+    /**
+     * 固定资产折旧占比
+     * <p>
+     * 固定资产折旧占总费用的比例
+     * </p>
+     */
+    private BigDecimal fixedAssetDepreciationRatio;
+
+    /**
+     * 无形资产摊销
+     * <p>
+     * 软件、专利权等无形资产的摊销费用
+     * </p>
+     */
+    private BigDecimal intangibleAssetAmortization;
+    
+    /**
+     * 无形资产摊销占比
+     * <p>
+     * 无形资产摊销占总费用的比例
+     * </p>
+     */
+    private BigDecimal intangibleAssetAmortizationRatio;
+
+    /**
+     * 医疗风险基金
+     * <p>
+     * 为应对医疗风险而提取的专项基金
+     * </p>
+     */
+    private BigDecimal medicalRiskFund;
+    
+    /**
+     * 医疗风险基金占比
+     * <p>
+     * 医疗风险基金占总费用的比例
+     * </p>
+     */
+    private BigDecimal medicalRiskFundRatio;
+
+    /**
+     * 其他医疗费用
+     * <p>
+     * 除上述费用外的其他医疗相关费用
+     * </p>
+     */
+    private BigDecimal otherMedicalExpenses;
+    
+    /**
+     * 其他医疗费用占比
+     * <p>
+     * 其他医疗费用占总费用的比例
+     * </p>
+     */
+    private BigDecimal otherMedicalExpensesRatio;
+
+    /**
+     * 科室对应的责任中心代码
+     */
+    private String responsibilityCode;
+
+    /**
+     * 科室对应的责任中心名称
+     */
+    private String responsibilityName;
+}

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini