package com.ruoyi.ai.assistant; import com.ruoyi.ai.tools.FinancialAgentTools; 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 FinancialIntentExecutor { 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 static final Pattern FUTURE_MONTH_PATTERN = Pattern.compile("(?:未来|后续|接下来)\\s*(\\d{1,2})\\s*(?:个)?月"); private final FinancialAgentTools financialAgentTools; public FinancialIntentExecutor(FinancialAgentTools financialAgentTools) { this.financialAgentTools = financialAgentTools; } 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; } DateRange dateRange = extractDateRange(text); Integer limit = extractLimit(text); String keyword = extractKeyword(text); String startDate = dateRange.startDate(); String endDate = dateRange.endDate(); String timeRange = dateRange.label(); if (containsAny(text, "成本核算", "产品成本", "工序成本", "人工成本", "折旧", "材料损耗", "成本最高")) { return financialAgentTools.calculateIntelligentCost(memoryId, startDate, endDate, timeRange, keyword, limit); } if (containsAny(text, "利润分析", "订单利润", "亏损订单", "低利润", "最赚钱客户", "哪个客户最赚钱", "客户最赚钱", "利润最高客户", "利润贡献最高", "利润下降")) { return financialAgentTools.analyzeOrderProfit(memoryId, startDate, endDate, timeRange, keyword, limit); } if (containsAny(text, "库存资金", "库存积压", "呆滞库存", "资金占用", "周转率", "库存周转")) { return financialAgentTools.analyzeInventoryCapital(memoryId, startDate, endDate, timeRange, keyword, limit); } if (containsAny(text, "现金流", "回款风险", "付款压力", "资金缺口", "应收", "应付", "回款预测")) { return financialAgentTools.forecastCashFlow(memoryId, startDate, endDate, timeRange, extractForecastMonths(text)); } if (containsAny(text, "异常预警", "经营异常", "风险预警", "成本异常", "利润异常", "回款异常", "订单风险")) { return financialAgentTools.detectBusinessAnomalies(memoryId, startDate, endDate, timeRange, limit); } if (containsAny(text, "驾驶舱", "经营看板", "经营总览", "经营仪表盘", "经营大盘")) { return financialAgentTools.getBusinessCockpit(memoryId, startDate, endDate, timeRange); } if (containsAny(text, "日报", "周报", "经营报告", "分析报告")) { return financialAgentTools.generateOperationReport(memoryId, startDate, endDate, timeRange, containsAny(text, "周报") ? "weekly" : "daily"); } if (containsAny(text, "业财融合", "业财联动", "口径", "指标解释", "为什么")) { return financialAgentTools.retrieveFinancialKnowledge(memoryId, text); } return null; } private String tryExecuteQuickPrompt(String memoryId, String text) { String normalized = normalizeForMatch(text); if ("生成本周经营周报利润与现金流".equals(normalized) || "生成本周经营周报".equals(normalized) || "生成周报".equals(normalized)) { DateRange range = weekRange(); return financialAgentTools.generateOperationReport(memoryId, range.startDate(), range.endDate(), range.label(), "weekly"); } if ("分析本月利润下降原因".equals(normalized)) { DateRange range = monthRange(); return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); } if ("近30天哪个客户利润贡献最高".equals(normalized)) { DateRange range = recentDaysRange(30); return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); } if ("查看本月经营驾驶舱".equals(normalized) || "查看经营驾驶舱".equals(normalized)) { DateRange range = monthRange(); return financialAgentTools.getBusinessCockpit(memoryId, range.startDate(), range.endDate(), range.label()); } if ("查询近30天亏损订单".equals(normalized)) { DateRange range = recentDaysRange(30); return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); } if ("分析近30天库存资金占用".equals(normalized)) { DateRange range = recentDaysRange(30); return financialAgentTools.analyzeInventoryCapital(memoryId, range.startDate(), range.endDate(), range.label(), null, null); } if ("预测未来3个月现金流".equals(normalized)) { return financialAgentTools.forecastCashFlow(memoryId, null, null, null, 3); } if ("哪个工序成本最高".equals(normalized)) { return financialAgentTools.calculateIntelligentCost(memoryId, null, null, null, null, null); } return null; } private boolean containsAny(String text, String... keywords) { for (String keyword : keywords) { if (text.contains(keyword)) { return true; } } return false; } private Integer extractLimit(String text) { Matcher matcher = LIMIT_PATTERN.matcher(text); return matcher.find() ? Integer.parseInt(matcher.group(1)) : null; } private Integer extractForecastMonths(String text) { Matcher matcher = FUTURE_MONTH_PATTERN.matcher(text); return matcher.find() ? Integer.parseInt(matcher.group(1)) : null; } 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, first + "至" + second); } if (text.contains("本月")) { return monthRange(); } if (text.contains("上月")) { return lastMonthRange(); } if (text.contains("今年") || text.contains("本年")) { return yearRange(); } if (text.contains("本周")) { return weekRange(); } Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text); if (relativeDayMatcher.find()) { int days = Integer.parseInt(relativeDayMatcher.group(1)); return recentDaysRange(days); } return new DateRange(null, null, null); } private DateRange buildDateRange(String start, String end, String label) { LocalDate startDate = parseDate(start); LocalDate endDate = parseDate(end); if (startDate == null || endDate == null) { return new DateRange(null, null, null); } if (startDate.isAfter(endDate)) { LocalDate temp = startDate; startDate = endDate; endDate = temp; } return new DateRange(formatDate(startDate), formatDate(endDate), label); } 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), "近" + safeDays + "天"); } private DateRange monthRange() { LocalDate today = LocalDate.now(); return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today), "本月"); } private DateRange weekRange() { LocalDate today = LocalDate.now(); LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L); return new DateRange(formatDate(start), 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(":", "") .replace(":", "") .replace(";", "") .replace(";", "") .replace(" ", "") .trim(); } private String extractKeyword(String text) { String cleaned = text .replaceAll("\\d{4}-\\d{2}-\\d{2}", "") .replaceAll("(?:近|最近)\\s*\\d{1,3}\\s*天", "") .replaceAll("(?:前|最近|展示|返回)?\\s*\\d{1,2}\\s*(?:条|个|名)", "") .replace("查询", "") .replace("查看", "") .replace("看下", "") .replace("看看", "") .replace("帮我", "") .replace("请", "") .replace("一个", "") .replace("为什么", "") .replace("哪个客户最赚钱", "") .replace("最近哪个客户最赚钱", "") .replace("本月哪个客户最赚钱", "") .replace("近30天哪个客户最赚钱", "") .replace("最赚钱客户", "") .replace("客户最赚钱", "") .replace("哪个客户利润最高", "") .replace("利润最高客户", "") .replace("哪个客户利润贡献最高", "") .replace("利润贡献最高客户", "") .replace("本月", "") .replace("本周", "") .replace("本年", "") .replace("今年", "") .replace("上月", "") .replace("近30天", "") .replace("近7天", "") .replace("近90天", "") .replace("前10条", "") .replace("最近10条", "") .replace("前20条", "") .replace("最近20条", "") .replace("订单利润分析", "") .replace("利润分析", "") .replace("库存资金分析", "") .replace("现金流预测", "") .replace("经营驾驶舱", "") .replace("日报", "") .replace("周报", "") .replace("异常预警", "") .replace("条", "") .trim(); return cleaned.length() >= 2 ? cleaned : null; } private record DateRange(String startDate, String endDate, String label) { } }