This commit is contained in:
zjf committed 2026-11-12 20:45:35 +08:00
1 parent c7fa112451
commit 8aa5d4e54a
2 files changed
+122 -40

No files matched your search

@@ -33,6 +33,9 @@ public class SmHotelMgrPushConfigEntity extends Model<SmHotelMgrPushConfigEntity
@Schema(description = "新订单推送正文,可含 {hotelName}/{channelNo}")
private String newOrderContent;
@Schema(description = "新订单同时推送 ROLE_ADMIN:1开 0关")
private String newOrderAdminEnabled;
@Schema(description = "日历提醒:1开 0关")
private String calendarRemindEnabled;
@@ -9,6 +9,7 @@ import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.tenant.TenantContextHolder;
import com.bsd.pjcloud.supermarket.entity.SmHotelEntity;
@@ -101,6 +102,8 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
current.setNewOrderEnabled(normalizeFlag(body.getNewOrderEnabled(), current.getNewOrderEnabled()));
current.setNewOrderTitle(StrUtil.blankToDefault(StrUtil.trim(body.getNewOrderTitle()), DEFAULT_NEW_TITLE));
current.setNewOrderContent(StrUtil.blankToDefault(StrUtil.trim(body.getNewOrderContent()), DEFAULT_NEW_CONTENT));
current.setNewOrderAdminEnabled(
normalizeFlag(body.getNewOrderAdminEnabled(), current.getNewOrderAdminEnabled()));
current.setCalendarRemindEnabled(
normalizeFlag(body.getCalendarRemindEnabled(), current.getCalendarRemindEnabled()));
current.setCalendarRemindTitle(
@@ -176,7 +179,7 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
private PushResult doPushNewOrder(Long orderId, boolean force) {
if (orderId == null) {
return PushResult.fail("订单ID为空");
return PushResult.fail("订单为空");
}
try {
SmHotelMgrPushConfigEntity cfg = getOrCreateConfig();
@@ -185,7 +188,7 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
}
SmHotelOrderEntity order = orderMapper.selectById(orderId);
if (order == null) {
return PushResult.fail("订单不存在:" + orderId);
return PushResult.fail("订单不存在");
}
if ("CREATED".equals(order.getOrderStatus()) && "UNPAID".equals(order.getPayStatus())) {
return force ? PushResult.fail("订单待支付,暂不推送") : PushResult.skip("待支付跳过");
@@ -204,26 +207,43 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
String title = StrUtil.blankToDefault(cfg.getNewOrderTitle(), DEFAULT_NEW_TITLE);
String contentTpl = StrUtil.blankToDefault(cfg.getNewOrderContent(), DEFAULT_NEW_CONTENT);
String trigger = force ? SmHotelMgrPushLogEntity.TRIGGER_MANUAL : SmHotelMgrPushLogEntity.TRIGGER_AUTO;
if (deptId == null) {
String tip = "酒店未绑定部门(hotelId=" + order.getHotelId()
+ ")。请在酒店信息里配置所属部门后再推。";
log.info("|酒店管理推送|新订单跳过无部门|orderId={}|hotelId={}|", orderId, order.getHotelId());
String channelNoVal = StrUtil.blankToDefault(order.getChannelNo(), String.valueOf(orderId));
String orderLabel = StrUtil.isNotBlank(order.getChannelNo()) ? order.getChannelNo() : ("订单#" + orderId);
boolean adminEnabled = ENABLED.equals(cfg.getNewOrderAdminEnabled());
List<Long> leaders = deptId == null ? List.of() : resolveDeptLeaders(deptId);
List<Long> admins = adminEnabled ? resolveUsersByRoleCode(CommonRoleConstant.ROLE_ADMIN) : List.of();
LinkedHashSet<Long> recipients = new LinkedHashSet<>();
recipients.addAll(leaders);
recipients.addAll(admins);
List<Long> logDepts = deptId == null ? List.of() : List.of(deptId);
String deptName = deptId == null ? "" : resolveDeptNames(logDepts);
if (recipients.isEmpty()) {
String tip;
if (deptId == null && !adminEnabled) {
tip = "酒店未绑定部门,且未开启「推送管理员」。请配置酒店所属部门或开启管理员推送。";
}
else if (deptId == null) {
tip = "酒店未绑定部门,且未找到 ROLE_ADMIN 用户。";
}
else if (CollUtil.isEmpty(leaders) && !adminEnabled) {
tip = "部门「" + StrUtil.blankToDefault(deptName, String.valueOf(deptId))
+ "」下没有岗位=部门负责人(TEAM_LEADER)的用户(仅本部门)。"
+ "请确认用户所属部门与岗位,或开启「推送管理员」。";
}
else if (CollUtil.isEmpty(leaders)) {
tip = "部门「" + StrUtil.blankToDefault(deptName, String.valueOf(deptId))
+ "」无部门负责人,且未找到 ROLE_ADMIN 用户。";
}
else {
tip = "未找到可推送对象。";
}
log.info("|酒店管理推送|新订单无接收人|orderId={}|deptId={}|adminEnabled={}|", orderId, deptId,
adminEnabled);
savePushLog(SmHotelMgrPushLogEntity.TYPE_NEW_ORDER, trigger, String.valueOf(orderId),
order.getHotelId(), hotelName, List.of(), List.of(), 0, 0, title, null, tip);
return force ? PushResult.fail(tip) : PushResult.skip(tip);
}
List<Long> leaders = resolveDeptLeaders(deptId);
if (CollUtil.isEmpty(leaders)) {
String tip = "部门 " + deptId + " 下没有岗位=部门负责人(TEAM_LEADER)的用户(仅本部门,不含下级)。"
+ "请到用户管理确认:用户所属部门=该酒店部门,且岗位勾选「部门负责人」。";
log.info("|酒店管理推送|新订单无负责人|orderId={}|deptId={}|hotelId={}|", orderId, deptId,
order.getHotelId());
savePushLog(SmHotelMgrPushLogEntity.TYPE_NEW_ORDER, trigger, String.valueOf(orderId),
order.getHotelId(), hotelName, List.of(deptId), List.of(), 0, 0, title, null, tip);
order.getHotelId(), hotelName, logDepts, List.of(), 0, 0, title, null, tip);
return force ? PushResult.fail(tip) : PushResult.skip(tip);
}
Long tenantId = resolveTenantId(order.getTenantId(), hotel == null ? null : hotel.getTenantId());
String channelNoVal = StrUtil.blankToDefault(order.getChannelNo(), String.valueOf(orderId));
String content = contentTpl.replace("{hotelName}", hotelName).replace("{channelNo}", channelNoVal);
if (!content.contains(hotelName) && !contentTpl.contains("{hotelName}")) {
content = hotelName + ":" + content;
@@ -234,6 +254,7 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
payload.put("channelNo", channelNoVal);
payload.put("deptId", deptId);
payload.put("force", force);
payload.put("adminPush", adminEnabled);
Map<String, Object> linkParams = new HashMap<>(4);
linkParams.put("orderId", String.valueOf(orderId));
String eventPrefix = force
@@ -241,7 +262,7 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
: ("HOTEL_MGR_ORDER:" + orderId);
int ok = 0;
List<String> failHints = new ArrayList<>();
for (Long userId : leaders) {
for (Long userId : recipients) {
if (userId == null) {
continue;
}
@@ -264,26 +285,28 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
ok++;
}
else if (failHints.size() < 3) {
failHints.add("userId=" + userId + ":" + err);
failHints.add(displayUserName(userId) + ":" + err);
}
}
int fail = Math.max(0, leaders.size() - ok);
log.info("|酒店管理推送|新订单完成|orderId={}|deptId={}|leaders={}|ok={}|force={}|leadersIds={}|",
orderId, deptId, leaders.size(), ok, force, leaders);
List<Long> recipientList = new ArrayList<>(recipients);
int fail = Math.max(0, recipientList.size() - ok);
String leaderNames = resolveUserNames(leaders);
String adminNames = resolveUserNames(admins);
String detail = buildNewOrderDetail(orderLabel, deptName, leaderNames, adminNames, adminEnabled);
log.info("|酒店管理推送|新订单完成|orderId={}|deptId={}|recipients={}|ok={}|force={}|admin={}|",
orderId, deptId, recipientList.size(), ok, force, adminEnabled);
if (ok == 0) {
String tip = "找到负责人 " + leaders.size() + " 人(deptId=" + deptId + ", userIds=" + leaders
+ "),但消息中心投递全部失败。"
+ (failHints.isEmpty() ? "请确认 thirdparty 已重启并包含酒店管理推送接口。"
: ("原因:" + String.join(";", failHints)));
String tip = "找到接收人 " + recipientList.size() + " 人,但消息中心投递全部失败。" + detail
+ (failHints.isEmpty() ? " 请确认 thirdparty 已重启并包含酒店管理推送接口。"
: (" 原因:" + String.join(";", failHints)));
savePushLog(SmHotelMgrPushLogEntity.TYPE_NEW_ORDER, trigger, String.valueOf(orderId),
order.getHotelId(), hotelName, List.of(deptId), leaders, 0, fail, title, content, tip);
order.getHotelId(), hotelName, logDepts, recipientList, 0, fail, title, content, tip);
return force ? PushResult.fail(tip) : PushResult.skip(tip);
}
String msg = "已推送成功 " + ok + "/" + leaders.size() + " 人(订单ID=" + orderId + ",deptId=" + deptId
+ ",负责人=" + leaders + ")";
String msg = "已推送成功 " + ok + "/" + recipientList.size() + " 人" + detail;
savePushLog(SmHotelMgrPushLogEntity.TYPE_NEW_ORDER, trigger, String.valueOf(orderId),
order.getHotelId(), hotelName, List.of(deptId), leaders, ok, fail, title, content, msg);
return PushResult.success(ok, leaders.size(), msg);
order.getHotelId(), hotelName, logDepts, recipientList, ok, fail, title, content, msg);
return PushResult.success(ok, recipientList.size(), msg);
}
catch (Exception e) {
log.warn("|酒店管理推送|新订单异常|orderId={}|err={}|", orderId, e.getMessage(), e);
@@ -324,8 +347,9 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
}
}
if (leaders.isEmpty()) {
List<Long> sampleDepts = deptIds.stream().limit(5).toList();
String tip = "扫描到 " + deptIds.size() + " 个酒店部门,但都没有岗位=部门负责人(TEAM_LEADER)的用户。"
+ "部门示例:" + deptIds.stream().limit(5).map(String::valueOf).collect(Collectors.joining(","));
+ "部门示例:" + StrUtil.blankToDefault(resolveDeptNames(sampleDepts), "无");
log.info("|酒店管理推送|日历提醒无负责人|hour={}|deptCount={}|", hour, deptIds.size());
savePushLog(SmHotelMgrPushLogEntity.TYPE_CALENDAR, trigger, day + "-" + hour, null, null,
new ArrayList<>(deptIds), List.of(), 0, 0, title, content, tip);
@@ -362,26 +386,80 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
ok++;
}
else if (failHints.size() < 3) {
failHints.add("userId=" + userId + ":" + err);
failHints.add(displayUserName(userId) + ":" + err);
}
}
int fail = Math.max(0, leaders.size() - ok);
log.info("|酒店管理推送|日历提醒完成|hour={}|deptCount={}|leaders={}|ok={}|ids={}|", hour, deptIds.size(),
leaders.size(), ok, leaders);
List<Long> leaderList = new ArrayList<>(leaders);
String leaderNames = resolveUserNames(leaderList);
log.info("|酒店管理推送|日历提醒完成|hour={}|deptCount={}|leaders={}|ok={}|", hour, deptIds.size(),
leaders.size(), ok);
List<Long> logDepts = deptsWithLeader.isEmpty() ? new ArrayList<>(deptIds) : deptsWithLeader;
if (ok == 0) {
String tip = "找到负责人 " + leaders.size() + " 人,但投递全部失败。"
String tip = "找到负责人 " + leaders.size() + " 人(" + leaderNames + "),但投递全部失败。"
+ (failHints.isEmpty() ? "请确认 thirdparty 已重启。" : ("原因:" + String.join(";", failHints)));
savePushLog(SmHotelMgrPushLogEntity.TYPE_CALENDAR, trigger, day + "-" + hour, null, null,
logDepts, new ArrayList<>(leaders), 0, fail, title, content, tip);
logDepts, leaderList, 0, fail, title, content, tip);
return force ? PushResult.fail(tip) : PushResult.skip(tip);
}
String msg = "日历提醒成功 " + ok + "/" + leaders.size() + " 人(负责人=" + leaders + ")";
String msg = "日历提醒成功 " + ok + "/" + leaders.size() + " 人(负责人=" + leaderNames + ")";
savePushLog(SmHotelMgrPushLogEntity.TYPE_CALENDAR, trigger, day + "-" + hour, null, null,
logDepts, new ArrayList<>(leaders), ok, fail, title, content, msg);
logDepts, leaderList, ok, fail, title, content, msg);
return PushResult.success(ok, leaders.size(), msg);
}
private static String buildNewOrderDetail(String orderLabel, String deptName, String leaderNames,
String adminNames, boolean adminEnabled) {
StringBuilder sb = new StringBuilder();
sb.append("(订单=").append(StrUtil.blankToDefault(orderLabel, "-"));
if (StrUtil.isNotBlank(deptName)) {
sb.append(",部门=").append(deptName);
}
if (StrUtil.isNotBlank(leaderNames)) {
sb.append(",负责人=").append(leaderNames);
}
if (adminEnabled) {
sb.append(",管理员=").append(StrUtil.blankToDefault(adminNames, "无"));
}
sb.append(")");
return sb.toString();
}
/** 按角色编码取当前租户有效用户,失败返回空列表 */
private List<Long> resolveUsersByRoleCode(String roleCode) {
if (StrUtil.isBlank(roleCode)) {
return List.of();
}
try {
R<List<Long>> resp = remoteUserService.getInnerUserIdsByRoleCode(roleCode);
if (resp == null || !resp.isOk() || CollUtil.isEmpty(resp.getData())) {
log.info("|酒店管理推送|角色无用户|roleCode={}|code={}|msg={}|", roleCode,
resp == null ? null : resp.getCode(), resp == null ? "null" : resp.getMsg());
return List.of();
}
List<Long> ids = new ArrayList<>();
for (Object o : resp.getData()) {
Long id = toLong(o);
if (id != null) {
ids.add(id);
}
}
return ids.stream().distinct().toList();
}
catch (Exception e) {
log.warn("|酒店管理推送|查角色用户异常|roleCode={}|err={}|", roleCode, e.getMessage());
return List.of();
}
}
private String displayUserName(Long userId) {
if (userId == null) {
return "-";
}
String names = resolveUserNames(List.of(userId));
return StrUtil.blankToDefault(names, String.valueOf(userId));
}
private void savePushLog(String pushType, String triggerType, String bizId, Long hotelId, String hotelName,
List<Long> deptIds, List<Long> userIds, int success, int fail, String title, String content,
String resultMsg) {
@@ -555,6 +633,7 @@ public class SmHotelMgrPushServiceImpl implements SmHotelMgrPushService {
row.setNewOrderEnabled(ENABLED);
row.setNewOrderTitle(DEFAULT_NEW_TITLE);
row.setNewOrderContent(DEFAULT_NEW_CONTENT);
row.setNewOrderAdminEnabled(ENABLED);
row.setCalendarRemindEnabled(ENABLED);
row.setCalendarRemindTitle(DEFAULT_CAL_TITLE);
row.setCalendarRemindContent(DEFAULT_CAL_CONTENT);