This commit is contained in:
van
2026-05-05 14:58:52 +08:00
parent e75f71d37b
commit 8b5abb44ee
4 changed files with 113 additions and 23 deletions

View File

@@ -28,8 +28,8 @@ public class InstructionController extends BaseController {
public AjaxResult execute(@RequestBody Map<String, Object> 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<String> result = instructionService.execute(cmd, forceGenerate, true);
// 控制台入口:全量统计视角(排除后台标记不参与统计的联盟),非单个企微成员
java.util.List<String> result = instructionService.execute(cmd, forceGenerate, true, null);
return AjaxResult.success(result);
}

View File

@@ -28,6 +28,12 @@ public interface IInstructionService {
*/
java.util.List<String> execute(String command, boolean forceGenerate, boolean isFromConsole);
/**
* 执行文本指令(支持传入企微成员 UserID用于「京」统计按绑定联盟过滤
* @param wecomUserId 企业微信成员 UserID控制台等非企微入口传 null按全局规则统计
*/
java.util.List<String> execute(String command, boolean forceGenerate, boolean isFromConsole, String wecomUserId);
/**
* 获取历史消息记录
* @param type 消息类型request(请求) 或 response(响应)

View File

@@ -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<String> execute(String command, boolean forceGenerate, boolean isFromConsole) {
return execute(command, forceGenerate, isFromConsole, null);
}
@Override
public List<String> 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<OrderRows> rows;
/** 可为 null禁止访问统计不参与统计等 */
private final String denyMessage;
/** 回复前缀,标明当前统计归属 */
private final String replyPrefix;
private JingStatsScope(List<OrderRows> 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<OrderRows> rows, String replyPrefix) {
return new JingStatsScope(rows, null, replyPrefix);
}
}
private List<Long> buildExcludeUnionIdsForStats() {
List<Long> excludeUnionIds = new ArrayList<>();
List<SuperAdmin> 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<OrderRows> 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<OrderRows> 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<OrderRows> all = orderRowsService.selectOrderRowsList(new OrderRows());
if (all == null) all = Collections.emptyList();
JingStatsScope scope = resolveJingStatsScope(wecomUserId);
if (scope.denyMessage != null) {
return scope.denyMessage;
}
List<OrderRows> 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"

View File

@@ -173,7 +173,7 @@ public class WeComInboundServiceImpl implements IWeComInboundService {
}
}
List<String> parts = instructionService.execute(content, false, isSuper);
List<String> parts = instructionService.execute(content, false, isSuper, from);
if (parts == null || parts.isEmpty()) {
return WeComInboundResult.empty();
}