From dc9c6c612cde7b938c6851383b9da99abab025a4 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 21 五月 2026 15:02:23 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New_pro' into dev_New_pro
---
src/main/java/com/ruoyi/home/controller/HomeController.java | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 429 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/ruoyi/home/controller/HomeController.java b/src/main/java/com/ruoyi/home/controller/HomeController.java
index 8ef87a5..9bd23f6 100644
--- a/src/main/java/com/ruoyi/home/controller/HomeController.java
+++ b/src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -1,6 +1,10 @@
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;
@@ -9,17 +13,31 @@
import com.ruoyi.home.annotation.DefaultType;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.service.HomeService;
-import io.swagger.v3.oas.annotations.Operation;
+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
@@ -32,12 +50,23 @@
public class HomeController extends BaseController {
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)
@Operation(summary = "寰呭姙浜嬮」")
- public R todos(ApproveProcess req) throws ParseException {
+ public R todos() throws ParseException {
List<ApproveProcess> approveProcessList = homeService.todos();
return R.ok(approveProcessList);
}
@@ -109,7 +138,7 @@
@GetMapping("/business")
@Log(title = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁", businessType = BusinessType.OTHER)
@Operation(summary = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁")
- public R business(HomeBusinessDto req) {
+ public R business() {
HomeBusinessDto homeBusinessDto = homeService.business();
return R.ok(homeBusinessDto);
}
@@ -117,7 +146,7 @@
@GetMapping("/analysisCustomerContractAmounts")
@Log(title = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽", businessType = BusinessType.OTHER)
@Operation(summary = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽")
- public R analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
+ public R analysisCustomerContractAmounts() {
AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
return R.ok(analysisCustomerContractAmounts);
}
@@ -179,6 +208,146 @@
}
/********************************************************璐ㄩ噺绫�*****************************************************/
+ @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){
@@ -235,7 +404,7 @@
@GetMapping("/qualityStatistics")
@Log(title = "璐ㄩ噺鍒嗘瀽", businessType = BusinessType.OTHER)
@Operation(summary = "璐ㄩ噺鍒嗘瀽")
- public R qualityStatistics(QualityStatisticsDto req) {
+ public R qualityStatistics() {
QualityStatisticsDto qualityStatisticsDto = homeService.qualityStatistics();
return R.ok(qualityStatisticsDto);
}
@@ -286,7 +455,7 @@
@GetMapping("/statisticsReceivablePayable")
@Log(title = "搴旀敹搴斾粯缁熻", businessType = BusinessType.OTHER)
@Operation(summary = "搴旀敹搴斾粯缁熻")
- public R statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
+ public R statisticsReceivablePayable(@DefaultType Integer type ) {
StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
return R.ok(statisticsReceivablePayable);
}
@@ -321,4 +490,258 @@
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