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<IPage<DryOrder>> 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<DryOrder> 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<DryOrder> page = new Page<DryOrder>(pageNo, pageSize);
|
IPage<DryOrder> 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<DryOrder> queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap());
|
LambdaQueryWrapper<DryOrder> 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<DryOrder> 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<String, Object> 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<DryOrder> queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap());
|
LambdaQueryWrapper<DryOrder> 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<DryOrder> list = dryOrderService.list(lambda);
|
|
List<Map<String, Object>> statList = list.stream()
|
.collect(Collectors.groupingBy(DryOrder::getHerbId))
|
.entrySet().stream()
|
.map(e -> {
|
String herbId = e.getKey();
|
List<DryOrder> 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<String, Object> 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<DryOrder> queryWrapper = QueryGenerator.initQueryWrapper(dryOrder, req.getParameterMap());
|
LambdaQueryWrapper<DryOrder> 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<DryOrder> 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<DryEquipment> eqs = dryEquipmentService.queryEqusByTenantId(eqParam);
|
Map<String, String> eqNameById = eqs.stream().collect(Collectors.toMap(DryEquipment::getId, DryEquipment::getName));
|
|
List<String> 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<String, Map<String, Double>> 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<String, Double> perEq = yieldByHerb.computeIfAbsent(herbName, k -> new HashMap<>());
|
perEq.put(eqName, perEq.getOrDefault(eqName, 0.0) + y);
|
}
|
|
List<Map<String, Object>> series = yieldByHerb.entrySet().stream()
|
.sorted(Map.Entry.comparingByKey())
|
.map(e -> {
|
String herbName = e.getKey();
|
Map<String, Double> perEq = e.getValue();
|
List<Double> equProList = yAxis.stream()
|
.map(eq -> {
|
double v = perEq.getOrDefault(eq, 0.0);
|
return Math.round(v * 10.0) / 10.0;
|
})
|
.collect(Collectors.toList());
|
Map<String, Object> m = new HashMap<>();
|
m.put("name", herbName);
|
m.put("equProList", equProList);
|
return m;
|
})
|
.collect(Collectors.toList());
|
|
List<Map<String, Object>> statList = list.stream()
|
// 机台维度分组
|
.collect(Collectors.groupingBy(DryOrder::getEquId))
|
.entrySet().stream()
|
.map(e -> {
|
String equId = e.getKey();
|
List<DryOrder> 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<String, Object> 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<String, Object> resp = new HashMap<>();
|
resp.put("statList", statList);
|
resp.put("yAxis", yAxis);
|
resp.put("series", series);
|
return Result.OK(resp);
|
}
|
|
}
|