Преглед на файлове

按会计科目分摊时的分摊及损益计算逻辑的批量保存优化

JammeyJiang преди 1 месец
родител
ревизия
7d78c39ba6
променени са 18 файла, в които са добавени 515 реда и са изтрити 84 реда
  1. 1 3
      src/main/java/com/kcim/dao/mapper/AllocationMapper.java
  2. 1 2
      src/main/java/com/kcim/dao/mapper/AllocationQueryMapper.java
  3. 129 0
      src/main/java/com/kcim/dao/mapper/BatchInsertProvider.java
  4. 1 1
      src/main/java/com/kcim/dao/mapper/CostDepartmentProfitAccountMapper.java
  5. 1 2
      src/main/java/com/kcim/dao/mapper/CostDepartmentProfitMapper.java
  6. 24 0
      src/main/java/com/kcim/dao/mapper/GenericBatchMapper.java
  7. 3 4
      src/main/java/com/kcim/dao/repository/ComputeLastProfitDateRepository.java
  8. 26 2
      src/main/java/com/kcim/dao/repository/CostDepartmentProfitAccountRepository.java
  9. 1 1
      src/main/java/com/kcim/service/AllocationQueryService.java
  10. 8 5
      src/main/java/com/kcim/service/impl/AllocationQueryServiceImpl.java
  11. 3 4
      src/main/java/com/kcim/service/impl/AllocationServiceImpl.java
  12. 78 0
      src/main/java/com/kcim/service/impl/BaseBatchServiceImpl.java
  13. 4 2
      src/main/java/com/kcim/service/impl/CostCostingGroupServiceImpl.java
  14. 171 57
      src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java
  15. 8 0
      src/main/java/com/kcim/service/impl/StandardReportServiceImpl.java
  16. 21 0
      src/main/java/com/kcim/vo/CommonResponsibilityReportVo.java
  17. 27 1
      src/main/java/com/kcim/vo/ProfitCalculationDataVo.java
  18. 8 0
      src/main/resources/mapper/GenericBatchMapper.xml

+ 1 - 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> {
 
     /**
      * 分摊后查询列表

+ 1 - 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);
 

+ 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();
+    }
+}

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

@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @date 2025-09-19 14:14:25
  */
 @Mapper
-public interface CostDepartmentProfitAccountMapper extends BaseMapper<CostDepartmentProfitAccount> {
+public interface CostDepartmentProfitAccountMapper extends GenericBatchMapper<CostDepartmentProfitAccount> {
 	
 }

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

@@ -1,6 +1,5 @@
 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;
@@ -15,7 +14,7 @@ import java.util.List;
  * @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);

+ 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);
+}

+ 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);
         }
     }

+ 26 - 2
src/main/java/com/kcim/dao/repository/CostDepartmentProfitAccountRepository.java

@@ -1,12 +1,15 @@
 package com.kcim.dao.repository;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+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;
 
 /**
@@ -16,11 +19,32 @@ import java.util.List;
  * @create: 2023-11-27 17:52
  **/
 @Repository
-public class CostDepartmentProfitAccountRepository extends ServiceImpl<CostDepartmentProfitAccountMapper, CostDepartmentProfitAccount> {
+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);
+    }
 }

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

@@ -59,6 +59,6 @@ public interface AllocationQueryService extends IService<AllocationQuery> {
 
     List<AllocationQuery> getRespOriginAcountAccounts(Long hospId, int dateYear, int month);
 
-
+    void batchInsertAllocationQuery(List<AllocationQuery> allocationQueryList);
 }
 

