|
|
|
|
@ -0,0 +1,365 @@
|
|
|
|
|
package cn.iocoder.yudao.module.iot.service.device;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
|
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
|
|
|
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
|
|
|
|
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.infra.service.file.FileService;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.DeviceProductionDailyReportGenerateReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.DeviceProductionDailyReportPageReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.DeviceProductionDailyReportRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.api.workteam.WorkTeamApi;
|
|
|
|
|
import cn.iocoder.yudao.module.mes.api.workteam.dto.WorkTeamRespDTO;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
|
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
|
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
|
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
|
|
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
|
|
|
|
import org.springframework.core.io.ClassPathResource;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.math.RoundingMode;
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.time.LocalTime;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
|
|
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_NOT_EXISTS;
|
|
|
|
|
|
|
|
|
|
@Service
|
|
|
|
|
@Validated
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class DeviceProductionDailyReportServiceImpl implements DeviceProductionDailyReportService {
|
|
|
|
|
|
|
|
|
|
private static final String TEMPLATE_PATH = "excel/templates/fully-automatic-molding-production-daily-report-template.xlsx";
|
|
|
|
|
private static final String REPORT_PATH_PREFIX = "iot/device/production-daily-report";
|
|
|
|
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private DeviceMapper deviceMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private DeviceContactModelMapper deviceContactModelMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private TDengineService tDengineService;
|
|
|
|
|
@Resource
|
|
|
|
|
private WorkTeamApi workTeamApi;
|
|
|
|
|
@Resource
|
|
|
|
|
private FileService fileService;
|
|
|
|
|
@Resource
|
|
|
|
|
private FileMapper fileMapper;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public DeviceProductionDailyReportRespVO generateReport(DeviceProductionDailyReportGenerateReqVO reqVO) {
|
|
|
|
|
List<Long> deviceIds = reqVO.getDeviceIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
|
|
|
|
if (CollUtil.isEmpty(deviceIds)) {
|
|
|
|
|
throw exception(DEVICE_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<Long, DeviceDO> deviceMap = deviceMapper.selectBatchIds(deviceIds).stream()
|
|
|
|
|
.collect(Collectors.toMap(DeviceDO::getId, item -> item));
|
|
|
|
|
if (deviceMap.size() != deviceIds.size()) {
|
|
|
|
|
throw exception(DEVICE_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WorkTeamRespDTO workTeam = workTeamApi.getWorkTeam(reqVO.getWorkTeamId());
|
|
|
|
|
if (workTeam == null || workTeam.getStartTime() == null || workTeam.getEndTime() == null) {
|
|
|
|
|
throw new IllegalArgumentException("Work team does not exist or start/end time is not configured");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LocalDateTime startTime = combineShiftTime(reqVO.getReportDate(), workTeam.getStartTime());
|
|
|
|
|
LocalDateTime endTime = combineShiftTime(reqVO.getReportDate(), workTeam.getEndTime());
|
|
|
|
|
if (!endTime.isAfter(startTime)) {
|
|
|
|
|
endTime = endTime.plusDays(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<DeviceProductionDailyReportRespVO.DeviceCapacityItem> items = buildCapacityItems(deviceIds, deviceMap, startTime, endTime);
|
|
|
|
|
byte[] excelContent = buildExcel(reqVO, workTeam, startTime, endTime, items);
|
|
|
|
|
|
|
|
|
|
String fileName = String.format("全自动成型机生产日报表_%s_%s_%s.xlsx",
|
|
|
|
|
reqVO.getReportDate().format(DateTimeFormatter.BASIC_ISO_DATE), reqVO.getWorkTeamId(), System.currentTimeMillis());
|
|
|
|
|
String filePath = String.format("%s/date=%s/workTeamId=%s/deviceIds=%s/deviceTags=%s/%s",
|
|
|
|
|
REPORT_PATH_PREFIX, reqVO.getReportDate(), reqVO.getWorkTeamId(), joinDeviceIds(deviceIds), buildDeviceTags(deviceIds), fileName);
|
|
|
|
|
Map<String, String> file = fileService.createFile(fileName, filePath, excelContent);
|
|
|
|
|
|
|
|
|
|
DeviceProductionDailyReportRespVO respVO = buildBaseResp(reqVO.getReportDate(), workTeam, startTime, endTime, deviceIds);
|
|
|
|
|
respVO.setFileName(file.get("fileName"));
|
|
|
|
|
respVO.setFileUrl(file.get("fileUrl"));
|
|
|
|
|
respVO.setFilePath(filePath);
|
|
|
|
|
respVO.setDevices(items);
|
|
|
|
|
respVO.setCreateTime(LocalDateTime.now());
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public PageResult<DeviceProductionDailyReportRespVO> getReportPage(DeviceProductionDailyReportPageReqVO reqVO) {
|
|
|
|
|
LambdaQueryWrapperX<FileDO> queryWrapper = new LambdaQueryWrapperX<>();
|
|
|
|
|
queryWrapper.like(FileDO::getPath, REPORT_PATH_PREFIX);
|
|
|
|
|
queryWrapper.orderByDesc(FileDO::getId);
|
|
|
|
|
if (reqVO.getReportDate() != null) {
|
|
|
|
|
queryWrapper.like(FileDO::getPath, "/date=" + reqVO.getReportDate() + "/");
|
|
|
|
|
}
|
|
|
|
|
if (reqVO.getWorkTeamId() != null) {
|
|
|
|
|
queryWrapper.like(FileDO::getPath, "/workTeamId=" + reqVO.getWorkTeamId() + "/");
|
|
|
|
|
}
|
|
|
|
|
if (reqVO.getDeviceId() != null) {
|
|
|
|
|
queryWrapper.like(FileDO::getPath, buildDeviceTag(reqVO.getDeviceId()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PageResult<FileDO> pageResult = fileMapper.selectPage(reqVO, queryWrapper);
|
|
|
|
|
List<DeviceProductionDailyReportRespVO> list = pageResult.getList().stream()
|
|
|
|
|
.map(this::convertFileToReport)
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
return new PageResult<>(list, pageResult.getTotal());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<DeviceProductionDailyReportRespVO.DeviceCapacityItem> buildCapacityItems(List<Long> deviceIds,
|
|
|
|
|
Map<Long, DeviceDO> deviceMap,
|
|
|
|
|
LocalDateTime startTime,
|
|
|
|
|
LocalDateTime endTime) {
|
|
|
|
|
Map<Long, List<DeviceContactModelDO>> capacityPointMap = queryCapacityPoints(deviceIds);
|
|
|
|
|
Map<Long, Map<String, Object>> firstRows = tDengineService.queryDevicesEarliestRow(deviceIds,
|
|
|
|
|
startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER));
|
|
|
|
|
Map<Long, Map<String, Object>> lastRows = tDengineService.queryDevicesLatestRow(deviceIds,
|
|
|
|
|
startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER));
|
|
|
|
|
|
|
|
|
|
List<DeviceProductionDailyReportRespVO.DeviceCapacityItem> items = new ArrayList<>();
|
|
|
|
|
for (Long deviceId : deviceIds) {
|
|
|
|
|
DeviceDO device = deviceMap.get(deviceId);
|
|
|
|
|
List<DeviceContactModelDO> points = capacityPointMap.getOrDefault(deviceId, Collections.emptyList());
|
|
|
|
|
if (CollUtil.isEmpty(points)) {
|
|
|
|
|
items.add(buildEmptyCapacityItem(device));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Map<String, Object> firstRow = firstRows.get(deviceId);
|
|
|
|
|
Map<String, Object> lastRow = lastRows.get(deviceId);
|
|
|
|
|
for (DeviceContactModelDO point : points) {
|
|
|
|
|
items.add(buildCapacityItem(device, point, firstRow, lastRow));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<Long, List<DeviceContactModelDO>> queryCapacityPoints(List<Long> deviceIds) {
|
|
|
|
|
List<DeviceContactModelDO> points = deviceContactModelMapper.selectList(
|
|
|
|
|
Wrappers.<DeviceContactModelDO>lambdaQuery()
|
|
|
|
|
.in(DeviceContactModelDO::getDeviceId, deviceIds)
|
|
|
|
|
.and(wrapper -> wrapper.like(DeviceContactModelDO::getTypeName, "产能")
|
|
|
|
|
.or().like(DeviceContactModelDO::getAttributeType, "产能")
|
|
|
|
|
.or().like(DeviceContactModelDO::getAttributeName, "产能"))
|
|
|
|
|
.orderByAsc(DeviceContactModelDO::getDeviceId)
|
|
|
|
|
.orderByAsc(DeviceContactModelDO::getSort)
|
|
|
|
|
.orderByAsc(DeviceContactModelDO::getId));
|
|
|
|
|
return points.stream().collect(Collectors.groupingBy(DeviceContactModelDO::getDeviceId, LinkedHashMap::new, Collectors.toList()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DeviceProductionDailyReportRespVO.DeviceCapacityItem buildEmptyCapacityItem(DeviceDO device) {
|
|
|
|
|
DeviceProductionDailyReportRespVO.DeviceCapacityItem item = new DeviceProductionDailyReportRespVO.DeviceCapacityItem();
|
|
|
|
|
item.setDeviceId(device.getId());
|
|
|
|
|
item.setDeviceCode(device.getDeviceCode());
|
|
|
|
|
item.setDeviceName(device.getDeviceName());
|
|
|
|
|
item.setCapacityDiff(0D);
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DeviceProductionDailyReportRespVO.DeviceCapacityItem buildCapacityItem(DeviceDO device, DeviceContactModelDO point,
|
|
|
|
|
Map<String, Object> firstRow, Map<String, Object> lastRow) {
|
|
|
|
|
DeviceProductionDailyReportRespVO.DeviceCapacityItem item = new DeviceProductionDailyReportRespVO.DeviceCapacityItem();
|
|
|
|
|
item.setDeviceId(device.getId());
|
|
|
|
|
item.setDeviceCode(device.getDeviceCode());
|
|
|
|
|
item.setDeviceName(device.getDeviceName());
|
|
|
|
|
item.setCapacityCode(point.getAttributeCode());
|
|
|
|
|
item.setCapacityName(point.getAttributeName());
|
|
|
|
|
item.setUnit(point.getDataUnit());
|
|
|
|
|
|
|
|
|
|
Double firstValue = getNumberValue(firstRow, point.getAttributeCode());
|
|
|
|
|
Double lastValue = getNumberValue(lastRow, point.getAttributeCode());
|
|
|
|
|
item.setStartValue(firstValue);
|
|
|
|
|
item.setEndValue(lastValue);
|
|
|
|
|
if (firstValue != null && lastValue != null) {
|
|
|
|
|
item.setCapacityDiff(BigDecimal.valueOf(lastValue).subtract(BigDecimal.valueOf(firstValue))
|
|
|
|
|
.setScale(3, RoundingMode.HALF_UP).doubleValue());
|
|
|
|
|
} else {
|
|
|
|
|
item.setCapacityDiff(0D);
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
private byte[] buildExcel(DeviceProductionDailyReportGenerateReqVO reqVO, WorkTeamRespDTO workTeam,
|
|
|
|
|
LocalDateTime startTime, LocalDateTime endTime,
|
|
|
|
|
List<DeviceProductionDailyReportRespVO.DeviceCapacityItem> items) {
|
|
|
|
|
try (InputStream inputStream = new ClassPathResource(TEMPLATE_PATH).getInputStream();
|
|
|
|
|
Workbook workbook = WorkbookFactory.create(inputStream);
|
|
|
|
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
|
|
|
Sheet sheet = workbook.getSheetAt(0);
|
|
|
|
|
setCellValue(sheet, 2, 0, "日期:" + LocalDate.now().format(DATE_FORMATTER));
|
|
|
|
|
setCellValue(sheet, 2, 4, "班次:" + StrUtil.blankToDefault(workTeam.getTeamName(), ""));
|
|
|
|
|
setCellValue(sheet, 19, 9, "审核:");
|
|
|
|
|
|
|
|
|
|
int rowIndex = 5;
|
|
|
|
|
for (int index = 0; index < items.size(); index++) {
|
|
|
|
|
if (rowIndex + index > 9) {
|
|
|
|
|
sheet.shiftRows(10, sheet.getLastRowNum(), 1, true, false);
|
|
|
|
|
}
|
|
|
|
|
Row row = sheet.getRow(rowIndex + index);
|
|
|
|
|
if (row == null) {
|
|
|
|
|
row = sheet.createRow(rowIndex + index);
|
|
|
|
|
}
|
|
|
|
|
DeviceProductionDailyReportRespVO.DeviceCapacityItem item = items.get(index);
|
|
|
|
|
setCellValue(row, 0, index + 1);
|
|
|
|
|
setCellValue(row, 1, StrUtil.blankToDefault(item.getDeviceCode(), item.getDeviceName()));
|
|
|
|
|
setCellValue(row, 4, item.getCapacityName());
|
|
|
|
|
setCellValue(row, 20, item.getCapacityDiff());
|
|
|
|
|
setCellValue(row, 21, toHour(startTime, endTime));
|
|
|
|
|
setCellValue(row, 22, startTime.toLocalTime() + "-" + endTime.toLocalTime());
|
|
|
|
|
setCellValue(row, 24, workTeam.getTeamName());
|
|
|
|
|
}
|
|
|
|
|
workbook.write(outputStream);
|
|
|
|
|
return outputStream.toByteArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DeviceProductionDailyReportRespVO convertFileToReport(FileDO file) {
|
|
|
|
|
DeviceProductionDailyReportRespVO respVO = new DeviceProductionDailyReportRespVO();
|
|
|
|
|
respVO.setFileName(file.getName());
|
|
|
|
|
respVO.setFileUrl(file.getUrl());
|
|
|
|
|
respVO.setFilePath(file.getPath());
|
|
|
|
|
respVO.setCreateTime(file.getCreateTime());
|
|
|
|
|
parsePathMetadata(file.getPath(), respVO);
|
|
|
|
|
if (respVO.getWorkTeamId() != null) {
|
|
|
|
|
WorkTeamRespDTO workTeam = workTeamApi.getWorkTeam(respVO.getWorkTeamId());
|
|
|
|
|
if (workTeam != null) {
|
|
|
|
|
respVO.setWorkTeamName(workTeam.getTeamName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void parsePathMetadata(String path, DeviceProductionDailyReportRespVO respVO) {
|
|
|
|
|
if (StringUtils.isBlank(path)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (String segment : path.split("/")) {
|
|
|
|
|
if (segment.startsWith("date=")) {
|
|
|
|
|
respVO.setReportDate(LocalDate.parse(segment.substring("date=".length())));
|
|
|
|
|
} else if (segment.startsWith("workTeamId=")) {
|
|
|
|
|
respVO.setWorkTeamId(Long.valueOf(segment.substring("workTeamId=".length())));
|
|
|
|
|
} else if (segment.startsWith("deviceIds=")) {
|
|
|
|
|
List<Long> deviceIds = new ArrayList<>();
|
|
|
|
|
for (String id : segment.substring("deviceIds=".length()).split("_")) {
|
|
|
|
|
if (StringUtils.isNumeric(id)) {
|
|
|
|
|
deviceIds.add(Long.valueOf(id));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
respVO.setDeviceIds(deviceIds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DeviceProductionDailyReportRespVO buildBaseResp(LocalDate reportDate, WorkTeamRespDTO workTeam,
|
|
|
|
|
LocalDateTime startTime, LocalDateTime endTime, List<Long> deviceIds) {
|
|
|
|
|
DeviceProductionDailyReportRespVO respVO = new DeviceProductionDailyReportRespVO();
|
|
|
|
|
respVO.setReportDate(reportDate);
|
|
|
|
|
respVO.setWorkTeamId(workTeam.getId());
|
|
|
|
|
respVO.setWorkTeamName(workTeam.getTeamName());
|
|
|
|
|
respVO.setStartTime(startTime);
|
|
|
|
|
respVO.setEndTime(endTime);
|
|
|
|
|
respVO.setDeviceIds(deviceIds);
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LocalDateTime combineShiftTime(LocalDate date, LocalDateTime workTeamTime) {
|
|
|
|
|
return LocalDateTime.of(date, LocalTime.from(workTeamTime));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Double getNumberValue(Map<String, Object> row, String code) {
|
|
|
|
|
if (row == null || StringUtils.isBlank(code)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
Object value = row.get(code);
|
|
|
|
|
if (value == null) {
|
|
|
|
|
value = row.get(code.toLowerCase());
|
|
|
|
|
}
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
return ((Number) value).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
if (value != null && StringUtils.isNotBlank(value.toString())) {
|
|
|
|
|
try {
|
|
|
|
|
return Double.valueOf(value.toString());
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
log.warn("capacity point value is not numeric: code={}, value={}", code, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildShiftText(WorkTeamRespDTO workTeam) {
|
|
|
|
|
if (StringUtils.isNotBlank(workTeam.getGroupType())) {
|
|
|
|
|
return workTeam.getGroupType();
|
|
|
|
|
}
|
|
|
|
|
return StrUtil.blankToDefault(workTeam.getTeamName(), "Shift:");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Double toHour(LocalDateTime startTime, LocalDateTime endTime) {
|
|
|
|
|
return BigDecimal.valueOf(java.time.Duration.between(startTime, endTime).toMinutes())
|
|
|
|
|
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String joinDeviceIds(List<Long> deviceIds) {
|
|
|
|
|
return deviceIds.stream().sorted(Comparator.naturalOrder()).map(String::valueOf).collect(Collectors.joining("_"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildDeviceTags(List<Long> deviceIds) {
|
|
|
|
|
return deviceIds.stream().sorted(Comparator.naturalOrder()).map(this::buildDeviceTag).collect(Collectors.joining(""));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildDeviceTag(Long deviceId) {
|
|
|
|
|
return "_" + deviceId + "_";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setCellValue(Sheet sheet, int rowIndex, int columnIndex, Object value) {
|
|
|
|
|
Row row = sheet.getRow(rowIndex);
|
|
|
|
|
if (row == null) {
|
|
|
|
|
row = sheet.createRow(rowIndex);
|
|
|
|
|
}
|
|
|
|
|
setCellValue(row, columnIndex, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setCellValue(Row row, int columnIndex, Object value) {
|
|
|
|
|
Cell cell = row.getCell(columnIndex);
|
|
|
|
|
if (cell == null) {
|
|
|
|
|
cell = row.createCell(columnIndex);
|
|
|
|
|
}
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
} else {
|
|
|
|
|
cell.setCellValue(value == null ? "" : value.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|