diff --git a/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java b/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java index 9b2ae7c..86eaf66 100644 --- a/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java +++ b/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java @@ -1,15 +1,10 @@ package com.fizz.business.comm.OPC; -import com.fizz.business.constants.enums.OpcMessageType; -import com.fizz.business.domain.msg.AppMeasureMessage; -import com.kangaroohy.milo.model.ReadWriteEntity; import com.kangaroohy.milo.service.MiloService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.utils.Lists; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; diff --git a/business/src/main/java/com/fizz/business/constants/CommonConstants.java b/business/src/main/java/com/fizz/business/constants/CommonConstants.java index 78031cf..471da3b 100644 --- a/business/src/main/java/com/fizz/business/constants/CommonConstants.java +++ b/business/src/main/java/com/fizz/business/constants/CommonConstants.java @@ -2,7 +2,7 @@ package com.fizz.business.constants; import com.fizz.business.constants.enums.DeviceEnum; -import static com.fizz.business.constants.enums.DeviceEnum.DISC; +import static com.fizz.business.constants.enums.DeviceEnum.INS; public class CommonConstants { @@ -50,7 +50,7 @@ public class CommonConstants { public static final String SEG_STRIP_LEN = "SEG_STRIP_LEN"; //卷取机前一个设备idx - public static final DeviceEnum BEFORE_TR_IDX = DISC; + public static final DeviceEnum BEFORE_TR_IDX = INS; // 工艺规程点位代码 public static final String SETUP_POINT_CODE = "SETUP_POINT_CODE"; diff --git a/business/src/main/java/com/fizz/business/constants/enums/DeviceEnum.java b/business/src/main/java/com/fizz/business/constants/enums/DeviceEnum.java index 58edfcd..bb0635e 100644 --- a/business/src/main/java/com/fizz/business/constants/enums/DeviceEnum.java +++ b/business/src/main/java/com/fizz/business/constants/enums/DeviceEnum.java @@ -5,57 +5,52 @@ import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; import lombok.Getter; -import java.util.HashMap; -import java.util.Map; +import java.util.*; @Getter @AllArgsConstructor +/** + * 细粒度设备枚举(按你给出的17台设备) + * position 为基准位置(单位:m),用于和 stripLocation 比较。 + * paramFields 列出该设备需要采样/缓存的字段名(与 AppMeasure*Message 中字段名对应)。 + */ public enum DeviceEnum { - POR1(0, "1#开卷机"), - POR2(1, "2#开卷机"), - WELDER(2, "焊机"), - BR1(3, "1#张力辊"), - CEL(4, "入口活套"), - BR2(5, "2#张力辊"), - ALKALI(6, "碱洗"), - DRYING(7, "热烘干"), - BR4(8, "4#张力辊"), - RTF(9, "加热炉"), - SF1(10, "均热炉1"), - EHF(11, "EHF"), - SF2(12, "均热炉2"), - CTF(13, "CTF"), - SF3(14, "均热炉3"), - RJC(15, "控冷段"), - AJC(16, "快冷段"), - BR5(17, "5#张力辊"), - BR6(18, "6#张力辊"), - CXL(19, "出口活套"), - BR7(20, "7#张力辊"), - BR8(21, "8#张力辊"), - COAT(22, "涂机"), - DISC(23, "圆盘剪"), - TR1(24, "1#卷取机"), - TR2(25, "2#卷取机"); + POR1(0, "1#开卷机", 0.0, Arrays.asList("tensionPorBr1", "stripSpeed")), + POR2(1, "2#开卷机", 1.0, Arrays.asList("tensionPorBr2", "stripSpeed")), + WELDER(2, "焊机", 5.0, Arrays.asList("weldStatus")), + ENL1(3, "入口活套1", 10.0, Arrays.asList("celLength", "celCapacity", "tensionCel")), + ENL2(4, "入口活套2", 12.0, Arrays.asList("celLength", "celCapacity", "tensionCel")), + CLEAN(5, "清洗段", 20.0, Arrays.asList("cleaningVoltage", "cleaningCurrent", "alkaliConcentration", "alkaliTemperature")), + FUR1(6, "退火炉-预热段", 30.0, Arrays.asList("phfExitStripTemp","potTemperature","gasConsumption")), + FUR2(7, "退火炉-加热段", 40.0, Arrays.asList("rtfExitStripTemp","zincPotPower")), + FUR3(8, "退火炉-冷却段", 50.0, Arrays.asList("jcsExitStripTemp","coolingTowerStripTemp")), + FUR4(9, "退火炉-均衡段", 60.0, Arrays.asList("scsExitStripTemp")), + TM(10, "光整机", 70.0, Arrays.asList("tensionBr5Tm", "stripSpeedTmExit")), + TL(11, "拉矫机", 80.0, Arrays.asList("tlElongation", "tensionTlBr7")), + COAT(12, "后处理段", 90.0, Arrays.asList( + "avrCoatingWeightTop","stdCoatingWeightTop","maxCoatingWeightTop","minCoatingWeightTop", + "avrCoatingWeightBottom","stdCoatingWeightBottom","maxCoatingWeightBottom","minCoatingWeightBottom", + "airKnifePressure","airKnifeFlow","airKnifeGap","stripSpeedTmExit","tensionBr5Tm", + "tensionTmBr6","tensionBr5Br6","tmMask","tmElongation","rollForceOperator","rollForceDrive", + "motorTorque","bendingForce","antiCrimpingRollMesh","billyRollMesh", + "tensionTlBr7","tensionBr6Br7","tlFlag","tlElongation","levelingUnit1Mesh","levelingUnit2Mesh", + "antiCrossBowUnitMesh","tensionBr7Br8","stripSpeedAfp","stripTempAfp" + )), + CXL1(13, "出口活套1", 100.0, Arrays.asList("cxlLength", "cxlCapacity", "tensionCxl")), + CXL2(14, "出口活套2", 102.0, Arrays.asList("cxlLength", "cxlCapacity", "tensionCxl")), + INS(15, "检查站", 110.0, Arrays.asList("inspectionStatus")), + TR(16, "卷取机", 120.0, Arrays.asList("coilLength", "speedExitSection", "tensionBr9Tr")), + EXC(17, "卸卷小车", 999999.0, Collections.emptyList()), + WEIGHT(18, "称重鞍座", 999999.0, Collections.emptyList()); - - private final Integer idx; + private final int idx; private final String desc; - private static final Map MAP = new HashMap<>(); + private final double basePosition; + private final List paramFields; + private static final Map NAME_MAP = new HashMap<>(); static { - for (DeviceEnum e : DeviceEnum.values()) { - MAP.put(e.getValue(), e); - } + for (DeviceEnum d : values()) NAME_MAP.put(d.name(), d); } - - @JsonCreator(mode = JsonCreator.Mode.DELEGATING) - public static DeviceEnum getByValue(String value) { - return MAP.get(value); - } - - @JsonValue - public String getValue() { - return this.name(); - } -} + public static DeviceEnum fromName(String name) { return NAME_MAP.get(name); } +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/constants/enums/L1OperateMatEnum.java b/business/src/main/java/com/fizz/business/constants/enums/L1OperateMatEnum.java index 5b44934..de6f937 100644 --- a/business/src/main/java/com/fizz/business/constants/enums/L1OperateMatEnum.java +++ b/business/src/main/java/com/fizz/business/constants/enums/L1OperateMatEnum.java @@ -57,8 +57,7 @@ public enum L1OperateMatEnum implements IEnum, IOperateMat, IOperateMat, IOperateMat, IOperateMat, IOperateMat matmapList = MatmapUtil.getMatmapList(); - matmapList.forEach(matmap -> { - if (Objects.equals(matmap.getMatId(), porCoil.getMatId())) { - MatmapUtil.setMatmap(matmap.getPosIdx(), form.getEntryMatId(), form.getPlanId(), form.getPlanNo()); - } - }); - RedisCacheManager redisCacheManager = BeanFactory.getBean(RedisCacheManager.class); - // 更新headList - List headList = redisCacheManager.getHeadList(); - headList.forEach(head -> { - if (Objects.equals(head.getMatId(), porCoil.getMatId())) { - head.setMatId(form.getEntryMatId()); - head.setPlanNo(form.getPlanNo()); - head.setPlanId(form.getPlanId()); - head.setPorIdx(form.getPorIdx()); - } - }); - redisCacheManager.setHeadList(headList); - // 更新prevHead - CoilHeadDTO prevHead = redisCacheManager.getPrevHead(); - if (Objects.nonNull(prevHead) && Objects.equals(prevHead.getMatId(), porCoil.getMatId())) { - prevHead.setMatId(form.getEntryMatId()); - prevHead.setPlanNo(form.getPlanNo()); - prevHead.setPlanId(form.getPlanId()); - prevHead.setPorIdx(form.getPorIdx()); - redisCacheManager.setPrevHead(prevHead); - } - // 更新mergeHead - CoilHeadDTO mergeHead = redisCacheManager.getMergeHead(); - if (Objects.nonNull(mergeHead) && Objects.equals(mergeHead.getMatId(), porCoil.getMatId())) { - mergeHead.setMatId(form.getEntryMatId()); - mergeHead.setPlanNo(form.getPlanNo()); - mergeHead.setPlanId(form.getPlanId()); - prevHead.setPorIdx(form.getPorIdx()); - redisCacheManager.setMergeHead(mergeHead); - } - // 更新segment - SegmentMapper segmentMapper = BeanFactory.getBean(SegmentMapper.class); - LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); - updateWrapper.eq(Segment::getEntryMatId, porCoil.getMatId()); - updateWrapper.eq(Segment::getPlanId, porCoil.getPlanId()); - updateWrapper.set(Segment::getEntryMatId, form.getEntryMatId()); - updateWrapper.set(Segment::getPlanId, form.getPlanId()); - segmentMapper.update(new Segment(), updateWrapper); - } } diff --git a/business/src/main/java/com/fizz/business/controller/CrmPdoExcoilController.java b/business/src/main/java/com/fizz/business/controller/CrmPdoExcoilController.java index 2e58943..37ce936 100644 --- a/business/src/main/java/com/fizz/business/controller/CrmPdoExcoilController.java +++ b/business/src/main/java/com/fizz/business/controller/CrmPdoExcoilController.java @@ -21,10 +21,10 @@ public class CrmPdoExcoilController { @Resource private CrmPdoExcoilService crmPdoExcoilService; - @GetMapping("/get/{excoilid}/{operid}") + @GetMapping("/get/{excoilid}") @Operation(summary ="查询实绩") - public R getByExcoilIdAndOperId(@PathVariable String excoilid, @PathVariable Integer operid) { - return R.ok(crmPdoExcoilService.getByExcoilIdAndOperId(excoilid, operid)); + public R getByExcoilId(@PathVariable String excoilid) { + return R.ok(crmPdoExcoilService.getByExcoilId(excoilid)); } @PostMapping("/add") diff --git a/business/src/main/java/com/fizz/business/controller/ReportController.java b/business/src/main/java/com/fizz/business/controller/ReportController.java new file mode 100644 index 0000000..6747185 --- /dev/null +++ b/business/src/main/java/com/fizz/business/controller/ReportController.java @@ -0,0 +1,52 @@ +package com.fizz.business.controller; + + +import com.fizz.business.service.CrmPdoExcoilService; +import com.fizz.business.vo.ReportDetailVO; +import com.fizz.business.vo.ReportSummaryVO; +import com.ruoyi.common.annotation.Anonymous; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.format.annotation.DateTimeFormat; +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; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping("/api/report") +@Tag(name= "报表接口",description = "报表接口") +@Anonymous +public class ReportController { + + @Resource + private CrmPdoExcoilService crmPdoExcoilService; + + @GetMapping("/summary") + @Operation(summary = "生产实绩报表-汇总信息查询") + public ReportSummaryVO getReportSummary( + @RequestParam(required = false) String groupNo, + @RequestParam(required = false) String shiftNo, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime + ) { + return crmPdoExcoilService.getReportSummary(groupNo, shiftNo, startTime, endTime); + } + + @GetMapping("/details") + @Operation(summary = "生产实绩报表-产出明细查询") + public List getReportDetails( + @RequestParam(required = false) String groupNo, + @RequestParam(required = false) String shiftNo, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime + ) { + return crmPdoExcoilService.getReportDetails(groupNo, shiftNo, startTime, endTime); + } + + +} diff --git a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java index 0d331fb..1f5b8c3 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureEntryMessage.java @@ -21,7 +21,7 @@ public class AppMeasureEntryMessage extends OpcMessage { @Schema(description = "钢带位置 (m),0 表示头部在参考点 (Welder)") private BigDecimal stripLocation; - @Schema(description = "支付卷号,1 或 2") + @Schema(description = "开卷机号,1 或 2") private Integer payOffReelNumber; @Schema(description = "钢带张力 POR – BR1 (daN)") diff --git a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java index b72c10c..202d9de 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureExitMessage.java @@ -21,13 +21,13 @@ public class AppMeasureExitMessage extends OpcMessage { @Schema(description = "钢带张力 BR8 – BR9 (daN)") private BigDecimal tensionBr8Br9; - @Schema(description = "入口活套位置(m)") + @Schema(description = "出口活套位置(m)") private BigDecimal cxlLength; - @Schema(description = "入口活套百分比(m)") + @Schema(description = "出口活套百分比(m)") private BigDecimal cxlCapacity; - @Schema(description = "入口活套张力(m)") + @Schema(description = "出口活套张力(m)") private BigDecimal tensionCxl ; @Schema(description = "涂油标志 (0=no, 1=yes)") diff --git a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureMessage.java b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureMessage.java index 8a61c49..e1b0320 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/AppMeasureMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/AppMeasureMessage.java @@ -1,5 +1,11 @@ package com.fizz.business.domain.msg; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data public class AppMeasureMessage extends OpcMessage { AppMeasureEntryMessage appMeasureEntryMessage; diff --git a/business/src/main/java/com/fizz/business/domain/msg/ExitCutMessage.java b/business/src/main/java/com/fizz/business/domain/msg/ExitCutMessage.java index d57ad7e..4f24a25 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/ExitCutMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/ExitCutMessage.java @@ -1,6 +1,7 @@ package com.fizz.business.domain.msg; +import com.fizz.business.constants.enums.ExitCutTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -16,7 +17,7 @@ public class ExitCutMessage extends OpcMessage { private Integer counter; @Schema(description = "剪切类型:0=split, 1=weldSeam, 2=stripBreak") - private Integer cutType; + private ExitCutTypeEnum cutType; @Schema(description = "剪切时卷取长度 (m)") private BigDecimal cutLength; diff --git a/business/src/main/java/com/fizz/business/domain/msg/ExitMovementMessage.java b/business/src/main/java/com/fizz/business/domain/msg/ExitMovementMessage.java index 0c98306..828afae 100644 --- a/business/src/main/java/com/fizz/business/domain/msg/ExitMovementMessage.java +++ b/business/src/main/java/com/fizz/business/domain/msg/ExitMovementMessage.java @@ -14,8 +14,8 @@ public class ExitMovementMessage extends OpcMessage { private Integer counter; @Schema(description = "Material Place Source") - private Integer materialPlaceSource; + private Integer exSrc; @Schema(description = "Material Place Destination") - private Integer materialPlaceDestination; + private Integer exDesc; } diff --git a/business/src/main/java/com/fizz/business/dto/ExitCoilInfoDTO.java b/business/src/main/java/com/fizz/business/dto/ExitCoilInfoDTO.java index 9c58acd..8b8f4e3 100644 --- a/business/src/main/java/com/fizz/business/dto/ExitCoilInfoDTO.java +++ b/business/src/main/java/com/fizz/business/dto/ExitCoilInfoDTO.java @@ -15,6 +15,7 @@ public class ExitCoilInfoDTO implements Serializable { private double startPos; private double endPos; private double exitCutLength; + private double outerDiameter; private String entryMatId; private String exitMatId; private boolean separateFlag; diff --git a/business/src/main/java/com/fizz/business/dto/SegValue.java b/business/src/main/java/com/fizz/business/dto/SegValue.java index 3a67098..7687615 100644 --- a/business/src/main/java/com/fizz/business/dto/SegValue.java +++ b/business/src/main/java/com/fizz/business/dto/SegValue.java @@ -1,17 +1,31 @@ package com.fizz.business.dto; +import lombok.Data; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.io.Serializable; +import java.math.BigDecimal; -@Getter -@Setter +@Data public class SegValue implements Serializable { - private double max; - private double min; - private double avg; - private double std; + private BigDecimal max; + private BigDecimal min; + private BigDecimal avg; + private BigDecimal std; private int cnt; - private double sum; + private BigDecimal sum; + + public void add(BigDecimal value) { + this.sum = this.sum.add(value); + this.cnt++; + } + + public BigDecimal getAverage() { + if (cnt == 0) { + return BigDecimal.ZERO; + } + return sum.divide(new BigDecimal(cnt), 2, BigDecimal.ROUND_HALF_UP); + } } diff --git a/business/src/main/java/com/fizz/business/dto/SegmentDTO.java b/business/src/main/java/com/fizz/business/dto/SegmentDTO.java index 9145afe..0cc71c1 100644 --- a/business/src/main/java/com/fizz/business/dto/SegmentDTO.java +++ b/business/src/main/java/com/fizz/business/dto/SegmentDTO.java @@ -1,26 +1,57 @@ package com.fizz.business.dto; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; +import java.io.Serializable; +import java.math.BigDecimal; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; @Data -public class SegmentDTO { +@TableName("cpl_segment_total") +public class SegmentDTO implements Serializable { - private boolean first; - private Long planId; - private String planNo; - private String coilID; + @TableId(type = IdType.AUTO) + private Long id; + + @TableField("en_coil_id") private String enCoilID; - private String exCoilID; - //MATID_Type matId; - private int segNo; - private double segLen; - private double startPos;//位于带钢的起始位置 - private double endPos; - private double headPos;//位于全线的位置 - private double tailPos; + + @TableField("pickling_count") + private Integer picklingCount; + + @TableField("seg_no") + private Integer segNo; + + // 以下字段用于业务逻辑,不存入数据库 + @TableField(exist = false) + private BigDecimal headPos; + @TableField(exist = false) + private BigDecimal tailPos; + + // 以下字段存入数据库 + @TableField("start_pos") + private BigDecimal startPos; + @TableField("end_pos") + private BigDecimal endPos; + @TableField("seg_len") + private BigDecimal segLen; + @TableField("total_values_json") + private String totalValuesJson; + + // 以下 Map 用于业务逻辑,不存入数据库 + @TableField(exist = false) + private Map totalValues = new ConcurrentHashMap<>(); + @TableField(exist = false) + private Map L3values = new ConcurrentHashMap<>(); + + // 两个未使用的字段,可以根据需要保留或移除 + @TableField(exist = false) private int headPosNum; + @TableField(exist = false) private int tailPosNum; - private Map segValMap; -} +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/mapper/CrmPdoExcoilMapper.java b/business/src/main/java/com/fizz/business/mapper/CrmPdoExcoilMapper.java index 1cdb31a..423a598 100644 --- a/business/src/main/java/com/fizz/business/mapper/CrmPdoExcoilMapper.java +++ b/business/src/main/java/com/fizz/business/mapper/CrmPdoExcoilMapper.java @@ -2,8 +2,30 @@ package com.fizz.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.fizz.business.domain.CrmPdoExcoil; +import com.fizz.business.vo.ReportDetailVO; +import com.fizz.business.vo.ReportSummaryVO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; @Mapper public interface CrmPdoExcoilMapper extends BaseMapper { + + + ReportSummaryVO getReportSummary( + @Param("groupNo") String groupNo, + @Param("shiftNo") String shiftNo, + @Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime + ); + + List getReportDetails( + @Param("groupNo") String groupNo, + @Param("shiftNo") String shiftNo, + @Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime + ); + } diff --git a/business/src/main/java/com/fizz/business/mapper/SegmentMapper.java b/business/src/main/java/com/fizz/business/mapper/SegmentMapper.java index fafee0e..43d79b6 100644 --- a/business/src/main/java/com/fizz/business/mapper/SegmentMapper.java +++ b/business/src/main/java/com/fizz/business/mapper/SegmentMapper.java @@ -3,6 +3,7 @@ package com.fizz.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.fizz.business.domain.PdoStripvalue; import com.fizz.business.domain.Segment; +import com.fizz.business.dto.SegmentDTO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -15,7 +16,7 @@ import org.apache.ibatis.annotations.Param; * @since 2023-05-17 */ @Mapper -public interface SegmentMapper extends BaseMapper { +public interface SegmentMapper extends BaseMapper { PdoStripvalue getStripValue(@Param("entryMatId") String entryMatId, @Param("startPos") double startPos, @Param("endPos") double endPos); diff --git a/business/src/main/java/com/fizz/business/service/CrmPdoExcoilService.java b/business/src/main/java/com/fizz/business/service/CrmPdoExcoilService.java index 15c2553..12797b5 100644 --- a/business/src/main/java/com/fizz/business/service/CrmPdoExcoilService.java +++ b/business/src/main/java/com/fizz/business/service/CrmPdoExcoilService.java @@ -5,11 +5,15 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.fizz.business.domain.CrmPdoExcoil; import com.fizz.business.domain.PdoExcoil; import com.fizz.business.form.CrmPdoExcoilForm; +import com.fizz.business.vo.ReportDetailVO; +import com.fizz.business.vo.ReportSummaryVO; +import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.List; public interface CrmPdoExcoilService extends IService { - CrmPdoExcoil getByExcoilIdAndOperId(String excoilid, Integer operid); + CrmPdoExcoil getByExcoilId(String excoilid); boolean addCrmPdoExcoil(CrmPdoExcoil crmPdoExcoil); @@ -20,5 +24,11 @@ public interface CrmPdoExcoilService extends IService { List listAll(CrmPdoExcoilForm form); Long getNumber(String matId,String planId,Integer subNumber); + + ReportSummaryVO getReportSummary(String groupNo, String shiftNo, LocalDateTime startTime, LocalDateTime endTime); + + List getReportDetails(String groupNo, String shiftNo, LocalDateTime startTime, LocalDateTime endTime); + + void updateExitCoilActualWeight(String exitMatId, BigDecimal weight); } diff --git a/business/src/main/java/com/fizz/business/service/client/LocalCacheManager.java b/business/src/main/java/com/fizz/business/service/client/LocalCacheManager.java deleted file mode 100644 index 313eddd..0000000 --- a/business/src/main/java/com/fizz/business/service/client/LocalCacheManager.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.fizz.business.service.client; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.lang.Pair; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.fizz.business.constants.enums.LimitItemCode; -import com.fizz.business.domain.DeviceDefine; -import com.fizz.business.dto.PointConfigDTO; -import com.fizz.business.mapper.DeviceDefineMapper; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.DependsOn; -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - - -/** - * 本地缓存管理 - * - * @author chenhao - * @date 2023/05/15 - */ -@Component -public class LocalCacheManager { - - private static DeviceDefineMapper deviceDefineMapper; - - @Autowired - public void setDeviceDefineMapper(DeviceDefineMapper deviceDefineMapper) { - LocalCacheManager.deviceDefineMapper = deviceDefineMapper; - } - - public static LinkedHashMap DEVICE_DEFINE_MAP = Maps.newLinkedHashMap(); - - @PostConstruct - public static void init() { - DEVICE_DEFINE_MAP = getDeviceDefine(); - } - - - - - - public static LinkedHashMap getDeviceDefine() { - List list = deviceDefineMapper.selectList(new LambdaQueryWrapper().orderByAsc(DeviceDefine::getPosIdx)); - return list.stream().collect(Collectors.toMap(DeviceDefine::getPositionNameEn, it -> it, (k1, k2) -> k1, LinkedHashMap::new)); - } - - -} diff --git a/business/src/main/java/com/fizz/business/service/client/RedisCacheManager.java b/business/src/main/java/com/fizz/business/service/client/RedisCacheManager.java index 79af708..7fdc0c6 100644 --- a/business/src/main/java/com/fizz/business/service/client/RedisCacheManager.java +++ b/business/src/main/java/com/fizz/business/service/client/RedisCacheManager.java @@ -116,14 +116,14 @@ public class RedisCacheManager { if (segmentList.isEmpty()) { segmentRedisTemplate.opsForList().rightPush(COIL_SEG_LIST_KEY, segment); log.info("create new segment, coilId=[{}], segNo={}, startPos={}, endPos={}, segLen={}", - segment.getCoilID(), segment.getSegNo(), segment.getStartPos(), segment.getEndPos(), segment.getSegLen()); + segment.getEnCoilID(), segment.getSegNo(), segment.getStartPos(), segment.getEndPos(), segment.getSegLen()); } else { - Map exists = segmentList.stream().collect(Collectors.toMap(s -> s.getCoilID() + "-" + s.getSegNo() + "-" + s.getPlanId(), s -> s.getCoilID() + s.getSegNo() + s.getPlanId(), (k1, k2) -> k1)); - String key = segment.getCoilID() + "-" + segment.getSegNo() + "-" + segment.getPlanId(); + Map exists = segmentList.stream().collect(Collectors.toMap(s -> s.getEnCoilID() + "-" + s.getSegNo(), s -> s.getEnCoilID() + s.getSegNo() , (k1, k2) -> k1)); + String key = segment.getEnCoilID() + "-" + segment.getSegNo() ; if (!exists.containsKey(key)) { segmentRedisTemplate.opsForList().rightPush(COIL_SEG_LIST_KEY, segment); log.info("create new segment, coilId=[{}], segNo={}, startPos={}, endPos={}, segLen={}", - segment.getCoilID(), segment.getSegNo(), segment.getStartPos(), segment.getEndPos(), segment.getSegLen()); + segment.getEnCoilID(), segment.getSegNo(), segment.getStartPos(), segment.getEndPos(), segment.getSegLen()); } } } diff --git a/business/src/main/java/com/fizz/business/service/hanle/AppMeasureHandler.java b/business/src/main/java/com/fizz/business/service/hanle/AppMeasureHandler.java index 5df4512..5856050 100644 --- a/business/src/main/java/com/fizz/business/service/hanle/AppMeasureHandler.java +++ b/business/src/main/java/com/fizz/business/service/hanle/AppMeasureHandler.java @@ -1,19 +1,45 @@ package com.fizz.business.service.hanle; import com.fizz.business.anno.OpcMessageHandlerType; +import com.fizz.business.constants.enums.DeviceEnum; import com.fizz.business.constants.enums.OpcMessageType; -import com.fizz.business.domain.msg.AppMeasureExitMessage; -import com.fizz.business.domain.msg.AppMeasureMessage; +import com.fizz.business.domain.msg.*; import com.fizz.business.service.OpcMessageHandler; +import com.fizz.business.service.strip.SegmentTrackerService; +import com.fizz.business.service.strip.StripPositionService; +import com.fizz.business.utils.WebSocketUtil; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import java.math.BigDecimal; + @Component @OpcMessageHandlerType(OpcMessageType.APP_MEASURE) +@RequiredArgsConstructor public class AppMeasureHandler implements OpcMessageHandler { + private final SegmentTrackerService tracker; + @Override public void handle(AppMeasureMessage message) { - // 处理出口段测量逻辑 - System.out.println("处理 APP_MEASURE_EXIT 消息: " + message); + if (message == null) return; + + AppMeasureEntryMessage entry = message.getAppMeasureEntryMessage(); + AppMeasureFurnaceMessage furnace = message.getAppMeasureFurnaceMessage(); + AppMeasureCoatMessage coat = message.getAppMeasureCoatMessage(); + AppMeasureExitMessage exit = message.getAppMeasureExitMessage(); + + WebSocketUtil.sendMeasureMsg(message); + + // 2) extract key fields + String coilId = entry == null ? "UNKNOWN" : entry.getEntryCoilId(); + BigDecimal lengthAtWelder = entry == null || entry.getStripLocation() == null ? BigDecimal.ZERO : entry.getStripLocation(); + + // 3) delegate core processing to tracker + tracker.handleMeasure(coilId, lengthAtWelder, entry, furnace, coat, exit); + + // 调用新的方法来跟踪钢卷头部位置,并处理快照和 matmap 更新 + // 使用焊机长度作为最接近的钢卷头部位置 + tracker.trackCoilHeadPosition(coilId, lengthAtWelder, entry, exit); } } \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/service/hanle/EntryMovementHandler.java b/business/src/main/java/com/fizz/business/service/hanle/EntryMovementHandler.java index c5cca32..df69296 100644 --- a/business/src/main/java/com/fizz/business/service/hanle/EntryMovementHandler.java +++ b/business/src/main/java/com/fizz/business/service/hanle/EntryMovementHandler.java @@ -5,10 +5,12 @@ import com.fizz.business.constants.enums.L1OperateMatEnum; import com.fizz.business.constants.enums.OpcMessageType; import com.fizz.business.domain.CrmPdiPlan; import com.fizz.business.domain.msg.EntryMovementMessage; +import com.fizz.business.dto.MatmapDTO; import com.fizz.business.form.L1OperateMatForm; import com.fizz.business.service.CrmPdiPlanService; import com.fizz.business.service.OpcMessageHandler; import com.fizz.business.service.TrackService; +import com.fizz.business.utils.MatmapUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -52,6 +54,17 @@ public class EntryMovementHandler implements OpcMessageHandler { + private final CrmPdoExcoilService crmPdoExcoilService; + @Override public void handle(ExitMeasureMessage message) { - // 出口称重逻辑处理 System.out.println("处理 EXIT_MEASURE 消息: " + message); + + // 1. 获取卷取机 (TR) 上的成品卷号 + String exitMatId = MatmapUtil.getMatId(TR.getIdx()); + + if (exitMatId == null) { + System.err.println("TR device has no coil. Cannot process ExitMeasureMessage."); + return; + } + + // 2. 调用服务层更新成品卷的实际重量 + crmPdoExcoilService.updateExitCoilActualWeight(exitMatId, message.getWeight()); } } - diff --git a/business/src/main/java/com/fizz/business/service/hanle/ExitMovementHandler.java b/business/src/main/java/com/fizz/business/service/hanle/ExitMovementHandler.java index f541bc1..157e587 100644 --- a/business/src/main/java/com/fizz/business/service/hanle/ExitMovementHandler.java +++ b/business/src/main/java/com/fizz/business/service/hanle/ExitMovementHandler.java @@ -1,18 +1,46 @@ package com.fizz.business.service.hanle; +import cn.hutool.core.util.ObjectUtil; import com.fizz.business.anno.OpcMessageHandlerType; import com.fizz.business.constants.enums.OpcMessageType; import com.fizz.business.domain.msg.ExitMovementMessage; +import com.fizz.business.dto.MatmapDTO; import com.fizz.business.service.OpcMessageHandler; +import com.fizz.business.utils.MatmapUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j @OpcMessageHandlerType(OpcMessageType.EXIT_MOVEMENT) +@RequiredArgsConstructor public class ExitMovementHandler implements OpcMessageHandler { @Override public void handle(ExitMovementMessage message) { - // 出口移动逻辑处理 - System.out.println("处理 EXIT_MOVEMENT 消息: " + message); + System.out.printf("处理 EXIT_MOVEMENT 消息: %d -> %d%n", message.getExSrc(), message.getExDesc()); + + // 1. 获取源位置的物料信息 + int srcIndex = message.getExSrc() -1 ; + MatmapDTO srcMatmap = MatmapUtil.getMatmap(srcIndex); + + if (ObjectUtil.isNull(srcMatmap) || ObjectUtil.isNull(srcMatmap.getMatId())) { + log.error("源位置 {} 没有物料信息,跳过移动处理。", srcIndex); + // 如果源位置没有物料,则可能是一次无效的移动,直接返回 + return; + } + + // 2. 清空源位置的物料信息 + MatmapUtil.clearMatmap(srcIndex); + log.info("成功清空源位置 {} 的物料信息。{}", srcIndex,srcMatmap.getMatId()); + + // 3. 将物料信息设置到目标位置 + int destIndex = message.getExDesc() - 1; + MatmapUtil.setMatmap(destIndex, srcMatmap.getMatId(), srcMatmap.getPlanId(), srcMatmap.getPlanNo()); + log.info("成功设置目标位置 {} 的物料信息为钢卷 {}", destIndex, srcMatmap.getMatId()); } -} + + + +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/service/impl/CrmPdoExcoilServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/CrmPdoExcoilServiceImpl.java index 21c7229..67d6175 100644 --- a/business/src/main/java/com/fizz/business/service/impl/CrmPdoExcoilServiceImpl.java +++ b/business/src/main/java/com/fizz/business/service/impl/CrmPdoExcoilServiceImpl.java @@ -8,24 +8,31 @@ import com.fizz.business.domain.PdoExcoil; import com.fizz.business.form.CrmPdoExcoilForm; import com.fizz.business.mapper.CrmPdoExcoilMapper; import com.fizz.business.service.CrmPdoExcoilService; +import com.fizz.business.vo.ReportDetailVO; +import com.fizz.business.vo.ReportSummaryVO; import com.ruoyi.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.List; +import java.util.Objects; @Service +@Slf4j public class CrmPdoExcoilServiceImpl extends ServiceImpl implements CrmPdoExcoilService { /** * 根据退出卷ID和操作员ID查询记录 * * @param excoilid 退出卷ID - * @param operid 操作员ID * @return 查询到的CrmPdoExcoil对象 */ - public CrmPdoExcoil getByExcoilIdAndOperId(String excoilid, Integer operid) { + public CrmPdoExcoil getByExcoilId(String excoilid) { QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("exit_coilid", excoilid).eq("operid", operid); + queryWrapper.eq("exit_coilid", excoilid); return this.getOne(queryWrapper); } @@ -98,5 +105,51 @@ public class CrmPdoExcoilServiceImpl extends ServiceImpl getReportDetails(String groupNo, String shiftNo, LocalDateTime startTime, LocalDateTime endTime) { + return baseMapper.getReportDetails(groupNo, shiftNo, startTime, endTime); + } + + /** + * 【新增实现】 + * 负责更新产出卷的实际重量和状态。 + */ + @Override + @Transactional + public void updateExitCoilActualWeight(String exitMatId, BigDecimal actualWeight) { + // 1. 根据成品卷号查询记录 + CrmPdoExcoil excoil = this.getByExcoilId(exitMatId); + + if (excoil == null) { + log.error("未找到成品卷 {} 的数据库记录,无法更新重量。", exitMatId); + return; + } + + // 2. 检查当前状态是否为 "UNWEIGHT" (未称重) + // 确保我们只更新未处理过的卷 + if (Objects.equals(excoil.getStatus(), "UNWEIGHT")) { + // 3. 更新实际重量和状态 + excoil.setActualWeight(actualWeight.doubleValue()); + excoil.setStatus("COMPLETED"); // 或其他最终状态,如 "WEIGHED" + + // 4. 调用 CRM 服务进行数据库更新 + boolean success = this.updateCrmPdoExcoil(excoil); + + if (success) { + log.info("成品卷 {} 的实际重量已成功更新为 {} kg,状态变为 {}.", + exitMatId, actualWeight, excoil.getStatus()); + } else { + log.error("更新成品卷 {} 失败。", exitMatId); + } + } else { + log.warn("成品卷 {} 的状态不是 'UNWEIGHT',当前状态为 '{}',跳过重量更新。", + exitMatId, excoil.getStatus()); + } + } } diff --git a/business/src/main/java/com/fizz/business/service/impl/PdoExCoilServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/PdoExCoilServiceImpl.java index bd052d3..b045122 100644 --- a/business/src/main/java/com/fizz/business/service/impl/PdoExCoilServiceImpl.java +++ b/business/src/main/java/com/fizz/business/service/impl/PdoExCoilServiceImpl.java @@ -98,7 +98,7 @@ public class PdoExCoilServiceImpl implements PdoExCoilService { // 产出实际入库 crmPdoExcoilService.addCrmPdoExcoil(pdoExCoilDTO); // 打包segment - pdoStripValueService.treatStripValues(exitCoil); +// pdoStripValueService.treatStripValues(exitCoil); return pdoExCoilDTO; } diff --git a/business/src/main/java/com/fizz/business/service/impl/SegmentService.java b/business/src/main/java/com/fizz/business/service/impl/SegmentService.java new file mode 100644 index 0000000..f6294c6 --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/impl/SegmentService.java @@ -0,0 +1,61 @@ +package com.fizz.business.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fizz.business.dto.SegmentDTO; +import com.fizz.business.mapper.SegmentMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +@Service +public class SegmentService { + + @Resource + private SegmentMapper segmentMapper; + private final ObjectMapper objectMapper = new ObjectMapper(); // 用于JSON转换 + + /** + * 保存完整的段数据,包含插入和更新逻辑。 + * 对应 C++ 的 saveTotalSegment() 方法。 + * + * @param segment 待保存的段数据对象 + */ + public void saveTotalSegment(SegmentDTO segment) { + if (segment == null || segment.getEnCoilID() == null || segment.getEnCoilID().isEmpty()) { + System.err.println("警告: Coil ID 为空,无法保存数据。"); + return; + } + + // 1. 将动态的 Map 数据转换为 JSON 字符串 + Map totalValuesAvg = new HashMap<>(); + segment.getTotalValues().forEach((key, segValue) -> { + // 这里将 key 拼接上 "_avg" 以示区分,如果需要也可以不加 + totalValuesAvg.put(key + "_avg", segValue.getAverage()); + }); + + try { + // 使用 Jackson ObjectMapper 将 Map 转换为 JSON 字符串 + String jsonString = objectMapper.writeValueAsString(totalValuesAvg); + segment.setTotalValuesJson(jsonString); + } catch (JsonProcessingException e) { + System.err.println("转换 JSON 失败: " + e.getMessage()); + return; + } + + // 2. 先执行删除,再插入,以避免重复数据(与 C++ 逻辑保持一致) + QueryWrapper deleteWrapper = new QueryWrapper<>(); + deleteWrapper.eq("en_coil_id", segment.getEnCoilID()) + .eq("seg_no", segment.getSegNo()); + segmentMapper.delete(deleteWrapper); + + // 3. 执行插入操作,MyBatis-Plus 会自动处理 totalValuesJson 字段的保存 + segmentMapper.insert(segment); + + System.out.println("段数据保存成功。钢卷号: " + segment.getEnCoilID() + ", 段号: " + segment.getSegNo()); + } +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/service/impl/TrackServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/TrackServiceImpl.java index ea51bf8..04662d8 100644 --- a/business/src/main/java/com/fizz/business/service/impl/TrackServiceImpl.java +++ b/business/src/main/java/com/fizz/business/service/impl/TrackServiceImpl.java @@ -3,30 +3,23 @@ package com.fizz.business.service.impl; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.NumberUtil; import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fizz.business.constants.enums.DeviceEnum; import com.fizz.business.constants.enums.PlanStatusEnum; import com.fizz.business.constants.enums.WebOperateMatEnum; -import com.fizz.business.domain.DeviceDefine; -import com.fizz.business.domain.HalfReturn; import com.fizz.business.dto.CoilHeadDTO; import com.fizz.business.dto.CoilPositionDTO; import com.fizz.business.dto.MatmapDTO; import com.fizz.business.form.AdjustPosForm; import com.fizz.business.form.L1OperateMatForm; import com.fizz.business.form.WebOperateMatForm; -import com.fizz.business.mapper.HalfReturnMapper; -import com.fizz.business.mapper.SegmentMapper; import com.fizz.business.service.CrmPdiPlanService; import com.fizz.business.service.TrackService; -import com.fizz.business.service.client.LocalCacheManager; import com.fizz.business.service.client.RedisCacheManager; import com.fizz.business.utils.CalcUtil; import com.fizz.business.utils.CoilMeasUtil; import com.fizz.business.utils.MatmapUtil; import com.fizz.business.utils.WebSocketUtil; import com.fizz.business.vo.CrmPdiPlanVO; -import com.fizz.business.vo.HalfReturnInfoVO; import com.fizz.business.vo.ReturnInfoVO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -50,8 +43,7 @@ public class TrackServiceImpl implements TrackService { @Autowired RedisCacheManager redisCacheManager; - @Autowired - SegmentMapper segmentMapper; + @Autowired CrmPdiPlanService crmPdiPlanService; @@ -107,10 +99,10 @@ public class TrackServiceImpl implements TrackService { */ @Override public void adjustPosition(AdjustPosForm form) { - DeviceDefine targetDevice = LocalCacheManager.DEVICE_DEFINE_MAP.get(form.getTargetPos().name()); + DeviceEnum targetDevice = DeviceEnum.fromName(form.getTargetPos().name()); Assert.notNull(targetDevice, "目标位置设备不存在"); - DeviceDefine currentDevice = LocalCacheManager.DEVICE_DEFINE_MAP.get(form.getCurrentPos().name()); + DeviceEnum currentDevice = DeviceEnum.fromName(form.getCurrentPos().name()); Assert.notNull(currentDevice, "当前位置设备不存在"); // 更新matmap @@ -129,16 +121,16 @@ public class TrackServiceImpl implements TrackService { return true; } // 多个卷取机需要跳过1#卷取机 - if (Objects.equals(endPos, DeviceEnum.TR2.getIdx()) - && Objects.equals(currPos, DeviceEnum.TR1.getIdx())) { + if (Objects.equals(endPos, DeviceEnum.TR.getIdx()) + ) { return true; } return false; } - private void refreshMatmap(DeviceDefine targetDevice, DeviceDefine currDevice, AdjustPosForm form) { - Integer targetPosIdx = targetDevice.getPosIdx(); - Integer currPosIdx = currDevice.getPosIdx(); + private void refreshMatmap(DeviceEnum targetDevice, DeviceEnum currDevice, AdjustPosForm form) { + Integer targetPosIdx = targetDevice.getIdx(); + Integer currPosIdx = currDevice.getIdx(); MatmapDTO target = MatmapUtil.getMatmap(targetPosIdx); MatmapDTO curr = MatmapUtil.getMatmap(currPosIdx); if (Objects.equals(curr.getMatId(), target.getMatId())) { diff --git a/business/src/main/java/com/fizz/business/service/strip/SegmentTrackerService.java b/business/src/main/java/com/fizz/business/service/strip/SegmentTrackerService.java new file mode 100644 index 0000000..e40ceeb --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/strip/SegmentTrackerService.java @@ -0,0 +1,309 @@ +package com.fizz.business.service.strip; + +import com.fizz.business.constants.enums.DeviceEnum; +import com.fizz.business.constants.enums.L1OperateMatEnum; +import com.fizz.business.domain.msg.AppMeasureCoatMessage; +import com.fizz.business.domain.msg.AppMeasureEntryMessage; +import com.fizz.business.domain.msg.AppMeasureExitMessage; +import com.fizz.business.domain.msg.AppMeasureFurnaceMessage; +import com.fizz.business.dto.MatmapDTO; +import com.fizz.business.dto.SegValue; +import com.fizz.business.dto.SegmentDTO; +import com.fizz.business.form.L1OperateMatForm; +import com.fizz.business.service.TrackService; +import com.fizz.business.service.impl.SegmentService; +import com.fizz.business.utils.MatmapUtil; +import com.fizz.business.utils.WebSocketUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.ConcurrentMap; + +import static com.fizz.business.constants.enums.DeviceEnum.WELDER; + +@Service +@Slf4j +@RequiredArgsConstructor +public class SegmentTrackerService { + + private final StripPositionService stripPositionService; + private final TrackService trackService; + private final SegmentService segmentService; // 注入新创建的段服务 + + private int traceCount = 0; + private boolean firstMeasure = true; + private BigDecimal weldLength = BigDecimal.ZERO; + private int coilSegNum = 1; + + private final Deque listSegment = new ConcurrentLinkedDeque<>(); + private static final double SEGSTRIPLEN = 2.0; + private static final int MAX_SEG_COUNT = 2000; + private final ConcurrentMap> coilReachedDevices = new ConcurrentHashMap<>(); + private static final double LOWSPEEDLIMIT = 0.05; + + /** + * 【主入口】 + * 负责处理新的测量数据,生成新段,并对新到达的设备做一次性快照。 + */ + public void handleMeasure(String coilId, + BigDecimal entryLengthAtWelder, + AppMeasureEntryMessage entry, + AppMeasureFurnaceMessage furnace, + AppMeasureCoatMessage coat, + AppMeasureExitMessage exit) { + + // 1. 首次测量初始化或新卷判定 + BigDecimal weldDev; + if (firstMeasure || entryLengthAtWelder.compareTo(weldLength) < 0) { + weldDev = entryLengthAtWelder; // 新卷偏移量等于当前长度 + coilSegNum = 1; + weldLength = entryLengthAtWelder; + firstMeasure = false; + listSegment.clear(); // 清空旧段 + coilReachedDevices.remove(coilId); // 清空旧钢卷的快照记录 + log.info("New coil detected or initialized:{} " ,coilId); + } else { + weldDev = entryLengthAtWelder.subtract(weldLength); + } + + // 更新焊机长度 + weldLength = entryLengthAtWelder; + + // trace 控制 + traceCount++; + if (traceCount > 5) { + log.info(String.format("Trace: weldLen=%.2f, speed=%s", + entryLengthAtWelder, procStripSpeed(entry, furnace, exit))); + traceCount = 0; + } + + + // 2. 检查是否达到生成新段的条件 + BigDecimal segThreshold = BigDecimal.valueOf(coilSegNum * SEGSTRIPLEN); + if (entryLengthAtWelder.compareTo(segThreshold) >= 0) { + + // 2.1. 创建新的 SegmentDTO 并初始化基本位置 + SegmentDTO newSeg = createNewSegment(coilId, entryLengthAtWelder); + + // 2.3. 将新段添加到队列中 + listSegment.addLast(newSeg); + if (listSegment.size() > MAX_SEG_COUNT) { + listSegment.removeFirst(); + } + coilSegNum++; + } + + // 3. 处理队列中所有已存在的段 + treatSegAsync(entry, furnace, coat, exit, weldDev); + + } + + /** + * 【核心功能】 + * 遍历所有已存在的段,更新其位置,并累积其在设备区域内的实时数据。 + * 这部分逻辑只负责“移动”和“累积”。 + */ + public void treatSeg(AppMeasureEntryMessage entry, + AppMeasureFurnaceMessage furnace, + AppMeasureCoatMessage coat, + AppMeasureExitMessage exit, + BigDecimal weldDev) { + if (listSegment.isEmpty()) { + return; + } + + BigDecimal celLength = entry != null ? entry.getCelLength() : BigDecimal.ZERO; + BigDecimal cxlLength = exit != null ? exit.getCxlLength() : BigDecimal.ZERO; + + Iterator iterator = listSegment.descendingIterator(); + while (iterator.hasNext()) { + SegmentDTO segment = iterator.next(); + + // 更新段在产线上的位置 + segment.setHeadPos(segment.getHeadPos().add(weldDev)); + segment.setTailPos(segment.getTailPos().add(weldDev)); + + // 遍历所有设备,累积段在设备区域内的数据 + for (DeviceEnum device : DeviceEnum.values()) { + double currentDevicePos = stripPositionService.calculate(device, celLength, cxlLength); + + // 判断段是否位于设备的“长区域”内 + if (segment.getHeadPos().compareTo(BigDecimal.valueOf(currentDevicePos)) > 0 && + segment.getTailPos().compareTo(BigDecimal.valueOf(currentDevicePos)) < 0) { + + double currentSpeed = getSpeedForDevice(device, entry, furnace, exit); + if (currentSpeed > LOWSPEEDLIMIT) { + for (String fieldName : device.getParamFields()) { + Object message = getMessageForDevice(device, entry, furnace, coat, exit); + if (message != null) { + BigDecimal value = getFieldFromMessage(message, fieldName); + setSegValue(segment.getTotalValues(), fieldName, value); + } + } + } + } + } + + // 出厂判断 + double exitPlantPos = stripPositionService.calculate(DeviceEnum.TR, celLength, cxlLength); + if (segment.getTailPos().compareTo(BigDecimal.valueOf(exitPlantPos)) >= 0) { + System.out.println("钢卷 " + segment.getEnCoilID() + " 的段号 " + segment.getSegNo() + " 已离开产线,开始持久化数据。"); + segmentService.saveTotalSegment(segment); // 调用服务进行持久化 + iterator.remove(); + } + } + } + + // --- 新增的辅助方法,将逻辑封装起来 --- + /** + * 【异步方法】 + * 异步处理队列中所有已存在的段,更新其位置和累积数据。 + */ + @Async("taskExecutor") // 指定使用名为 "taskExecutor" 的线程池 + public void treatSegAsync(AppMeasureEntryMessage entry, + AppMeasureFurnaceMessage furnace, + AppMeasureCoatMessage coat, + AppMeasureExitMessage exit, + BigDecimal weldDev) { + // 调用原有的同步方法 + this.treatSeg(entry, furnace, coat, exit, weldDev); + } + + + + /** + * 创建并初始化一个新的 SegmentDTO。 + */ + private SegmentDTO createNewSegment(String coilId, BigDecimal entryLengthAtWelder) { + SegmentDTO seg = new SegmentDTO(); + seg.setSegNo(coilSegNum); + seg.setEnCoilID(coilId); + + if (coilSegNum == 1) { + // 第一个段的特殊处理 + seg.setStartPos(BigDecimal.ZERO); + seg.setEndPos(entryLengthAtWelder); + seg.setSegLen(entryLengthAtWelder); + seg.setHeadPos(entryLengthAtWelder); + seg.setTailPos(BigDecimal.ZERO); + } else { + // 后续段的计算 + SegmentDTO prev = listSegment.peekLast(); + seg.setStartPos(prev.getEndPos()); + seg.setEndPos(entryLengthAtWelder); + seg.setSegLen(seg.getEndPos().subtract(seg.getStartPos())); + // 这两个位置是全线绝对位置,后续会通过 weldDev 动态更新 + seg.setHeadPos(entryLengthAtWelder); + seg.setTailPos(seg.getEndPos().subtract(seg.getSegLen())); + } + return seg; + } + + + // --- 辅助方法,与消息处理和反射相关 --- + + private Object getMessageForDevice(DeviceEnum device, AppMeasureEntryMessage entry, AppMeasureFurnaceMessage furnace, AppMeasureCoatMessage coat, AppMeasureExitMessage exit) { + if (device.getDesc().contains("开卷机") || device.getDesc().contains("活套") || device.getDesc().contains("焊机")) { + return entry; + } else if (device.getDesc().contains("清洗段") || device.getDesc().contains("退火炉")) { + return furnace; + } else if (device.getDesc().contains("涂机")) { + return coat; + } else { + return exit; + } + } + + private double getSpeedForDevice(DeviceEnum device, AppMeasureEntryMessage entry, AppMeasureFurnaceMessage furnace, AppMeasureExitMessage exit) { + if (device.getDesc().contains("开卷机") || device.getDesc().contains("活套") || device.getDesc().contains("焊机")) { + return entry != null && entry.getStripSpeed() != null ? entry.getStripSpeed().doubleValue() : 0.0; + } else if (device.getDesc().contains("清洗段") || device.getDesc().contains("退火炉")) { + return furnace != null && furnace.getStripSpeed() != null ? furnace.getStripSpeed().doubleValue() : 0.0; + } else { + return exit != null && exit.getSpeedExitSection() != null ? exit.getSpeedExitSection().doubleValue() : 0.0; + } + } + + private double procStripSpeed(AppMeasureEntryMessage entry, AppMeasureFurnaceMessage furnace, AppMeasureExitMessage exit) { + if (entry != null && entry.getStripSpeed() != null) return entry.getStripSpeed().doubleValue(); + if (furnace != null && furnace.getStripSpeed() != null) return furnace.getStripSpeed().doubleValue(); + if (exit != null && exit.getSpeedExitSection() != null) return exit.getSpeedExitSection().doubleValue(); + return 0.0; + } + + private BigDecimal getFieldFromMessage(Object message, String fieldName) { + if (message == null || fieldName == null) return null; + try { + String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + Method getter = message.getClass().getMethod(getterName); + Object value = getter.invoke(message); + + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } else if (value instanceof Number) { + return BigDecimal.valueOf(((Number) value).doubleValue()); + } else { + return null; + } + } catch (Exception e) { + System.err.println("Error getting field " + fieldName + " from message: " + e.getMessage()); + return null; + } + } + + private void setSegValue(Map segValues, String key, BigDecimal value) { + if (value != null) { + segValues.computeIfAbsent(key, k -> new SegValue()).add(value); + } + } + + /** + * 【新方法】 + * 专门用于处理钢卷头部在设备间的移动和物料跟踪。 + * 这部分逻辑包含了对 Redis/DB 的写入,最适合异步化。 + */ + @Async("taskExecutor") + public void trackCoilHeadPosition(String coilId, BigDecimal headPos, + AppMeasureEntryMessage entry, AppMeasureExitMessage exit) { + + Set prevReached = coilReachedDevices.computeIfAbsent(coilId, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())); + + BigDecimal celLength = entry != null ? entry.getCelLength() : BigDecimal.ZERO; + BigDecimal cxlLength = exit != null ? exit.getCxlLength() : BigDecimal.ZERO; + + for (DeviceEnum d : DeviceEnum.values()) { + double dynPos = stripPositionService.calculate(d, celLength, cxlLength); + + // 判断钢卷的头部是否首次到达该设备 + if (headPos.compareTo(BigDecimal.valueOf(dynPos)) >= 0) { + if (!prevReached.contains(d)) { + + // 1. 如果是焊机,则调用 CRM 更新计划状态 + if (d == WELDER) { + + MatmapDTO matmap = MatmapUtil.getMatmap(WELDER.getIdx()); + trackService.l1OperateMat(L1OperateMatForm.builder() + .entryMatId(coilId) + .planId(matmap.getPlanId()) + .porIdx(entry.getPayOffReelNumber()) + .operation(L1OperateMatEnum.PRODUCING) + .build()); + } + + // 2. 更新 Matmap + MatmapUtil.setMatId(d.getIdx(), coilId); + WebSocketUtil.sendMatmapMsg(); + // 3. 标记为已到达,防止重复操作 + prevReached.add(d); + } + } + } + } +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/service/strip/StripPositionService.java b/business/src/main/java/com/fizz/business/service/strip/StripPositionService.java new file mode 100644 index 0000000..ef5c52e --- /dev/null +++ b/business/src/main/java/com/fizz/business/service/strip/StripPositionService.java @@ -0,0 +1,68 @@ +package com.fizz.business.service.strip; + +import com.fizz.business.constants.enums.DeviceEnum; +import com.fizz.business.domain.msg.AppMeasureEntryMessage; +import com.fizz.business.domain.msg.AppMeasureExitMessage; +import org.springframework.stereotype.Service; + + +import java.math.BigDecimal; + +/** + * 位置计算服务 —— 根据 entry.stripLocation(焊机参考)和活套长度动态判断设备的比较位置 + */ +@Service +public class StripPositionService { + + /** + * 计算设备在 entry 坐标系的“比较位置” + * + * 规则: + * - device.basePosition < ENL_MIN : 不加活套 + * - ENL_MIN <= device.basePosition < CXL_MIN : 加 celLength + * - >= CXL_MIN : 加 cxlLength + */ + public double calculate(DeviceEnum device, BigDecimal celLength, BigDecimal cxlLength) { + double base = device.getBasePosition(); + double cel = celLength == null ? 0.0 : celLength.doubleValue(); + double cxl = cxlLength == null ? 0.0 : cxlLength.doubleValue(); + + double enlMin = findEnlMin(); + double cxlMin = findCxlMin(); + + if (base < enlMin) { + return base; + } else if (base < cxlMin) { + return base + cel; + } else { + return base + cxl; + } + } + + public double calculate(DeviceEnum device,AppMeasureEntryMessage entry, + AppMeasureExitMessage exit) { + BigDecimal cel = entry == null ? null : entry.getCelLength(); + BigDecimal cxl = exit == null ? null : exit.getCxlLength(); + return calculate(device, cel, cxl); + } + + private double findEnlMin() { + double min = Double.MAX_VALUE; + for (DeviceEnum d : DeviceEnum.values()) { + if (d.name().startsWith("ENL")) { + min = Math.min(min, d.getBasePosition()); + } + } + return min == Double.MAX_VALUE ? 0.0 : min; + } + + private double findCxlMin() { + double min = Double.MAX_VALUE; + for (DeviceEnum d : DeviceEnum.values()) { + if (d.name().startsWith("CXL")) { + min = Math.min(min, d.getBasePosition()); + } + } + return min == Double.MAX_VALUE ? Double.MAX_VALUE : min; + } +} \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/utils/CoilMeasUtil.java b/business/src/main/java/com/fizz/business/utils/CoilMeasUtil.java index b626e35..6a78cdb 100644 --- a/business/src/main/java/com/fizz/business/utils/CoilMeasUtil.java +++ b/business/src/main/java/com/fizz/business/utils/CoilMeasUtil.java @@ -1,23 +1,21 @@ package com.fizz.business.utils; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import com.alibaba.fastjson.JSON; import com.fizz.business.constants.enums.DeviceEnum; import com.fizz.business.domain.DeviceDefine; -import com.fizz.business.dto.*; +import com.fizz.business.dto.CoilHeadDTO; +import com.fizz.business.dto.CoilPositionDTO; +import com.fizz.business.dto.L1CoilLineMeasureDTO; +import com.fizz.business.dto.MatmapDTO; import com.fizz.business.service.client.RedisCacheManager; import com.fizz.business.service.impl.BeanFactory; import com.google.common.collect.Lists; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.*; -import java.util.stream.Collectors; +import java.util.List; +import java.util.Objects; import static com.fizz.business.constants.CommonConstants.CoilMeasure.BEFORE_TR_IDX; -import static com.fizz.business.service.client.LocalCacheManager.DEVICE_DEFINE_MAP; /** @@ -67,9 +65,7 @@ public class CoilMeasUtil { Integer trIdx = null; if (trCode == 1) { - trIdx = DeviceEnum.TR1.getIdx(); - } else if (trCode == 2) { - trIdx = DeviceEnum.TR2.getIdx(); + trIdx = DeviceEnum.TR.getIdx(); } else { log.warn("W: invalid working TR, trCode={}", trCode); } @@ -81,7 +77,7 @@ public class CoilMeasUtil { } public static List getTrIdxList() { - return Lists.newArrayList(DeviceEnum.TR1.getIdx(), DeviceEnum.TR2.getIdx()); + return Lists.newArrayList(DeviceEnum.TR.getIdx()); } /** @@ -93,147 +89,4 @@ public class CoilMeasUtil { return BEFORE_TR_IDX.getIdx(); } - public static double initStripLocation(double stripLocation) { - if (stripLocation < 0) { - stripLocation = 0; - } else if (stripLocation > 25000) { - stripLocation = 25000; - } - return stripLocation; - } - - public static DeviceDefine matchDevice(double posLen, double entryLoopLen, double exitLoopLen) { - DeviceDefine mCEL = DEVICE_DEFINE_MAP.get(DeviceEnum.CEL.name()); // 入口活套 - DeviceDefine mCXL = DEVICE_DEFINE_MAP.get(DeviceEnum.CXL.name()); // 出口活套 - for (DeviceDefine device : DEVICE_DEFINE_MAP.values()) { - Double start = device.getPositionLengthStart(); - Double end = device.getPositionLengthEnd(); - // 入口活套之后的设备,需要加上entryLoopLen - if (device.getPosIdx() >= mCEL.getPosIdx()) { -// start = NumberUtil.add(start, entryLoopLen); - end = NumberUtil.add(end, entryLoopLen); - } - // 出口活套之后的设备,还需要加上exitLoopLen - if (device.getPosIdx() >= mCXL.getPosIdx()) { -// start = NumberUtil.add(start, exitLoopLen); - end = NumberUtil.add(end, exitLoopLen); - } - if (posLen >= start && posLen < end) { - return device; - } - } - - return null; - } - - public static CoilPositionDTO buildCoilPos(L1CoilLineMeasureDTO measureDTO, List headList) { - List coilStripLocationList = Lists.newArrayList(); - Integer workPor = measureDTO.getWorkPor(); - Integer workTr = measureDTO.getWorkTr(); - - CoilHeadDTO prevHead = BeanFactory.getBean(RedisCacheManager.class).getPrevHead(); - if (Objects.nonNull(prevHead)) { - coilStripLocationList.add( - CoilPositionDTO.CoilStripLocation.builder() - .matId(prevHead.getMatId()) - .planId(prevHead.getPlanId()) - .planNo(prevHead.getPlanNo()) - .porId(prevHead.getPorIdx()) - .stripLocation(99999).build()); - } - headList.forEach(head -> coilStripLocationList.add( - CoilPositionDTO.CoilStripLocation.builder() - .matId(head.getMatId()) - .planId(head.getPlanId()) - .planNo(head.getPlanNo()) - .porId(head.getPorIdx()) - .stripLocation(head.getPos()).build())); - - // 两个开卷机时,需要设置另一个未运行的开卷机上的钢卷数据 - Integer anotherPorIdx = getAnotherPorIdx(workPor); - if (Objects.nonNull(anotherPorIdx)) { - MatmapDTO matmap = MatmapUtil.getMatmap(anotherPorIdx); - coilStripLocationList.add( - CoilPositionDTO.CoilStripLocation.builder() - .matId(matmap.getMatId()) - .planId(matmap.getPlanId()) - .planNo(matmap.getPlanNo()) - .porId(anotherPorIdx) - .stripLocation(0).build()); - } - - // 当前开卷机与焊机的卷号不同时,需要设置当前开卷机上的钢卷数据(这种情况只出现在只有一个开卷机运行的时候) - Integer porIdx = CoilMeasUtil.getPorIdx(workPor); - MatmapDTO welderCoil = MatmapUtil.getMatmap(DeviceEnum.WELDER.getIdx()); - if (Objects.nonNull(porIdx) && MatmapUtil.already(welderCoil)) { - MatmapDTO porCoil = MatmapUtil.getMatmap(porIdx); - if (!Objects.equals(welderCoil.getMatId(), porCoil.getMatId())) { - coilStripLocationList.add( - CoilPositionDTO.CoilStripLocation.builder() - .matId(porCoil.getMatId()) - .planId(porCoil.getPlanId()) - .planNo(porCoil.getPlanNo()) - .porId(porIdx) - .stripLocation(0).build()); - } - } - - return CoilPositionDTO.builder() - .coilStripLocationList(coilStripLocationList) - .entryLoopLen(measureDTO.getEntryLoopLength()) - .exitLoopLen(measureDTO.getExitLoopLength()) - .entryLoopPer(measureDTO.getEntryLoopPercent()) - .exitLoopLPer(measureDTO.getExitLoopPercent()) - .entrySpeed(measureDTO.getInSpeed()) - .technologySpeed(measureDTO.getUnitSpeed()) - .exitSpeed(measureDTO.getOutSpeed()) - .porId(CoilMeasUtil.getPorIdx(workPor)) - .trId(CoilMeasUtil.getTrIdx(workTr)) - .build(); - } - - public static double getPorSpeed(L1CoilLineMeasureDTO measureDTO) { - return measureDTO.getUnitSpeed(); - } - -// public static List getParamKey(String deviceName) { -// List list = DEVICE_PARAM_MAP.get(deviceName); -// if (CollUtil.isEmpty(list)) { -// return Collections.emptyList(); -// } -// return list.stream().map(PointConfigDTO::getParam).collect(Collectors.toList()); -// } -// -// public static String getParamKey(String deviceName, String paramDesc) { -// List list = DEVICE_PARAM_MAP.get(deviceName); -// if (CollUtil.isEmpty(list)) { -// return null; -// } -// List keys = list.stream() -// .filter(p -> paramDesc.equals(p.getDesc())) -// .map(PointConfigDTO::getParam) -// .collect(Collectors.toList()); -// if (CollUtil.isEmpty(keys)) { -// return null; -// } -// return keys.get(0); -// } - -// public static List getParamDesc(String deviceName) { -// List list = DEVICE_PARAM_MAP.get(deviceName); -// if (CollUtil.isEmpty(list)) { -// return Collections.emptyList(); -// } -// return list.stream().map(PointConfigDTO::getDesc).collect(Collectors.toList()); -// } -// -// public static LinkedHashMap getParamMap(String deviceName) { -// List list = DEVICE_PARAM_MAP.get(deviceName); -// if (CollUtil.isEmpty(list)) { -// return Maps.newLinkedHashMap(); -// } -// -// return list.stream().collect(Collectors.toMap(PointConfigDTO::getParam, PointConfigDTO::getDesc, (k1, k2) -> k1, LinkedHashMap::new)); -// } - } diff --git a/business/src/main/java/com/fizz/business/utils/WebSocketUtil.java b/business/src/main/java/com/fizz/business/utils/WebSocketUtil.java index 17559da..6ac1a62 100644 --- a/business/src/main/java/com/fizz/business/utils/WebSocketUtil.java +++ b/business/src/main/java/com/fizz/business/utils/WebSocketUtil.java @@ -6,6 +6,8 @@ import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.fizz.business.constants.CommonConstants; import com.fizz.business.constants.enums.WsTypeEnum; +import com.fizz.business.domain.msg.AppMeasureEntryMessage; +import com.fizz.business.domain.msg.AppMeasureMessage; import com.fizz.business.dto.CoilPositionDTO; import com.fizz.business.dto.L1CoilLineMeasureDTO; import com.fizz.business.dto.MatmapDTO; @@ -79,6 +81,13 @@ public class WebSocketUtil { sendMessage(WsTypeEnum.track_measure, JSONUtil.toJsonStr(measureDTO)); } + public static void sendMeasureMsg(AppMeasureMessage measureDTO) { + + + sendMessage(WsTypeEnum.track_measure, JSONUtil.toJsonStr(measureDTO)); + } + + public static void sendMatmapMsg() { List list = MatmapUtil.getMatmapList(); if (CollUtil.isEmpty(list)) return; diff --git a/business/src/main/java/com/fizz/business/vo/ReportDetailVO.java b/business/src/main/java/com/fizz/business/vo/ReportDetailVO.java new file mode 100644 index 0000000..7c9f448 --- /dev/null +++ b/business/src/main/java/com/fizz/business/vo/ReportDetailVO.java @@ -0,0 +1,47 @@ +package com.fizz.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Schema(name = "ReportDetailVO", description = "钢卷明细信息") +public class ReportDetailVO { + + @Schema(description = "成品卷号") + private String exitMatId; + + @Schema(description = "原料卷号") + private String entryMatId; + + @Schema(description = "班号") + private String groupNo; + + @Schema(description = "组号") + private String shiftNo; + + @Schema(description = "钢种") + private String steelGrade; + + @Schema(description = "成品宽度") + private Double exitWidth; + + @Schema(description = "成品长度") + private Double exitLength; + + @Schema(description = "理论重量") + private Double theoryWeight; + + @Schema(description = "实际重量") + private Double actualWeight; + + @Schema(description = "成品厚度") + private Double exitThickness; + + @Schema(description = "上线时间") + private LocalDateTime onlineTime; + + @Schema(description = "结束时间") + private LocalDateTime endTime; +} diff --git a/business/src/main/java/com/fizz/business/vo/ReportSummaryVO.java b/business/src/main/java/com/fizz/business/vo/ReportSummaryVO.java new file mode 100644 index 0000000..6f1e453 --- /dev/null +++ b/business/src/main/java/com/fizz/business/vo/ReportSummaryVO.java @@ -0,0 +1,51 @@ +package com.fizz.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(name = "ReportSummaryVO", description = "报表汇总统计结果") +public class ReportSummaryVO { + + // 汇总指标 + @Schema(description = "总成品宽度") + private Double totalExitWidth; + + @Schema(description = "总成品长度") + private Double totalExitLength; + + @Schema(description = "总理论重量") + private Double totalTheoryWeight; + + @Schema(description = "总实际重量") + private Double totalActualWeight; + + @Schema(description = "总成品厚度") + private Double totalExitThickness; + + // 平均指标 + @Schema(description = "平均成品宽度") + private Double avgExitWidth; + + @Schema(description = "平均成品长度") + private Double avgExitLength; + + @Schema(description = "平均理论重量") + private Double avgTheoryWeight; + + @Schema(description = "平均实际重量") + private Double avgActualWeight; + + @Schema(description = "平均成品厚度") + private Double avgExitThickness; + + // 新增指标 + @Schema(description = "钢卷总数") + private Long coilCount; + + @Schema(description = "原料总重(去重计算)") + private Double totalEntryWeight; + + @Schema(description = "成材率(成品实际重量/原料重量)") + private Double yieldRate; +} \ No newline at end of file diff --git a/business/src/main/resources/mapper/CrmPdoExcoilMapper.xml b/business/src/main/resources/mapper/CrmPdoExcoilMapper.xml index c23d813..f82ee39 100644 --- a/business/src/main/resources/mapper/CrmPdoExcoilMapper.xml +++ b/business/src/main/resources/mapper/CrmPdoExcoilMapper.xml @@ -3,4 +3,139 @@ + + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java index 05b60e3..31d70e0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java @@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; /** * 启动程序 @@ -11,6 +12,7 @@ import org.springframework.context.annotation.ComponentScan; * @author ruoyi */ @ComponentScan(basePackages = {"com.ruoyi","com.fizz"}) +@EnableAsync // 启用异步处理 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class RuoYiApplication { diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 899b016..2aec294 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -74,9 +74,9 @@ spring: port: 6379 # 数据库索引 database: 0 - # 密码 abcd1234 fe2b3cef78b74d3692909bdcbdf46331 KeLunPu123! - password: KeLunPu123! - #password: +# 密码 abcd1234 fe2b3cef78b74d3692909bdcbdf46331 KeLunPu123! +# password: KeLunPu123! + password: abcd1234 # 连接超时时间 timeout: 10s lettuce: @@ -140,10 +140,10 @@ xss: # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* -#rocketmq: - #name-server: 127.0.0.1:9876 - #producer: - #group: test + #rocketmq: + #name-server: 127.0.0.1:9876 + #producer: + #group: test springdoc: api-docs: