package com.ruoyi.ai.assistant; import com.ruoyi.ai.tools.SalesAgentTools; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.time.LocalDate; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.regex.Matcher; import java.util.regex.Pattern; @Component public class SalesIntentExecutor { private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final Pattern LIMIT_PATTERN = Pattern.compile("(前|最近)?\\s*(\\d{1,2})\\s*条"); private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})"); private static final Pattern RELATIVE_DAY_PATTERN = Pattern.compile("(近|最近)?\\s*(\\d{1,3})\\s*天"); private final SalesAgentTools salesAgentTools; public SalesIntentExecutor(SalesAgentTools salesAgentTools) { this.salesAgentTools = salesAgentTools; } public String tryExecute(String memoryId, String message) { if (!StringUtils.hasText(message)) { return null; } String text = message.trim(); String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text); if (StringUtils.hasText(quickPromptResponse)) { return quickPromptResponse; } String keyword = extractKeyword(text); Integer limit = extractLimit(text); DateRange dateRange = extractDateRange(text); String startDate = dateRange.startDate(); String endDate = dateRange.endDate(); if (containsAny(text, "流失", "流失风险", "客户流失", "风险分析")) { return salesAgentTools.analyzeCustomerChurnRisk(memoryId, startDate, endDate, text, keyword, limit); } if (containsAny(text, "回款", "收款", "报价") && containsAny(text, "建议", "策略", "优化", "方案")) { return salesAgentTools.suggestCollectionAndQuotationStrategy( memoryId, startDate, endDate, text, keyword, limit, shouldPrioritizeHighRisk(text)); } if (containsAny(text, "指标", "统计", "看板", "总览", "经营分析")) { return salesAgentTools.getSalesDashboard(memoryId, startDate, endDate, text); } if (containsAny(text, "客户档案", "私海", "公海", "客户池")) { return salesAgentTools.listCustomerProfiles(memoryId, extractSeaType(text), keyword, limit); } if (containsAny(text, "销售报价", "报价单", "报价", "询价")) { return salesAgentTools.listSalesQuotations(memoryId, keyword, startDate, endDate, limit); } if (containsAny(text, "销售退货", "退货", "退款")) { return salesAgentTools.listSalesReturns(memoryId, startDate, endDate, keyword, limit); } if (containsAny(text, "客户往来", "往来", "回款", "应收", "来款", "收款明细")) { return salesAgentTools.listCustomerInteractions(memoryId, keyword, startDate, endDate, limit); } if (containsAny(text, "发货台账", "发货", "物流", "快递", "运输")) { return salesAgentTools.listShippingLedgers(memoryId, keyword, startDate, endDate, limit); } if (containsAny(text, "销售台账", "销售合同", "销售订单", "合同台账", "订单台账")) { return salesAgentTools.listSalesLedgers(memoryId, keyword, startDate, endDate, limit); } return null; } private String tryExecuteQuickPrompt(String memoryId, String text) { String normalized = normalizeForMatch(text); if ("查询私海客户档案前10条".equals(normalized)) { return salesAgentTools.listCustomerProfiles(memoryId, "private", null, 10); } if ("查询公海客户档案".equals(normalized)) { return salesAgentTools.listCustomerProfiles(memoryId, "public", null, 10); } if ("查询本月销售报价".equals(normalized)) { DateRange range = monthRange(); return salesAgentTools.listSalesQuotations(memoryId, null, range.startDate(), range.endDate(), 10); } if ("查询本月销售台账".equals(normalized)) { DateRange range = monthRange(); return salesAgentTools.listSalesLedgers(memoryId, null, range.startDate(), range.endDate(), 10); } if ("查询近30天销售退货".equals(normalized)) { DateRange range = recentDaysRange(30); return salesAgentTools.listSalesReturns(memoryId, range.startDate(), range.endDate(), null, 10); } if ("查询近30天客户回款往来".equals(normalized)) { DateRange range = recentDaysRange(30); return salesAgentTools.listCustomerInteractions(memoryId, null, range.startDate(), range.endDate(), 10); } if ("查询本月发货台账".equals(normalized)) { DateRange range = monthRange(); return salesAgentTools.listShippingLedgers(memoryId, null, range.startDate(), range.endDate(), 10); } if ("查看销售指标统计".equals(normalized)) { return salesAgentTools.getSalesDashboard(memoryId, null, null, "本月"); } if ("帮我做客户流失风险分析近30天前20条".equals(normalized)) { DateRange range = recentDaysRange(30); return salesAgentTools.analyzeCustomerChurnRisk(memoryId, range.startDate(), range.endDate(), "近30天", null, 20); } if ("生成回款与报价策略建议优先高风险客户".equals(normalized)) { DateRange range = recentDaysRange(30); return salesAgentTools.suggestCollectionAndQuotationStrategy(memoryId, range.startDate(), range.endDate(), "近30天", null, 10, true); } return null; } private boolean containsAny(String text, String... keywords) { for (String keyword : keywords) { if (text.contains(keyword)) { return true; } } return false; } private String extractSeaType(String text) { if (text.contains("公海")) { return "public"; } if (text.contains("私海")) { return "private"; } return null; } private Integer extractLimit(String text) { Matcher matcher = LIMIT_PATTERN.matcher(text); return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10; } private DateRange extractDateRange(String text) { Matcher matcher = DATE_PATTERN.matcher(text); if (matcher.find()) { String first = matcher.group(1); String second = matcher.find() ? matcher.group(1) : first; return buildDateRange(first, second); } if (text.contains("本月")) { return monthRange(); } if (text.contains("上月")) { return lastMonthRange(); } if (text.contains("本年") || text.contains("今年")) { return yearRange(); } Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text); if (relativeDayMatcher.find()) { int days = Integer.parseInt(relativeDayMatcher.group(2)); return recentDaysRange(days); } return new DateRange(null, null); } private DateRange buildDateRange(String start, String end) { LocalDate startDate = parseDate(start); LocalDate endDate = parseDate(end); if (startDate == null || endDate == null) { return new DateRange(null, null); } if (startDate.isAfter(endDate)) { LocalDate temp = startDate; startDate = endDate; endDate = temp; } return new DateRange(formatDate(startDate), formatDate(endDate)); } private DateRange recentDaysRange(int days) { LocalDate end = LocalDate.now(); int safeDays = Math.max(days, 1); LocalDate start = end.minusDays(safeDays - 1L); return new DateRange(formatDate(start), formatDate(end)); } private DateRange monthRange() { LocalDate today = LocalDate.now(); return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today)); } private DateRange lastMonthRange() { YearMonth lastMonth = YearMonth.now().minusMonths(1); return new DateRange(formatDate(lastMonth.atDay(1)), formatDate(lastMonth.atEndOfMonth())); } private DateRange yearRange() { LocalDate today = LocalDate.now(); return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today)); } private LocalDate parseDate(String text) { try { return LocalDate.parse(text, DATE_FMT); } catch (Exception ignored) { return null; } } private String formatDate(LocalDate date) { return date == null ? null : date.format(DATE_FMT); } private String normalizeForMatch(String text) { if (!StringUtils.hasText(text)) { return ""; } return text.replace(",", "") .replace(",", "") .replace("。", "") .replace(".", "") .replace("!", "") .replace("!", "") .replace("?", "") .replace("?", "") .replace(":", "") .replace(":", "") .replace(";", "") .replace(";", "") .replace(" ", "") .trim(); } private Boolean shouldPrioritizeHighRisk(String text) { return containsAny(text, "优先高风险", "高风险客户", "高风险"); } private String extractKeyword(String text) { String cleaned = text .replace("查询", "") .replace("查看", "") .replace("看下", "") .replace("看看", "") .replace("帮我", "") .replace("请", "") .replace("一下", "") .replace("销售", "") .replace("客户档案", "") .replace("报价单", "") .replace("销售报价", "") .replace("销售台账", "") .replace("发货台账", "") .replace("客户往来", "") .replace("销售退货", "") .replace("前10条", "") .replace("最近10条", "") .replace("前20条", "") .replace("最近20条", "") .replace("近30天", "") .replace("本月", "") .replace("本年", "") .replace("今年", "") .replace("条", "") .trim(); return cleaned.length() >= 2 ? cleaned : null; } private record DateRange(String startDate, String endDate) { } }