From 0d7d874912d0147376826b55667a1deb6547ed91 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 21 五月 2026 15:25:27 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' into dev_宁夏_英泽防锈

---
 src/main/java/com/ruoyi/home/controller/HomeController.java |  892 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 657 insertions(+), 235 deletions(-)

diff --git a/src/main/java/com/ruoyi/home/controller/HomeController.java b/src/main/java/com/ruoyi/home/controller/HomeController.java
index 7cf3f95..9bd23f6 100644
--- a/src/main/java/com/ruoyi/home/controller/HomeController.java
+++ b/src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -1,325 +1,747 @@
 package com.ruoyi.home.controller;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.device.mapper.DeviceLedgerMapper;
+import com.ruoyi.device.mapper.DeviceRepairMapper;
+import com.ruoyi.device.pojo.DeviceRepair;
+import com.ruoyi.dto.MapDto;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.home.annotation.DefaultType;
 import com.ruoyi.home.dto.*;
 import com.ruoyi.home.service.HomeService;
-import com.ruoyi.dto.MapDto;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
+import com.ruoyi.production.mapper.ProductionOrderMapper;
+import com.ruoyi.production.mapper.ProductionProductOutputMapper;
+import com.ruoyi.production.pojo.ProductionOrder;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.AllArgsConstructor;
 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 java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * @author :yys
  * @date : 2025/7/25 9:15
  */
 @RestController
-@Api(tags = "棣栭〉缁熻")
+@Tag(name = "棣栭〉缁熻")
 @RequestMapping("/home")
