package cn.iocoder.yudao.module.bi.service.decision; import cn.iocoder.yudao.module.bi.dal.mysql.decision.BiKpiDefinitionMapper; import cn.iocoder.yudao.module.bi.dal.dataobject.decision.BiKpiDefinitionDO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; /** * 决策支持 KPI 聚合 Service 实现 * * 通过 JdbcTemplate 跨模块执行聚合 SQL * * @author 超级管理员 */ @Slf4j @Service public class BiDecisionKpiServiceImpl implements BiDecisionKpiService { @Resource private BiKpiDefinitionMapper kpiMapper; @Resource private JdbcTemplate jdbcTemplate; @Override public Map getKpiOverview() { List kpis = kpiMapper.selectList(); List> items = new ArrayList<>(); for (BiKpiDefinitionDO kpi : kpis) { Map item = new LinkedHashMap<>(); item.put("code", kpi.getCode()); item.put("name", kpi.getName()); item.put("category", kpi.getCategory()); item.put("unit", kpi.getUnit()); item.put("chartType", kpi.getChartType()); item.put("status", kpi.getStatus()); // 执行查询获取当前值 BigDecimal value = executeKpiSql(kpi.getQuerySql()); item.put("value", value); // 判断预警状态 String alertStatus = evaluateAlertStatus(kpi, value); item.put("alertStatus", alertStatus); items.add(item); } Map result = new LinkedHashMap<>(); result.put("kpis", items); result.put("total", items.size()); return result; } @Override public Map getKpiDetail(String kpiCode) { BiKpiDefinitionDO kpi = kpiMapper.selectOne(BiKpiDefinitionDO::getCode, kpiCode); if (kpi == null) { return Collections.emptyMap(); } Map result = new LinkedHashMap<>(); result.put("code", kpi.getCode()); result.put("name", kpi.getName()); result.put("unit", kpi.getUnit()); result.put("category", kpi.getCategory()); result.put("value", executeKpiSql(kpi.getQuerySql())); return result; } @Override public Map getKpiByCategory(String category) { List kpis = kpiMapper.selectList( BiKpiDefinitionDO::getCategory, category); List> items = new ArrayList<>(); for (BiKpiDefinitionDO kpi : kpis) { Map item = new LinkedHashMap<>(); item.put("code", kpi.getCode()); item.put("name", kpi.getName()); item.put("unit", kpi.getUnit()); item.put("value", executeKpiSql(kpi.getQuerySql())); items.add(item); } Map result = new LinkedHashMap<>(); result.put("category", category); result.put("kpis", items); return result; } @Override public BigDecimal refreshKpi(String kpiCode) { BiKpiDefinitionDO kpi = kpiMapper.selectOne(BiKpiDefinitionDO::getCode, kpiCode); if (kpi == null) { return BigDecimal.ZERO; } return executeKpiSql(kpi.getQuerySql()); } /** * 执行 KPI 查询 SQL */ private BigDecimal executeKpiSql(String querySql) { if (querySql == null || querySql.isBlank()) { return BigDecimal.ZERO; } try { List> result = jdbcTemplate.queryForList(querySql); if (result.isEmpty()) { return BigDecimal.ZERO; } // 取第一行第一列的值 Map row = result.get(0); Object value = row.values().iterator().next(); if (value instanceof Number) { return BigDecimal.valueOf(((Number) value).doubleValue()); } return BigDecimal.ZERO; } catch (Exception e) { log.error("[executeKpiSql][SQL执行失败] {}", querySql, e); return BigDecimal.ZERO; } } /** * 评估预警状态 */ private String evaluateAlertStatus(BiKpiDefinitionDO kpi, BigDecimal value) { if (kpi.getThresholdCritical() != null) { int cmp = value.compareTo(kpi.getThresholdCritical()); boolean triggered = ">".equals(kpi.getComparisonOperator()) ? cmp > 0 : "<".equals(kpi.getComparisonOperator()) ? cmp < 0 : ">=".equals(kpi.getComparisonOperator()) ? cmp >= 0 : "<=".equals(kpi.getComparisonOperator()) ? cmp <= 0 : false; if (triggered) { return "critical"; } } if (kpi.getThresholdWarn() != null) { int cmp = value.compareTo(kpi.getThresholdWarn()); boolean triggered = ">".equals(kpi.getComparisonOperator()) ? cmp > 0 : "<".equals(kpi.getComparisonOperator()) ? cmp < 0 : ">=".equals(kpi.getComparisonOperator()) ? cmp >= 0 : "<=".equals(kpi.getComparisonOperator()) ? cmp <= 0 : false; if (triggered) { return "warn"; } } return "normal"; } }