package org.jeecg.modules.dry.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.config.TenantContext; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.util.oConvertUtils; import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.jeecg.modules.dry.entity.DryEquipment; import org.jeecg.modules.dry.entity.DryOrder; import org.jeecg.modules.dry.service.IDryEquipmentService; import org.jeecg.modules.dry.service.IDryOrderService; import org.jeecg.modules.dry.service.IDryOrderTrendService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.stream.Collectors; /** * 报表模块相关聚合接口 */ @Api(tags="报表管理") @RestController @RequestMapping("/dry/report") @Slf4j public class ReportController{ @Autowired private IDryOrderService dryOrderService; @Autowired private IDryOrderTrendService dryOrderTrendService; @Autowired private IDryEquipmentService dryEquipmentService; private final Integer FINISH_ORDER_STATU = 4; @ApiOperation(value="报表管理-批次质量分析", notes="干燥工单(分页列表查询)-批次质量分析") @GetMapping(value = "/batchQualityList") public Result> queryPageList(DryOrder dryOrder, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req) { //------------------------------------------------------------------------------------------------ //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】 if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ dryOrder.setTenantId(oConvertUtils.getInt(TenantContext.getTenant(),0)); } //------------------------------------------------------------------------------------------------ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap()); queryWrapper.isNotNull("herb_id") // 药材不为空 .ge("origin_weight", 50)// 药材初始重量不低于50 .ge("yield", 0)// 药材干料重量不低于0 .ge("order_status", FINISH_ORDER_STATU)// 工单状态为已完成 .ge("dry_time", 30)// 干燥时间大于30分钟 .ge("watt", 0) //电能消耗大于0 .ge("steam", 0);//蒸汽消耗大于0 Page page = new Page(pageNo, pageSize); IPage pageList = dryOrderService.page(page, queryWrapper); return Result.OK(pageList); } @ApiOperation(value="报表管理-批次质量分析", notes="干燥工单(统计数据)-批次质量分析") @GetMapping(value = "/batchQualityStatis") public Result queryBatchQualityStatis(DryOrder dryOrder, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req) { //------------------------------------------------------------------------------------------------ //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】 if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ dryOrder.setTenantId(oConvertUtils.getInt(TenantContext.getTenant(),0)); } //------------------------------------------------------------------------------------------------ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap()); LambdaQueryWrapper lambda = queryWrapper.lambda() .isNotNull(DryOrder::getHerbId) // 药材不为空 .ne(DryOrder::getHerbId, "") .isNotNull(DryOrder::getOriginWeight)// 药材初始重量不低于50 .ge(DryOrder::getOriginWeight, 50) .ge(DryOrder::getYield, 0)// 药材干料重量不低于0 .eq(DryOrder::getOrderStatus, FINISH_ORDER_STATU)// 工单状态为已完成 .isNotNull(DryOrder::getDryTime)// 干燥时间大于30分钟 .ge(DryOrder::getDryTime, 30) .ge(DryOrder::getWatt, 0) //电能消耗大于0 .ge(DryOrder::getSteam, 0);//蒸汽消耗大于0 List list = dryOrderService.list(lambda); // 平均效率 double efficiencyAvg = list.stream() .map(vo -> { if (vo == null) { return null; } Integer dt = vo.getDryTime(); Double originWeight = vo.getOriginWeight(); Double yield = vo.getYield(); // 检查 originWeight 和 yield 是否为空 if (originWeight == null || yield == null) { return null; } Double ow = originWeight - yield; if (dt != null && dt > 0 && ow != null) { double hours = dt / 60.0; if (hours > 0) { return ow / hours; } } return null; }) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .average() .orElse(0.0); // 平均含水率 double moistureDeviationAvg = list.stream() .map(vo -> { Double moisture = vo.getMoisture(); Double target = vo.getTarget(); if (moisture != null && moisture > 0 && target != null) { return Math.abs(moisture - target); } return null; }) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .average() .orElse(0.0); // 平均得分(目前计算方式:含水率每相差1个点扣5分) double qualityScoreAvg = list.stream() .map(vo -> { Double moisture = vo.getMoisture(); Double target = vo.getTarget(); if (moisture != null && moisture > 0 && target != null) { double diff = Math.abs(moisture - target); double score = 100 - diff * 5; if (score < 0) score = 0; if (score > 100) score = 100; return score; } return null; }) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .average() .orElse(0.0); Map stat = new HashMap<>(); stat.put("effeAvg", String.format("%.2f", efficiencyAvg)); stat.put("moistureAvg", String.format("%.2f", moistureDeviationAvg)); stat.put("scoreAvg", String.format("%.2f", qualityScoreAvg)); stat.put("count", list.size()); return Result.OK(stat); } @ApiOperation(value="报表管理-车间统计", notes="车间统计-品种汇总") @GetMapping(value = "/workshopStatis") public Result queryWorkshopStatis(DryOrder dryOrder, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req) { //------------------------------------------------------------------------------------------------ //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】 if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ dryOrder.setTenantId(oConvertUtils.getInt(TenantContext.getTenant(),0)); } //------------------------------------------------------------------------------------------------ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap()); LambdaQueryWrapper lambda = queryWrapper.lambda() .isNotNull(DryOrder::getHerbId) // 药材不为空 .ne(DryOrder::getHerbId, "") .isNotNull(DryOrder::getOriginWeight)// 药材初始重量不低于50 .ge(DryOrder::getOriginWeight, 50) .ge(DryOrder::getYield, 0)// 药材干料重量不低于0 .eq(DryOrder::getOrderStatus, FINISH_ORDER_STATU)// 工单状态为已完成 .isNotNull(DryOrder::getDryTime)// 干燥时间大于30分钟 .ge(DryOrder::getDryTime, 30) .ge(DryOrder::getWatt, 0) //电能消耗大于0 .ge(DryOrder::getSteam, 0);//蒸汽消耗大于0 List list = dryOrderService.list(lambda); List> statList = list.stream() .collect(Collectors.groupingBy(DryOrder::getHerbId)) .entrySet().stream() .map(e -> { String herbId = e.getKey(); List group = e.getValue(); String herbName = group.stream() .map(DryOrder::getHerbName) .filter(Objects::nonNull) .findFirst() .orElse(""); // 投料量合计 long feedSum = group.stream() .map(DryOrder::getFeed) .filter(Objects::nonNull) .mapToLong(Integer::longValue) .sum(); // 产量合计 double yieldSum = group.stream() .map(DryOrder::getYield) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 蒸发量合计 = 初始重量(originWeight) - 产量(yield),负值按0处理后求和 double evaporationSum = group.stream() .map(vo -> { double ow = vo.getOriginWeight() != null ? vo.getOriginWeight() : 0.0; double y = vo.getYield() != null ? vo.getYield() : 0.0; double evap = ow - y; return evap < 0 ? 0.0 : evap; }) .mapToDouble(Double::doubleValue) .sum(); // 干燥时长合计(分钟) int dryMinutes = group.stream() .map(DryOrder::getDryTime) .filter(Objects::nonNull) .mapToInt(Integer::intValue) .sum(); // 干燥时长展示为 x小时x分钟 int hoursPart = dryMinutes / 60; int minutesPart = dryMinutes % 60; String dryDuration = String.format("%d小时%d分钟", hoursPart, minutesPart); double dryHours = dryMinutes / 60.0; // 干燥效率 = 蒸发量合计 / 干燥时长(小时) double efficiency = dryHours > 0 ? (evaporationSum / dryHours) : 0.0; // 蒸汽消耗合计 double steamSum = group.stream() .map(DryOrder::getSteam) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 单位蒸汽消耗 = 蒸汽消耗合计 / 蒸发量合计 double unitSteam = evaporationSum > 0 ? (steamSum / evaporationSum) : 0.0; // 电能消耗合计 double wattSum = group.stream() .map(DryOrder::getWatt) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 单位电能消耗 = 电能消耗合计 / 蒸发量合计 double unitWatt = evaporationSum > 0 ? (wattSum / evaporationSum) : 0.0; Map m = new HashMap<>(); m.put("herbId", herbId); m.put("herbName", herbName); m.put("feed", feedSum); m.put("yield", String.format("%.2f", yieldSum)); m.put("evaporation", String.format("%.2f", evaporationSum)); m.put("dryDuration", dryDuration); m.put("efficiency", String.format("%.2f", efficiency)); m.put("steam", String.format("%.2f", steamSum)); m.put("unitSteam", String.format("%.2f", unitSteam)); m.put("watt", String.format("%.2f", wattSum)); m.put("unitWatt", String.format("%.2f", unitWatt)); return m; }) .sorted(Comparator.comparing(m -> (String) m.get("herbName"), Comparator.nullsLast(Comparator.naturalOrder()))) .collect(Collectors.toList()); return Result.OK(statList); } @ApiOperation(value="报表管理-品种统计", notes="品种统计-机台汇总") @GetMapping(value = "/herbStatis") public Result queryHerbStatis(DryOrder dryOrder, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req) { //------------------------------------------------------------------------------------------------ //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】 if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ dryOrder.setTenantId(oConvertUtils.getInt(TenantContext.getTenant(),0)); } //------------------------------------------------------------------------------------------------ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap()); LambdaQueryWrapper lambda = queryWrapper.lambda() .isNotNull(DryOrder::getHerbId) // 药材不为空 .ne(DryOrder::getHerbId, "") .isNotNull(DryOrder::getOriginWeight)// 药材初始重量不低于50 .ge(DryOrder::getOriginWeight, 50) .ge(DryOrder::getYield, 0)// 药材干料重量不低于0 .eq(DryOrder::getOrderStatus, FINISH_ORDER_STATU)// 工单状态为已完成 .isNotNull(DryOrder::getDryTime)// 干燥时间大于30分钟 .ge(DryOrder::getDryTime, 30) .ge(DryOrder::getWatt, 0) //电能消耗大于0 .ge(DryOrder::getSteam, 0);//蒸汽消耗大于0 List list = dryOrderService.list(lambda); Integer tenantId = dryOrder.getTenantId(); if (tenantId == null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0); } DryEquipment eqParam = new DryEquipment(); eqParam.setTenantId(tenantId); List eqs = dryEquipmentService.queryEqusByTenantId(eqParam); Map eqNameById = eqs.stream().collect(Collectors.toMap(DryEquipment::getId, DryEquipment::getName)); List yAxis = list.stream() .map(DryOrder::getEquId) .filter(Objects::nonNull) .map(id -> eqNameById.getOrDefault(id, "")) .filter(name -> name != null && !name.isEmpty()) .distinct() .sorted() .collect(Collectors.toList()); Map> yieldByHerb = new HashMap<>(); for (DryOrder vo : list) { String herbName = vo.getHerbName(); if (herbName == null || herbName.isEmpty()) { continue; } String eqName = eqNameById.getOrDefault(vo.getEquId(), ""); if (eqName == null || eqName.isEmpty()) { continue; } double y = vo.getYield() != null ? vo.getYield() : 0.0; Map perEq = yieldByHerb.computeIfAbsent(herbName, k -> new HashMap<>()); perEq.put(eqName, perEq.getOrDefault(eqName, 0.0) + y); } List> series = yieldByHerb.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(e -> { String herbName = e.getKey(); Map perEq = e.getValue(); List equProList = yAxis.stream() .map(eq -> { double v = perEq.getOrDefault(eq, 0.0); return Math.round(v * 10.0) / 10.0; }) .collect(Collectors.toList()); Map m = new HashMap<>(); m.put("name", herbName); m.put("equProList", equProList); return m; }) .collect(Collectors.toList()); List> statList = list.stream() // 机台维度分组 .collect(Collectors.groupingBy(DryOrder::getEquId)) .entrySet().stream() .map(e -> { String equId = e.getKey(); List group = e.getValue(); String herbId = group.stream() .map(DryOrder::getHerbId) .filter(h -> h != null && !h.isEmpty()) .distinct() // 去重 .collect(Collectors.joining(",")); String herbName = group.stream() .map(DryOrder::getHerbName) .filter(Objects::nonNull) .distinct() .collect(Collectors.joining(",")); // 投料量合计 long feedSum = group.stream() .map(DryOrder::getFeed) .filter(Objects::nonNull) .mapToLong(Integer::longValue) .sum(); // 产量合计 double yieldSum = group.stream() .map(DryOrder::getYield) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 蒸发量合计 = 初始重量(originWeight) - 产量(yield),负值按0处理后求和 double evaporationSum = group.stream() .map(vo -> { double ow = vo.getOriginWeight() != null ? vo.getOriginWeight() : 0.0; double y = vo.getYield() != null ? vo.getYield() : 0.0; double evap = ow - y; return evap < 0 ? 0.0 : evap; }) .mapToDouble(Double::doubleValue) .sum(); // 干燥时长合计(分钟) int dryMinutes = group.stream() .map(DryOrder::getDryTime) .filter(Objects::nonNull) .mapToInt(Integer::intValue) .sum(); // 干燥时长展示为 x小时x分钟 int hoursPart = dryMinutes / 60; int minutesPart = dryMinutes % 60; String dryDuration = String.format("%d小时%d分钟", hoursPart, minutesPart); double dryHours = dryMinutes / 60.0; // 干燥效率 = 蒸发量合计 / 干燥时长(小时) double efficiency = dryHours > 0 ? (evaporationSum / dryHours) : 0.0; // 蒸汽消耗合计 double steamSum = group.stream() .map(DryOrder::getSteam) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 单位蒸汽消耗 = 蒸汽消耗合计 / 蒸发量合计 double unitSteam = evaporationSum > 0 ? (steamSum / evaporationSum) : 0.0; // 电能消耗合计 double wattSum = group.stream() .map(DryOrder::getWatt) .filter(Objects::nonNull) .mapToDouble(Double::doubleValue) .sum(); // 单位电能消耗 = 电能消耗合计 / 蒸发量合计 double unitWatt = evaporationSum > 0 ? (wattSum / evaporationSum) : 0.0; Map m = new HashMap<>(); m.put("equId", equId); m.put("equName", eqNameById.getOrDefault(equId, "")); m.put("herbId", herbId); m.put("herbName", herbName); m.put("feed", feedSum); m.put("yield", String.format("%.2f", yieldSum)); m.put("evaporation", String.format("%.2f", evaporationSum)); m.put("dryDuration", dryDuration); m.put("dryTime", dryMinutes); m.put("efficiency", String.format("%.2f", efficiency)); m.put("steam", String.format("%.2f", steamSum)); m.put("unitSteam", String.format("%.2f", unitSteam)); m.put("watt", String.format("%.2f", wattSum)); m.put("unitWatt", String.format("%.2f", unitWatt)); return m; }) .sorted(Comparator.comparing(m -> (String) m.get("equName"), Comparator.nullsLast(Comparator.naturalOrder()))) .collect(Collectors.toList()); Map resp = new HashMap<>(); resp.put("statList", statList); resp.put("yAxis", yAxis); resp.put("series", series); return Result.OK(resp); } }