From 5c7db3994099595bf75c213b6edbddfadce010b9 Mon Sep 17 00:00:00 2001 From: 86156 <823267011@qq.com> Date: Wed, 31 Dec 2025 17:59:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=99=E5=85=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/comm/OPC/OpcMessageSend.java | 53 +++ .../controller/BizSendTemplateController.java | 31 ++ .../controller/SendJobController.java | 90 +++++ .../com/fizz/business/domain/BizSendJob.java | 51 +++ .../fizz/business/domain/BizSendJobGroup.java | 40 +++ .../fizz/business/domain/BizSendJobItem.java | 58 ++++ .../fizz/business/domain/BizSendTemplate.java | 35 ++ .../business/domain/BizSendTemplateItem.java | 43 +++ .../business/domain/dto/SendJobCreateDTO.java | 76 +++++ .../business/domain/dto/SendJobQueryDTO.java | 18 + .../domain/vo/BizSendTemplateItemVO.java | 19 ++ .../business/domain/vo/BizSendTemplateVO.java | 21 ++ .../business/domain/vo/SendJobDetailVO.java | 26 ++ .../business/domain/vo/SendJobGroupVO.java | 27 ++ .../business/domain/vo/SendJobItemVO.java | 38 +++ .../domain/vo/SendJobLastSuccessVO.java | 23 ++ .../fizz/business/domain/vo/SendJobVO.java | 27 ++ .../mapper/BizSendJobGroupMapper.java | 10 + .../business/mapper/BizSendJobItemMapper.java | 10 + .../business/mapper/BizSendJobMapper.java | 10 + .../mapper/BizSendTemplateItemMapper.java | 10 + .../mapper/BizSendTemplateMapper.java | 10 + .../service/IBizSendTemplateService.java | 17 + .../service/ISendJobQueryService.java | 15 + .../business/service/ISendJobService.java | 41 +++ .../impl/BizSendTemplateServiceImpl.java | 55 +++ .../service/impl/SendJobQueryServiceImpl.java | 77 +++++ .../service/impl/SendJobServiceImpl.java | 320 ++++++++++++++++++ .../service/manager/OpcMessageIdsManager.java | 11 + 29 files changed, 1262 insertions(+) create mode 100644 business/src/main/java/com/fizz/business/controller/BizSendTemplateController.java create mode 100644 business/src/main/java/com/fizz/business/controller/SendJobController.java create mode 100644 business/src/main/java/com/fizz/business/domain/BizSendJob.java create mode 100644 business/src/main/java/com/fizz/business/domain/BizSendJobGroup.java create mode 100644 business/src/main/java/com/fizz/business/domain/BizSendJobItem.java create mode 100644 business/src/main/java/com/fizz/business/domain/BizSendTemplate.java create mode 100644 business/src/main/java/com/fizz/business/domain/BizSendTemplateItem.java create mode 100644 business/src/main/java/com/fizz/business/domain/dto/SendJobCreateDTO.java create mode 100644 business/src/main/java/com/fizz/business/domain/dto/SendJobQueryDTO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateItemVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/SendJobDetailVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/SendJobGroupVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/SendJobItemVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/SendJobLastSuccessVO.java create mode 100644 business/src/main/java/com/fizz/business/domain/vo/SendJobVO.java create mode 100644 business/src/main/java/com/fizz/business/mapper/BizSendJobGroupMapper.java create mode 100644 business/src/main/java/com/fizz/business/mapper/BizSendJobItemMapper.java create mode 100644 business/src/main/java/com/fizz/business/mapper/BizSendJobMapper.java create mode 100644 business/src/main/java/com/fizz/business/mapper/BizSendTemplateItemMapper.java create mode 100644 business/src/main/java/com/fizz/business/mapper/BizSendTemplateMapper.java create mode 100644 business/src/main/java/com/fizz/business/service/IBizSendTemplateService.java create mode 100644 business/src/main/java/com/fizz/business/service/ISendJobQueryService.java create mode 100644 business/src/main/java/com/fizz/business/service/ISendJobService.java create mode 100644 business/src/main/java/com/fizz/business/service/impl/BizSendTemplateServiceImpl.java create mode 100644 business/src/main/java/com/fizz/business/service/impl/SendJobQueryServiceImpl.java create mode 100644 business/src/main/java/com/fizz/business/service/impl/SendJobServiceImpl.java diff --git a/business/src/main/java/com/fizz/business/comm/OPC/OpcMessageSend.java b/business/src/main/java/com/fizz/business/comm/OPC/OpcMessageSend.java index c1effdd..9e31632 100644 --- a/business/src/main/java/com/fizz/business/comm/OPC/OpcMessageSend.java +++ b/business/src/main/java/com/fizz/business/comm/OPC/OpcMessageSend.java @@ -61,6 +61,59 @@ public class OpcMessageSend { } } + /** + * 通用写入方法,用于向指定 OPC 节点写入一个值 + * @param address OPC 节点地址 (e.g., "ns=2;s=ProcessCGL.PLCLine.ExitCut.cutLength") + * @param value 要写入的值 + */ + public void writeNode(String address, Object value) { + try { + List entities = new ArrayList<>(); + entities.add(ReadWriteEntity.builder() + .identifier(address) + .value(value) + .build()); + miloService.writeToOpcUa(entities); + log.info("写入 OPC 成功, node={}, value={}", address, value); + } catch (Exception e) { + log.error("写入 OPC 失败, node={}, value={}, 原因: {}", address, value, e.getMessage(), e); + // 抛出运行时异常,以便上层调用者(如 SendJobServiceImpl)可以捕获并处理失败状态 + throw new RuntimeException("写入 OPC 失败: " + e.getMessage(), e); + } + } + + /** + * 写入 OPC 节点(增强版):根据字符串值尝试转换为数值/布尔,再写入 + * 规则: + * 1) 先尝试转 Integer + * 2) 再尝试转 Double + * 3) 再尝试转 Boolean(true/false/1/0) + * 4) 都不行则按原字符串写入 + */ + public void writeNode(String address, String valueRaw) { + Object v = valueRaw; + if (valueRaw != null) { + String s = valueRaw.trim(); + // boolean + if ("1".equals(s) || "0".equals(s) || "true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) { + v = ("1".equals(s) || "true".equalsIgnoreCase(s)); + } else { + // int + try { + v = Integer.parseInt(s); + } catch (Exception ignore) { + // double + try { + v = Double.parseDouble(s); + } catch (Exception ignore2) { + v = valueRaw; + } + } + } + } + writeNode(address, v); + } + private List getWriteEntities(OpcMessage msg, Map msgIds) { List entities = new ArrayList<>(); for (String key : msgIds.keySet()) { diff --git a/business/src/main/java/com/fizz/business/controller/BizSendTemplateController.java b/business/src/main/java/com/fizz/business/controller/BizSendTemplateController.java new file mode 100644 index 0000000..ebfdd3a --- /dev/null +++ b/business/src/main/java/com/fizz/business/controller/BizSendTemplateController.java @@ -0,0 +1,31 @@ +package com.fizz.business.controller; + +import com.fizz.business.domain.vo.BizSendTemplateVO; +import com.fizz.business.service.IBizSendTemplateService; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 发送模板配置 Controller + */ +@RestController +@RequestMapping("/business/sendTemplate") +public class BizSendTemplateController extends BaseController { + + @Autowired + private IBizSendTemplateService templateService; + + /** + * 按模板编码获取模板(含明细) + */ + @GetMapping("/{templateCode}") + public AjaxResult getByCode(@PathVariable String templateCode) { + BizSendTemplateVO vo = templateService.getTemplateWithItems(templateCode); + if (vo == null) { + return AjaxResult.error("Template not found"); + } + return AjaxResult.success(vo); + } +} diff --git a/business/src/main/java/com/fizz/business/controller/SendJobController.java b/business/src/main/java/com/fizz/business/controller/SendJobController.java new file mode 100644 index 0000000..65b9260 --- /dev/null +++ b/business/src/main/java/com/fizz/business/controller/SendJobController.java @@ -0,0 +1,90 @@ +package com.fizz.business.controller; + +import com.fizz.business.domain.BizSendJob; +import com.fizz.business.domain.dto.SendJobCreateDTO; +import com.fizz.business.domain.dto.SendJobQueryDTO; +import com.fizz.business.domain.vo.SendJobDetailVO; +import com.fizz.business.service.ISendJobService; +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.SendJobLastSuccessVO; +import com.fizz.business.service.ISendJobQueryService; +import com.ruoyi.common.annotation.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 发送任务 Controller + */ +@RestController +@RequestMapping("/business/sendJob") +public class SendJobController extends BaseController { + + @Autowired + private ISendJobService sendJobService; + + @Autowired + private ISendJobQueryService sendJobQueryService; + + /** + * 创建发送任务 + */ + @Log(title = "发送任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult create(@Validated @RequestBody SendJobCreateDTO dto) { + Integer jobId = sendJobService.createSendJob(dto); + return success(jobId); + } + + /** + * 查询发送任务列表 + */ + @GetMapping("/list") + public TableDataInfo list(SendJobQueryDTO query) { + startPage(); // 使用BaseController的分页方法 + List list = sendJobService.selectSendJobList(query); + return getDataTable(list); + } + + /** + * 获取发送任务详情 + */ + @GetMapping("/{jobId}") + public AjaxResult getDetail(@PathVariable Integer jobId) { + SendJobDetailVO detail = sendJobService.selectSendJobDetail(jobId); + return success(detail); + } + + /** + * 删除发送任务(逻辑删除) + */ + @Log(title = "发送任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{jobIds}") + public AjaxResult remove(@PathVariable Integer[] jobIds) { + return toAjax(sendJobService.deleteSendJobByJobIds(jobIds)); + } + + /** + * 执行发送任务 + */ + @Log(title = "发送任务", businessType = BusinessType.UPDATE) + @PostMapping("/{jobId}/execute") + public AjaxResult execute(@PathVariable Integer jobId) { + return toAjax(sendJobService.executeSendJob(jobId)); + } + + /** + * 查询最近一次成功发送(用于界面显示上次发送时间 + 推荐上次值) + * @param groupType DRIVE / FURNACE + */ + @GetMapping("/lastSuccess") + public AjaxResult lastSuccess(@RequestParam String groupType) { + SendJobLastSuccessVO vo = sendJobQueryService.getLastSuccess(groupType); + return AjaxResult.success(vo); + } +} diff --git a/business/src/main/java/com/fizz/business/domain/BizSendJob.java b/business/src/main/java/com/fizz/business/domain/BizSendJob.java new file mode 100644 index 0000000..10cd8b4 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/BizSendJob.java @@ -0,0 +1,51 @@ +package com.fizz.business.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +/** + * 业务发送批次表 biz_send_job + * + * @author Cascade + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("biz_send_job") +public class BizSendJob extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 批次ID */ + @TableId(type = IdType.AUTO) + private Integer jobId; + + /** 业务唯一键, 用于幂等控制 */ + private String bizKey; + + /** 目标设备/产线名称 (如 CGL_LINE_1, FURNACE_A) */ + private String deviceName; + + /** 计划发送时间 */ + private Date planSendTime; + + /** 实际开始发送时间 */ + private Date actualSendTime; + + /** 发送完成时间 */ + private Date finishTime; + + /** 批次状态: PENDING, IN_PROGRESS, COMPLETED, PARTIAL_SUCCESS, FAILED */ + private String status; + + /** 操作员ID */ + private Long operatorId; + + /** 操作员姓名 */ + private String operatorName; +} + diff --git a/business/src/main/java/com/fizz/business/domain/BizSendJobGroup.java b/business/src/main/java/com/fizz/business/domain/BizSendJobGroup.java new file mode 100644 index 0000000..6060028 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/BizSendJobGroup.java @@ -0,0 +1,40 @@ +package com.fizz.business.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 业务发送分组表 biz_send_job_group + * + * @author Cascade + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("biz_send_job_group") +public class BizSendJobGroup extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 分组ID */ + @TableId(type = IdType.AUTO) + private Integer groupId; + + /** 所属批次ID */ + private Integer jobId; + + /** 在本批次内的组序号 */ + private Integer groupNo; + + /** 组类型: DRIVE(传动), FURNACE(炉火) */ + private String groupType; + + /** 组名称 (可选) */ + private String groupName; + + /** 分组状态: PENDING, IN_PROGRESS, COMPLETED, FAILED */ + private String status; +} + diff --git a/business/src/main/java/com/fizz/business/domain/BizSendJobItem.java b/business/src/main/java/com/fizz/business/domain/BizSendJobItem.java new file mode 100644 index 0000000..b548334 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/BizSendJobItem.java @@ -0,0 +1,58 @@ +package com.fizz.business.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 业务发送项历史表 biz_send_job_item + * + * @author Cascade + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("biz_send_job_item") +public class BizSendJobItem extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 发送项ID */ + @TableId(type = IdType.AUTO) + private Integer itemId; + + /** 所属批次ID (冗余) */ + private Integer jobId; + + /** 所属分组ID */ + private Integer groupId; + + /** 参数业务编码 */ + private String paramCode; + + /** 设定地址 (OPC地址) */ + private String address; + + /** 设定的原始值 */ + private String valueRaw; + + /** 设定值的数值形式 */ + private BigDecimal valueNum; + + /** 参数的设定时间 */ + private Date setTime; + + /** 发送结果: PENDING, SUCCESS, FAILED */ + private String resultStatus; + + /** 结果消息 */ + private String resultMsg; + + /** 重试次数 */ + private Integer retryCount; +} + diff --git a/business/src/main/java/com/fizz/business/domain/BizSendTemplate.java b/business/src/main/java/com/fizz/business/domain/BizSendTemplate.java new file mode 100644 index 0000000..9077444 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/BizSendTemplate.java @@ -0,0 +1,35 @@ +package com.fizz.business.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发送默认模板主表 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("biz_send_template") +public class BizSendTemplate extends BaseEntity { + @TableId(type = IdType.AUTO) + private Integer templateId; + + /** 模板编码 */ + private String templateCode; + + /** 模板名称 */ + private String templateName; + + /** 默认设备名称 */ + private String deviceName; + + /** 组类型 DRIVE / FURNACE */ + private String groupType; + + /** 是否启用 */ + private Integer enabled; +} + diff --git a/business/src/main/java/com/fizz/business/domain/BizSendTemplateItem.java b/business/src/main/java/com/fizz/business/domain/BizSendTemplateItem.java new file mode 100644 index 0000000..5eed05b --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/BizSendTemplateItem.java @@ -0,0 +1,43 @@ +package com.fizz.business.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发送默认模板明细表 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("biz_send_template_item") +public class BizSendTemplateItem extends BaseEntity { + @TableId(type = IdType.AUTO) + private Integer templateItemId; + + private Integer templateId; + + /** 明细序号 */ + private Integer itemNo; + + /** 参数编码 */ + private String paramCode; + + /** 英文显示名 */ + private String labelEn; + + /** 英文分组名 */ + private String groupNameEn; + + /** OPC地址 */ + private String address; + + /** 默认值(字符串) */ + private String defaultValueRaw; + + /** 是否启用 */ + private Integer enabled; +} + diff --git a/business/src/main/java/com/fizz/business/domain/dto/SendJobCreateDTO.java b/business/src/main/java/com/fizz/business/domain/dto/SendJobCreateDTO.java new file mode 100644 index 0000000..df26ce5 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/dto/SendJobCreateDTO.java @@ -0,0 +1,76 @@ +package com.fizz.business.domain.dto; + +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; +import java.util.List; + +/** + * 创建发送任务 DTO + */ +@Data +public class SendJobCreateDTO { + + /** 目标设备/产线名称 (如 CGL_LINE_1, FURNACE_A) */ + @NotBlank(message = "deviceName不能为空") + private String deviceName; + + /** 计划发送时间 */ + private Date planSendTime; + + /** 操作员ID */ + private Long operatorId; + + /** 操作员姓名 */ + private String operatorName; + + /** 分组列表 */ + @Valid + @NotNull(message = "groups不能为空") + @Size(min = 1, message = "至少需要一个分组") + private List groups; + + @Data + public static class GroupDTO { + + /** 在本批次内的组序号 */ + @NotNull(message = "groupNo不能为空") + private Integer groupNo; + + /** 组类型: DRIVE(传动), FURNACE(炉火) */ + @NotBlank(message = "groupType不能为空") + private String groupType; + + /** 组名称 (可选) */ + private String groupName; + + /** 参数项列表 */ + @Valid + @NotNull(message = "items不能为空") + @Size(min = 1, message = "至少需要一个参数项") + private List items; + } + + @Data + public static class ItemDTO { + + /** 参数业务编码 */ + private String paramCode; + + /** 设定地址 (OPC地址) */ + @NotBlank(message = "address不能为空") + private String address; + + /** 设定的原始值 */ + @NotBlank(message = "valueRaw不能为空") + private String valueRaw; + + /** 参数的设定时间 */ + private Date setTime; + } +} + diff --git a/business/src/main/java/com/fizz/business/domain/dto/SendJobQueryDTO.java b/business/src/main/java/com/fizz/business/domain/dto/SendJobQueryDTO.java new file mode 100644 index 0000000..adbf14f --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/dto/SendJobQueryDTO.java @@ -0,0 +1,18 @@ +package com.fizz.business.domain.dto; + +import lombok.Data; + +/** + * 发送任务查询 DTO + * 说明:分页参数沿用 RuoYi BaseController 的 startPage() 机制,从 request 里取 pageNum/pageSize。 + */ +@Data +public class SendJobQueryDTO { + + /** 设备/产线名称 */ + private String deviceName; + + /** 状态: PENDING, IN_PROGRESS, COMPLETED, PARTIAL_SUCCESS, FAILED, DELETED */ + private String status; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateItemVO.java b/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateItemVO.java new file mode 100644 index 0000000..185ae96 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateItemVO.java @@ -0,0 +1,19 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +/** + * 模板明细 VO + */ +@Data +public class BizSendTemplateItemVO { + private Integer templateItemId; + private Integer templateId; + private Integer itemNo; + private String paramCode; + private String labelEn; + private String groupNameEn; + private String address; + private String defaultValueRaw; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateVO.java b/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateVO.java new file mode 100644 index 0000000..316dccd --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/BizSendTemplateVO.java @@ -0,0 +1,21 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 模板主VO(含明细) + */ +@Data +public class BizSendTemplateVO { + private Integer templateId; + private String templateCode; + private String templateName; + private String deviceName; + private String groupType; + private Integer enabled; + + private List items; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/SendJobDetailVO.java b/business/src/main/java/com/fizz/business/domain/vo/SendJobDetailVO.java new file mode 100644 index 0000000..ecf8e74 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/SendJobDetailVO.java @@ -0,0 +1,26 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import java.util.List; + +/** + * 发送任务详情 VO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SendJobDetailVO extends SendJobVO { + + private Date planSendTime; + + private Date actualSendTime; + + private Date finishTime; + + private String remark; + + private List groups; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/SendJobGroupVO.java b/business/src/main/java/com/fizz/business/domain/vo/SendJobGroupVO.java new file mode 100644 index 0000000..744a327 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/SendJobGroupVO.java @@ -0,0 +1,27 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 发送任务分组 VO + */ +@Data +public class SendJobGroupVO { + + private Integer groupId; + + private Integer jobId; + + private Integer groupNo; + + private String groupType; + + private String groupName; + + private String status; + + private List items; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/SendJobItemVO.java b/business/src/main/java/com/fizz/business/domain/vo/SendJobItemVO.java new file mode 100644 index 0000000..5504ed5 --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/SendJobItemVO.java @@ -0,0 +1,38 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 发送任务明细项 VO + */ +@Data +public class SendJobItemVO { + + private Integer itemId; + + private Integer jobId; + + private Integer groupId; + + private String paramCode; + + private String address; + + private String valueRaw; + + private BigDecimal valueNum; + + private Date setTime; + + private String resultStatus; + + private String resultMsg; + + private Integer retryCount; + + private LocalDateTime createTime; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/SendJobLastSuccessVO.java b/business/src/main/java/com/fizz/business/domain/vo/SendJobLastSuccessVO.java new file mode 100644 index 0000000..367b9df --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/SendJobLastSuccessVO.java @@ -0,0 +1,23 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 最近一次成功发送结果(用于前端推荐默认值 + 显示上次发送时间) + */ +@Data +public class SendJobLastSuccessVO { + + /** 最近一次成功发送时间(job.finish_time) */ + private Date lastSendTime; + + /** paramCode -> valueRaw */ + private Map values; + + /** 最近一次成功的jobId(可选) */ + private Integer jobId; +} + diff --git a/business/src/main/java/com/fizz/business/domain/vo/SendJobVO.java b/business/src/main/java/com/fizz/business/domain/vo/SendJobVO.java new file mode 100644 index 0000000..2804b4a --- /dev/null +++ b/business/src/main/java/com/fizz/business/domain/vo/SendJobVO.java @@ -0,0 +1,27 @@ +package com.fizz.business.domain.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 发送任务列表 VO + */ +@Data +public class SendJobVO { + + private Integer jobId; + + private String bizKey; + + private String deviceName; + + private String status; + + private Long operatorId; + + private String operatorName; + + private Date createTime; +} + diff --git a/business/src/main/java/com/fizz/business/mapper/BizSendJobGroupMapper.java b/business/src/main/java/com/fizz/business/mapper/BizSendJobGroupMapper.java new file mode 100644 index 0000000..6cf14d5 --- /dev/null +++ b/business/src/main/java/com/fizz/business/mapper/BizSendJobGroupMapper.java @@ -0,0 +1,10 @@ +package com.fizz.business.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.fizz.business.domain.BizSendJobGroup; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BizSendJobGroupMapper extends BaseMapper { +} + diff --git a/business/src/main/java/com/fizz/business/mapper/BizSendJobItemMapper.java b/business/src/main/java/com/fizz/business/mapper/BizSendJobItemMapper.java new file mode 100644 index 0000000..3639d7a --- /dev/null +++ b/business/src/main/java/com/fizz/business/mapper/BizSendJobItemMapper.java @@ -0,0 +1,10 @@ +package com.fizz.business.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.fizz.business.domain.BizSendJobItem; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BizSendJobItemMapper extends BaseMapper { +} + diff --git a/business/src/main/java/com/fizz/business/mapper/BizSendJobMapper.java b/business/src/main/java/com/fizz/business/mapper/BizSendJobMapper.java new file mode 100644 index 0000000..e44c172 --- /dev/null +++ b/business/src/main/java/com/fizz/business/mapper/BizSendJobMapper.java @@ -0,0 +1,10 @@ +package com.fizz.business.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.fizz.business.domain.BizSendJob; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BizSendJobMapper extends BaseMapper { +} + diff --git a/business/src/main/java/com/fizz/business/mapper/BizSendTemplateItemMapper.java b/business/src/main/java/com/fizz/business/mapper/BizSendTemplateItemMapper.java new file mode 100644 index 0000000..4487a17 --- /dev/null +++ b/business/src/main/java/com/fizz/business/mapper/BizSendTemplateItemMapper.java @@ -0,0 +1,10 @@ +package com.fizz.business.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.fizz.business.domain.BizSendTemplateItem; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BizSendTemplateItemMapper extends BaseMapper { +} + diff --git a/business/src/main/java/com/fizz/business/mapper/BizSendTemplateMapper.java b/business/src/main/java/com/fizz/business/mapper/BizSendTemplateMapper.java new file mode 100644 index 0000000..6eab0a6 --- /dev/null +++ b/business/src/main/java/com/fizz/business/mapper/BizSendTemplateMapper.java @@ -0,0 +1,10 @@ +package com.fizz.business.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.fizz.business.domain.BizSendTemplate; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BizSendTemplateMapper extends BaseMapper { +} + diff --git a/business/src/main/java/com/fizz/business/service/IBizSendTemplateService.java b/business/src/main/java/com/fizz/business/service/IBizSendTemplateService.java new file mode 100644 index 0000000..230e4d2 --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/IBizSendTemplateService.java @@ -0,0 +1,17 @@ +package com.fizz.business.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.fizz.business.domain.BizSendTemplate; +import com.fizz.business.domain.vo.BizSendTemplateVO; + +/** + * 发送默认模板 Service + */ +public interface IBizSendTemplateService extends IService { + + /** + * 按模板编码获取模板(含明细) + */ + BizSendTemplateVO getTemplateWithItems(String templateCode); +} + diff --git a/business/src/main/java/com/fizz/business/service/ISendJobQueryService.java b/business/src/main/java/com/fizz/business/service/ISendJobQueryService.java new file mode 100644 index 0000000..2dcf5c8 --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/ISendJobQueryService.java @@ -0,0 +1,15 @@ +package com.fizz.business.service; + +import com.fizz.business.domain.vo.SendJobLastSuccessVO; + +/** + * 发送任务查询扩展(用于推荐值、上次发送时间) + */ +public interface ISendJobQueryService { + + /** + * 查询最近一次成功发送(按 groupType 过滤:DRIVE / FURNACE) + */ + SendJobLastSuccessVO getLastSuccess(String groupType); +} + diff --git a/business/src/main/java/com/fizz/business/service/ISendJobService.java b/business/src/main/java/com/fizz/business/service/ISendJobService.java new file mode 100644 index 0000000..6403ced --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/ISendJobService.java @@ -0,0 +1,41 @@ +package com.fizz.business.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.fizz.business.domain.BizSendJob; +import com.fizz.business.domain.dto.SendJobCreateDTO; +import com.fizz.business.domain.dto.SendJobQueryDTO; +import com.fizz.business.domain.vo.SendJobDetailVO; + +import java.util.List; + +/** + * 发送任务 Service + */ +public interface ISendJobService extends IService { + + /** + * 创建发送任务(包含分组与明细) + */ + Integer createSendJob(SendJobCreateDTO dto); + + /** + * 查询发送任务列表(分页由 Controller 的 startPage() 控制) + */ + List selectSendJobList(SendJobQueryDTO query); + + /** + * 查询发送任务详情(包含分组与明细) + */ + SendJobDetailVO selectSendJobDetail(Integer jobId); + + /** + * 删除任务(逻辑删除:status=DELETED) + */ + Boolean deleteSendJobByJobIds(Integer[] jobIds); + + /** + * 执行发送:写入 OPC,并将发送结果保存为历史(更新 job/group/item 状态) + */ + Boolean executeSendJob(Integer jobId); +} + diff --git a/business/src/main/java/com/fizz/business/service/impl/BizSendTemplateServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/BizSendTemplateServiceImpl.java new file mode 100644 index 0000000..7a15983 --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/impl/BizSendTemplateServiceImpl.java @@ -0,0 +1,55 @@ +package com.fizz.business.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fizz.business.domain.BizSendTemplate; +import com.fizz.business.domain.BizSendTemplateItem; +import com.fizz.business.domain.vo.BizSendTemplateItemVO; +import com.fizz.business.domain.vo.BizSendTemplateVO; +import com.fizz.business.mapper.BizSendTemplateItemMapper; +import com.fizz.business.mapper.BizSendTemplateMapper; +import com.fizz.business.service.IBizSendTemplateService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class BizSendTemplateServiceImpl extends ServiceImpl implements IBizSendTemplateService { + + @Autowired + private BizSendTemplateItemMapper templateItemMapper; + + @Override + public BizSendTemplateVO getTemplateWithItems(String templateCode) { + BizSendTemplate template = this.lambdaQuery() + .eq(BizSendTemplate::getTemplateCode, templateCode) + .eq(BizSendTemplate::getEnabled, 1) + .one(); + + if (template == null) { + return null; + } + + List items = templateItemMapper.selectList( + new LambdaQueryWrapper() + .eq(BizSendTemplateItem::getTemplateId, template.getTemplateId()) + .eq(BizSendTemplateItem::getEnabled, 1) + .orderByAsc(BizSendTemplateItem::getItemNo) + ); + + BizSendTemplateVO vo = new BizSendTemplateVO(); + BeanUtils.copyProperties(template, vo); + + List itemVOs = items.stream().map(item -> { + BizSendTemplateItemVO it = new BizSendTemplateItemVO(); + BeanUtils.copyProperties(item, it); + return it; + }).collect(Collectors.toList()); + + vo.setItems(itemVOs); + return vo; + } +} diff --git a/business/src/main/java/com/fizz/business/service/impl/SendJobQueryServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/SendJobQueryServiceImpl.java new file mode 100644 index 0000000..3f1226a --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/impl/SendJobQueryServiceImpl.java @@ -0,0 +1,77 @@ +package com.fizz.business.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fizz.business.domain.BizSendJob; +import com.fizz.business.domain.BizSendJobGroup; +import com.fizz.business.domain.BizSendJobItem; +import com.fizz.business.domain.vo.SendJobLastSuccessVO; +import com.fizz.business.mapper.BizSendJobGroupMapper; +import com.fizz.business.mapper.BizSendJobItemMapper; +import com.fizz.business.mapper.BizSendJobMapper; +import com.fizz.business.service.ISendJobQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class SendJobQueryServiceImpl implements ISendJobQueryService { + + @Autowired + private BizSendJobMapper jobMapper; + + @Autowired + private BizSendJobGroupMapper groupMapper; + + @Autowired + private BizSendJobItemMapper itemMapper; + + @Override + public SendJobLastSuccessVO getLastSuccess(String groupType) { + // 1) 先找最近一次 COMPLETED 的 job(倒序) + BizSendJob lastJob = jobMapper.selectOne( + new LambdaQueryWrapper() + .eq(BizSendJob::getStatus, "COMPLETED") + .orderByDesc(BizSendJob::getFinishTime) + .last("LIMIT 1") + ); + if (lastJob == null) { + return null; + } + + // 2) 找该 job 下对应 groupType 的 groups + List groups = groupMapper.selectList( + new LambdaQueryWrapper() + .eq(BizSendJobGroup::getJobId, lastJob.getJobId()) + .eq(groupType != null && !groupType.trim().isEmpty(), BizSendJobGroup::getGroupType, groupType) + ); + if (groups == null || groups.isEmpty()) { + return null; + } + + List groupIds = groups.stream().map(BizSendJobGroup::getGroupId).collect(java.util.stream.Collectors.toList()); + + // 3) 取这些 group 的 item,按 paramCode 聚合最后一次值(同 paramCode 取最后一条 itemId 最大) + List items = itemMapper.selectList( + new LambdaQueryWrapper() + .in(BizSendJobItem::getGroupId, groupIds) + .eq(BizSendJobItem::getResultStatus, "SUCCESS") + .orderByAsc(BizSendJobItem::getItemId) + ); + + Map values = new HashMap<>(); + for (BizSendJobItem it : items) { + if (it.getParamCode() == null) continue; + values.put(it.getParamCode(), it.getValueRaw()); + } + + SendJobLastSuccessVO vo = new SendJobLastSuccessVO(); + vo.setJobId(lastJob.getJobId()); + vo.setLastSendTime(lastJob.getFinishTime()); + vo.setValues(values); + return vo; + } +} + diff --git a/business/src/main/java/com/fizz/business/service/impl/SendJobServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/SendJobServiceImpl.java new file mode 100644 index 0000000..698af5a --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/impl/SendJobServiceImpl.java @@ -0,0 +1,320 @@ +package com.fizz.business.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fizz.business.domain.BizSendJob; +import com.fizz.business.domain.BizSendJobGroup; +import com.fizz.business.domain.BizSendJobItem; +import com.fizz.business.domain.dto.SendJobCreateDTO; +import com.fizz.business.domain.dto.SendJobQueryDTO; +import com.fizz.business.domain.vo.SendJobDetailVO; +import com.fizz.business.domain.vo.SendJobGroupVO; +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.service.ISendJobService; +import com.fizz.business.service.manager.OpcMessageIdsManager; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class SendJobServiceImpl extends ServiceImpl implements ISendJobService { + + @Autowired + private com.fizz.business.comm.OPC.OpcMessageSend opcMessageSend; + + + @Autowired + private BizSendJobGroupMapper jobGroupMapper; + + @Autowired + private BizSendJobItemMapper jobItemMapper; + + @Autowired + private OpcMessageIdsManager opcMessageIdsManager; + + @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()) { + // 2.1 保存分组 + BizSendJobGroup group = new BizSendJobGroup(); + BeanUtils.copyProperties(groupDTO, group); + group.setJobId(job.getJobId()); + group.setStatus("PENDING"); + group.setCreateBy(username); + group.setCreateTime(new Date()); + jobGroupMapper.insert(group); + + // 2.2 保存明细项 + if (groupDTO.getItems() != null) { + for (SendJobCreateDTO.ItemDTO itemDTO : groupDTO.getItems()) { + BizSendJobItem item = new BizSendJobItem(); + BeanUtils.copyProperties(itemDTO, item); + item.setJobId(job.getJobId()); + item.setGroupId(group.getGroupId()); + 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(); + } + + @Override + public List selectSendJobList(SendJobQueryDTO query) { + LambdaQueryWrapper 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); + return baseMapper.selectList(qw); + } + + @Override + public SendJobDetailVO selectSendJobDetail(Integer jobId) { + // 1. 查询任务 + BizSendJob job = baseMapper.selectById(jobId); + if (job == null) { + return null; + } + + // 2. 转换为VO + SendJobDetailVO detailVO = new SendJobDetailVO(); + BeanUtils.copyProperties(job, detailVO); + + // 3. 查询分组 + List groups = jobGroupMapper.selectList( + new LambdaQueryWrapper() + .eq(BizSendJobGroup::getJobId, jobId) + .orderByAsc(BizSendJobGroup::getGroupNo) + ); + + if (groups.isEmpty()) { + return detailVO; + } + + // 4. 查询所有明细项 + List groupIds = groups.stream() + .map(BizSendJobGroup::getGroupId) + .collect(Collectors.toList()); + + List items = jobItemMapper.selectList( + new LambdaQueryWrapper() + .in(BizSendJobItem::getGroupId, groupIds) + ); + + // 5. 按groupId分组 + Map> groupItemsMap = items.stream() + .collect(Collectors.groupingBy(BizSendJobItem::getGroupId)); + + // 6. 构建分组VO + List groupVOs = groups.stream().map(group -> { + SendJobGroupVO groupVO = new SendJobGroupVO(); + BeanUtils.copyProperties(group, groupVO); + + // 设置分组下的明细项 + List groupItems = groupItemsMap + .getOrDefault(group.getGroupId(), Collections.emptyList()); + + List 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; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteSendJobByJobIds(Integer[] jobIds) { + if (jobIds == null || jobIds.length == 0) { + return true; + } + + // 1. 更新任务状态为已删除 + BizSendJob updateJob = new BizSendJob(); + updateJob.setStatus("DELETED"); + updateJob.setUpdateBy(SecurityUtils.getUsername()); + updateJob.setUpdateTime(new Date()); + + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.in(BizSendJob::getJobId, Arrays.asList(jobIds)); + + return update(updateJob, qw); + } + + /** + * 执行发送:写入 OPC,并将发送结果保存为历史(更新 job/group/item 状态) + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean executeSendJob(Integer jobId) { + BizSendJob job = baseMapper.selectById(jobId); + if (job == null) { + return false; + } + if ("DELETED".equalsIgnoreCase(job.getStatus())) { + return false; + } + + // 更新 job 状态为发送中 + BizSendJob jobUpd = new BizSendJob(); + jobUpd.setJobId(jobId); + jobUpd.setStatus("IN_PROGRESS"); + jobUpd.setActualSendTime(new Date()); + jobUpd.setUpdateBy(SecurityUtils.getUsername()); + jobUpd.setUpdateTime(new Date()); + baseMapper.updateById(jobUpd); + + // 查询该job下所有 PENDING 的 item + List items = jobItemMapper.selectList( + new LambdaQueryWrapper() + .eq(BizSendJobItem::getJobId, jobId) + .eq(BizSendJobItem::getResultStatus, "PENDING") + ); + + // 如果没有 PENDING 的项,检查是否有其他状态的项 + if (items == null || items.isEmpty()) { + boolean hasItems = jobItemMapper.selectCount( + new LambdaQueryWrapper().eq(BizSendJobItem::getJobId, jobId) + ) > 0; + + BizSendJob finish = new BizSendJob(); + finish.setJobId(jobId); + finish.setStatus(hasItems ? "COMPLETED" : "FAILED"); + finish.setFinishTime(new Date()); + finish.setUpdateBy(SecurityUtils.getUsername()); + finish.setUpdateTime(new Date()); + finish.setRemark(hasItems ? "没有待发送的项" : "没有找到任何发送项"); + baseMapper.updateById(finish); + return hasItems; + } + + // 查询该job下group + List groups = jobGroupMapper.selectList( + new LambdaQueryWrapper().eq(BizSendJobGroup::getJobId, jobId) + ); + for (BizSendJobGroup g : groups) { + BizSendJobGroup gu = new BizSendJobGroup(); + gu.setGroupId(g.getGroupId()); + gu.setStatus("IN_PROGRESS"); + gu.setUpdateBy(SecurityUtils.getUsername()); + gu.setUpdateTime(new Date()); + jobGroupMapper.updateById(gu); + } + + boolean allSuccess = true; + + // 按 address 分组,只发送最后一条记录 + Map> itemsByAddr = items.stream() + .collect(Collectors.groupingBy(BizSendJobItem::getAddress)); + + for (Map.Entry> entry : itemsByAddr.entrySet()) { + List addrItems = entry.getValue(); + // 取最后一条(按 itemId 最大 || createTime 最新) + addrItems.sort(Comparator.comparing(BizSendJobItem::getItemId)); + BizSendJobItem last = addrItems.get(addrItems.size() - 1); + boolean success = true; + String failMsg = null; + try { + opcMessageSend.writeNode(last.getAddress(), last.getValueRaw()); + } catch (Exception ex) { + success = false; + allSuccess = false; + failMsg = ex.getMessage(); + } + + // 更新该 address 下所有项的状态(统一) + for (BizSendJobItem it : addrItems) { + BizSendJobItem upd = new BizSendJobItem(); + upd.setItemId(it.getItemId()); + upd.setResultStatus(success ? "SUCCESS" : "FAILED"); + upd.setResultMsg(success ? "OK" : failMsg); + upd.setUpdateBy(SecurityUtils.getUsername()); + upd.setUpdateTime(new Date()); + jobItemMapper.updateById(upd); + } + } + + // 更新 group 状态(按 group 下 item 是否全部成功) + Map> itemByGroup = jobItemMapper.selectList( + new LambdaQueryWrapper().eq(BizSendJobItem::getJobId, jobId) + ).stream().collect(Collectors.groupingBy(BizSendJobItem::getGroupId)); + + for (BizSendJobGroup g : groups) { + List gi = itemByGroup.getOrDefault(g.getGroupId(), Collections.emptyList()); + boolean groupOk = gi.stream().allMatch(x -> "SUCCESS".equalsIgnoreCase(x.getResultStatus())); + + BizSendJobGroup gu = new BizSendJobGroup(); + gu.setGroupId(g.getGroupId()); + gu.setStatus(groupOk ? "COMPLETED" : "FAILED"); + gu.setUpdateBy(SecurityUtils.getUsername()); + gu.setUpdateTime(new Date()); + jobGroupMapper.updateById(gu); + } + + // 更新 job 最终状态 + BizSendJob finish = new BizSendJob(); + finish.setJobId(jobId); + finish.setFinishTime(new Date()); + finish.setUpdateBy(SecurityUtils.getUsername()); + finish.setUpdateTime(new Date()); + finish.setStatus(allSuccess ? "COMPLETED" : "PARTIAL_SUCCESS"); + finish.setRemark(allSuccess ? "全部发送成功" : "部分发送失败"); + baseMapper.updateById(finish); + + return true; + } +} + diff --git a/business/src/main/java/com/fizz/business/service/manager/OpcMessageIdsManager.java b/business/src/main/java/com/fizz/business/service/manager/OpcMessageIdsManager.java index 029a9b2..a80836e 100644 --- a/business/src/main/java/com/fizz/business/service/manager/OpcMessageIdsManager.java +++ b/business/src/main/java/com/fizz/business/service/manager/OpcMessageIdsManager.java @@ -14,6 +14,17 @@ import java.util.Map; @Component public class OpcMessageIdsManager { + /** + * 生成业务/消息唯一ID(用于发送批次 bizKey 等) + * 规则:PREFIX_时间戳_8位随机 + */ + public String generateMessageId(String prefix) { + String p = (prefix == null || prefix.trim().isEmpty()) ? "MSG" : prefix.trim(); + String random = java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 8); + return (p + "_" + System.currentTimeMillis() + "_" + random).toUpperCase(); + } + + public static List msgTriggers = Lists.newArrayList(); public static Map lineMeasureIds = Maps.newHashMap();