package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.Pictures; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.MatrixToImageWriter; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.production.dto.ProductWorkOrderDto; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.mapper.ProductionProductReportDailyMapper; import com.ruoyi.production.mapper.ProductWorkOrderFileMapper; import com.ruoyi.production.mapper.ProductWorkOrderMapper; import com.ruoyi.production.mapper.ProductWorkOrderRapporteurMapper; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.production.pojo.ProductionProductReportDaily; import com.ruoyi.production.pojo.ProductWorkOrder; import com.ruoyi.production.pojo.ProductWorkOrderFile; import com.ruoyi.production.pojo.ProductWorkOrderRapporteur; import com.ruoyi.production.service.ProductWorkOrderService; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.net.URLEncoder; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @Service @Transactional(rollbackFor = Exception.class) public class ProductWorkOrderServiceImpl extends ServiceImpl implements ProductWorkOrderService { @Autowired private ProductWorkOrderMapper productWorkOrdermapper; @Autowired private ProductWorkOrderFileMapper productWorkOrderFileMapper; @Autowired private ProductWorkOrderRapporteurMapper productWorkOrderRapporteurMapper; @Autowired private SysUserMapper sysUserMapper; @Autowired private ProductionProductMainMapper productionProductMainMapper; @Autowired private ProductionProductReportDailyMapper productionProductReportDailyMapper; @Value("${file.temp-dir}") private String tempDir; @Override public IPage listPage(Page page, ProductWorkOrderDto productWorkOrder) { boolean reportView = productWorkOrder != null && Integer.valueOf(2).equals(productWorkOrder.getType()); Long currentUserId = null; if (reportView) { currentUserId = SecurityUtils.getUserId(); productWorkOrder.setCurrentUserId(currentUserId); } IPage pageData = productWorkOrdermapper.pageProductWorkOrder(page, productWorkOrder); List records = pageData.getRecords(); if (CollectionUtils.isEmpty(records)) { return pageData; } List workOrderIds = records.stream() .map(ProductWorkOrderDto::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(workOrderIds)) { return pageData; } List rapporteurs = productWorkOrderRapporteurMapper.selectList(Wrappers.lambdaQuery() .in(ProductWorkOrderRapporteur::getWorkOrderId, workOrderIds)); final Map> rapporteurMap = CollectionUtils.isNotEmpty(rapporteurs) ? rapporteurs.stream() .filter(item -> item.getWorkOrderId() != null && item.getUserId() != null) .collect(Collectors.groupingBy( ProductWorkOrderRapporteur::getWorkOrderId, LinkedHashMap::new, Collectors.mapping(ProductWorkOrderRapporteur::getUserId, Collectors.toList()) )) : new LinkedHashMap<>(); records.forEach(item -> { List userIds = rapporteurMap.get(item.getId()); item.setReportWorkersId(userIds == null ? new Long[0] : userIds.toArray(new Long[0])); }); // type=2 时:回填“当前报工人今日状态” if (reportView && currentUserId != null) { // 1) 进行中(status=0)的报工 List runningList = productionProductMainMapper.selectList( Wrappers.lambdaQuery() .in(ProductionProductMain::getWorkOrderId, workOrderIds) .eq(ProductionProductMain::getUserId, currentUserId) .eq(ProductionProductMain::getStatus, 0) ); final java.util.Set runningWorkOrders = CollectionUtils.isNotEmpty(runningList) ? runningList.stream().map(ProductionProductMain::getWorkOrderId).filter(Objects::nonNull).collect(Collectors.toSet()) : java.util.Collections.emptySet(); // 2) 今日已结束(今日有 daily 明细) LocalDate today = LocalDate.now(); List todayDailyList = productionProductReportDailyMapper.selectList( Wrappers.lambdaQuery() .in(ProductionProductReportDaily::getWorkOrderId, workOrderIds) .eq(ProductionProductReportDaily::getUserId, currentUserId) .eq(ProductionProductReportDaily::getReportDate, today) ); final java.util.Set endedTodayWorkOrders = CollectionUtils.isNotEmpty(todayDailyList) ? todayDailyList.stream().map(ProductionProductReportDaily::getWorkOrderId).filter(Objects::nonNull).collect(Collectors.toSet()) : java.util.Collections.emptySet(); records.forEach(item -> { Long woId = item.getId(); if (woId == null) { item.setTodayReportState(1); return; } if (runningWorkOrders.contains(woId)) { item.setTodayReportState(2); return; } if (endedTodayWorkOrders.contains(woId)) { item.setTodayReportState(3); return; } item.setTodayReportState(1); }); } // 回填报工时间总和(分钟): type=2 按当前登录人汇总,其他按工单全员汇总 QueryWrapper totalDurationQw = new QueryWrapper<>(); totalDurationQw.select("work_order_id as workOrderId", "sum(duration_minutes) as totalMinutes") .in("work_order_id", workOrderIds) .groupBy("work_order_id"); if (reportView && currentUserId != null) { totalDurationQw.eq("user_id", currentUserId); } List> durationRows = productionProductReportDailyMapper.selectMaps(totalDurationQw); Map durationMap = new HashMap<>(); if (CollectionUtils.isNotEmpty(durationRows)) { for (Map row : durationRows) { Object workOrderObj = row.get("workOrderId"); if (workOrderObj == null) { workOrderObj = row.get("work_order_id"); } Object totalObj = row.get("totalMinutes"); if (totalObj == null) { totalObj = row.get("total_minutes"); } if (workOrderObj == null || totalObj == null) { continue; } Long woId = workOrderObj instanceof Number ? ((Number) workOrderObj).longValue() : Long.valueOf(workOrderObj.toString()); BigDecimal totalMinutes = totalObj instanceof BigDecimal ? (BigDecimal) totalObj : new BigDecimal(totalObj.toString()); durationMap.put(woId, totalMinutes); } } records.forEach(item -> item.setTotalReportDurationMinutes(durationMap.getOrDefault(item.getId(), BigDecimal.ZERO))); return pageData; } @Override public int updateProductWorkOrder(ProductWorkOrderDto productWorkOrderDto) { int rows = productWorkOrdermapper.updateById(productWorkOrderDto); if (rows <= 0 || productWorkOrderDto.getId() == null) { return rows; } productWorkOrderRapporteurMapper.delete(Wrappers.lambdaQuery() .eq(ProductWorkOrderRapporteur::getWorkOrderId, productWorkOrderDto.getId())); Long[] rapporteurIds = productWorkOrderDto.getReportWorkersId(); if (rapporteurIds == null || rapporteurIds.length == 0) { return rows; } List candidateUserIds = Arrays.stream(rapporteurIds) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (CollectionUtils.isEmpty(candidateUserIds)) { return rows; } List existUserIds = sysUserMapper.selectUsersByIds(candidateUserIds).stream() .map(SysUser::getUserId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (existUserIds.size() != candidateUserIds.size()) { List invalidUserIds = candidateUserIds.stream() .filter(id -> !existUserIds.contains(id)) .collect(Collectors.toList()); throw new ServiceException("报工人不存在: " + invalidUserIds); } List rapporteurList = candidateUserIds.stream() .map(userId -> { ProductWorkOrderRapporteur rapporteur = new ProductWorkOrderRapporteur(); rapporteur.setWorkOrderId(productWorkOrderDto.getId()); rapporteur.setUserId(userId); return rapporteur; }) .collect(Collectors.toList()); if (!rapporteurList.isEmpty()) { rapporteurList.forEach(productWorkOrderRapporteurMapper::insert); } return rows; } @Override public void down(HttpServletResponse response, ProductWorkOrder productWorkOrder) { ProductWorkOrderDto productWorkOrderDto = productWorkOrdermapper.getProductWorkOrderFlowCard(productWorkOrder.getId()); Long workOrderId = productWorkOrder.getId(); Long productProcessRouteItemId = productWorkOrderDto.getProductProcessRouteItemId(); String qrContent = String.format( "{\"workOrderId\":%d,\"productProcessRouteItemId\":%d}", workOrderId, productProcessRouteItemId == null ? 0 : productProcessRouteItemId ); String codePath; try { codePath = new MatrixToImageWriter().code(qrContent, tempDir); } catch (Exception e) { throw new RuntimeException(e); } /*获取附件图片类型*/ List> images = new ArrayList<>(); List productWorkOrderFiles = productWorkOrderFileMapper.selectList(Wrappers.lambdaQuery().eq(ProductWorkOrderFile::getWorkOrderId, productWorkOrder.getId())); if (CollectionUtils.isNotEmpty(productWorkOrderFiles)) { productWorkOrderFiles.forEach(productWorkOrderFile -> { Map image = new HashMap<>(); PictureRenderData pictureRenderData = Pictures.ofLocal(productWorkOrderFile.getUrl()).sizeInCm(17, 20).create(); image.put("url", pictureRenderData); images.add(image); }); } InputStream inputStream = this.getClass().getResourceAsStream("/static/work-order-template.docx"); XWPFTemplate template = XWPFTemplate.compile(inputStream).render( new HashMap() {{ put("process", productWorkOrderDto.getProcessName()); put("workOrderNo", productWorkOrderDto.getWorkOrderNo()); put("productOrderNpsNo", productWorkOrderDto.getProductOrderNpsNo()); put("productName", productWorkOrderDto.getProductName()); put("planQuantity", productWorkOrderDto.getPlanQuantity()); put("model", productWorkOrderDto.getModel()); put("completeQuantity", productWorkOrderDto.getCompleteQuantity()); put("scrapQty", productWorkOrderDto.getScrapQty()); put("planStartTime", productWorkOrderDto.getPlanStartTime()); put("planEndTime", productWorkOrderDto.getPlanEndTime()); put("actualStartTime", productWorkOrderDto.getActualStartTime()); put("actualEndTime", productWorkOrderDto.getActualEndTime()); put("twoCode", Pictures.ofLocal(codePath).create()); put("images", images.isEmpty() ? null : images); }}); try { response.setContentType("application/msword"); String fileName = URLEncoder.encode( "流转卡", "UTF-8"); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx"); OutputStream os = response.getOutputStream(); template.write(os); os.flush(); os.close(); inputStream.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("导出失败"); } } }