| | |
| | | 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); |
| | | return R.ok(homeSummaryDto); |
| | | } |
| | | |
| | | /********************************************************营销采购类**************************************************/ |
| | | @GetMapping("/supplierPurchaseRanking") |
| | | @ApiOperation("供应商采购排名") |
| | | public AjaxResult supplierPurchaseRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) { |
| | | @Operation(summary = "供应商采购排名") |
| | | public R supplierPurchaseRanking(@DefaultType Integer type) { |
| | | List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/customerRevenueAnalysis") |
| | | @ApiOperation("客户营收贡献数值分析") |
| | | public AjaxResult customerRevenueAnalysis(@RequestParam("customerId") Long customerId, @RequestParam(value = "type", defaultValue = "1") Integer type) { |
| | | @Operation(summary = "客户营收贡献数值分析") |
| | | public R customerRevenueAnalysis(Long customerId, @DefaultType Integer type) { |
| | | CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type); |
| | | return AjaxResult.success(dto); |
| | | return R.ok(dto); |
| | | } |
| | | |
| | | @GetMapping("/customerContributionRanking") |
| | | @ApiOperation("客户金额贡献排名") |
| | | public AjaxResult customerContributionRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) { |
| | | @Operation(summary = "客户金额贡献排名") |
| | | public R customerContributionRanking(@DefaultType Integer type) { |
| | | List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/productSalesAnalysis") |
| | | @ApiOperation("各产品销售金额分析") |
| | | public AjaxResult productSalesAnalysis() { |
| | | @Operation(summary = "各产品销售金额分析") |
| | | public R productSalesAnalysis() { |
| | | List<MapDto> list = homeService.productSalesAnalysis(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/rawMaterialPurchaseAmountRatio") |
| | | @ApiOperation("原材料采购金额占比") |
| | | public AjaxResult rawMaterialPurchaseAmountRatio(){ |
| | | @Operation(summary = "原材料采购金额占比") |
| | | public R rawMaterialPurchaseAmountRatio(){ |
| | | List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/business") |
| | | @Log(title = "销售-采购-库存数据", businessType = BusinessType.OTHER) |
| | | @ApiOperation("销售-采购-库存数据") |
| | | public AjaxResult business(HomeBusinessDto req) { |
| | | @Operation(summary = "销售-采购-库存数据") |
| | | public R business() { |
| | | HomeBusinessDto homeBusinessDto = homeService.business(); |
| | | return AjaxResult.success(homeBusinessDto); |
| | | 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") |
| | | @ApiOperation("投入产出分析") |
| | | public AjaxResult inputOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | @Operation(summary = "投入产出分析") |
| | | public R inputOutputAnalysis(@DefaultType Integer type){ |
| | | List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/processOutputAnalysis") |
| | | @ApiOperation("工序产出分析") |
| | | public AjaxResult processOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | @Operation(summary = "工序产出分析") |
| | | public R processOutputAnalysis(@DefaultType Integer type){ |
| | | List<MapDto> list = homeService.processOutputAnalysis(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/workOrderEfficiencyAnalysis") |
| | | @ApiOperation("工单执行效率分析") |
| | | public AjaxResult workOrderEfficiencyAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | @Operation(summary = "工单执行效率分析") |
| | | public R workOrderEfficiencyAnalysis(@DefaultType Integer type){ |
| | | List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/productionAccountingAnalysis") |
| | | @ApiOperation("生产核算分析") |
| | | public AjaxResult productionAccountingAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | @Operation(summary = "生产核算分析") |
| | | public R productionAccountingAnalysis(@DefaultType Integer type){ |
| | | List<ProductionAccountingDto> list = homeService.productionAccountingAnalysis(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/orderCount") |
| | | @ApiOperation("订单数") |
| | | public AjaxResult orderCount(){ |
| | | return AjaxResult.success(homeService.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") |
| | | @ApiOperation("原材料检测") |
| | | public AjaxResult rawMaterialDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | return AjaxResult.success(homeService.rawMaterialDetection(type)); |
| | | @Operation(summary = "原材料检测") |
| | | public R rawMaterialDetection(@DefaultType Integer type){ |
| | | return R.ok(homeService.rawMaterialDetection(type)); |
| | | } |
| | | |
| | | @GetMapping("/processDetection") |
| | | @ApiOperation("过程检测") |
| | | public AjaxResult processDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | return AjaxResult.success(homeService.processDetection(type)); |
| | | @Operation(summary = "过程检测") |
| | | public R processDetection(@DefaultType Integer type){ |
| | | return R.ok(homeService.processDetection(type)); |
| | | } |
| | | |
| | | @GetMapping("/factoryDetection") |
| | | @ApiOperation("成品出厂检测") |
| | | public AjaxResult factoryDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | return AjaxResult.success(homeService.factoryDetection(type)); |
| | | @Operation(summary = "成品出厂检测") |
| | | public R factoryDetection(@DefaultType Integer type){ |
| | | return R.ok(homeService.factoryDetection(type)); |
| | | } |
| | | |
| | | @GetMapping("/qualityInspectionCount") |
| | | @ApiOperation("质量检验数量") |
| | | public AjaxResult qualityInspectionCount(){ |
| | | @Operation(summary = "质量检验数量") |
| | | public R qualityInspectionCount(){ |
| | | QualityInspectionCountDto qualityInspectionCountDto = homeService.qualityInspectionCount(); |
| | | return AjaxResult.success(qualityInspectionCountDto); |
| | | return R.ok(qualityInspectionCountDto); |
| | | } |
| | | |
| | | @GetMapping("/nonComplianceWarning") |
| | | @ApiOperation("不合格预警") |
| | | public AjaxResult nonComplianceWarning(){ |
| | | @Operation(summary = "不合格预警") |
| | | public R nonComplianceWarning(){ |
| | | NonComplianceWarningDto nonComplianceWarningDto = homeService.nonComplianceWarning(); |
| | | return AjaxResult.success(nonComplianceWarningDto); |
| | | return R.ok(nonComplianceWarningDto); |
| | | } |
| | | |
| | | @GetMapping("/completedInspectionCount") |
| | | @ApiOperation("完成检验数") |
| | | public AjaxResult completedInspectionCount(){ |
| | | @Operation(summary = "完成检验数") |
| | | public R completedInspectionCount(){ |
| | | List<CompletedInspectionCountDto> list = homeService.completedInspectionCount(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/unqualifiedProductRanking") |
| | | @ApiOperation("不合格产品排名") |
| | | public AjaxResult unqualifiedProductRanking(){ |
| | | @Operation(summary = "不合格产品排名") |
| | | public R unqualifiedProductRanking(){ |
| | | List<UnqualifiedProductRankDto> list = homeService.unqualifiedProductRanking(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/unqualifiedProductProcessingAnalysis") |
| | | @ApiOperation("不合格检品处理分析") |
| | | public AjaxResult unqualifiedProductProcessingAnalysis(){ |
| | | @Operation(summary = "不合格检品处理分析") |
| | | public R unqualifiedProductProcessingAnalysis(){ |
| | | List<MapDto> list = homeService.unqualifiedProductProcessingAnalysis(); |
| | | return AjaxResult.success(list); |
| | | 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("/incomeExpenseAnalysis") |
| | | @ApiOperation("支收对比分析") |
| | | public AjaxResult incomeExpenseAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) { |
| | | @Operation(summary = "支收对比分析") |
| | | public R incomeExpenseAnalysis(@DefaultType Integer type) { |
| | | List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type); |
| | | return AjaxResult.success(result); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | @GetMapping("/profitTrendAnalysis") |
| | | @ApiOperation("利润趋势分析") |
| | | public AjaxResult profitTrendAnalysis(){ |
| | | @Operation(summary = "利润趋势分析") |
| | | public R profitTrendAnalysis(){ |
| | | List<MapDto> list = homeService.profitTrendAnalysis(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/expenseCompositionAnalysis") |
| | | @ApiOperation("构成分析") |
| | | public AjaxResult expenseCompositionAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) { |
| | | @Operation(summary = "构成分析") |
| | | public R expenseCompositionAnalysis(@DefaultType Integer type) { |
| | | List<MapDto> list = homeService.expenseCompositionAnalysis(type); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/monthlyIncome") |
| | | @ApiOperation("月度收入") |
| | | public AjaxResult monthlyIncome(){ |
| | | @Operation(summary = "月度收入") |
| | | public R monthlyIncome(){ |
| | | MonthlyIncomeDto dto = homeService.monthlyIncome(); |
| | | return AjaxResult.success(dto); |
| | | return R.ok(dto); |
| | | } |
| | | |
| | | @GetMapping("/monthlyExpenditure") |
| | | @ApiOperation("月度支出") |
| | | public AjaxResult monthlyExpenditure(){ |
| | | @Operation(summary = "月度支出") |
| | | public R monthlyExpenditure(){ |
| | | MonthlyExpenditureDto dto = homeService.monthlyExpenditure(); |
| | | return AjaxResult.success(dto); |
| | | return R.ok(dto); |
| | | } |
| | | |
| | | @GetMapping("/statisticsReceivablePayable") |
| | | @Log(title = "应收应付统计", businessType = BusinessType.OTHER) |
| | | @ApiOperation("应收应付统计") |
| | | public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @RequestParam(value = "type", defaultValue = "1") Integer type ) { |
| | | @Operation(summary = "应收应付统计") |
| | | public R statisticsReceivablePayable(@DefaultType Integer type ) { |
| | | StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type); |
| | | return AjaxResult.success(statisticsReceivablePayable); |
| | | return R.ok(statisticsReceivablePayable); |
| | | } |
| | | |
| | | /********************************************************仓储类*****************************************************/ |
| | | |
| | | @GetMapping("/productCategoryDistribution") |
| | | @ApiOperation("产品大类分布") |
| | | public AjaxResult productCategoryDistribution() { |
| | | @Operation(summary = "产品大类分布") |
| | | public R productCategoryDistribution() { |
| | | ProductCategoryDistributionDto dto = homeService.productCategoryDistribution(); |
| | | return AjaxResult.success(dto); |
| | | return R.ok(dto); |
| | | } |
| | | |
| | | @GetMapping("/salesPurchaseStorageProductCount") |
| | | @ApiOperation("销售-采购-储存产品数") |
| | | public AjaxResult salesPurchaseStorageProductCount(){ |
| | | @Operation(summary = "销售-采购-储存产品数") |
| | | public R salesPurchaseStorageProductCount(){ |
| | | List<MapDto> list = homeService.salesPurchaseStorageProductCount(); |
| | | return AjaxResult.success(list); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/productInOutAnalysis") |
| | | @ApiOperation("产品出入库分析") |
| | | public AjaxResult productInOutAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){ |
| | | @Operation(summary = "产品出入库分析") |
| | | public R productInOutAnalysis(@DefaultType Integer type){ |
| | | List<Map<String, Object>> result = homeService.productInOutAnalysis(type); |
| | | return AjaxResult.success(result); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | @GetMapping("/productTurnoverDays") |
| | | @ApiOperation("产品周转天数") |
| | | public AjaxResult productTurnoverDays(){ |
| | | @Operation(summary = "产品周转天数") |
| | | public R productTurnoverDays(){ |
| | | List<MapDto> list = homeService.productTurnoverDays(); |
| | | return AjaxResult.success(list); |
| | | 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); |
| | | } |
| | | |
| | | } |