From e0c62ae8f22ebcc343a3bf77d2d93d1f54c48e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E9=B9=8F=E9=A3=9E?= Date: Wed, 6 Aug 2025 19:21:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20bug-528=20app=E7=AB=AF=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=A7=86=E9=A2=91=E9=80=9A=E8=AF=9D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/TicketController.java | 40 ++++++++++-- .../admin/task/ShengWangScheduledTasks.java | 10 +-- .../cfs/controller/TicketController.java | 17 +++-- .../mobilebroken/push/UserSseEmitter.java | 9 ++- .../push/service/SSEManagerBase.java | 63 ++++++++++--------- .../service/ITicketCallService.java | 2 +- .../impl/TicketCallJoinServiceImpl.java | 8 ++- .../service/impl/TicketCallServiceImpl.java | 9 +-- 8 files changed, 101 insertions(+), 57 deletions(-) diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java index ffa30458..72a54ddb 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java @@ -745,6 +745,9 @@ public class TicketController extends ControllerBase { .throwMessage("当前工单状态不允许发送消息"); List adminUsers=adminUserService.getTickerMangagers(); adminUsers.addAll(StrUtil.split(ticket.getHandle(),",").stream().map(Integer::parseInt).collect(Collectors.toList())); + if (StrUtil.equals(Constant.FROM_ADMIN,ticket.getUserPlatform())){ + adminUsers.add(ticket.getUserId()); + } VUtils.trueThrowBusinessError(adminUsers.stream() .noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId()))) .throwMessage("你无权发送消息"); @@ -1246,13 +1249,33 @@ public class TicketController extends ControllerBase { VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.Processing.getState())) .throwMessage("当前工单状态不允许请求通话"); Integer handlerUserId = Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).findFirst().get(); - VUtils.trueThrowBusinessError(!Objects.equals(AdminUserUtil.getUserId(), handlerUserId)) - .throwMessage("不是工单主负责人无权限呼叫"); + if (StrUtil.equals(Constant.FROM_APP,ticket.getUserPlatform())) { + VUtils.trueThrowBusinessError(!Objects.equals(AdminUserUtil.getUserId(), handlerUserId)) + .throwMessage("不是工单主负责人无权限呼叫"); + }else { + VUtils.trueThrowBusinessError(!Objects.equals(ticket.getUserId(), AdminUserUtil.getUserId()) && !Objects.equals(AdminUserUtil.getUserId(), handlerUserId)) + .throwMessage("无权限呼叫"); + } VUtils.trueThrowBusinessError(ticketCallService.isInCall(ticket.getUserId())).throwMessage("对方正在通话中"); + boolean userIdCreate=StrUtil.equals(ticket.getUserPlatform(),Constant.FROM_ADMIN) && Objects.equals(ticket.getUserId(), AdminUserUtil.getUserId()); + Integer sendUserId=0,receiveUserId=0; + String sendUserFrom,receiveUserFrom; + if (userIdCreate){ + sendUserId=ticket.getUserId(); + receiveUserId=handlerUserId; + sendUserFrom=Constant.FROM_ADMIN; + receiveUserFrom=Constant.FROM_ADMIN; + }else { + sendUserId=handlerUserId; + receiveUserId=ticket.getUserId(); + sendUserFrom=Constant.FROM_ADMIN; + receiveUserFrom=Constant.FROM_APP; + } + ticketCallService.add(ticketId, sendUserId,sendUserFrom, receiveUserId, receiveUserFrom); AdminUser adminUser = adminUserService.getById(handlerUserId); uniPushService.send(new UniPushMessage() .setSenderId("admin-uid-" + handlerUserId) - .setReceiverId("app-uid-" + ticket.getUserId()) + .setReceiverId(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) .setSendData(new UniPushMessageBody() .setTitle("视频通话") .setContent(adminUser.getUserName() + "请求与您视频通话") @@ -1266,8 +1289,11 @@ public class TicketController extends ControllerBase { ) ) ); - ssePushService.sendTicketCallToApp(adminUser, ticket.getUserId(), ticketId); - ticketCallService.add(ticketId, handlerUserId, ticket.getUserId(), Constant.FROM_ADMIN); + if (StrUtil.equals(Constant.FROM_APP,ticket.getUserPlatform())) { + ssePushService.sendTicketCallToApp(adminUser, ticket.getUserId(), ticketId); + }else { + ssePushService.sendTicketCallToAdmin(adminUser, ticket.getUserId(), ticketId); + } ticketEventPublisher.publishTicketCallBeginEvent(ticketId, adminUser.getUserName()); return ApiResult.success(); } @@ -1326,7 +1352,7 @@ public class TicketController extends ControllerBase { ticketCallJoinService.join(ticketId, AdminUserUtil.getUserId(),Constant.FROM_ADMIN); ssePushService.sendTicketCallJoinedToAdmin(AdminUserUtil.getUserId(), ticketId); uniPushService.send(new UniPushMessage() - .setSenderId("admin-uid-" + AdminUserUtil.getUserId()) + .setSenderId("admin-uid-" + AdminUserUtil.getUserId())//不重要 .setReceiverId("admin-uid-" + AdminUserUtil.getUserId()) .setSendData(new UniPushMessageBody() .setTitle("视频通话") @@ -1351,7 +1377,9 @@ public class TicketController extends ControllerBase { TicketCall ticketCall = ticketCallService.lambdaQuery() .eq(TicketCall::getTicketId, request.getTicketId()) .ne(TicketCall::getState, 2) + .last("limit 1") .one(); + if (Objects.isNull(ticketCall)) return ApiResult.success(); boolean flag=false; if (request.getReject()) { AdminUser adminUser = adminUserService.getById(AdminUserUtil.getUserId()); diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/task/ShengWangScheduledTasks.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/task/ShengWangScheduledTasks.java index ba1283af..7acf0918 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/task/ShengWangScheduledTasks.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/task/ShengWangScheduledTasks.java @@ -13,6 +13,7 @@ import com.nflg.mobilebroken.repository.service.ITicketCallService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.slf4j.MDC; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -23,6 +24,7 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +@ConditionalOnProperty(name = "shengwang.sync.enable", havingValue = "true", matchIfMissing = true) @Component @Slf4j public class ShengWangScheduledTasks { @@ -62,7 +64,7 @@ public class ShengWangScheduledTasks { ticketCallService.updateById(ticketCall); ticketCallJoinService.lambdaUpdate() .set(TicketCallJoin::getState, 2) - .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) +// .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) .eq(TicketCallJoin::getCallId, ticketCall.getId()) .update(); }); @@ -80,7 +82,7 @@ public class ShengWangScheduledTasks { if (CollectionUtil.isEmpty(channelUsers)) { ticketCallJoinService.lambdaUpdate() .set(TicketCallJoin::getState, 2) - .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) +// .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) .eq(TicketCallJoin::getCallId, ticketCall.getId()) .update(); } else { @@ -94,7 +96,7 @@ public class ShengWangScheduledTasks { if (CollectionUtil.isNotEmpty(userIds)) { ticketCallJoinService.lambdaUpdate() .set(TicketCallJoin::getState, 2) - .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) +// .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) .eq(TicketCallJoin::getCallId, ticketCall.getId()) .eq(TicketCallJoin::getFrom, Constant.FROM_APP) .notIn(TicketCallJoin::getUserId, userIds) @@ -110,7 +112,7 @@ public class ShengWangScheduledTasks { if (CollectionUtil.isNotEmpty(userIds)) { ticketCallJoinService.lambdaUpdate() .set(TicketCallJoin::getState, 2) - .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) +// .set(TicketCallJoin::getHangupTime, LocalDateTime.now()) .eq(TicketCallJoin::getCallId, ticketCall.getId()) .eq(TicketCallJoin::getFrom, Constant.FROM_ADMIN) .notIn(TicketCallJoin::getUserId, userIds) diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TicketController.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TicketController.java index 04807717..b4a7f6c2 100644 --- a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TicketController.java +++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TicketController.java @@ -507,7 +507,7 @@ public class TicketController extends ControllerBase { VUtils.trueThrowBusinessError(ticketCallService.isInCall(handlerUserId)).throwMessage("对方正在通话中"); AppUser appUser = appUserService.getById(ticket.getUserId()); uniPushService.send(new UniPushMessage() - .setSenderId("app-uid-" + ticket.getUserId()) + .setSenderId(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) .setReceiverId("admin-uid-" + handlerUserId) .setSendData(new UniPushMessageBody() .setTitle("视频通话") @@ -523,7 +523,7 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallToAdmin(appUser, handlerUserId, ticketId); - ticketCallService.add(ticketId, AppUserUtil.getUserId(), handlerUserId, Constant.FROM_APP); + ticketCallService.add(ticketId, AppUserUtil.getUserId(),Constant.FROM_APP, handlerUserId, Constant.FROM_ADMIN); ticketEventPublisher.publishTicketCallBeginEvent(ticketId,appUser.getName()); return ApiResult.success(); } @@ -538,13 +538,17 @@ public class TicketController extends ControllerBase { VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在"); VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.Processing.getState())) .throwMessage("当前工单状态不允许通话"); + VUtils.trueThrowBusinessError(!StrUtil.equals(ticket.getUserPlatform(), AppUserUtil.getFrom()) + || Objects.equals(AppUserUtil.getUserId(), ticket.getUserId())) + .throwMessage("不是创建人无法加入通话"); VUtils.trueThrowBusinessError(ticketCallService.isInCall(AppUserUtil.getUserId())) .throwMessage("您已加入别的通话中"); ticketCallJoinService.join(ticketId, AppUserUtil.getUserId(), Constant.FROM_APP); ssePushService.sendTicketCallJoinedToApp(AppUserUtil.getUserId(), ticketId); + Integer handlerUserId = Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).findFirst().get(); uniPushService.send(new UniPushMessage() - .setSenderId("app-uid-" + AppUserUtil.getUserId()) - .setReceiverId("app-uid-" + AppUserUtil.getUserId()) + .setSenderId(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) + .setReceiverId("admin-uid-" + handlerUserId) .setSendData(new UniPushMessageBody() .setTitle("视频通话") .setContent("您已加入别的通话中") @@ -572,7 +576,7 @@ public class TicketController extends ControllerBase { Ticket ticket = ticketService.getById(request.getTicketId()); int handlerId= Integer.parseInt(StrUtil.split(ticket.getHandle(), ",").stream().findFirst().get()); uniPushService.send(new UniPushMessage() - .setSenderId("app-uid-" + appUser.getId()) + .setSenderId(ticket.getUserPlatform()+"-uid-" + appUser.getId()) .setReceiverId("admin-uid-" + handlerId) .setSendData(new UniPushMessageBody() .setTitle("挂断视频通话") @@ -591,8 +595,9 @@ public class TicketController extends ControllerBase { flag=ticketCallService.hangUp(request.getTicketId(), AppUserUtil.getUserId(), Constant.FROM_APP, true); }else { AppUser appUser = appUserService.getById(AppUserUtil.getUserId()); + Ticket ticket = ticketService.getById(request.getTicketId()); uniPushService.send(new UniPushMessage() - .setSenderId("app-uid-" + appUser.getId()) + .setSenderId(ticket.getUserPlatform()+"-uid-" + appUser.getId()) .setReceiverId("admin-uid-" + request.getFromUserId()) .setSendData(new UniPushMessageBody() .setTitle("拒绝视频通话") diff --git a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/UserSseEmitter.java b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/UserSseEmitter.java index 55290553..1a9764e1 100644 --- a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/UserSseEmitter.java +++ b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/UserSseEmitter.java @@ -1,5 +1,6 @@ package com.nflg.mobilebroken.push; +import cn.hutool.core.util.IdUtil; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -22,6 +23,8 @@ public class UserSseEmitter extends SseEmitter { private Integer ticketId; + private String id = IdUtil.getSnowflakeNextIdStr(); + private ScheduledFuture heartbeatFuture; public UserSseEmitter(){ @@ -34,8 +37,8 @@ public class UserSseEmitter extends SseEmitter { this.ticketId = ticketId; } - public String getUser(){ - return from + "-" + userId; + public String getLable() { + return from + "-" + userId + ",连接id:" + id; } public void startHeartbeat(TaskScheduler taskScheduler) { @@ -44,7 +47,7 @@ public class UserSseEmitter extends SseEmitter { send(SseEmitter.event().data("ping")); } catch (IOException e) { heartbeatFuture.cancel(true); - log.error("sse发送ping数据出错({}):{}", getUser(),e.getMessage()); + log.error("sse发送ping数据出错({}):{}", getLable(),e.getMessage()); completeWithError(e); } }, 30_000); diff --git a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/service/SSEManagerBase.java b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/service/SSEManagerBase.java index 8b3c682e..fe8f9c2f 100644 --- a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/service/SSEManagerBase.java +++ b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/service/SSEManagerBase.java @@ -34,53 +34,53 @@ public class SSEManagerBase { protected String from; - protected void check(){ - VUtils.trueThrow(IS_SHUTDOWN).throwMessage(STATE.ServiceConnectRefused,"SSE服务已关闭"); + protected void check() { + VUtils.trueThrow(IS_SHUTDOWN).throwMessage(STATE.ServiceConnectRefused, "SSE服务已关闭"); } @PreDestroy protected void shutdown() { - IS_SHUTDOWN=true; + IS_SHUTDOWN = true; log.warn("准备关闭SSE服务"); - SSE_EMITTERS.forEach(emitter->{ + SSE_EMITTERS.forEach(emitter -> { try { emitter.send("因SSE服务关闭,连接即将断开"); emitter.complete(); - }catch (Exception ex){ - log.error("SSE发送消息失败",ex); + } catch (Exception ex) { + log.error("SSE发送消息失败", ex); emitter.completeWithError(ex); } }); log.warn("SSE服务已关闭"); } - protected SseEmitter connect(Integer ticketId,Integer userId) { + protected SseEmitter connect(Integer ticketId, Integer userId) { check(); - log.info(from + "SSE连接:用户id:" + userId + ",工单id:" + ticketId); UserSseEmitter emitter = new UserSseEmitter(from, userId, ticketId); + log.info(from + "SSE连接:用户id:" + userId + ",工单id:" + ticketId + ",连接id:" + emitter.getId()); emitter.startHeartbeat(taskScheduler); SSE_EMITTERS.add(emitter); emitter.onError((ex) -> { remove(emitter); - log.error("SSE异常({}):{}", ex.getMessage(),emitter.getUser()); + log.error("SSE异常({}):{}", ex.getMessage(), emitter.getLable()); }); emitter.onTimeout(() -> { remove(emitter); - log.error("SSE超时:"+userId); + log.error("SSE超时:" + userId); }); emitter.onCompletion(() -> { remove(emitter); - log.error("SSE完成:"+userId); + log.error("SSE完成:" + userId); }); try { + log.info("发送连接成功信息:" + emitter.getLable()); emitter.send(SseEmitter.event().data("已连接").reconnectTime(5000)); - }catch (ClientAbortException e){ - log.error("客户端断开连接:{}", userId); - emitter.completeWithError(e); - } - catch (IOException e) { + } catch (ClientAbortException e) { + log.error("断开已连接:{}", e.getMessage()); + emitter.complete(); + } catch (IOException e) { log.error("sse发送数据出错:{}", e.getMessage()); - emitter.completeWithError(e); + emitter.complete(); } return emitter; } @@ -90,19 +90,21 @@ public class SSEManagerBase { List emitters = SSE_EMITTERS.stream() .filter(s -> Objects.equals(s.getTicketId(), ticketId)) .collect(Collectors.toList()); - if (CollectionUtil.isEmpty(emitters)){ + if (CollectionUtil.isEmpty(emitters)) { log.info(StrUtil.format(from + "没有用户连接工单:{}", ticketId)); return; } emitters.forEach(emitter -> { try { + log.info("发送给用户:" + emitter.getLable()); emitter.send(SseEmitter.event().name(dto.getType()).data(dto.getData())); + log.info("发送成功"); } catch (ClientAbortException e) { - log.error("客户端断开连接:{}", emitter.getUser()); - emitter.completeWithError(e); + log.error("发送失败,{}", e.getMessage()); + emitter.complete(); } catch (IOException e) { - log.error("sse发送数据出错:{}", e.getMessage()); - emitter.completeWithError(e); + log.error("发送失败,sse发送数据出错:{}", e.getMessage()); + emitter.complete(); } }); } @@ -118,21 +120,22 @@ public class SSEManagerBase { } emitters.forEach(emitter -> { try { + log.info("发送给用户:" + emitter.getLable()); emitter.send(SseEmitter.event().name(dto.getType()).data(dto.getData())); log.info("发送成功"); - } catch (ClientAbortException e) { - log.error("客户端断开连接:{}", emitter.getUser()); - emitter.completeWithError(e); - }catch (IOException e) { - log.error("sse发送数据出错:{}", e.getMessage()); - emitter.completeWithError(e); + } catch (ClientAbortException e) { + log.error("发送失败,{}", e.getMessage()); + emitter.complete(); + } catch (IOException e) { + log.error("发送失败,sse发送数据出错:{}", e.getMessage()); + emitter.complete(); } }); } - private void remove(UserSseEmitter emitter){ + private void remove(UserSseEmitter emitter) { SSE_EMITTERS.remove(emitter); emitter.complete(); - emitter=null; + emitter = null; } } \ No newline at end of file diff --git a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/ITicketCallService.java b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/ITicketCallService.java index fe460741..f5a8f05d 100644 --- a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/ITicketCallService.java +++ b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/ITicketCallService.java @@ -17,7 +17,7 @@ public interface ITicketCallService extends IService { boolean isInCall(Integer userId); - void add(Integer ticketId, Integer callerUserId, Integer calledUserId, String from); + void add(Integer ticketId, Integer callerUserId,String callerUserFrom, Integer calledUserId, String calledUserFrom); boolean hangUp(@NotNull Integer ticketId, Integer userId, String from, boolean reject); } diff --git a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/impl/TicketCallJoinServiceImpl.java b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/impl/TicketCallJoinServiceImpl.java index 22f47fd9..1e463ea0 100644 --- a/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/impl/TicketCallJoinServiceImpl.java +++ b/nflg-mobilebroken-repository/src/main/java/com/nflg/mobilebroken/repository/service/impl/TicketCallJoinServiceImpl.java @@ -41,6 +41,7 @@ public class TicketCallJoinServiceImpl extends ServiceImpl