From a4a0e8df26bb039ef1eff488c24608ec4a6d6686 Mon Sep 17 00:00:00 2001
From: cb <275647614@qq.com>
Date: Tue, 23 Sep 2025 12:22:32 +0800
Subject: [PATCH] no message
---
.../customer/CustomerServiceController.java | 35 +++--
.../templates/customer/service/index.html | 136 ++++++++++++++----
.../ruoyi/framework/config/ShiroConfig.java | 9 +-
.../impl/CustomerServiceServiceImpl.java | 65 ++++++++-
.../system/domain/ManualServiceSessions.java | 29 ++++
.../com/ruoyi/system/domain/UserSessions.java | 15 ++
.../system/ManualServiceSessionsMapper.xml | 38 ++++-
.../mapper/system/UserSessionsMapper.xml | 30 ++--
8 files changed, 296 insertions(+), 61 deletions(-)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/CustomerServiceController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/CustomerServiceController.java
index 3e814628..2f6604bd 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/CustomerServiceController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/customer/CustomerServiceController.java
@@ -1,6 +1,7 @@
package com.ruoyi.web.controller.customer;
import java.util.List;
+import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@@ -134,23 +135,37 @@ public class CustomerServiceController extends BaseController
*/
@PostMapping("/transfer")
@ResponseBody
- public AjaxResult transferToManual(Long sessionId, String reason)
+ public AjaxResult transferToManual(Long sessionId, String reason, HttpServletRequest request)
{
+ logger.info("[转人工服务] 收到转人工请求 - sessionId: {}, reason: {}", sessionId, reason);
+ logger.info("[转人工服务] 请求头信息 - Authorization: {}, Content-Type: {}",
+ request.getHeader("Authorization"), request.getHeader("Content-Type"));
+
try {
+ // 获取当前用户ID
+ // Long currentUserId = getUserId();
+ // logger.info("[转人工服务] 当前用户ID: {}", currentUserId);
+
ManualServiceSessions manualSession = new ManualServiceSessions();
manualSession.setSessionId(sessionId);
manualSession.setReason(reason);
- manualSession.setStatus("PENDING");
- manualSession.setCreateBy(getLoginName());
+ manualSession.setStatus("0"); // 0-待处理
+ manualSession.setCreateBy(sessionId+"");
+
+ logger.info("[转人工服务] 准备插入数据库 - 转人工会话对象: {}", manualSession);
int result = customerServiceService.createManualServiceRequest(manualSession);
+ logger.info("[转人工服务] 数据库插入结果: {}", result);
+
if (result > 0) {
+ logger.info("[转人工服务] 转人工请求提交成功");
return AjaxResult.success("转人工请求已提交");
} else {
+ logger.error("[转人工服务] 转人工请求提交失败 - 数据库插入返回0");
return AjaxResult.error("转人工请求提交失败");
}
} catch (Exception e) {
- logger.error("转人工服务失败", e);
+ logger.error("[转人工服务] 转人工服务异常", e);
return AjaxResult.error("转人工服务失败: " + e.getMessage());
}
}
@@ -180,10 +195,10 @@ public class CustomerServiceController extends BaseController
{
try {
ManualServiceSessions manualSession = new ManualServiceSessions();
- manualSession.setUserId(requestId);
- manualSession.setStatus("ACCEPTED");
+ manualSession.setManualSessionId(requestId); // 设置主键ID
+ manualSession.setStatus("1"); // 1-已接受
manualSession.setServiceId(getUserId());
- manualSession.setUpdateBy(getLoginName());
+ manualSession.setUpdateBy(requestId+"");
int result = customerServiceService.updateManualServiceRequest(manualSession);
if (result > 0) {
@@ -206,10 +221,10 @@ public class CustomerServiceController extends BaseController
{
try {
ManualServiceSessions manualSession = new ManualServiceSessions();
- manualSession.setUserId(requestId);
- manualSession.setStatus("REJECTED");
+ manualSession.setManualSessionId(requestId); // 设置主键ID
+ manualSession.setStatus("2"); // 2-已拒绝
manualSession.setServiceId(getUserId());
- manualSession.setUpdateBy(getLoginName());
+ manualSession.setUpdateBy(requestId+"");
int result = customerServiceService.updateManualServiceRequest(manualSession);
if (result > 0) {
diff --git a/ruoyi-admin/src/main/resources/templates/customer/service/index.html b/ruoyi-admin/src/main/resources/templates/customer/service/index.html
index ab6f8ca2..8d3ef705 100644
--- a/ruoyi-admin/src/main/resources/templates/customer/service/index.html
+++ b/ruoyi-admin/src/main/resources/templates/customer/service/index.html
@@ -284,50 +284,100 @@
// 初始化WebSocket连接
function initWebSocket() {
+ console.log("[DEBUG] 开始初始化WebSocket连接...");
+
if (typeof(WebSocket) == "undefined") {
- console.log("您的浏览器不支持WebSocket");
+ console.error("[ERROR] 您的浏览器不支持WebSocket");
return;
}
- var wsUrl = "ws://" + window.location.host + "/websocket/customer-service";
- wsConnection = new WebSocket(wsUrl);
+ var wsUrl = "ws://bwy.opsoul.com/websocket/customer-service";
+ console.log("[DEBUG] WebSocket连接URL:", wsUrl);
+
+ try {
+ wsConnection = new WebSocket(wsUrl);
+ console.log("[DEBUG] WebSocket对象创建成功");
+ } catch (e) {
+ console.error("[ERROR] WebSocket对象创建失败:", e);
+ return;
+ }
wsConnection.onopen = function() {
- console.log("WebSocket连接已建立");
+ console.log("[SUCCESS] WebSocket连接已建立");
+ console.log("[DEBUG] WebSocket readyState:", wsConnection.readyState);
};
wsConnection.onmessage = function(event) {
- var message = JSON.parse(event.data);
- handleWebSocketMessage(message);
+ console.log("[DEBUG] 收到WebSocket原始消息:", event.data);
+ try {
+ var message = JSON.parse(event.data);
+ console.log("[DEBUG] 解析后的消息对象:", message);
+ handleWebSocketMessage(message);
+ } catch (e) {
+ console.error("[ERROR] 解析WebSocket消息失败:", e, "原始数据:", event.data);
+ }
};
- wsConnection.onclose = function() {
- console.log("WebSocket连接已关闭");
+ wsConnection.onclose = function(event) {
+ console.log("[WARN] WebSocket连接已关闭", {
+ code: event.code,
+ reason: event.reason,
+ wasClean: event.wasClean
+ });
// 尝试重连
+ console.log("[DEBUG] 5秒后尝试重连WebSocket...");
setTimeout(initWebSocket, 5000);
};
wsConnection.onerror = function(error) {
- console.log("WebSocket连接错误:", error);
+ console.error("[ERROR] WebSocket连接错误:", error);
+ console.log("[DEBUG] WebSocket readyState:", wsConnection ? wsConnection.readyState : 'undefined');
};
}
// 处理WebSocket消息
function handleWebSocketMessage(message) {
+ console.log('[DEBUG] 开始处理WebSocket消息:', message);
+ console.log('[DEBUG] 消息类型:', message.type);
+
switch(message.type) {
case 'NEW_MESSAGE':
+ // 处理新消息
+ console.log('[DEBUG] 处理新消息:', message);
if (message.sessionId == currentSessionId) {
appendMessage(message.content, false, message.timestamp);
+ console.log('[DEBUG] 新消息已添加到当前会话');
+ } else {
+ console.log('[DEBUG] 新消息不属于当前会话,sessionId:', message.sessionId, '当前会话:', currentSessionId);
}
loadSessionList(); // 刷新会话列表
break;
case 'SESSION_UPDATE':
+ // 处理会话更新
+ console.log('[DEBUG] 处理会话更新:', message);
loadSessionList();
break;
case 'MANUAL_REQUEST':
+ // 处理转人工请求
+ console.log('[SUCCESS] 收到转人工请求通知:', message);
+ console.log('[DEBUG] 开始刷新转人工请求列表...');
loadManualRequests();
+ // 显示通知
+ console.log('[DEBUG] 显示转人工请求通知...');
+ if (typeof $.modal !== 'undefined') {
+ $.modal.msg('收到新的转人工请求');
+ console.log('[DEBUG] 使用$.modal显示通知');
+ } else {
+ alert('收到新的转人工请求');
+ console.log('[DEBUG] 使用alert显示通知');
+ }
+ break;
+ default:
+ console.warn('[WARN] 未知的消息类型:', message.type, '完整消息:', message);
break;
}
+
+ console.log('[DEBUG] WebSocket消息处理完成');
}
// 加载会话列表
@@ -474,28 +524,54 @@
// 加载转人工请求列表
function loadManualRequests() {
- $.get('/customer/service/manual-requests', function(data) {
- var html = '';
- if (data.code === 0 && data.data) {
- data.data.forEach(function(request) {
- html += '
';
- html += '
' + (request.customerName || '访客' + request.sessionId) + '
';
- html += '
' + (request.reason || '无') + '
';
- html += '
' + formatTime(request.createTime) + '
';
- html += '
';
- html += ' ';
- html += ' ';
- html += '
';
- html += '
';
+ console.log('开始加载转人工请求列表...');
+
+ $.get('/customer/service/manual-requests')
+ .done(function(data) {
+ console.log('转人工请求API响应:', data);
+
+ if (data.code === 0) {
+ var html = '';
+ var requests = data.data || [];
+
+ console.log('转人工请求数量:', requests.length);
+
+ if (requests.length === 0) {
+ html = '暂无转人工请求
';
+ } else {
+ requests.forEach(function(request, index) {
+ console.log('处理转人工请求 ' + (index + 1) + ':', request);
+ html += '';
+ html += '
';
+ html += '
会话ID: ' + request.sessionId + '
';
+ html += '
原因: ' + (request.reason || '无') + '
';
+ html += '
' + formatTime(request.createTime) + '
';
+ html += '
';
+ html += '
';
+ html += ' ';
+ html += ' ';
+ html += '
';
+ html += '
';
+ });
+ }
+
+ $('#manualRequestContainer').html(html);
+ $('#manualRequestCount').text(requests.length);
+ console.log('转人工请求列表渲染完成,容器内容:', $('#manualRequestContainer').html());
+ } else {
+ console.error('转人工请求API返回错误:', data.msg);
+ $('#manualRequestContainer').html('加载失败: ' + data.msg + '
');
+ }
+ })
+ .fail(function(xhr, status, error) {
+ console.error('转人工请求API调用失败:', {
+ status: xhr.status,
+ statusText: xhr.statusText,
+ error: error,
+ response: xhr.responseText
});
- $('#manualRequestCount').text(data.data.length);
- }
- $('#manualRequestContainer').html(html);
- });
+ $('#manualRequestContainer').html('网络错误,请稍后重试
');
+ });
}
// 接受转人工请求
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java
index 9043ca07..bd3cd8e3 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java
@@ -306,8 +306,13 @@ public class ShiroConfig
filterChainDefinitionMap.put("/system/material/app/**", "anon");
// 客服回复接口
filterChainDefinitionMap.put("/system/customerServiceReply/app/**", "anon");
-
- filterChainDefinitionMap.put("/system/chatHistory/app/**", "anon");
+ // 聊天记录接口
+ filterChainDefinitionMap.put("/system/chatHistory/**", "anon");
+
+ // 客服相关接口
+ filterChainDefinitionMap.put("/customer/service/**", "anon");
+ // WebSocket连接
+ filterChainDefinitionMap.put("/websocket/**", "anon");
// 退出 logout地址,shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
diff --git a/ruoyi-system/src/main/java/com/ruoyi/customer/service/impl/CustomerServiceServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/customer/service/impl/CustomerServiceServiceImpl.java
index 4429c18f..1fbc67f8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/customer/service/impl/CustomerServiceServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/customer/service/impl/CustomerServiceServiceImpl.java
@@ -155,9 +155,68 @@ public class CustomerServiceServiceImpl implements ICustomerServiceService
@Override
public int createManualServiceRequest(ManualServiceSessions manualServiceSessions)
{
+ System.out.println("[DEBUG] 开始创建转人工服务请求 - sessionId: " + manualServiceSessions.getSessionId() + ", reason: " + manualServiceSessions.getReason());
+
manualServiceSessions.setCreateTime(DateUtils.getNowDate());
- manualServiceSessions.setStatus("pending");
- return manualServiceSessionsMapper.insertManualServiceSessions(manualServiceSessions);
+ manualServiceSessions.setStatus("0"); // 0-待处理
+
+ System.out.println("[DEBUG] 准备插入数据库 - 数据: " + manualServiceSessions.toString());
+ int result = manualServiceSessionsMapper.insertManualServiceSessions(manualServiceSessions);
+ System.out.println("[DEBUG] 数据库插入结果: " + result);
+
+ // 如果插入成功,通知所有在线客服
+ if (result > 0) {
+ try {
+ System.out.println("[DEBUG] 数据库插入成功,开始发送WebSocket通知");
+
+ // 创建WebSocket消息
+ com.alibaba.fastjson.JSONObject message = new com.alibaba.fastjson.JSONObject();
+ message.put("type", "MANUAL_REQUEST");
+ message.put("sessionId", manualServiceSessions.getSessionId());
+ message.put("reason", manualServiceSessions.getReason());
+ message.put("timestamp", System.currentTimeMillis());
+
+ System.out.println("[DEBUG] WebSocket消息内容: " + message.toJSONString());
+
+ // 通过反射获取WebSocket类并发送广播消息
+ Class> webSocketClass = Class.forName("com.ruoyi.web.websocket.CustomerServiceWebSocket");
+ java.lang.reflect.Method getWebSocketMapMethod = webSocketClass.getMethod("getWebSocketMap");
+ @SuppressWarnings("unchecked")
+ java.util.concurrent.ConcurrentHashMap webSocketMap =
+ (java.util.concurrent.ConcurrentHashMap) getWebSocketMapMethod.invoke(null);
+
+ System.out.println("[DEBUG] 当前在线WebSocket连接数: " + webSocketMap.size());
+
+ // 向所有在线客服发送通知
+ int successCount = 0;
+ int failCount = 0;
+ for (String key : webSocketMap.keySet()) {
+ Object webSocket = webSocketMap.get(key);
+ try {
+ System.out.println("[DEBUG] 向WebSocket连接发送消息: " + key);
+ java.lang.reflect.Method sendMessageMethod = webSocket.getClass().getMethod("sendMessage", String.class);
+ sendMessageMethod.invoke(webSocket, message.toJSONString());
+ successCount++;
+ System.out.println("[DEBUG] 消息发送成功: " + key);
+ } catch (Exception e) {
+ failCount++;
+ System.err.println("[DEBUG] 向WebSocket连接发送消息失败: " + key + ", 错误: " + e.getMessage());
+ }
+ }
+
+ System.out.println("[DEBUG] WebSocket通知发送完成 - 成功: " + successCount + ", 失败: " + failCount);
+
+ } catch (Exception e) {
+ // 记录日志但不影响主要业务流程
+ System.err.println("[DEBUG] 发送WebSocket通知失败: " + e.getMessage());
+ e.printStackTrace();
+ }
+ } else {
+ System.err.println("[DEBUG] 数据库插入失败,不发送WebSocket通知");
+ }
+
+ System.out.println("[DEBUG] 创建转人工服务请求完成 - 返回结果: " + result);
+ return result;
}
/**
@@ -182,7 +241,7 @@ public class CustomerServiceServiceImpl implements ICustomerServiceService
public List getPendingManualRequests()
{
ManualServiceSessions manualServiceSessions = new ManualServiceSessions();
- manualServiceSessions.setStatus("pending");
+ manualServiceSessions.setStatus("0"); // 0-待处理
return manualServiceSessionsMapper.selectManualServiceSessionsList(manualServiceSessions);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ManualServiceSessions.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ManualServiceSessions.java
index 2f9e3282..0ac1e8f0 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ManualServiceSessions.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ManualServiceSessions.java
@@ -32,6 +32,15 @@ public class ManualServiceSessions extends BaseEntity
@Excel(name = "客服ID")
private Long serviceId;
+ /** 客服人员 */
+ @Excel(name = "客服人员")
+ private String serviceStaff;
+
+ /** 开始时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date startTime;
+
/** 转人工请求时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "转人工请求时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@@ -99,6 +108,24 @@ public class ManualServiceSessions extends BaseEntity
{
return serviceId;
}
+ public void setServiceStaff(String serviceStaff)
+ {
+ this.serviceStaff = serviceStaff;
+ }
+
+ public String getServiceStaff()
+ {
+ return serviceStaff;
+ }
+ public void setStartTime(Date startTime)
+ {
+ this.startTime = startTime;
+ }
+
+ public Date getStartTime()
+ {
+ return startTime;
+ }
public void setRequestTime(Date requestTime)
{
this.requestTime = requestTime;
@@ -170,6 +197,8 @@ public class ManualServiceSessions extends BaseEntity
.append("sessionId", getSessionId())
.append("userId", getUserId())
.append("serviceId", getServiceId())
+ .append("serviceStaff", getServiceStaff())
+ .append("startTime", getStartTime())
.append("requestTime", getRequestTime())
.append("acceptTime", getAcceptTime())
.append("endTime", getEndTime())
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSessions.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSessions.java
index 5a5f75a5..e2321dac 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSessions.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSessions.java
@@ -43,6 +43,10 @@ public class UserSessions extends BaseEntity
@Excel(name = "最后活动时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date lastActivity;
+ /** 会话令牌 */
+ @Excel(name = "会话令牌")
+ private String sessionToken;
+
public void setSessionId(Long sessionId)
{
this.sessionId = sessionId;
@@ -98,6 +102,16 @@ public class UserSessions extends BaseEntity
return lastActivity;
}
+ public void setSessionToken(String sessionToken)
+ {
+ this.sessionToken = sessionToken;
+ }
+
+ public String getSessionToken()
+ {
+ return sessionToken;
+ }
+
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -107,6 +121,7 @@ public class UserSessions extends BaseEntity
.append("sessionEnd", getSessionEnd())
.append("status", getStatus())
.append("lastActivity", getLastActivity())
+ .append("sessionToken", getSessionToken())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.toString();
diff --git a/ruoyi-system/src/main/resources/mapper/system/ManualServiceSessionsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ManualServiceSessionsMapper.xml
index 694b6b97..95a721c3 100644
--- a/ruoyi-system/src/main/resources/mapper/system/ManualServiceSessionsMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/ManualServiceSessionsMapper.xml
@@ -5,19 +5,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-
+
+
+
+
+
+
+
- select id, session_id, user_id, service_staff, start_time, end_time, status, create_time, update_time from manual_service_sessions
+ select id, session_id, user_id, service_id, service_staff, start_time, end_time, status, request_time, accept_time, reason, rating, feedback, create_time, update_time from manual_service_sessions
-
+
insert into manual_service_sessions
session_id,
user_id,
+ service_id,
service_staff,
start_time,
end_time,
status,
+ request_time,
+ accept_time,
+ reason,
+ rating,
+ feedback,
create_time,
update_time,
#{sessionId},
#{userId},
+ #{serviceId},
#{serviceStaff},
#{startTime},
#{endTime},
#{status},
+ #{requestTime},
+ #{acceptTime},
+ #{reason},
+ #{rating},
+ #{feedback},
#{createTime},
#{updateTime},
@@ -64,24 +82,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
session_id = #{sessionId},
user_id = #{userId},
+ service_id = #{serviceId},
service_staff = #{serviceStaff},
start_time = #{startTime},
end_time = #{endTime},
status = #{status},
+ request_time = #{requestTime},
+ accept_time = #{acceptTime},
+ reason = #{reason},
+ rating = #{rating},
+ feedback = #{feedback},
create_time = #{createTime},
update_time = #{updateTime},
- where id = #{id}
+ where id = #{manualSessionId}
- delete from manual_service_sessions where id = #{id}
+ delete from manual_service_sessions where id = #{manualSessionId}
delete from manual_service_sessions where id in
-
- #{id}
+
+ #{manualSessionId}
diff --git a/ruoyi-system/src/main/resources/mapper/system/UserSessionsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UserSessionsMapper.xml
index 698f5be9..a3c1e2f6 100644
--- a/ruoyi-system/src/main/resources/mapper/system/UserSessionsMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/UserSessionsMapper.xml
@@ -6,15 +6,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-
-
-
-
-
+
+
+
+
+
+
+
+
- select session_id, user_id, session_token, create_time, update_time, status from user_sessions
+ select session_id, user_id, session_start, session_end, last_activity, session_token, status, create_time, update_time from user_sessions
@@ -53,10 +62,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update user_sessions
user_id = #{userId},
+ session_start = #{sessionStart},
+ session_end = #{sessionEnd},
+ last_activity = #{lastActivity},
session_token = #{sessionToken},
+ status = #{status},
create_time = #{createTime},
update_time = #{updateTime},
- status = #{status},
where session_id = #{sessionId}