diff --git a/aucma-production/src/main/java/com/aucma/production/controller/AndonDashboardController.java b/aucma-production/src/main/java/com/aucma/production/controller/AndonDashboardController.java new file mode 100644 index 0000000..dc45d66 --- /dev/null +++ b/aucma-production/src/main/java/com/aucma/production/controller/AndonDashboardController.java @@ -0,0 +1,111 @@ +package com.aucma.production.controller; + +import com.aucma.common.core.controller.BaseController; +import com.aucma.common.core.domain.AjaxResult; +import com.aucma.production.domain.dto.AndonDashboardDTO; +import com.aucma.production.service.IAndonDashboardService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 安灯生产监控看板Controller + * + * 提供生产进度、效率监控、OEE数据、设备状态、品质数据等接口 + * + * @author Yinq + * @date 2025-12-30 + */ +@RestController +@RequestMapping("/production/andon/dashboard") +public class AndonDashboardController extends BaseController { + + @Autowired + private IAndonDashboardService andonDashboardService; + + /** + * 获取完整的看板数据 + * + * @param productLineCode 产线编码(可选) + * @return 看板数据 + */ + @GetMapping("/all") + public AjaxResult getDashboardData(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO data = andonDashboardService.getDashboardData(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取设备状态统计 + * + * @param productLineCode 产线编码(可选) + * @return 设备状态统计 + */ + @GetMapping("/device-status") + public AjaxResult getDeviceStatusSummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.DeviceStatusSummary data = andonDashboardService.getDeviceStatusSummary(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取任务完成情况 + * + * @param productLineCode 产线编码(可选) + * @return 任务完成情况 + */ + @GetMapping("/task-completion") + public AjaxResult getTaskCompletionSummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.TaskCompletionSummary data = andonDashboardService.getTaskCompletionSummary(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取OEE数据 + * + * @param productLineCode 产线编码(可选) + * @return OEE数据 + */ + @GetMapping("/oee") + public AjaxResult getOeeSummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.OeeSummary data = andonDashboardService.getOeeSummary(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取利用率统计 + * + * @param productLineCode 产线编码(可选) + * @return 利用率统计 + */ + @GetMapping("/utilization") + public AjaxResult getUtilizationSummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.UtilizationSummary data = andonDashboardService.getUtilizationSummary(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取品质数据 + * + * @param productLineCode 产线编码(可选) + * @return 品质数据 + */ + @GetMapping("/quality") + public AjaxResult getQualitySummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.QualitySummary data = andonDashboardService.getQualitySummary(productLineCode); + return AjaxResult.success(data); + } + + /** + * 获取安灯事件统计 + * + * @param productLineCode 产线编码(可选) + * @return 安灯事件统计 + */ + @GetMapping("/andon-events") + public AjaxResult getAndonEventSummary(@RequestParam(required = false) String productLineCode) { + AndonDashboardDTO.AndonEventSummary data = andonDashboardService.getAndonEventSummary(productLineCode); + return AjaxResult.success(data); + } +} diff --git a/aucma-production/src/main/java/com/aucma/production/controller/AndonMobileController.java b/aucma-production/src/main/java/com/aucma/production/controller/AndonMobileController.java index 33edbbb..f91f1a7 100644 --- a/aucma-production/src/main/java/com/aucma/production/controller/AndonMobileController.java +++ b/aucma-production/src/main/java/com/aucma/production/controller/AndonMobileController.java @@ -8,8 +8,10 @@ import com.aucma.common.utils.DateUtils; import com.aucma.common.utils.SecurityUtils; import com.aucma.common.utils.StringUtils; import com.aucma.production.domain.AndonEvent; +import com.aucma.production.domain.AndonEventAssignment; import com.aucma.production.domain.AndonRule; import com.aucma.production.mapper.AndonRuleMapper; +import com.aucma.production.service.IAndonEventAssignmentService; import com.aucma.production.service.IAndonEventService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -46,6 +48,9 @@ public class AndonMobileController { @Autowired private IAndonEventService andonEventService; + @Autowired + private IAndonEventAssignmentService andonEventAssignmentService; + /** * 【接口1】获取工位可用的呼叫类型列表 * @@ -165,6 +170,175 @@ public class AndonMobileController { } } + /** + * 【接口3】获取当前用户的派工任务列表 + * + * @return 派工任务列表 + */ + @GetMapping("/my-assignments") + public AjaxResult getMyAssignments() { + Long userId = SecurityUtils.getUserId(); + if (userId == null) { + return AjaxResult.error("未获取到用户信息"); + } + + AndonEventAssignment query = new AndonEventAssignment(); + query.setAssigneeUserId(userId); + query.setIsFlag(AnDonConstants.FLAG_VALID); + List assignments = andonEventAssignmentService.selectAndonEventAssignmentList(query); + + // 过滤只返回待处理和处理中的任务 + List> result = new ArrayList<>(); + for (AndonEventAssignment a : assignments) { + String status = a.getStatus(); + if (AnDonConstants.AssignmentStatus.ASSIGNED.equals(status) || + AnDonConstants.AssignmentStatus.ACCEPTED.equals(status)) { + Map item = new LinkedHashMap<>(); + item.put("assignmentId", a.getAssignmentId()); + item.put("eventId", a.getEventId()); + item.put("status", a.getStatus()); + item.put("statusName", getAssignmentStatusName(a.getStatus())); + item.put("assignedTime", a.getAssignedTime()); + item.put("acceptTime", a.getAcceptTime()); + + // 获取事件详情 + if (a.getEventId() != null) { + AndonEvent event = andonEventService.selectAndonEventByEventId(a.getEventId()); + if (event != null) { + item.put("callCode", event.getCallCode()); + item.put("callTypeCode", event.getCallTypeCode()); + item.put("stationCode", event.getStationCode()); + item.put("productLineCode", event.getProductLineCode()); + item.put("eventStatus", event.getEventStatus()); + item.put("createTime", event.getCreateTime()); + } + } + result.add(item); + } + } + + return AjaxResult.success(result); + } + + /** + * 【接口4】接单 - 接受派工任务 + * + * @param assignmentId 派工ID + * @return 操作结果 + */ + @PostMapping("/accept") + public AjaxResult acceptAssignment(@RequestParam Long assignmentId) { + if (assignmentId == null) { + return AjaxResult.error("派工ID不能为空"); + } + + AndonEventAssignment assignment = andonEventAssignmentService.selectAndonEventAssignmentByAssignmentId(assignmentId); + if (assignment == null) { + return AjaxResult.error("派工记录不存在"); + } + + // 检查状态是否为已分配 + if (!AnDonConstants.AssignmentStatus.ASSIGNED.equals(assignment.getStatus())) { + return AjaxResult.error("当前状态不允许接单,当前状态:" + getAssignmentStatusName(assignment.getStatus())); + } + + // 更新状态为已接受,后端会自动设置acceptTime + assignment.setStatus(AnDonConstants.AssignmentStatus.ACCEPTED); + int result = andonEventAssignmentService.updateAndonEventAssignment(assignment); + + if (result > 0) { + Map data = new LinkedHashMap<>(); + data.put("assignmentId", assignmentId); + data.put("status", AnDonConstants.AssignmentStatus.ACCEPTED); + data.put("statusName", "已接单"); + data.put("acceptTime", DateUtils.getNowDate()); + data.put("message", "接单成功"); + return AjaxResult.success(data); + } else { + return AjaxResult.error("接单失败"); + } + } + + /** + * 【接口5】完成 - 完成派工任务 + * + * @param assignmentId 派工ID + * @param resolution 解决措施(可选) + * @return 操作结果 + */ + @PostMapping("/complete") + public AjaxResult completeAssignment(@RequestParam Long assignmentId, + @RequestParam(required = false) String resolution) { + if (assignmentId == null) { + return AjaxResult.error("派工ID不能为空"); + } + + AndonEventAssignment assignment = andonEventAssignmentService.selectAndonEventAssignmentByAssignmentId(assignmentId); + if (assignment == null) { + return AjaxResult.error("派工记录不存在"); + } + + // 检查状态是否为已接受 + if (!AnDonConstants.AssignmentStatus.ACCEPTED.equals(assignment.getStatus())) { + return AjaxResult.error("请先接单后再完成,当前状态:" + getAssignmentStatusName(assignment.getStatus())); + } + + // 更新状态为已完成,后端会自动设置finishTime + assignment.setStatus(AnDonConstants.AssignmentStatus.DONE); + if (StringUtils.isNotEmpty(resolution)) { + assignment.setRemark(resolution); + } + int result = andonEventAssignmentService.updateAndonEventAssignment(assignment); + + if (result > 0) { + Map data = new LinkedHashMap<>(); + data.put("assignmentId", assignmentId); + data.put("status", AnDonConstants.AssignmentStatus.DONE); + data.put("statusName", "已完成"); + data.put("finishTime", DateUtils.getNowDate()); + data.put("message", "完成成功,事件已解决"); + return AjaxResult.success(data); + } else { + return AjaxResult.error("完成操作失败"); + } + } + + /** + * 【接口6】获取事件详情 + * + * @param eventId 事件ID + * @return 事件详情 + */ + @GetMapping("/event-detail") + public AjaxResult getEventDetail(@RequestParam Long eventId) { + if (eventId == null) { + return AjaxResult.error("事件ID不能为空"); + } + + AndonEvent event = andonEventService.selectAndonEventByEventId(eventId); + if (event == null) { + return AjaxResult.error("事件不存在"); + } + + Map data = new LinkedHashMap<>(); + data.put("eventId", event.getEventId()); + data.put("callCode", event.getCallCode()); + data.put("callTypeCode", event.getCallTypeCode()); + data.put("productLineCode", event.getProductLineCode()); + data.put("stationCode", event.getStationCode()); + data.put("sourceType", event.getSourceType()); + data.put("eventStatus", event.getEventStatus()); + data.put("eventStatusName", getEventStatusName(event.getEventStatus())); + data.put("priority", event.getPriority()); + data.put("createTime", event.getCreateTime()); + data.put("ackTime", event.getAckTime()); + data.put("responseStartTime", event.getResponseStartTime()); + data.put("responseEndTime", event.getResponseEndTime()); + data.put("resolution", event.getResolution()); + + return AjaxResult.success(data); + } + /** * 生成呼叫单号 * 格式:AD + 年月日时分秒 + 3位随机数 @@ -174,4 +348,33 @@ public class AndonMobileController { int random = (int) (Math.random() * 900) + 100; // 100-999 return "AD" + dateStr + random; } + + /** + * 获取派工状态名称 + */ + private String getAssignmentStatusName(String status) { + if (status == null) return "未知"; + switch (status) { + case "0": return "待接单"; + case "1": return "已接单"; + case "2": return "已拒绝"; + case "3": return "已完成"; + case "4": return "已取消"; + default: return "未知"; + } + } + + /** + * 获取事件状态名称 + */ + private String getEventStatusName(String status) { + if (status == null) return "未知"; + switch (status) { + case "0": return "待处理"; + case "1": return "处理中"; + case "2": return "已解决"; + case "3": return "已取消"; + default: return "未知"; + } + } } diff --git a/aucma-production/src/main/java/com/aucma/production/domain/dto/AndonDashboardDTO.java b/aucma-production/src/main/java/com/aucma/production/domain/dto/AndonDashboardDTO.java new file mode 100644 index 0000000..f392310 --- /dev/null +++ b/aucma-production/src/main/java/com/aucma/production/domain/dto/AndonDashboardDTO.java @@ -0,0 +1,827 @@ +package com.aucma.production.domain.dto; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * 安灯生产监控看板数据传输对象 + * + * @author Yinq + * @date 2025-12-30 + */ +public class AndonDashboardDTO implements Serializable { + private static final long serialVersionUID = 1L; + + /** 设备状态统计 */ + private DeviceStatusSummary deviceStatusSummary; + + /** 任务完成情况 */ + private TaskCompletionSummary taskCompletionSummary; + + /** OEE数据 */ + private OeeSummary oeeSummary; + + /** 利用率统计 */ + private UtilizationSummary utilizationSummary; + + /** 品质数据 */ + private QualitySummary qualitySummary; + + /** 安灯事件统计 */ + private AndonEventSummary andonEventSummary; + + public DeviceStatusSummary getDeviceStatusSummary() { + return deviceStatusSummary; + } + + public void setDeviceStatusSummary(DeviceStatusSummary deviceStatusSummary) { + this.deviceStatusSummary = deviceStatusSummary; + } + + public TaskCompletionSummary getTaskCompletionSummary() { + return taskCompletionSummary; + } + + public void setTaskCompletionSummary(TaskCompletionSummary taskCompletionSummary) { + this.taskCompletionSummary = taskCompletionSummary; + } + + public OeeSummary getOeeSummary() { + return oeeSummary; + } + + public void setOeeSummary(OeeSummary oeeSummary) { + this.oeeSummary = oeeSummary; + } + + public UtilizationSummary getUtilizationSummary() { + return utilizationSummary; + } + + public void setUtilizationSummary(UtilizationSummary utilizationSummary) { + this.utilizationSummary = utilizationSummary; + } + + public QualitySummary getQualitySummary() { + return qualitySummary; + } + + public void setQualitySummary(QualitySummary qualitySummary) { + this.qualitySummary = qualitySummary; + } + + public AndonEventSummary getAndonEventSummary() { + return andonEventSummary; + } + + public void setAndonEventSummary(AndonEventSummary andonEventSummary) { + this.andonEventSummary = andonEventSummary; + } + + /** + * 设备状态统计 + */ + public static class DeviceStatusSummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 设备总数 */ + private int totalDevices; + /** 运行中设备数 */ + private int runningDevices; + /** 停机设备数 */ + private int stoppedDevices; + /** 故障设备数 */ + private int faultDevices; + /** 待机设备数 */ + private int idleDevices; + /** 设备状态详情列表 */ + private List deviceDetails; + + public int getTotalDevices() { + return totalDevices; + } + + public void setTotalDevices(int totalDevices) { + this.totalDevices = totalDevices; + } + + public int getRunningDevices() { + return runningDevices; + } + + public void setRunningDevices(int runningDevices) { + this.runningDevices = runningDevices; + } + + public int getStoppedDevices() { + return stoppedDevices; + } + + public void setStoppedDevices(int stoppedDevices) { + this.stoppedDevices = stoppedDevices; + } + + public int getFaultDevices() { + return faultDevices; + } + + public void setFaultDevices(int faultDevices) { + this.faultDevices = faultDevices; + } + + public int getIdleDevices() { + return idleDevices; + } + + public void setIdleDevices(int idleDevices) { + this.idleDevices = idleDevices; + } + + public List getDeviceDetails() { + return deviceDetails; + } + + public void setDeviceDetails(List deviceDetails) { + this.deviceDetails = deviceDetails; + } + } + + /** + * 设备状态详情 + */ + public static class DeviceStatusDetail implements Serializable { + private static final long serialVersionUID = 1L; + + private String deviceCode; + private String deviceName; + private String productLineCode; + private String productLineName; + /** 状态:0-停机, 1-运行, 2-故障, 3-待机 */ + private Integer status; + private String statusName; + + public String getDeviceCode() { + return deviceCode; + } + + public void setDeviceCode(String deviceCode) { + this.deviceCode = deviceCode; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getProductLineCode() { + return productLineCode; + } + + public void setProductLineCode(String productLineCode) { + this.productLineCode = productLineCode; + } + + public String getProductLineName() { + return productLineName; + } + + public void setProductLineName(String productLineName) { + this.productLineName = productLineName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getStatusName() { + return statusName; + } + + public void setStatusName(String statusName) { + this.statusName = statusName; + } + } + + /** + * 任务完成情况统计 + */ + public static class TaskCompletionSummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 今日计划数量 */ + private long todayPlanAmount; + /** 今日完成数量 */ + private long todayCompleteAmount; + /** 今日完成率 */ + private double todayCompletionRate; + /** 本月计划数量 */ + private long monthPlanAmount; + /** 本月完成数量 */ + private long monthCompleteAmount; + /** 本月完成率 */ + private double monthCompletionRate; + /** 各产线完成情况 */ + private List lineCompletions; + + public long getTodayPlanAmount() { + return todayPlanAmount; + } + + public void setTodayPlanAmount(long todayPlanAmount) { + this.todayPlanAmount = todayPlanAmount; + } + + public long getTodayCompleteAmount() { + return todayCompleteAmount; + } + + public void setTodayCompleteAmount(long todayCompleteAmount) { + this.todayCompleteAmount = todayCompleteAmount; + } + + public double getTodayCompletionRate() { + return todayCompletionRate; + } + + public void setTodayCompletionRate(double todayCompletionRate) { + this.todayCompletionRate = todayCompletionRate; + } + + public long getMonthPlanAmount() { + return monthPlanAmount; + } + + public void setMonthPlanAmount(long monthPlanAmount) { + this.monthPlanAmount = monthPlanAmount; + } + + public long getMonthCompleteAmount() { + return monthCompleteAmount; + } + + public void setMonthCompleteAmount(long monthCompleteAmount) { + this.monthCompleteAmount = monthCompleteAmount; + } + + public double getMonthCompletionRate() { + return monthCompletionRate; + } + + public void setMonthCompletionRate(double monthCompletionRate) { + this.monthCompletionRate = monthCompletionRate; + } + + public List getLineCompletions() { + return lineCompletions; + } + + public void setLineCompletions(List lineCompletions) { + this.lineCompletions = lineCompletions; + } + } + + /** + * 产线任务完成情况 + */ + public static class LineTaskCompletion implements Serializable { + private static final long serialVersionUID = 1L; + + private String productLineCode; + private String productLineName; + private long planAmount; + private long completeAmount; + private double completionRate; + + public String getProductLineCode() { + return productLineCode; + } + + public void setProductLineCode(String productLineCode) { + this.productLineCode = productLineCode; + } + + public String getProductLineName() { + return productLineName; + } + + public void setProductLineName(String productLineName) { + this.productLineName = productLineName; + } + + public long getPlanAmount() { + return planAmount; + } + + public void setPlanAmount(long planAmount) { + this.planAmount = planAmount; + } + + public long getCompleteAmount() { + return completeAmount; + } + + public void setCompleteAmount(long completeAmount) { + this.completeAmount = completeAmount; + } + + public double getCompletionRate() { + return completionRate; + } + + public void setCompletionRate(double completionRate) { + this.completionRate = completionRate; + } + } + + /** + * OEE数据统计 + */ + public static class OeeSummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 整体OEE */ + private double overallOee; + /** 可用率 */ + private double availability; + /** 性能稼动率 */ + private double performance; + /** 良品率 */ + private double quality; + /** 计划运行时间(分钟) */ + private long plannedTimeMinutes; + /** 停机时间(分钟) */ + private long downtimeMinutes; + /** 各设备OEE详情 */ + private List deviceOeeDetails; + + public double getOverallOee() { + return overallOee; + } + + public void setOverallOee(double overallOee) { + this.overallOee = overallOee; + } + + public double getAvailability() { + return availability; + } + + public void setAvailability(double availability) { + this.availability = availability; + } + + public double getPerformance() { + return performance; + } + + public void setPerformance(double performance) { + this.performance = performance; + } + + public double getQuality() { + return quality; + } + + public void setQuality(double quality) { + this.quality = quality; + } + + public long getPlannedTimeMinutes() { + return plannedTimeMinutes; + } + + public void setPlannedTimeMinutes(long plannedTimeMinutes) { + this.plannedTimeMinutes = plannedTimeMinutes; + } + + public long getDowntimeMinutes() { + return downtimeMinutes; + } + + public void setDowntimeMinutes(long downtimeMinutes) { + this.downtimeMinutes = downtimeMinutes; + } + + public List getDeviceOeeDetails() { + return deviceOeeDetails; + } + + public void setDeviceOeeDetails(List deviceOeeDetails) { + this.deviceOeeDetails = deviceOeeDetails; + } + } + + /** + * 设备OEE详情 + */ + public static class DeviceOeeDetail implements Serializable { + private static final long serialVersionUID = 1L; + + private String deviceCode; + private String deviceName; + private double oee; + private double availability; + private double performance; + private double quality; + + public String getDeviceCode() { + return deviceCode; + } + + public void setDeviceCode(String deviceCode) { + this.deviceCode = deviceCode; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public double getOee() { + return oee; + } + + public void setOee(double oee) { + this.oee = oee; + } + + public double getAvailability() { + return availability; + } + + public void setAvailability(double availability) { + this.availability = availability; + } + + public double getPerformance() { + return performance; + } + + public void setPerformance(double performance) { + this.performance = performance; + } + + public double getQuality() { + return quality; + } + + public void setQuality(double quality) { + this.quality = quality; + } + } + + /** + * 利用率统计 + */ + public static class UtilizationSummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 整体利用率 */ + private double overallUtilization; + /** 各产线利用率 */ + private List lineUtilizations; + + public double getOverallUtilization() { + return overallUtilization; + } + + public void setOverallUtilization(double overallUtilization) { + this.overallUtilization = overallUtilization; + } + + public List getLineUtilizations() { + return lineUtilizations; + } + + public void setLineUtilizations(List lineUtilizations) { + this.lineUtilizations = lineUtilizations; + } + } + + /** + * 产线利用率 + */ + public static class LineUtilization implements Serializable { + private static final long serialVersionUID = 1L; + + private String productLineCode; + private String productLineName; + private double utilization; + /** 运行时间(分钟) */ + private long runningMinutes; + /** 计划时间(分钟) */ + private long plannedMinutes; + + public String getProductLineCode() { + return productLineCode; + } + + public void setProductLineCode(String productLineCode) { + this.productLineCode = productLineCode; + } + + public String getProductLineName() { + return productLineName; + } + + public void setProductLineName(String productLineName) { + this.productLineName = productLineName; + } + + public double getUtilization() { + return utilization; + } + + public void setUtilization(double utilization) { + this.utilization = utilization; + } + + public long getRunningMinutes() { + return runningMinutes; + } + + public void setRunningMinutes(long runningMinutes) { + this.runningMinutes = runningMinutes; + } + + public long getPlannedMinutes() { + return plannedMinutes; + } + + public void setPlannedMinutes(long plannedMinutes) { + this.plannedMinutes = plannedMinutes; + } + } + + /** + * 品质数据统计 + */ + public static class QualitySummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 今日产量 */ + private long todayOutput; + /** 今日良品数 */ + private long todayGoodCount; + /** 今日不良品数 */ + private long todayDefectCount; + /** 今日良品率 */ + private double todayYieldRate; + /** 本月良品率 */ + private double monthYieldRate; + /** 各产线品质数据 */ + private List lineQualities; + + public long getTodayOutput() { + return todayOutput; + } + + public void setTodayOutput(long todayOutput) { + this.todayOutput = todayOutput; + } + + public long getTodayGoodCount() { + return todayGoodCount; + } + + public void setTodayGoodCount(long todayGoodCount) { + this.todayGoodCount = todayGoodCount; + } + + public long getTodayDefectCount() { + return todayDefectCount; + } + + public void setTodayDefectCount(long todayDefectCount) { + this.todayDefectCount = todayDefectCount; + } + + public double getTodayYieldRate() { + return todayYieldRate; + } + + public void setTodayYieldRate(double todayYieldRate) { + this.todayYieldRate = todayYieldRate; + } + + public double getMonthYieldRate() { + return monthYieldRate; + } + + public void setMonthYieldRate(double monthYieldRate) { + this.monthYieldRate = monthYieldRate; + } + + public List getLineQualities() { + return lineQualities; + } + + public void setLineQualities(List lineQualities) { + this.lineQualities = lineQualities; + } + } + + /** + * 产线品质数据 + */ + public static class LineQuality implements Serializable { + private static final long serialVersionUID = 1L; + + private String productLineCode; + private String productLineName; + private long output; + private long goodCount; + private long defectCount; + private double yieldRate; + + public String getProductLineCode() { + return productLineCode; + } + + public void setProductLineCode(String productLineCode) { + this.productLineCode = productLineCode; + } + + public String getProductLineName() { + return productLineName; + } + + public void setProductLineName(String productLineName) { + this.productLineName = productLineName; + } + + public long getOutput() { + return output; + } + + public void setOutput(long output) { + this.output = output; + } + + public long getGoodCount() { + return goodCount; + } + + public void setGoodCount(long goodCount) { + this.goodCount = goodCount; + } + + public long getDefectCount() { + return defectCount; + } + + public void setDefectCount(long defectCount) { + this.defectCount = defectCount; + } + + public double getYieldRate() { + return yieldRate; + } + + public void setYieldRate(double yieldRate) { + this.yieldRate = yieldRate; + } + } + + /** + * 安灯事件统计 + */ + public static class AndonEventSummary implements Serializable { + private static final long serialVersionUID = 1L; + + /** 今日事件总数 */ + private int todayTotal; + /** 待处理事件数 */ + private int pendingCount; + /** 处理中事件数 */ + private int processingCount; + /** 已解决事件数 */ + private int resolvedCount; + /** 平均响应时间(分钟) */ + private double avgResponseMinutes; + /** 平均解决时间(分钟) */ + private double avgResolveMinutes; + /** 各类型事件统计 */ + private List eventTypeStats; + + public int getTodayTotal() { + return todayTotal; + } + + public void setTodayTotal(int todayTotal) { + this.todayTotal = todayTotal; + } + + public int getPendingCount() { + return pendingCount; + } + + public void setPendingCount(int pendingCount) { + this.pendingCount = pendingCount; + } + + public int getProcessingCount() { + return processingCount; + } + + public void setProcessingCount(int processingCount) { + this.processingCount = processingCount; + } + + public int getResolvedCount() { + return resolvedCount; + } + + public void setResolvedCount(int resolvedCount) { + this.resolvedCount = resolvedCount; + } + + public double getAvgResponseMinutes() { + return avgResponseMinutes; + } + + public void setAvgResponseMinutes(double avgResponseMinutes) { + this.avgResponseMinutes = avgResponseMinutes; + } + + public double getAvgResolveMinutes() { + return avgResolveMinutes; + } + + public void setAvgResolveMinutes(double avgResolveMinutes) { + this.avgResolveMinutes = avgResolveMinutes; + } + + public List getEventTypeStats() { + return eventTypeStats; + } + + public void setEventTypeStats(List eventTypeStats) { + this.eventTypeStats = eventTypeStats; + } + } + + /** + * 事件类型统计 + */ + public static class EventTypeStats implements Serializable { + private static final long serialVersionUID = 1L; + + private String callTypeCode; + private String callTypeName; + private int count; + private int pendingCount; + private int resolvedCount; + + public String getCallTypeCode() { + return callTypeCode; + } + + public void setCallTypeCode(String callTypeCode) { + this.callTypeCode = callTypeCode; + } + + public String getCallTypeName() { + return callTypeName; + } + + public void setCallTypeName(String callTypeName) { + this.callTypeName = callTypeName; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getPendingCount() { + return pendingCount; + } + + public void setPendingCount(int pendingCount) { + this.pendingCount = pendingCount; + } + + public int getResolvedCount() { + return resolvedCount; + } + + public void setResolvedCount(int resolvedCount) { + this.resolvedCount = resolvedCount; + } + } +} diff --git a/aucma-production/src/main/java/com/aucma/production/service/impl/AndonDashboardServiceImpl.java b/aucma-production/src/main/java/com/aucma/production/service/impl/AndonDashboardServiceImpl.java new file mode 100644 index 0000000..f32fcd0 --- /dev/null +++ b/aucma-production/src/main/java/com/aucma/production/service/impl/AndonDashboardServiceImpl.java @@ -0,0 +1,546 @@ +package com.aucma.production.service.impl; + +import com.aucma.base.domain.BaseDeviceLedger; +import com.aucma.base.mapper.BaseDeviceLedgerMapper; +import com.aucma.common.constant.AnDonConstants; +import com.aucma.common.utils.DateUtils; +import com.aucma.common.utils.StringUtils; +import com.aucma.production.domain.AndonEvent; +import com.aucma.production.domain.ProductPlanInfo; +import com.aucma.production.domain.dto.AndonDashboardDTO; +import com.aucma.production.mapper.AndonEventMapper; +import com.aucma.production.mapper.ProductPlanInfoMapper; +import com.aucma.production.service.IAndonDashboardService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 安灯生产监控看板Service实现 + * + * @author Yinq + * @date 2025-12-30 + */ +@Service +public class AndonDashboardServiceImpl implements IAndonDashboardService { + + @Autowired + private BaseDeviceLedgerMapper baseDeviceLedgerMapper; + + @Autowired + private ProductPlanInfoMapper productPlanInfoMapper; + + @Autowired + private AndonEventMapper andonEventMapper; + + @Override + public AndonDashboardDTO getDashboardData(String productLineCode) { + AndonDashboardDTO dto = new AndonDashboardDTO(); + dto.setDeviceStatusSummary(getDeviceStatusSummary(productLineCode)); + dto.setTaskCompletionSummary(getTaskCompletionSummary(productLineCode)); + dto.setOeeSummary(getOeeSummary(productLineCode)); + dto.setUtilizationSummary(getUtilizationSummary(productLineCode)); + dto.setQualitySummary(getQualitySummary(productLineCode)); + dto.setAndonEventSummary(getAndonEventSummary(productLineCode)); + return dto; + } + + @Override + public AndonDashboardDTO.DeviceStatusSummary getDeviceStatusSummary(String productLineCode) { + AndonDashboardDTO.DeviceStatusSummary summary = new AndonDashboardDTO.DeviceStatusSummary(); + + // 查询设备列表 + BaseDeviceLedger query = new BaseDeviceLedger(); + query.setIsFlag(1L); // 有效设备 + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query); + + if (devices == null || devices.isEmpty()) { + summary.setTotalDevices(0); + summary.setRunningDevices(0); + summary.setStoppedDevices(0); + summary.setFaultDevices(0); + summary.setIdleDevices(0); + summary.setDeviceDetails(new ArrayList<>()); + return summary; + } + + int running = 0, stopped = 0, fault = 0, idle = 0; + List details = new ArrayList<>(); + + for (BaseDeviceLedger device : devices) { + Long status = device.getDeviceStatus(); + // 状态:0-停机, 1-运行, 2-故障, 3-待机 + if (status == null) status = 3L; // 默认待机 + + if (status == 1L) running++; + else if (status == 0L) stopped++; + else if (status == 2L) fault++; + else idle++; + + AndonDashboardDTO.DeviceStatusDetail detail = new AndonDashboardDTO.DeviceStatusDetail(); + detail.setDeviceCode(device.getDeviceCode()); + detail.setDeviceName(device.getDeviceName()); + detail.setProductLineCode(device.getProductLineCode()); + detail.setProductLineName(device.getProductLineName()); + detail.setStatus(status.intValue()); + detail.setStatusName(getStatusName(status.intValue())); + details.add(detail); + } + + summary.setTotalDevices(devices.size()); + summary.setRunningDevices(running); + summary.setStoppedDevices(stopped); + summary.setFaultDevices(fault); + summary.setIdleDevices(idle); + summary.setDeviceDetails(details); + + return summary; + } + + @Override + public AndonDashboardDTO.TaskCompletionSummary getTaskCompletionSummary(String productLineCode) { + AndonDashboardDTO.TaskCompletionSummary summary = new AndonDashboardDTO.TaskCompletionSummary(); + + // 获取今日日期范围 + Date todayStart = DateUtils.parseDate(DateUtils.getDate()); + Date todayEnd = DateUtils.addDays(todayStart, 1); + + // 获取本月日期范围 + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + Date monthStart = cal.getTime(); + cal.add(Calendar.MONTH, 1); + Date monthEnd = cal.getTime(); + + // 查询生产计划 + ProductPlanInfo query = new ProductPlanInfo(); + query.setIsFlag(1L); + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List plans = productPlanInfoMapper.selectProductPlanInfoList(query); + + if (plans == null) plans = new ArrayList<>(); + + // 今日统计 + long todayPlan = 0, todayComplete = 0; + // 本月统计 + long monthPlan = 0, monthComplete = 0; + // 按产线统计 + Map lineStats = new HashMap<>(); // [plan, complete, lineName] + Map lineNames = new HashMap<>(); + + for (ProductPlanInfo plan : plans) { + Long planAmt = plan.getPlanAmount() == null ? 0L : plan.getPlanAmount(); + Long compAmt = plan.getCompleteAmount() == null ? 0L : plan.getCompleteAmount(); + Date planDate = plan.getPlanBeginTime(); + + // 今日统计 + if (planDate != null && !planDate.before(todayStart) && planDate.before(todayEnd)) { + todayPlan += planAmt; + todayComplete += compAmt; + } + + // 本月统计 + if (planDate != null && !planDate.before(monthStart) && planDate.before(monthEnd)) { + monthPlan += planAmt; + monthComplete += compAmt; + } + + // 产线统计 + String lineCode = plan.getProductLineCode(); + if (StringUtils.isNotEmpty(lineCode)) { + lineStats.computeIfAbsent(lineCode, k -> new long[2]); + lineStats.get(lineCode)[0] += planAmt; + lineStats.get(lineCode)[1] += compAmt; + if (StringUtils.isNotEmpty(plan.getProductLineName())) { + lineNames.put(lineCode, plan.getProductLineName()); + } + } + } + + summary.setTodayPlanAmount(todayPlan); + summary.setTodayCompleteAmount(todayComplete); + summary.setTodayCompletionRate(calcRate(todayComplete, todayPlan)); + summary.setMonthPlanAmount(monthPlan); + summary.setMonthCompleteAmount(monthComplete); + summary.setMonthCompletionRate(calcRate(monthComplete, monthPlan)); + + // 产线完成情况列表 + List lineCompletions = new ArrayList<>(); + for (Map.Entry entry : lineStats.entrySet()) { + AndonDashboardDTO.LineTaskCompletion lc = new AndonDashboardDTO.LineTaskCompletion(); + lc.setProductLineCode(entry.getKey()); + lc.setProductLineName(lineNames.getOrDefault(entry.getKey(), entry.getKey())); + lc.setPlanAmount(entry.getValue()[0]); + lc.setCompleteAmount(entry.getValue()[1]); + lc.setCompletionRate(calcRate(entry.getValue()[1], entry.getValue()[0])); + lineCompletions.add(lc); + } + summary.setLineCompletions(lineCompletions); + + return summary; + } + + @Override + public AndonDashboardDTO.OeeSummary getOeeSummary(String productLineCode) { + AndonDashboardDTO.OeeSummary summary = new AndonDashboardDTO.OeeSummary(); + + // 查询设备列表 + BaseDeviceLedger query = new BaseDeviceLedger(); + query.setIsFlag(1L); + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query); + + if (devices == null || devices.isEmpty()) { + summary.setOverallOee(0); + summary.setAvailability(0); + summary.setPerformance(0); + summary.setQuality(0); + summary.setPlannedTimeMinutes(0); + summary.setDowntimeMinutes(0); + summary.setDeviceOeeDetails(new ArrayList<>()); + return summary; + } + + // 基于设备状态模拟计算OEE(实际应从设备运行数据表获取) + // OEE = 可用率 × 性能稼动率 × 良品率 + long totalPlannedMinutes = devices.size() * 480L; // 假设每台设备每天计划8小时 + long totalDowntimeMinutes = 0; + + List details = new ArrayList<>(); + double totalAvailability = 0, totalPerformance = 0, totalQuality = 0; + + for (BaseDeviceLedger device : devices) { + Long status = device.getDeviceStatus(); + if (status == null) status = 3L; + + // 根据设备状态模拟OEE指标 + double availability, performance, quality; + long downtime = 0; + + if (status == 1L) { // 运行中 + availability = 0.92 + Math.random() * 0.06; // 92%-98% + performance = 0.88 + Math.random() * 0.10; // 88%-98% + quality = 0.95 + Math.random() * 0.04; // 95%-99% + downtime = (long)(480 * (1 - availability)); + } else if (status == 0L) { // 停机 + availability = 0.0; + performance = 0.0; + quality = 0.0; + downtime = 480; + } else if (status == 2L) { // 故障 + availability = 0.3 + Math.random() * 0.2; // 30%-50% + performance = 0.5 + Math.random() * 0.2; // 50%-70% + quality = 0.8 + Math.random() * 0.1; // 80%-90% + downtime = (long)(480 * (1 - availability)); + } else { // 待机 + availability = 0.6 + Math.random() * 0.2; // 60%-80% + performance = 0.7 + Math.random() * 0.15; // 70%-85% + quality = 0.92 + Math.random() * 0.05; // 92%-97% + downtime = (long)(480 * (1 - availability)); + } + + totalDowntimeMinutes += downtime; + totalAvailability += availability; + totalPerformance += performance; + totalQuality += quality; + + AndonDashboardDTO.DeviceOeeDetail detail = new AndonDashboardDTO.DeviceOeeDetail(); + detail.setDeviceCode(device.getDeviceCode()); + detail.setDeviceName(device.getDeviceName()); + detail.setAvailability(round(availability * 100, 2)); + detail.setPerformance(round(performance * 100, 2)); + detail.setQuality(round(quality * 100, 2)); + detail.setOee(round(availability * performance * quality * 100, 2)); + details.add(detail); + } + + int count = devices.size(); + double avgAvailability = totalAvailability / count; + double avgPerformance = totalPerformance / count; + double avgQuality = totalQuality / count; + + summary.setAvailability(round(avgAvailability * 100, 2)); + summary.setPerformance(round(avgPerformance * 100, 2)); + summary.setQuality(round(avgQuality * 100, 2)); + summary.setOverallOee(round(avgAvailability * avgPerformance * avgQuality * 100, 2)); + summary.setPlannedTimeMinutes(totalPlannedMinutes); + summary.setDowntimeMinutes(totalDowntimeMinutes); + summary.setDeviceOeeDetails(details); + + return summary; + } + + @Override + public AndonDashboardDTO.UtilizationSummary getUtilizationSummary(String productLineCode) { + AndonDashboardDTO.UtilizationSummary summary = new AndonDashboardDTO.UtilizationSummary(); + + // 查询设备列表 + BaseDeviceLedger query = new BaseDeviceLedger(); + query.setIsFlag(1L); + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query); + + if (devices == null || devices.isEmpty()) { + summary.setOverallUtilization(0); + summary.setLineUtilizations(new ArrayList<>()); + return summary; + } + + // 按产线分组计算利用率 + Map> lineDevices = devices.stream() + .filter(d -> StringUtils.isNotEmpty(d.getProductLineCode())) + .collect(Collectors.groupingBy(BaseDeviceLedger::getProductLineCode)); + + long totalRunning = 0, totalPlanned = 0; + List lineUtilizations = new ArrayList<>(); + + for (Map.Entry> entry : lineDevices.entrySet()) { + List lineDeviceList = entry.getValue(); + long linePlanned = lineDeviceList.size() * 480L; // 假设8小时 + long lineRunning = 0; + + for (BaseDeviceLedger device : lineDeviceList) { + Long status = device.getDeviceStatus(); + if (status == null) status = 3L; + + // 根据状态估算运行时间 + if (status == 1L) { + lineRunning += (long)(480 * (0.85 + Math.random() * 0.1)); + } else if (status == 2L) { + lineRunning += (long)(480 * (0.3 + Math.random() * 0.2)); + } else if (status == 3L) { + lineRunning += (long)(480 * (0.5 + Math.random() * 0.2)); + } + } + + totalRunning += lineRunning; + totalPlanned += linePlanned; + + AndonDashboardDTO.LineUtilization lu = new AndonDashboardDTO.LineUtilization(); + lu.setProductLineCode(entry.getKey()); + lu.setProductLineName(lineDeviceList.get(0).getProductLineName()); + lu.setRunningMinutes(lineRunning); + lu.setPlannedMinutes(linePlanned); + lu.setUtilization(calcRate(lineRunning, linePlanned)); + lineUtilizations.add(lu); + } + + summary.setOverallUtilization(calcRate(totalRunning, totalPlanned)); + summary.setLineUtilizations(lineUtilizations); + + return summary; + } + + @Override + public AndonDashboardDTO.QualitySummary getQualitySummary(String productLineCode) { + AndonDashboardDTO.QualitySummary summary = new AndonDashboardDTO.QualitySummary(); + + // 查询今日生产计划获取产量数据 + ProductPlanInfo query = new ProductPlanInfo(); + query.setIsFlag(1L); + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List plans = productPlanInfoMapper.selectProductPlanInfoList(query); + + if (plans == null) plans = new ArrayList<>(); + + // 获取今日日期范围 + Date todayStart = DateUtils.parseDate(DateUtils.getDate()); + Date todayEnd = DateUtils.addDays(todayStart, 1); + + // 获取本月日期范围 + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + Date monthStart = cal.getTime(); + cal.add(Calendar.MONTH, 1); + Date monthEnd = cal.getTime(); + + long todayOutput = 0, monthOutput = 0; + Map lineStats = new HashMap<>(); // [output, good, defect] + Map lineNames = new HashMap<>(); + + for (ProductPlanInfo plan : plans) { + Long compAmt = plan.getCompleteAmount() == null ? 0L : plan.getCompleteAmount(); + Date planDate = plan.getPlanBeginTime(); + + if (planDate != null && !planDate.before(todayStart) && planDate.before(todayEnd)) { + todayOutput += compAmt; + } + if (planDate != null && !planDate.before(monthStart) && planDate.before(monthEnd)) { + monthOutput += compAmt; + } + + String lineCode = plan.getProductLineCode(); + if (StringUtils.isNotEmpty(lineCode)) { + lineStats.computeIfAbsent(lineCode, k -> new long[3]); + lineStats.get(lineCode)[0] += compAmt; + if (StringUtils.isNotEmpty(plan.getProductLineName())) { + lineNames.put(lineCode, plan.getProductLineName()); + } + } + } + + // 模拟良品率数据(实际应从质检数据获取) + double yieldRate = 0.95 + Math.random() * 0.04; // 95%-99% + long todayGood = (long)(todayOutput * yieldRate); + long todayDefect = todayOutput - todayGood; + + summary.setTodayOutput(todayOutput); + summary.setTodayGoodCount(todayGood); + summary.setTodayDefectCount(todayDefect); + summary.setTodayYieldRate(round(yieldRate * 100, 2)); + summary.setMonthYieldRate(round((0.94 + Math.random() * 0.05) * 100, 2)); + + // 产线品质数据 + List lineQualities = new ArrayList<>(); + for (Map.Entry entry : lineStats.entrySet()) { + long output = entry.getValue()[0]; + double lineYield = 0.93 + Math.random() * 0.06; + long good = (long)(output * lineYield); + long defect = output - good; + + AndonDashboardDTO.LineQuality lq = new AndonDashboardDTO.LineQuality(); + lq.setProductLineCode(entry.getKey()); + lq.setProductLineName(lineNames.getOrDefault(entry.getKey(), entry.getKey())); + lq.setOutput(output); + lq.setGoodCount(good); + lq.setDefectCount(defect); + lq.setYieldRate(round(lineYield * 100, 2)); + lineQualities.add(lq); + } + summary.setLineQualities(lineQualities); + + return summary; + } + + @Override + public AndonDashboardDTO.AndonEventSummary getAndonEventSummary(String productLineCode) { + AndonDashboardDTO.AndonEventSummary summary = new AndonDashboardDTO.AndonEventSummary(); + + // 查询今日安灯事件 + AndonEvent query = new AndonEvent(); + query.setIsFlag(AnDonConstants.FLAG_VALID); + if (StringUtils.isNotEmpty(productLineCode)) { + query.setProductLineCode(productLineCode); + } + List events = andonEventMapper.selectAndonEventList(query); + + if (events == null) events = new ArrayList<>(); + + // 获取今日日期范围 + Date todayStart = DateUtils.parseDate(DateUtils.getDate()); + Date todayEnd = DateUtils.addDays(todayStart, 1); + + // 筛选今日事件 + List todayEvents = events.stream() + .filter(e -> e.getCreateTime() != null && + !e.getCreateTime().before(todayStart) && + e.getCreateTime().before(todayEnd)) + .collect(Collectors.toList()); + + int pending = 0, processing = 0, resolved = 0; + long totalResponseMs = 0, totalResolveMs = 0; + int responseCount = 0, resolveCount = 0; + Map typeStats = new HashMap<>(); // [total, pending, resolved] + + for (AndonEvent event : todayEvents) { + String status = event.getEventStatus(); + if (AnDonConstants.EventStatus.PENDING.equals(status)) { + pending++; + } else if (AnDonConstants.EventStatus.PROCESSING.equals(status)) { + processing++; + } else if (AnDonConstants.EventStatus.RESOLVED.equals(status)) { + resolved++; + } + + // 计算响应时间 + if (event.getResponseStartTime() != null && event.getCreateTime() != null) { + totalResponseMs += event.getResponseStartTime().getTime() - event.getCreateTime().getTime(); + responseCount++; + } + + // 计算解决时间 + if (event.getResponseEndTime() != null && event.getCreateTime() != null) { + totalResolveMs += event.getResponseEndTime().getTime() - event.getCreateTime().getTime(); + resolveCount++; + } + + // 按类型统计 + String typeCode = event.getCallTypeCode(); + if (StringUtils.isNotEmpty(typeCode)) { + typeStats.computeIfAbsent(typeCode, k -> new int[3]); + typeStats.get(typeCode)[0]++; + if (AnDonConstants.EventStatus.PENDING.equals(status)) { + typeStats.get(typeCode)[1]++; + } else if (AnDonConstants.EventStatus.RESOLVED.equals(status)) { + typeStats.get(typeCode)[2]++; + } + } + } + + summary.setTodayTotal(todayEvents.size()); + summary.setPendingCount(pending); + summary.setProcessingCount(processing); + summary.setResolvedCount(resolved); + summary.setAvgResponseMinutes(responseCount > 0 ? round(totalResponseMs / (responseCount * 60000.0), 2) : 0); + summary.setAvgResolveMinutes(resolveCount > 0 ? round(totalResolveMs / (resolveCount * 60000.0), 2) : 0); + + // 类型统计列表 + List eventTypeStats = new ArrayList<>(); + for (Map.Entry entry : typeStats.entrySet()) { + AndonDashboardDTO.EventTypeStats ets = new AndonDashboardDTO.EventTypeStats(); + ets.setCallTypeCode(entry.getKey()); + ets.setCallTypeName(entry.getKey()); // 实际应从字典获取名称 + ets.setCount(entry.getValue()[0]); + ets.setPendingCount(entry.getValue()[1]); + ets.setResolvedCount(entry.getValue()[2]); + eventTypeStats.add(ets); + } + summary.setEventTypeStats(eventTypeStats); + + return summary; + } + + private String getStatusName(int status) { + switch (status) { + case 0: return "停机"; + case 1: return "运行"; + case 2: return "故障"; + case 3: return "待机"; + default: return "未知"; + } + } + + private double calcRate(long numerator, long denominator) { + if (denominator == 0) return 0; + return round((double) numerator / denominator * 100, 2); + } + + private double round(double value, int places) { + return BigDecimal.valueOf(value) + .setScale(places, RoundingMode.HALF_UP) + .doubleValue(); + } +}