|
@@ -52,7 +52,6 @@ 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;
|
|
@@ -1116,6 +1115,10 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
|
|
|
@Override
|
|
|
public void computeProfit(String computeDate, Long hospId, String reportType) {
|
|
|
computeProfitAction(computeDate, hospId, reportType);
|
|
|
+ //需要用代码计算同环比时
|
|
|
+ if(IsNeedCalcYM()){
|
|
|
+ handleSpecificMonthsCalculation(hospId, computeDate, reportType);
|
|
|
+ }
|
|
|
execDeptProfitSql(computeDate, reportType);
|
|
|
}
|
|
|
|
|
@@ -1209,6 +1212,7 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
|
|
|
//记录最后一次 损益计算日期
|
|
|
computeLastProfitDateRepository.saveLastComputeDate(hospId, computeDate);
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
|
|
|
*
|
|
@@ -1217,105 +1221,153 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
|
|
|
* @param shareType 报表类型
|
|
|
*/
|
|
|
public void handleSpecificMonthsCalculation(Long hospId, String computeDate, String shareType) {
|
|
|
-
|
|
|
// 解析输入的年月
|
|
|
- int currentYear = Integer.parseInt(computeDate.substring(0, 4));
|
|
|
- int currentMonth = Integer.parseInt(computeDate.substring(5, 7));
|
|
|
+ Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
|
|
|
+ Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
|
|
|
+ // 计算需要处理的期间信息
|
|
|
+ List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
|
|
|
|
|
|
- // 计算下个月
|
|
|
- int nextMonth = currentMonth + 1;
|
|
|
- int nextMonthYear = currentYear;
|
|
|
+ // 获取所有相关的期间数据
|
|
|
+ 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<>();
|
|
|
|
|
|
- if (nextMonth > 12) {
|
|
|
+ // 添加当前期间
|
|
|
+ result.add(calculatePeriodInfo(baseYear, baseMonth));
|
|
|
+
|
|
|
+ // 下个月
|
|
|
+ int nextMonth = baseMonth + 1;
|
|
|
+ int nextMonthYear = baseYear;
|
|
|
+ if (baseMonth == 12) {
|
|
|
nextMonth = 1;
|
|
|
- nextMonthYear = currentYear + 1;
|
|
|
+ nextMonthYear += 1;
|
|
|
}
|
|
|
+ result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
|
|
|
+
|
|
|
+ // 明年同月
|
|
|
+ result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
|
|
|
|
|
|
- // 计算明年同月
|
|
|
- int nextYearMonth = currentMonth;
|
|
|
- int nextYearMonthYear = currentYear + 1;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建单个期间的信息(当前月、上月、去年同期)
|
|
|
+ */
|
|
|
+ private PeriodInfoVO calculatePeriodInfo(int year, int month) {
|
|
|
+ PeriodInfoVO info = new PeriodInfoVO();
|
|
|
|
|
|
- // 检查各月份是否有数据
|
|
|
- boolean currentExists = checkDataExistence(hospId, shareType, currentYear, currentMonth);
|
|
|
- boolean nextMonthExists = checkDataExistence(hospId, shareType, nextMonthYear, nextMonth);
|
|
|
- boolean nextYearMonthExists = checkDataExistence(hospId, shareType, nextYearMonthYear, nextYearMonth);
|
|
|
+ info.setYear( year);
|
|
|
+ info.setMonth( month);
|
|
|
|
|
|
- // 执行当前月份计算
|
|
|
- if (currentExists) {
|
|
|
- calculatePeriodComparisonOptimized(hospId, shareType, currentYear, currentMonth);
|
|
|
+ // 上期
|
|
|
+ if (month == 1) {
|
|
|
+ info.setPrevYear(year - 1);
|
|
|
+ info.setPrevMonth(12);
|
|
|
+ } else {
|
|
|
+ info.setPrevYear( year);
|
|
|
+ info.setPrevMonth(month - 1);
|
|
|
}
|
|
|
- // 执行下个月计算
|
|
|
- if (nextMonthExists) {
|
|
|
- calculatePeriodComparisonOptimized(hospId, shareType, nextMonthYear, nextMonth);
|
|
|
+
|
|
|
+ // 同期
|
|
|
+ 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()));
|
|
|
}
|
|
|
- // 执行明年同月计算
|
|
|
- if (nextYearMonthExists) {
|
|
|
- calculatePeriodComparisonOptimized(hospId, shareType, nextYearMonthYear, nextYearMonth);
|
|
|
+
|
|
|
+ // 去重后查询
|
|
|
+ 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 是否存在数据
|
|
|
+ * @return 符合条件的数据列表
|
|
|
*/
|
|
|
- private boolean checkDataExistence(Long hospId, String shareType, int year, int month) {
|
|
|
- LambdaQueryWrapper<CostDepartmentProfit> last = new QueryWrapper<CostDepartmentProfit>().lambda()
|
|
|
+ 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)
|
|
|
- .last("LIMIT 1");
|
|
|
- CostDepartmentProfit one = this.getOne(last);
|
|
|
- return !ObjectUtils.isEmpty(one);
|
|
|
+ .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());
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
- * 批量计算同环比及同期金额
|
|
|
- *
|
|
|
- * @param hospId 院区ID
|
|
|
- * @param shareType 报表类型
|
|
|
- * @param year 年份
|
|
|
- * @param month 月份
|
|
|
+ * 批量计算同环比及同期金额(使用预加载数据)
|
|
|
*/
|
|
|
- public void calculatePeriodComparisonOptimized(Long hospId, String shareType, Integer year, Integer month) {
|
|
|
- // 查询符合条件的数据
|
|
|
- List<CostDepartmentProfit> records = getPeriodRecords(hospId, shareType, year, month);
|
|
|
- // 如果没有记录,直接返回
|
|
|
- if (CollectionUtils.isEmpty(records)) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ public void calculatePeriodComparisonWithPreloadedData(
|
|
|
+ List<CostDepartmentProfit> currentRecords,
|
|
|
+ List<CostDepartmentProfit> prevRecords,
|
|
|
+ List<CostDepartmentProfit> lastYearRecords) {
|
|
|
|
|
|
- // 构建上期和同期的时间参数
|
|
|
- int prevPeriodYear = year;
|
|
|
- int prevPeriodMonth = month - 1;
|
|
|
- if (month == 1) {
|
|
|
- prevPeriodYear = year - 1;
|
|
|
- prevPeriodMonth = 12;
|
|
|
+ if (CollectionUtils.isEmpty(currentRecords)) {
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- int lastYearYear = year - 1;
|
|
|
-
|
|
|
- // 批量查询上期数据
|
|
|
- List<CostDepartmentProfit> prevPeriodRecords = getPeriodRecords(hospId, shareType, prevPeriodYear, prevPeriodMonth);
|
|
|
-
|
|
|
- // 批量查询同期数据
|
|
|
- List<CostDepartmentProfit> lastYearRecords = getPeriodRecords(hospId, shareType, lastYearYear, month);
|
|
|
-
|
|
|
- // 将上期数据转换为映射
|
|
|
- Map<String, CostDepartmentProfit> prevPeriodMap = new HashMap<>();
|
|
|
- for (CostDepartmentProfit record : prevPeriodRecords) {
|
|
|
+ // 创建责任码+报表编号到记录的映射
|
|
|
+ Map<String, CostDepartmentProfit> prevMap = new HashMap<>();
|
|
|
+ for (CostDepartmentProfit record : prevRecords) {
|
|
|
String key = buildRecordKey(record);
|
|
|
- prevPeriodMap.put(key, record);
|
|
|
+ prevMap.put(key, record);
|
|
|
}
|
|
|
|
|
|
- // 将同期数据转换为映射
|
|
|
Map<String, CostDepartmentProfit> lastYearMap = new HashMap<>();
|
|
|
for (CostDepartmentProfit record : lastYearRecords) {
|
|
|
String key = buildRecordKey(record);
|
|
@@ -1323,79 +1375,59 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
|
|
|
}
|
|
|
|
|
|
// 批量更新数据
|
|
|
- for (CostDepartmentProfit record : records) {
|
|
|
- // 构建上期和同期的键
|
|
|
- String prevKey = String.format("%d_%d_%s_%d",
|
|
|
- prevPeriodYear, prevPeriodMonth, record.getResponsibilityCode(), record.getReportNum());
|
|
|
- String lastYearKey = String.format("%d_%d_%s_%d",
|
|
|
- lastYearYear, month, record.getResponsibilityCode(), record.getReportNum());
|
|
|
-
|
|
|
- // 获取上期和同期记录
|
|
|
- CostDepartmentProfit prevRecord = prevPeriodMap.get(prevKey);
|
|
|
- CostDepartmentProfit lastYearRecord = lastYearMap.get(lastYearKey);
|
|
|
+ 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(), record.getPrevPeriodAmount()));
|
|
|
- // 计算同比
|
|
|
record.setYoyRate(calculateProfitRate(record.getAmount(), record.getSamePeriodAmount()));
|
|
|
}
|
|
|
|
|
|
// 批量更新数据库
|
|
|
- this.updateBatchById(records);
|
|
|
+ this.updateBatchById(currentRecords);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
- * 获取指定期间的数据
|
|
|
- *
|
|
|
- * @param hospId 院区ID
|
|
|
- * @param shareType 报表类型
|
|
|
- * @param year 年份
|
|
|
- * @param month 月份
|
|
|
- * @return 符合条件的数据列表
|
|
|
+ * 构建期间键(用于存储和检索数据)
|
|
|
*/
|
|
|
- private List<CostDepartmentProfit> getPeriodRecords(Long hospId, String shareType, int year, int month) {
|
|
|
- return this.baseMapper.selectList(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 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])};
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
- * 构建记录的唯一标识键
|
|
|
- *
|
|
|
- * @param record 记录对象
|
|
|
- * @return 唯一标识键
|
|
|
+ * 构建记录的唯一标识键(责任码 + 报表编号)
|
|
|
*/
|
|
|
private String buildRecordKey(CostDepartmentProfit record) {
|
|
|
- return String.format("%d_%d_%s_%d",
|
|
|
- record.getYear(), record.getMonth(), record.getResponsibilityCode(), record.getReportNum());
|
|
|
+ return record.getResponsibilityCode() + "_" + record.getReportNum();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 安全地计算百分比:避免除零错误
|
|
|
- *
|
|
|
- * @param current 当前值
|
|
|
- * @param base 基准值
|
|
|
- * @return 计算结果,保留4位小数
|
|
|
*/
|
|
|
private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
|
|
|
if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
- // 先计算到4位小数,再四舍五入到4位
|
|
|
- BigDecimal rate = current.divide(base, 4, RoundingMode.HALF_UP);
|
|
|
- return rate.setScale(4, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
|
|
|
+ return bigDecimal;
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* 执行科室损益后续脚本
|
|
|
*
|
|
@@ -2789,6 +2821,15 @@ public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentP
|
|
|
return NumberConstant.ONE_S.equals(parameterValue);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 是否需要计算同环比
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public boolean IsNeedCalcYM() {
|
|
|
+ String parameterValue = centerService.getParameterValue(ParameterConstant.YM_CALC_TYPE);
|
|
|
+ return NumberConstant.ONE_S.equals(parameterValue);
|
|
|
+ }
|
|
|
+
|
|
|
private List<CommonResponsibilityReportVo> getChildTitle(List<Responsibility> responsibilities, Map<Long, List<Responsibility>> responsibilityGroup) {
|
|
|
List<CommonResponsibilityReportVo> list = new ArrayList<>();
|
|
|
for (Responsibility responsibility : responsibilities) {
|