+@AllArgsConstructor
 public class HomeController extends BaseController {
 
-    @Autowired
-    private HomeService homeService;
+    private final HomeService homeService;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionProductOutputMapper productionProductOutputMapper;
+    private final DeviceLedgerMapper deviceLedgerMapper;
+    private final DeviceRepairMapper deviceRepairMapper;
+
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final Integer ORDER_STATUS_WAIT = 1;
+    private static final Integer ORDER_STATUS_RUNNING = 2;
+    private static final Integer ORDER_STATUS_COMPLETED = 3;
+    private static final Integer ORDER_STATUS_PAUSED = 4;
 
     /********************************************************鍩虹绫�*****************************************************/
     @GetMapping("/todos")
     @Log(title = "寰呭姙浜嬮」", businessType = BusinessType.OTHER)
-    @ApiOperation("寰呭姙浜嬮」")
-    public AjaxResult todos(ApproveProcess req) throws ParseException {
+    @Operation(summary = "寰呭姙浜嬮」")
+    public R todos() throws ParseException {
         List<ApproveProcess> approveProcessList = homeService.todos();
-        return AjaxResult.success(approveProcessList);
+        return R.ok(approveProcessList);
     }
 
     @GetMapping("/approveAndDeviceTodos")
-    @ApiOperation("瀹℃壒鍗忓悓锛岃澶囨姤淇緟鍔炰簨椤�")
-    public AjaxResult approveAndDeviceTodos(){
+    @Operation(summary = "瀹℃壒鍗忓悓锛岃澶囨姤淇緟鍔炰簨椤�")
+    public R approveAndDeviceTodos(){
         Map<String, Object> map = homeService.approveAndDeviceTodos();
-        return AjaxResult.success(map);
+        return R.ok(map);
     }
 
     @GetMapping("/noticesCount")
-    @ApiOperation("鏈繃鏈熺殑鍏憡鏁伴噺")
-    public AjaxResult noticesCount(){
+    @Operation(summary = "鏈繃鏈熺殑鍏憡鏁伴噺")
+    public R noticesCount(){
         Long count = homeService.noticesCount();
-        return AjaxResult.success(count);
+        return R.ok(count);
     }
 
     @GetMapping("/deptStaffDistribution")
-    @ApiOperation("鍚勯儴闂ㄤ汉鍛樺垎甯�")
-    public AjaxResult deptStaffDistribution() {
+    @Operation(summary = "鍚勯儴闂ㄤ汉鍛樺垎甯�")
+    public R deptStaffDistribution() {
         DeptStaffDistributionDto dto = homeService.deptStaffDistribution();
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/summaryStatistics")
-    @ApiOperation("鍛樺伐-瀹㈡埛-渚涘簲鍟嗘�绘暟")
-    public AjaxResult summaryStatistics() {
+    @Operation(summary = "鍛樺伐-瀹㈡埛-渚涘簲鍟嗘�绘暟")
+    public R summaryStatistics() {
         HomeSummaryDto homeSummaryDto = homeService.summaryStatistics();
-        return AjaxResult.success(homeSummaryDto);
-    }
-
-    @GetMapping("/supplierPurchaseRanking")
-    @ApiOperation("渚涘簲鍟嗛噰璐帓鍚�")
-    public AjaxResult supplierPurchaseRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
-        List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/customerRevenueAnalysis")
-    @ApiOperation("瀹㈡埛钀ユ敹璐$尞鏁板�煎垎鏋�")
-    public AjaxResult customerRevenueAnalysis(@RequestParam("customerId") Long customerId, @RequestParam(value = "type", defaultValue = "1") Integer type) {
-        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
-        return AjaxResult.success(dto);
-    }
-
-    @GetMapping("/productCategoryDistribution")
-    @ApiOperation("浜у搧澶х被鍒嗗竷")
-    public AjaxResult productCategoryDistribution() {
-        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
-        return AjaxResult.success(dto);
-    }
-
-    @GetMapping("/customerContributionRanking")
-    @ApiOperation("瀹㈡埛閲戦璐$尞鎺掑悕")
-    public AjaxResult customerContributionRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
-        List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/productSalesAnalysis")
-    @ApiOperation("鍚勪骇鍝侀攢鍞噾棰濆垎鏋�")
-    public AjaxResult productSalesAnalysis() {
-        List<MapDto> list = homeService.productSalesAnalysis();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/rawMaterialPurchaseAmountRatio")
-    @ApiOperation("鍘熸潗鏂欓噰璐噾棰濆崰姣�")
-    public AjaxResult rawMaterialPurchaseAmountRatio(){
-        List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/salesPurchaseStorageProductCount")
-    @ApiOperation("閿�鍞�-閲囪喘-鍌ㄥ瓨浜у搧鏁�")
-    public AjaxResult salesPurchaseStorageProductCount(){
-        List<MapDto> list = homeService.salesPurchaseStorageProductCount();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/productInOutAnalysis")
-    @ApiOperation("浜у搧鍑哄叆搴撳垎鏋�")
-    public AjaxResult productInOutAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
-        return AjaxResult.success(result);
-    }
-
-    @GetMapping("/productTurnoverDays")
-    @ApiOperation("浜у搧鍛ㄨ浆澶╂暟")
-    public AjaxResult productTurnoverDays(){
-        List<MapDto> list = homeService.productTurnoverDays();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/incomeExpenseAnalysis")
-    @ApiOperation("鏀敹瀵规瘮鍒嗘瀽")
-    public AjaxResult incomeExpenseAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
-        List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
-        return AjaxResult.success(result);
-    }
-
-    @GetMapping("/profitTrendAnalysis")
-    @ApiOperation("鍒╂鼎瓒嬪娍鍒嗘瀽")
-    public AjaxResult profitTrendAnalysis(){
-        List<MapDto> list = homeService.profitTrendAnalysis();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/expenseCompositionAnalysis")
-    @ApiOperation("鏋勬垚鍒嗘瀽")
-    public AjaxResult expenseCompositionAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
-        List<MapDto> list = homeService.expenseCompositionAnalysis(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/monthlyIncome")
-    @ApiOperation("鏈堝害鏀跺叆")
-    public AjaxResult monthlyIncome(){
-        MonthlyIncomeDto dto = homeService.monthlyIncome();
-        return AjaxResult.success(dto);
-    }
-
-   @GetMapping("/monthlyExpenditure")
-   @ApiOperation("鏈堝害鏀嚭")
-   public AjaxResult monthlyExpenditure(){
-        MonthlyExpenditureDto dto = homeService.monthlyExpenditure();
-        return AjaxResult.success(dto);
-   }
-   
-
-    @GetMapping("/inputOutputAnalysis")
-    @ApiOperation("鎶曞叆浜у嚭鍒嗘瀽")
-    public AjaxResult inputOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
-      List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/processOutputAnalysis")
-    @ApiOperation("宸ュ簭浜у嚭鍒嗘瀽") 
-    public AjaxResult processOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        List<MapDto> list = homeService.processOutputAnalysis(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/workOrderEfficiencyAnalysis")
-    @ApiOperation("宸ュ崟鎵ц鏁堢巼鍒嗘瀽")
-    public AjaxResult workOrderEfficiencyAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/productionAccountingAnalysis")
-    @ApiOperation("鐢熶骇鏍哥畻鍒嗘瀽")
-    public AjaxResult productionAccountingAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        List<ProductionAccountingDto> list   = homeService.productionAccountingAnalysis(type);
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/orderCount")
-    @ApiOperation("璁㈠崟鏁�")
-    public AjaxResult orderCount(){
-        return AjaxResult.success(homeService.orderCount());
-    }
-
-    @GetMapping("/rawMaterialDetection")
-    @ApiOperation("鍘熸潗鏂欐娴�")
-    public AjaxResult rawMaterialDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        return AjaxResult.success(homeService.rawMaterialDetection(type));
-    }
-
-    @GetMapping("/processDetection")
-    @ApiOperation("杩囩▼妫�娴�")
-    public AjaxResult processDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        return AjaxResult.success(homeService.processDetection(type));
-    }
-
-    @GetMapping("/factoryDetection")
-    @ApiOperation("鎴愬搧鍑哄巶妫�娴�")
-    public AjaxResult factoryDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
-        return AjaxResult.success(homeService.factoryDetection(type));
-    }
-
-    @GetMapping("/qualityInspectionCount")
-    @ApiOperation("璐ㄩ噺妫�楠屾暟閲�")
-    public AjaxResult qualityInspectionCount(){
-        QualityInspectionCountDto qualityInspectionCountDto = homeService.qualityInspectionCount();
-        return AjaxResult.success(qualityInspectionCountDto);
-    }
-
-    @GetMapping("/nonComplianceWarning")
-    @ApiOperation("涓嶅悎鏍奸璀�")
-    public AjaxResult nonComplianceWarning(){
-        NonComplianceWarningDto nonComplianceWarningDto = homeService.nonComplianceWarning();
-        return AjaxResult.success(nonComplianceWarningDto);
-    }
-
-    @GetMapping("/completedInspectionCount")
-    @ApiOperation("瀹屾垚妫�楠屾暟")
-    public AjaxResult completedInspectionCount(){
-        List<CompletedInspectionCountDto> list = homeService.completedInspectionCount();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/unqualifiedProductRanking")
-    @ApiOperation("涓嶅悎鏍间骇鍝佹帓鍚�")
-    public AjaxResult unqualifiedProductRanking(){
-        List<UnqualifiedProductRankDto> list = homeService.unqualifiedProductRanking();
-        return AjaxResult.success(list);
-    }
-
-    @GetMapping("/unqualifiedProductProcessingAnalysis")
-    @ApiOperation("涓嶅悎鏍兼鍝佸鐞嗗垎鏋�")
-    public AjaxResult unqualifiedProductProcessingAnalysis(){
-        List<MapDto> list = homeService.unqualifiedProductProcessingAnalysis();
-        return AjaxResult.success(list);
+        return R.ok(homeSummaryDto);
     }
 
     /********************************************************钀ラ攢閲囪喘绫�**************************************************/
-    @GetMapping("/business")
-    @Log(title = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁", businessType = BusinessType.OTHER)
-    @ApiOperation("閿�鍞�-閲囪喘-搴撳瓨鏁版嵁")
-    public AjaxResult business(HomeBusinessDto req) {
-        HomeBusinessDto homeBusinessDto = homeService.business();
-        return AjaxResult.success(homeBusinessDto);
+    @GetMapping("/supplierPurchaseRanking")
+    @Operation(summary = "渚涘簲鍟嗛噰璐帓鍚�")
+    public R supplierPurchaseRanking(@DefaultType Integer type) {
+        List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
+        return R.ok(list);
     }
 
+    @GetMapping("/customerRevenueAnalysis")
+    @Operation(summary = "瀹㈡埛钀ユ敹璐$尞鏁板�煎垎鏋�")
+    public R customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
+        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
+        return R.ok(dto);
+    }
+
+    @GetMapping("/customerContributionRanking")
+    @Operation(summary = "瀹㈡埛閲戦璐$尞鎺掑悕")
+    public R customerContributionRanking(@DefaultType Integer type) {
+        List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/productSalesAnalysis")
+    @Operation(summary = "鍚勪骇鍝侀攢鍞噾棰濆垎鏋�")
+    public R productSalesAnalysis() {
+        List<MapDto> list = homeService.productSalesAnalysis();
+        return R.ok(list);
+    }
+
+    @GetMapping("/rawMaterialPurchaseAmountRatio")
+    @Operation(summary = "鍘熸潗鏂欓噰璐噾棰濆崰姣�")
+    public R rawMaterialPurchaseAmountRatio(){
+        List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio();
+        return R.ok(list);
+    }
+
+    @GetMapping("/business")
+    @Log(title = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁", businessType = BusinessType.OTHER)
+    @Operation(summary = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁")
+    public R business() {
+        HomeBusinessDto homeBusinessDto = homeService.business();
+        return R.ok(homeBusinessDto);
+    }
 
     @GetMapping("/analysisCustomerContractAmounts")
     @Log(title = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽", businessType = BusinessType.OTHER)
-    @ApiOperation("瀹㈡埛鍚堝悓閲戦鍒嗘瀽")
-    public AjaxResult analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
+    @Operation(summary = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽")
+    public R analysisCustomerContractAmounts() {
         AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
-        return AjaxResult.success(analysisCustomerContractAmounts);
+        return R.ok(analysisCustomerContractAmounts);
     }
-
 
     /********************************************************鐢熶骇绫�*****************************************************/
+    @GetMapping("/inputOutputAnalysis")
+    @Operation(summary = "鎶曞叆浜у嚭鍒嗘瀽")
+    public R inputOutputAnalysis(@DefaultType Integer type){
+      List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/processOutputAnalysis")
+    @Operation(summary = "宸ュ簭浜у嚭鍒嗘瀽")
+    public R processOutputAnalysis(@DefaultType Integer type){
+        List<MapDto> list = homeService.processOutputAnalysis(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/workOrderEfficiencyAnalysis")
+    @Operation(summary = "宸ュ崟鎵ц鏁堢巼鍒嗘瀽")
+    public R workOrderEfficiencyAnalysis(@DefaultType Integer type){
+        List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/productionAccountingAnalysis")
+    @Operation(summary = "鐢熶骇鏍哥畻鍒嗘瀽")
+    public R productionAccountingAnalysis(@DefaultType Integer type){
+        List<ProductionAccountingDto> list   = homeService.productionAccountingAnalysis(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/orderCount")
+    @Operation(summary = "璁㈠崟鏁�")
+    public R orderCount(){
+        return R.ok(homeService.orderCount());
+    }
+
     @GetMapping("/progressStatistics")
-    @ApiOperation("鍚勭敓浜ц鍗曠殑瀹屾垚杩涘害缁熻")
-    public AjaxResult progressStatistics(){
+    @Operation(summary = "鍚勭敓浜ц鍗曠殑瀹屾垚杩涘害缁熻")
+    public R progressStatistics(){
         ProductionProgressDto productionProgressDto = homeService.productionProgress();
-        return AjaxResult.success(productionProgressDto);
+        return R.ok(productionProgressDto);
     }
+
     @GetMapping("/workInProcessTurnover")
-    @ApiOperation("鍦ㄥ埗鍝佸懆杞儏鍐�")
-    public AjaxResult workInProcessTurnover(){
+    @Operation(summary = "鍦ㄥ埗鍝佸懆杞儏鍐�")
+    public R workInProcessTurnover(){
         ProductionTurnoverDto productionTurnoverDto = homeService.workInProcessTurnover();
-        return AjaxResult.success(productionTurnoverDto);
+        return R.ok(productionTurnoverDto);
     }
 
+    @GetMapping("/processDataProductionStatistics")
+    @Operation(summary = "宸ュ簭鏁版嵁鐢熶骇缁熻鏁版嵁")
+    public R processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
+        List<processDataProductionStatisticsDto> list = homeService.processDataProductionStatistics(type, processIds);
+        return R.ok(list);
+    }
 
-    
     /********************************************************璐ㄩ噺绫�*****************************************************/
+    @GetMapping("/productionOverview")
+    @Operation(summary = "Production Overview")
+    public R productionOverview() {
+        LocalDate today = LocalDate.now();
+        Map<String, BigDecimal> totalStats = loadOutputStats(LocalDate.of(2000, 1, 1), today.plusDays(1));
+        BigDecimal totalOutput = totalStats.get("quantity");
+        BigDecimal totalScrap = totalStats.get("scrapQty");
+        BigDecimal yieldRate = calcRate(totalOutput, totalOutput.add(totalScrap));
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("totalOutput", scale(totalOutput));
+        result.put("totalScrap", scale(totalScrap));
+        result.put("yieldRate", scale(yieldRate));
+        return R.ok(result);
+    }
+
+    @GetMapping("/productionRealtimeBoard")
+    @Operation(summary = "Production Realtime Board")
+    public R productionRealtimeBoard() {
+        LocalDate today = LocalDate.now();
+        LocalDate yesterday = today.minusDays(1);
+
+        BigDecimal todayDeviceOee = calcDeviceOee(today);
+        BigDecimal yesterdayDeviceOee = calcDeviceOee(yesterday);
+
+        BigDecimal todayOrderAchievementRate = calcOrderAchievementRate(today);
+        BigDecimal yesterdayOrderAchievementRate = calcOrderAchievementRate(yesterday);
+
+        BigDecimal todayDefectRate = calcDefectRate(today);
+        BigDecimal yesterdayDefectRate = calcDefectRate(yesterday);
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("deviceOee", buildRealtimeMetric(todayDeviceOee, todayDeviceOee.subtract(yesterdayDeviceOee)));
+        result.put("orderAchievementRate", buildRealtimeMetric(todayOrderAchievementRate, todayOrderAchievementRate.subtract(yesterdayOrderAchievementRate)));
+        result.put("defectRate", buildRealtimeMetric(todayDefectRate, todayDefectRate.subtract(yesterdayDefectRate)));
+        return R.ok(result);
+    }
+
+    @GetMapping("/productionOrderProgress")
+    @Operation(summary = "Production Order Progress")
+    public R productionOrderProgress(@RequestParam(defaultValue = "all") String tab,
+                                     @RequestParam(required = false) String status,
+                                     @RequestParam(required = false) String bizDate,
+                                     @RequestParam(defaultValue = "1") Long pageNum,
+                                     @RequestParam(defaultValue = "10") Long pageSize) {
+        LocalDate queryDate = parseDateOrNull(bizDate);
+        if (!isBlank(bizDate) && queryDate == null) {
+            return R.fail("bizDate鏍煎紡閿欒锛岃浣跨敤yyyy-MM-dd");
+        }
+        Integer statusFromParam = parseOrderStatus(status);
+        if (!isBlank(status) && statusFromParam == null && !"all".equalsIgnoreCase(status.trim())) {
+            return R.fail("status鍙傛暟涓嶅悎娉曪紝鍙�夊�硷細all/waiting/inProgress/completed/paused 鎴� 1/2/3/4");
+        }
+        Integer queryStatus = resolveOrderStatus(status, tab);
+
+        long safePageNum = pageNum == null || pageNum < 1 ? 1 : pageNum;
+        long safePageSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50);
+        long offset = (safePageNum - 1) * safePageSize;
+        LocalDateTime startTime = queryDate == null ? null : queryDate.atStartOfDay();
+        LocalDateTime endTime = queryDate == null ? null : queryDate.plusDays(1).atStartOfDay();
+
+        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeOrderProgressPage(queryStatus, offset, safePageSize, startTime, endTime);
+        List<Map<String, Object>> records = new ArrayList<>();
+        if (rawRows != null) {
+            for (Map<String, Object> rawRow : rawRows) {
+                records.add(buildOrderProgressRow(rawRow));
+            }
+        }
+
+        long waitingCount = 0L;
+        long inProgressCount = 0L;
+        long completedCount = 0L;
+        long pausedCount = 0L;
+        List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus(startTime, endTime);
+        if (statusCountRows != null) {
+            for (Map<String, Object> countRow : statusCountRows) {
+                Integer statusKey = toInteger(countRow.get("status"));
+                long cnt = toLong(countRow.get("cnt"));
+                if (Objects.equals(statusKey, ORDER_STATUS_WAIT)) {
+                    waitingCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_RUNNING)) {
+                    inProgressCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_COMPLETED)) {
+                    completedCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_PAUSED)) {
+                    pausedCount = cnt;
+                }
+            }
+        }
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("tab", mapOrderTab(queryStatus));
+        result.put("status", mapOrderStatus(queryStatus));
+        result.put("bizDate", queryDate == null ? null : queryDate.format(DATE_FORMATTER));
+        result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(queryStatus, startTime, endTime)));
+        result.put("pageNum", safePageNum);
+        result.put("pageSize", safePageSize);
+        result.put("waitingCount", waitingCount);
+        result.put("inProgressCount", inProgressCount);
+        result.put("completedCount", completedCount);
+        result.put("pausedCount", pausedCount);
+        result.put("records", records);
+        return R.ok(result);
+    }
+
+    @GetMapping("/todayProductionPlan")
+    @Operation(summary = "Today Production Plan")
+    public R todayProductionPlan(@RequestParam(defaultValue = "4") Long limit,
+                                 @RequestParam(required = false) String planDate) {
+        LocalDate queryDate = parseDateOrNull(planDate);
+        if (!isBlank(planDate) && queryDate == null) {
+            return R.fail("planDate鏍煎紡閿欒锛岃浣跨敤yyyy-MM-dd");
+        }
+
+        long safeLimit = limit == null || limit < 1 ? 4 : Math.min(limit, 20);
+        LocalDateTime planStart = queryDate == null ? null : queryDate.atStartOfDay();
+        LocalDateTime planEnd = queryDate == null ? null : queryDate.plusDays(1).atStartOfDay();
+        List<Map<String, Object>> records = new ArrayList<>();
+        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeTodayProductionPlan(safeLimit, planStart, planEnd);
+        if (rawRows != null) {
+            for (Map<String, Object> rawRow : rawRows) {
+                Map<String, Object> row = new LinkedHashMap<>();
+                Integer rowStatus = toInteger(rawRow.get("status"));
+                row.put("orderNo", rawRow.get("orderNo"));
+                row.put("productName", rawRow.get("productName"));
+                row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
+                row.put("dueDate", rawRow.get("dueDate"));
+                row.put("status", rowStatus);
+                row.put("statusLabel", mapOrderStatusLabel(rowStatus));
+                records.add(row);
+            }
+        }
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("planDate", queryDate == null ? null : queryDate.format(DATE_FORMATTER));
+        result.put("total", toLong(productionOrderMapper.countHomeTodayProductionPlan(planStart, planEnd)));
+        result.put("records", records);
+        return R.ok(result);
+    }
+
+    @GetMapping("/rawMaterialDetection")
+    @Operation(summary = "鍘熸潗鏂欐娴�")
+    public R rawMaterialDetection(@DefaultType Integer type){
+        return R.ok(homeService.rawMaterialDetection(type));
+    }
+
+    @GetMapping("/processDetection")
+    @Operation(summary = "杩囩▼妫�娴�")
+    public R processDetection(@DefaultType Integer type){
+        return R.ok(homeService.processDetection(type));
+    }
+
+    @GetMapping("/factoryDetection")
+    @Operation(summary = "鎴愬搧鍑哄巶妫�娴�")
+    public R factoryDetection(@DefaultType Integer type){
+        return R.ok(homeService.factoryDetection(type));
+    }
+
+    @GetMapping("/qualityInspectionCount")
+    @Operation(summary = "璐ㄩ噺妫�楠屾暟閲�")
+    public R qualityInspectionCount(){
+        QualityInspectionCountDto qualityInspectionCountDto = homeService.qualityInspectionCount();
+        return R.ok(qualityInspectionCountDto);
+    }
+
+    @GetMapping("/nonComplianceWarning")
+    @Operation(summary = "涓嶅悎鏍奸璀�")
+    public R nonComplianceWarning(){
+        NonComplianceWarningDto nonComplianceWarningDto = homeService.nonComplianceWarning();
+        return R.ok(nonComplianceWarningDto);
+    }
+
+    @GetMapping("/completedInspectionCount")
+    @Operation(summary = "瀹屾垚妫�楠屾暟")
+    public R completedInspectionCount(){
+        List<CompletedInspectionCountDto> list = homeService.completedInspectionCount();
+        return R.ok(list);
+    }
+
+    @GetMapping("/unqualifiedProductRanking")
+    @Operation(summary = "涓嶅悎鏍间骇鍝佹帓鍚�")
+    public R unqualifiedProductRanking(){
+        List<UnqualifiedProductRankDto> list = homeService.unqualifiedProductRanking();
+        return R.ok(list);
+    }
+
+    @GetMapping("/unqualifiedProductProcessingAnalysis")
+    @Operation(summary = "涓嶅悎鏍兼鍝佸鐞嗗垎鏋�")
+    public R unqualifiedProductProcessingAnalysis(){
+        List<MapDto> list = homeService.unqualifiedProductProcessingAnalysis();
+        return R.ok(list);
+    }
+
     @GetMapping("/qualityStatistics")
     @Log(title = "璐ㄩ噺鍒嗘瀽", businessType = BusinessType.OTHER)
-    @ApiOperation("璐ㄩ噺鍒嗘瀽")
-    public AjaxResult qualityStatistics(QualityStatisticsDto req) {
+    @Operation(summary = "璐ㄩ噺鍒嗘瀽")
+    public R qualityStatistics() {
         QualityStatisticsDto qualityStatisticsDto = homeService.qualityStatistics();
-        return AjaxResult.success(qualityStatisticsDto);
+        return R.ok(qualityStatisticsDto);
     }
 
+    @GetMapping("/qualityInspectionStatistics")
+    @Operation(summary = "璐ㄩ噺缁熻")
+    public R qualityInspectionStatistics(@DefaultType Integer type) {
+       QualityStatisticsDto  dto = homeService.qualityInspectionStatistics(type);
+        return R.ok(dto);
+    }
 
     /********************************************************璐㈠姟绫�*****************************************************/
-    @GetMapping("/statisticsReceivablePayable")
-    @Log(title = "搴旀敹搴斾粯缁熻", businessType = BusinessType.OTHER)
-    @ApiOperation("搴旀敹搴斾粯缁熻")
-    public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @RequestParam(value = "type", defaultValue = "1") Integer type ) {
-        StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
-        return AjaxResult.success(statisticsReceivablePayable);
+    @GetMapping("/incomeExpenseAnalysis")
+    @Operation(summary = "鏀敹瀵规瘮鍒嗘瀽")
+    public R incomeExpenseAnalysis(@DefaultType Integer type) {
+        List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
+        return R.ok(result);
     }
 
+    @GetMapping("/profitTrendAnalysis")
+    @Operation(summary = "鍒╂鼎瓒嬪娍鍒嗘瀽")
+    public R profitTrendAnalysis(){
+        List<MapDto> list = homeService.profitTrendAnalysis();
+        return R.ok(list);
+    }
+
+    @GetMapping("/expenseCompositionAnalysis")
+    @Operation(summary = "鏋勬垚鍒嗘瀽")
+    public R expenseCompositionAnalysis(@DefaultType Integer type) {
+        List<MapDto> list = homeService.expenseCompositionAnalysis(type);
+        return R.ok(list);
+    }
+
+    @GetMapping("/monthlyIncome")
+    @Operation(summary = "鏈堝害鏀跺叆")
+    public R monthlyIncome(){
+        MonthlyIncomeDto dto = homeService.monthlyIncome();
+        return R.ok(dto);
+    }
+
+    @GetMapping("/monthlyExpenditure")
+    @Operation(summary = "鏈堝害鏀嚭")
+    public R monthlyExpenditure(){
+        MonthlyExpenditureDto dto = homeService.monthlyExpenditure();
+        return R.ok(dto);
+    }
+
+    @GetMapping("/statisticsReceivablePayable")
+    @Log(title = "搴旀敹搴斾粯缁熻", businessType = BusinessType.OTHER)
+    @Operation(summary = "搴旀敹搴斾粯缁熻")
+    public R statisticsReceivablePayable(@DefaultType Integer type ) {
+        StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
+        return R.ok(statisticsReceivablePayable);
+    }
 
     /********************************************************浠撳偍绫�*****************************************************/
 
+    @GetMapping("/productCategoryDistribution")
+    @Operation(summary = "浜у搧澶х被鍒嗗竷")
+    public R productCategoryDistribution() {
+        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
+        return R.ok(dto);
+    }
 
+    @GetMapping("/salesPurchaseStorageProductCount")
+    @Operation(summary = "閿�鍞�-閲囪喘-鍌ㄥ瓨浜у搧鏁�")
+    public R salesPurchaseStorageProductCount(){
+        List<MapDto> list = homeService.salesPurchaseStorageProductCount();
+        return R.ok(list);
+    }
 
+    @GetMapping("/productInOutAnalysis")
+    @Operation(summary = "浜у搧鍑哄叆搴撳垎鏋�")
+    public R productInOutAnalysis(@DefaultType Integer type){
+        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
+        return R.ok(result);
+    }
 
+    @GetMapping("/productTurnoverDays")
+    @Operation(summary = "浜у搧鍛ㄨ浆澶╂暟")
+    public R productTurnoverDays(){
+        List<MapDto> list = homeService.productTurnoverDays();
+        return R.ok(list);
+    }
 
+    private Map<String, Object> buildOrderProgressRow(Map<String, Object> rawRow) {
+        Map<String, Object> row = new LinkedHashMap<>();
+        Integer rowStatus = toInteger(rawRow.get("status"));
+        row.put("orderNo", rawRow.get("orderNo"));
+        row.put("productName", rawRow.get("productName"));
+        row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
+        row.put("completedQuantity", scale(toBigDecimal(rawRow.get("completedQuantity"))));
+        row.put("completionRate", scale(toBigDecimal(rawRow.get("completionRate"))));
+        row.put("dueDate", rawRow.get("dueDate"));
+        row.put("status", rowStatus);
+        row.put("statusLabel", mapOrderStatusLabel(rowStatus));
+        return row;
+    }
 
+    private Integer resolveOrderStatus(String status, String tab) {
+        if (!isBlank(status)) {
+            return parseOrderStatus(status);
+        }
+        return parseOrderStatus(tab);
+    }
 
+    private Integer parseOrderStatus(String rawStatus) {
+        if (isBlank(rawStatus)) {
+            return null;
+        }
+        String normalized = rawStatus.trim().toLowerCase();
+        if ("all".equals(normalized)) {
+            return null;
+        }
+        if ("1".equals(normalized) || "waiting".equals(normalized) || "wait".equals(normalized)) {
+            return ORDER_STATUS_WAIT;
+        }
+        if ("2".equals(normalized) || "inprogress".equals(normalized) || "running".equals(normalized)) {
+            return ORDER_STATUS_RUNNING;
+        }
+        if ("3".equals(normalized) || "completed".equals(normalized)) {
+            return ORDER_STATUS_COMPLETED;
+        }
+        if ("4".equals(normalized) || "paused".equals(normalized)) {
+            return ORDER_STATUS_PAUSED;
+        }
+        return null;
+    }
 
+    private String mapOrderTab(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "inProgress";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "completed";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "paused";
+        }
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "waiting";
+        }
+        return "all";
+    }
 
+    private String mapOrderStatus(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "waiting";
+        }
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "inProgress";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "completed";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "paused";
+        }
+        return "all";
+    }
 
+    private String mapOrderStatusLabel(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "寰呭紑濮�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "杩涜涓�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "宸插畬鎴�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "宸叉殏鍋�";
+        }
+        return "鏈煡";
+    }
+
+    private Map<String, BigDecimal> loadOutputStats(LocalDate startDate, LocalDate endDateExclusive) {
+        String start = startDate.atStartOfDay().format(DATE_TIME_FORMATTER);
+        String end = endDateExclusive.atStartOfDay().format(DATE_TIME_FORMATTER);
+
+        BigDecimal quantity = BigDecimal.ZERO;
+        BigDecimal scrapQty = BigDecimal.ZERO;
+        List<Map<String, Object>> rows = productionProductOutputMapper.selectDailyOutputStats(start, end);
+        if (rows != null) {
+            for (Map<String, Object> row : rows) {
+                quantity = quantity.add(toBigDecimal(row.get("quantity")));
+                scrapQty = scrapQty.add(toBigDecimal(row.get("scrapQty")));
+            }
+        }
+
+        Map<String, BigDecimal> stats = new LinkedHashMap<>();
+        stats.put("quantity", quantity);
+        stats.put("scrapQty", scrapQty);
+        return stats;
+    }
+
+    private BigDecimal calcDeviceOee(LocalDate day) {
+        long totalDeviceCount = deviceLedgerMapper.selectCount(new LambdaQueryWrapper<>());
+        if (totalDeviceCount <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        Date start = Date.from(day.atStartOfDay(ZoneId.systemDefault()).toInstant());
+        Date end = Date.from(day.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
+
+        List<DeviceRepair> repairList = deviceRepairMapper.selectList(new LambdaQueryWrapper<DeviceRepair>()
+                .select(DeviceRepair::getDeviceLedgerId)
+                .ge(DeviceRepair::getRepairTime, start)
+                .lt(DeviceRepair::getRepairTime, end)
+                .in(DeviceRepair::getStatus, 0, 3));
+
+        long repairingDeviceCount = repairList == null ? 0 : repairList.stream()
+                .map(DeviceRepair::getDeviceLedgerId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .count();
+
+        long availableDeviceCount = Math.max(totalDeviceCount - repairingDeviceCount, 0);
+        return new BigDecimal(availableDeviceCount)
+                .multiply(new BigDecimal("100"))
+                .divide(new BigDecimal(totalDeviceCount), 2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal calcOrderAchievementRate(LocalDate day) {
+        List<ProductionOrder> orderList = productionOrderMapper.selectList(new LambdaQueryWrapper<ProductionOrder>()
+                .select(ProductionOrder::getQuantity, ProductionOrder::getCompleteQuantity)
+                .ge(ProductionOrder::getCreateTime, day.atStartOfDay())
+                .lt(ProductionOrder::getCreateTime, day.plusDays(1).atStartOfDay())
+                .ne(ProductionOrder::getStatus, ORDER_STATUS_PAUSED));
+
+        BigDecimal totalQuantity = BigDecimal.ZERO;
+        BigDecimal totalCompleteQuantity = BigDecimal.ZERO;
+        if (orderList != null) {
+            for (ProductionOrder order : orderList) {
+                totalQuantity = totalQuantity.add(zeroIfNull(order.getQuantity()));
+                totalCompleteQuantity = totalCompleteQuantity.add(zeroIfNull(order.getCompleteQuantity()));
+            }
+        }
+        return calcRate(totalCompleteQuantity, totalQuantity);
+    }
+
+    private BigDecimal calcDefectRate(LocalDate day) {
+        Map<String, BigDecimal> stats = loadOutputStats(day, day.plusDays(1));
+        BigDecimal quantity = stats.get("quantity");
+        BigDecimal scrapQty = stats.get("scrapQty");
+        return calcRate(scrapQty, quantity.add(scrapQty));
+    }
+
+    private Map<String, Object> buildRealtimeMetric(BigDecimal value, BigDecimal change) {
+        Map<String, Object> metric = new LinkedHashMap<>();
+        metric.put("value", scale(value));
+        metric.put("compareYesterday", scale(change));
+        return metric;
+    }
+
+    private BigDecimal calcRate(BigDecimal numerator, BigDecimal denominator) {
+        if (denominator == null || denominator.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        return zeroIfNull(numerator)
+                .multiply(new BigDecimal("100"))
+                .divide(denominator, 2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal toBigDecimal(Object value) {
+        if (value == null) {
+            return BigDecimal.ZERO;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Number) {
+            return BigDecimal.valueOf(((Number) value).doubleValue());
+        }
+        try {
+            return new BigDecimal(String.valueOf(value));
+        } catch (Exception ex) {
+            return BigDecimal.ZERO;
+        }
+    }
+
+    private Integer toInteger(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        try {
+            return Integer.valueOf(String.valueOf(value));
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    private long toLong(Object value) {
+        if (value == null) {
+            return 0L;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        try {
+            return Long.parseLong(String.valueOf(value));
+        } catch (Exception ex) {
+            return 0L;
+        }
+    }
+
+    private LocalDate parseDateOrNull(String rawDate) {
+        if (isBlank(rawDate)) {
+            return null;
+        }
+        try {
+            return LocalDate.parse(rawDate.trim(), DATE_FORMATTER);
+        } catch (DateTimeParseException ex) {
+            return null;
+        }
+    }
+
+    private boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+
+    private BigDecimal zeroIfNull(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    private BigDecimal scale(BigDecimal value) {
+        return zeroIfNull(value).setScale(2, RoundingMode.HALF_UP);
+    }
 
 }

--
Gitblit v1.9.3