|
|
|
@ -3,6 +3,7 @@ package com.xujie.sys.modules.longchuang.service.impl; |
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|
|
|
import com.xujie.sys.common.exception.I18nException; |
|
|
|
import com.xujie.sys.common.exception.XJException; |
|
|
|
import com.xujie.sys.common.utils.PageUtils; |
|
|
|
import com.xujie.sys.modules.longchuang.data.ProductionPlanNodeReportData; |
|
|
|
import com.xujie.sys.modules.longchuang.data.ProductionPlanNodeAssigneeData; |
|
|
|
@ -22,25 +23,32 @@ import com.xujie.sys.modules.longchuang.data.ProductionPlanRoleQueryData; |
|
|
|
import com.xujie.sys.modules.longchuang.data.ProductionPlanUserOptionData; |
|
|
|
import com.xujie.sys.modules.longchuang.mapper.ProductionPlanMapper; |
|
|
|
import com.xujie.sys.modules.longchuang.service.ProductionPlanService; |
|
|
|
import com.xujie.sys.modules.oss.entity.SysOssEntity; |
|
|
|
import com.xujie.sys.modules.oss.service.SysOssService; |
|
|
|
import com.xujie.sys.modules.sys.entity.SysUserEntity; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.shiro.SecurityUtils; |
|
|
|
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 org.springframework.util.StringUtils; |
|
|
|
import org.springframework.web.multipart.MultipartFile; |
|
|
|
|
|
|
|
import java.io.File; |
|
|
|
import java.math.BigDecimal; |
|
|
|
import java.time.LocalDate; |
|
|
|
import java.time.LocalDateTime; |
|
|
|
import java.time.format.DateTimeFormatter; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.Date; |
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.LinkedHashMap; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.UUID; |
|
|
|
import java.util.concurrent.ThreadLocalRandom; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
@ -60,10 +68,17 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
private static final String NODE_STATUS_DONE = "已完成"; |
|
|
|
private static final String NODE_REPORT_MODE_PARALLEL = "PARALLEL"; |
|
|
|
private static final String NODE_REPORT_MODE_SEQUENTIAL = "SEQUENTIAL"; |
|
|
|
private static final String NODE_MEDIA_REF_TYPE = "LONGCHUANG_NODE_REPORT_MEDIA"; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ProductionPlanMapper productionPlanMapper; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private SysOssService sysOssService; |
|
|
|
|
|
|
|
@Value("${longchuang.production-report.media-root:D:\\longchuang}") |
|
|
|
private String workReportMediaRootPath; |
|
|
|
|
|
|
|
@Override |
|
|
|
public PageUtils queryHomeLiftOrderPage(ProductionPlanOrderQueryData data) { |
|
|
|
return queryOrderPage(data, ORDER_TYPE_HOME_LIFT); |
|
|
|
@ -83,8 +98,8 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public void reportHomeLiftOrderNode(ProductionPlanNodeReportData data) { |
|
|
|
reportOrderNode(data, ORDER_TYPE_HOME_LIFT); |
|
|
|
public String reportHomeLiftOrderNode(ProductionPlanNodeReportData data) { |
|
|
|
return reportOrderNode(data, ORDER_TYPE_HOME_LIFT); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -112,8 +127,8 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public void reportCableCopTaskNode(ProductionPlanNodeReportData data) { |
|
|
|
reportOrderNode(data, ORDER_TYPE_CABLE_COP); |
|
|
|
public String reportCableCopTaskNode(ProductionPlanNodeReportData data) { |
|
|
|
return reportOrderNode(data, ORDER_TYPE_CABLE_COP); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -141,8 +156,8 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public void reportRenovationOrderNode(ProductionPlanNodeReportData data) { |
|
|
|
reportOrderNode(data, ORDER_TYPE_RENOVATION); |
|
|
|
public String reportRenovationOrderNode(ProductionPlanNodeReportData data) { |
|
|
|
return reportOrderNode(data, ORDER_TYPE_RENOVATION); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -170,8 +185,26 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public void reportMachiningTaskNode(ProductionPlanNodeReportData data) { |
|
|
|
reportOrderNode(data, ORDER_TYPE_MACHINING); |
|
|
|
public String reportMachiningTaskNode(ProductionPlanNodeReportData data) { |
|
|
|
return reportOrderNode(data, ORDER_TYPE_MACHINING); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public String reportNodeWithMedia(ProductionPlanNodeReportData data, MultipartFile[] files) { |
|
|
|
if (data == null || !StringUtils.hasText(data.getOrderType())) { |
|
|
|
throw new I18nException("lc.production.report.param.incomplete"); |
|
|
|
} |
|
|
|
if (files == null || files.length <= 0) { |
|
|
|
throw new XJException("请先拍照或录制视频"); |
|
|
|
} |
|
|
|
String orderType = normalizeOrderType(data.getOrderType()); |
|
|
|
if (ORDER_TYPE_MACHINING.equals(orderType)) { |
|
|
|
throw new XJException("机加工报工无需上传影像"); |
|
|
|
} |
|
|
|
String logNo = reportOrderNode(data, orderType); |
|
|
|
saveNodeReportMedia(data, orderType, logNo, files); |
|
|
|
return logNo; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -717,7 +750,7 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
return node; |
|
|
|
} |
|
|
|
|
|
|
|
private void reportOrderNode(ProductionPlanNodeReportData data, String orderType) { |
|
|
|
private String reportOrderNode(ProductionPlanNodeReportData data, String orderType) { |
|
|
|
if (data == null || !StringUtils.hasText(data.getOrderNo()) || !StringUtils.hasText(data.getNodeCode())) { |
|
|
|
throw new I18nException("lc.production.report.param.incomplete"); |
|
|
|
} |
|
|
|
@ -780,9 +813,138 @@ public class ProductionPlanServiceImpl implements ProductionPlanService { |
|
|
|
data.setNodeName(node.getNodeName()); |
|
|
|
data.setReportUserId(userId); |
|
|
|
data.setReportUserName(userName); |
|
|
|
data.setLogNo(generateLogNo(orderType)); |
|
|
|
String logNo = generateLogNo(orderType); |
|
|
|
data.setLogNo(logNo); |
|
|
|
data.setRemark(ORDER_TYPE_MACHINING.equals(orderType)&&data.getReportQty() != null ? "报工数量:"+data.getReportQty():""); |
|
|
|
productionPlanMapper.insertNodeReportLog(data); |
|
|
|
return logNo; |
|
|
|
} |
|
|
|
|
|
|
|
private void saveNodeReportMedia(ProductionPlanNodeReportData data, String orderType, String logNo, MultipartFile[] files) { |
|
|
|
ProductionPlanOrderNodeData node = productionPlanMapper.queryOrderNodeByCode(data.getOrderNo(), data.getNodeCode()); |
|
|
|
if (node == null) { |
|
|
|
throw new I18nException("lc.production.report.node.not.exists"); |
|
|
|
} |
|
|
|
String rootPath = StringUtils.hasText(workReportMediaRootPath) ? workReportMediaRootPath : "D:\\longchuang"; |
|
|
|
File rootDir = new File(rootPath); |
|
|
|
if (!rootDir.exists() && !rootDir.mkdirs()) { |
|
|
|
throw new XJException("报工影像根目录创建失败"); |
|
|
|
} |
|
|
|
String folderName = sanitizeFolderName(node.getNodeName()); |
|
|
|
if (!StringUtils.hasText(folderName)) { |
|
|
|
folderName = sanitizeFolderName(node.getNodeCode()); |
|
|
|
} |
|
|
|
if (!StringUtils.hasText(folderName)) { |
|
|
|
folderName = "UNKNOWN_NODE"; |
|
|
|
} |
|
|
|
File nodeFolder = new File(rootDir, folderName); |
|
|
|
if (!nodeFolder.exists() && !nodeFolder.mkdirs()) { |
|
|
|
throw new XJException("节点影像目录创建失败"); |
|
|
|
} |
|
|
|
String dateFolderName = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); |
|
|
|
File nodeDateFolder = new File(nodeFolder, dateFolderName); |
|
|
|
if (!nodeDateFolder.exists() && !nodeDateFolder.mkdirs()) { |
|
|
|
throw new XJException("节点影像日期目录创建失败"); |
|
|
|
} |
|
|
|
|
|
|
|
Long userId = getCurrentUserId(); |
|
|
|
String userName = getCurrentUserName(); |
|
|
|
List<File> savedFileList = new ArrayList<>(); |
|
|
|
int uploadCount = 0; |
|
|
|
try { |
|
|
|
for (MultipartFile file : files) { |
|
|
|
if (file == null || file.isEmpty()) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
String suffix = resolveMediaSuffix(file.getOriginalFilename(), file.getContentType()); |
|
|
|
String newFileName = buildMediaFileName(suffix); |
|
|
|
File targetFile = new File(nodeDateFolder, newFileName); |
|
|
|
file.transferTo(targetFile); |
|
|
|
savedFileList.add(targetFile); |
|
|
|
|
|
|
|
SysOssEntity ossEntity = new SysOssEntity(); |
|
|
|
ossEntity.setUrl(targetFile.getAbsolutePath()); |
|
|
|
ossEntity.setCreateDate(new Date()); |
|
|
|
ossEntity.setFileName(StringUtils.hasText(file.getOriginalFilename()) ? file.getOriginalFilename() : newFileName); |
|
|
|
ossEntity.setNewFileName(newFileName); |
|
|
|
ossEntity.setFileType(suffix); |
|
|
|
ossEntity.setCreatedBy(userName); |
|
|
|
ossEntity.setOrderRef1(data.getOrderNo()); |
|
|
|
ossEntity.setOrderRef2(node.getNodeCode()); |
|
|
|
ossEntity.setOrderRef3(logNo); |
|
|
|
ossEntity.setOrderRef4(orderType); |
|
|
|
ossEntity.setOrderRef5(String.valueOf(userId)); |
|
|
|
ossEntity.setOrderRef6(node.getNodeName()); |
|
|
|
ossEntity.setOrderReftype(NODE_MEDIA_REF_TYPE); |
|
|
|
ossEntity.setCAdditionalInfo(resolveMediaCategory(file.getContentType())); |
|
|
|
ossEntity.setConclusion(userName); |
|
|
|
sysOssService.save(ossEntity); |
|
|
|
uploadCount++; |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
for (File savedFile : savedFileList) { |
|
|
|
if (savedFile != null && savedFile.exists()) { |
|
|
|
savedFile.delete(); |
|
|
|
} |
|
|
|
} |
|
|
|
throw new XJException("报工影像上传失败,请重试"); |
|
|
|
} |
|
|
|
if (uploadCount <= 0) { |
|
|
|
throw new XJException("请先拍照或录制视频"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private String sanitizeFolderName(String folderName) { |
|
|
|
if (!StringUtils.hasText(folderName)) { |
|
|
|
return ""; |
|
|
|
} |
|
|
|
return folderName.replaceAll("[\\\\/:*?\"<>|]", "_").trim(); |
|
|
|
} |
|
|
|
|
|
|
|
private String resolveMediaSuffix(String originalFileName, String contentType) { |
|
|
|
if (StringUtils.hasText(originalFileName)) { |
|
|
|
int dotIndex = originalFileName.lastIndexOf("."); |
|
|
|
if (dotIndex >= 0 && dotIndex < originalFileName.length() - 1) { |
|
|
|
return originalFileName.substring(dotIndex + 1).toLowerCase(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!StringUtils.hasText(contentType)) { |
|
|
|
return "bin"; |
|
|
|
} |
|
|
|
String lowerType = contentType.toLowerCase(); |
|
|
|
if (lowerType.contains("jpeg")) { |
|
|
|
return "jpg"; |
|
|
|
} |
|
|
|
if (lowerType.contains("png")) { |
|
|
|
return "png"; |
|
|
|
} |
|
|
|
if (lowerType.contains("webm")) { |
|
|
|
return "webm"; |
|
|
|
} |
|
|
|
if (lowerType.contains("mp4")) { |
|
|
|
return "mp4"; |
|
|
|
} |
|
|
|
return "bin"; |
|
|
|
} |
|
|
|
|
|
|
|
private String buildMediaFileName(String suffix) { |
|
|
|
String timeText = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); |
|
|
|
String randomText = UUID.randomUUID().toString().replace("-", ""); |
|
|
|
return "LCM_" + timeText + "_" + randomText + "." + suffix; |
|
|
|
} |
|
|
|
|
|
|
|
private String resolveMediaCategory(String contentType) { |
|
|
|
if (!StringUtils.hasText(contentType)) { |
|
|
|
return "OTHER"; |
|
|
|
} |
|
|
|
String lowerType = contentType.toLowerCase(); |
|
|
|
if (lowerType.startsWith("image/")) { |
|
|
|
return "IMAGE"; |
|
|
|
} |
|
|
|
if (lowerType.startsWith("video/")) { |
|
|
|
return "VIDEO"; |
|
|
|
} |
|
|
|
return "OTHER"; |
|
|
|
} |
|
|
|
|
|
|
|
private void checkNodeAssigneePermission(String orderNo, String orderType, String nodeCode) { |
|
|
|
|