OEE添加镀锌接口
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package com.klp.pocket.galvanize1.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeCoilInfoByDateVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
@DS("master")
|
||||
public interface GalvanizeOeeMasterMapper {
|
||||
|
||||
List<AcidOeeDailySummaryVo> selectDailySummary(@Param("startDate") String startDate,
|
||||
@Param("endDate") String endDate,
|
||||
@Param("createBy") String createBy);
|
||||
|
||||
List<AcidOeeCoilInfoByDateVo> selectCoilInfoByDate(@Param("startDate") String startDate,
|
||||
@Param("endDate") String endDate,
|
||||
@Param("createBy") String createBy);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.klp.pocket.galvanize1.service;
|
||||
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeIdealCycleVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.domain.vo.Klptcm1ProStoppageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IGalvanizeOeeService {
|
||||
|
||||
List<AcidOeeDailySummaryVo> getDailySummary(String startDate, String endDate);
|
||||
|
||||
List<Klptcm1ProStoppageVo> getStoppageEvents(String startDate, String endDate);
|
||||
|
||||
List<AcidOeeLoss7Vo> getLoss7Summary(String startDate, String endDate);
|
||||
|
||||
AcidOeeIdealCycleVo getIdealCycle(String startDate, String endDate);
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package com.klp.pocket.galvanize1.service.impl;
|
||||
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeCoilInfoByDateVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeIdealCycleVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.domain.vo.Klptcm1ProStoppageVo;
|
||||
import com.klp.pocket.galvanize1.domain.bo.ProStoppageBo;
|
||||
import com.klp.pocket.galvanize1.domain.vo.ProStoppageVo;
|
||||
import com.klp.pocket.galvanize1.mapper.GalvanizeOeeMasterMapper;
|
||||
import com.klp.pocket.galvanize1.service.IGalvanizeOeeService;
|
||||
import com.klp.pocket.galvanize1.service.IProStoppageService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class GalvanizeOeeServiceImpl implements IGalvanizeOeeService {
|
||||
|
||||
private static final Set<String> CD_SERIES = new HashSet<>(Arrays.asList("C+", "C", "C-", "D+", "D", "D-"));
|
||||
|
||||
private final GalvanizeOeeMasterMapper galvanizeOeeMasterMapper;
|
||||
private final IProStoppageService proStoppageService;
|
||||
|
||||
@Value("${oee.galvanize1.coil-create-by:duxinkuguan}")
|
||||
private String galvanizeCreateBy;
|
||||
|
||||
@Override
|
||||
public List<AcidOeeDailySummaryVo> getDailySummary(String startDate, String endDate) {
|
||||
List<AcidOeeDailySummaryVo> summaries = galvanizeOeeMasterMapper.selectDailySummary(startDate, endDate, galvanizeCreateBy);
|
||||
if (summaries == null || summaries.isEmpty()) return Collections.emptyList();
|
||||
|
||||
Map<String, Long> downtimeByDate = aggregateDowntimeByDate(startDate, endDate);
|
||||
Map<String, List<CoilInfo>> coilInfoByDate = getCoilNosByDate(startDate, endDate);
|
||||
|
||||
List<BigDecimal> dailyCycles = new ArrayList<>();
|
||||
for (AcidOeeDailySummaryVo s : summaries) {
|
||||
s.setLineId("DX1");
|
||||
s.setLineName("镀锌一线");
|
||||
Long downtime = downtimeByDate.getOrDefault(s.getStatDate(), 0L);
|
||||
s.setDowntimeMin(downtime);
|
||||
Long loading = s.getLoadingTimeMin() == null ? 0L : s.getLoadingTimeMin();
|
||||
Long run = Math.max(0, loading - downtime);
|
||||
s.setRunTimeMin(run);
|
||||
BigDecimal ton = s.getTotalOutputTon();
|
||||
if (run > 0 && ton != null && ton.compareTo(BigDecimal.ZERO) > 0) {
|
||||
dailyCycles.add(BigDecimal.valueOf(run).divide(ton, 6, RoundingMode.HALF_UP));
|
||||
}
|
||||
}
|
||||
dailyCycles.sort(BigDecimal::compareTo);
|
||||
BigDecimal ideal = applyEightyPercent(median(dailyCycles));
|
||||
|
||||
for (AcidOeeDailySummaryVo s : summaries) {
|
||||
if (ideal != null) s.setIdealCycleTimeMinPerTon(ideal);
|
||||
List<CoilInfo> coilInfos = coilInfoByDate.get(s.getStatDate());
|
||||
if (coilInfos != null) {
|
||||
calculateQualityOutput(s, coilInfos);
|
||||
} else {
|
||||
s.setGoodOutputTon(BigDecimal.ZERO);
|
||||
s.setGoodOutputCoil(0L);
|
||||
s.setQualifiedOutputTon(BigDecimal.ZERO);
|
||||
s.setQualifiedOutputCoil(0L);
|
||||
s.setAbOutputTon(BigDecimal.ZERO);
|
||||
s.setAbOutputCoil(0L);
|
||||
s.setDefectOutputTon(BigDecimal.ZERO);
|
||||
s.setDefectOutputCoil(0L);
|
||||
s.setPendingOutputTon(s.getTotalOutputTon());
|
||||
s.setPendingOutputCoil(s.getTotalOutputCoil());
|
||||
}
|
||||
calculateDerivedMetrics(s);
|
||||
}
|
||||
return summaries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Klptcm1ProStoppageVo> getStoppageEvents(String startDate, String endDate) {
|
||||
ProStoppageBo bo = new ProStoppageBo();
|
||||
bo.setStartDate(parseDate(startDate));
|
||||
bo.setEndDate(parseDate(endDate));
|
||||
List<ProStoppageVo> list = proStoppageService.queryList(bo);
|
||||
List<Klptcm1ProStoppageVo> out = new ArrayList<>();
|
||||
for (ProStoppageVo p : list) {
|
||||
Klptcm1ProStoppageVo v = new Klptcm1ProStoppageVo();
|
||||
v.setStopid(p.getStopid());
|
||||
v.setShift(p.getShift());
|
||||
v.setCrew(p.getCrew());
|
||||
v.setArea(p.getArea());
|
||||
v.setUnit(p.getUnit());
|
||||
v.setSeton(p.getSeton());
|
||||
v.setStartDate(p.getStartDate());
|
||||
v.setEndDate(p.getEndDate());
|
||||
v.setRemark(p.getRemark());
|
||||
v.setStopType(p.getStopType());
|
||||
long durationSec = p.getDuration() == null ? 0L : Math.round(p.getDuration());
|
||||
v.setDuration(durationSec);
|
||||
out.add(v);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AcidOeeLoss7Vo> getLoss7Summary(String startDate, String endDate) {
|
||||
List<Klptcm1ProStoppageVo> events = getStoppageEvents(startDate, endDate);
|
||||
if (events.isEmpty()) return Collections.emptyList();
|
||||
Map<String, long[]> m = new HashMap<>();
|
||||
long total = 0L;
|
||||
for (Klptcm1ProStoppageVo e : events) {
|
||||
String k = StringUtils.isBlank(e.getStopType()) ? "未分类" : e.getStopType();
|
||||
long min = Math.max(1, (e.getDuration() == null ? 0L : e.getDuration()) / 60);
|
||||
if (min <= 0) continue;
|
||||
m.computeIfAbsent(k, x -> new long[2]);
|
||||
m.get(k)[0] += min;
|
||||
m.get(k)[1] += 1;
|
||||
total += min;
|
||||
}
|
||||
List<AcidOeeLoss7Vo> out = new ArrayList<>();
|
||||
for (Map.Entry<String, long[]> en : m.entrySet()) {
|
||||
AcidOeeLoss7Vo vo = new AcidOeeLoss7Vo();
|
||||
vo.setLossCategoryCode(en.getKey());
|
||||
vo.setLossCategoryName(en.getKey());
|
||||
vo.setLossTimeMin(en.getValue()[0]);
|
||||
vo.setCount((int) en.getValue()[1]);
|
||||
vo.setAvgDurationMin(BigDecimal.valueOf(en.getValue()[0]).divide(BigDecimal.valueOf(Math.max(1, en.getValue()[1])), 2, RoundingMode.HALF_UP));
|
||||
vo.setLossTimeRate(total == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(en.getValue()[0]).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
out.add(vo);
|
||||
}
|
||||
out.sort(Comparator.comparingLong(AcidOeeLoss7Vo::getLossTimeMin).reversed());
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AcidOeeIdealCycleVo getIdealCycle(String startDate, String endDate) {
|
||||
List<AcidOeeDailySummaryVo> daily = getDailySummary(startDate, endDate);
|
||||
AcidOeeIdealCycleVo rsp = new AcidOeeIdealCycleVo();
|
||||
rsp.setLineId("DX1");
|
||||
rsp.setLineName("镀锌一线");
|
||||
rsp.setStartDate(startDate);
|
||||
rsp.setEndDate(endDate);
|
||||
if (daily.isEmpty()) {
|
||||
rsp.setDailyComparePoints(Collections.emptyList());
|
||||
rsp.setSampleDays(0);
|
||||
return rsp;
|
||||
}
|
||||
List<BigDecimal> dailyCycles = new ArrayList<>();
|
||||
List<AcidOeeIdealCycleVo.DailyComparePointVo> points = new ArrayList<>();
|
||||
for (AcidOeeDailySummaryVo d : daily) {
|
||||
if (d.getRunTimeMin() == null || d.getRunTimeMin() <= 0 || d.getTotalOutputTon() == null || d.getTotalOutputTon().compareTo(BigDecimal.ZERO) <= 0) continue;
|
||||
BigDecimal c = BigDecimal.valueOf(d.getRunTimeMin()).divide(d.getTotalOutputTon(), 6, RoundingMode.HALF_UP);
|
||||
dailyCycles.add(c);
|
||||
}
|
||||
dailyCycles.sort(BigDecimal::compareTo);
|
||||
BigDecimal med = median(dailyCycles);
|
||||
BigDecimal ideal = applyEightyPercent(med);
|
||||
for (AcidOeeDailySummaryVo d : daily) {
|
||||
if (ideal == null || d.getTotalOutputTon() == null || d.getRunTimeMin() == null) continue;
|
||||
AcidOeeIdealCycleVo.DailyComparePointVo p = new AcidOeeIdealCycleVo.DailyComparePointVo();
|
||||
p.setStatDate(d.getStatDate());
|
||||
p.setActualRunTimeMin(d.getRunTimeMin());
|
||||
p.setTheoreticalTimeMin(ideal.multiply(d.getTotalOutputTon()));
|
||||
points.add(p);
|
||||
}
|
||||
rsp.setIdealCycleTimeMinPerTon(ideal);
|
||||
rsp.setMedianCycleTimeMinPerTon(med);
|
||||
rsp.setSampleDays(daily.size());
|
||||
rsp.setDailyComparePoints(points);
|
||||
return rsp;
|
||||
}
|
||||
|
||||
private Map<String, List<CoilInfo>> getCoilNosByDate(String startDate, String endDate) {
|
||||
List<AcidOeeCoilInfoByDateVo> list = galvanizeOeeMasterMapper.selectCoilInfoByDate(startDate, endDate, galvanizeCreateBy);
|
||||
Map<String, List<CoilInfo>> map = new HashMap<>();
|
||||
for (AcidOeeCoilInfoByDateVo i : list) {
|
||||
map.computeIfAbsent(i.getStatDate(), k -> new ArrayList<>()).add(new CoilInfo(i.getWeight(), i.getQualityStatus()));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void calculateQualityOutput(AcidOeeDailySummaryVo summary, List<CoilInfo> coilInfos) {
|
||||
BigDecimal aTon = BigDecimal.ZERO, bTon = BigDecimal.ZERO, cdTon = BigDecimal.ZERO, oTon = BigDecimal.ZERO;
|
||||
long a = 0, b = 0, cd = 0, o = 0;
|
||||
for (CoilInfo c : coilInfos) {
|
||||
BigDecimal w = c.weight == null ? BigDecimal.ZERO : c.weight;
|
||||
String q = StringUtils.upperCase(StringUtils.trim(c.qualityStatus));
|
||||
if (StringUtils.isBlank(q) || "O".equals(q)) {
|
||||
oTon = oTon.add(w); o++; continue;
|
||||
}
|
||||
if (q.startsWith("A")) { aTon = aTon.add(w); a++; }
|
||||
else if (q.startsWith("B")) { bTon = bTon.add(w); b++; }
|
||||
else if (CD_SERIES.contains(q)) { cdTon = cdTon.add(w); cd++; }
|
||||
else { oTon = oTon.add(w); o++; }
|
||||
}
|
||||
summary.setGoodOutputTon(aTon); summary.setGoodOutputCoil(a);
|
||||
summary.setQualifiedOutputTon(bTon); summary.setQualifiedOutputCoil(b);
|
||||
summary.setAbOutputTon(aTon.add(bTon)); summary.setAbOutputCoil(a + b);
|
||||
summary.setDefectOutputTon(cdTon); summary.setDefectOutputCoil(cd);
|
||||
summary.setPendingOutputTon(oTon); summary.setPendingOutputCoil(o);
|
||||
}
|
||||
|
||||
private void calculateDerivedMetrics(AcidOeeDailySummaryVo s) {
|
||||
long loading = s.getLoadingTimeMin() == null ? 0 : s.getLoadingTimeMin();
|
||||
long downtime = s.getDowntimeMin() == null ? 0 : s.getDowntimeMin();
|
||||
if (loading > 0) s.setAvailability(BigDecimal.valueOf(loading - downtime).divide(BigDecimal.valueOf(loading), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
long run = s.getRunTimeMin() == null ? 0 : s.getRunTimeMin();
|
||||
BigDecimal ideal = s.getIdealCycleTimeMinPerTon();
|
||||
BigDecimal ton = s.getTotalOutputTon();
|
||||
if (run > 0 && ideal != null && ideal.compareTo(BigDecimal.ZERO) > 0 && ton != null && ton.compareTo(BigDecimal.ZERO) > 0) {
|
||||
s.setPerformanceTon(ideal.multiply(ton).divide(BigDecimal.valueOf(run), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
}
|
||||
if (ton != null && ton.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal a = Optional.ofNullable(s.getGoodOutputTon()).orElse(BigDecimal.ZERO);
|
||||
BigDecimal b = Optional.ofNullable(s.getQualifiedOutputTon()).orElse(BigDecimal.ZERO);
|
||||
BigDecimal cd = Optional.ofNullable(s.getDefectOutputTon()).orElse(BigDecimal.ZERO);
|
||||
BigDecimal o = Optional.ofNullable(s.getPendingOutputTon()).orElse(BigDecimal.ZERO);
|
||||
s.setQuality(a.divide(ton, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
s.setQualifiedRate(a.add(b).divide(ton, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
s.setDefectRate(cd.divide(ton, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
s.setPendingRate(o.divide(ton, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
|
||||
}
|
||||
if (s.getAvailability() != null && s.getPerformanceTon() != null && s.getQuality() != null) {
|
||||
s.setOee(s.getAvailability().multiply(s.getPerformanceTon()).multiply(s.getQuality()).divide(BigDecimal.valueOf(10000), 4, RoundingMode.HALF_UP));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Long> aggregateDowntimeByDate(String startDate, String endDate) {
|
||||
List<Klptcm1ProStoppageVo> events = getStoppageEvents(startDate, endDate);
|
||||
Map<String, Long> map = new HashMap<>();
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
for (Klptcm1ProStoppageVo e : events) {
|
||||
if (e.getStartDate() == null || e.getDuration() == null || e.getDuration() <= 0) continue;
|
||||
long min = Math.max(1, (e.getDuration() + 59) / 60);
|
||||
map.merge(df.format(e.getStartDate()), min, Long::sum);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private BigDecimal median(List<BigDecimal> values) {
|
||||
if (values == null || values.isEmpty()) return null;
|
||||
int n = values.size();
|
||||
if (n % 2 == 1) return values.get(n / 2);
|
||||
return values.get(n / 2 - 1).add(values.get(n / 2)).divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal applyEightyPercent(BigDecimal v) {
|
||||
return v == null ? null : v.multiply(BigDecimal.valueOf(0.7)).setScale(6, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private Date parseDate(String dateStr) {
|
||||
if (StringUtils.isBlank(dateStr)) return null;
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CoilInfo {
|
||||
final BigDecimal weight;
|
||||
final String qualityStatus;
|
||||
|
||||
CoilInfo(BigDecimal weight, String qualityStatus) {
|
||||
this.weight = weight;
|
||||
this.qualityStatus = qualityStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user