feat(andon): 添加手持设备安灯呼叫功能并优化规则匹配算法

- 新增 AndonMobileController 提供手持设备安灯呼叫接口
- 新增 AndonMobileCallRequest DTO 用于手持设备请求数据传输
- 实现 /call-types 接口获取工位可用呼叫类型列表
- 实现 /call 接口处理手持设备安灯呼叫提交
- 优化 AndonEventAssignmentServiceImpl 规则匹配逻辑,添加 pickBestRule 方法
- 修复安灯事件插入时的事务回滚问题,添加 @Transactional 注解
- 更新版权年份至2026年
- 完善安灯事件创建时的呼叫单号生成规则
master
zangch@mesnac.com 2 days ago
parent 4c790c5206
commit 2eb76b394b

@ -5,7 +5,7 @@ ruoyi:
# 版本
version: 3.8.6
# 版权年份
copyrightYear: 2023
copyrightYear: 2026
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath

@ -0,0 +1,176 @@
package com.aucma.production.controller;
import com.aucma.base.domain.BaseProcessStation;
import com.aucma.base.service.IBaseProcessStationService;
import com.aucma.common.constant.AnDonConstants;
import com.aucma.common.core.domain.AjaxResult;
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.AndonRule;
import com.aucma.production.mapper.AndonRuleMapper;
import com.aucma.production.service.IAndonEventService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
*
*
* 1. PDAstationCode
* 2. PDA /call-types
* 3. PDA
* 4. PDA /call stationCode + callTypeCode
* 5.
* 6.
*
* @author Yinq
* @date 2025-12-29
*/
@RestController
@RequestMapping("/production/andon/mobile")
public class AndonMobileController {
@Autowired
private IBaseProcessStationService baseProcessStationService;
@Autowired
private AndonRuleMapper andonRuleMapper;
@Autowired
private IAndonEventService andonEventService;
/**
* 1
*
* PDA
*
* @param stationCode
* @return [{callTypeCode, callTypeName, ruleName}]
*/
@GetMapping("/call-types")
public AjaxResult getCallTypes(@RequestParam String stationCode) {
if (StringUtils.isEmpty(stationCode)) {
return AjaxResult.error("工位编码不能为空");
}
// 查询该工位配置的所有安灯规则
AndonRule ruleQuery = new AndonRule();
ruleQuery.setStationCode(stationCode);
ruleQuery.setIsFlag(AnDonConstants.FLAG_VALID);
List<AndonRule> rules = andonRuleMapper.selectAndonRuleList(ruleQuery);
if (rules == null || rules.isEmpty()) {
return AjaxResult.error("该工位未配置安灯规则,请联系管理员");
}
// 构建返回数据
List<Map<String, Object>> callTypes = new ArrayList<>();
for (AndonRule rule : rules) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("callTypeCode", rule.getCallTypeCode());
item.put("ruleName", rule.getRuleName());
item.put("ruleId", rule.getRuleId());
callTypes.add(item);
}
return AjaxResult.success(callTypes);
}
/**
* 2
*
* @param stationCode
* @param callTypeCode - /call-types
* @return
*/
@PostMapping("/call")
public AjaxResult submitAndonCall(@RequestParam String stationCode,
@RequestParam String callTypeCode) {
System.out.println("stationCode: " + stationCode + ", callTypeCode: " + callTypeCode);
// 参数校验
if (StringUtils.isEmpty(stationCode)) {
return AjaxResult.error("工位编码不能为空");
}
if (StringUtils.isEmpty(callTypeCode)) {
return AjaxResult.error("呼叫类型不能为空");
}
// 1. 根据 stationCode 查询工位信息
BaseProcessStation stationQuery = new BaseProcessStation();
stationQuery.setProcessCode(stationCode);
List<BaseProcessStation> stations = baseProcessStationService.selectBaseProcessStationList(stationQuery);
if (stations == null || stations.isEmpty()) {
return AjaxResult.error("工位不存在:" + stationCode);
}
BaseProcessStation station = stations.get(0);
String productLineCode = station.getProductLineCode();
// 2. 根据 stationCode + callTypeCode 匹配安灯规则
AndonRule ruleQuery = new AndonRule();
ruleQuery.setStationCode(stationCode);
ruleQuery.setCallTypeCode(callTypeCode);
ruleQuery.setIsFlag(AnDonConstants.FLAG_VALID);
List<AndonRule> rules = andonRuleMapper.selectAndonRuleList(ruleQuery);
if (rules == null || rules.isEmpty()) {
return AjaxResult.error("未找到该工位+呼叫类型的安灯规则");
}
AndonRule rule = rules.get(0);
// 3. 构建安灯事件
AndonEvent event = new AndonEvent();
// 生成呼叫单号
event.setCallCode(generateCallCode());
// 从规则获取呼叫类型
event.setCallTypeCode(rule.getCallTypeCode());
// 从工位获取产线
event.setProductLineCode(productLineCode);
event.setStationCode(stationCode);
// 呼叫人可选默认为PDA
event.setCreateBy(SecurityUtils.getLoginUser().getUserId() != null ? SecurityUtils.getLoginUser().getUserId().toString() : "PDA");
// 触发源类型:工位
event.setSourceType(AnDonConstants.SourceType.STATION);
// 初始状态
event.setEventStatus(AnDonConstants.EventStatus.PENDING);
event.setIsFlag(AnDonConstants.FLAG_VALID);
event.setCreateTime(DateUtils.getNowDate());
// 4. 调用服务保存(自动匹配规则、计算时限、创建派工)
int result = andonEventService.insertAndonEvent(event);
if (result > 0) {
Map<String, Object> data = new LinkedHashMap<>();
data.put("eventId", event.getEventId());
data.put("callCode", event.getCallCode());
data.put("stationName", station.getStationName() != null ? station.getStationName() : station.getProcessName());
data.put("callType", rule.getRuleName());
data.put("message", "安灯呼叫成功,已通知相关人员");
return AjaxResult.success(data);
} else {
return AjaxResult.error("安灯呼叫失败");
}
}
/**
*
* AD + + 3
*/
private String generateCallCode() {
String dateStr = DateUtils.dateTimeNow("yyyyMMddHHmmss");
int random = (int) (Math.random() * 900) + 100; // 100-999
return "AD" + dateStr + random;
}
}

