1
This commit is contained in:
@@ -28,8 +28,8 @@ public class InstructionController extends BaseController {
|
|||||||
public AjaxResult execute(@RequestBody Map<String, Object> body) {
|
public AjaxResult execute(@RequestBody Map<String, Object> body) {
|
||||||
String cmd = body != null ? (body.get("command") != null ? String.valueOf(body.get("command")) : null) : null;
|
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")));
|
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);
|
return AjaxResult.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,13 @@ public interface IInstructionService {
|
|||||||
* @return 执行结果文本列表(可能为单条或多条)
|
* @return 执行结果文本列表(可能为单条或多条)
|
||||||
*/
|
*/
|
||||||
java.util.List<String> execute(String command, boolean forceGenerate, boolean isFromConsole);
|
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(响应)
|
* @param type 消息类型:request(请求) 或 response(响应)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ruoyi.jarvis.service.impl;
|
|||||||
|
|
||||||
import com.ruoyi.jarvis.domain.OrderRows;
|
import com.ruoyi.jarvis.domain.OrderRows;
|
||||||
import com.ruoyi.jarvis.domain.JDOrder;
|
import com.ruoyi.jarvis.domain.JDOrder;
|
||||||
|
import com.ruoyi.jarvis.domain.SuperAdmin;
|
||||||
import com.ruoyi.jarvis.domain.WeComShareLinkLogisticsJob;
|
import com.ruoyi.jarvis.domain.WeComShareLinkLogisticsJob;
|
||||||
import com.ruoyi.jarvis.service.IInstructionService;
|
import com.ruoyi.jarvis.service.IInstructionService;
|
||||||
import com.ruoyi.jarvis.service.IOrderRowsService;
|
import com.ruoyi.jarvis.service.IOrderRowsService;
|
||||||
@@ -61,6 +62,9 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private com.ruoyi.jarvis.service.ITencentDocDelayedPushService tencentDocDelayedPushService;
|
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\\-]+");
|
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
|
@Override
|
||||||
public List<String> execute(String command, boolean forceGenerate, boolean isFromConsole) {
|
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队列
|
// 存储接收的消息到Redis队列
|
||||||
storeMessageToRedis("instruction:request", command);
|
storeMessageToRedis("instruction:request", command);
|
||||||
|
|
||||||
@@ -99,7 +108,7 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
|
|
||||||
// 一级命令分流:京系(统计/订单)、录单/慢单、转链/礼金…
|
// 一级命令分流:京系(统计/订单)、录单/慢单、转链/礼金…
|
||||||
if (input.startsWith("京") || menuKeywords().contains(input)) {
|
if (input.startsWith("京") || menuKeywords().contains(input)) {
|
||||||
result = Collections.singletonList(handleJingFen(input.replaceFirst("^京", "")));
|
result = Collections.singletonList(handleJingFen(input.replaceFirst("^京", ""), wecomUserId));
|
||||||
}
|
}
|
||||||
// TF/H/生/拼多多 生成类指令
|
// TF/H/生/拼多多 生成类指令
|
||||||
else if (input.startsWith("TF")) {
|
else if (input.startsWith("TF")) {
|
||||||
@@ -130,6 +139,77 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
return result;
|
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条
|
* 将消息存储到Redis队列,最多保留100条
|
||||||
* @param key Redis键
|
* @param key Redis键
|
||||||
@@ -202,7 +282,7 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
return new HashSet<>(Arrays.asList("菜单", "今日统计", "昨日统计", "三日统计", "七日统计", "一个月统计", "两个月统计", "三个月统计", "这个月统计", "上个月统计", "今日订单", "昨日订单", "七日订单", "总统计"));
|
return new HashSet<>(Arrays.asList("菜单", "今日统计", "昨日统计", "三日统计", "七日统计", "一个月统计", "两个月统计", "三个月统计", "这个月统计", "上个月统计", "今日订单", "昨日订单", "七日订单", "总统计"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String handleJingFen(String cmd) {
|
private String handleJingFen(String cmd, String wecomUserId) {
|
||||||
String action = cmd.trim();
|
String action = cmd.trim();
|
||||||
if (action.isEmpty() || action.equals("菜单")) {
|
if (action.isEmpty() || action.equals("菜单")) {
|
||||||
return jingMenu();
|
return jingMenu();
|
||||||
@@ -217,37 +297,40 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
return textExternalShareLinkLogisticsDelete(rest);
|
return textExternalShareLinkLogisticsDelete(rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取出所有订单(排除被删除/无效:这里沿用 OrderRowsService 的常规查询,必要时可增加过滤参数)
|
JingStatsScope scope = resolveJingStatsScope(wecomUserId);
|
||||||
List<OrderRows> all = orderRowsService.selectOrderRowsList(new OrderRows());
|
if (scope.denyMessage != null) {
|
||||||
if (all == null) all = Collections.emptyList();
|
return scope.denyMessage;
|
||||||
|
}
|
||||||
|
List<OrderRows> all = scope.rows;
|
||||||
|
String header = scope.replyPrefix;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "今日统计":
|
case "今日统计":
|
||||||
return statsText(filterByDays(all, 0), "今日统计");
|
return header + statsText(filterByDays(all, 0), "今日统计");
|
||||||
case "昨日统计":
|
case "昨日统计":
|
||||||
return statsText(filterYesterday(all), "昨日统计");
|
return header + statsText(filterYesterday(all), "昨日统计");
|
||||||
case "三日统计":
|
case "三日统计":
|
||||||
return statsText(filterByRange(all, 3), "三日统计");
|
return header + statsText(filterByRange(all, 3), "三日统计");
|
||||||
case "七日统计":
|
case "七日统计":
|
||||||
return statsText(filterByRange(all, 7), "七日统计");
|
return header + statsText(filterByRange(all, 7), "七日统计");
|
||||||
case "一个月统计":
|
case "一个月统计":
|
||||||
return statsText(filterByRange(all, 30), "一个月统计");
|
return header + statsText(filterByRange(all, 30), "一个月统计");
|
||||||
case "两个月统计":
|
case "两个月统计":
|
||||||
return statsText(filterByRange(all, 60), "两个月统计");
|
return header + statsText(filterByRange(all, 60), "两个月统计");
|
||||||
case "三个月统计":
|
case "三个月统计":
|
||||||
return statsText(filterByRange(all, 90), "三个月统计");
|
return header + statsText(filterByRange(all, 90), "三个月统计");
|
||||||
case "这个月统计":
|
case "这个月统计":
|
||||||
return statsText(filterThisMonth(all), "这个月统计");
|
return header + statsText(filterThisMonth(all), "这个月统计");
|
||||||
case "上个月统计":
|
case "上个月统计":
|
||||||
return statsText(filterLastMonth(all), "上个月统计");
|
return header + statsText(filterLastMonth(all), "上个月统计");
|
||||||
case "总统计":
|
case "总统计":
|
||||||
return statsText(all, "总统计");
|
return header + statsText(all, "总统计");
|
||||||
case "今日订单":
|
case "今日订单":
|
||||||
return listOrders(filterByDays(all, 0), "今日订单");
|
return header + listOrders(filterByDays(all, 0), "今日订单");
|
||||||
case "昨日订单":
|
case "昨日订单":
|
||||||
return listOrders(filterYesterday(all), "昨日订单");
|
return header + listOrders(filterYesterday(all), "昨日订单");
|
||||||
case "七日订单":
|
case "七日订单":
|
||||||
return listOrders(filterByRange(all, 7), "七日订单");
|
return header + listOrders(filterByRange(all, 7), "七日订单");
|
||||||
default:
|
default:
|
||||||
// 高级命令:违规N、SKU、搜索、JF… 此处按需扩展
|
// 高级命令:违规N、SKU、搜索、JF… 此处按需扩展
|
||||||
if (action.startsWith("高级")) {
|
if (action.startsWith("高级")) {
|
||||||
@@ -2338,7 +2421,8 @@ public class InstructionServiceImpl implements IInstructionService {
|
|||||||
// ===== 工具 =====
|
// ===== 工具 =====
|
||||||
private String jingMenu() {
|
private String jingMenu() {
|
||||||
return "「京粉 · 菜单」\n\n"
|
return "「京粉 · 菜单」\n\n"
|
||||||
+ "企微/机器人前请加「京」,例如:京今日统计\n\n"
|
+ "企微/机器人前请加「京」,例如:京今日统计\n"
|
||||||
|
+ "说明:企微内统计仅含当前账号在「超级管理员」绑定的联盟ID;标记为不参与订单统计的联盟不会在全局汇总中出现(与后台京粉订单列表统计一致)。\n\n"
|
||||||
+ "—— 统计 ——\n"
|
+ "—— 统计 ——\n"
|
||||||
+ "今日统计、昨日统计、三日统计、七日统计\n"
|
+ "今日统计、昨日统计、三日统计、七日统计\n"
|
||||||
+ "一个月统计、两个月统计、三个月统计\n"
|
+ "一个月统计、两个月统计、三个月统计\n"
|
||||||
|
|||||||
@@ -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()) {
|
if (parts == null || parts.isEmpty()) {
|
||||||
return WeComInboundResult.empty();
|
return WeComInboundResult.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user