From 09655b466d315335e53d42cf9abe23929005b94a Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期三, 10 十二月 2025 15:01:44 +0800
Subject: [PATCH] 添加报表管理相关接口

---
 jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/service/impl/DryRealTimeDataServiceImpl.java |   15 +
 jeecg-module-dry/jeecg-module-dry-api/src/main/java/org/jeecg/modules/dry/entity/DryOrder.java                         |    4 
 jeecg-boot-base-core/pom.xml                                                                                           |    6 
 jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/controller/ReportController.java             |  481 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 501 insertions(+), 5 deletions(-)

diff --git a/jeecg-boot-base-core/pom.xml b/jeecg-boot-base-core/pom.xml
index f3e1c9f..46c8cc5 100755
--- a/jeecg-boot-base-core/pom.xml
+++ b/jeecg-boot-base-core/pom.xml
@@ -264,11 +264,7 @@
             <artifactId>bcprov-jdk15to18</artifactId>
             <version>1.78</version>
         </dependency>
-        <dependency>
-            <groupId>org.bouncycastle</groupId>
-            <artifactId>bcpkix-jdk15to18</artifactId>
-            <version>1.78</version>
-        </dependency>
+
   </dependencies>
 
 </project>
diff --git a/jeecg-module-dry/jeecg-module-dry-api/src/main/java/org/jeecg/modules/dry/entity/DryOrder.java b/jeecg-module-dry/jeecg-module-dry-api/src/main/java/org/jeecg/modules/dry/entity/DryOrder.java
index 29ac2c8..e0b6db4 100755
--- a/jeecg-module-dry/jeecg-module-dry-api/src/main/java/org/jeecg/modules/dry/entity/DryOrder.java
+++ b/jeecg-module-dry/jeecg-module-dry-api/src/main/java/org/jeecg/modules/dry/entity/DryOrder.java
@@ -62,6 +62,10 @@
 	@Excel(name = "鐩爣鍚按鐜�", width = 15)
     @ApiModelProperty(value = "鐩爣鍚按鐜�")
     private Double target;
+    /**鏈�缁堝惈姘寸巼*/
+    @Excel(name = "鏈�缁堝惈姘寸巼", width = 15)
+    @ApiModelProperty(value = "鏈�缁堝惈姘寸巼")
+    private Double moisture;
 	/**鎶曟枡閲�*/
 	@Excel(name = "鎶曟枡閲�", width = 15)
     @ApiModelProperty(value = "鎶曟枡閲�")
diff --git a/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/controller/ReportController.java b/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/controller/ReportController.java
new file mode 100644
index 0000000..e59b833
--- /dev/null
+++ b/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/controller/ReportController.java
@@ -0,0 +1,481 @@
+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) {
+        //------------------------------------------------------------------------------------------------
+        //鏄惁寮�鍚郴缁熺鐞嗘ā鍧楃殑澶氱鎴锋暟鎹殧绂汇�怱AAS澶氱鎴锋ā寮忋��
+        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) {
+        //------------------------------------------------------------------------------------------------
+        //鏄惁寮�鍚郴缁熺鐞嗘ā鍧楃殑澶氱鎴锋暟鎹殧绂汇�怱AAS澶氱鎴锋ā寮忋��
+        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) {
+        //------------------------------------------------------------------------------------------------
+        //鏄惁寮�鍚郴缁熺鐞嗘ā鍧楃殑澶氱鎴锋暟鎹殧绂汇�怱AAS澶氱鎴锋ā寮忋��
+        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) {
+        //------------------------------------------------------------------------------------------------
+        //鏄惁寮�鍚郴缁熺鐞嗘ā鍧楃殑澶氱鎴锋暟鎹殧绂汇�怱AAS澶氱鎴锋ā寮忋��
+        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);
+    }
+
+}
diff --git a/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/service/impl/DryRealTimeDataServiceImpl.java b/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/service/impl/DryRealTimeDataServiceImpl.java
index 648ddcc..167f90d 100755
--- a/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/service/impl/DryRealTimeDataServiceImpl.java
+++ b/jeecg-module-dry/jeecg-module-dry-biz/src/main/java/org/jeecg/modules/dry/service/impl/DryRealTimeDataServiceImpl.java
@@ -541,15 +541,30 @@
      * @param orderVo
      */
     private void saveOrderTrendVo(DryOrderTrendVo trendVo, DryOrderVo orderVo) {
+
         //鍒ゆ柇 瀹炴椂鍚按鐜� 鎴� 瀹炴椂閲嶉噺鏈夋病鏈夊彉鍖栵紝鏈夊彉鍖栧垯鏇存柊
         if (orderVo.getTrendVo() == null && trendVo != null && trendVo.getWeight() > 0
                 || orderVo.getTrendVo() != null && trendVo.getWeight() < orderVo.getTrendVo().getWeight()
         ) {
+
             DryOrder byId = dryOrderService.getById(orderVo.getId());
+
+
             // 灏嗘渶鏂扮粨鏋滄洿鏂板埌宸ュ崟
             if (byId != null) {
                 BeanUtil.copyProperties(orderVo, byId);
                 byId.setTemps(JSONObject.toJSONString(orderVo.getBellowsTemp()));
+
+                // 鏇存柊宸ュ崟鐘舵��
+                if(orderVo.getOrderStatus()!=null && byId.getOrderStatus()!=null && orderVo.getOrderStatus() > byId.getOrderStatus()){
+                    byId.setOrderStatus(orderVo.getOrderStatus());
+                }
+                // 宸ュ崟鏈畬鎴愭洿鏂板惈姘寸巼 TODO 楠岃瘉
+//                if(byId.getOrderStatus()!=null && byId.getOrderStatus().intValue()!=4 ){
+//
+//                }
+                byId.setMoisture(trendVo.getMoisture());
+
                 dryOrderService.updateById(byId);
             }
             // 淇濆瓨鍚按鐜囧彉鍖�

--
Gitblit v1.9.3