From 30ca39a4b658cb3256455fb33d4d0cd9b4d2fa17 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 14 Dec 2025 15:04:50 +0800 Subject: [PATCH] 1 --- .../service/impl/InstructionServiceImpl.java | 291 ++++++++++++++---- 1 file changed, 229 insertions(+), 62 deletions(-) diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/InstructionServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/InstructionServiceImpl.java index 6bb1ed1..ea1fc60 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/InstructionServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/InstructionServiceImpl.java @@ -1290,9 +1290,9 @@ public class InstructionServiceImpl implements IInstructionService { // 与 JDUtil.parseOrderFromText 一致的模板字段 JDOrder order = parseOrderFromText(originalInput); - // 字段校验并返回缺失项 + // 字段校验并返回缺失项(根据新模板格式,单号存储在remark字段中) StringBuilder missing = new StringBuilder(); - if (isEmpty(order.getOrderId())) missing.append("单号\n"); + if (isEmpty(order.getRemark())) missing.append("单号\n"); if (isEmpty(order.getBuyer())) missing.append("下单人\n"); if (order.getPaymentAmount() == null || order.getPaymentAmount() == 0) missing.append("下单价格\n"); if (order.getRebateAmount() == null) missing.append("后返金额\n"); @@ -1480,58 +1480,41 @@ public class InstructionServiceImpl implements IInstructionService { // 参照 JDUtil.parseOrderFromText private JDOrder parseOrderFromText(String input) { - // 不要替换所有空格,保留换行符用于正确解析 + // 检测是否是新格式(包含分隔线"—————————"或新格式字段标签) + boolean isNewFormat = input.contains("—————————") || + input.contains("下单链接(必须用这个):") || + input.contains("下单地址(注意带分机):") || + input.contains("下单人(需填):") || + input.contains("下单付款(注意核对):") || + input.contains("后返金额(注意核对):") || + input.contains("订单号(需填):") || + input.contains("物流链接(需填):") || + input.contains("备注(下单号码有变动/没法带分机号的写这里):"); + + System.out.println("=== 开始解析订单文本 ==="); + System.out.println("是否为新格式: " + isNewFormat); + System.out.println("输入文本长度: " + (input != null ? input.length() : 0)); + Map fields = new HashMap<>(); - // 先尝试新格式(带第三方单号和京粉实际价格) - extractField(input, fields, "单:", "备注:"); - extractField(input, fields, "备注:", "分销标记:"); - - // 检查是否有"第三方单号:"字段,如果没有则是旧格式 - boolean hasThirdPartyOrderNo = input.contains("第三方单号:"); - boolean hasJingfenPrice = input.contains("京粉实际价格:"); - - if (hasThirdPartyOrderNo) { - // 新格式:有第三方单号字段 - extractField(input, fields, "分销标记:", "第三方单号:"); - extractField(input, fields, "第三方单号:", "型号:"); + if (isNewFormat) { + // 新格式:使用新的解析方法(支持分隔线) + System.out.println("使用新格式解析方法"); + parseNewFormat(input, fields); } else { - // 旧格式:分销标记后面直接是型号 - extractField(input, fields, "分销标记:", "型号:"); - } - - extractField(input, fields, "型号:", "链接:"); - extractField(input, fields, "链接:", "下单付款:"); - extractField(input, fields, "下单付款:", "后返金额:"); - extractField(input, fields, "后返金额:", "地址:"); - extractField(input, fields, "地址:", "物流链接:"); - extractField(input, fields, "物流链接:", "订单号:"); - extractField(input, fields, "订单号:", "下单人:"); - - // 京粉实际价格不从表单解析,而是从数据库查询获取 - // 如果表单中有这个字段,也提取出来(但不会使用,仅用于兼容) - if (hasJingfenPrice) { - extractField(input, fields, "下单人:", "京粉实际价格:"); - extractField(input, fields, "京粉实际价格:", ""); - } else { - extractField(input, fields, "下单人:", ""); - } - - // 使用正则提取下单人(兼容新旧格式) - String nextField = hasJingfenPrice ? "京粉实际价格:" : "单:"; - java.util.regex.Pattern buyerPattern = java.util.regex.Pattern.compile("下单人:\\s*(.*?)\\s*(?=" + nextField + "|\\Z)", java.util.regex.Pattern.DOTALL); - java.util.regex.Matcher buyerMatcher = buyerPattern.matcher(input); - if (buyerMatcher.find()) { - String buyer = buyerMatcher.group(1).trim(); - // 如果提取的内容包含换行符,可能是提取过度了,只取第一行 - if (buyer.contains("\n")) { - buyer = buyer.split("\n")[0].trim(); - } - fields.put("下单人", buyer); + // 旧格式:保持原有逻辑不变 + System.out.println("使用旧格式解析方法"); + parseOldFormat(input, fields); } + + System.out.println("解析到的字段: " + fields); + // 构建 JDOrder 对象 JDOrder order = new JDOrder(); - order.setRemark(fields.getOrDefault("单", null)); + // 单号(格式:2025-12-13 006) + String orderNo = fields.getOrDefault("单", "").trim(); + order.setRemark(orderNo); + System.out.println("单号(remark): " + orderNo); // 处理分销标记:如果提取的内容包含换行符,说明可能提取过度了,只取第一行 String distributionMark = fields.getOrDefault("分销标记", null); @@ -1568,33 +1551,217 @@ public class InstructionServiceImpl implements IInstructionService { // 保存第三方单号到订单对象 order.setThirdPartyOrderNo(thirdPartyOrderNo != null && !thirdPartyOrderNo.trim().isEmpty() ? thirdPartyOrderNo.trim() : null); order.setModelNumber(fields.getOrDefault("型号", null)); - order.setLink(fields.getOrDefault("链接", null)); + System.out.println("型号: " + order.getModelNumber()); + + // 下单链接(新格式)或链接(旧格式) + String link = fields.getOrDefault("下单链接(必须用这个)", null); + if (link == null) { + link = fields.getOrDefault("链接", null); + } + order.setLink(link); + System.out.println("链接: " + link); + + // 备注字段 order.setStatus(fields.getOrDefault("备注", null)); - try { - order.setPaymentAmount(Double.parseDouble(fields.getOrDefault("下单付款", "0"))); - } catch (Exception ignore) { + System.out.println("备注: " + order.getStatus()); + + // 下单付款(新格式)或下单付款(旧格式) + String paymentStr = fields.getOrDefault("下单付款(注意核对)", null); + if (paymentStr == null) { + paymentStr = fields.getOrDefault("下单付款", "0"); } try { - order.setRebateAmount(Double.parseDouble(fields.getOrDefault("后返金额", "0"))); - } catch (Exception ignore) { + paymentStr = paymentStr.trim(); + if (!paymentStr.isEmpty() && !paymentStr.equals("0")) { + order.setPaymentAmount(Double.parseDouble(paymentStr)); + } + } catch (Exception e) { + System.out.println("解析下单付款失败: " + paymentStr + ", error: " + e.getMessage()); } - order.setAddress(fields.getOrDefault("地址", null)); - // 写入数据库时清理物流链接,只保留URL - order.setLogisticsLink(extractFirstUrl(fields.getOrDefault("物流链接", ""))); - order.setOrderId(fields.getOrDefault("订单号", null)); - order.setBuyer(fields.getOrDefault("下单人", null)); + System.out.println("下单付款: " + order.getPaymentAmount()); + + // 后返金额(新格式)或后返金额(旧格式) + String rebateStr = fields.getOrDefault("后返金额(注意核对)", null); + if (rebateStr == null) { + rebateStr = fields.getOrDefault("后返金额", "0"); + } + try { + rebateStr = rebateStr.trim(); + if (!rebateStr.isEmpty() && !rebateStr.equals("0")) { + order.setRebateAmount(Double.parseDouble(rebateStr)); + } + } catch (Exception e) { + System.out.println("解析后返金额失败: " + rebateStr + ", error: " + e.getMessage()); + } + System.out.println("后返金额: " + order.getRebateAmount()); + + // 下单地址(新格式)或地址(旧格式) + String address = fields.getOrDefault("下单地址(注意带分机)", null); + if (address == null) { + address = fields.getOrDefault("地址", null); + } + order.setAddress(address); + System.out.println("地址: " + (address != null && address.length() > 50 ? address.substring(0, 50) + "..." : address)); + + // 物流链接(新格式)或物流链接(旧格式) + String logisticsLink = fields.getOrDefault("物流链接(需填)", null); + if (logisticsLink == null) { + logisticsLink = fields.getOrDefault("物流链接", ""); + } + order.setLogisticsLink(extractFirstUrl(logisticsLink)); + System.out.println("物流链接: " + order.getLogisticsLink()); + + // 订单号(新格式)或订单号(旧格式) + String orderId = fields.getOrDefault("订单号(需填)", null); + if (orderId == null) { + orderId = fields.getOrDefault("订单号", null); + } + order.setOrderId(orderId); + System.out.println("订单号: " + orderId); + + // 下单人(新格式)或下单人(旧格式) + String buyer = fields.getOrDefault("下单人(需填)", null); + if (buyer == null) { + buyer = fields.getOrDefault("下单人", null); + } + order.setBuyer(buyer); + System.out.println("下单人: " + buyer); // 京粉实际价格不从表单解析,而是从数据库order_rows表中查询获取 // 默认参与统计 order.setIsCountEnabled(1); + + // 设置下单时间 try { - String dateStr = fields.getOrDefault("单", "").split(" ")[0]; - java.text.SimpleDateFormat sdf2 = new java.text.SimpleDateFormat("yyyy-MM-dd"); - order.setOrderTime(sdf2.parse(dateStr)); + if (!orderNo.isEmpty()) { + String dateStr = orderNo.split("\\s+")[0]; // 从"2025-12-13 006"中提取日期部分 + java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); + order.setOrderTime(sdf.parse(dateStr)); + System.out.println("下单时间: " + order.getOrderTime()); + } else { + order.setOrderTime(new Date()); + System.out.println("下单时间(默认): " + order.getOrderTime()); + } } catch (Exception e) { order.setOrderTime(new Date()); + System.out.println("解析下单时间失败: " + e.getMessage()); } + + System.out.println("=== 解析完成 ==="); return order; } + + // 解析新格式(带分隔线) + private void parseNewFormat(String input, Map fields) { + extractFieldWithSeparator(input, fields, "单:", "分销标记:"); + extractFieldWithSeparator(input, fields, "分销标记:", "第三方单号:"); + extractFieldWithSeparator(input, fields, "第三方单号:", "下单链接(必须用这个):"); + extractFieldWithSeparator(input, fields, "下单链接(必须用这个):", "下单地址(注意带分机):"); + extractFieldWithSeparator(input, fields, "下单地址(注意带分机):", "型号:"); + extractFieldWithSeparator(input, fields, "型号:", "下单人(需填):"); + extractFieldWithSeparator(input, fields, "下单人(需填):", "下单付款(注意核对):"); + extractFieldWithSeparator(input, fields, "下单付款(注意核对):", "后返金额(注意核对):"); + extractFieldWithSeparator(input, fields, "后返金额(注意核对):", "订单号(需填):"); + extractFieldWithSeparator(input, fields, "订单号(需填):", "物流链接(需填):"); + extractFieldWithSeparator(input, fields, "物流链接(需填):", "备注(下单号码有变动/没法带分机号的写这里):"); + + // 手动提取"备注"字段(最后一个字段,可能后面有分隔线或"京粉实际价格") + java.util.regex.Pattern remarkPattern = java.util.regex.Pattern.compile("备注(下单号码有变动/没法带分机号的写这里):[\\s\\n]*([\\s\\S]*?)[\\s\\n]*(?=—————————|京粉实际价格|\\Z)", java.util.regex.Pattern.DOTALL); + java.util.regex.Matcher remarkMatcher = remarkPattern.matcher(input); + if (remarkMatcher.find()) { + String remarkValue = remarkMatcher.group(1); + if (remarkValue != null) { + remarkValue = remarkValue.trim(); + // 去掉可能的分隔线 + remarkValue = remarkValue.replaceAll("^—————————[\\s\\n]*", "").trim(); + if (!remarkValue.isEmpty()) { + fields.put("备注", remarkValue); + } + } + } + } + + // 解析旧格式(保持原有逻辑不变) + private void parseOldFormat(String input, Map fields) { + extractField(input, fields, "单:", "备注:"); + extractField(input, fields, "备注:", "分销标记:"); + + // 检查是否有"第三方单号:"字段 + boolean hasThirdPartyOrderNo = input.contains("第三方单号:"); + boolean hasJingfenPrice = input.contains("京粉实际价格:"); + + if (hasThirdPartyOrderNo) { + extractField(input, fields, "分销标记:", "第三方单号:"); + extractField(input, fields, "第三方单号:", "型号:"); + } else { + extractField(input, fields, "分销标记:", "型号:"); + } + + extractField(input, fields, "型号:", "链接:"); + extractField(input, fields, "链接:", "下单付款:"); + extractField(input, fields, "下单付款:", "后返金额:"); + extractField(input, fields, "后返金额:", "地址:"); + extractField(input, fields, "地址:", "物流链接:"); + extractField(input, fields, "物流链接:", "订单号:"); + extractField(input, fields, "订单号:", "下单人:"); + + if (hasJingfenPrice) { + extractField(input, fields, "下单人:", "京粉实际价格:"); + extractField(input, fields, "京粉实际价格:", ""); + } else { + extractField(input, fields, "下单人:", ""); + } + + // 使用正则提取下单人(兼容新旧格式) + String nextField = hasJingfenPrice ? "京粉实际价格:" : "单:"; + java.util.regex.Pattern buyerPattern = java.util.regex.Pattern.compile("下单人:\\s*(.*?)\\s*(?=" + nextField + "|\\Z)", java.util.regex.Pattern.DOTALL); + java.util.regex.Matcher buyerMatcher = buyerPattern.matcher(input); + if (buyerMatcher.find()) { + String buyer = buyerMatcher.group(1).trim(); + if (buyer.contains("\n")) { + buyer = buyer.split("\n")[0].trim(); + } + fields.put("下单人", buyer); + } + } + + // 提取字段的方法(支持分隔线,用于新格式) + private void extractFieldWithSeparator(String input, Map map, String startKeyword, String endKeyword) { + try { + String escapedStart = java.util.regex.Pattern.quote(startKeyword); + String escapedEnd = java.util.regex.Pattern.quote(endKeyword); + + // 匹配模式:startKeyword + 可选的空白和换行 + 字段值(非贪婪,支持多行) + 后面是换行+endKeyword或换行+分隔线或结束 + String patternStr = escapedStart + "[\\s\\n]*([\\s\\S]*?)(?=\\s*\\n?\\s*" + escapedEnd + "|\\s*\\n?\\s*—————————|\\Z)"; + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(patternStr, java.util.regex.Pattern.DOTALL); + java.util.regex.Matcher matcher = pattern.matcher(input); + + if (matcher.find()) { + String value = matcher.group(1); + if (value != null) { + value = value.trim(); + // 去掉可能的分隔线(在值的前后) + value = value.replaceAll("^—————————[\\s\\n]*", "").replaceAll("[\\s\\n]*—————————$", "").trim(); + // 去掉字段标签本身(如果被匹配到了) + value = value.replaceAll("^" + escapedStart, "").trim(); + // 保存字段值,使用去掉冒号的key + String key = startKeyword.replace(":", "").trim(); + if (!value.isEmpty()) { + map.put(key, value); + System.out.println(" ✓ 提取字段成功: " + key + " = " + (value.length() > 50 ? value.substring(0, 50) + "..." : value)); + } else { + System.out.println(" ✗ 字段值为空: " + key); + } + } else { + System.out.println(" ✗ 未找到字段值: " + startKeyword); + } + } else { + System.out.println(" ✗ 正则未匹配: " + startKeyword + " -> " + endKeyword); + } + } catch (Exception e) { + System.out.println(" ✗ 提取字段异常: " + startKeyword + " -> " + endKeyword + ", error: " + e.getMessage()); + e.printStackTrace(); + } + } private void extractField(String input, Map map, String startKeyword, String endKeyword) { // 如果结束关键词为空,匹配到字符串末尾