+ 8 - 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 {
 
 
     /**
@@ -73,6 +71,11 @@ public class AllocationQueryServiceImpl extends ServiceImpl<AllocationQueryMappe
         return baseMapper.getRespOriginAcountAccounts(hospId, dateYear, month);
     }
 
+    @Override
+    public void batchInsertAllocationQuery(List<AllocationQuery> allocationQueryList) {
+         this.batchInsert(allocationQueryList);
+    }
+
     /**
      * 获取这个月的分摊数据
      *

+ 3 - 4
src/main/java/com/kcim/service/impl/AllocationServiceImpl.java

@@ -7,7 +7,6 @@ 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;
@@ -45,7 +44,7 @@ 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;
 //
@@ -196,7 +195,7 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
         // 删除该年月已经分摊过的数据
         removeData(startDTO, hospId);
         //保存分摊结果信息
-        this.saveBatch(allocationCostList);
+        this.batchInsert(allocationCostList);
         //保存分摊结果查询表
         applyAllocationQuery(startDTO,respDirectCostMap,allocationCostList,responsibilityCodeMap);
     }
@@ -691,7 +690,7 @@ public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocat
             return;
         }
         //保存分摊结果查询对象信息
-        allocationQueryService.saveBatch(allocationQueryList);
+        allocationQueryService.batchInsertAllocationQuery(allocationQueryList);
     }
 
     /**

+ 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;
+    }
+}

+ 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);
             }
         });

+ 171 - 57
src/main/java/com/kcim/service/impl/CostDepartmentProfitServiceImpl.java

@@ -12,12 +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.ParameterConstant;
-import com.kcim.common.constants.SQLParameter;
-import com.kcim.common.constants.SplitConstant;
+import com.kcim.common.constants.*;
 import com.kcim.common.enums.CustomSqlTypeEnum;
 import com.kcim.common.enums.DateStyleEnum;
 import com.kcim.common.enums.ErrorCodeEnum;
@@ -30,10 +26,7 @@ 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.CostDepartmentProfitAccountRepository;
-import com.kcim.dao.repository.CostDepartmentProfitRepository;
-import com.kcim.dao.repository.ResponsibilityRepository;
+import com.kcim.dao.repository.*;
 import com.kcim.service.*;
 import com.kcim.vo.*;
 import com.kcim.web.reponse.BatchCostProfitResponse;
@@ -56,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;
@@ -79,7 +73,7 @@ import static com.kcim.common.constants.ParameterConstant.MEDICAL_TECHNIQUES_SHA
 @Service("costDepartmentProfitService")
 @Slf4j
 @AllArgsConstructor
-public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentProfitMapper, CostDepartmentProfit> implements CostDepartmentProfitService {
+public class CostDepartmentProfitServiceImpl extends BaseBatchServiceImpl<CostDepartmentProfitMapper, CostDepartmentProfit> implements CostDepartmentProfitService {
 
 //    @Value("${file.filelocal}")
 //    private String hospProfitReportUrl;
@@ -122,6 +116,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
     ResponsibilityRepository responsibilityRepository;
 
     CostDepartmentProfitAccountRepository costDepartmentProfitAccountRepository;
+    AccountingRepository accountingRepository;
 
     private final SqlService sqlService;
     private final String AMOUNT = "金额";
@@ -1143,6 +1138,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 //        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);
         // 先查询指定条件的报表数据  查询损益表的数据
@@ -1226,7 +1222,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
 
         this.saveBatch(costDepartmentProfits);
         //记录最后一次 损益计算日期
-        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
+        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate,userId);
     }
 
     /**
@@ -3685,8 +3681,6 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         ProfitCalculationDataVo profitCalculationData = getProfitCalculationData(computeDate, hospId, reportType);
         //计算科室损益
         List<CostDepartmentProfitVO> costDepartmentProfitVOS = calcDeptProfit(profitCalculationData);
-        // 删除这个年月的数据
-        deleteDeptProfit(profitCalculationData.getYear(),profitCalculationData.getMonth(),reportType  );
         // 添加数据
         List<CostDepartmentProfit> costDepartmentProfits = BeanUtil.convertList(costDepartmentProfitVOS, CostDepartmentProfit.class);
         //统一创建时间
@@ -3694,8 +3688,11 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         costDepartmentProfits.forEach(i -> {
             i.setCreateTime(l);
         });
+        // 删除这个年月的数据
+        deleteDeptProfit(profitCalculationData.getYear(),profitCalculationData.getMonth(),reportType ,hospId);
+        costDepartmentProfitAccountRepository.deleteDeptProfitAccountWithUser(hospId,computeDate,profitCalculationData.getCurrentUserID());
         //保存科室损益数据
-        this.saveBatch(costDepartmentProfits);
+        this.batchInsert(costDepartmentProfits);
         //处理科室损益的会计科目金额数据
         List<CostDepartmentProfitAccount> costDepartmentProfitAccounts=new ArrayList<>();
         for (CostDepartmentProfit deptProfit : costDepartmentProfits) {
@@ -3707,9 +3704,9 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             costDepartmentProfitAccounts.addAll(deptProfit.getCostDepartmentProfitAccounts());
         }
         //保存科室损益的会计科目金额数据
-        costDepartmentProfitAccountRepository.saveBatch(costDepartmentProfitAccounts);
+        costDepartmentProfitAccountRepository.batchInsert(costDepartmentProfitAccounts);
         //记录最后一次 损益计算日期
-        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
+        computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate,profitCalculationData.getCurrentUserID());
     }
 
     /**
@@ -3721,6 +3718,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
      */
     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);
 
