diff --git a/mining-pool/.env.development b/mining-pool/.env.development
index 9f360fd..40adac6 100644
--- a/mining-pool/.env.development
+++ b/mining-pool/.env.development
@@ -5,8 +5,8 @@ VUE_APP_TITLE = m2pool
ENV = 'development'
#开发环境
-VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
-# VUE_APP_BASE_API = 'http://10.168.2.150:8101/'
+# VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
+ VUE_APP_BASE_API = 'http://10.168.2.150:8101/'
VUE_APP_BASE_URL = 'https://test.m2pool.com/'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/mining-pool/src/api/customerService.js b/mining-pool/src/api/customerService.js
index 9ff785d..6558277 100644
--- a/mining-pool/src/api/customerService.js
+++ b/mining-pool/src/api/customerService.js
@@ -58,11 +58,11 @@ export function getUpdateRoom(data) {
//图根据当前用户邮箱查询聊天室id
-export function getUserid() {
+export function getUserid(data) {
return request({
url: `chat/rooms/find/room/by/userid`,
- method: 'get',
-
+ method: 'post',
+ data
})
}
diff --git a/mining-pool/src/components/ChatWidget.vue b/mining-pool/src/components/ChatWidget.vue
index 3f7d644..e2f8517 100644
--- a/mining-pool/src/components/ChatWidget.vue
+++ b/mining-pool/src/components/ChatWidget.vue
@@ -220,10 +220,16 @@ export default {
cachedMessages: {}, // 缓存各聊天室的消息
isMinimized: false, // 区分最小化和关闭状态
+
+ reconnectAttempts: 0,
+ maxReconnectAttempts: 5,
+ reconnectInterval: 5000, // 5秒
+ isReconnecting: false,
};
},
-
+
async created() {
+ this.determineUserType();
// 页面加载时立即获取用户信息
await this.initChatSystem();
},
@@ -247,7 +253,7 @@ export default {
async initChatSystem() {
try {
// 获取用户ID和未读消息数
- const userData = await this.fetchUserid();
+ const userData = await this.fetchUserid({ email: this.userEmail });
if (userData) {
this.roomId = userData.id;
this.receivingEmail = userData.userEmail;
@@ -273,7 +279,7 @@ export default {
determineUserType() {
try {
const token = localStorage.getItem("token");
-
+ console.log("token", token);
if (!token) {
// 游客身份
this.userType = 0;
@@ -293,11 +299,13 @@ export default {
if (userInfo.roleKey === "customer_service") {
// 客服用户
this.userType = 2;
+ this.userEmail = "";
} else {
// 登录用户
this.userType = 1;
+ this.userEmail = email;
}
- this.userEmail = email;
+
} catch (parseError) {
console.error("解析用户信息失败:", parseError);
// 解析失败时默认为游客
@@ -317,68 +325,124 @@ export default {
},
// 添加订阅消息的方法
- subscribeToPersonalMessages() {
- if (!this.stompClient || !this.isWebSocketConnected) return;
+ subscribeToPersonalMessages() {
+ if (!this.stompClient || !this.isWebSocketConnected) return;
- try {
- // 订阅个人消息频道
- this.stompClient.subscribe(
- `/user/queue/${this.userEmail}`,
- this.onMessageReceived,
- {
- id: `chat_${this.userEmail}`,
- }
- );
-
- console.log("成功订阅消息频道:", `/user/queue/${this.userEmail}`);
- } catch (error) {
- console.error("订阅消息失败:", error);
- this.$message.error("消息订阅失败,可能无法接收新消息");
- }
- },
+ try {
+ // 订阅个人消息频道
+ this.stompClient.subscribe(
+ `/sub/queue/user/${this.userEmail}`,
+ this.onMessageReceived,
+ // {
+ // id: `chat_${this.userEmail}`,
+ // }
+ );
+ console.log("成功订阅消息频道:", `/sub/queue/user/${this.userEmail}`);
+ } catch (error) {
+ console.error("订阅消息失败:", error);
+ this.$message.error("消息订阅失败,可能无法接收新消息");
+ }
+ },
// 连接 WebSocket
connectWebSocket() {
- if (this.isWebSocketConnected) return;
+ if (this.isWebSocketConnected || this.isReconnecting) return;
- this.connectionStatus = "connecting";
- try {
- const wsUrl = `${process.env.VUE_APP_BASE_API}chat/ws`;
- this.stompClient = Stomp.client(wsUrl);
+ this.connectionStatus = "connecting";
+ this.isReconnecting = true;
- const headers = {
- email: this.userEmail,
- type: this.userType,
- };
+ try {
+ const wsUrl = `${process.env.VUE_APP_BASE_API}chat/ws`;
+ this.stompClient = Stomp.client(wsUrl);
+ // 配置 STOMP 客户端参数
+ this.stompClient.splitLargeFrames = true; // 启用大型消息帧分割
+ // 添加详细的调试日志
+ // this.stompClient.debug = (str) => {
+ // console.log("STOMP Debug:", str);
+ // // 记录连接状态变化
+ // if (str.includes("CONNECTED")) {
+ // console.log("WebSocket 连接成功");
+ // this.isWebSocketConnected = true;
+ // this.connectionStatus = "connected";
+ // this.reconnectAttempts = 0;
+ // this.isReconnecting = false;
+ // } else if (
+ // str.includes("DISCONNECTED") ||
+ // str.includes("Connection closed")
+ // ) {
+ // console.log("WebSocket 连接断开");
+ // this.handleDisconnect();
+ // }
+ // };
- this.stompClient.connect(
- headers,
- (frame) => {
- console.log("WebSocket Connected:", frame);
- this.isWebSocketConnected = true;
- this.connectionStatus = "connected";
-
- // 连接成功后立即订阅消息
- this.subscribeToPersonalMessages();
- },
- (error) => {
- console.error("WebSocket Error:", error);
- this.isWebSocketConnected = false;
- this.connectionStatus = "error";
- // 添加重连逻辑
- setTimeout(() => this.connectWebSocket(), 5000);
- }
- );
+ const headers = {
+ email: this.userEmail,
+ type: this.userType,
+ };
- // 配置心跳
- this.stompClient.heartbeat.outgoing = 20000;
- this.stompClient.heartbeat.incoming = 20000;
- } catch (error) {
- console.error("初始化 WebSocket 失败:", error);
+ // 添加连接状态监听
+ this.stompClient.onStompError = (frame) => {
+ console.error("STOMP 错误:", frame);
+ this.handleDisconnect();
+ };
+
+ this.stompClient.connect(
+ headers,
+ (frame) => {
+ console.log("WebSocket Connected:", frame);
+ this.isWebSocketConnected = true;
+ this.connectionStatus = "connected";
+ this.reconnectAttempts = 0;
+ this.isReconnecting = false;
+
+ // 连接成功后立即订阅消息
+ this.subscribeToPersonalMessages();
+
+ // 显示连接成功提示
+ this.$message.success("连接成功");
+ },
+ (error) => {
+ console.error("WebSocket Error:", error);
+ this.handleDisconnect();
+ }
+ );
+
+ // 配置心跳
+ this.stompClient.heartbeat.outgoing = 20000;
+ this.stompClient.heartbeat.incoming = 20000;
+ } catch (error) {
+ console.error("初始化 WebSocket 失败:", error);
+ this.handleDisconnect();
+ }
+ },
+ // 添加新重连最多重连5次
+ handleDisconnect() {
+ this.isWebSocketConnected = false;
this.connectionStatus = "error";
- }
- },
+ this.isReconnecting = false;
+
+ // 如果重连次数未超过最大尝试次数,则尝试重连
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
+ this.reconnectAttempts++;
+ console.log(
+ `尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`
+ );
+
+ this.$message.warning(
+ `连接断开,${this.reconnectInterval / 1000}秒后重试...`
+ );
+
+ setTimeout(() => {
+ if (!this.isWebSocketConnected) {
+ this.connectWebSocket();
+ }
+ }, this.reconnectInterval);
+ } else {
+ console.log("达到最大重连次数,停止重连");
+ this.$message.error("连接失败,请刷新页面重试");
+ }
+ },
// 新增:页面卸载时的处理
handleBeforeUnload() {
@@ -387,73 +451,93 @@ export default {
// 发送消息
sendMessage() {
- if (!this.inputMessage.trim() || this.connectionStatus !== "connected")
- return;
+ if (!this.inputMessage.trim()) return;
+
+ // 检查 WebSocket 连接状态
+ if (!this.stompClient || !this.stompClient.connected) {
+ console.log('发送消息时连接已断开,尝试重连...');
+ this.$message.warning('连接已断开,正在重新连接...');
+ this.handleDisconnect();
+ return;
+ }
const messageText = this.inputMessage.trim();
- // 添加用户消息到界面
- this.messages.push({
- type: "user",
- text: messageText,
- time: new Date(),
- email: this.receivingEmail,
- receiveUserType: 2, //接收消息用户类型
- roomId: this.roomId,
- isRead: false, // 新发送的消息默认未读
- });
- const message = {
- content: messageText,
- type: 1, // 1 表示文字消息
- email: this.receivingEmail,
- receiveUserType: 2,
- roomId: this.roomId,
- };
- // 发送消息
- this.stompClient.send("/point/send/message", {}, JSON.stringify(message));
- // 通过 WebSocket 发送消息
- // if (this.stompClient && this.stompClient.connected) {
- // this.stompClient.send({
- // destination: "/point/send/message",
- // body: JSON.stringify({
- // content: messageText,
- // type: 1,
- // email: this.receivingEmail,
- // receiveUserType:2,//当前用户类型
- // roomId: this.roomId,
- // }),
- // });
- // } else {
- // this.handleAutoResponse(messageText);
- // }
+ try {
+ // 添加用户消息到界面
+ this.messages.push({
+ type: "user",
+ text: messageText,
+ time: new Date(),
+ email: this.receivingEmail,
+ receiveUserType: 2, //接收消息用户类型
+ roomId: this.roomId,
+ isRead: false, // 新发送的消息默认未读
+ });
+ const message = {
+ content: messageText,
+ type: 1, // 1 表示文字消息
+ email: this.receivingEmail,
+ receiveUserType: 2,
+ roomId: this.roomId,
+ };
+ // 发送消息
+ this.stompClient.send(
+ "/point/send/message/to/customer",
+ {},
+ JSON.stringify(message)
+ );
- this.inputMessage = "";
+ // 通过 WebSocket 发送消息
+ // if (this.stompClient && this.stompClient.connected) {
+ // this.stompClient.send({
+ // destination: "/point/send/message",
+ // body: JSON.stringify({
+ // content: messageText,
+ // type: 1,
+ // email: this.receivingEmail,
+ // receiveUserType:2,//当前用户类型
+ // roomId: this.roomId,
+ // }),
+ // });
+ // } else {
+ // this.handleAutoResponse(messageText);
+ // }
- this.$nextTick(() => {
- this.scrollToBottom();
- });
+ this.inputMessage = "";
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ } catch (error) {
+ console.error("发送消息失败:", error);
+ this.$message.error("发送消息失败,请重试");
+ this.handleDisconnect();
+ }
},
// 断开 WebSocket 连接
disconnectWebSocket() {
- if (this.stompClient) {
- try {
- // 取消所有订阅
- if (this.stompClient.subscriptions) {
- Object.keys(this.stompClient.subscriptions).forEach(id => {
- this.stompClient.unsubscribe(id);
- });
+ if (this.stompClient) {
+ try {
+ // 取消所有订阅
+ if (this.stompClient.subscriptions) {
+ Object.keys(this.stompClient.subscriptions).forEach((id) => {
+ this.stompClient.unsubscribe(id);
+ });
+ }
+
+ // 断开连接
+ this.stompClient.deactivate();
+ this.isWebSocketConnected = false;
+ this.connectionStatus = "disconnected";
+ this.reconnectAttempts = 0;
+ this.isReconnecting = false;
+ } catch (error) {
+ console.error("断开 WebSocket 连接失败:", error);
}
-
- // 断开连接
- this.stompClient.deactivate();
- this.isWebSocketConnected = false;
- this.connectionStatus = "disconnected";
- } catch (error) {
- console.error("断开 WebSocket 连接失败:", error);
}
- }
- },
+ },
// 处理页面可见性变化
handleVisibilityChange() {
// 当页面变为可见且聊天窗口已打开时,标记消息为已读
@@ -496,53 +580,61 @@ export default {
this.isLoadingHistory = true;
try {
- const response = await getHistory7({ roomId: this.roomId, userType: this.userType });
+ const response = await getHistory7({
+ roomId: this.roomId,
+ userType: this.userType,
+ email: this.userEmail,
+ });
console.log("历史消息数据:", response);
-
+
if (response?.code === 200 && Array.isArray(response.data)) {
// 处理历史消息
- const historyMessages = response.data.map(msg => ({
- type: msg.isSelf === 1 ? "user" : "system", // 根据 isSelf 判断消息类型
+ const historyMessages = response.data.map((msg) => ({
+ type: msg.isSelf === 1 ? "user" : "system",
text: msg.content,
isImage: msg.type === 2,
imageUrl: msg.type === 2 ? msg.content : null,
- time: new Date(msg.createTime), // 使用 createTime 字段
+ time: new Date(msg.createTime),
id: msg.id,
roomId: msg.roomId,
sender: msg.sendEmail,
isHistory: true,
- isRead: true // 历史消息默认已读
+ isRead: true,
}));
// 按时间顺序排序
- this.messages = historyMessages.sort((a, b) =>
- new Date(a.time) - new Date(b.time)
+ this.messages = historyMessages.sort(
+ (a, b) => new Date(a.time) - new Date(b.time)
);
- // 滚动到底部
- this.$nextTick(() => {
- this.scrollToBottom();
- });
+ // 等待 DOM 更新和图片加载完成后再滚动
+ await this.$nextTick();
+ // 添加一个小延时确保所有内容都渲染完成
+ setTimeout(() => {
+ this.scrollToBottom(true); // 传入 true 表示强制滚动
+ }, 100);
} else {
- // 没有历史消息时显示提示
- this.messages = [{
- type: "system",
- text: "暂无历史消息",
- isSystemHint: true,
- time: new Date()
- }];
+ this.messages = [
+ {
+ type: "system",
+ text: "暂无历史消息",
+ isSystemHint: true,
+ time: new Date(),
+ },
+ ];
}
} catch (error) {
console.error("加载历史消息失败:", error);
this.$message.error("加载历史消息失败");
- // 显示错误提示
- this.messages = [{
- type: "system",
- text: "加载历史消息失败,请重试",
- isSystemHint: true,
- time: new Date(),
- isError: true
- }];
+ this.messages = [
+ {
+ type: "system",
+ text: "加载历史消息失败,请重试",
+ isSystemHint: true,
+ time: new Date(),
+ isError: true,
+ },
+ ];
} finally {
this.isLoadingHistory = false;
}
@@ -550,105 +642,118 @@ export default {
// 加载更多历史消息(超过7天的)
async loadMoreHistory() {
- if (this.isLoadingHistory || !this.roomId) return;
+ if (this.isLoadingHistory || !this.roomId) return;
- this.isLoadingHistory = true;
+ this.isLoadingHistory = true;
- try {
- // 显示加载中提示
- const loadingMsg = {
- type: "system",
- text: "正在加载更多历史消息...",
- isLoading: true,
- time: new Date(),
- };
- this.messages.unshift(loadingMsg);
+ try {
+ // 获取当前消息列表中最旧消息的 ID
+ const oldestMessage = this.messages.find(msg => !msg.isSystemHint && !msg.isLoading);
+ if (!oldestMessage || !oldestMessage.id) {
+ console.warn('没有找到有效的消息ID');
+ this.hasMoreHistory = false;
+ return;
+ }
- // 获取更早的聊天记录
- const response = await getHistory({ roomId: this.roomId });
+ // 显示加载中提示
+ const loadingMsg = {
+ type: "system",
+ text: "正在加载更多历史消息...",
+ isLoading: true,
+ time: new Date(),
+ };
+ this.messages.unshift(loadingMsg);
- // 移除加载中提示
- this.messages = this.messages.filter((msg) => !msg.isLoading);
+ // 获取更早的聊天记录,添加 id 参数
+ const response = await getHistory7({
+ roomId: this.roomId,
+ userType: this.userType,
+ email: this.userEmail,
+ id: oldestMessage.id // 添加最旧消息的 ID
+ });
- if (
- response &&
- response.code === 200 &&
- response.data &&
- response.data.length > 0
- ) {
- // 处理并添加历史消息
- const historyMessages = this.formatHistoryMessages(response.data);
+ // 移除加载中提示
+ this.messages = this.messages.filter((msg) => !msg.isLoading);
- // 将历史消息添加到消息列表的前面
- this.messages = [...historyMessages, ...this.messages];
+ if (
+ response &&
+ response.code === 200 &&
+ response.data &&
+ response.data.length > 0
+ ) {
+ // 处理并添加历史消息
+ const historyMessages = this.formatHistoryMessages(response.data);
- // 如果没有数据返回,表示没有更多历史记录
- this.hasMoreHistory = historyMessages.length > 0;
+ // 将历史消息添加到消息列表的前面
+ this.messages = [...historyMessages, ...this.messages];
- if (historyMessages.length === 0) {
- this.messages.unshift({
- type: "system",
- text: "没有更多历史消息了",
- isSystemHint: true,
- time: new Date(),
- });
- }
- } else {
- this.hasMoreHistory = false;
- this.messages.unshift({
- type: "system",
- text: "没有更多历史消息了",
- isSystemHint: true,
- time: new Date(),
- });
- }
- } catch (error) {
- console.error("加载更多历史消息失败:", error);
+ // 如果没有数据返回,表示没有更多历史记录
+ this.hasMoreHistory = historyMessages.length > 0;
+
+ if (historyMessages.length === 0) {
this.messages.unshift({
type: "system",
- text: "加载更多历史消息失败",
- isError: true,
+ text: "没有更多历史消息了",
+ isSystemHint: true,
time: new Date(),
});
- } finally {
- this.isLoadingHistory = false;
}
- },
+ } else {
+ this.hasMoreHistory = false;
+ this.messages.unshift({
+ type: "system",
+ text: "没有更多历史消息了",
+ isSystemHint: true,
+ time: new Date(),
+ });
+ }
+ } catch (error) {
+ console.error("加载更多历史消息失败:", error);
+ this.messages.unshift({
+ type: "system",
+ text: "加载更多历史消息失败",
+ isError: true,
+ time: new Date(),
+ });
+ } finally {
+ this.isLoadingHistory = false;
+ }
+},
// 格式化历史消息数据
formatHistoryMessages(messagesData) {
- if (!messagesData || !Array.isArray(messagesData)) return [];
+ if (!messagesData || !Array.isArray(messagesData)) return [];
- return messagesData
- .map((msg) => ({
- type: msg.isSelf === 1 ? "user" : "system", // 根据 isSelf 判断消息类型
- text: msg.content || "",
- isImage: msg.type === 2,
- imageUrl: msg.type === 2 ? msg.content : null,
- time: new Date(msg.createTime),
- id: msg.id,
- roomId: msg.roomId,
- sender: msg.sendEmail,
- isHistory: true,
- isRead: true
- }))
- .sort((a, b) => new Date(a.time) - new Date(b.time));
-},
+ return messagesData
+ .map((msg) => ({
+ type: msg.isSelf === 1 ? "user" : "system", // 根据 isSelf 判断消息类型
+ text: msg.content || "",
+ isImage: msg.type === 2,
+ imageUrl: msg.type === 2 ? msg.content : null,
+ time: new Date(msg.createTime),
+ id: msg.id,
+ roomId: msg.roomId,
+ sender: msg.sendEmail,
+ isHistory: true,
+ isRead: true,
+ }))
+ .sort((a, b) => new Date(a.time) - new Date(b.time));
+ },
// 修改 fetchUserid 方法,添加 token 检查
- async fetchUserid() {
+ async fetchUserid(params) {
try {
// 先检查是否有 token
- const token = localStorage.getItem("token");
- if (!token) {
- console.log("用户未登录,不发起 getUserid 请求");
- // 对于未登录用户,可以生成一个临时 ID
- this.roomId = `guest_${Date.now()}`;
- this.receivingEmail = "customer_service@example.com"; // 或默认客服邮箱
- return null;
- }
+ // const token = localStorage.getItem("token");
+ // if (!token) {
+ // console.log("用户未登录,不发起 getUserid 请求");
+ // // 对于未登录用户,可以生成一个临时 ID
+ // this.roomId = `guest_${Date.now()}`;
+ // this.receivingEmail = "customer_service@example.com"; // 或默认客服邮箱
+ // return null;
+ // }
- const res = await getUserid();
+ const res = await getUserid(params);
if (res && res.code == 200) {
console.log("获取用户ID成功:", res);
this.receivingEmail = res.data.userEmail;
@@ -685,50 +790,49 @@ export default {
// 接收消息处理
onMessageReceived(message) {
- try {
- const data = JSON.parse(message.body);
- console.log("收到新消息:", data);
-
- // 构造消息对象
- const messageObj = {
- type: data.sendUserType === this.userType ? "user" : "system", // 用户类型判断
- text: data.content,
- isImage: data.type === 2,
- imageUrl: data.type === 2 ? data.content : null,
- time: new Date(data.sendTime),
- id: data.id,
- roomId: data.roomId,
- sender: data.sendEmail,
- isRead: false
- };
+ try {
+ const data = JSON.parse(message.body);
+ console.log("收到新消息:", data);
- // 直接添加到消息列表
- this.messages.push(messageObj);
+ // 构造消息对象
+ const messageObj = {
+ type: data.sendUserType === this.userType ? "user" : "system", // 用户类型判断
+ text: data.content,
+ isImage: data.type === 2,
+ imageUrl: data.type === 2 ? data.content : null,
+ time: new Date(data.sendTime),
+ id: data.id,
+ roomId: data.roomId,
+ sender: data.sendEmail,
+ isRead: false,
+ };
- // 如果聊天窗口未打开,增加未读消息数
- if (!this.isChatOpen) {
- // 使用服务器返回的未读数,如果没有则增加1
- if (data.clientReadNum !== undefined) {
- this.unreadMessages = data.clientReadNum;
- } else {
- this.unreadMessages++;
+ // 直接添加到消息列表
+ this.messages.push(messageObj);
+
+ // 如果聊天窗口未打开,增加未读消息数
+ if (!this.isChatOpen) {
+ // 使用服务器返回的未读数,如果没有则增加1
+ if (data.clientReadNum !== undefined) {
+ this.unreadMessages = data.clientReadNum;
+ } else {
+ this.unreadMessages++;
+ }
+ // 显示消息通知
+ this.showNotification(messageObj);
+ } else {
+ // 如果聊天窗口已打开,立即标记为已读
+ this.markMessagesAsRead();
+ }
+
+ // 滚动到底部
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ } catch (error) {
+ console.error("处理消息失败:", error);
}
- // 显示消息通知
- this.showNotification(messageObj);
- } else {
- // 如果聊天窗口已打开,立即标记为已读
- this.markMessagesAsRead();
- }
-
- // 滚动到底部
- this.$nextTick(() => {
- this.scrollToBottom();
- });
-
- } catch (error) {
- console.error("处理消息失败:", error);
- }
-},
+ },
// 显示消息通知
showNotification(message) {
@@ -778,35 +882,46 @@ export default {
}
},
- // 切换聊天窗口
+ // 打开聊天框
async toggleChat() {
this.isChatOpen = !this.isChatOpen;
+ // 1. 判别身份
+ this.determineUserType();
+
+ // 2. 如果是客服,跳转到客服页面
+ if (this.userType === 2) {
+ const lang = this.$i18n.locale;
+ this.$router.push(`/${lang}/customerService`);
+ return;
+ }
+
if (this.isChatOpen) {
- // 打开聊天窗口时
try {
// 确定用户类型
this.determineUserType();
- // 如果未连接,则初始化 WebSocket
- if (this.connectionStatus === "disconnected") {
- await this.initWebSocket();
+ // 如果未连接或连接断开,则重新初始化 WebSocket
+ if (!this.isWebSocketConnected || this.connectionStatus === "disconnected") {
+ await this.connectWebSocket();
}
// 如果消息列表为空,加载历史消息
if (this.messages.length === 0) {
await this.loadHistoryMessages();
+ } else {
+ // 如果已有消息,确保滚动到底部
+ await this.$nextTick();
+ setTimeout(() => {
+ this.scrollToBottom(true);
+ }, 100);
}
// 标记消息为已读
await this.markMessagesAsRead();
-
- // 滚动到底部
- this.$nextTick(() => {
- this.scrollToBottom();
- });
} catch (error) {
console.error("初始化聊天失败:", error);
+ this.$message.error("初始化聊天失败,请重试");
}
}
},
@@ -879,22 +994,22 @@ export default {
this.loadMoreHistory();
}
},
+ //滚动到底部
+ scrollToBottom(force = false) {
+ if (!this.$refs.chatBody) return;
- scrollToBottom() {
- if (this.$refs.chatBody) {
- const scrollOptions = {
- top: this.$refs.chatBody.scrollHeight,
- behavior: "smooth",
- };
+ const scrollOptions = {
+ top: this.$refs.chatBody.scrollHeight,
+ behavior: force ? 'auto' : 'smooth' // 强制滚动时使用 'auto'
+ };
- try {
- this.$refs.chatBody.scrollTo(scrollOptions);
- } catch (error) {
- // 如果平滑滚动不支持,则直接设置
- this.$refs.chatBody.scrollTop = this.$refs.chatBody.scrollHeight;
- }
- }
- },
+ try {
+ this.$refs.chatBody.scrollTo(scrollOptions);
+ } catch (error) {
+ // 如果平滑滚动不支持,则直接设置
+ this.$refs.chatBody.scrollTop = this.$refs.chatBody.scrollHeight;
+ }
+},
formatTime(date) {
if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
@@ -950,7 +1065,10 @@ export default {
// 处理图片上传
async handleImageUpload(event) {
- if (this.connectionStatus !== "connected") return;
+ if (this.connectionStatus !== "connected") {
+ console.log("当前连接状态:", this.connectionStatus);
+ return;
+ }
const file = event.target.files[0];
if (!file) return;
@@ -981,62 +1099,71 @@ export default {
type: "info",
});
- // 准备FormData
- const formData = new FormData();
- formData.append("file", file);
+ // 将文件转换为 base64
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const base64Image = e.target.result;
- // 上传文件到后端
- const response = await getFileUpdate(formData);
- console.log("文件上传返回:", response);
-
- // 检查上传结果
- if (response && response.code === 200 && response.data) {
- // 从后端响应中获取图片信息
- const imageData = response.data;
- // 使用后端返回的URL
- const imageUrl = this.formatImageUrl(imageData.url);
-
- console.log("图片URL:", imageUrl); // 调试用:打印URL
+ // 检查连接状态
+ if (!this.stompClient || !this.stompClient.connected) {
+ console.error("发送图片时连接已断开");
+ this.$message.error("连接已断开,正在重新连接...");
+ this.connectWebSocket();
+ return;
+ }
// 添加用户图片消息到界面(本地显示)
this.messages.push({
type: "user",
- text: "", // 保留空字符串
+ text: "",
isImage: true,
- imageUrl: imageUrl, // 确保URL正确
+ imageUrl: base64Image,
time: new Date(),
email: this.receivingEmail,
sendUserType: this.userType,
roomId: this.roomId,
isRead: false,
});
- // 通过WebSocket发送图片消息
- if (this.stompClient && this.stompClient.connected) {
+
+ try {
+ // 通过 WebSocket 发送图片消息
const message = {
- content: imageUrl, // URL作为消息内容
- type: 2, // 使用数字类型2表示图片消息
+ content: base64Image,
+ type: 2,
email: this.receivingEmail,
receiveUserType: 2,
roomId: this.roomId,
};
- // 使用WebSocket发送消息
+ console.log(
+ "准备发送图片消息,当前连接状态:",
+ this.stompClient.connected
+ );
this.stompClient.send(
"/point/send/message",
{},
JSON.stringify(message)
);
- }
+ console.log("图片消息发送完成");
- this.$nextTick(() => {
- this.scrollToBottom();
- });
- } else {
- this.$message.error("图片上传失败: " + (response?.msg || "未知错误"));
- }
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ } catch (sendError) {
+ console.error("发送图片消息失败:", sendError);
+ this.$message.error("发送图片失败,请重试");
+ }
+ };
+
+ reader.onerror = (error) => {
+ console.error("读取文件失败:", error);
+ this.$message.error("读取图片失败,请重试");
+ };
+
+ reader.readAsDataURL(file);
} catch (error) {
- console.error("图片上传异常:", error);
- this.$message.error("图片上传失败,请重试");
+ console.error("图片处理失败:", error);
+ this.$message.error("图片处理失败,请重试");
} finally {
// 清空input,允许重复选择同一文件
this.$refs.imageUpload.value = "";
@@ -1070,7 +1197,7 @@ export default {
},
beforeDestroy() {
- this.disconnectWebSocket();
+
// 移除滚动监听
if (this.$refs.chatBody) {
@@ -1081,7 +1208,11 @@ export default {
"visibilitychange",
this.handleVisibilityChange
);
-
+ // 确保在销毁时断开连接
+ if (this.stompClient) {
+ this.stompClient.disconnect();
+ this.stompClient = null;
+ }
// 断开 WebSocket 连接
this.disconnectWebSocket();
},
diff --git a/mining-pool/src/views/customerService/index.vue b/mining-pool/src/views/customerService/index.vue
index 2558b64..73424f6 100644
--- a/mining-pool/src/views/customerService/index.vue
+++ b/mining-pool/src/views/customerService/index.vue
@@ -202,7 +202,7 @@
v-model="inputMessage"
:rows="3"
:disabled="!currentContact"
- placeholder="请输入消息,按Enter键发送,按Ctrl+Enter键换行"
+ placeholder="请输入消息,按Enter键发送,按Ctrl+Enter键换行"
@keydown.enter.native="handleKeyDown"
>
@@ -213,7 +213,6 @@
type="primary"
:disabled="!currentContact || !inputMessage.trim() || sending"
@click="sendMessage"
-
>
发送
@@ -270,18 +269,22 @@ export default {
userScrolled: false, // 新增:用户是否手动滚动过
history7Params: {
//7天历史消息参数
- id: "", //最后一条消息id
+ id: "", //最后一条消息id
roomId: "", //聊天室id
userType: 2, //用户类型
+ email: "497681109@qq.com", //客服邮箱
},
historyAllParams: {
//7天以前的历史消息
- id: "", //最后一条消息id
+ id: "", //最后一条消息id
roomId: "", //聊天室id
userType: 2, //用户类型
},
receiveUserType: "", //接收者类型
manualCreatedRooms: [], //手动创建的聊天室
+ chatRooms: [], // 初始化聊天室列表数组
+ isWebSocketConnected: false,
+ connectionStatus: "disconnected",
};
},
computed: {
@@ -307,18 +310,23 @@ export default {
},
async created() {
- // 初始化 WebSocket 连接
- this.initWebSocket();
+ try {
+ // 初始化用户信息
+ // this.determineUserType();
- // 获取聊天室列表
- await this.fetchRoomList();
-
- // 默认选择第一个联系人
- if (this.contacts.length > 0) {
- this.selectContact(this.contacts[0].roomId);
+ // 获取聊天室列表
+ await this.fetchRoomList();
+ // 默认选择第一个联系人
+ if (this.contacts.length > 0) {
+ this.selectContact(this.contacts[0].roomId);
+ }
+ // 在组件创建时加载手动创建的聊天室
+ this.loadManualCreatedRooms();
+ // 初始化 WebSocket 连接
+ this.initWebSocket();
+ } catch (error) {
+ console.error("初始化失败:", error);
}
- // 在组件创建时加载手动创建的聊天室
- this.loadManualCreatedRooms();
},
async mounted() {
// 获取聊天室列表
@@ -328,17 +336,14 @@ export default {
if (this.contacts.length > 0) {
this.selectContact(this.contacts[0].roomId);
}
- this.confirmUserType(); //确认用户类型
- // 定时刷新聊天室列表,例如每30秒刷新一次
- // this.roomListInterval = setInterval(() => {
- // this.fetchRoomList();
-
- // // 如果有选中联系人,刷新消息
- // if (this.currentContactId) {
- // this.loadMessages(this.currentContactId);
- // }
- // }, 30000);
+
+ let userEmail = localStorage.getItem("userEmail");
+ this.userEmail = JSON.parse(userEmail);
+ window.addEventListener("setItem", () => {
+ let userEmail = localStorage.getItem("userEmail");
+ this.userEmail = JSON.parse(userEmail);
+ });
// 确保初始加载后滚动到底部
this.$nextTick(() => {
this.scrollToBottom();
@@ -356,7 +361,7 @@ export default {
methods: {
handleKeyDown(e) {
console.log("e:hhhhshshsshshshhh好的好的和", e);
- // 如果按住了 Ctrl 键,则不发送消息(换行)
+ // 如果按住了 Ctrl 键,则不发送消息(换行)
if (e.ctrlKey) {
return;
}
@@ -365,93 +370,120 @@ export default {
// 发送消息
this.sendMessage();
},
- confirmUserType() {
- try {
- const token = localStorage.getItem("token");
-
- if (!token) {
- // 游客身份
- this.userType = 0;
-
-
- this.userEmail = `guest_${Date.now()}_${Math.random()
- .toString(36)
- .substr(2, 9)}`;
- return;
- }
-
- try {
- const userInfo = JSON.parse(
- localStorage.getItem("jurisdiction") || "{}"
- );
- const email = JSON.parse(localStorage.getItem("userEmail") || "{}");
-
- if (userInfo.roleKey === "customer_service") {
- // 客服用户
- this.userType = 2;
-
-
- } else {
- // 登录用户
- this.userType = 1;
-
-
- }
- this.userEmail = email;
- } catch (parseError) {
- console.error("解析用户信息失败:", parseError);
- // 解析失败时默认为游客
- this.userType = 0;
- this.userEmail = `guest_${Date.now()}_${Math.random()
- .toString(36)
- .substr(2, 9)}`;
- }
- } catch (error) {
- console.error("获取用户信息失败:", error);
- // 出错时默认为游客
- this.userType = 0;
- this.userEmail = `guest_${Date.now()}_${Math.random()
- .toString(36)
- .substr(2, 9)}`;
- }
- },
// 初始化 WebSocket 连接
initWebSocket() {
- const wsUrl = `${process.env.VUE_APP_BASE_API}chat/ws`;
+ if (this.isWebSocketConnected) return;
- this.stompClient = Stomp.client(wsUrl);
+ try {
+ const wsUrl = `${process.env.VUE_APP_BASE_API}chat/ws`;
+ this.stompClient = Stomp.client(wsUrl);
- // 配置连接参数
- const headers = {
- email: this.userEmail,
- type: 2,
- };
- // 连接并传入参数
- this.stompClient.connect(
- headers, // 连接参数
- (frame) => {
- // 连接成功回调
- console.log("WebSocket Connected:", frame);
- this.wsConnected = true;
- this.subscribeToPersonalMessages();
- },
- (error) => {
- // 连接错误回调
- console.error("WebSocket Error:", error);
- this.wsConnected = false;
- this.$message.error("连接失败,正在重试...");
+ // 配置 STOMP 客户端参数
+ this.stompClient.splitLargeFrames = true; // 启用大型消息帧分割
+
+ // 修改调试日志的方式
+ this.stompClient.debug = (str) => {
+ // 只打印与客服相关的日志
+ if (
+ str.includes("CONNECTED") ||
+ str.includes("DISCONNECTED") ||
+ str.includes("ERROR")
+ ) {
+ console.log("[客服系统]", str);
+ }
+ };
+
+ const headers = {
+ email: this.userEmail,
+ type: this.userType,
+ };
+
+ this.stompClient.connect(
+ headers,
+ (frame) => {
+ console.log("[客服系统] WebSocket 连接成功", frame);
+ this.isWebSocketConnected = true;
+ this.connectionStatus = "connected";
+ this.subscribeToMessages();
+ },
+ (error) => {
+ console.error("[客服系统] WebSocket 错误:", error);
+ this.handleDisconnect();
+ }
+ );
+
+ // 配置心跳
+ this.stompClient.heartbeat.outgoing = 20000;
+ this.stompClient.heartbeat.incoming = 20000;
+ } catch (error) {
+ console.error("初始化 CustomerService WebSocket 失败:", error);
+ this.handleDisconnect();
+ }
+ },
+
+ // // 订阅消息
+ subscribeToMessages() {
+ if (!this.stompClient || !this.isWebSocketConnected) return;
+
+ try {
+ // 修改订阅路径,使用客服特定的订阅路径
+ this.stompClient.subscribe(
+ `/sub/queue/customer/${this.userEmail}`,
+ this.handleIncomingMessage,
+ {
+ id: `customer_${this.userEmail}`,
+ }
+ );
+ // this.stompClient.subscribe(
+ // `/user/queue/customer_service`, // 修改为客服专用的订阅路径
+ // this.handleIncomingMessage,
+ // {
+ // id: `customer_service_${this.userEmail}`,
+ // }
+ // );
+
+ console.log(
+ "CustomerService 成功订阅消息频道:",
+ `/sub/queue/customer/${this.userEmail}`
+ );
+ } catch (error) {
+ console.error("CustomerService 订阅消息失败:", error);
+ }
+ },
+
+ // 断开连接
+ disconnectWebSocket() {
+ if (this.stompClient) {
+ try {
+ // 取消所有订阅
+ if (this.stompClient.subscriptions) {
+ Object.keys(this.stompClient.subscriptions).forEach((id) => {
+ this.stompClient.unsubscribe(id);
+ });
+ }
+
+ // 断开连接
+ this.stompClient.deactivate();
+ this.isWebSocketConnected = false;
+ this.connectionStatus = "disconnected";
+ } catch (error) {
+ console.error("断开 CustomerService WebSocket 连接失败:", error);
}
- );
+ }
+ },
- // 可选:配置心跳
- this.stompClient.heartbeat.outgoing = 20000; // 20秒
- this.stompClient.heartbeat.incoming = 20000;
+ // 处理断开连接
+ handleDisconnect() {
+ this.isWebSocketConnected = false;
+ this.connectionStatus = "error";
- // 可选:开启调试日志
- this.stompClient.debug = function (str) {
- console.log("STOMP: " + str);
- };
+ // 尝试重新连接
+ setTimeout(() => {
+ if (!this.isWebSocketConnected) {
+ this.initWebSocket();
+ }
+ }, 5000);
},
// 获取当前的 UTC 时间
@@ -489,12 +521,12 @@ export default {
// 发送消息
this.stompClient.send(
- "/point/send/message",
+ "/point/send/message/to/user",
{},
JSON.stringify(message)
);
- // 添加到本地消息列表
+ // 添加到本地消息列表
this.addMessageToChat({
sender: "我",
content: messageContent,
@@ -502,7 +534,7 @@ export default {
isSelf: true,
isImage: false,
roomId: this.currentContactId,
- type: 1
+ type: 1,
});
// 重置当前聊天室的未读消息数
@@ -530,39 +562,92 @@ export default {
},
// 处理接收到的消息
- handleIncomingMessage(message) {
+ async handleIncomingMessage(message) {
+ try {
const msg = JSON.parse(message.body);
-
+ console.log("客服收到的消息", msg);
+
const messageData = {
id: msg.id,
sender: msg.sendEmail,
- avatar: msg.sendUserType === 2 ? "iconfont icon-icon28" : "iconfont icon-user",
+ avatar:
+ msg.sendUserType === 2
+ ? "iconfont icon-icon28"
+ : "iconfont icon-user",
content: msg.content,
time: new Date(msg.sendTime),
- isSelf: msg.sendUserType === this.userType && msg.sendEmail === this.userEmail,
+ isSelf:
+ msg.sendUserType === this.userType &&
+ msg.sendEmail === this.userEmail,
isImage: msg.type === 2,
type: msg.type,
roomId: msg.roomId,
sendUserType: msg.sendUserType,
isCreate: msg.isCreate,
- clientReadNum: msg.clientReadNum
+ clientReadNum: msg.clientReadNum,
};
- // 新聊天室处理
- if (messageData.isCreate) {
- this.handleNewChatRoom(messageData);
+ // 更新或创建聊天室
+ const existingContact = this.contacts.find(
+ (c) => c.roomId === messageData.roomId
+ );
+
+ if (!existingContact) {
+ // 如果聊天室不存在,创建新的聊天室
+ const newContact = {
+ roomId: messageData.roomId,
+ name: messageData.sender,
+ lastMessage: messageData.isImage ? "[图片]" : messageData.content,
+ lastTime: messageData.time,
+ unread: 1,
+ important: false,
+ isGuest: messageData.sendUserType === 0,
+ sendUserType: messageData.sendUserType,
+ isManualCreated: true,
+ };
+
+ this.contacts.push(newContact);
+ this.$set(this.messages, messageData.roomId, []);
+ } else {
+ // 如果聊天室已存在,更新最后一条消息
+ existingContact.lastMessage = messageData.isImage ? "[图片]" : messageData.content;
+ existingContact.lastTime = messageData.time;
}
- this.updateChatRoomList(messageData);
+ // 添加消息到聊天记录
+ if (!this.messages[messageData.roomId]) {
+ this.$set(this.messages, messageData.roomId, []);
+ }
- // 当前聊天室消息
+ this.messages[messageData.roomId].push({
+ id: messageData.id,
+ sender: messageData.sender,
+ avatar: messageData.avatar,
+ content: messageData.content,
+ time: messageData.time,
+ isSelf: messageData.isSelf,
+ isImage: messageData.isImage,
+ type: messageData.type,
+ roomId: messageData.roomId,
+ });
+
+ // 如果是当前选中的聊天室,标记为已读
if (messageData.roomId === this.currentContactId) {
- this.addMessageToChat(messageData);
this.markMessagesAsRead(messageData.roomId);
} else {
- this.incrementUnreadCount(messageData.roomId, messageData.clientReadNum);
+ // 更新未读消息数
+ const contact = this.contacts.find((c) => c.roomId === messageData.roomId);
+ if (contact) {
+ contact.unread = (contact.unread || 0) + 1;
+ }
}
- },
+
+ // 重新排序联系人列表
+ this.sortContacts();
+ } catch (error) {
+ console.error("处理新消息失败:", error);
+ }
+},
// 处理新聊天室创建
handleNewChatRoom(messageData) {
@@ -570,24 +655,21 @@ export default {
const existingContact = this.contacts.find(
(c) => c.roomId === messageData.roomId
);
- console.log("messageData:hhhhshshsshshshhh好的好的和", messageData);
-
-
- // && messageData.isCreate && messageData.sender
- if (!existingContact) {//只需要判断是否在联系人列表中存在 如果不在就创建新的聊天室对象
+ if (!existingContact) {
// 创建新的聊天室对象
const newContact = {
roomId: messageData.roomId,
name: messageData.sender,
+ // 修改这里:使用实际收到的消息内容作为最后一条消息
lastMessage: messageData.isImage ? "[图片]" : messageData.content,
lastTime: messageData.time,
unread: 1,
important: false,
isGuest: messageData.sendUserType === 0,
sendUserType: messageData.sendUserType,
- isManualCreated: true, // 新增:标记为手动创建
- clientReadNum: messageData.clientReadNum, //未读条数
+ isManualCreated: true,
+ clientReadNum: messageData.clientReadNum,
};
// 添加到聊天列表
@@ -616,6 +698,7 @@ export default {
this.manualCreatedRooms.push(newContact);
this.saveManualCreatedRooms();
+ // 重新排序联系人列表
this.sortContacts();
}
},
@@ -657,23 +740,53 @@ export default {
console.error("加载手动创建的聊天室失败:", error);
}
},
+
+ // 添加新方法:创建新聊天室
+ async createNewChatRoom(messageData) {
+ try {
+ // 调用后端 API 创建新的聊天室
+ const response = await createChatRoom({
+ userEmail: messageData.sender,
+ userType: messageData.sendUserType,
+ });
+
+ if (response && response.code === 200) {
+ const newRoom = {
+ userEmail: messageData.sender,
+ roomId: response.data.roomId,
+ lastMessage: messageData.content,
+ lastMessageTime: messageData.time,
+ unreadCount: messageData.clientReadNum || 0,
+ userType: messageData.sendUserType,
+ };
+
+ this.chatRooms.unshift(newRoom);
+ return newRoom;
+ }
+ } catch (error) {
+ console.error("创建新聊天室失败:", error);
+ throw error;
+ }
+ },
// 更新聊天室列表
updateChatRoomList(messageData) {
- // 寻找现有联系人
- const contactIndex = this.contacts.findIndex(
- (c) => c.roomId === messageData.roomId
+ const roomIndex = this.chatRooms.findIndex(
+ (room) => room.roomId === messageData.roomId
);
- if (contactIndex !== -1) {
- // 更新现有联系人的最后消息和时间
- const contact = this.contacts[contactIndex];
- contact.lastMessage = messageData.isImage
- ? "[图片]"
- : messageData.content;
- contact.lastTime = messageData.time;
+ if (roomIndex !== -1) {
+ // 更新现有聊天室信息
+ this.chatRooms[roomIndex] = {
+ ...this.chatRooms[roomIndex],
+ lastMessage: messageData.content,
+ lastMessageTime: messageData.time,
+ unreadCount:
+ messageData.clientReadNum || this.chatRooms[roomIndex].unreadCount,
+ };
- // 重新排序联系人列表,将最新消息的联系人移到前面
- this.sortContacts();
+ // 将更新的聊天室移到列表顶部
+ const updatedRoom = this.chatRooms.splice(roomIndex, 1)[0];
+ this.chatRooms.unshift(updatedRoom);
}
},
// 修改标记为已读方法,添加参数支持
@@ -683,7 +796,7 @@ export default {
try {
const data = {
roomId: roomId,
- userType:2,
+ userType: 2,
};
const response = await getReadMessage(data);
@@ -717,69 +830,63 @@ export default {
// 获取聊天室列表
async fetchRoomList() {
- try {
- this.loadingRooms = true;
- const response = await getRoomList();
- if (response?.code === 200) {
- // 创建全新的联系人数组
- const newContacts = response.rows.map((room) => {
- // 查找旧联系人中是否存在相同roomId
- const existingContact = this.contacts.find(
- (c) => c.roomId === room.id
- );
+ try {
+ this.loadingRooms = true;
+ const response = await getRoomList();
+ if (response?.code === 200) {
+ const newContacts = response.rows.map((room) => {
+ const existingContact = this.contacts.find(
+ (c) => c.roomId === room.id
+ );
- const isImportant =
- room.flag === 1
- ? true
- : room.flag === 0
- ? false
- : room.important === 1
- ? true
- : existingContact
- ? existingContact.important
- : false;
+ const manualRoom = this.manualCreatedRooms.find(
+ (c) => c.roomId === room.id
+ );
- return {
- roomId: room.id,
- name: room.userEmail || "未命名聊天室",
- avatar: this.getDefaultAvatar(room.roomName || "未命名聊天室"),
- lastMessage: room.lastMessage || "暂无消息",
- lastTime: room.lastUserSendTime
- ? new Date(room.lastUserSendTime)
- : new Date(),
- unread: existingContact?.unread ?? room.unreadCount ?? 0,
- important: isImportant,
- isManualCreated: existingContact?.isManualCreated || false, // 保持手动创建标记
- };
- });
+ const isImportant =
+ room.flag === 1
+ ? true
+ : room.flag === 0
+ ? false
+ : room.important === 1
+ ? true
+ : existingContact
+ ? existingContact.important
+ : false;
- // 合并手动创建的聊天室
- this.manualCreatedRooms.forEach((room) => {
- const exists = newContacts.find((c) => c.roomId === room.roomId);
- if (!exists) {
- newContacts.push({
- ...room,
- lastTime: new Date(room.lastTime),
- });
- }
- });
+ return {
+ roomId: room.id,
+ name: room.userEmail || "未命名聊天室",
+ avatar: this.getDefaultAvatar(room.roomName || "未命名聊天室"),
+ // 修改这里:优先使用服务器返回的消息,其次是现有联系人的消息
+ lastMessage: room.lastMessage || (existingContact ? existingContact.lastMessage : "暂无消息"),
+ lastTime: room.lastUserSendTime
+ ? new Date(room.lastUserSendTime)
+ : new Date(),
+ unread: existingContact?.unread ?? room.unreadCount ?? 0,
+ important: isImportant,
+ isManualCreated: manualRoom ? true : false,
+ sendUserType: room.sendUserType,
+ isGuest: room.sendUserType === 0,
+ };
+ });
- // 更新联系人列表
- this.contacts = newContacts;
- this.sortContacts();
- }
- } catch (error) {
- console.error("获取聊天室列表异常:", error);
- this.$message.error("获取聊天室列表异常");
- } finally {
- this.loadingRooms = false;
- }
- },
+ // 更新联系人列表
+ this.contacts = newContacts;
+ this.sortContacts();
+ }
+ } catch (error) {
+ console.error("获取聊天室列表异常:", error);
+ this.$message.error("获取聊天室列表异常");
+ } finally {
+ this.loadingRooms = false;
+ }
+},
// 加载更多历史消息
async loadMoreHistory() {
if (!this.currentContactId) return;
-
+
// 获取当前已加载的消息列表
const currentMsgs = this.messages[this.currentContactId] || [];
@@ -789,7 +896,7 @@ export default {
this.history7Params.id = lastMsg ? lastMsg.id : "";
// this.history7Params.pageNum += 1; // 递增页码
this.history7Params.roomId = this.currentContactId;
-
+ this.history7Params.email = this.userEmail;
try {
this.messagesLoading = true;
@@ -830,38 +937,37 @@ export default {
// 选择联系人
async selectContact(roomId) {
- if (this.currentContactId === roomId) return;
-
- try {
- this.messagesLoading = true; // 显示加载状态
- this.currentContactId = roomId;
- this.userViewHistory = false;
-
- // 重置分页参数
- this.history7Params = {
- id: "", // 首次加载为空
- // pageNum: 1, // 首次页码为1
- roomId: roomId,
- userType:2,
- };
+ if (this.currentContactId === roomId) return;
- // 加载历史消息
- await this.loadMessages(roomId);
-
- // 标记消息为已读
- await this.markMessagesAsRead(roomId);
+ try {
+ this.messagesLoading = true; // 显示加载状态
+ this.currentContactId = roomId;
+ this.userViewHistory = false;
- } catch (error) {
- console.error("选择联系人失败:", error);
- this.$message.error("加载聊天记录失败");
- } finally {
- this.messagesLoading = false;
- // 滚动到底部
- this.$nextTick(() => {
- this.scrollToBottom();
- });
- }
-},
+ // 重置分页参数
+ this.history7Params = {
+ id: "", // 首次加载为空
+ // pageNum: 1, // 首次页码为1
+ roomId: roomId,
+ userType: 2,
+ };
+
+ // 加载历史消息
+ await this.loadMessages(roomId);
+
+ // 标记消息为已读
+ await this.markMessagesAsRead(roomId);
+ } catch (error) {
+ console.error("选择联系人失败:", error);
+ this.$message.error("加载聊天记录失败");
+ } finally {
+ this.messagesLoading = false;
+ // 滚动到底部
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ }
+ },
//判断是否在聊天框底部
isAtBottom() {
const container = this.$refs.messageContainer;
@@ -875,175 +981,192 @@ export default {
// 加载聊天消息
async loadMessages(roomId) {
- if (!roomId) return;
+ if (!roomId) return;
+
+ try {
+ this.history7Params.email = this.userEmail;
+ this.history7Params.roomId = roomId;
+ const response = await getHistory7(this.history7Params);
+
+ if (response?.code === 200 && response.data) {
+ // 处理消息数据
+ let roomMessages = response.data
+ .filter((msg) => msg.roomId == roomId)
+ .map((msg) => ({
+ id: msg.id,
+ sender: msg.isSelf === 1 ? "我" : msg.sendEmail || "未知发送者",
+ avatar:
+ msg.sendUserType == 2
+ ? "iconfont icon-icon28"
+ : "iconfont icon-user",
+ content: msg.content,
+ time: new Date(msg.createTime),
+ isSelf: msg.isSelf === 1,
+ isImage: msg.type === 2,
+ isRead: msg.isRead === 1,
+ type: msg.type,
+ roomId: msg.roomId,
+ sendUserType: msg.sendUserType,
+ }));
+
+ // 按时间排序
+ roomMessages = roomMessages.sort((a, b) => a.time - b.time);
+
+ // 更新消息列表
+ this.$set(this.messages, roomId, roomMessages);
+
+ // 更新联系人的未读状态
+ const contact = this.contacts.find((c) => c.roomId === roomId);
+ if (contact) {
+ contact.unread = 0;
+ }
+ } else {
+ // 如果没有消息数据,初始化为空数组
+ this.$set(this.messages, roomId, []);
+ if (response?.code !== 200) {
+ this.$message.warning("获取聊天记录失败");
+ }
+ }
+ } catch (error) {
+ console.error("加载消息异常:", error);
+ this.$message.error("加载消息异常");
+ this.$set(this.messages, roomId, []);
+ }
+ },
+
+ // 添加消息到聊天记录
+ addMessageToChat(messageData) {
+ const roomId = messageData.roomId || this.currentContactId;
+
+ // 如果该聊天室的消息数组不存在,则初始化
+ if (!this.messages[roomId]) {
+ this.$set(this.messages, roomId, []);
+ }
+
+ // 构造消息对象
+ const message = {
+ id: messageData.id || Date.now(), // 如果没有id则使用时间戳
+ sender: messageData.sender,
+ avatar: messageData.avatar || (messageData.isSelf ? "iconfont icon-icon28" : "iconfont icon-user"),
+ content: messageData.content,
+ time: messageData.time || new Date(),
+ isSelf: messageData.isSelf,
+ isImage: messageData.isImage || false,
+ type: messageData.type || 1,
+ roomId: roomId,
+ isRead: messageData.isRead || false,
+ };
+
+ // 添加消息到数组
+ this.messages[roomId].push(message);
+
+ // 更新最后一条消息
+ this.updateContactLastMessage({
+ roomId: roomId,
+ content: message.isImage ? "[图片]" : message.content,
+ isImage: message.isImage,
+ });
+
+ // 如果是当前聊天室且用户在底部,滚动到底部
+ if (roomId === this.currentContactId && !this.userViewHistory) {
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ }
+},
+ // 处理图片上传
+ async handleImageUpload(event) {
+ // 检查是否有选中的联系人和 WebSocket 连接
+ if (!this.currentContact) {
+ this.$message.warning("请先选择联系人");
+ return;
+ }
+
+ if (!this.stompClient || !this.isWebSocketConnected) {
+ this.$message.warning("聊天连接已断开,请刷新页面重试");
+ return;
+ }
+
+ const file = event.target.files[0];
+ if (!file) return;
+
+ // 检查是否为图片
+ if (!file.type.startsWith("image/")) {
+ this.$message.warning("只能上传图片文件!");
+ return;
+ }
+
+ // 检查文件大小 (限制为5MB)
+ const maxSize = 5 * 1024 * 1024;
+ if (file.size > maxSize) {
+ this.$message.warning("图片大小不能超过5MB!");
+ return;
+ }
+
+ this.sending = true;
try {
- const response = await getHistory7(this.history7Params);
-
- if (response?.code === 200 && response.data) {
- // 处理消息数据
- let roomMessages = response.data
- .filter(msg => msg.roomId == roomId)
- .map(msg => ({
- id: msg.id,
- sender: msg.isSelf === 1 ? "我" : msg.sendEmail || "未知发送者",
- avatar: msg.sendUserType == 2 ? "iconfont icon-icon28" : "iconfont icon-user",
- content: msg.content,
- time: new Date(msg.createTime),
- isSelf: msg.isSelf === 1,
- isImage: msg.type === 2,
- isRead: msg.isRead === 1,
- type: msg.type,
- roomId: msg.roomId,
- sendUserType: msg.sendUserType
- }));
+ // 将图片转换为 base64
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const base64Image = e.target.result;
+
+ // 构建WebSocket消息对象
+ const message = {
+ content: base64Image,
+ type: 2, // 类型2表示图片消息
+ email: this.currentContact.name,
+ receiveUserType: this.currentContact.sendUserType || 1, // 使用联系人的用户类型
+ roomId: this.currentContactId,
+ };
- // 按时间排序
- roomMessages = roomMessages.sort((a, b) => a.time - b.time);
+ // 发送WebSocket消息
+ this.stompClient.send(
+ "/point/send/message/to/user",
+ {},
+ JSON.stringify(message)
+ );
- // 更新消息列表
- this.$set(this.messages, roomId, roomMessages);
+ // 添加到本地消息列表
+ this.addMessageToChat({
+ sender: "我",
+ content: base64Image,
+ time: new Date(),
+ isSelf: true,
+ isImage: true,
+ type: 2,
+ roomId: this.currentContactId,
+ });
- // 更新联系人的未读状态
- const contact = this.contacts.find(c => c.roomId === roomId);
- if (contact) {
- contact.unread = 0;
- }
+ // 更新联系人最后一条消息
+ this.updateContactLastMessage({
+ roomId: this.currentContactId,
+ content: "[图片]",
+ isImage: true
+ });
+
+ this.$message.success("图片已发送");
+ };
+
+ reader.onerror = () => {
+ this.$message.error("图片读取失败");
+ this.sending = false;
+ };
+
+ // 开始读取文件
+ reader.readAsDataURL(file);
- } else {
- // 如果没有消息数据,初始化为空数组
- this.$set(this.messages, roomId, []);
- if (response?.code !== 200) {
- this.$message.warning("获取聊天记录失败");
- }
- }
} catch (error) {
- console.error("加载消息异常:", error);
- this.$message.error("加载消息异常");
- this.$set(this.messages, roomId, []);
+ console.error("上传图片异常:", error);
+ this.$message.error("上传图片失败,请重试");
+ } finally {
+ this.sending = false;
+ // 清空文件选择器
+ this.$refs.imageInput.value = "";
}
},
- // 添加消息到聊天记录
- addMessageToChat(messageData) {
- const roomId = messageData.roomId || this.currentContactId;
-
- // 如果该聊天室的消息数组不存在,则初始化
- if (!this.messages[roomId]) {
- this.$set(this.messages, roomId, []);
- }
-
- // 构造消息对象
- const message = {
- id: messageData.id,
- sender: messageData.sender,
- avatar: messageData.avatar || (messageData.isSelf ? "iconfont icon-icon28" : "iconfont icon-user"),
- content: messageData.content,
- time: messageData.time || new Date(),
- isSelf: messageData.isSelf,
- isImage: messageData.isImage || false,
- type: messageData.type || 1,
- roomId: roomId,
- isRead: messageData.isRead || false
- };
-
- // 添加消息到数组
- this.messages[roomId].push(message);
-
- // 更新最后一条消息
- this.updateContactLastMessage({
- roomId: roomId,
- content: message.content,
- isImage: message.isImage
- });
-
- // 如果是当前聊天室且用户在底部,滚动到底部
- if (roomId === this.currentContactId && !this.userViewHistory) {
- this.$nextTick(() => {
- this.scrollToBottom();
- });
- }
- },
-
- // 处理图片上传
- async handleImageUpload(event) {
- if (!this.currentContact || !this.wsConnected) return;
-
- const file = event.target.files[0];
- if (!file) return;
-
- // 检查是否为图片
- if (!file.type.startsWith("image/")) {
- this.$message.warning("只能上传图片文件!");
- return;
- }
-
- // 检查文件大小 (限制为5MB)
- const maxSize = 5 * 1024 * 1024;
- if (file.size > maxSize) {
- this.$message.warning("图片大小不能超过5MB!");
- return;
- }
-
- this.sending = true;
-
- try {
- // 准备FormData
- const formData = new FormData();
- formData.append("file", file);
-
- this.$message.info("正在上传图片...");
-
- // 调用API上传图片到后端
- const response = await getFileUpdate(formData);
- console.log("图片上传响应:", response);
-
- if (response && response.code === 200 && response.data) {
- // 获取后端返回的图片信息
- const imageData = response.data;
- const imageUrl = imageData.url;
-
- console.log("后端返回的图片URL:", imageUrl);
-
- // 构建WebSocket消息对象
- const message = {
- content: imageUrl, // 使用后端返回的URL作为内容
- type: 2, // 类型2表示图片消息
- email: this.currentContact.name,
- receiveUserType: this.userType,
- roomId: this.currentContactId,
- };
-
- // 发送WebSocket消息
- this.stompClient.send(
- "/point/send/message",
- {},
- JSON.stringify(message)
- );
-
- // 添加到本地消息列表以在UI中显示
- this.addMessageToChat({
- sender: "我",
- avatar: "iconfont icon-icon28",
- content: imageUrl,
- time: new Date(),
- isSelf: true,
- isImage: true, // 标记为图片消息
- });
-
- this.$message.success("图片已发送");
- } else {
- this.$message.error("图片上传失败: " + (response?.msg || "未知错误"));
- }
- } catch (error) {
- console.error("上传图片异常:", error);
- this.$message.error("上传图片失败,请重试");
- } finally {
- this.sending = false;
- // 清空文件选择器,以便于用户可以再次选择同一个文件
- this.$refs.imageInput.value = "";
- }
- },
+
// 更新联系人最后一条消息
updateContactLastMessage(message) {
@@ -1249,7 +1372,7 @@ export default {
}
},
- // 加载历史消息(7天前)
+ // 小时钟加载历史消息(7天前)
async loadHistory() {
this.loadingHistory = true;
this.userViewHistory = true; // 用户主动查看历史
@@ -1258,8 +1381,17 @@ export default {
try {
this.messagesLoading = true;
+ // 获取当前已加载的消息列表
+ const currentMsgs = this.messages[this.currentContactId] || [];
- const response = await getHistory({ roomId: this.currentContactId });
+ // 取最后一条消息的id
+ const lastMsg =
+ currentMsgs.length > 0 ? currentMsgs[currentMsgs.length - 1] : null;
+ this.history7Params.id = lastMsg ? lastMsg.id : "";
+ // this.history7Params.pageNum += 1; // 递增页码
+ this.history7Params.roomId = this.currentContactId;
+ this.history7Params.email = this.userEmail;
+ const response = await getHistory7(this.history7Params);
if (response && response.code === 200 && response.data) {
let historyMessages = response.data
@@ -1320,6 +1452,9 @@ export default {
}
}
+ // 组件销毁前断开连接
+ this.disconnectWebSocket();
+
// if (this.roomListInterval) {
// clearInterval(this.roomListInterval);
// }
diff --git a/mining-pool/src/views/home/index.js b/mining-pool/src/views/home/index.js
index 348c381..3f53e5b 100644
--- a/mining-pool/src/views/home/index.js
+++ b/mining-pool/src/views/home/index.js
@@ -76,22 +76,22 @@ export default {
nameTextStyle: {
padding: [0, 0, 0, -40],
- }
+ },
// min: `dataMin`,
// max: `dataMax`,
- // axisLabel: {
- // formatter: function (value) {
- // let data
- // if (value > 10000000) {
- // data = `${(value / 10000000)} KW`
- // } else if (value > 1000000) {
- // data = `${(value / 1000000)} M`
- // } else if (value / 10000) {
- // data = `${(value / 10000)} W`
- // }
- // return data
- // }
- // }
+ axisLabel: {
+ formatter: function (value) {
+ // let data
+ // if (value > 10000000) {
+ // data = `${(value / 10000000)} KW`
+ // } else if (value > 1000000) {
+ // data = `${(value / 1000000)} M`
+ // } else if (value / 10000) {
+ // data = `${(value / 10000)} W`
+ // }
+ return value
+ }
+ }
},
{
@@ -506,7 +506,8 @@ export default {
show: true,
amount: 1,
- }
+ },
+
// { //告知已删除此币种 Radiant
// value: "dgb2_odo",
// label: "dgb-odocrypt-pool2",
@@ -825,8 +826,37 @@ export default {
}
+ }else{ //动态计算图表的grid.left 让左侧的Y轴标签显示完全
+
+
+ const yAxis = this.option.yAxis[0]; // 第一个 Y 轴
+ const maxValue = Math.max(...this.option.series[0].data); // 获取数据最大值
+ const formatter = yAxis.axisLabel.formatter;
+ const formattedValue = formatter(maxValue); // 格式化最大值
+
+ // 创建一个临时 DOM 元素计算宽度
+ const tempDiv = document.createElement('div');
+ tempDiv.style.position = 'absolute';
+ tempDiv.style.visibility = 'hidden';
+ tempDiv.style.fontSize = '12px'; // 与 axisLabel.fontSize 一致
+ tempDiv.innerText = formattedValue;
+ document.body.appendChild(tempDiv);
+ const labelWidth = tempDiv.offsetWidth;
+ document.body.removeChild(tempDiv);
+
+ // 动态设置 grid.left,加上安全边距
+ const safeMargin = 20;
+ this.option.grid.left = labelWidth + safeMargin + 'px';
+ // this.$nextTick(
+ // // 更新图表
+ // this.inCharts()
+
+ // )
+
}
+
+
this.getBlockInfoData(this.BlockInfoParams)
this.getCoinInfoData(this.params)
@@ -1395,52 +1425,111 @@ export default {
handelCalculation() {
this.calculateIncome()
},
-
- // 左滑动逻辑
- scrollLeft() {
- const allLength = this.currencyList.length * 120
- const boxLength = document.getElementById('list-box').clientWidth
- if (allLength < boxLength) return
- const listEl = document.getElementById('list')
- const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
- if (leftMove + boxLength - 360 < boxLength) {
- // 到最开始的时候
- listEl.style.left = '0PX'
- } else {
- listEl.style.left = '-' + (leftMove - 360) + 'PX'
- }
- },
- // 右滑动逻辑
- scrollRight() {
- const allLength = this.currencyList.length * 120
- const boxLength = document.getElementById('list-box').clientWidth
- if (allLength < boxLength) return
- const listEl = document.getElementById('list')
- const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
- if (leftMove + boxLength + 360 > allLength) {
- listEl.style.left = '-' + (allLength - boxLength) + 'PX'
- } else {
- listEl.style.left = '-' + (leftMove + 360) + 'PX'
- }
- },
-
- // clickCurrency: throttle(function(item) {
- // this.currency = item.label
- // this.currencyPath = item.imgUrl
- // this.params.coin = item.value
- // this.BlockInfoParams.coin = item.value
- // this.itemActive = item.value
- // this.PowerParams.coin = item.value
- // this.getCoinInfoData(this.params)
- // this.getBlockInfoData(this.BlockInfoParams)
- // // this.getPoolPowerData(this.PowerParams)
- // // this.getMinerCountData(this.params)
- // if (this.powerActive) {
- // this.handelPower()
- // } else if (!this.powerActive) {
- // this.handelMiner()
+ // 获取单个币种项目的完整宽度(包含margin)
+ getItemFullWidth() {
+ const listEl = this.$refs.currencyList;
+ if (!listEl) return 120;
+
+ const firstItem = listEl.querySelector('.list-item');
+ if (!firstItem) return 120;
+
+ const style = window.getComputedStyle(firstItem);
+ const width = firstItem.offsetWidth;
+ const marginLeft = parseInt(style.marginLeft) || 0;
+ const marginRight = parseInt(style.marginRight) || 0;
+
+ return width + marginLeft + marginRight;
+ },
+
+ // 左滑动逻辑
+ scrollLeft() {
+ const listEl = this.$refs.currencyList;
+ const listBox = this.$refs.listBox;
+ if (!listEl || !listBox) return;
+
+ const itemFullWidth = this.getItemFullWidth();
+ const step = 2 * itemFullWidth; // 每次滑动2个币种
+ const allLength = this.currencyList.length * itemFullWidth;
+ const boxLength = listBox.clientWidth;
+
+ if (allLength <= boxLength) return;
+
+ let currentLeft = Math.abs(parseInt(listEl.style.transform.replace('translateX(', '').replace('px)', '')) || 0);
+ let newLeft = currentLeft - step;
+
+ listEl.classList.add('scrolling');
+
+ if (newLeft <= 0) {
+ listEl.style.transform = 'translateX(0)';
+ } else {
+ listEl.style.transform = `translateX(-${newLeft}px)`;
+ }
+
+ // 增加动画时间到 500ms
+ setTimeout(() => {
+ listEl.classList.remove('scrolling');
+ }, 500);
+ },
+
+ // 右滑动逻辑
+ scrollRight() {
+ const listEl = this.$refs.currencyList;
+ const listBox = this.$refs.listBox;
+ if (!listEl || !listBox) return;
+
+ const itemFullWidth = this.getItemFullWidth();
+ const step = 2 * itemFullWidth; // 每次滑动2个币种
+ const allLength = this.currencyList.length * itemFullWidth;
+ const boxLength = listBox.clientWidth;
+
+ if (allLength <= boxLength) return;
+
+ let currentLeft = Math.abs(parseInt(listEl.style.transform.replace('translateX(', '').replace('px)', '')) || 0);
+ let newLeft = currentLeft + step;
+ const maxLeft = allLength - boxLength;
+
+ listEl.classList.add('scrolling');
+
+ if (newLeft >= maxLeft) {
+ listEl.style.transform = `translateX(-${maxLeft}px)`;
+ } else {
+ listEl.style.transform = `translateX(-${newLeft}px)`;
+ }
+
+ // 增加动画时间到 500ms
+ setTimeout(() => {
+ listEl.classList.remove('scrolling');
+ }, 500);
+ },
+ // // 左滑动逻辑
+ // scrollLeft() {
+ // const allLength = this.currencyList.length * 120
+ // const boxLength = document.getElementById('list-box').clientWidth
+ // if (allLength < boxLength) return
+ // const listEl = document.getElementById('list')
+ // const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
+ // if (leftMove + boxLength - 360 < boxLength) {
+ // // 到最开始的时候
+ // listEl.style.left = '0PX'
+ // } else {
+ // listEl.style.left = '-' + (leftMove - 360) + 'PX'
// }
- // }, 1000),
+ // },
+ // // 右滑动逻辑
+ // scrollRight() {
+ // const allLength = this.currencyList.length * 120
+ // const boxLength = document.getElementById('list-box').clientWidth
+ // if (allLength < boxLength) return
+ // const listEl = document.getElementById('list')
+ // const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
+ // if (leftMove + boxLength + 360 > allLength) {
+ // listEl.style.left = '-' + (allLength - boxLength) + 'PX'
+ // } else {
+ // listEl.style.left = '-' + (leftMove + 360) + 'PX'
+ // }
+ // },
+
+
handleActiveItemChange(item) {
if (!item) return;
diff --git a/mining-pool/src/views/home/index.vue b/mining-pool/src/views/home/index.vue
index 40299be..671711e 100644
--- a/mining-pool/src/views/home/index.vue
+++ b/mining-pool/src/views/home/index.vue
@@ -340,6 +340,29 @@
+
+ {{ item.label }}
+
+