From 8b5abb44ee6f91c3a353ca13af206ae09fed2be3 Mon Sep 17 00:00:00 2001 From: van Date: Tue, 5 May 2026 14:58:52 +0800 Subject: [PATCH] 1 --- .../jarvis/InstructionController.java | 4 +- .../jarvis/service/IInstructionService.java | 8 +- .../service/impl/InstructionServiceImpl.java | 122 +++++++++++++++--- .../service/impl/WeComInboundServiceImpl.java | 2 +- 4 files changed, 113 insertions(+), 23 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/InstructionController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/InstructionController.java index 98b9d1a..1dabc79 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/InstructionController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/InstructionController.java @@ -28,8 +28,8 @@ public class InstructionController extends BaseController { public AjaxResult execute(@RequestBody Map body) { String cmd = body != null ? (body.get("command") != null ? String.valueOf(body.get("command")) : null) : null; boolean forceGenerate = body != null && body.get("forceGenerate") != null && Boolean.parseBoolean(String.valueOf(body.get("forceGenerate"))); - // 控制台入口,传递 isFromConsole=true,跳过订单查询校验 - java.util.List result = instructionService.execute(cmd, forceGenerate, true); + // 控制台入口:全量统计视角(排除后台标记不参与统计的联盟),非单个企微成员 + java.util.List result = instructionService.execute(cmd, forceGenerate, true, null); return AjaxResult.success(result); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IInstructionService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IInstructionService.java index af01765..bdc9421 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IInstructionService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IInstructionService.java @@ -27,7 +27,13 @@ public interface IInstructionService { * @return 执行结果文本列表(可能为单条或多条) */ java.util.List execute(String command, boolean forceGenerate, boolean isFromConsole); - + + /** + * 执行文本指令(支持传入企微成员 UserID,用于「京」统计按绑定联盟过滤) + * @param wecomUserId 企业微信成员 UserID;控制台等非企微入口传 null(按全局规则统计) + */ + java.util.List execute(String command, boolean forceGenerate, boolean isFromConsole, String wecomUserId); + /** * 获取历史消息记录 * @param type 消息类型:request(请求) 或 response(响应) 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 c8a4f2a..8340437 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 @@ -2,6 +2,7 @@ package com.ruoyi.jarvis.service.impl; import com.ruoyi.jarvis.domain.OrderRows; import com.ruoyi.jarvis.domain.JDOrder; +import com.ruoyi.jarvis.domain.SuperAdmin; import com.ruoyi.jarvis.domain.WeComShareLinkLogisticsJob; import com.ruoyi.jarvis.service.IInstructionService; import com.ruoyi.jarvis.service.IOrderRowsService; @@ -61,6 +62,9 @@ public class InstructionServiceImpl implements IInstructionService { @Autowired(required = false) private com.ruoyi.jarvis.service.ITencentDocDelayedPushService tencentDocDelayedPushService; + /** 与 {@link com.ruoyi.jarvis.service.impl.WeComInboundServiceImpl#WE_COM_SUPER_USER_ID} 一致:该账号在京统计中视为全局视角 */ + private static final String WE_COM_SUPER_GLOBAL_STATS_USER = "LinPingFan"; + /** 与企微物流分享链解析一致 */ private static final Pattern JD_3CN = Pattern.compile("https://3\\.cn/[A-Za-z0-9\\-]+"); @@ -82,6 +86,11 @@ public class InstructionServiceImpl implements IInstructionService { @Override public List execute(String command, boolean forceGenerate, boolean isFromConsole) { + return execute(command, forceGenerate, isFromConsole, null); + } + + @Override + public List execute(String command, boolean forceGenerate, boolean isFromConsole, String wecomUserId) { // 存储接收的消息到Redis队列 storeMessageToRedis("instruction:request", command); @@ -99,7 +108,7 @@ public class InstructionServiceImpl implements IInstructionService { // 一级命令分流:京系(统计/订单)、录单/慢单、转链/礼金… if (input.startsWith("京") || menuKeywords().contains(input)) { - result = Collections.singletonList(handleJingFen(input.replaceFirst("^京", ""))); + result = Collections.singletonList(handleJingFen(input.replaceFirst("^京", ""), wecomUserId)); } // TF/H/生/拼多多 生成类指令 else if (input.startsWith("TF")) { @@ -130,6 +139,77 @@ public class InstructionServiceImpl implements IInstructionService { return result; } + /** + * 「京」统计/订单所用京粉订单数据源:企微成员按超级管理员绑定 unionId;全局视角排除「不参与订单统计」联盟。 + */ + private static final class JingStatsScope { + private final List rows; + /** 可为 null:禁止访问统计(不参与统计等) */ + private final String denyMessage; + /** 回复前缀,标明当前统计归属 */ + private final String replyPrefix; + + private JingStatsScope(List rows, String denyMessage, String replyPrefix) { + this.rows = rows != null ? rows : Collections.emptyList(); + this.denyMessage = denyMessage; + this.replyPrefix = replyPrefix != null ? replyPrefix : ""; + } + + static JingStatsScope denied(String msg) { + return new JingStatsScope(Collections.emptyList(), msg, ""); + } + + static JingStatsScope ok(List rows, String replyPrefix) { + return new JingStatsScope(rows, null, replyPrefix); + } + } + + private List buildExcludeUnionIdsForStats() { + List excludeUnionIds = new ArrayList<>(); + List superAdminList = superAdminService.selectSuperAdminList(null); + if (superAdminList != null) { + for (SuperAdmin admin : superAdminList) { + if (admin.getIsCount() != null && admin.getIsCount() == 0 && admin.getUnionId() != null && !admin.getUnionId().trim().isEmpty()) { + try { + excludeUnionIds.add(Long.parseLong(admin.getUnionId().trim())); + } catch (NumberFormatException ignored) { + } + } + } + } + return excludeUnionIds; + } + + private JingStatsScope resolveJingStatsScope(String wecomUserId) { + if (wecomUserId == null || wecomUserId.trim().isEmpty() + || WE_COM_SUPER_GLOBAL_STATS_USER.equals(wecomUserId.trim())) { + List all = orderRowsService.selectOrderRowsListWithFilter(new OrderRows(), null, null, buildExcludeUnionIdsForStats()); + return JingStatsScope.ok(all, ""); + } + String wxUser = wecomUserId.trim(); + SuperAdmin sa = superAdminService.selectSuperAdminByWecomUserId(wxUser); + if (sa == null) { + return JingStatsScope.ok(Collections.emptyList(), ""); + } + if (sa.getIsCount() != null && sa.getIsCount() == 0) { + return JingStatsScope.denied("「京统计」\n\n当前企微账号在后台「超级管理员」中标记为不参与订单统计,无法使用统计与订单类京指令。\n如需开通请联系管理员。"); + } + if (sa.getUnionId() == null || sa.getUnionId().trim().isEmpty()) { + return JingStatsScope.denied("「京统计」\n\n当前企微账号未绑定联盟ID,无法匹配京粉订单。\n请在后台「超级管理员」中维护该账号对应行的联盟ID。"); + } + try { + long uid = Long.parseLong(sa.getUnionId().trim()); + OrderRows probe = new OrderRows(); + probe.setUnionId(uid); + List scoped = orderRowsService.selectOrderRowsListWithFilter(probe, null, null, Collections.emptyList()); + String namePart = sa.getName() != null && !sa.getName().trim().isEmpty() ? sa.getName().trim() : "未命名"; + String prefix = "【联盟 " + sa.getUnionId().trim() + " · " + namePart + "】\n"; + return JingStatsScope.ok(scoped, prefix); + } catch (NumberFormatException e) { + return JingStatsScope.denied("「京统计」\n\n联盟ID格式不正确,请联系管理员检查「超级管理员」配置。"); + } + } + /** * 将消息存储到Redis队列,最多保留100条 * @param key Redis键 @@ -202,7 +282,7 @@ public class InstructionServiceImpl implements IInstructionService { return new HashSet<>(Arrays.asList("菜单", "今日统计", "昨日统计", "三日统计", "七日统计", "一个月统计", "两个月统计", "三个月统计", "这个月统计", "上个月统计", "今日订单", "昨日订单", "七日订单", "总统计")); } - private String handleJingFen(String cmd) { + private String handleJingFen(String cmd, String wecomUserId) { String action = cmd.trim(); if (action.isEmpty() || action.equals("菜单")) { return jingMenu(); @@ -217,37 +297,40 @@ public class InstructionServiceImpl implements IInstructionService { return textExternalShareLinkLogisticsDelete(rest); } - // 取出所有订单(排除被删除/无效:这里沿用 OrderRowsService 的常规查询,必要时可增加过滤参数) - List all = orderRowsService.selectOrderRowsList(new OrderRows()); - if (all == null) all = Collections.emptyList(); + JingStatsScope scope = resolveJingStatsScope(wecomUserId); + if (scope.denyMessage != null) { + return scope.denyMessage; + } + List all = scope.rows; + String header = scope.replyPrefix; switch (action) { case "今日统计": - return statsText(filterByDays(all, 0), "今日统计"); + return header + statsText(filterByDays(all, 0), "今日统计"); case "昨日统计": - return statsText(filterYesterday(all), "昨日统计"); + return header + statsText(filterYesterday(all), "昨日统计"); case "三日统计": - return statsText(filterByRange(all, 3), "三日统计"); + return header + statsText(filterByRange(all, 3), "三日统计"); case "七日统计": - return statsText(filterByRange(all, 7), "七日统计"); + return header + statsText(filterByRange(all, 7), "七日统计"); case "一个月统计": - return statsText(filterByRange(all, 30), "一个月统计"); + return header + statsText(filterByRange(all, 30), "一个月统计"); case "两个月统计": - return statsText(filterByRange(all, 60), "两个月统计"); + return header + statsText(filterByRange(all, 60), "两个月统计"); case "三个月统计": - return statsText(filterByRange(all, 90), "三个月统计"); + return header + statsText(filterByRange(all, 90), "三个月统计"); case "这个月统计": - return statsText(filterThisMonth(all), "这个月统计"); + return header + statsText(filterThisMonth(all), "这个月统计"); case "上个月统计": - return statsText(filterLastMonth(all), "上个月统计"); + return header + statsText(filterLastMonth(all), "上个月统计"); case "总统计": - return statsText(all, "总统计"); + return header + statsText(all, "总统计"); case "今日订单": - return listOrders(filterByDays(all, 0), "今日订单"); + return header + listOrders(filterByDays(all, 0), "今日订单"); case "昨日订单": - return listOrders(filterYesterday(all), "昨日订单"); + return header + listOrders(filterYesterday(all), "昨日订单"); case "七日订单": - return listOrders(filterByRange(all, 7), "七日订单"); + return header + listOrders(filterByRange(all, 7), "七日订单"); default: // 高级命令:违规N、SKU、搜索、JF… 此处按需扩展 if (action.startsWith("高级")) { @@ -2338,7 +2421,8 @@ public class InstructionServiceImpl implements IInstructionService { // ===== 工具 ===== private String jingMenu() { return "「京粉 · 菜单」\n\n" - + "企微/机器人前请加「京」,例如:京今日统计\n\n" + + "企微/机器人前请加「京」,例如:京今日统计\n" + + "说明:企微内统计仅含当前账号在「超级管理员」绑定的联盟ID;标记为不参与订单统计的联盟不会在全局汇总中出现(与后台京粉订单列表统计一致)。\n\n" + "—— 统计 ——\n" + "今日统计、昨日统计、三日统计、七日统计\n" + "一个月统计、两个月统计、三个月统计\n" diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WeComInboundServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WeComInboundServiceImpl.java index f1627d8..973ed3f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WeComInboundServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WeComInboundServiceImpl.java @@ -173,7 +173,7 @@ public class WeComInboundServiceImpl implements IWeComInboundService { } } - List parts = instructionService.execute(content, false, isSuper); + List parts = instructionService.execute(content, false, isSuper, from); if (parts == null || parts.isEmpty()) { return WeComInboundResult.empty(); }