package com.ruoyi.common.utils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.ruoyi.basic.dto.ProductModelExcelDto; import com.ruoyi.basic.dto.ProductModelExcelItemDto; import com.ruoyi.common.utils.uuid.UUID; import org.apache.poi.ss.formula.functions.T; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * @author :yys * @date : 2025/9/15 15:31 */ public class OrderUtils { /** * 查询当天(基于createTime字段)的记录数量 * @param mapper 实体类对应的BaseMapper * @param 实体类泛型 * @return 当天记录数量 */ public static String countTodayByCreateTime(BaseMapper mapper,String preFix) { // 获取当天开始时间(00:00:00) LocalDateTime todayStart = LocalDateTime.of( LocalDateTime.now().toLocalDate(), LocalTime.MIN ); // 获取当天结束时间(23:59:59.999) LocalDateTime todayEnd = LocalDateTime.of( LocalDateTime.now().toLocalDate(), LocalTime.MAX ); // 转换为Date类型(如果实体类中createTime是LocalDateTime可直接使用) Date startDate = Date.from(todayStart.atZone(ZoneId.systemDefault()).toInstant()); Date endDate = Date.from(todayEnd.atZone(ZoneId.systemDefault()).toInstant()); // 构建查询条件 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.ge("create_time", startDate) // 大于等于当天开始 .lt("create_time", endDate); // 小于当天结束(避免毫秒精度问题) // 执行查询 Long aLong = mapper.selectCount(queryWrapper); // 拼接订单编号 preFix + 时间(yyyyMMdd) + 订单数量(001) return preFix + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE).replaceAll("-", "") + String.format("%03d", (aLong + 1)) + "-" + new Date().getTime(); } /** * 将平面列表转换为树形结构(含规格型号拆分功能) * @param flatList 导入的平面数据列表 * @return 树形结构的根节点列表 */ public static List buildTree(List flatList) { // 1. 参数校验 if (CollectionUtils.isEmpty(flatList)) { return new ArrayList<>(); } // 2. 预处理:过滤无效数据 + 规格型号拆分 + 初始化子节点列表 List validList = preprocessData(flatList); if (CollectionUtils.isEmpty(validList)) { return new ArrayList<>(); } // 3. 按层级分组,便于逐层处理 Map> levelGroupMap = groupByLevel(validList); // 4. 构建节点映射(序号 -> 节点),提高查询效率 Map nodeMap = buildNodeMap(validList); // 5. 逐层构建父子关系 buildParentChildRelation(levelGroupMap, nodeMap); // 6. 获取根节点(层级1)并排序 List rootNodes = getRootNodes(levelGroupMap); sortTreeNodes(rootNodes); return rootNodes; } /** * 数据预处理: * 1. 过滤无效数据 * 2. 规格型号拆分并填充到items集合 * 3. 初始化子节点列表 */ private static List preprocessData(List flatList) { return flatList.stream() // 过滤核心字段无效的节点 .filter(node -> isValidNode(node)) // 处理规格型号拆分和items填充 .peek(node -> { // 拆分规格型号并填充到items splitModelAndFillItems(node); // 初始化子节点列表(避免空指针) if (node.getChildren() == null) { node.setChildren(new ArrayList<>()); } }) .collect(Collectors.toList()); } /** * 验证节点是否有效(核心字段校验) */ private static boolean isValidNode(ProductModelExcelDto node) { if (node == null) { return false; } // 序号必须有效(基础校验) if (!isValidSequence(node.getNumber())) { return false; } // 产品名称非空(业务校验,可根据实际需求调整) return StringUtils.isNotBlank(node.getProductName()); } /** * 规格型号拆分并填充到items集合 * @param node 待处理的节点 */ private static void splitModelAndFillItems(ProductModelExcelDto node) { // 1. 获取原始规格型号 String originalModel = node.getModel(); List items = new ArrayList<>(); if (StringUtils.isNotBlank(originalModel)) { // 2. 按"+"拆分规格型号(如果有多个),处理每个片段 List splitModels = Arrays.stream(originalModel.split("\\+")) .map(String::trim) .filter(StringUtils::isNotBlank) .distinct() .collect(Collectors.toList()); // 3. 为每个规格创建Item(即使只有一个,也生成一个Item) items = splitModels.stream() .map(model -> createExcelItem(node, model)) .collect(Collectors.toList()); } // 4. 填充到节点的items集合(覆盖原有数据) node.setItems(items); } /** * 创建ProductModelExcelItemDto对象(继承原节点的公共属性) * @param node 原节点 * @param model 拆分后的规格型号 * @return 构建好的Item对象 */ private static ProductModelExcelItemDto createExcelItem(ProductModelExcelDto node, String model) { ProductModelExcelItemDto item = new ProductModelExcelItemDto(); // 1. 拆分后的规格型号 item.setModel(model); // 2. 继承原节点的单位(空值处理) item.setUnit(StringUtils.defaultIfBlank(node.getUnit(), "")); // 3. 继承原节点的产品类型(空值处理,默认0表示未知) item.setProductType(Optional.ofNullable(node.getProductType()).orElse(0)); // 4. 继承原节点的图纸编号(空值处理) item.setDrawingNumber(StringUtils.defaultIfBlank(node.getDrawingNumber(), "")); return item; } /** * 验证序号格式是否有效(支持1、1.1、1.1.1等格式) */ private static boolean isValidSequence(String sequence) { if (StringUtils.isBlank(sequence)) { return false; } // 正则表达式:匹配数字开头,后续可跟.和数字 return sequence.trim().matches("^\\d+(\\.\\d+)*$"); } /** * 按节点层级分组 */ private static Map> groupByLevel(List validList) { return validList.stream() .collect(Collectors.groupingBy( node -> getNodeLevel(node.getNumber()), // 计算层级 TreeMap::new, // 按层级升序排序 Collectors.toList() )); } /** * 计算节点层级(序号中.的数量 + 1) * 例:1 -> 1级,1.1 -> 2级,1.1.1 -> 3级 */ private static int getNodeLevel(String sequence) { if (StringUtils.isBlank(sequence)) { return 0; } String trimmedSeq = sequence.trim(); return trimmedSeq.split("\\.").length; } /** * 构建节点映射表(序号 -> 节点) */ private static Map buildNodeMap(List validList) { return validList.stream() .collect(Collectors.toMap( node -> node.getNumber().trim(), // 键:序号(去空格) node -> node, // 值:节点对象 (oldVal, newVal) -> oldVal // 处理重复序号:保留第一个 )); } /** * 构建父子节点关系 */ private static void buildParentChildRelation(Map> levelGroupMap, Map nodeMap) { // 从层级2开始处理(层级1是根节点,无父节点) for (Map.Entry> entry : levelGroupMap.entrySet()) { int currentLevel = entry.getKey(); if (currentLevel <= 1) { continue; // 跳过根节点层级 } List currentLevelNodes = entry.getValue(); for (ProductModelExcelDto currentNode : currentLevelNodes) { // 计算父节点序号 String parentSequence = getParentSequence(currentNode.getNumber()); if (StringUtils.isBlank(parentSequence)) { continue; } // 查找父节点 ProductModelExcelDto parentNode = nodeMap.get(parentSequence); if (parentNode != null && parentNode.getChildren() != null) { // 添加到父节点的子节点列表 parentNode.getChildren().add(currentNode); } } } } /** * 根据当前节点序号获取父节点序号 * 例:1.1.2 -> 1.1,1.2 -> 1,1 -> null */ private static String getParentSequence(String currentSequence) { if (StringUtils.isBlank(currentSequence)) { return null; } String trimmedSeq = currentSequence.trim(); String[] seqParts = trimmedSeq.split("\\."); if (seqParts.length <= 1) { return null; // 根节点无父节点 } // 去掉最后一部分,拼接父节点序号 String[] parentParts = Arrays.copyOfRange(seqParts, 0, seqParts.length - 1); return String.join(".", parentParts); } /** * 获取根节点列表(层级1的节点) */ private static List getRootNodes(Map> levelGroupMap) { return levelGroupMap.getOrDefault(1, new ArrayList<>()); } /** * 递归排序所有节点(按序号数字顺序) */ private static void sortTreeNodes(List nodeList) { if (CollectionUtils.isEmpty(nodeList)) { return; } // 排序当前层级节点 nodeList.sort(Comparator.comparing( ProductModelExcelDto::getNumber, new SequenceComparator() // 自定义序号比较器 )); // 递归排序子节点 for (ProductModelExcelDto node : nodeList) { sortTreeNodes(node.getChildren()); } } /** * 序号比较器:按数字顺序排序(支持1.10在1.2之后) */ private static class SequenceComparator implements Comparator { @Override public int compare(String seq1, String seq2) { if (StringUtils.isBlank(seq1) && StringUtils.isBlank(seq2)) { return 0; } if (StringUtils.isBlank(seq1)) { return -1; } if (StringUtils.isBlank(seq2)) { return 1; } // 分割序号为数字数组 String[] parts1 = seq1.trim().split("\\."); String[] parts2 = seq2.trim().split("\\."); // 逐段比较数字 int minLength = Math.min(parts1.length, parts2.length); for (int i = 0; i < minLength; i++) { int num1 = parseSequencePart(parts1[i]); int num2 = parseSequencePart(parts2[i]); if (num1 != num2) { return num1 - num2; } } // 长度不同时,短的在前(如1.1在1.1.1之前) return parts1.length - parts2.length; } /** * 解析序号片段为数字(处理异常情况) */ private int parseSequencePart(String part) { try { return Integer.parseInt(part.trim()); } catch (NumberFormatException e) { return 0; // 异常情况按0处理 } } } /** * 产品类型映射(1=物料,2=产品,0=未知) */ private static String mapProductType(Integer productType) { return Optional.ofNullable(productType) .map(type -> type == 1 ? "物料" : (type == 2 ? "产品" : "未知")) .orElse("未知"); } }