feat(send-job): 新增炉火写入钢卷信息功能并优化发送作业服务
- 新增 FurnaceSendCoilInfoVO 类用于存储炉火写入的钢卷信息 - 在 SendJobController 中添加获取上次炉火写入钢卷信息的接口 - 在 SendJobServiceImpl 中实现炉火写入成功后自动存储钢卷信息到 Redis - 新增 getCurrentOnlineCoil 方法用于获取当前正在线上的钢卷 - 优化 CrmPdiPlanService 接口定义和实现类代码格式 - 修复 SendJobQueryServiceImpl 中的错误提示信息国际化 - 优化 SendJobServiceImpl 中的代码结构和依赖注入 - 添加完整的 Java 代码注释和文档说明
This commit is contained in:
@@ -35,7 +35,7 @@ public class BizSendTemplateController extends BaseController {
|
||||
public AjaxResult getByCode(@PathVariable String templateCode) {
|
||||
BizSendTemplateVO vo = templateService.getTemplateWithItems(templateCode);
|
||||
if (vo == null) {
|
||||
return AjaxResult.error("Template not found");
|
||||
return AjaxResult.error("模板未找到");
|
||||
}
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class BizSendTemplateController extends BaseController {
|
||||
@PutMapping
|
||||
public AjaxResult updateTemplate(@RequestBody BizSendTemplate template) {
|
||||
if (template == null || template.getTemplateId() == null) {
|
||||
return AjaxResult.error("templateId is required");
|
||||
return AjaxResult.error("模板ID是必需的");
|
||||
}
|
||||
template.setUpdateBy(SecurityUtils.getUsername());
|
||||
template.setUpdateTime(new Date());
|
||||
@@ -76,7 +76,7 @@ public class BizSendTemplateController extends BaseController {
|
||||
@PutMapping("/items/batchSave")
|
||||
public AjaxResult batchSaveItems(@RequestBody SendTemplateItemsBatchSaveDTO dto) {
|
||||
if (dto == null || dto.getTemplateId() == null) {
|
||||
return AjaxResult.error("templateId is required");
|
||||
return AjaxResult.error("模板ID是必需的");
|
||||
}
|
||||
try {
|
||||
Boolean ok = templateItemService.batchSave(
|
||||
|
||||
@@ -9,8 +9,11 @@ import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.fizz.business.domain.vo.FurnaceSendCoilInfoVO;
|
||||
import com.fizz.business.domain.vo.SendJobLastSuccessVO;
|
||||
import com.fizz.business.service.ISendJobQueryService;
|
||||
import com.fizz.business.utils.RedisUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -87,4 +90,24 @@ public class SendJobController extends BaseController {
|
||||
SendJobLastSuccessVO vo = sendJobQueryService.getLastSuccess(groupType);
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次炉火写入的钢卷信息
|
||||
* @return 上次写入的钢卷信息(coilId、planId、sendTime)
|
||||
*/
|
||||
@GetMapping("/furnace/lastCoilInfo")
|
||||
public AjaxResult getLastFurnaceSendCoilInfo() {
|
||||
try {
|
||||
String jsonValue = RedisUtil.getValue("furnace:send:coil:info");
|
||||
if (jsonValue == null || jsonValue.isEmpty()) {
|
||||
return AjaxResult.success(null);
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
FurnaceSendCoilInfoVO coilInfo = objectMapper.readValue(jsonValue, FurnaceSendCoilInfoVO.class);
|
||||
return AjaxResult.success(coilInfo);
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("获取上次炉火写入钢卷信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.fizz.business.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 炉火写入时的钢卷信息(存储到 Redis)
|
||||
*/
|
||||
@Data
|
||||
public class FurnaceSendCoilInfoVO {
|
||||
|
||||
/** 钢卷号 */
|
||||
private String coilId;
|
||||
|
||||
/** 计划ID */
|
||||
private String planId;
|
||||
|
||||
/** 写入时间 */
|
||||
private Date sendTime;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ import java.util.List;
|
||||
|
||||
public interface CrmPdiPlanService extends IService<CrmPdiPlan> {
|
||||
|
||||
CrmPdiPlanVO getByCoilIdAndOperId(String coilid);
|
||||
CrmPdiPlanVO getByCoilIdAndOperId(String coilid);
|
||||
|
||||
boolean addCrmPdiPlan(CrmPdiPlan crmPdiPlan);
|
||||
boolean addCrmPdiPlan(CrmPdiPlan crmPdiPlan);
|
||||
|
||||
boolean updateCrmPdiPlan(CrmPdiPlan crmPdiPlan);
|
||||
boolean updateCrmPdiPlan(CrmPdiPlan crmPdiPlan);
|
||||
|
||||
boolean deleteCrmPdiPlan(List<Long> coilid);
|
||||
boolean deleteCrmPdiPlan(List<Long> coilid);
|
||||
|
||||
List<CrmPdiPlanVO> listAll(PlanQueryForm form);
|
||||
List<CrmPdiPlanVO> listAll(PlanQueryForm form);
|
||||
|
||||
/**
|
||||
* 获取未生产的第一个钢卷(按顺序号或创建时间最早)
|
||||
@@ -29,4 +29,10 @@ public interface CrmPdiPlanService extends IService<CrmPdiPlan> {
|
||||
CrmPdiPlan getFirstUnProducedCoil();
|
||||
|
||||
void changeStatus(ChangePlanStatusForm build);
|
||||
|
||||
/**
|
||||
* 获取当前正在线上的钢卷(优先级:ONLINE > PRODUCING > READY/NEW)
|
||||
* @return 当前正在线上的钢卷,如果没有则返回null
|
||||
*/
|
||||
CrmPdiPlan getCurrentOnlineCoil();
|
||||
}
|
||||
|
||||
@@ -53,11 +53,11 @@ public class BizSendTemplateItemServiceImpl extends ServiceImpl<BizSendTemplateI
|
||||
Set<String> seen = new HashSet<>();
|
||||
for (BizSendTemplateItem it : items) {
|
||||
if (it.getParamCode() == null || it.getParamCode().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("paramCode is required");
|
||||
throw new IllegalArgumentException("参数编码是必需的");
|
||||
}
|
||||
String code = it.getParamCode().trim();
|
||||
if (!seen.add(code)) {
|
||||
throw new IllegalArgumentException("Duplicate paramCode in request: " + code);
|
||||
throw new IllegalArgumentException("请求中包含重复参数编码: " + code);
|
||||
}
|
||||
it.setParamCode(code);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class BizSendTemplateItemServiceImpl extends ServiceImpl<BizSendTemplateI
|
||||
}
|
||||
long cnt = this.count(qw);
|
||||
if (cnt > 0) {
|
||||
throw new IllegalArgumentException("paramCode already exists: " + it.getParamCode());
|
||||
throw new IllegalArgumentException("参数编码已存在: " + it.getParamCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public class CrmPdiPlanServiceImpl extends ServiceImpl<CrmPdiPlanMapper, CrmPdiP
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
public boolean addCrmPdiPlan(CrmPdiPlan crmPdiPlan) {
|
||||
crmPdiPlan.setStatus("READY");
|
||||
crmPdiPlan.setStatus("READY");
|
||||
|
||||
return this.save(crmPdiPlan);
|
||||
}
|
||||
@@ -169,4 +169,45 @@ public class CrmPdiPlanServiceImpl extends ServiceImpl<CrmPdiPlanMapper, CrmPdiP
|
||||
log.info("计划状态更新成功,ID: {}, 新状态: {}", build.getId(), build.getOperation());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前正在线上的钢卷(优先级:ONLINE > PRODUCING > READY/NEW)
|
||||
* @return 当前正在线上的钢卷,如果没有则返回null
|
||||
*/
|
||||
@Override
|
||||
public CrmPdiPlan getCurrentOnlineCoil() {
|
||||
|
||||
|
||||
// 1. 优先查找 PRODUCING 状态的钢卷
|
||||
CrmPdiPlan producingPlan = this.lambdaQuery()
|
||||
.eq(CrmPdiPlan::getStatus, "PRODUCING")
|
||||
.orderByAsc(CrmPdiPlan::getSeqid)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
|
||||
if (producingPlan != null) {
|
||||
return producingPlan;
|
||||
}
|
||||
|
||||
// 2. 其次查找 ONLINE 状态的钢卷
|
||||
CrmPdiPlan onlinePlan = this.lambdaQuery()
|
||||
.eq(CrmPdiPlan::getStatus, "ONLINE")
|
||||
.orderByAsc(CrmPdiPlan::getSeqid)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
|
||||
if (onlinePlan != null) {
|
||||
return onlinePlan;
|
||||
}
|
||||
|
||||
|
||||
// 3. 最后查找 READY 或 NEW 状态的钢卷(按顺序号排序,取第一个)
|
||||
CrmPdiPlan readyOrNewPlan = this.lambdaQuery()
|
||||
.in(CrmPdiPlan::getStatus, "READY", "NEW")
|
||||
.orderByAsc(CrmPdiPlan::getSeqid)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
|
||||
return readyOrNewPlan;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class SendJobQueryServiceImpl implements ISendJobQueryService {
|
||||
}
|
||||
|
||||
if (currentPlan == null) {
|
||||
return createEmptyResponse("No active or ready plan found.");
|
||||
return createEmptyResponse("未找到活跃或就绪的计划");
|
||||
}
|
||||
|
||||
// 将 CrmPdiPlan 对象的字段反射为 Map
|
||||
|
||||
@@ -13,8 +13,13 @@ import com.fizz.business.domain.vo.SendJobItemVO;
|
||||
import com.fizz.business.mapper.BizSendJobGroupMapper;
|
||||
import com.fizz.business.mapper.BizSendJobItemMapper;
|
||||
import com.fizz.business.mapper.BizSendJobMapper;
|
||||
import com.fizz.business.domain.CrmPdiPlan;
|
||||
import com.fizz.business.domain.vo.FurnaceSendCoilInfoVO;
|
||||
import com.fizz.business.service.CrmPdiPlanService;
|
||||
import com.fizz.business.service.ISendJobService;
|
||||
import com.fizz.business.service.manager.OpcMessageIdsManager;
|
||||
import com.fizz.business.utils.RedisUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -38,33 +43,38 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
|
||||
@Autowired
|
||||
private BizSendJobGroupMapper jobGroupMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private BizSendJobItemMapper jobItemMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private OpcMessageIdsManager opcMessageIdsManager;
|
||||
|
||||
@Autowired
|
||||
private CrmPdiPlanService crmPdiPlanService;
|
||||
|
||||
private static final String REDIS_KEY_FURNACE_SEND_COIL_INFO = "furnace:send:coil:info";
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer createSendJob(SendJobCreateDTO dto) {
|
||||
// 1. 创建批次
|
||||
BizSendJob job = new BizSendJob();
|
||||
BeanUtils.copyProperties(dto, job);
|
||||
|
||||
|
||||
// 生成业务唯一键
|
||||
String bizKey = opcMessageIdsManager.generateMessageId("SEND_JOB");
|
||||
job.setBizKey(bizKey);
|
||||
job.setStatus("PENDING");
|
||||
|
||||
|
||||
// 设置操作人
|
||||
String username = SecurityUtils.getUsername();
|
||||
job.setCreateBy(username);
|
||||
job.setCreateTime(new Date());
|
||||
|
||||
|
||||
// 保存批次
|
||||
baseMapper.insert(job);
|
||||
|
||||
|
||||
// 2. 保存分组与明细
|
||||
if (dto.getGroups() != null) {
|
||||
for (SendJobCreateDTO.GroupDTO groupDTO : dto.getGroups()) {
|
||||
@@ -76,7 +86,7 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
group.setCreateBy(username);
|
||||
group.setCreateTime(new Date());
|
||||
jobGroupMapper.insert(group);
|
||||
|
||||
|
||||
// 2.2 保存明细项
|
||||
if (groupDTO.getItems() != null) {
|
||||
for (SendJobCreateDTO.ItemDTO itemDTO : groupDTO.getItems()) {
|
||||
@@ -87,20 +97,20 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
item.setResultStatus("PENDING");
|
||||
item.setCreateBy(username);
|
||||
item.setCreateTime(new Date());
|
||||
|
||||
|
||||
// 尝试将valueRaw转为数值
|
||||
try {
|
||||
item.setValueNum(new BigDecimal(itemDTO.getValueRaw()));
|
||||
} catch (Exception e) {
|
||||
log.warn("转换数值失败: {}", itemDTO.getValueRaw(), e);
|
||||
}
|
||||
|
||||
|
||||
jobItemMapper.insert(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return job.getJobId();
|
||||
}
|
||||
|
||||
@@ -108,10 +118,10 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
public List<BizSendJob> selectSendJobList(SendJobQueryDTO query) {
|
||||
LambdaQueryWrapper<BizSendJob> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(StringUtils.isNotBlank(query.getDeviceName()),
|
||||
BizSendJob::getDeviceName, query.getDeviceName())
|
||||
.eq(StringUtils.isNotBlank(query.getStatus()),
|
||||
BizSendJob::getStatus, query.getStatus())
|
||||
.orderByDesc(BizSendJob::getCreateTime);
|
||||
BizSendJob::getDeviceName, query.getDeviceName())
|
||||
.eq(StringUtils.isNotBlank(query.getStatus()),
|
||||
BizSendJob::getStatus, query.getStatus())
|
||||
.orderByDesc(BizSendJob::getCreateTime);
|
||||
|
||||
List<BizSendJob> jobs = baseMapper.selectList(qw);
|
||||
if (jobs == null || jobs.isEmpty()) {
|
||||
@@ -124,9 +134,9 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
|
||||
List<Integer> jobIds = jobs.stream().map(BizSendJob::getJobId).collect(Collectors.toList());
|
||||
List<BizSendJobGroup> groups = jobGroupMapper.selectList(
|
||||
new LambdaQueryWrapper<BizSendJobGroup>()
|
||||
.in(BizSendJobGroup::getJobId, jobIds)
|
||||
.eq(BizSendJobGroup::getGroupType, gt)
|
||||
new LambdaQueryWrapper<BizSendJobGroup>()
|
||||
.in(BizSendJobGroup::getJobId, jobIds)
|
||||
.eq(BizSendJobGroup::getGroupType, gt)
|
||||
);
|
||||
if (groups == null || groups.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
@@ -146,55 +156,55 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
if (job == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 2. 转换为VO
|
||||
SendJobDetailVO detailVO = new SendJobDetailVO();
|
||||
BeanUtils.copyProperties(job, detailVO);
|
||||
|
||||
|
||||
// 3. 查询分组
|
||||
List<BizSendJobGroup> groups = jobGroupMapper.selectList(
|
||||
new LambdaQueryWrapper<BizSendJobGroup>()
|
||||
.eq(BizSendJobGroup::getJobId, jobId)
|
||||
.orderByAsc(BizSendJobGroup::getGroupNo)
|
||||
new LambdaQueryWrapper<BizSendJobGroup>()
|
||||
.eq(BizSendJobGroup::getJobId, jobId)
|
||||
.orderByAsc(BizSendJobGroup::getGroupNo)
|
||||
);
|
||||
|
||||
|
||||
if (groups.isEmpty()) {
|
||||
return detailVO;
|
||||
}
|
||||
|
||||
|
||||
// 4. 查询所有明细项
|
||||
List<Integer> groupIds = groups.stream()
|
||||
.map(BizSendJobGroup::getGroupId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
.map(BizSendJobGroup::getGroupId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<BizSendJobItem> items = jobItemMapper.selectList(
|
||||
new LambdaQueryWrapper<BizSendJobItem>()
|
||||
.in(BizSendJobItem::getGroupId, groupIds)
|
||||
new LambdaQueryWrapper<BizSendJobItem>()
|
||||
.in(BizSendJobItem::getGroupId, groupIds)
|
||||
);
|
||||
|
||||
|
||||
// 5. 按groupId分组
|
||||
Map<Integer, List<BizSendJobItem>> groupItemsMap = items.stream()
|
||||
.collect(Collectors.groupingBy(BizSendJobItem::getGroupId));
|
||||
|
||||
.collect(Collectors.groupingBy(BizSendJobItem::getGroupId));
|
||||
|
||||
// 6. 构建分组VO
|
||||
List<SendJobGroupVO> groupVOs = groups.stream().map(group -> {
|
||||
SendJobGroupVO groupVO = new SendJobGroupVO();
|
||||
BeanUtils.copyProperties(group, groupVO);
|
||||
|
||||
|
||||
// 设置分组下的明细项
|
||||
List<BizSendJobItem> groupItems = groupItemsMap
|
||||
.getOrDefault(group.getGroupId(), Collections.emptyList());
|
||||
|
||||
.getOrDefault(group.getGroupId(), Collections.emptyList());
|
||||
|
||||
List<SendJobItemVO> itemVOs = groupItems.stream().map(item -> {
|
||||
SendJobItemVO itemVO = new SendJobItemVO();
|
||||
BeanUtils.copyProperties(item, itemVO);
|
||||
return itemVO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
|
||||
groupVO.setItems(itemVOs);
|
||||
return groupVO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
|
||||
detailVO.setGroups(groupVOs);
|
||||
return detailVO;
|
||||
}
|
||||
@@ -244,16 +254,16 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
// 查询该job下所有 PENDING 的 item
|
||||
List<BizSendJobItem> items = jobItemMapper.selectList(
|
||||
new LambdaQueryWrapper<BizSendJobItem>()
|
||||
.eq(BizSendJobItem::getJobId, jobId)
|
||||
.eq(BizSendJobItem::getResultStatus, "PENDING")
|
||||
.eq(BizSendJobItem::getJobId, jobId)
|
||||
.eq(BizSendJobItem::getResultStatus, "PENDING")
|
||||
);
|
||||
|
||||
|
||||
// 如果没有 PENDING 的项,检查是否有其他状态的项
|
||||
if (items == null || items.isEmpty()) {
|
||||
boolean hasItems = jobItemMapper.selectCount(
|
||||
new LambdaQueryWrapper<BizSendJobItem>().eq(BizSendJobItem::getJobId, jobId)
|
||||
new LambdaQueryWrapper<BizSendJobItem>().eq(BizSendJobItem::getJobId, jobId)
|
||||
) > 0;
|
||||
|
||||
|
||||
BizSendJob finish = new BizSendJob();
|
||||
finish.setJobId(jobId);
|
||||
finish.setStatus(hasItems ? "COMPLETED" : "FAILED");
|
||||
@@ -338,6 +348,35 @@ public class SendJobServiceImpl extends ServiceImpl<BizSendJobMapper, BizSendJob
|
||||
finish.setRemark(allSuccess ? "全部发送成功" : "部分发送失败");
|
||||
baseMapper.updateById(finish);
|
||||
|
||||
// 如果是炉火写入(FURNACE),获取当前正在线上的钢卷信息并存储到 Redis
|
||||
try {
|
||||
boolean isFurnaceSend = groups.stream()
|
||||
.anyMatch(g -> "FURNACE".equalsIgnoreCase(g.getGroupType()));
|
||||
|
||||
if (isFurnaceSend && allSuccess) {
|
||||
CrmPdiPlan currentCoil = crmPdiPlanService.getCurrentOnlineCoil();
|
||||
if (currentCoil != null) {
|
||||
FurnaceSendCoilInfoVO coilInfo = new FurnaceSendCoilInfoVO();
|
||||
coilInfo.setCoilId(currentCoil.getCoilid());
|
||||
coilInfo.setPlanId(currentCoil.getPlanid());
|
||||
coilInfo.setSendTime(new Date());
|
||||
|
||||
// 存储到 Redis(使用 JSON 格式)
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String jsonValue = objectMapper.writeValueAsString(coilInfo);
|
||||
RedisUtil.setValue(REDIS_KEY_FURNACE_SEND_COIL_INFO, jsonValue);
|
||||
|
||||
log.info("炉火写入成功,已保存钢卷信息到 Redis: coilId={}, planId={}",
|
||||
coilInfo.getCoilId(), coilInfo.getPlanId());
|
||||
} else {
|
||||
log.warn("炉火写入成功,但未找到当前正在线上的钢卷");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("保存炉火写入钢卷信息到 Redis 失败", e);
|
||||
// 不影响主流程,只记录日志
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user