@@ -3747,6 +3745,12 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         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);
@@ -3754,13 +3758,74 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             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)) {
@@ -3776,6 +3841,10 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         profitCalculationData.setReportRelationMap(reportRelationMap);
         profitCalculationData.setCostShareLevelList(costShareLevelList);
         profitCalculationData.setResponsibilityList(responsibilityList);
+        profitCalculationData.setRespIncomeGroup(respIncomeGroup);
+        profitCalculationData.setRespAccountCostGroup(respAccountCostGroup);
+        profitCalculationData.setRespSourceCostGroup(respSourceCostGroup);
+        profitCalculationData.setRespShareLevelCostGroup(respShareLevelCostGroup);
         return profitCalculationData;
     }
 
@@ -3785,7 +3854,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
      * @return
      */
     private List<CostDepartmentProfitVO> calcDeptProfit(ProfitCalculationDataVo profitCalculationData) {
-        List<ReportForm> firstLevelReports = profitCalculationData.getReportFormList().stream().filter(i -> i.getParentId().equals(NumberConstant.ZERO)).collect(Collectors.toList());
+        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, "未找到第一层报表项目,请检查报表配置");
         }
@@ -3798,16 +3867,30 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             setChildReport(reportForm,reportParentGroup);
         }
         //按责任中心计算科室损益
-        for (Responsibility responsibility : profitCalculationData.getResponsibilityList()) {
-            Map<Integer,CostDepartmentProfitVO> costDepartmentProfitMap=new HashMap<>();
-            //计算责任中心的所有报表项目
-            for (ReportForm reportForm : firstLevelReports) {
-                calcRespReportAmount(responsibility, reportForm,profitCalculationData, costDepartmentProfitMap);
-            }
-            //添加到结果集合
-            costDepartmentProfitVOList.addAll(costDepartmentProfitMap.values());
-        }
-        return null;
+//        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<>();
+                    // 计算责任中心的所有报表项目
+                    for (ReportForm reportForm : firstLevelReports) {
+                        calcRespReportAmount(responsibility, reportForm, profitCalculationData, costDepartmentProfitMap);
+                    }
+                    return new ArrayList<>(costDepartmentProfitMap.values());
+                })
+                .flatMap(List::stream)
+                .collect(Collectors.toList());
+
+        costDepartmentProfitVOList.addAll(result);
+        return costDepartmentProfitVOList;
     }
 
     /**
@@ -3927,7 +4010,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         costDepartmentProfitVO.setResponsibilityName(responsibility.getResponsibilityName());
         costDepartmentProfitVO.setCostType(NumberConstant.ONE);
         costDepartmentProfitVO.setIncomeType(NumberConstant.ONE);
-        costDepartmentProfitVO.setHospId(UserContext.getHospId());
+        costDepartmentProfitVO.setHospId(profitCalculationData.getHospId());
         costDepartmentProfitVO.setShareType(Integer.valueOf(profitCalculationData.getReportType()));
         costDepartmentProfitVO.setType(reportForm.getCostType());
         costDepartmentProfitVO.setFraction(reportForm.getFraction());
@@ -3950,13 +4033,19 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
         // 获取对应的会计科目信息  筛选会计科目的Code
         List<String> responsibilityCodeList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
-        //类型是收入时取分摊结果表单的数据计算
-        // 需要查询分摊后的表
-        List<AllocationQueryReportVO> reportVOList = profitCalculationData.getAllocationQueryReportVOList().stream().filter(m ->
-                m.getTargetResponsibilityCode().equals(responsibility.getResponsibilityCode())
-                        &&NumberConstant.TWO.equals(m.getOriginType().intValue())
-                        && responsibilityCodeList.contains(m.getResponsibilityCode())).collect(Collectors.toList());
-        if (CollUtil.isEmpty(reportVOList)) {
+        // 获取指定责任中心的分摊数据
+        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);
@@ -4149,14 +4238,20 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
             return ;
         }
         // 获取对应的会计科目信息  筛选会计科目的Code
-        List<String> shareLevelIdList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
-        //类型是收入时取分摊结果表单的数据计算
-        // 需要查询分摊后的表
-        List<AllocationQueryReportVO> reportVOList = profitCalculationData.getAllocationQueryReportVOList().stream().filter(m ->
-                m.getTargetResponsibilityCode().equals(responsibility.getResponsibilityCode())
-                        &&NumberConstant.TWO.equals(m.getOriginType().intValue())
-                        && shareLevelIdList.contains(m.getShareLevelId())).collect(Collectors.toList());
-        if (CollUtil.isEmpty(reportVOList)) {
+        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);
@@ -4183,14 +4278,22 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
         // 获取对应的会计科目信息  筛选会计科目的Code
         List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
-        // 查找在归集数据里面当前责任中心对应的这些会计科目的金额
-        List<IncomeCollection> incomeCollectionList = profitCalculationData.getIncomeList().stream().filter(income ->
-                        income.getResponsibilityCode().equals(responsibility.getResponsibilityCode())
-                        && accountList.contains(income.getAccountingCode())).collect(Collectors.toList());
-        if(CollectionUtils.isEmpty(incomeCollectionList)){
+        // 获取指定责任中心的收入数据
+        Map<String, List<IncomeCollection>> respAccountIncomeMap = profitCalculationData.getRespIncomeGroup().get(responsibility.getResponsibilityCode());
+        if(ObjectUtils.isEmpty(respAccountIncomeMap) || respAccountIncomeMap.isEmpty()){
             return ;
         }
-        BigDecimal totalAmount = incomeCollectionList.stream()
+        //获取指定会计科目的收入数据
+        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);
@@ -4211,12 +4314,23 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
         }
         // 获取对应的会计科目信息  筛选会计科目的Code
         List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
-        //类型是收入时取分摊结果表单的数据计算
-        // 需要查询分摊后的表
-        List<AllocationQueryReportVO> reportVOList = profitCalculationData.getAllocationQueryReportVOList().stream().filter(m ->
-                        m.getTargetResponsibilityCode().equals(responsibility.getResponsibilityCode())
-                        &&(NumberConstant.ZERO.equals(reportForm.getCostType())||reportForm.getCostType().equals(m.getOriginType().intValue()))
-                        &&accountList.contains(m.getAccountingCode())).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 ;
         }
@@ -4327,9 +4441,9 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
      * @param month
      * @param reportType
      */
