diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 3284ebf3e..b9cad06f0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -29,6 +29,12 @@ ${revision} + + cn.iocoder.boot + yudao-module-mes-api + ${revision} + + cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java index e8da0afd6..d02bc0e3d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java @@ -16,6 +16,7 @@ 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.framework.mqtt.consumer.IMqttservice; import cn.iocoder.yudao.module.iot.service.device.DeviceService; +import cn.iocoder.yudao.module.iot.service.device.DeviceProductionDailyReportService; import cn.iocoder.yudao.module.iot.service.device.TDengineService; import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.v3.oas.annotations.Operation; @@ -55,6 +56,8 @@ public class DeviceController { @Resource private TDengineService tDengineService; @Resource + private DeviceProductionDailyReportService deviceProductionDailyReportService; + @Resource private JobService jobService; // @Resource @@ -140,6 +143,24 @@ public class DeviceController { // 导出 Excel ExcelUtils.write(response, "物联设备.xls", "数据", DeviceRespVO.class,list); } + + @PostMapping("/production-daily-report/generate") + @Operation(summary = "生成设备生产日报 Excel") + @PreAuthorize("@ss.hasPermission('iot:device:export')") + @ApiAccessLog(operateType = EXPORT) + public CommonResult generateProductionDailyReport( + @Valid @RequestBody DeviceProductionDailyReportGenerateReqVO reqVO) { + return success(deviceProductionDailyReportService.generateReport(reqVO)); + } + + @GetMapping("/production-daily-report/page") + @Operation(summary = "获得设备生产日报 Excel 分页") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult> getProductionDailyReportPage( + @Valid DeviceProductionDailyReportPageReqVO reqVO) { + return success(deviceProductionDailyReportService.getReportPage(reqVO)); + } + @GetMapping("/deviceList") // @PreAuthorize("@ss.hasPermission('iot:device:query')") public CommonResult> deviceList(@Valid DevicePageReqVO pageReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportGenerateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportGenerateReqVO.java new file mode 100644 index 000000000..ed84e3194 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportGenerateReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - 设备生产日报生成 Request VO") +@Data +public class DeviceProductionDailyReportGenerateReqVO { + + @Schema(description = "设备 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2]") + @NotEmpty(message = "设备 ID 不能为空") + private List deviceIds; + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-07-23") + @NotNull(message = "日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate reportDate; + + @Schema(description = "班次 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "班次 ID 不能为空") + private Long workTeamId; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportPageReqVO.java new file mode 100644 index 000000000..8cc315517 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportPageReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - 设备生产日报分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeviceProductionDailyReportPageReqVO extends PageParam { + + @Schema(description = "日期", example = "2026-07-23") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate reportDate; + + @Schema(description = "班次 ID", example = "1") + private Long workTeamId; + + @Schema(description = "设备 ID,按生成时的设备集合筛选", example = "1") + private Long deviceId; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportRespVO.java new file mode 100644 index 000000000..aec4e084e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceProductionDailyReportRespVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 设备生产日报 Response VO") +@Data +public class DeviceProductionDailyReportRespVO { + + @Schema(description = "文件名") + private String fileName; + + @Schema(description = "文件访问地址") + private String fileUrl; + + @Schema(description = "文件路径") + private String filePath; + + @Schema(description = "日期") + private LocalDate reportDate; + + @Schema(description = "班次 ID") + private Long workTeamId; + + @Schema(description = "班次名称") + private String workTeamName; + + @Schema(description = "查询开始时间") + private LocalDateTime startTime; + + @Schema(description = "查询结束时间") + private LocalDateTime endTime; + + @Schema(description = "设备 ID 列表") + private List deviceIds; + + @Schema(description = "设备产能明细") + private List devices; + + @Schema(description = "生成时间") + private LocalDateTime createTime; + + @Data + public static class DeviceCapacityItem { + + @Schema(description = "设备 ID") + private Long deviceId; + @Schema(description = "设备编码") + private String deviceCode; + @Schema(description = "设备名称") + private String deviceName; + @Schema(description = "产能点位编码") + private String capacityCode; + @Schema(description = "产能点位名称") + private String capacityName; + @Schema(description = "开始值") + private Double startValue; + @Schema(description = "结束值") + private Double endValue; + @Schema(description = "差值") + private Double capacityDiff; + @Schema(description = "单位") + private String unit; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportService.java new file mode 100644 index 000000000..3ad8f2cb2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportService.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +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; + +public interface DeviceProductionDailyReportService { + + DeviceProductionDailyReportRespVO generateReport(DeviceProductionDailyReportGenerateReqVO reqVO); + + PageResult getReportPage(DeviceProductionDailyReportPageReqVO reqVO); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportServiceImpl.java new file mode 100644 index 000000000..6d82107bd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceProductionDailyReportServiceImpl.java @@ -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 deviceIds = reqVO.getDeviceIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); + if (CollUtil.isEmpty(deviceIds)) { + throw exception(DEVICE_NOT_EXISTS); + } + + Map 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 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 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 getReportPage(DeviceProductionDailyReportPageReqVO reqVO) { + LambdaQueryWrapperX 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 pageResult = fileMapper.selectPage(reqVO, queryWrapper); + List list = pageResult.getList().stream() + .map(this::convertFileToReport) + .collect(Collectors.toList()); + return new PageResult<>(list, pageResult.getTotal()); + } + + private List buildCapacityItems(List deviceIds, + Map deviceMap, + LocalDateTime startTime, + LocalDateTime endTime) { + Map> capacityPointMap = queryCapacityPoints(deviceIds); + Map> firstRows = tDengineService.queryDevicesEarliestRow(deviceIds, + startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER)); + Map> lastRows = tDengineService.queryDevicesLatestRow(deviceIds, + startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER)); + + List items = new ArrayList<>(); + for (Long deviceId : deviceIds) { + DeviceDO device = deviceMap.get(deviceId); + List points = capacityPointMap.getOrDefault(deviceId, Collections.emptyList()); + if (CollUtil.isEmpty(points)) { + items.add(buildEmptyCapacityItem(device)); + continue; + } + Map firstRow = firstRows.get(deviceId); + Map lastRow = lastRows.get(deviceId); + for (DeviceContactModelDO point : points) { + items.add(buildCapacityItem(device, point, firstRow, lastRow)); + } + } + return items; + } + + private Map> queryCapacityPoints(List deviceIds) { + List points = deviceContactModelMapper.selectList( + Wrappers.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 firstRow, Map 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 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 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 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 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 deviceIds) { + return deviceIds.stream().sorted(Comparator.naturalOrder()).map(String::valueOf).collect(Collectors.joining("_")); + } + + private String buildDeviceTags(List 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()); + } + } +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/excel/templates/fully-automatic-molding-production-daily-report-template.xlsx b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/excel/templates/fully-automatic-molding-production-daily-report-template.xlsx new file mode 100644 index 000000000..ab81f204d Binary files /dev/null and b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/excel/templates/fully-automatic-molding-production-daily-report-template.xlsx differ diff --git a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApi.java b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApi.java new file mode 100644 index 000000000..e1c0921aa --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApi.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.mes.api.workteam; + +import cn.iocoder.yudao.module.mes.api.workteam.dto.WorkTeamRespDTO; + +public interface WorkTeamApi { + + WorkTeamRespDTO getWorkTeam(Long id); + +} diff --git a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/dto/WorkTeamRespDTO.java b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/dto/WorkTeamRespDTO.java new file mode 100644 index 000000000..8155af3fd --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/dto/WorkTeamRespDTO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.mes.api.workteam.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class WorkTeamRespDTO { + + private Long id; + + private String teamName; + + private String groupType; + + private LocalDateTime startTime; + + private LocalDateTime endTime; +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApiImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApiImpl.java new file mode 100644 index 000000000..19de3958c --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/workteam/WorkTeamApiImpl.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.mes.api.workteam; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.api.workteam.dto.WorkTeamRespDTO; +import cn.iocoder.yudao.module.mes.dal.dataobject.workteam.WorkTeamDO; +import cn.iocoder.yudao.module.mes.service.workteam.WorkTeamService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +public class WorkTeamApiImpl implements WorkTeamApi { + + @Resource + private WorkTeamService workTeamService; + + @Override + public WorkTeamRespDTO getWorkTeam(Long id) { + WorkTeamDO workTeam = workTeamService.getWorkTeam(id); + return BeanUtils.toBean(workTeam, WorkTeamRespDTO.class); + } +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/workteam/WorkTeamController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/workteam/WorkTeamController.java index c0b9d81a6..359d428a9 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/workteam/WorkTeamController.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/workteam/WorkTeamController.java @@ -80,6 +80,14 @@ public class WorkTeamController { return success(pageResult); } + @GetMapping("/list") + @Operation(summary = "获得生产班组列表") + @PreAuthorize("@ss.hasPermission('mes:work-team:query')") + public CommonResult> getWorkTeamList(@Valid WorkTeamPageReqVO pageReqVO) { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + return success(workTeamService.getWorkTeamPage(pageReqVO).getList()); + } + @GetMapping("/export-excel") @Operation(summary = "导出生产班组 Excel") @PreAuthorize("@ss.hasPermission('mes:work-team:export')") @@ -148,4 +156,4 @@ public class WorkTeamController { public CommonResult> getUserList2(@RequestParam("orgId") Long orgId,String groupType) { return success(workTeamService.getUserList2(orgId,groupType)); } -} \ No newline at end of file +}