From 29c5a1e556774eac4e165a1f184c717044176a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E9=B9=8F=E9=A3=9E?= Date: Fri, 8 Aug 2025 18:27:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=A7=86=E9=A2=91?= =?UTF-8?q?=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/ShengWangController.java | 4 +- .../admin/controller/TicketController.java | 90 +++++----- .../admin/event/TicketCallEndEvent.java | 34 ++-- .../admin/listener/TicketEventListener.java | 4 +- .../admin/service/ShengWangService.java | 3 +- .../admin/task/ShengWangScheduledTasks.java | 4 +- .../cfs/config/HttpClientConfig.java | 19 +++ .../cfs/controller/TicketController.java | 72 ++++---- .../cfs/event/TicketCallEndEvent.java | 35 ++-- .../cfs/listener/TicketEventListener.java | 4 +- .../cfs/service/ShengWangService.java | 159 ++++++++++++++++++ .../common}/pojo/dto/ShengWangChannelDTO.java | 2 +- .../pojo/dto/ShengWangChannelInfoDTO.java | 2 +- .../pojo/dto/ShengWangKickingRuleAddDTO.java | 2 +- .../dto/ShengWangKickingRuleListItemDTO.java | 2 +- .../ShengWangKickingRuleListResponseDTO.java | 2 +- .../common}/pojo/dto/ShengWangResponse.java | 2 +- 17 files changed, 309 insertions(+), 131 deletions(-) create mode 100644 nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/config/HttpClientConfig.java create mode 100644 nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/ShengWangService.java rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangChannelDTO.java (87%) rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangChannelInfoDTO.java (87%) rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangKickingRuleAddDTO.java (72%) rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangKickingRuleListItemDTO.java (97%) rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangKickingRuleListResponseDTO.java (80%) rename {nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin => nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common}/pojo/dto/ShengWangResponse.java (71%) diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/ShengWangController.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/ShengWangController.java index 80ce0608..023c8d1f 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/ShengWangController.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/ShengWangController.java @@ -1,9 +1,9 @@ package com.nflg.mobilebroken.admin.controller; -import com.nflg.mobilebroken.admin.pojo.dto.ShengWangChannelDTO; -import com.nflg.mobilebroken.admin.pojo.dto.ShengWangKickingRuleListItemDTO; import com.nflg.mobilebroken.admin.service.ShengWangService; import com.nflg.mobilebroken.common.pojo.ApiResult; +import com.nflg.mobilebroken.common.pojo.dto.ShengWangChannelDTO; +import com.nflg.mobilebroken.common.pojo.dto.ShengWangKickingRuleListItemDTO; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; 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 7dd8730e..aa1b1d7d 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 @@ -130,11 +130,11 @@ public class TicketController extends ControllerBase { @Resource private UniPushService uniPushService; - @Resource - private ITicketCallService ticketCallService; - - @Resource - private ITicketCallJoinService ticketCallJoinService; +// @Resource +// private ITicketCallService ticketCallService; +// +// @Resource +// private ITicketCallJoinService ticketCallJoinService; /** * 获取问题类型 @@ -1256,7 +1256,6 @@ public class TicketController extends ControllerBase { 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; @@ -1271,7 +1270,8 @@ public class TicketController extends ControllerBase { sendUserFrom = Constant.FROM_ADMIN; receiveUserFrom = Constant.FROM_APP; } - ticketCallService.add(ticketId, sendUserId, sendUserFrom, receiveUserId, receiveUserFrom); +// VUtils.trueThrowBusinessError(ticketCallJoinService.isInCall(ticket.getId(), receiveUserFrom, receiveUserId)).throwMessage("对方正在通话中"); +// ticketCallService.add(ticketId, sendUserId, sendUserFrom, receiveUserId, receiveUserFrom); AdminUser adminUser = adminUserService.getById(sendUserId); uniPushService.send(new UniPushMessage() .setSenderId("admin-uid-" + sendUserId) @@ -1306,11 +1306,11 @@ public class TicketController extends ControllerBase { @PostMapping("addCallUser") public ApiResult addCallUser(@Valid @RequestBody CallUserAddRequest request){ AdminUser adminUser = adminUserService.getById(AdminUserUtil.getUserId()); - TicketCall ticketCall = ticketCallService.lambdaQuery() - .eq(TicketCall::getTicketId, request.getTicketId()) - .eq(TicketCall::getState, 1) - .one(); - VUtils.trueThrowBusinessError(Objects.isNull(ticketCall)).throwMessage("未在通话中"); +// TicketCall ticketCall = ticketCallService.lambdaQuery() +// .eq(TicketCall::getTicketId, request.getTicketId()) +// .eq(TicketCall::getState, 1) +// .one(); +// VUtils.trueThrowBusinessError(Objects.isNull(ticketCall)).throwMessage("未在通话中"); request.getUserIds().forEach(userId->{ AdminUser adminUser1 = adminUserService.getById(userId); if (Objects.nonNull(adminUser1)) { @@ -1331,7 +1331,7 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallToAdmin(adminUser, userId, request.getTicketId()); - ticketCallJoinService.add(ticketCall.getId(), userId, Constant.FROM_ADMIN); +// ticketCallJoinService.add(ticketCall.getId(), userId, Constant.FROM_ADMIN); } }); return ApiResult.success(); @@ -1347,24 +1347,24 @@ public class TicketController extends ControllerBase { VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在"); VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.Processing.getState())) .throwMessage("当前工单状态不允许请求通话"); - VUtils.trueThrowBusinessError(ticketCallService.isInCall(AdminUserUtil.getUserId())) - .throwMessage("您已加入别的通话中"); - ticketCallJoinService.join(ticketId, AdminUserUtil.getUserId(),Constant.FROM_ADMIN); - ssePushService.sendTicketCallJoinedToAdmin(AdminUserUtil.getUserId(), ticketId); - uniPushService.send(new UniPushMessage() - .setSenderId("admin-uid-" + AdminUserUtil.getUserId())//不重要 - .setReceiverId("admin-uid-" + AdminUserUtil.getUserId()) - .setSendData(new UniPushMessageBody() - .setTitle("视频通话") - .setContent("您已加入别的通话中") - .setPayload(new UniPushMessageCallPayload() - .setTicketId(ticketId) - .setUserId(AdminUserUtil.getUserId()) - .setCategory("ticketCallJoined") - .setFrom("admin") - ) - ) - ); +// VUtils.trueThrowBusinessError(ticketCallJoinService.isInCall(ticket.getId(), Constant.FROM_ADMIN, AdminUserUtil.getUserId())) +// .throwMessage("您已加入别的通话中"); +// ticketCallJoinService.join(ticketId, AdminUserUtil.getUserId(),Constant.FROM_ADMIN); +// ssePushService.sendTicketCallJoinedToAdmin(AdminUserUtil.getUserId(), ticketId); +// uniPushService.send(new UniPushMessage() +// .setSenderId("admin-uid-" + AdminUserUtil.getUserId())//不重要 +// .setReceiverId("admin-uid-" + AdminUserUtil.getUserId()) +// .setSendData(new UniPushMessageBody() +// .setTitle("视频通话") +// .setContent("您已加入别的通话中") +// .setPayload(new UniPushMessageCallPayload() +// .setTicketId(ticketId) +// .setUserId(AdminUserUtil.getUserId()) +// .setCategory("ticketCallJoined") +// .setFrom("admin") +// ) +// ) +// ); return ApiResult.success(); } @@ -1374,16 +1374,11 @@ public class TicketController extends ControllerBase { */ @PostMapping("call/hangUp") public ApiResult hangUp(@Valid @RequestBody TicketCallHangUpRequest request) { - 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; +// TicketCall ticketCall = ticketCallService.getLast(request.getTicketId()); +// if (Objects.isNull(ticketCall)) return ApiResult.success(); if (request.getReject()) { AdminUser adminUser = adminUserService.getById(AdminUserUtil.getUserId()); - if (StrUtil.equals(request.getFrom(), "app")) { + if (StrUtil.equals(request.getFrom(), Constant.FROM_APP)) { uniPushService.send(new UniPushMessage() .setSenderId("admin-uid-" + adminUser.getId()) .setReceiverId("app-uid-" + request.getFromUserId()) @@ -1401,8 +1396,7 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallHangUpToApp(request.getTicketId(), request.getFromUserId(), adminUser); - flag=ticketCallJoinService.hangUp(request.getTicketId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, true); - }else if (StrUtil.equals(request.getFrom(), "admin")) { + } else if (StrUtil.equals(request.getFrom(), Constant.FROM_ADMIN)) { if (Objects.equals(request.getFromUserId(), AdminUserUtil.getUserId())){ Ticket ticket = ticketService.getById(request.getTicketId()); int handlerId= Integer.parseInt(StrUtil.split(ticket.getHandle(), ",").stream().findFirst().get()); @@ -1411,7 +1405,7 @@ public class TicketController extends ControllerBase { .setReceiverId("admin-uid-" + handlerId) .setSendData(new UniPushMessageBody() .setTitle("挂断视频通话") - .setContent(adminUser.getUserName() + "挂断了与您的视频通话") + .setContent(adminUser.getUserName() + "取消了与您的视频通话") .setPayload(new UniPushMessageCallPayload() .setTicketId(request.getTicketId()) .setUserId(adminUser.getId()) @@ -1423,7 +1417,6 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallCancelToAdmin(request.getTicketId(), handlerId, adminUser); - flag=ticketCallService.hangUp(request.getTicketId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, true); }else { uniPushService.send(new UniPushMessage() .setSenderId("admin-uid-" + adminUser.getId()) @@ -1442,19 +1435,12 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallHangUpToAdmin(request.getTicketId(), request.getFromUserId(), adminUser); - flag=ticketCallJoinService.hangUp(ticketCall.getId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, true); } } - }else { - if (StrUtil.equals(request.getFrom(), "app") || Objects.equals(request.getFromUserId(), AdminUserUtil.getUserId())) { - flag=ticketCallService.hangUp(request.getTicketId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, false); - }else { - flag=ticketCallJoinService.hangUp(ticketCall.getId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, false); - } } - if (flag){ +// if (ticketCallJoinService.hangUp(ticketCall.getId(), AdminUserUtil.getUserId(), Constant.FROM_ADMIN, request.getReject())) { ticketEventPublisher.publishTicketCallEndEvent(request.getTicketId()); - } +// } return ApiResult.success(); } } \ No newline at end of file diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/event/TicketCallEndEvent.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/event/TicketCallEndEvent.java index fbf067cb..7e88ebe3 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/event/TicketCallEndEvent.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/event/TicketCallEndEvent.java @@ -1,5 +1,7 @@ package com.nflg.mobilebroken.admin.event; +import cn.hutool.core.collection.CollectionUtil; +import com.nflg.mobilebroken.admin.service.ShengWangService; import com.nflg.mobilebroken.admin.service.SsePushService; import com.nflg.mobilebroken.common.constant.TicketState; import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO; @@ -9,7 +11,9 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; +import java.io.IOException; import java.time.Instant; +import java.util.concurrent.TimeUnit; public class TicketCallEndEvent extends ApplicationEvent implements ApplicationContextAware { @@ -17,6 +21,7 @@ public class TicketCallEndEvent extends ApplicationEvent implements ApplicationC private SsePushService ssePushService; private TicketChatService ticketChatService; + private ShengWangService shengWangService; public TicketCallEndEvent(Object source, Integer ticketId) { super(source); @@ -29,18 +34,21 @@ public class TicketCallEndEvent extends ApplicationEvent implements ApplicationC this.ticketChatService = applicationContext.getBean(TicketChatService.class); } - public void send(){ - ChatMessageDTO message = new ChatMessageDTO() - .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr()) - .setFrom("call") - .setTicketState(TicketState.Processing.getState()) - .setSenderId(0) - .setSenderName("通话助手") - .setContent("视频通话已结束") - .setCreateTime(Instant.now()); - ticketChatService.addMessage(ticketId, message); - //推送消息 - ssePushService.sendTicketMessageToAdmin(ticketId,message); - ssePushService.sendTicketMessageToApp(ticketId,message); + public void send() throws IOException, InterruptedException { + TimeUnit.SECONDS.sleep(2); + if (CollectionUtil.isEmpty(shengWangService.getChannelUsers("ticket-" + ticketId))) { + ChatMessageDTO message = new ChatMessageDTO() + .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr()) + .setFrom("call") + .setTicketState(TicketState.Processing.getState()) + .setSenderId(0) + .setSenderName("通话助手") + .setContent("视频通话已结束") + .setCreateTime(Instant.now()); + ticketChatService.addMessage(ticketId, message); + //推送消息 + ssePushService.sendTicketMessageToAdmin(ticketId, message); + ssePushService.sendTicketMessageToApp(ticketId, message); + } } } \ No newline at end of file diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/listener/TicketEventListener.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/listener/TicketEventListener.java index 8ed15aac..a1c714da 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/listener/TicketEventListener.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/listener/TicketEventListener.java @@ -5,6 +5,8 @@ import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import java.io.IOException; + @Component public class TicketEventListener { @@ -40,7 +42,7 @@ public class TicketEventListener { @Async @EventListener - public void handleTicketCallEndEvent(TicketCallEndEvent event) { + public void handleTicketCallEndEvent(TicketCallEndEvent event) throws IOException, InterruptedException { event.send(); } } diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/ShengWangService.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/ShengWangService.java index 727ea15d..1e7590fc 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/ShengWangService.java +++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/ShengWangService.java @@ -4,8 +4,7 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.nflg.mobilebroken.admin.pojo.dto.*; -import com.nflg.mobilebroken.common.pojo.dto.ShengWangChannelUserResponseDTO; +import com.nflg.mobilebroken.common.pojo.dto.*; import com.nflg.mobilebroken.common.util.VUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; 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 7acf0918..b7128c5a 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 @@ -1,10 +1,10 @@ package com.nflg.mobilebroken.admin.task; import cn.hutool.core.collection.CollectionUtil; -import com.nflg.mobilebroken.admin.pojo.dto.ShengWangChannelDTO; -import com.nflg.mobilebroken.admin.pojo.dto.ShengWangChannelInfoDTO; import com.nflg.mobilebroken.admin.service.ShengWangService; import com.nflg.mobilebroken.common.constant.Constant; +import com.nflg.mobilebroken.common.pojo.dto.ShengWangChannelDTO; +import com.nflg.mobilebroken.common.pojo.dto.ShengWangChannelInfoDTO; import com.nflg.mobilebroken.common.util.IdUtil; import com.nflg.mobilebroken.repository.entity.TicketCall; import com.nflg.mobilebroken.repository.entity.TicketCallJoin; diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/config/HttpClientConfig.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/config/HttpClientConfig.java new file mode 100644 index 00000000..041e72e1 --- /dev/null +++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/config/HttpClientConfig.java @@ -0,0 +1,19 @@ +package com.nflg.mobilebroken.cfs.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.net.http.HttpClient; +import java.time.Duration; + +@Configuration +public class HttpClientConfig { + + @Bean + public HttpClient getHttpClient() { + return HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .connectTimeout(Duration.ofSeconds(10)) + .build(); + } +} 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 d92e5c37..b4a7cce5 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 @@ -93,11 +93,11 @@ public class TicketController extends ControllerBase { @Resource private UniPushService uniPushService; - @Resource - private ITicketCallService ticketCallService; - - @Resource - private ITicketCallJoinService ticketCallJoinService; +// @Resource +// private ITicketCallService ticketCallService; +// +// @Resource +// private ITicketCallJoinService ticketCallJoinService; /** * 搜索设备 @@ -504,7 +504,7 @@ public class TicketController extends ControllerBase { VUtils.trueThrowBusinessError(!Objects.equals(AppUserUtil.getUserId(), ticket.getUserId())) .throwMessage("不是工单创建人无权限呼叫"); Integer handlerUserId = Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).findFirst().get(); - VUtils.trueThrowBusinessError(ticketCallService.isInCall(handlerUserId)).throwMessage("对方正在通话中"); +// VUtils.trueThrowBusinessError(ticketCallJoinService.isInCall(ticket.getId(), Constant.FROM_ADMIN, handlerUserId)).throwMessage("对方正在通话中"); AppUser appUser = appUserService.getById(ticket.getUserId()); uniPushService.send(new UniPushMessage() .setSenderId(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) @@ -523,7 +523,7 @@ public class TicketController extends ControllerBase { ) ); ssePushService.sendTicketCallToAdmin(appUser, handlerUserId, ticketId); - ticketCallService.add(ticketId, AppUserUtil.getUserId(),Constant.FROM_APP, handlerUserId, Constant.FROM_ADMIN); +// ticketCallService.add(ticketId, AppUserUtil.getUserId(),Constant.FROM_APP, handlerUserId, Constant.FROM_ADMIN); ticketEventPublisher.publishTicketCallBeginEvent(ticketId,appUser.getName()); return ApiResult.success(); } @@ -538,28 +538,28 @@ 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(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) - .setReceiverId("admin-uid-" + handlerUserId) - .setSendData(new UniPushMessageBody() - .setTitle("视频通话") - .setContent("您已加入别的通话中") - .setPayload(new UniPushMessageCallPayload() - .setTicketId(ticketId) - .setUserId(AppUserUtil.getUserId()) - .setCategory("ticketCallJoined") - .setFrom("app") - ) - ) - ); +// VUtils.trueThrowBusinessError(!StrUtil.equals(ticket.getUserPlatform(), AppUserUtil.getFrom()) +// || !Objects.equals(AppUserUtil.getUserId(), ticket.getUserId())) +// .throwMessage("不是创建人无法加入通话"); +// VUtils.trueThrowBusinessError(ticketCallJoinService.isInCall(ticket.getId(), Constant.FROM_APP, 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(ticket.getUserPlatform()+"-uid-" + ticket.getUserId()) +// .setReceiverId("admin-uid-" + handlerUserId) +// .setSendData(new UniPushMessageBody() +// .setTitle("视频通话") +// .setContent("您已加入别的通话中") +// .setPayload(new UniPushMessageCallPayload() +// .setTicketId(ticketId) +// .setUserId(AppUserUtil.getUserId()) +// .setCategory("ticketCallJoined") +// .setFrom("app") +// ) +// ) +// ); return ApiResult.success(); } @@ -569,9 +569,9 @@ public class TicketController extends ControllerBase { */ @PostMapping("call/hangUp") public ApiResult hangUp(@Valid @RequestBody TicketCallHangUpRequest request) { - TicketCall ticketCall = ticketCallService.getLast(request.getTicketId()); +// TicketCall ticketCall = ticketCallService.getLast(request.getTicketId()); if (request.getReject()) { - if (Objects.isNull(ticketCall)) return ApiResult.success(); +// if (Objects.isNull(ticketCall)) return ApiResult.success(); if (StrUtil.equals(request.getFrom(), Constant.FROM_APP) && Objects.equals(AppUserUtil.getUserId(), request.getFromUserId())) { AppUser appUser = appUserService.getById(AppUserUtil.getUserId()); Ticket ticket = ticketService.getById(request.getTicketId()); @@ -615,15 +615,9 @@ public class TicketController extends ControllerBase { ssePushService.sendTicketCallHangUpToAdmin(request.getTicketId(), request.getFromUserId(), appUser); } } - boolean flag; - if (StrUtil.equals(request.getFrom(), Constant.FROM_APP)) { - flag = ticketCallService.hangUp(ticketCall.getId(), AppUserUtil.getUserId(), Constant.FROM_APP, request.getReject()); - } else { - flag = ticketCallJoinService.hangUp(ticketCall.getId(), AppUserUtil.getUserId(), Constant.FROM_APP, request.getReject()); - } - if (flag) { +// if (ticketCallJoinService.hangUp(ticketCall.getId(), AppUserUtil.getUserId(), Constant.FROM_APP, request.getReject())) { ticketEventPublisher.publishTicketCallEndEvent(request.getTicketId()); - } +// } return ApiResult.success(); } } diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/event/TicketCallEndEvent.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/event/TicketCallEndEvent.java index 943d67c2..b9c203a4 100644 --- a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/event/TicketCallEndEvent.java +++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/event/TicketCallEndEvent.java @@ -1,5 +1,7 @@ package com.nflg.mobilebroken.cfs.event; +import cn.hutool.core.collection.CollectionUtil; +import com.nflg.mobilebroken.cfs.service.ShengWangService; import com.nflg.mobilebroken.cfs.service.SsePushService; import com.nflg.mobilebroken.common.constant.TicketState; import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO; @@ -9,7 +11,9 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; +import java.io.IOException; import java.time.Instant; +import java.util.concurrent.TimeUnit; public class TicketCallEndEvent extends ApplicationEvent implements ApplicationContextAware { @@ -17,6 +21,7 @@ public class TicketCallEndEvent extends ApplicationEvent implements ApplicationC private SsePushService ssePushService; private TicketChatService ticketChatService; + private ShengWangService shengWangService; public TicketCallEndEvent(Object source,Integer ticketId) { super(source); @@ -27,20 +32,24 @@ public class TicketCallEndEvent extends ApplicationEvent implements ApplicationC public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ssePushService = applicationContext.getBean(SsePushService.class); this.ticketChatService = applicationContext.getBean(TicketChatService.class); + this.shengWangService = applicationContext.getBean(ShengWangService.class); } - public void send(){ - ChatMessageDTO message = new ChatMessageDTO() - .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr()) - .setFrom("call") - .setTicketState(TicketState.Processing.getState()) - .setSenderId(0) - .setSenderName("通话助手") - .setContent("视频通话已结束") - .setCreateTime(Instant.now()); - ticketChatService.addMessage(ticketId, message); - //推送消息 - ssePushService.sendTicketMessageToAdmin(ticketId,message); - ssePushService.sendTicketMessageToApp(ticketId,message); + public void send() throws IOException, InterruptedException { + TimeUnit.SECONDS.sleep(2); + if (CollectionUtil.isEmpty(shengWangService.getChannelUsers("ticket-" + ticketId))) { + ChatMessageDTO message = new ChatMessageDTO() + .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr()) + .setFrom("call") + .setTicketState(TicketState.Processing.getState()) + .setSenderId(0) + .setSenderName("通话助手") + .setContent("视频通话已结束") + .setCreateTime(Instant.now()); + ticketChatService.addMessage(ticketId, message); + //推送消息 + ssePushService.sendTicketMessageToAdmin(ticketId, message); + ssePushService.sendTicketMessageToApp(ticketId, message); + } } } \ No newline at end of file diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/listener/TicketEventListener.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/listener/TicketEventListener.java index a9394044..155755f2 100644 --- a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/listener/TicketEventListener.java +++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/listener/TicketEventListener.java @@ -5,6 +5,8 @@ import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import java.io.IOException; + @Component public class TicketEventListener { @@ -46,7 +48,7 @@ public class TicketEventListener { @Async @EventListener - public void handleTicketCallEndEvent(TicketCallEndEvent event) { + public void handleTicketCallEndEvent(TicketCallEndEvent event) throws IOException, InterruptedException { event.send(); } } diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/ShengWangService.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/ShengWangService.java new file mode 100644 index 00000000..cdd1ac1d --- /dev/null +++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/ShengWangService.java @@ -0,0 +1,159 @@ +package com.nflg.mobilebroken.cfs.service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nflg.mobilebroken.common.pojo.dto.*; +import com.nflg.mobilebroken.common.util.VUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Base64; +import java.util.List; + +/** + * 声网服务 + */ +@Slf4j +@Component +@RefreshScope +public class ShengWangService { + + private static final String baseUrl = "https://api.sd-rtn.com/dev"; + + @Resource + private HttpClient httpClient; + + @Resource + private ObjectMapper objectMapper; + + @Value("${shengwang.rtc.appId}") + private String appId; + + @Value("${shengwang.rtc.customerKey}") + private String customerKey; + + @Value("${shengwang.rtc.customerSecret}") + private String customerSecret; + + public ShengWangChannelDTO getAllChannels() throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder() + .GET() + .header("Authorization", generateAuthorization(customerKey, customerSecret)) + .uri(URI.create(baseUrl + "/v1/channel/" + appId)) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("getAllChannels Response:" + response.body()); + VUtils.trueThrowBusinessError(response.statusCode() != 200).throwMessage("请求失败"); + ShengWangResponse result = objectMapper.readValue(response.body(), new TypeReference<>() { + }); + VUtils.trueThrowBusinessError(!result.isSuccess()).throwMessage("获取频道信息失败"); + return result.getData(); + } + + /** + * 创建规则 + * @param channelName 频道名称 + * @param uid 用户ID + * @param time 封禁时间,单位为分钟,取值范围为 [1,1440]。当设置的值为 0 时,表示不封禁。服务端会对频道内符合设定规则的用户进行下线一次的操作。用户可以重新登录进入频道。 + * @param privileges 要封禁的用户权限,取值包括【join_channel】加入频道,表示禁止用户加入频道或将用户踢出频道。【publish_audio】发送音频,表示禁止用户发送音频流。可以与 publish_video 同时设置,表示禁止用户发送音视流和视频流。【publish_video】发送视频,表示禁止用户发送视频流。可以与 publish_audio 同时设置,表示禁止用户发送音视流和视频流。 + * @return 规则ID + */ + public Long addKickingRule(String channelName, Integer uid, Integer time, List privileges) throws Exception { + JSONObject json = new JSONObject(); + json.putOpt("appid", appId); + json.putOpt("cname", channelName); + json.putOpt("uid", uid); + json.putOpt("time", time); + json.putOpt("privileges", privileges); + HttpRequest request = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(json.toString())) + .header("Authorization", generateAuthorization(customerKey, customerSecret)) + .header("Content-Type", "application/json") + .uri(URI.create(baseUrl + "/v1/kicking-rule")) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("addKickingRule Response:" + response.body()); + VUtils.trueThrowBusinessError(response.statusCode() != 200).throwMessage("请求失败"); + ShengWangKickingRuleAddDTO result = objectMapper.readValue(response.body(), ShengWangKickingRuleAddDTO.class); + VUtils.trueThrowBusinessError(!StrUtil.equals(result.getStatus(), "success")).throwMessage("创建规则失败"); + return result.getId(); + } + + /** + * 获取规则 + * @return 规则列表 + */ + public List getKickingRule() throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder() + .GET() + .header("Authorization", generateAuthorization(customerKey, customerSecret)) + .uri(URI.create(baseUrl + "/v1/kicking-rule?appid=" + appId)) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("getKickingRule Response:" + response.body()); + VUtils.trueThrowBusinessError(response.statusCode() != 200).throwMessage("请求失败"); + ShengWangKickingRuleListResponseDTO result = objectMapper.readValue(response.body(), ShengWangKickingRuleListResponseDTO.class); + VUtils.trueThrowBusinessError(!StrUtil.equals(result.getStatus(), "success")).throwMessage("获取规则失败"); + return result.getRules(); + } + + /** + * 删除规则 + * @param id 规则ID + */ + public void deleteKickingRule(long id) throws IOException, InterruptedException { + JSONObject json = new JSONObject(); + json.putOpt("appid", appId); + json.putOpt("id", id); + HttpRequest request = HttpRequest.newBuilder() + .method("DELETE", HttpRequest.BodyPublishers.ofString(json.toString())) + .header("Authorization", generateAuthorization(customerKey, customerSecret)) + .header("Content-Type", "application/json") + .uri(URI.create(baseUrl + "/v1/kicking-rule")) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("deleteKickingRule Response:" + response.body()); + VUtils.trueThrowBusinessError(response.statusCode() == 404).throwMessage("规则不存在"); + VUtils.trueThrowBusinessError(response.statusCode() != 200).throwMessage("请求失败"); + ShengWangKickingRuleAddDTO result = objectMapper.readValue(response.body(), ShengWangKickingRuleAddDTO.class); + VUtils.trueThrowBusinessError(!StrUtil.equals(result.getStatus(), "success")).throwMessage("删除规则失败"); + } + + /** + * 生成鉴权信息 + * @param customerKey 客户ID + * @param customerSecret 客户密钥 + * @return 鉴权信息 + */ + private String generateAuthorization(String customerKey, String customerSecret) { + // 拼接客户 ID 和客户密钥并使用 base64 编码 + String plainCredentials = customerKey + ":" + customerSecret; + String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes())); + // 创建 authorization header + return "Basic " + base64Credentials; + } + + public List getChannelUsers(String channelName) throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder() + .GET() + .header("Authorization", generateAuthorization(customerKey, customerSecret)) + .uri(URI.create(baseUrl + "/v1/channel/user/" + appId + "/" + channelName)) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("getChannelUsers Response:" + response.body()); + VUtils.trueThrowBusinessError(response.statusCode() != 200).throwMessage("请求失败"); + ShengWangChannelUserResponseDTO result = objectMapper.readValue(response.body(), ShengWangChannelUserResponseDTO.class); + VUtils.trueThrowBusinessError(!result.getSuccess()).throwMessage("获取频道用户失败"); + return result.getData().isChannel_exist() ? result.getData().getUsers() : null; + } +} diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelDTO.java similarity index 87% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelDTO.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelDTO.java index f446a0fa..5324f13e 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelDTO.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelDTO.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelInfoDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelInfoDTO.java similarity index 87% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelInfoDTO.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelInfoDTO.java index a446bd85..d1c9155e 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangChannelInfoDTO.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangChannelInfoDTO.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleAddDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleAddDTO.java similarity index 72% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleAddDTO.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleAddDTO.java index 1f9ce1b9..39e514dd 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleAddDTO.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleAddDTO.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import lombok.Data; diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListItemDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListItemDTO.java similarity index 97% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListItemDTO.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListItemDTO.java index e1c1979d..a62128de 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListItemDTO.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListItemDTO.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import cn.hutool.core.date.DatePattern; import cn.hutool.core.util.StrUtil; diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListResponseDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListResponseDTO.java similarity index 80% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListResponseDTO.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListResponseDTO.java index cfa66bb5..833acd68 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangKickingRuleListResponseDTO.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangKickingRuleListResponseDTO.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import lombok.Data; diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangResponse.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangResponse.java similarity index 71% rename from nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangResponse.java rename to nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangResponse.java index 8640e5bf..53b3a704 100644 --- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/pojo/dto/ShengWangResponse.java +++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/ShengWangResponse.java @@ -1,4 +1,4 @@ -package com.nflg.mobilebroken.admin.pojo.dto; +package com.nflg.mobilebroken.common.pojo.dto; import lombok.Data;