feat(andon): 添加移动端派工任务和生产监控看板功能

- 在AndonMobileController中新增派工任务相关接口,包括获取用户任务列表、接单、完成任务等功能
- 添加AndonDashboardController提供生产监控看板数据接口,包含设备状态、任务完成、OEE、利用率、品质、安灯事件等统计
- 新增AndonDashboardDTO数据传输对象,定义完整的生产监控数据结构
- 实现AndonDashboardServiceImpl提供看板数据查询服务,整合设备、生产计划、安灯事件等多维度数据
- 扩展AndonEventAssignment相关功能,支持移动端派工任务的完整流程处理
master
zangch@mesnac.com 3 months ago
parent ceee55e8c4
commit 41c5d56e63

@ -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);
}
}

@ -8,8 +8,10 @@ import com.aucma.common.utils.DateUtils;
import com.aucma.common.utils.SecurityUtils; import com.aucma.common.utils.SecurityUtils;
import com.aucma.common.utils.StringUtils; import com.aucma.common.utils.StringUtils;
import com.aucma.production.domain.AndonEvent; import com.aucma.production.domain.AndonEvent;
import com.aucma.production.domain.AndonEventAssignment;
import com.aucma.production.domain.AndonRule; import com.aucma.production.domain.AndonRule;
import com.aucma.production.mapper.AndonRuleMapper; import com.aucma.production.mapper.AndonRuleMapper;
import com.aucma.production.service.IAndonEventAssignmentService;
import com.aucma.production.service.IAndonEventService; import com.aucma.production.service.IAndonEventService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -46,6 +48,9 @@ public class AndonMobileController {
@Autowired @Autowired
private IAndonEventService andonEventService; private IAndonEventService andonEventService;
@Autowired
private IAndonEventAssignmentService andonEventAssignmentService;
/** /**
* 1 * 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<AndonEventAssignment> assignments = andonEventAssignmentService.selectAndonEventAssignmentList(query);
// 过滤只返回待处理和处理中的任务
List<Map<String, Object>> result = new ArrayList<>();
for (AndonEventAssignment a : assignments) {
String status = a.getStatus();
if (AnDonConstants.AssignmentStatus.ASSIGNED.equals(status) ||
AnDonConstants.AssignmentStatus.ACCEPTED.equals(status)) {
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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 * AD + + 3
@ -174,4 +348,33 @@ public class AndonMobileController {
int random = (int) (Math.random() * 900) + 100; // 100-999 int random = (int) (Math.random() * 900) + 100; // 100-999
return "AD" + dateStr + random; 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 "未知";
}
}
} }

@ -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<DeviceStatusDetail> 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<DeviceStatusDetail> getDeviceDetails() {
return deviceDetails;
}
public void setDeviceDetails(List<DeviceStatusDetail> 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<LineTaskCompletion> 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<LineTaskCompletion> getLineCompletions() {
return lineCompletions;
}
public void setLineCompletions(List<LineTaskCompletion> 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<DeviceOeeDetail> 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<DeviceOeeDetail> getDeviceOeeDetails() {
return deviceOeeDetails;
}
public void setDeviceOeeDetails(List<DeviceOeeDetail> 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<LineUtilization> lineUtilizations;
public double getOverallUtilization() {
return overallUtilization;
}
public void setOverallUtilization(double overallUtilization) {
this.overallUtilization = overallUtilization;
}
public List<LineUtilization> getLineUtilizations() {
return lineUtilizations;
}
public void setLineUtilizations(List<LineUtilization> 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<LineQuality> 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<LineQuality> getLineQualities() {
return lineQualities;
}
public void setLineQualities(List<LineQuality> 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> 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<EventTypeStats> getEventTypeStats() {
return eventTypeStats;
}
public void setEventTypeStats(List<EventTypeStats> 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;
}
}
}

@ -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<BaseDeviceLedger> 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<AndonDashboardDTO.DeviceStatusDetail> 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<ProductPlanInfo> plans = productPlanInfoMapper.selectProductPlanInfoList(query);
if (plans == null) plans = new ArrayList<>();
// 今日统计
long todayPlan = 0, todayComplete = 0;
// 本月统计
long monthPlan = 0, monthComplete = 0;
// 按产线统计
Map<String, long[]> lineStats = new HashMap<>(); // [plan, complete, lineName]
Map<String, String> 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<AndonDashboardDTO.LineTaskCompletion> lineCompletions = new ArrayList<>();
for (Map.Entry<String, long[]> 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<BaseDeviceLedger> 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<AndonDashboardDTO.DeviceOeeDetail> 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<BaseDeviceLedger> devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query);
if (devices == null || devices.isEmpty()) {
summary.setOverallUtilization(0);
summary.setLineUtilizations(new ArrayList<>());
return summary;
}
// 按产线分组计算利用率
Map<String, List<BaseDeviceLedger>> lineDevices = devices.stream()
.filter(d -> StringUtils.isNotEmpty(d.getProductLineCode()))
.collect(Collectors.groupingBy(BaseDeviceLedger::getProductLineCode));
long totalRunning = 0, totalPlanned = 0;
List<AndonDashboardDTO.LineUtilization> lineUtilizations = new ArrayList<>();
for (Map.Entry<String, List<BaseDeviceLedger>> entry : lineDevices.entrySet()) {
List<BaseDeviceLedger> 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<ProductPlanInfo> 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<String, long[]> lineStats = new HashMap<>(); // [output, good, defect]
Map<String, String> 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<AndonDashboardDTO.LineQuality> lineQualities = new ArrayList<>();
for (Map.Entry<String, long[]> 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<AndonEvent> events = andonEventMapper.selectAndonEventList(query);
if (events == null) events = new ArrayList<>();
// 获取今日日期范围
Date todayStart = DateUtils.parseDate(DateUtils.getDate());
Date todayEnd = DateUtils.addDays(todayStart, 1);
// 筛选今日事件
List<AndonEvent> 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<String, int[]> 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<AndonDashboardDTO.EventTypeStats> eventTypeStats = new ArrayList<>();
for (Map.Entry<String, int[]> 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();
}
}
Loading…
Cancel
Save