-    public void deleteDeptProfit(Integer year, Integer month,String reportType) {
+    public void deleteDeptProfit(Integer year, Integer month,String reportType,Long hospId) {
         // 删除这个年月的数据
-        this.remove(new QueryWrapper<CostDepartmentProfit>().lambda().eq(CostDepartmentProfit::getHospId, UserContext.getHospId())
+        this.remove(new QueryWrapper<CostDepartmentProfit>().lambda().eq(CostDepartmentProfit::getHospId, hospId)
                 .eq(CostDepartmentProfit::getYear, year).eq(CostDepartmentProfit::getMonth, month).eq(CostDepartmentProfit::getShareType, Integer.valueOf(reportType)));
     }
 

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

@@ -1621,11 +1621,19 @@ public class StandardReportServiceImpl implements StandardReportService {
         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);
         commonResponsibility.getChild().add( amount);
         CommonResponsibilityReportVo percent=new CommonResponsibilityReportVo();
         percent.setResponsibilityCode(getResponsibilityPercentCode(commonResponsibility.getResponsibilityCode()));
         percent.setResponsibilityName("占比");
         percent.setSort(NumberConstant.ONE);
+        amount.setDataType(NumberConstant.TWO);
+        amount.setDataTypeName("百分比");
+        amount.setDecimalPlace(NumberConstant.TWO);
+        amount.setPermil(NumberConstant.ZERO);
         commonResponsibility.getChild().add( percent);
     }
 

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

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

+ 27 - 1
src/main/java/com/kcim/vo/ProfitCalculationDataVo.java

@@ -16,7 +16,12 @@ public class ProfitCalculationDataVo {
      * 计算日期
      */
     private String computeDate;
-    
+
+    /**
+     * 当前用户ID
+     */
+    private Long currentUserID;
+
     /**
      * 年份
      */
@@ -81,4 +86,25 @@ public class ProfitCalculationDataVo {
      * 分摊数据列表
      */
     private List<Allocation> allocationList;
+
+    /**
+     *  科室收入归集数据分组
+     */
+    private Map<String, Map<String, List<IncomeCollection>>> respIncomeGroup;
+
+
+    /**
+     * 责任中心+会计科目分组
+     */
+    Map<String, Map<String, List<AllocationQueryReportVO>>> respAccountCostGroup;
+
+    /**
+     * 责任中心+来源责任中心分组
+     */
+    Map<String, Map<String, List<AllocationQueryReportVO>>> respSourceCostGroup;
+
+    /**
+     * 责任中心+分摊层级分组
+     */
+    Map<String, Map<Long, List<AllocationQueryReportVO>>> respShareLevelCostGroup;
 }

+ 8 - 0
src/main/resources/mapper/GenericBatchMapper.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.kcim.dao.mapper.GenericBatchMapper">
+    <!-- 通用批量插入语句,通过Provider动态生成SQL -->
+    <insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
+        ${@com.kcim.dao.mapper.BatchInsertProvider@insertBatch(list)}
+    </insert>
+</mapper>