123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- package com.jjt.calc.service.impl;
- import com.jjt.biz.domain.TwinDevice;
- import com.jjt.biz.service.ITwinDeviceService;
- import com.jjt.calc.domain.TwinCalcAlarms;
- import com.jjt.calc.domain.TwinCalcDay;
- import com.jjt.calc.domain.TwinCalcHour;
- import com.jjt.calc.domain.TwinCalcStop;
- import com.jjt.calc.mapper.TwinCalcDayMapper;
- import com.jjt.calc.service.ITwinCalcAlarmsService;
- import com.jjt.calc.service.ITwinCalcDayService;
- import com.jjt.calc.service.ITwinCalcHourService;
- import com.jjt.calc.service.ITwinCalcStopService;
- import com.jjt.common.utils.DateUtils;
- import com.jjt.utils.AsyncService;
- import com.jjt.utils.Tools;
- import javafx.util.Pair;
- import org.apache.ibatis.session.ExecutorType;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.springframework.stereotype.Service;
- import javax.annotation.Resource;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.util.*;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.Future;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.TimeoutException;
- import java.util.concurrent.atomic.AtomicLong;
- import java.util.function.BiConsumer;
- import java.util.stream.Collectors;
- /**
- * 日统计数据Service业务层处理
- *
- * @author wukai
- * @date 2025-01-18
- */
- @Service
- public class TwinCalcDayServiceImpl implements ITwinCalcDayService {
- @Resource
- private TwinCalcDayMapper twinCalcDayMapper;
- @Resource
- private ITwinCalcHourService hourService;
- @Resource
- private ITwinCalcStopService stopService;
- @Resource
- private ITwinCalcAlarmsService alarmsService;
- @Resource
- private ITwinDeviceService deviceService;
- @Resource
- private AsyncService asyncService;
- @Resource
- private SqlSessionFactory factory;
- /**
- * 查询日统计数据
- *
- * @param id 日统计数据主键
- * @return 日统计数据
- */
- @Override
- public TwinCalcDay selectTwinCalcDayById(Long id) {
- return twinCalcDayMapper.selectTwinCalcDayById(id);
- }
- /**
- * 查询日统计数据列表
- *
- * @param twinCalcDay 日统计数据
- * @return 日统计数据
- */
- @Override
- public List<TwinCalcDay> selectTwinCalcDayList(TwinCalcDay twinCalcDay) {
- return twinCalcDayMapper.selectTwinCalcDayList(twinCalcDay);
- }
- /**
- * 新增日统计数据
- *
- * @param twinCalcDay 日统计数据
- * @return 结果
- */
- @Override
- public int insertTwinCalcDay(TwinCalcDay twinCalcDay) {
- return twinCalcDayMapper.insertTwinCalcDay(twinCalcDay);
- }
- /**
- * 修改日统计数据
- *
- * @param twinCalcDay 日统计数据
- * @return 结果
- */
- @Override
- public int updateTwinCalcDay(TwinCalcDay twinCalcDay) {
- return twinCalcDayMapper.updateTwinCalcDay(twinCalcDay);
- }
- /**
- * 批量删除日统计数据
- *
- * @param ids 需要删除的日统计数据主键
- * @return 结果
- */
- @Override
- public int deleteTwinCalcDayByIds(Long[] ids) {
- return twinCalcDayMapper.deleteTwinCalcDayByIds(ids);
- }
- /**
- * 删除日统计数据信息
- *
- * @param id 日统计数据主键
- * @return 结果
- */
- @Override
- public int deleteTwinCalcDayById(Long id) {
- return twinCalcDayMapper.deleteTwinCalcDayById(id);
- }
- /**
- * 近日统计数据
- *
- * @param localDate 日期
- */
- @Override
- public void day(LocalDate localDate) {
- Date date = DateUtils.toDate(localDate);
- //先删除当前日期数据
- twinCalcDayMapper.delete4date(date);
- //计算统计时间
- Pair<Date, Date> pair = Tools.calcDay(localDate);
- Date sTime = pair.getKey();
- Date eTime = pair.getValue();
- List<TwinCalcHour> hourList = hourService.selectTwinCalcHourListByDate(sTime, eTime);
- List<TwinCalcStop> stopList = stopService.selectTwinCalcStopListByDate(sTime, eTime);
- List<TwinCalcAlarms> alarmsList = alarmsService.selectTwinCalcAlarmsListByDate(sTime, eTime);
- Pair<Date, Date> teamPairA = Tools.teamA(localDate);
- Pair<Date, Date> teamPairB = Tools.teamB(localDate);
- // 提取A班和B班的开始和结束时间,避免在循环中重复调用
- Date startTimeA = teamPairA.getKey();
- Date endTimeA = teamPairA.getValue();
- Date startTimeB = teamPairB.getKey();
- Date endTimeB = teamPairB.getValue();
- Map<Long, List<TwinCalcHour>> hourDeviceGroup = hourList.stream().collect(Collectors.groupingBy(TwinCalcHour::getDeviceId, LinkedHashMap::new, Collectors.toList()));
- List<TwinCalcDay> dayList = new ArrayList<>();
- for (Map.Entry<Long, List<TwinCalcHour>> entry : hourDeviceGroup.entrySet()) {
- List<TwinCalcHour> hours = entry.getValue();
- TwinCalcDay day = new TwinCalcDay(date);
- day.setDeviceId(entry.getKey());
- //计算产量数据
- day.calcHours(hours);
- //计算停机数据
- List<TwinCalcStop> stops = stopList.stream().filter(s -> s.getDeviceId().equals(entry.getKey())).collect(Collectors.toList());
- AtomicLong closeA = new AtomicLong(0L);
- AtomicLong closeB = new AtomicLong(0L);
- //A班停机计数
- BiConsumer<Integer, Integer> updateDayA = (type, count) -> {
- switch (type) {
- case 1:
- day.setStop1A(day.getStop1A() + count);
- break;
- case 2:
- day.setStop2A(day.getStop2A() + count);
- break;
- case 3:
- day.setStop3A(day.getStop3A() + count);
- break;
- default:
- }
- };
- BiConsumer<Integer, Integer> updateDayB = (type, count) -> {
- switch (type) {
- case 1:
- day.setStop1B(day.getStop1B() + count);
- break;
- case 2:
- day.setStop2B(day.getStop2B() + count);
- break;
- case 3:
- day.setStop3B(day.getStop3B() + count);
- break;
- default:
- }
- };
- // 使用Stream API,结合if-else逻辑的优化
- stops.forEach(stop -> {
- // 根据停机时间判断属于哪个班次
- boolean isAshift = !stop.getStartTime().after(endTimeA) && !stop.getEndTime().before(startTimeA);
- Date shiftStart = isAshift ? startTimeA : startTimeB;
- Date shiftEnd = isAshift ? endTimeA : endTimeB;
- AtomicLong totalStopTime = isAshift ? closeA : closeB;
- BiConsumer<Integer, Integer> eventCounter = isAshift ? updateDayA : updateDayB;
- // 调整停机时间
- if (stop.getEndTime().compareTo(shiftEnd) > 0) {
- stop.setEndTime(shiftEnd);
- }
- if (stop.getStartTime().compareTo(shiftStart) < 0) {
- stop.setStartTime(shiftStart);
- }
- // 计算并更新停机时间和事件计数
- long stopTime = (stop.getEndTime().getTime() - stop.getStartTime().getTime()) / 1000;
- updateStopCounters(stopTime, stop.getStopType(), totalStopTime, eventCounter);
- });
- //计算稼动率
- //AB班排班时间,要乘以设备总数
- long teamTimeA = 12L * 60 * 60;
- long teamTimeB = 12L * 60 * 60;
- long totalTeamTime = teamTimeA + teamTimeB;
- long openTimeA = teamTimeA - closeA.get();
- long openTimeB = teamTimeB - closeB.get();
- long totalOpenTime = openTimeA + openTimeB;
- BigDecimal ea = BigDecimal.valueOf(openTimeA).divide(BigDecimal.valueOf(teamTimeA), 4, RoundingMode.HALF_UP);
- BigDecimal eb = BigDecimal.valueOf(openTimeB).divide(BigDecimal.valueOf(teamTimeB), 4, RoundingMode.HALF_UP);
- BigDecimal ee = BigDecimal.valueOf(totalOpenTime).divide(BigDecimal.valueOf(totalTeamTime), 4, RoundingMode.HALF_UP);
- day.setOpenTimeA(BigDecimal.valueOf(openTimeA));
- day.setOpenTimeB(BigDecimal.valueOf(openTimeB));
- day.setCloseTimeA(BigDecimal.valueOf(closeA.get()));
- day.setCloseTimeB(BigDecimal.valueOf(closeB.get()));
- day.setEfficiencyA(ea);
- day.setEfficiencyB(eb);
- day.setEfficiency(ee);
- //如果米长为0,稼动率处理
- //20250317 潘工提的需求,把没有开机的设备也需要计算稼动
- if (day.getLengthA().doubleValue() == 0d) {
- day.setOpenTimeA(BigDecimal.ZERO);
- day.setCloseTimeA(BigDecimal.valueOf(teamTimeA));
- day.setEfficiencyA(BigDecimal.ZERO);
- }
- if (day.getLengthB().doubleValue() == 0d) {
- day.setOpenTimeB(BigDecimal.ZERO);
- day.setCloseTimeB(BigDecimal.valueOf(teamTimeB));
- day.setEfficiencyB(BigDecimal.ZERO);
- }
- if (day.getLength().doubleValue() == 0d) {
- day.setEfficiency(BigDecimal.ZERO);
- }
- List<TwinCalcAlarms> alarms = alarmsList.stream().filter(a -> a.getDeviceId().equals(entry.getKey())).collect(Collectors.toList());
- day.setAlarm((long) alarms.size());
- dayList.add(day);
- }
- try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
- TwinCalcDayMapper mapper = sqlSession.getMapper(TwinCalcDayMapper.class);
- dayList.forEach(mapper::insertTwinCalcDay);
- sqlSession.commit();
- }
- }
- /**
- * 用于更新停机时间计数器和事件计数
- *
- * @param stopTime 停机时间
- * @param stopType 停机类型
- * @param totalTimeCounter 停机总时间
- * @param eventCounterUpdater 抽象方法
- */
- private void updateStopCounters(long stopTime, int stopType, AtomicLong
- totalTimeCounter, BiConsumer<Integer, Integer> eventCounterUpdater) {
- totalTimeCounter.addAndGet(stopTime);
- eventCounterUpdater.accept(stopType, 1);
- }
- /**
- * 统计今天的产量数据
- *
- * @return 当日数据 7:00至第二天7点(不含)
- */
- @Override
- public TwinCalcDay today() {
- //计算统计时间
- Pair<Date, Date> pair = Tools.calcToday();
- Date sTime = pair.getKey();
- Date eTime = pair.getValue();
- List<TwinCalcHour> hourList = hourService.selectTwinCalcHourListByDate(sTime, eTime);
- // 按照deviceId、density、mick、team,并统计每组的length总和
- //按照deviceId分组统计
- Map<Long, BigDecimal> resultMap = hourList.stream().collect(Collectors.groupingBy(TwinCalcHour::getDeviceId, Collectors.reducing(BigDecimal.ZERO, TwinCalcHour::getLength, BigDecimal::add)));
- TwinCalcDay calcDay = new TwinCalcDay(sTime);
- if (hourList.size() > 0) {
- calcDay.calcHours(hourList);
- }
- List<TwinCalcHour> hours = new ArrayList<>();
- TwinCalcHour lastHour = hourService.lastHour();
- LocalDate localDate = DateUtils.toLocalDate(lastHour.getDataDate());
- LocalDateTime start = LocalDateTime.of(localDate, LocalTime.MIN).plusHours(lastHour.getHour() + 1);
- //为了避免多线程同时获取token导致重复执行,先执行一次获取token
- TwinDevice search = new TwinDevice();
- //查询所有在线的设备
- search.setOnline("1");
- List<TwinDevice> list = deviceService.selectTwinDeviceList(search);
- List<Future<Map<String, List<?>>>> futureList = new ArrayList<>();
- for (int i = 0; i < list.size(); i++) {
- TwinDevice twinDevice = list.get(i);
- futureList.add(asyncService.process(twinDevice, start, LocalDateTime.now()));
- }
- try {
- for (Future<Map<String, List<?>>> future : futureList) {
- // 任务完成后获取结果
- try {
- Map<String, List<?>> map = future.get(10L, TimeUnit.SECONDS);
- List<TwinCalcHour> calcHours = (List<TwinCalcHour>) map.get("calc");
- hours.addAll(calcHours);
- } catch (TimeoutException e) {
- e.printStackTrace();
- }
- }
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- if (hours.size() > 0) {
- calcDay.calcHours(hours);
- int num = 0;
- for (TwinCalcHour hour : hours) {
- BigDecimal v = BigDecimal.ZERO;
- if (resultMap.get(hour.getDeviceId()) != null) {
- v = resultMap.get(hour.getDeviceId());
- }
- v.add(hour.getLength());
- if (v.doubleValue() > 0d) {
- num++;
- }
- }
- int deviceNum = list.size();
- BigDecimal ratio = BigDecimal.valueOf(num).divide(BigDecimal.valueOf(deviceNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
- calcDay.setRunningRatio(ratio.doubleValue());
- }
- BigDecimal totalTimeA = calcDay.getOpenTimeA().add(calcDay.getCloseTimeA());
- BigDecimal totalTimeB = calcDay.getOpenTimeB().add(calcDay.getCloseTimeB());
- if (!totalTimeA.equals(BigDecimal.ZERO)) {
- BigDecimal eff = calcDay.getOpenTimeA().divide(totalTimeA, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
- calcDay.setEfficiencyA(eff);
- }
- if (!totalTimeB.equals(BigDecimal.ZERO)) {
- BigDecimal eff = calcDay.getOpenTimeB().divide(totalTimeB, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
- calcDay.setEfficiencyB(eff);
- }
- return calcDay;
- }
- /**
- * 按月度查询
- *
- * @param month 月份
- * @return 结果
- */
- @Override
- public List<TwinCalcDay> selectTwinCalcDayListByMonth(String month) {
- return twinCalcDayMapper.selectTwinCalcDayListByMonth(month);
- }
- /**
- * 查询指定日期及之后的数据
- *
- * @param sd 开始日期
- * @return 列表
- */
- @Override
- public List<TwinCalcDay> selectTwinCalcDayListByTime(Date sd) {
- return twinCalcDayMapper.selectTwinCalcDayListByTime(sd, null);
- }
- /**
- * 查询指定日期的数据
- *
- * @param sd 开始日期
- * @param ed 结束日期
- * @return 列表
- */
- @Override
- public List<TwinCalcDay> selectTwinCalcDayListByTime(Date sd, Date ed) {
- return twinCalcDayMapper.selectTwinCalcDayListByTime(sd, ed);
- }
- }
|