package com.kcim.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.toolkit.SqlRunner; import com.kcim.common.constants.Constant; import com.kcim.common.constants.NumberConstant; import com.kcim.common.constants.SQLParameter; import com.kcim.common.exception.CostException; 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.CenterService; import com.kcim.service.ReportService; import com.kcim.vo.*; import com.kcim.web.reponse.ReportResponse; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** * @program: CostAccount * @description: 报表查询接口实现类 * @author: Wang.YS * @create: 2023-11-01 20:41 **/ @Service("ReportService") @AllArgsConstructor @Slf4j public class ReportServiceImpl implements ReportService { CostReportRepository repository; CostReportColumnRepository costReportColumnRepository; CostColumnRepository costColumnRepository; CostReportRedirectRepository costReportRedirectRepository; CenterService centerService; CostReportIndexRepository costReportIndexRepository; @Override public Object getReportData(Integer current, Integer pageSize, String reportCode, Map parameter) { CostReport report = repository.getReportByReportCode(Long.valueOf(reportCode)); if(Objects.isNull(report)){ log.error("未找到当前报表代码【"+reportCode+"】报表,请确认当前报表是否存在"); throw new CostException("未找到当前报表代码报表,请确认当前报表是否存在"); } //查询报表 获取主键列 List reportColumns = costReportColumnRepository.getReportColumnByReportCode(Long.valueOf(reportCode)); if(CollectionUtils.isEmpty(reportColumns)){ log.error("报表"+report.getName()+"未配置任何显示列,请先添加报表列再查询!"); throw new CostException("报表"+report.getName()+"未配置任何显示列,请先添加报表列再查询!"); } //获取主键列 List collect = reportColumns.stream().filter(f -> f.getPrimaryKey().equals(NumberConstant.ONE)).collect(Collectors.toList()); //主键列校验 if(CollectionUtils.isEmpty(collect)){ log.error("报表【"+report.getName()+"】未添加主键列,请重新维护!"); throw new CostException("报表【"+report.getName()+"】未添加主键列,请重新维护!"); } List columnCodes = reportColumns.stream().map(CostReportColumn::getColumnCode).collect(Collectors.toList()); //获取列代码 List costColumns = costColumnRepository.getColumnByColumnCode(columnCodes); if(CollectionUtils.isEmpty(costColumns)){ throw new CostException("报表"+report.getName()+"无符合条件报表列数据"); } Map costColumnMap = costColumns.stream().collect(Collectors.toMap(CostColumn::getCode, column -> column, (a, b) -> b)); Map> dataSourceGroup = costColumns.stream().collect(Collectors.groupingBy(CostColumn::getDataSource)); //获取报表是否可以跳转数据及跳转列 及跳转报表code List redirectByReportCode = costReportRedirectRepository.getRedirectByReportCode(Long.valueOf(reportCode)); // Map reportRedirectMap = redirectByReportCode.stream().collect(Collectors.toMap(ReportRedirect::getReportColumnCode, redirect -> redirect, (a, b) -> b)); //此需求不一定符合实际情况 强制要求改动 单报表同一字段 实际运用过程过只会下钻 子类数据一张报表 不会存在多张 备注记录一下 Map> reportRedirectMap = redirectByReportCode.stream().collect(Collectors.groupingBy(CostReportRedirect::getReportColumnCode)); //创建报表列标题 从字典中获取看是否存在已维护的标题 2023/7/12 // Map columnNameMap = sysDictDetailService.getDictionaryCodeNameMap(DirectoryConstant.REPORT_COLUMN_TEXT_MAP); DictDataVo dict = centerService.getDict(Constant.REPORT_COLUMN_TEXT_MAP); List dataVoList = dict.getDataVoList(); Map columnNameMap = new HashMap<>(); Map columnSortMap = new HashMap<>(); if(!CollectionUtils.isEmpty(dataVoList)){ columnNameMap = dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b)); columnSortMap = dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getSort, (a, b) -> b)); } //获取主键列代码 Long columnCode = collect.get(0).getColumnCode(); //获取主键数据 CostColumn costColumn = costColumnMap.get(columnCode); String keySql = costColumn.getSql(); if(!CollectionUtils.isEmpty(parameter)){ keySql = MatchParameter(keySql, parameter); }else { keySql = MatchParameter(keySql, new HashMap<>()); } log.info("主键sql"+keySql); List> keyList = sqlRunnerList(keySql); if(CollectionUtils.isEmpty(keyList)){ log.error("报表"+report.getName()+"无符合条件主键数据"+keySql); throw new CostException("报表"+report.getName()+"无符合条件主键数据"); } Integer totalCount = keyList.size(); if (current ==null){ current = 1; } if(pageSize ==null){ pageSize = 100; } List> maps = PageUtils.startPage(keyList, current, pageSize); List calcFormulaList = dataSourceGroup.get(NumberConstant.ONE); List calcCode = new ArrayList<>(); if(!CollectionUtils.isEmpty(calcFormulaList)){ calcCode = calcFormulaList.stream().map(CostColumn::getCode).collect(Collectors.toList()); } List sqlList = dataSourceGroup.get(NumberConstant.TWO); List sqlCode = sqlList.stream().map(CostColumn::getCode).collect(Collectors.toList()); List calcReportColumn = new ArrayList<>(); List sqlReportColumn = new ArrayList<>(); for (CostReportColumn reportColumn : reportColumns) { if(!CollectionUtils.isEmpty(calcCode)){ if(calcCode.contains(reportColumn.getColumnCode())){ calcReportColumn.add(reportColumn); } } if(sqlCode.contains(reportColumn.getColumnCode())){ sqlReportColumn.add(reportColumn); } } calcReportColumn.sort(Comparator.comparing(CostReportColumn::getSort)); List> vos = new ArrayList<>(); ReportCodeModifyVo reportCodeModifyVo = new ReportCodeModifyVo(); for(Map result:maps){ if(CollectionUtils.isEmpty(result)){ continue; } Map keyParameter = result.keySet().stream().collect(Collectors.toMap(s -> s, result::get, (a, b) -> b)); List dataVo = new ArrayList<>(); //sql报表列 if(!CollectionUtils.isEmpty(sqlReportColumn)){ for(CostReportColumn column:sqlReportColumn){ Integer primaryKey = column.getPrimaryKey(); if(primaryKey.equals(NumberConstant.ONE)){ if(result.size()>1){ Map modify = new HashMap<>(); for(String s:result.keySet()){ ReportVo vo = new ReportVo(); vo.setCode(column.getReportCode()+s); vo.setValue(result.get(s)); dataVo.add(vo); modify.put(column.getReportCode()+s,s); } reportCodeModifyVo.setReportCode(column.getColumnCode()); reportCodeModifyVo.setModifyReportCode(modify); }else { ReportVo vo = new ReportVo(); vo.setCode(column.getColumnCode().toString()); vo.setValue(result.values().stream().findFirst().get()); // modify.put(vo.getCode(),result.keySet().stream().findFirst().get()); dataVo.add(vo); } // reportCodeModifyVo.setReportCode(column.getColumnCode()); // reportCodeModifyVo.setModifyReportCode(modify); }else { ReportVo vo = new ReportVo(); vo.setCode(column.getColumnCode().toString()); CostColumn col = costColumnMap.get(column.getColumnCode()); String sql = col.getSql(); String handleSql ; if(!CollectionUtils.isEmpty(parameter)){ handleSql = MatchParameter(sql, keyParameter, parameter); }else { handleSql = MatchParameter(sql, keyParameter,new HashMap<>()); } Object o = sqlRunner(handleSql); // Integer dataType = col.getDataType(); // // if(dataType != null&&dataType.equals(NumberConstant.THREE)){ // Integer decimalPlace = col.getDecimalPlace(); // if(o.equals("")){ // vo.setValue(BigDecimal.ZERO.setScale(decimalPlace,RoundingMode.HALF_UP)); // }else { // BigDecimal value = new BigDecimal(o.toString()); // vo.setValue(value.setScale(decimalPlace,RoundingMode.HALF_UP)); // } // }else { vo.setValue(o); // } dataVo.add(vo); } } } //添加计算公式算法 if(!CollectionUtils.isEmpty(calcReportColumn)){ for(CostReportColumn column:calcReportColumn){ Integer primaryKey = column.getPrimaryKey(); if(primaryKey.equals(NumberConstant.ONE)){ if(result.size()>1){ Map modify = new HashMap<>(); for(String s:result.keySet()){ ReportVo vo = new ReportVo(); vo.setCode(column.getReportCode()+s); vo.setValue(result.get(s)); dataVo.add(vo); modify.put(column.getReportCode()+s,s); } reportCodeModifyVo.setReportCode(column.getColumnCode()); reportCodeModifyVo.setModifyReportCode(modify); }else { ReportVo vo = new ReportVo(); vo.setCode(column.getColumnCode().toString()); vo.setValue(result.values().stream().findFirst().get()); dataVo.add(vo); } }else { ReportVo vo = new ReportVo(); vo.setCode(column.getColumnCode().toString()); CostColumn col = costColumnMap.get(column.getColumnCode()); String formula = col.getFormula(); BigDecimal formulaData = getFormulaData(formula, dataVo,column); // Integer dataType = col.getDataType(); // if(dataType != null&&dataType.equals(NumberConstant.THREE)){ // Integer decimalPlace = col.getDecimalPlace(); // vo.setValue(formulaData.setScale(decimalPlace, RoundingMode.HALF_UP)); // }else { vo.setValue(formulaData); // } dataVo.add(vo); } } } vos.add(dataVo); } List titleVos = new ArrayList<>(); for(CostReportColumn column:reportColumns){ Integer primaryKey = column.getPrimaryKey(); if(primaryKey.equals(NumberConstant.ONE)){ if(reportCodeModifyVo.getReportCode() != null){ if(reportCodeModifyVo.getReportCode().equals(column.getColumnCode())){ Map modifyReportCode = reportCodeModifyVo.getModifyReportCode(); List primary = modifyReportCode.keySet().stream().map(modifyReportCode::get).collect(Collectors.toList()); for(String key:modifyReportCode.keySet()){ ReportTitleVo vo = new ReportTitleVo(); vo.setCode(key); String columnName = modifyReportCode.get(key); String name; if(!CollectionUtils.isEmpty(columnNameMap)){ name = columnNameMap.get(columnName); if(StringUtils.isEmpty(name)){ name = columnName; } }else { name = columnName; } vo.setName(name); if(!CollectionUtils.isEmpty(columnSortMap)){ Integer sort = columnSortMap.get(columnName); vo.setSort(sort != null ? sort : column.getSort()); }else { vo.setSort(column.getSort()); } vo.setHide(column.getHide()); vo.setFreeze(column.getFreeze()); vo.setSortStatus(column.getSortStatus()); // 2023/7/13 主键列为多个时候 需要用sql查出的列表作为 columnName 要求改造 vo.setColumnName(columnName); vo.setSearch(column.getSearch()); List reportRedirects = reportRedirectMap.get(column.getColumnCode()); if(!CollectionUtils.isEmpty(reportRedirects)){ List redirectDataList = new ArrayList<>(); for(CostReportRedirect redirect:reportRedirects){ RedirectData redirectData = new RedirectData(); redirectData.setRedirectReportCode(redirect.getRedirectReportCode()); // 2023/7/13 主键列为多个时候 有跳转报表 把每个主键列都放进去 要求改造 StringBuilder redirectParameter = setRedirectParameter(primary, redirect); redirectData.setRedirectParameter(redirectParameter.toString()); redirectData.setRedirectReportName(redirect.getRedirectReportName()); redirectDataList.add(redirectData); } vo.setRedirect(true); vo.setRedirectData(redirectDataList); } titleVos.add(vo); } } else { titleVos.add(getReportTitleVo(column.getColumnCode().toString(), column.getColumnHeaderText(), column, reportRedirectMap,reportCodeModifyVo,costColumnMap)); } }else { titleVos.add(getReportTitleVo(column.getColumnCode().toString(), column.getColumnHeaderText(), column, reportRedirectMap, reportCodeModifyVo, costColumnMap)); } }else { titleVos.add(getReportTitleVo(column.getColumnCode().toString(), column.getColumnHeaderText(), column, reportRedirectMap, reportCodeModifyVo, costColumnMap)); } } ReportResponse response = new ReportResponse(); titleVos.sort(Comparator.comparing(ReportTitleVo::getSort)); response.setReportName(report.getName()); response.setTitle(titleVos); response.setData(vos); response.setCurrent(current); response.setPageSize(pageSize); response.setTotalCount(totalCount); response.setTotalPage((int)Math.ceil((double)totalCount/pageSize)); return response; } @Override public Object getReportIndex(Long reportCode) { CostReport report = repository.getReportByReportCode(reportCode); List byReportCode = costReportIndexRepository.getByReportCode(Collections.singletonList(reportCode)); if(!CollectionUtils.isEmpty(byReportCode)){ report.setReportIndex(byReportCode); } return report; } private BigDecimal getFormulaData(String formula, List dataVo, CostReportColumn column) { //找出公式当中所有代码 String replace = formula.replace("[", "") .replace("]", "") .replace("-", ",") .replace("+", ",") .replace("*",",") .replace("/",","); ArrayList codeList = CollUtil.newArrayList(replace.split(",")); Map codeMap = new ConcurrentHashMap<>(); for (int j = 0; j < codeList.size(); j++) { codeMap.put(j, codeList.get(j)); } List expressions = ReUtil.findAll("[^0-9]", "+" + formula.replace("[", "") .replace("]", "").trim(), 0) .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); // 得到预算表达式 得到所有表达式的Map + - 相关的 Map expressionMap = new ConcurrentHashMap<>(); for (int k = 0; k < expressions.size(); k++) { expressionMap.put(k, expressions.get(k)); } // 数字的索引和表达式的索引累加计算 Set codeSet = codeMap.keySet(); List codes = new ArrayList<>(codeSet); AtomicReference totalAmount = new AtomicReference<>(); totalAmount.set(BigDecimal.ZERO); Map dataMap = dataVo.stream().collect(Collectors.toMap(ReportVo::getCode, ReportVo::getValue, (a, b) -> b)); for (int i = 0; i < codes.size(); i++) { // 编号 String code = codeMap.get(i); Object o = dataMap.get(code); 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("+")) { totalAmount.set(totalAmount.get().add(amount)); } else if(str.contains("-")){ 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("报表列【"+column.getColumnName()+"】公式除数为0,数据为【"+code+"】数据"); totalAmount.set(BigDecimal.ZERO) ; break; }else { totalAmount.set(totalAmount.get().divide(amount,4, RoundingMode.HALF_UP)); } } } return totalAmount.get(); } private static StringBuilder setRedirectParameter(List primary, CostReportRedirect redirect) { StringBuilder redirectParameter = new StringBuilder(redirect.getRedirectParameter()); if(!StringUtils.isEmpty(redirectParameter.toString())){ if(redirectParameter.toString().contains("|")){ String[] split = StrUtil.splitToArray(redirectParameter.toString(), "|"); assert split != null; List strings1 = Arrays.asList(split); List strings = new ArrayList<>(strings1); List collect1 = strings.stream().filter(primary::contains).collect(Collectors.toList()); if(!CollectionUtils.isEmpty(collect1)){ primary.removeAll(collect1); if(!CollectionUtils.isEmpty(primary)){ for(String s: primary){ redirectParameter.append("|").append(s); } } }else { for(String s: primary){ redirectParameter.append("|").append(s); } } }else { boolean contains = false; for(String s: primary){ if (redirectParameter.toString().equals(s)) { contains = true; break; } } if(contains){ primary.remove(redirectParameter.toString()); } if(!CollectionUtils.isEmpty(primary)){ for(String s: primary){ redirectParameter.append("|").append(s); } } } }else { for(String s: primary){ redirectParameter = new StringBuilder(s + "|"); } redirectParameter.deleteCharAt(redirectParameter.length() -1); } return redirectParameter; } private static ReportTitleVo getReportTitleVo(String column, String columnName, CostReportColumn reportColumn, Map> reportRedirectMap, ReportCodeModifyVo reportCodeModifyVo, Map map) { ReportTitleVo vo = new ReportTitleVo(); vo.setCode(column); vo.setName(columnName); vo.setSort(reportColumn.getSort()+100); vo.setHide(reportColumn.getHide()); vo.setFreeze(reportColumn.getFreeze()); vo.setColumnName(reportColumn.getColumnName()); vo.setSortStatus(reportColumn.getSortStatus()); vo.setSearch(reportColumn.getSearch()); CostColumn computeColumn = map.get(Long.valueOf(column)); if(Objects.nonNull(computeColumn)){ vo.setDataType(computeColumn.getDataType()); vo.setDecimalPlace(computeColumn.getDecimalPlace()); String permil = computeColumn.getPermil(); if(StringUtils.isEmpty(permil)){ vo.setPermil(false); }else { vo.setPermil(permil.equals(NumberConstant.ONE_S)); } } List primary = new ArrayList<>(); if(reportCodeModifyVo.getReportCode() != null){ Map modifyReportCode = reportCodeModifyVo.getModifyReportCode(); List collect = new ArrayList<>(); modifyReportCode.forEach((key, v) -> collect.add(v)); primary.addAll(collect); } //此需求不一定符合实际情况 强制要求改动 单报表同一字段 实际运用过程过只会下钻 子类数据一张报表 不会存在多张 备注记录一下 // ReportRedirect redirect = reportRedirectMap.get(column.getColumnCode()); // if(Objects.nonNull(redirect)){ // vo.setRedirectReportCode(redirect.getRedirectReportCode()); // vo.setRedirect(true); // vo.setRedirectParameter(redirect.getRedirectParameter()); // } if(!CollectionUtils.isEmpty(primary)){ List reportRedirects = reportRedirectMap.get(reportColumn.getColumnCode()); if(!CollectionUtils.isEmpty(reportRedirects)){ List redirectDataList = new ArrayList<>(); for(CostReportRedirect redirect:reportRedirects){ RedirectData redirectData = new RedirectData(); redirectData.setRedirectReportCode(redirect.getRedirectReportCode()); StringBuilder redirectParameter = setRedirectParameter(primary, redirect); redirectData.setRedirectParameter(redirectParameter.toString()); redirectData.setRedirectReportName(redirect.getRedirectReportName()); redirectDataList.add(redirectData); } vo.setRedirect(true); vo.setRedirectData(redirectDataList); } }else { List reportRedirects = reportRedirectMap.get(reportColumn.getColumnCode()); if(!CollectionUtils.isEmpty(reportRedirects)){ List redirectDataList = new ArrayList<>(); for(CostReportRedirect redirect:reportRedirects){ RedirectData redirectData = new RedirectData(); redirectData.setRedirectReportCode(redirect.getRedirectReportCode()); redirectData.setRedirectParameter(redirect.getRedirectParameter()); redirectData.setRedirectReportName(redirect.getRedirectReportName()); redirectDataList.add(redirectData); } vo.setRedirect(true); vo.setRedirectData(redirectDataList); } } return vo; } private String MatchParameter(String sql, Map keyParameter, Map parameter) { if(StringUtils.isEmpty(sql)){ throw new CostException("无效自定义sql语句"); } //替换主键 if(!CollectionUtils.isEmpty(keyParameter)){ for (String s : keyParameter.keySet()) { String key = "#" + s; if (sql.contains(key)) { sql = sql.replace(key, keyParameter.get(s).toString()); } } } sql = MatchSystemParameter(sql); //替换传参 if(!CollectionUtils.isEmpty(parameter)){ for(String s:parameter.keySet()){ //拼接 # String sqlFilter = "#" + s; if (sql.contains(sqlFilter)) { sql = sql.replace(sqlFilter, parameter.get(s)); } } } if(sql.contains("#")){ log.error("sql 所需条件未全部传递,请确认后再进行查询"+sql); throw new CostException("sql 所需条件未全部传递,请确认后再进行查询"); } return sql; } private String MatchParameter(String sql,String keyCode,String keyValue,Map parameter) { if(StringUtils.isEmpty(sql)){ throw new CostException("无效自定义sql语句"); } //替换主键 String key = "#" + keyCode; if (sql.contains(key)) { sql = sql.replace(key, keyValue); } sql = MatchSystemParameter(sql); //替换传参 if(!CollectionUtils.isEmpty(parameter)){ for(String s:parameter.keySet()){ //拼接 # String sqlFilter = "#" + s; if (sql.contains(sqlFilter)) { sql = sql.replace(sqlFilter, parameter.get(s)); } } } if(sql.contains("#")){ log.error("sql 所需条件未全部传递,请确认后再进行查询"); throw new ClassCastException("sql 所需条件未全部传递,请确认后再进行查询"); } return sql; } private String MatchParameter(String sql,Map parameter) { if(StringUtils.isEmpty(sql)){ throw new CostException("无效自定义sql语句"); } sql = MatchSystemParameter(sql); //替换传参 if(!CollectionUtils.isEmpty(parameter)){ for(String s:parameter.keySet()){ //拼接 # String sqlFilter = "#" + s; if (sql.contains(sqlFilter)) { sql = sql.replace(sqlFilter, parameter.get(s)); } } } if(sql.contains("#")){ log.error("sql 所需条件未全部传递,请确认后再进行查询"+sql); throw new CostException("sql 所需条件未全部传递,请确认后再进行查询"); } return sql; } private Object sqlRunner(String sql) { // List objects = SqlUtil.getresult(sql, Object.class); log.info("sqlRunner执行"+sql); Object objects = SqlRunner.db().selectObj(sql, Object.class); if(Objects.nonNull(objects)){ Class aClass = objects.getClass(); if(objects instanceof Integer || objects instanceof Long || objects instanceof Double || objects instanceof Float){ return Double.parseDouble(objects.toString()); } else if (objects instanceof BigDecimal) { return objects; }else { return objects.toString(); } }else{ return ""; } } private List> sqlRunnerList(String sql) { return SqlRunner.db().selectList(sql, String.class); } private static String MatchSystemParameter(String sql) { if(StringUtils.isEmpty(sql)){ throw new CostException("无效自定义sql语句"); } if (sql.contains(SQLParameter.HOSP_ID_CODE)) { sql = sql.replace(SQLParameter.HOSP_ID_CODE, String.valueOf(UserContext.getCurrentLoginHospId())); } if (sql.contains(SQLParameter.USER_CODE)) { sql = sql.replace(SQLParameter.USER_CODE, String.valueOf(UserContext.getCurrentUser().getId())); } return sql; } }