@ -0,0 +1,65 @@
package com.aucma.production.domain.dto;
import java.io.Serializable;
/**
* DTO
*
* PDA
* - stationCodePDA
* - callerUserName
* - description
*
* stationCode 线
*
* @author Yinq
* @date 2025-12-29
*/
public class AndonMobileCallRequest implements Serializable {
private static final long serialVersionUID = 1L;
/** 工位编码(必填)- PDA绑定的工位编码 */
private String stationCode;
/** 呼叫人用户名(可选)- 手持设备登录用户 */
private String callerUserName;
/** 问题描述(可选)- 用户输入的问题描述 */
private String description;
// ==================== Getter/Setter ====================
public String getStationCode() {
return stationCode;
}
public void setStationCode(String stationCode) {
this.stationCode = stationCode;
}
public String getCallerUserName() {
return callerUserName;
}
public void setCallerUserName(String callerUserName) {
this.callerUserName = callerUserName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "AndonMobileCallRequest{" +
"stationCode='" + stationCode + '\'' +
", callerUserName='" + callerUserName + '\'' +
", description='" + description + '\'' +
'}';
}
}

@ -170,9 +170,9 @@ public class AndonEventAssignmentServiceImpl implements IAndonEventAssignmentSer
AndonRule q = new AndonRule();
q.setCallTypeCode(e.getCallTypeCode());
q.setIsFlag(AnDonConstants.FLAG_VALID);
List<AndonRule> rules = andonRuleMapper.selectAndonRuleList(q);
if (rules == null || rules.isEmpty()) return false;
String remark = rules.get(0).getRemark();
AndonRule bestRule = pickBestRule(andonRuleMapper.selectAndonRuleList(q), e);
if (bestRule == null) return false;
String remark = bestRule.getRemark();
if (remark == null || remark.trim().isEmpty()) return true;
try {
com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
@ -185,6 +185,28 @@ public class AndonEventAssignmentServiceImpl implements IAndonEventAssignmentSer
}
}
/**
* AndonEventServiceImpl
* 线/// 1
*/
private AndonRule pickBestRule(List<AndonRule> rules, AndonEvent e) {
if (rules == null || rules.isEmpty() || e == null) return null;
AndonRule best = null;
int bestScore = -1;
for (AndonRule r : rules) {
int score = 0;
if (r.getProductLineCode() != null && r.getProductLineCode().equals(e.getProductLineCode())) score++;
if (r.getStationCode() != null && r.getStationCode().equals(e.getStationCode())) score++;
if (r.getTeamCode() != null && r.getTeamCode().equals(e.getTeamCode())) score++;
if (r.getSourceType() != null && r.getSourceType().equals(e.getSourceType())) score++;
if (score > bestScore) {
bestScore = score;
best = r;
}
}
return best;
}
/** 取消同一事件下除当前派工外的其他派工。 */
private void cancelOtherAssignments(Long eventId, Long currentAssignmentId) {
if (eventId == null) return;

@ -15,6 +15,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.aucma.common.constant.AnDonConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@ -71,6 +72,7 @@ public class AndonEventServiceImpl implements IAndonEventService
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int insertAndonEvent(AndonEvent andonEvent)
{
andonEvent.setCreateTime(DateUtils.getNowDate());

Loading…
Cancel
Save