diff --git a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmHotelMgrPushConfigEntity.java b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmHotelMgrPushConfigEntity.java index 7a93bfe64..c41c94e6b 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmHotelMgrPushConfigEntity.java +++ b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmHotelMgrPushConfigEntity.java @@ -33,6 +33,9 @@ public class SmHotelMgrPushConfigEntity extends Model leaders = deptId == null ? List.of() : resolveDeptLeaders(deptId); + List admins = adminEnabled ? resolveUsersByRoleCode(CommonRoleConstant.ROLE_ADMIN) : List.of(); + LinkedHashSet recipients = new LinkedHashSet<>(); + recipients.addAll(leaders); + recipients.addAll(admins); + List 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 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 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 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 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 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 leaderList = new ArrayList<>(leaders); + String leaderNames = resolveUserNames(leaderList); + log.info("|酒店管理推送|日历提醒完成|hour={}|deptCount={}|leaders={}|ok={}|", hour, deptIds.size(), + leaders.size(), ok); List 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 resolveUsersByRoleCode(String roleCode) { + if (StrUtil.isBlank(roleCode)) { + return List.of(); + } + try { + R> 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 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 deptIds, List 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);