package com.moral.service.impl; import static com.moral.common.bean.Constants.NULL_VALUE; import static org.springframework.util.ObjectUtils.isEmpty; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.temporal.TemporalAdjusters; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; import javax.annotation.Resource; import com.moral.common.util.ReportTimeFormat; import com.moral.entity.charts.DataCondition; import com.moral.entity.charts.LineChartCriteria; import com.moral.entity.charts.PairData; import com.moral.entity.charts.TimePeriod; import org.apache.commons.lang3.time.DateUtils; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.moral.common.util.CalculateUtils; import com.moral.common.util.ResourceUtil; import com.moral.common.util.ValidateUtil; import com.moral.entity.Device; import com.moral.entity.Sensor; import com.moral.mapper.DeviceMapper; import com.moral.mapper.HistoryMinutelyMapper; import com.moral.mapper.SensorMapper; import com.moral.service.HistoryMinutelyService; @Service @SuppressWarnings({ "unchecked", "rawtypes", "unused" }) public class HistoryMinutelyServiceImpl implements HistoryMinutelyService { @Resource private HistoryMinutelyMapper historyMinutelyMapper; @Resource private DeviceMapper deviceMapper; @Resource private SensorMapper sensorMapper; // volatile @Override public Map getDayAQIByDevice(Map parameters) { ValidateUtil.notNull(parameters.get("mac"), "param.is.null"); LocalDate localDate = LocalDate.now(); // 昨日00:00:00 parameters.put("start", localDate.minusDays(1)); // 今日00:00:00 parameters.put("end", localDate); String[] macKeys = { "e1", "e2", "e10", "e11", "e15", "e16" }; parameters.put("sensorKeys", Arrays.asList(macKeys)); Map average = historyMinutelyMapper.getSersionAvgByDevice(parameters); return getAQIByDataMap(average); } private Map getAQIByDataMap(Map average) { Map resultMap = new HashMap(); if (isEmpty(average)) { resultMap.put("AQI", "N/V"); } else { String[] IAQIValues = ResourceUtil.getArrValue("IAQI"); Set IAQIs = new HashSet(); for (Map.Entry entry : average.entrySet()) { double minMacKey = 0, maxMacKey = 0, minIAQI = 0, maxIAQI = 0; String[] macKeyValues = ResourceUtil.getArrValue(entry.getKey()); Double avg = entry.getValue(); if (isEmpty(avg)) { IAQIs.add(null); } else { int index = -1; for (int i = 0; i < macKeyValues.length; i++) { if (avg <= Double.valueOf(macKeyValues[i])) { if (i == 0) { index = i; } else { index = i - 1; } break; } } if (index == -1) { IAQIs.add(Double.MAX_VALUE); } else { minMacKey = Double.valueOf(macKeyValues[index]); maxMacKey = Double.valueOf(macKeyValues[index + 1]); minIAQI = Double.valueOf(IAQIValues[index]); maxIAQI = Double.valueOf(IAQIValues[index + 1]); Double result = CalculateUtils.calculateIAQI(maxIAQI, minIAQI, maxMacKey, minMacKey, avg); IAQIs.add(result); } } } IAQIs.remove(null); if (isEmpty(IAQIs)) { resultMap.put("AQI", "N/V"); } else { Double AQI = Collections.max(IAQIs); if (AQI == Double.MAX_VALUE) { resultMap.put("AQI", IAQIValues[IAQIValues.length - 1]); } else { resultMap.put("AQI", String.format("%.0f", AQI)); } } } return resultMap; } @Override public Map> getCompareReport(Map parameters) throws Exception { Map> resultMap = new HashMap>(); List> list = JSON.parseObject((String)parameters.remove("items"), new TypeReference>>() {}); String type = (String) parameters.get("type"); parameters.putAll(getElementByType(type)); Integer timeLength = Integer.valueOf(parameters.remove("timeLength").toString()); if ("month".equals(type)) { for (Map map : list) { String[] formatTime = map.get("formatTime").toString().split("-"); LocalDate localDate = LocalDate.of(Integer.valueOf(formatTime[0]), Integer.valueOf(formatTime[1]), 1); int lengthOfMonth = localDate.lengthOfMonth(); if (lengthOfMonth > timeLength) { timeLength = lengthOfMonth; } } } List timeList = new ArrayList(); for (int i = 0; i < timeLength; i++) { timeList.add(i, String.format("%02d", "day".equals(type) || "hour".equals(type) ? i : i + 1)); } parameters.put("timeList", timeList); ExecutorService threadPool = Executors.newCachedThreadPool(); CompletionService>> cs = new ExecutorCompletionService>>(threadPool); for (int i = 0; i < list.size(); i++) { Map map = list.get(i); map.put("part", i); if (ObjectUtils.isEmpty(map.get("mac"))) { map.remove("mac"); } map.put("time", map.remove("formatTime")); map.putAll(parameters); cs.submit(new Callable>>() { @Override public Map> call() throws Exception { return getMonitorPointOrDeviceAvgData4Compare(map); } }); } List dataList = new ArrayList(); for (Map map : list) { dataList.add(cs.take().get()); } Map[] maps = new HashMap[list.size()]; Set sensors = new TreeSet(new Comparator() { @Override public int compare(String o1, String o2) { return Integer.compare(Integer.valueOf(o1.split("-")[0].replace("e", "")), Integer.valueOf(o2.split("-")[0].replace("e", ""))); } }); for (Object object : dataList) { Map map = (Map)object; for (String key : map.keySet()) { if (key.startsWith("data")) { int index = Integer.valueOf(key.replace("data", "")); maps[index] = map; } if (key.startsWith("sensors")) { sensors.addAll((List) map.get(key)); } } } resultMap.put("times", timeList); resultMap.put("datas", Arrays.asList(maps)); resultMap.put("sensors", new ArrayList(sensors)); return resultMap; } public Map> getMonitorPointOrDeviceAvgData4Compare(Map parameters) throws Exception { Map> resultMap = new HashMap>(); List> resultList = getMonitorPointOrDeviceAvgData(parameters); List timeList = (List) parameters.get("timeList"); List dataList = new ArrayList(); Set sensors = new TreeSet(new Comparator() { @Override public int compare(String o1, String o2) { return Integer.compare(Integer.valueOf(o1.split("-")[0].replace("e", "")), Integer.valueOf(o2.split("-")[0].replace("e", ""))); } }); sensors.addAll((Set)parameters.get("sensors")); Map doubleMap = new LinkedHashMap(); for (Map map : resultList) { String time = map.get("time").toString(); time = time.substring(time.length() - 2); int index = timeList.indexOf(time); for (String sensor : sensors) { String[] split = sensor.split("-"); String sensorKey = split[0]; if (map.containsKey(sensorKey)) { Double[] doubles; if (doubleMap.containsKey(sensor)) { doubles = doubleMap.get(sensor); } else { doubles = new Double[timeList.size()]; } doubles[index] = (Double) map.get(sensorKey); doubleMap.put(sensor, doubles); } } } dataList.add(doubleMap); String part = parameters.get("part").toString(); resultMap.put("data" + part, dataList); resultMap.put("sensors" + part, new ArrayList(sensors)); return resultMap; } @Override public List> getMonitorPointOrDeviceAvgData(Map parameters) throws Exception { String type = (String) parameters.get("type"); if (!parameters.containsKey("field")) { parameters.putAll(getElementByType(type)); } String time = (String) parameters.get("time"); String format = (String) parameters.get("format"); Integer field = Integer.valueOf(parameters.get("field").toString()); Date start = DateUtils.parseDate(time, format), end = null ; if (parameters.containsKey("timeb")) { end = DateUtils.parseDate((String)parameters.get("timeb"), format); } else { Calendar instance = Calendar.getInstance(); instance.setTime(start); instance.add(field, 1); end = instance.getTime(); } parameters.put("start", start); parameters.put("end", end); List sensorKeys = new ArrayList(); Set sensorsSet = new HashSet(); if (parameters.containsKey("sensors")) { List sensors; try { sensors = JSON.parseObject((String)parameters.remove("sensors"), new TypeReference>() {}); for (String sensor : sensors) { sensorKeys.add(sensor.split("-")[0]); } } catch (Exception e) { sensors = (List)parameters.remove("sensors"); sensorKeys.addAll(sensors); } sensorsSet.addAll(sensors); } else { List sensors = sensorMapper.getSensorsByCriteria(parameters); for (Sensor sensor : sensors) { sensorKeys.add(sensor.getSensorKey()); sensorsSet.add(sensor.getSensorKey() + "-" + sensor.getName() + "-" + sensor.getUnit()); } } parameters.put("sensorKeys", sensorKeys); parameters.put("sensors", sensorsSet); return historyMinutelyMapper.getMonitorPointOrDeviceAvgData(parameters); } @Override public Map getMonthAverageBySensor(Map parameters) { ValidateUtil.notNull(parameters.get("mac"), "param.is.null"); ValidateUtil.notNull(parameters.get("macKey"), "param.is.null"); Map result = new HashMap(); LocalDate end = LocalDate.now(),start; // 每月一日的数据取上月的数据 if (1 == end.getDayOfMonth()) { // 上个月1日00:00:00 start = end.plusDays(-1).with(TemporalAdjusters.firstDayOfMonth()); } else { // 这个月1日00:00:00 start = end.with(TemporalAdjusters.firstDayOfMonth()); } parameters.put("start", start); parameters.put("end", end); String sensorKey = (String) parameters.remove("macKey"); List sensorKeys = new ArrayList(); sensorKeys.add(sensorKey); parameters.put("sensorKeys", sensorKeys); Map average = historyMinutelyMapper.getSersionAvgByDevice(parameters); if (isEmpty(average)) { result.put("average", NULL_VALUE); } else { result.put("average", String.format("%.2f", average.get(sensorKey))); } return result; } /** * 根据线性表单的条件规则,获取多条线性表单数据 * @param lineChartCriteria * @return */ @Override public Map>> queryLineChartDateByCrieria(LineChartCriteria lineChartCriteria){ Map>> listMap = new HashMap<>(); List sensorKeys = lineChartCriteria.getSensorKeys(); List dataConditionList = lineChartCriteria.getDataConditions(); TimePeriod timePeriod = lineChartCriteria.getTimePeriod(); sensorKeys.forEach(sensorKey -> { listMap.put(sensorKey,new ArrayList>(dataConditionList.size())); }); dataConditionList.forEach(dataCondition -> { Map> dataMap = queryOneLineChartDateByCrieria(sensorKeys,timePeriod,dataCondition); // 数据装载 listMap.forEach( (sensorKey,list) -> { List rowData = dataMap.get(sensorKey); list.add(rowData); }); }); return listMap; } /** * 根据线性表单的条件规则,获取一条线性表单数据,包含 所有检测项目 * @param sensorKeys * @param timePeriod * @param dataCondition * @return */ public Map> queryOneLineChartDateByCrieria(List sensorKeys, TimePeriod timePeriod, DataCondition dataCondition){ List timeList = ReportTimeFormat.makeTimeList(timePeriod); List> lineChartDatas = historyMinutelyMapper.selectLineChartDateByCrieria(sensorKeys,timePeriod,dataCondition); Map> lineChartDatasWithEmpty = new HashMap<>(); // lineChartDatasWithEmpty 初始化 sensorKeys.forEach(sensorKey -> { lineChartDatasWithEmpty.put(sensorKey,timeList.stream().map(time -> { Double data = null; return data; }).collect(Collectors.toList())); }); // m 为查询data的index,此处要防止m越界 int m = 0; int dataLength = lineChartDatas.size()-1; m = dataLength>-1?0:-1; if(m >-1){ for(int n =0;n-1) { String time = timeList.get(n); Map rowData = lineChartDatas.get(m); String keyTime = rowData.get("format_time").toString(); if(time.equals(keyTime)){ // list to map int finalN = n; sensorKeys.forEach(sensorKey -> { Object value = rowData.get(sensorKey); List lineChartDatasWithEmptyTemp = lineChartDatasWithEmpty.get(sensorKey); if(finalN < lineChartDatasWithEmptyTemp.size()){ Double sensorValue = value!= null?new Double(value.toString()):null; lineChartDatasWithEmptyTemp.set(finalN,sensorValue); } }); // 置为 -1,防止越界 m = m getElementByType(Object type){ Map resultMap = new HashMap(); switch (type.toString()) { case "year": resultMap.put("format", "yyyy"); resultMap.put("typeFormat", "%Y-%m"); resultMap.put("timeLength", 12); resultMap.put("field", Calendar.YEAR); break; case "month": resultMap.put("format", "yyyy-MM"); resultMap.put("typeFormat", "%Y-%m-%d"); resultMap.put("timeLength", 28); resultMap.put("field", Calendar.MONTH); break; case "day": resultMap.put("format", "yyyy-MM-dd"); resultMap.put("typeFormat", "%Y-%m-%d %H"); resultMap.put("timeLength", 24); resultMap.put("field", Calendar.DATE); break; case "hour": resultMap.put("format", "yyyy-MM-dd HH"); resultMap.put("typeFormat", "%Y-%m-%d %H:%i"); resultMap.put("timeLength", 60); resultMap.put("field", Calendar.HOUR); break; } return resultMap; } }