This commit is contained in:
van
2026-05-06 17:38:58 +08:00
parent 9d03cca517
commit 7582868b2c
4 changed files with 303 additions and 62 deletions

View File

@@ -110,22 +110,17 @@ public class WxSendGoofishNotifyClient {
}
}
/**
* 企微短通知:场景标题 + 订单号 + 必要字段行(不再展示数据来源等冗长前缀)。
*/
private static String buildContent(String orderNo, String eventType, String source, String message) {
String on = orderNo != null ? orderNo : "-";
String head = resolveNotifyHeadline(eventType, message);
String detail = normalizeNotifyDetailLines(eventType, message);
StringBuilder sb = new StringBuilder();
sb.append("【闲鱼订单】").append(orderNo != null ? orderNo : "-").append("\n");
String typeLabel = humanEventType(eventType);
String srcLabel = humanSource(source);
if (StringUtils.hasText(typeLabel)) {
sb.append(typeLabel);
if (StringUtils.hasText(srcLabel)) {
sb.append(" · ").append(srcLabel);
}
} else if (StringUtils.hasText(srcLabel)) {
sb.append(srcLabel);
}
sb.append("\n");
if (StringUtils.hasText(message)) {
sb.append(message);
sb.append(head).append("\n订单号").append(on).append('\n');
if (StringUtils.hasText(detail)) {
sb.append(detail);
}
String s = sb.toString();
if (s.length() > CONTENT_MAX) {
@@ -134,48 +129,221 @@ public class WxSendGoofishNotifyClient {
return s;
}
/** 企微展示用,与库内 event_type 枚举一致 */
private static String humanEventType(String eventType) {
if (!StringUtils.hasText(eventType)) {
return "";
private static String resolveNotifyHeadline(String eventType, String message) {
String m = message != null ? message : "";
String t = eventType != null ? eventType.trim() : "";
if ("SHIP".equals(t)) {
if (m.contains("失败") || m.contains("异常") || m.contains("缺地址")) {
return "发货失败";
}
return "发货";
}
switch (eventType.trim()) {
case "ORDER_SYNC":
return "订单同步";
case "LOGISTICS_SYNC":
return "物流同步";
case "SHIP":
return "发货";
default:
return eventType.trim();
if ("LOGISTICS_SYNC".equals(t)) {
return "物流";
}
if ("ORDER_SYNC".equals(t)) {
if (m.startsWith("新订单") || m.contains("新订单入库")) {
return "新订单";
}
if (looksRefundOnlyDiffLine(m)) {
return "退款";
}
return "订单";
}
return StringUtils.hasText(t) ? t : "订单";
}
/** 企微展示用,与库内 source 一致 */
private static String humanSource(String source) {
if (!StringUtils.hasText(source)) {
/** ORDER_SYNC 正文里是否仅有退款状态变更(单行或多行中的唯一语义块) */
private static boolean looksRefundOnlyDiffLine(String message) {
if (!StringUtils.hasText(message) || message.contains("新订单")) {
return false;
}
String normalized = message.replace('', '\n').trim();
String[] lines = normalized.split("\n");
boolean sawRefund = false;
boolean sawOrder = false;
for (String raw : lines) {
String line = raw.trim();
if (line.isEmpty()) {
continue;
}
if (line.startsWith("退款状态")) {
sawRefund = true;
continue;
}
if (line.startsWith("订单状态")) {
sawOrder = true;
continue;
}
return false;
}
return sawRefund && !sawOrder;
}
/**
* 将内部摘要句转为「字段:值」行;箭头统一为「 → 」。
*/
private static String normalizeNotifyDetailLines(String eventType, String message) {
if (!StringUtils.hasText(message)) {
return "";
}
switch (source.trim()) {
case "LIST_UPSERT":
return "列表拉单写入";
case "NOTIFY_UPSERT":
return "推送回调写入";
case "LIST":
return "列表摘要";
case "DETAIL_REFRESH":
return "详情刷新";
case "NOTIFY":
return "推送";
case "REDIS_WAYBILL":
return "Redis 运单";
case "AUTO_SHIP":
return "自动发货";
case "JD_LOGISTICS_PUSH":
return "京东物流扫描";
default:
return source.trim();
String t = eventType != null ? eventType.trim() : "";
String m = message.trim();
if ("SHIP".equals(t)) {
if (m.startsWith("发货成功")) {
StringBuilder details = new StringBuilder();
String wb = extractCommaField(m, "运单 ");
if (StringUtils.hasText(wb)) {
details.append("物流单号:").append(normalizeArrowSpaces(wb)).append('\n');
}
String os = extractCommaField(m, "订单状态 ");
if (StringUtils.hasText(os)) {
details.append("订单状态:").append(normalizeArrowSpaces(os)).append('\n');
}
String rs = extractCommaField(m, "退款状态 ");
if (StringUtils.hasText(rs)) {
details.append("退款状态:").append(normalizeArrowSpaces(rs)).append('\n');
}
if (details.length() > 0) {
return details.toString();
}
}
if (m.startsWith("发货失败") || m.startsWith("发货异常")) {
int idx = m.indexOf('');
String reason = idx >= 0 && idx < m.length() - 1 ? m.substring(idx + 1).trim() : m;
return "原因:" + normalizeArrowSpaces(reason) + "\n";
}
}
if ("ORDER_SYNC".equals(t)) {
// 新订单入库,订单状态 X退款状态 Y
if (m.contains("新订单入库") && m.contains("订单状态 ") && m.contains("退款状态 ")) {
String os = substringBetweenPrefixes(m, "订单状态 ", ",退款状态");
String rs = substringAfterPrefix(m, "退款状态 ");
StringBuilder sb = new StringBuilder();
if (StringUtils.hasText(os)) {
sb.append("订单状态:").append(os.trim()).append('\n');
}
if (StringUtils.hasText(rs)) {
sb.append("退款状态:").append(rs.trim()).append('\n');
}
return sb.toString();
}
// 订单状态 A → B退款状态 …(仅输出消息里出现的块)
return formatOrderSyncSemicolonParts(m);
}
if ("LOGISTICS_SYNC".equals(t)) {
return formatLogisticsParts(m);
}
return normalizeArrowSpaces(m) + "\n";
}
private static String formatOrderSyncSemicolonParts(String m) {
String[] parts = m.split("");
StringBuilder sb = new StringBuilder();
for (String p : parts) {
String line = kvLineOrderOrRefund(p.trim());
if (line != null) {
sb.append(line).append('\n');
}
}
return sb.toString();
}
private static String kvLineOrderOrRefund(String segment) {
if (!StringUtils.hasText(segment)) {
return null;
}
if (segment.startsWith("订单状态 ")) {
return "订单状态:" + normalizeArrowSpaces(segment.substring("订单状态 ".length()).trim());
}
if (segment.startsWith("退款状态 ")) {
return "退款状态:" + normalizeArrowSpaces(segment.substring("退款状态 ".length()).trim());
}
return null;
}
private static String formatLogisticsParts(String m) {
String[] parts = m.split("");
StringBuilder sb = new StringBuilder();
for (String p : parts) {
String line = logisticsSegmentToKv(p.trim());
if (line != null) {
sb.append(line).append('\n');
}
}
return sb.toString();
}
/** 本地/平台运单 → 对用户展示为物流单号;其它变更行仍可保留技术性标签 */
private static String logisticsSegmentToKv(String segment) {
if (!StringUtils.hasText(segment)) {
return null;
}
if (segment.startsWith("本地运单 ") || segment.startsWith("平台运单 ")) {
int cut = segment.indexOf(' ');
String rest = normalizeArrowSpaces(segment.substring(cut + 1).trim());
return "物流单号:" + rest;
}
String kv = logisticLabelToColon(segment);
return kv != null ? kv : (normalizeArrowSpaces(segment));
}
private static String logisticLabelToColon(String segment) {
String[] prefixes = {"快递编码 ", "快递名称 "};
for (String pref : prefixes) {
if (segment.startsWith(pref)) {
String label = pref.trim();
return label.substring(0, label.length() - 1) + ""
+ normalizeArrowSpaces(segment.substring(pref.length()).trim());
}
}
return null;
}
private static String normalizeArrowSpaces(String s) {
if (s == null) {
return "";
}
return s.replace("", "").replace("", "").replace("", "");
}
/** 从「片段1片段2…」中取出以 {@code fieldPrefix} 开头的片段值(去掉前缀) */
private static String extractCommaField(String m, String fieldPrefix) {
if (!StringUtils.hasText(m) || !StringUtils.hasText(fieldPrefix)) {
return null;
}
for (String part : m.split("")) {
String p = part.trim();
if (p.startsWith(fieldPrefix)) {
String v = p.substring(fieldPrefix.length()).trim();
return v.length() > 0 ? v : null;
}
}
return null;
}
private static String substringBetweenPrefixes(String m, String a, String b) {
int ia = m.indexOf(a);
if (ia < 0) {
return null;
}
int ib = m.indexOf(b, ia + a.length());
if (ib < 0) {
return null;
}
return m.substring(ia + a.length(), ib);
}
private static String substringAfterPrefix(String m, String pref) {
int i = m.indexOf(pref);
if (i < 0) {
return null;
}
return m.substring(i + pref.length()).trim();
}
/**